Open ocrete opened 6 years ago
This has something similar to PR #2711 conceptually. The key is that pkgconfig dependencies could be used both as static and shared library. So meson has to make a choice and currently always link dynamically.
It makes sense to have a project wide option to tell which one to choose when both are available. I think this issue should use the same config than the one I introduced for both_library() case.
Actually PkgConfigDependency
already has a static
argument and the code to invoke pkg-config --static
. So it is just a matter to add a global setting to set self.static
to true by default on all ExternalDependency
objects. Right?
Except that linking statically means putting all the deps explicitly on the GCC command line. But using the output of pkg-config --static
won't work as some of those may be static. also the order must be respected when linking statically.
Another option for this is to instead do it path based, so I can say "libraries in ~/cerbero/build/ are statically linked, but those in ~/devicesdk/ are dynamically linked"
If you set static: true
on a pkg-config dependency()
, Meson will do some magic to find a static library corresponding to the paths outputted by pkg-config --libs
and pass the full path to it to gcc. I implement this a couple of weeks ago, and this will work with 0.44.0
. If it doesn't work, please file a bug.
The same should also work for cc.find_library()
.
Do you need anything else?
Nope, that doesn't work, because you take the whole output of "pkg-config --libs --static" and try to build all of those as static. But this is not what I want, I just want some of them to be.
Here is an example
My meson.build is
project('test','c')
mydep = dependency('libpng', static: true)
executable('test2',['test.c'], dependencies: mydep)
Then I run meson as
PKG_CONFIG_PATH=~/cerbero/build/dist/linux_x86_64/lib/pkgconfig meson build
But that fails because it tries to find a static library for libm which is in the Libs.private.. Which is what I want to avoid. It does:
Meson encountered an error in file meson.build, line 3, column 0:
Static library not found for 'm'
For platform libraries, we should actually add a blacklist. For instance, no one wants -ldl -lm -lc -lpthread
to be statically linked unless they are building with a custom toolchain and with no libc.
Would have to think how this would be implemented.
I'd rather not having something magical for platform libraries, as maybe we want to use other libraries that are already in the platform such as glib or openssl (to make a smaller binary)
I think what we need is an exclude list like ['/usr', '/lib']. So if the fullpath of libfoo.a has one of them as prefix, link it dynamically instead.
The same should also work for cc.find_library().
This doesn't support static: true
- even though I wish it did!
I'm facing a similar case for glib CI: https://gitlab.gnome.org/GNOME/glib/merge_requests/360
I would like in the CI to install glib into a prefix, then build a simple app that static link on the installed glib build, to verify the installed .pc is correct and static links works (spoiler alert, current they don't).
My test project looks like this:
project('test-static-link', 'c')
app = executable('test-static-link', 'app.c',
dependencies : dependency('gio-2.0', static : true)
)
test('test-static-link', app)
The problem is the "static : true" kwarg is a all-or-nothing switch. Setting it to true means it will try to static link all glib dependencies (e.g. libffi) but fedora (used as base for our CI docker) doesn't package static libraries, so meson is printing WARNING message that it cannot find .a file for them. I would like to be able to tell "static link glib/gobject/gio that are installed into a custom prefix, and dynamic link their dependencies that comes from the distro".
I'm not convinced anymore PR #2816 is the best way to achieve this, I think there are easier and less invasive ways. I think we just need to make static
kwarg accept other types than a a simple boolean. For example dependency('foo', static : ['/home/user/my-prefix/lib'])
that would mean "static link only if the .a is found in that directory".
We could then do something like (would require nicer API to avoid double dependency lookup):
tmp = dependency('foo')
libdir = tmp.get_pkgconfig_variable('libdir')
dep = dependency('foo', static : [libdir])
The "-static-libtool-libs" argument to libtool tells it only statically link libraries that have a ".la" files, but to dynamically link other libraries.
The use-case is the following:
The device contains the .so files for libraries that are also in its SDK. I want to create the smallest possible binary for my device using GStreamer. So I want the files coming from the "app SDK" to be statically linked into my application, but the files from the "platform SDK" to be static.
Currently, the way I do it is by making sure there are no ".la" files in the "device SDK", but that the "app SDK" always has a .la file.. Then I use the "-static-libtool-libs" option to libtool and it just works.
I suggest doing the same with .pc files. I think the trick is to take the output of "pkg-config --libs --static" and of "pkg-config --libs", and if a library is in both, add it to the list of static libraries. If a library is only in "pkgconfig --libs --static" then add it to the general list.. When all the libraries have been processed, remove all "static" libs from the general list. Then we'll have 2 lists, the "static" list.. which must be statically linked, and the "general list" which must be dynamically linked...