diff mbox series

[04/10] meson: option to build as shared library

Message ID 20201012232939.48481-5-j@getutm.app
State New
Headers show
Series iOS and Apple Silicon host support | expand

Commit Message

Joelle van Dyne Oct. 12, 2020, 11:29 p.m. UTC
From: osy <osy86@users.noreply.github.com>

On iOS, we cannot fork() new processes, so the best way to load QEMU into an
app is through a shared library. We add a new configure option
`--enable-shared-lib` that will build the bulk of QEMU into a shared lib.
The usual executables will then link to the library.

Signed-off-by: Joelle van Dyne <j@getutm.app>
---
 configure         | 14 ++++++++++++--
 meson.build       | 40 ++++++++++++++++++++++++++++++++++------
 meson_options.txt |  2 ++
 3 files changed, 48 insertions(+), 8 deletions(-)

Comments

Daniel P. Berrangé Oct. 13, 2020, 7:51 a.m. UTC | #1
On Mon, Oct 12, 2020 at 04:29:33PM -0700, Joelle van Dyne wrote:
> From: osy <osy86@users.noreply.github.com>
> 
> On iOS, we cannot fork() new processes, so the best way to load QEMU into an
> app is through a shared library. We add a new configure option
> `--enable-shared-lib` that will build the bulk of QEMU into a shared lib.
> The usual executables will then link to the library.

Note that QEMU as a combined work is licensed GPLv2-only, so if an app is
linking to it as a shared library, the application's license has to be
GPLv2 compatible. I fear that shipping as a shared library is an easy way
for apps to get into a license violating situation without realizing.

Regards,
Daniel
Daniel P. Berrangé Oct. 13, 2020, 2:46 p.m. UTC | #2
On Tue, Oct 13, 2020 at 04:41:06PM +0200, BALATON Zoltan wrote:
> On Tue, 13 Oct 2020, Daniel P. Berrangé wrote:
> > On Mon, Oct 12, 2020 at 04:29:33PM -0700, Joelle van Dyne wrote:
> > > From: osy <osy86@users.noreply.github.com>
> > > 
> > > On iOS, we cannot fork() new processes, so the best way to load QEMU into an
> > > app is through a shared library. We add a new configure option
> > > `--enable-shared-lib` that will build the bulk of QEMU into a shared lib.
> > > The usual executables will then link to the library.
> > 
> > Note that QEMU as a combined work is licensed GPLv2-only, so if an app is
> > linking to it as a shared library, the application's license has to be
> > GPLv2 compatible. I fear that shipping as a shared library is an easy way
> > for apps to get into a license violating situation without realizing.
> 
> Please don't let that be an obstacle in merging this series. They'll do it
> anyway as seen here so having it upstream is probably better than having a
> lot of different/divergent forks.

"They'll violate the license anyway" is not a compelling argument.

> In case of UTM it seems to be licensed under Apache License 2.0:
> 
> https://github.com/utmapp/UTM/blob/master/LICENSE
> 
> which FSF says not compatible with GPLv2 but it is with GPLv3:
> 
> http://www.gnu.org/licenses/license-list.html#apache2
> 
> Not sure however if that's for using Apache licenced part in GPLv2 code or
> the other way around like in UTM in which case I think the whole work will
> effectively become GPLv3 as most parts of QEMU is probably GPLv2+ already or
> BSD like free that should be possible to combine with only files explicitely
> GPLv2 in QEMU remaining at that license and UTM parts are Apache 2.0 when
> separated from QEMU. I have no idea about legal stuff whatsoever but
> combining two free software components should be legal some way (otherwise
> it's not possible to combine GPLv2 with GPLv3 either).

You need to distinguish between GPLv2-only and GPLv2-or-later.

GPLv2-or-later is fine as that upgrades to GPLv3 when used in a
combined work with Apache License or GPLv3 software.

GPLv2-only will, by design, *not* upgrade to newer GPL versions
when combined - it is simply license incompatible.

QEMU unfortunately has a bunch a GPLv2-only code present that we
cannot eliminate.

Regards,
Daniel
Joelle van Dyne Oct. 13, 2020, 3:16 p.m. UTC | #3
I will start a separate conversation of UTM's license compatibility.

Regarding the patch, would some sort of warning message in configure
(if building as a shared library) regarding the license be wise? Or
would it pollute the output logs?

-j

On Tue, Oct 13, 2020 at 7:46 AM Daniel P. Berrangé <berrange@redhat.com> wrote:
>
> On Tue, Oct 13, 2020 at 04:41:06PM +0200, BALATON Zoltan wrote:
> > On Tue, 13 Oct 2020, Daniel P. Berrangé wrote:
> > > On Mon, Oct 12, 2020 at 04:29:33PM -0700, Joelle van Dyne wrote:
> > > > From: osy <osy86@users.noreply.github.com>
> > > >
> > > > On iOS, we cannot fork() new processes, so the best way to load QEMU into an
> > > > app is through a shared library. We add a new configure option
> > > > `--enable-shared-lib` that will build the bulk of QEMU into a shared lib.
> > > > The usual executables will then link to the library.
> > >
> > > Note that QEMU as a combined work is licensed GPLv2-only, so if an app is
> > > linking to it as a shared library, the application's license has to be
> > > GPLv2 compatible. I fear that shipping as a shared library is an easy way
> > > for apps to get into a license violating situation without realizing.
> >
> > Please don't let that be an obstacle in merging this series. They'll do it
> > anyway as seen here so having it upstream is probably better than having a
> > lot of different/divergent forks.
>
> "They'll violate the license anyway" is not a compelling argument.
>
> > In case of UTM it seems to be licensed under Apache License 2.0:
> >
> > https://github.com/utmapp/UTM/blob/master/LICENSE
> >
> > which FSF says not compatible with GPLv2 but it is with GPLv3:
> >
> > http://www.gnu.org/licenses/license-list.html#apache2
> >
> > Not sure however if that's for using Apache licenced part in GPLv2 code or
> > the other way around like in UTM in which case I think the whole work will
> > effectively become GPLv3 as most parts of QEMU is probably GPLv2+ already or
> > BSD like free that should be possible to combine with only files explicitely
> > GPLv2 in QEMU remaining at that license and UTM parts are Apache 2.0 when
> > separated from QEMU. I have no idea about legal stuff whatsoever but
> > combining two free software components should be legal some way (otherwise
> > it's not possible to combine GPLv2 with GPLv3 either).
>
> You need to distinguish between GPLv2-only and GPLv2-or-later.
>
> GPLv2-or-later is fine as that upgrades to GPLv3 when used in a
> combined work with Apache License or GPLv3 software.
>
> GPLv2-only will, by design, *not* upgrade to newer GPL versions
> when combined - it is simply license incompatible.
>
> QEMU unfortunately has a bunch a GPLv2-only code present that we
> cannot eliminate.
>
> Regards,
> Daniel
> --
> |: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
> |: https://libvirt.org         -o-            https://fstop138.berrange.com :|
> |: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|
>
Daniel P. Berrangé Oct. 13, 2020, 3:57 p.m. UTC | #4
On Tue, Oct 13, 2020 at 08:16:46AM -0700, Joelle van Dyne wrote:
> I will start a separate conversation of UTM's license compatibility.
> 
> Regarding the patch, would some sort of warning message in configure
> (if building as a shared library) regarding the license be wise? Or
> would it pollute the output logs?

I think there's also a more fundamental question of whether this is
a concept we actually want to support at all.

IIUC, this shared library just exposes a "qemu_main" method which
the external app has to jump into. IOW, the "char **argv" parameter
to qemu_main becomes the ELF library ABI.  Declaring this a shared
library interface is a non-negligible commitment for QEMU maintainers,
especially given that there is alot about QMEU's command line parsing
that maintainers do not like and wish to change.

There is a further question about whether we want to commit to an
architectural model where  fork() is not something we can use. A
significant area of development for QEMU right now is around the
modularization of the device model such that QEMU is no longer a
single process, but rather a collection of processes, each proc
responsible for some specific hardware emulation. Thus far all the
device modularization stuff is strictly optional, but we have the
freedom to make it mandatory and use it transparently behind the
scenes. If we declare this shared library model supported in order
to avoid use of fork, then we're restricting our future options
wrt device modularization.

So including the license issue, that's three major questionmarks
around desirability of supporting use of QEMU as a shared library.


Regards,
Daniel
Joelle van Dyne Oct. 14, 2020, 4:09 p.m. UTC | #5
Since there seems to be some more push back on this one, I will remove
this patch from the v2 submission and submit it as a separate patch

-j

On Tue, Oct 13, 2020 at 9:40 AM BALATON Zoltan <balaton@eik.bme.hu> wrote:
>
> On Tue, 13 Oct 2020, Daniel P. Berrangé wrote:
> > On Tue, Oct 13, 2020 at 08:16:46AM -0700, Joelle van Dyne wrote:
> >> I will start a separate conversation of UTM's license compatibility.
> >>
> >> Regarding the patch, would some sort of warning message in configure
> >> (if building as a shared library) regarding the license be wise? Or
> >> would it pollute the output logs?
> >
> > I think there's also a more fundamental question of whether this is
> > a concept we actually want to support at all.
>
> Discussing other compelling reasons for doubt is OK, just wanted to avoid
> having this dismissed on possible licensing problems only. I still think
> it would be a good idea to support QEMU on iOS but due to the (mostly
> security related) limitations of that platform some compromises my be
> needed. Please consider it instead of being quick to decide to avoid these
> problems by not taking the patches upstream which is a convenient solution
> from QEMU viewpoint but not helping other projects. (Other platforms may
> come up in the future with similar limitations that iOS has as more
> desktop OSes also move in the same direction to increase security so these
> may need to be handled anyway at one point, iOS is a good test case for
> that.)
>
> > IIUC, this shared library just exposes a "qemu_main" method which
> > the external app has to jump into. IOW, the "char **argv" parameter
> > to qemu_main becomes the ELF library ABI.  Declaring this a shared
> > library interface is a non-negligible commitment for QEMU maintainers,
> > especially given that there is alot about QMEU's command line parsing
> > that maintainers do not like and wish to change.
>
> Given that libvirt uses the command line instead of a proper API
> currently, this is not worse than that. If there was a better API or there
> will be one in the future, the shared lib API can be changed the same way
> as libvirt will need to be adapted for that but it's not reasonable to
> demand these patches to come up with that API now. So for now this seems
> to be acceptable and does not prevent cleaning it up later together with
> the planned changes you mentioned. Compatibility for the command line will
> have to be maintained until a better API is devised for use by other
> software like libvirt and anyone intending to use it as dll so this does
> not seem like added commitment.
>
> > There is a further question about whether we want to commit to an
> > architectural model where  fork() is not something we can use. A
>
> Does Windows support fork()? I think we're already committed to support
> Windows so any solution you'll come up with will have the same problem
> anyway. So I think this does not add additional restriction that we don't
> already have either.
>
> Regards,
> BALATON Zoltan
diff mbox series

Patch

diff --git a/configure b/configure
index c474d7c221..37b27d9e35 100755
--- a/configure
+++ b/configure
@@ -448,6 +448,7 @@  ninja=""
 skip_meson=no
 gettext=""
 host_block_device_support="yes"
+shared_lib="false"
 
 bogus_os="no"
 malloc_trim="auto"
@@ -1563,6 +1564,10 @@  for opt do
   ;;
   --disable-libdaxctl) libdaxctl=no
   ;;
+  --enable-shared-lib) shared_lib=true
+  ;;
+  --disable-shared-lib) shared_lib=false
+  ;;
   *)
       echo "ERROR: unknown option $opt"
       echo "Try '$0 --help' for more information"
@@ -1770,6 +1775,7 @@  Advanced options (experts only):
                            enable plugins via shared library loading
   --disable-containers     don't use containers for cross-building
   --gdb=GDB-path           gdb to use for gdbstub tests [$gdb_bin]
+  --enable-shared-lib      build QEMU as a shared library
 
 Optional features, enabled with --enable-FEATURE and
 disabled with --disable-FEATURE, default is enabled if available:
@@ -7211,7 +7217,11 @@  echo "ranlib = [$(meson_quote $ranlib)]" >> $cross
 if has $sdl2_config; then
   echo "sdl2-config = [$(meson_quote $sdl2_config)]" >> $cross
 fi
-echo "strip = [$(meson_quote $strip)]" >> $cross
+if test "$shared_lib" = "true"; then
+  echo "strip = [$(meson_quote $strip), '-x']" >> $cross
+else
+  echo "strip = [$(meson_quote $strip)]" >> $cross
+fi
 echo "windres = [$(meson_quote $windres)]" >> $cross
 if test "$cross_compile" = "yes"; then
     cross_arg="--cross-file config-meson.cross"
@@ -7273,7 +7283,7 @@  NINJA=${ninja:-$PWD/ninjatool} $meson setup \
 	-Dcocoa=$cocoa -Dmpath=$mpath -Dsdl=$sdl -Dsdl_image=$sdl_image \
 	-Dvnc=$vnc -Dvnc_sasl=$vnc_sasl -Dvnc_jpeg=$vnc_jpeg -Dvnc_png=$vnc_png \
 	-Dgettext=$gettext -Dxkbcommon=$xkbcommon -Du2f=$u2f \
-	-Dcapstone=$capstone -Dslirp=$slirp -Dfdt=$fdt \
+	-Dcapstone=$capstone -Dslirp=$slirp -Dfdt=$fdt -Dshared-lib=$shared_lib \
         $cross_arg \
         "$PWD" "$source_path"
 
diff --git a/meson.build b/meson.build
index 69a3c00cce..32cf08619f 100644
--- a/meson.build
+++ b/meson.build
@@ -1565,14 +1565,31 @@  foreach target : target_dirs
   arch_srcs += target_specific.sources()
   arch_deps += target_specific.dependencies()
 
-  lib = static_library('qemu-' + target,
+  if get_option('shared-lib')
+    build_lib_args = {
+      'target_type': 'shared_library',
+      'install': true,
+      'dependencies': arch_deps + deps,
+      'link_language': link_language,
+      'link_depends': [block_syms, qemu_syms],
+      'link_args': link_args + cc.get_supported_link_arguments(['-Wl,-U,_qemu_main'])
+    }
+  else
+    build_lib_args = {
+      'target_type': 'static_library',
+      'install': false,
+      'dependencies': arch_deps,
+      'name_suffix': 'fa'
+    }
+  endif
+
+  lib = build_target('qemu-' + target,
                  sources: arch_srcs + genh,
-                 dependencies: arch_deps,
                  objects: objects,
                  include_directories: target_inc,
                  c_args: c_args,
                  build_by_default: false,
-                 name_suffix: 'fa')
+                 kwargs: build_lib_args)
 
   if target.endswith('-softmmu')
     execs = [{
@@ -1606,17 +1623,27 @@  foreach target : target_dirs
       'dependencies': []
     }]
   endif
+  if get_option('shared-lib')
+    build_exe_args = {
+      'link_with': lib,
+      'link_args': link_args + cc.get_supported_link_arguments(['-Wl,--exclude-libs,ALL'])
+    }
+  else
+    build_exe_args = {
+      'objects': lib.extract_all_objects(recursive: true),
+      'link_args': link_args
+    }
+  endif
   foreach exe: execs
     emulators += {exe['name']:
          executable(exe['name'], exe['sources'],
                install: true,
                c_args: c_args,
                dependencies: arch_deps + deps + exe['dependencies'],
-               objects: lib.extract_all_objects(recursive: true),
                link_language: link_language,
                link_depends: [block_syms, qemu_syms] + exe.get('link_depends', []),
-               link_args: link_args,
-               gui_app: exe['gui'])
+               gui_app: exe['gui'],
+               kwargs: build_exe_args)
     }
 
     if 'CONFIG_TRACE_SYSTEMTAP' in config_host
@@ -1758,6 +1785,7 @@  endif
 summary_info += {'Doc directory':     get_option('docdir')}
 summary_info += {'Build directory':   meson.current_build_dir()}
 summary_info += {'Source path':       meson.current_source_dir()}
+summary_info += {'build shared lib':  get_option('shared-lib')}
 summary_info += {'GIT binary':        config_host['GIT']}
 summary_info += {'GIT submodules':    config_host['GIT_SUBMODULES']}
 summary_info += {'C compiler':        meson.get_compiler('c').cmd_array()[0]}
diff --git a/meson_options.txt b/meson_options.txt
index 1d3c94840a..bcecbd5e12 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -2,6 +2,8 @@  option('qemu_suffix', type : 'string', value: 'qemu',
        description: 'Suffix for QEMU data/modules/config directories (can be empty)')
 option('docdir', type : 'string', value : 'doc',
        description: 'Base directory for documentation installation (can be empty)')
+option('shared-lib', type : 'boolean', value : false,
+       description: 'build QEMU as a shared library')
 
 option('gettext', type : 'boolean', value : true,
        description: 'Localization of the GTK+ user interface')