-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix pkg-config dependencies leaking out (debbug 892956) #3251
Conversation
This builds a project with pkg-config file, installs it and then builds a second project that uses that dependency and runs the result.
run_unittests.py
Outdated
os.environ['PKG_CONFIG_PATH'] = pkg_dir | ||
# Private internal libraries must not leak out. | ||
pkg_out = subprocess.check_output(['pkg-config', '--static', '--libs', 'libpkgdep']) | ||
#self.assertFalse(b'libpkgdep-int' in pkg_out, 'Internal library leaked out.') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Flake8]
[E265] block comment should start with '# '
7b405a1
to
c385f79
Compare
I don't understand when does it make sense for pkg-config to list cflags of private deps. |
I mean, this seems a bug in pkgconfig to me... Unless there is something I don't understand and that's likely :) |
# This way (hopefully) "pkgconfig --libs --static foobar" works | ||
# and "pkgconfig --cflags/--libs foobar" does not have any trace | ||
# of dependencies that the build file creator has not explicitly | ||
# added to the dependency list. | ||
processed_libs.append(obj) | ||
if public: | ||
if not hasattr(obj, 'generated_pc'): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this if should also be done for build.SharedLibrary. (i.e. obj.generated_pc = self.name if public)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doing that is exactly what caused this bug.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why?
I think what causes this bug is one (or both) of the self.add_priv_libs(
lines.
obj.generated_pc is only used if something else depends on this library, possibly even explicitly.
All we currently know why pkg-config lists cflags of private deps is this commit: I just noticed that it does reference https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=340904 |
It is either a bug or a feature of pkg-config, yes. If you specify private depends on a pc file, then those arguments are used for If we install a shared library foo, we know that it is shared so it could not even be compiled with |
That's going to hit back when we add both_library() then. I need to read that Debian bug, I still think it makes no sense to have private cflags. |
It seems to be currently impossible to do a pkg-config file that:
Pkg-config's static linking is a bit broken anyway. It does not actually make the flags point to the .a files. (as an example |
debian 340904 is indeed an interesting read. From my reading they needed a cflags only variant of |
So from what I understand, the summary is:
As a result, every pkg-config file now requires the entire dependency tree of development packages to be installed because our This is nuts. The correct solution, as @textshell said, is to have something like |
I think the solution in this PR is incorrect, pkgconfig doesn't care what your installed libraries look like, and making the outputted pkgconfig file conditional on that doesn't sound right. One solution here is to never add private requires automatically, and require people to provide those manually. I am sure there are other solutions, suggestions welcome. |
I think meson does this right thing here, and finally after 10+ years we have correct PC files. I think we should revert the commit in pkg-config, add requires.cflags, and wait another 10 years for everyone to fix their pc files. |
That's not really how you make progress though. You can't break the world and tell people to deal with it. That just makes them patch your code away and not do anything. For the future, we will want to extend the pkgconfig format after talking to the pkg-config and pkgconf maintainers. The way I see it, one way would be by changing the meaning of
There is no such thing as "correct PC files" in this case. The format is fundamentally broken. |
I think static / dynamic linking of libraries in pkg-config is just not working well and meson has to work with pkg-config limitations as best as possible. And that fundamentally depends on what variants of a library are going to be available. For libraries that are only going to be installed in a dynamic variant, outputting .private dependencies only breaks users like this bug shows. For libraries that are only going to be installed in a static variant, outputting .private dependencies forces consumers of the library to be aware that currently only a static variant is available, so i argue that meson should in the future change to outputting the in that case always needed dependencies as non private to make using the static library easy. This will not be worse than using .private in leaking cflags because .private cflags leak anyway (debian 340904). For libraries that are only going to be installed in both a static and a dynamic variant, meson has no other choice than to output the dependencies needed only for static linking to .private. This will then have the side effect of requiring -dev packages for the parts of the dependency tree that allow static linking. But i think this will not be a regression as long as libraries are not introducing the static option where they did not offer that before. I agree with nirbheek that breaking the world right now will simply not work. So the approach of this PR at least for the short term is the right solution. Libraries that want to have the additional dependencies still can request them explicitly in their meson.build, right? I also agree that in the long term pkg-config should be extended. Preferably when there is a good collection of use cases in form of unit tests that can be used to validate proposals so they don't end like what we are dealing with here(i.e. seemed reasonable at that time) |
I agree with @textshell, for SharedLibrary we don't need private deps at all, and for StaticLibrary we could put private deps in public. The problem will appear when we'll add BothLibraries. I guess we should deprecate Requires.private because it's ambiguous and add Requires.private-libs and Requires.private-cflags. Meson will use Requires.private-libs when generating pc file for BothLibraries and depend on a future version of pkg-config. |
With autoconf or cmake this is usually done with something like I am not convinced that this will always work correctly with several levels of static libraries, but if there are problems they are at least not widespread. So as a short-term solution putting into |
That is one possible solution, but it has a few problems:
|
I think this problem already exists; I know of projects that build both shared and static by reusing built objects. BothLibrary will merely formalize the breakage. |
Yes, while meson doesn't yet have both_libraries, there are libraries that manually build both variants. But libraries build with meson that both
to be affected. Maybe finding a workaround for just dpdk might be ok for now. But of course i might have false negatives. Does anyone know other cases? I think we should try to have some official guidance in 0.46 how to use the pkgconfig module for manual both_library like usecases. Currently meson would have to guess based on target name and |
Projects that does both libraries manually could just switch to BothLibraries to get special treatment in pc generator. |
I did not dare to hope that both_libraries would be ready for inclusion in the 0.46 time-frame and i think it is important to have some/any supported option for doing shared/static with pkgconfig when we break it here. |
I reported the pkg-config bug there: https://bugs.freedesktop.org/show_bug.cgi?id=105572 What I would suggest here:
|
@jpakkane I had a look at the failing unit tests and created a branch with suggestions for getting the tests to work again https://github.com/mesonbuild/meson/compare/fixpkgconfigdeps...textshell:fixpkgconfigdeps-suggestions?expand=1 The fix for test_pkgconfig_gen_deps just switches the test to use a static_library, for now the fixes the test. That test likely needs to be rethought depending on what further actions we decide. These suggestion also include setting I think with these fixes this PR implements step 1 in @xclaesse 's plan in #3251 (comment) |
Updated with test fixes. |
run_unittests.py
Outdated
test_exe = os.path.join(self.builddir, 'pkguser') | ||
self.assertTrue(os.path.isfile(test_exe)) | ||
subprocess.check_call(test_exe, env=myenv) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
test_pkgconfig_gen_deps() already pretty much does the same thing. I think it would be better to add test cases there instead of a completely new test case. Also I added self.new_builddir() for this kind of test.
@@ -510,7 +510,8 @@ def tearDown(self): | |||
windows_proof_rmtree(path) | |||
except FileNotFoundError: | |||
pass | |||
os.environ = self.orig_env | |||
os.environ.clear() | |||
os.environ.update(self.orig_env) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm curious, why is this needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
os.environ
is a dict like object but not actually a dict. setUp
and tearDown
previously tried to restore the state of os.environ
by assigning os.environ.copy()
to os.environ
. But that is a normal dict and thus after that os.environ
no longer has effect on processes started with subprocess.
I spend some time debugging why the test worked in isolation but not with the whole test suit and decided to fix the root cause, by not assigning but by replacing the contents back into the special object.
Since this is urgent we'll need to get a point release out with this fix either today or, at the very latest, tomorrow. This may mean that the end result won't work perfectly with static dependencies, but that is not really such a huge problem because the old version did not work either. |
Afaik this PR doesn't produce any regressions in the static libraries only use case. From my pov the only real blocker is getting rid of the OS X test failures caused by glib2 not being found in some way. For point 2 (changes for static libs) of @xclaesse 's plan i will rebase #3093 after this PR lands so we can discuss that there. |
Note that Fedora moved to pkgconf a while ago, so we need to report it there too. CCing @kaniini |
I've written up my understanding of the situation on https://bugs.freedesktop.org/show_bug.cgi?id=105572. The tl;dr version is that there are three use-cases, of different levels of "privateness".
Hopefully my comment on the pkg-config bug makes it clearer. If it doesn't, let's use the pkg-config bug (since pkg-config provides the "specification" that Meson, pkgconf and library authors need to follow) to reach a common understanding of what's happening here and what needs to be done about it. @AdrianBunk: I've tried to summarize the problems caused by having too many CFLAGS, paraphrasing what you said on IRC. I know we have different opinions on what the severity of those problems is, but hopefully I've described the facts correctly? If there are some that I missed, please describe them on the pkg-config bug. Thanks! |
I added patches to add Requires.internal in pkg-config. In the bright future, I think dependencies automatically pulled by meson's pkgconfig generator should all go into Requires.internal because meson as no way to know if they are exposed in API or not. Up to the user to manually pass a list of deps to promote to requires or requires_private. |
0cea660
to
79a343f
Compare
pkgconf now supports |
Wow that was quick. |
It was literally one line of code to implement it as I proposed :) |
Edit: It is now implemented closer to @xclaesse 's proposal. |
Sure, but it means we have a way of getting a correct set of libraries with |
79a343f
to
b331ce6
Compare
run_unittests.py
Outdated
myenv = os.environ.copy() | ||
myenv['LD_LIBRARY_PATH'] = lib_dir | ||
self.assertTrue(os.path.isdir(lib_dir)) | ||
#self.assertTrue(os.path.isfile(os.path.join(lib_dir, 'libpkgdep.so'))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Flake8]
[E265] block comment should start with '# '
Try adding jon-turney@2e90399 to fix the new test on Cygwin. |
b331ce6
to
26a1fa6
Compare
run_unittests.py
Outdated
bin_dir = os.path.join(tempdirname, 'bin') | ||
myenv['PATH'] = bin_dir + os.pathsep + myenv['PATH'] | ||
self.assertTrue(os.path.isdir(lib_dir)) | ||
#self.assertTrue(os.path.isfile(os.path.join(lib_dir, 'libpkgdep.so'))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Flake8]
[E265] block comment should start with '# '
26a1fa6
to
cf5f1a8
Compare
Do not add private dependencies of shared libraries. Pkg-config leaks them out with
--cflags
and thus requires that all dependency dev libraries are installed when using this. That should not be required. If the thing to be installed is a static library, the dependencies are added because there is no other way.This will fail in CI because the old tests verifying pkg-config output obviously no longer work. @sarum9in and @xclaesse, you seemed to be the last persons to touch these. Could you check out what should be the correct way to fix those? Thanks.