Assuming those files :
meson.build :
project('test', ['c'])
testlib = dependency('testlib', static:true)
and /some/custom/prefix/lib/pkgconfig/testlib.pc :
prefix=/some/custom/prefix
libdir=${prefix}/lib
Name: testlib
Description: A test library
Version: 0.0.1
Libs: -L${libdir}
Libs.private: -lm
With meson 0.43.0 :
$ PKG_CONFIG_PATH=/some/custom/prefix/lib/pkgconfig meson . build
The Meson build system
Version: 0.43.0
Source dir: [...]
Build dir: [...]
Build type: native build
Project name: test
Build machine cpu family: x86_64
Build machine cpu: x86_64
Found pkg-config: /usr/bin/pkg-config (1.3.10)
Native dependency testlib found: YES 0.0.1
Build targets in project: 0
Found ninja-1.8.2 at /usr/bin/ninja
With meson 0.44.0 :
$ PKG_CONFIG_PATH=lib/pkgconfig meson . build
The Meson build system
Version: 0.44.0
Source dir: [...]
Build dir: [...]
Build type: native build
Project name: test
Native C compiler: ccache cc (gcc 7.2.1)
Build machine cpu family: x86_64
Build machine cpu: x86_64
Found pkg-config: /usr/bin/pkg-config (1.3.10)
Meson encountered an error in file meson.build, line 3, column 0:
Static library not found for 'm'
A full log can be found at /home/mgautier/Project/KIWIX/test_meson_0.44.0/build/meson-logs/meson-log.txt
This is probably because here (https://github.com/mesonbuild/meson/blob/master/mesonbuild/dependencies/base.py#L473-L487), we are only searching for static library in path provided by pkg-config and not in standard library directories.
Another problem is that currently we require all dependencies of the current package to be static when static: true is passed, but maybe we should simple 'prefer-static' for dependencies of the current package, and require static only for the package itself.
So it probably makes sense to do the following:
1) Require the base library to be static (f.ex, -lgio-2.0 in gio-2.0.pc)
2) Prefer static libs for dependencies, but also accept shared libraries (f.ex -lglib-2.0 -lgobject-2.0 -lpcre -lselinux -lresolv -lmount -lz in gio-2.0.pc)
If people require a strict all-static mode, we can extend the kwargs on the function later.
Note: yes, the example is not great since you must always link to all glib libraries exactly once, but we can require the user to ensure that since we have no way of knowing such a thing.
It sounds like having a enum policy of the linking mode could be useful in general. static only accepts boolean now and in my opinion we should not have inconsistencies in it. The problem is static = false is relaxed shared mode (try shared, fallback to static), while static = true is strict static, but it was relaxed static in 0.43. Documentation currently says "try static", see #3084, so it is relaxed static mode.
In my opinion static should be just just a preference for all cases and strict static linking can be added separately. Advantage of relaxed static linking is that global static option can be introduced to flip preference project-wide and it would still work for dependencies without static version. I can easily imagine something like meson builddir -Dprefer-static=true which would set static : true for each dependency call unless overridden, and package maintainer can then flip this for the whole project. So I disagree with (1) that we should require it, but with static=false we don't require shared and allow static.
The reason why 0.43 was "relaxed static" was because the static linking wasn't implemented at all. The only thing it did was pass --static to pkg-config, so the only way to get a static build was to delete your shared libraries. static: true was, effectively, a new feature in 0.44.
However, it was also broken because now it would require all libraries to be static, even ones you didn't intend.
With a "try static, fallback to shared" behaviour, it would be too easy for users to build in a way that the maintainers did not intend if the base library can silently go to shared. I think having static: true be strict for the base library and not be strict recursively is a good middle-ground for fixing this regression.
We can and should fix this properly in a later release once we have a better idea of what the API will look like.
Another option, as discussed on IRC with @textshell is that when self.compiler.find_library(lib[2:], self.env, libpaths, libtype='static') fails, we keep the -lfoo arg as-is instead and let the linker find it.
This will be the least-code (and hence least-possibility of regression) method to fix this, and would actually be 'relaxed static' as @sarum9in advocated.
I'll test and submit a PR for this tomorrow unless someone has an objection or a better idea.
Protecting from accidental shared linking makes sense. @nirbheek as a person who worked a lot with autotools, how does it work in autotools + pkg-config? If you want to use static dependency, is it strict for direct dependency and relaxed for transitive dependencies? Or some other way? The reason I am asking is that it seems to me that static here would make sense to keep somewhat similar to usual pkg-config semantics.
Also I wonder how meson is going to handle case with static direct dependency which is pulled transitively also.
# imagine that 'bbb' depends on 'ccc' via pkg-config file
Name: Libbbb
Libs: -L${libdir} -lccc
# and we use it in meson
e = executable(dependencies : [dependency('bbb', static : true), dependency('ccc')]
Will this link static ccc? Or it will try to link both static and shared and fail? It would be awesome to test this case regardless of implementation pursued.
... fails, we keep the -lfoo arg as-is instead and let the linker find it
Do you mean for transitive dependencies or direct as well? If for all, does it mean that the difference with my proposal is that we fallback to literal -lfoo instead? I am not sure how it works now though.
The simple fallback (i.e. 'relaxed static' for everything) is what we discussed on irc for 0.44.1 as a simple (and unlikely to break builds) fix. The plan is still to go for a more comprehensive solution. Because of limitations in the pkg-config API doing a static with enforcement only for the direct dependency needs quite complex code, but afaiu having this as option is still very much on the roadmap.
@nirbheek as a person who worked a lot with autotools, how does it work in autotools + pkg-config? If you want to use static dependency, is it strict for direct dependency and relaxed for transitive dependencies? Or some other way?
There is no way to prefer static libraries over shared ones with autotools since it always uses -Lfoo -lbar arguments. You can add -Wl,-static but that will force every library after it to be statically linked in, so it's not usable unless you manually construct your linker command.
Like @textshell said, we will have to think about the API that people need, and how we will implement it because pkg-config's API is very limited.
Most helpful comment
The simple fallback (i.e. 'relaxed static' for everything) is what we discussed on irc for 0.44.1 as a simple (and unlikely to break builds) fix. The plan is still to go for a more comprehensive solution. Because of limitations in the pkg-config API doing a static with enforcement only for the direct dependency needs quite complex code, but afaiu having this as option is still very much on the roadmap.