Skip to content
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

[RFC] add prefer_static built-in option #9603

Merged
merged 2 commits into from
May 4, 2022

Conversation

Dudemanguy
Copy link
Contributor

@Dudemanguy Dudemanguy commented Nov 21, 2021

By default, meson will try to look for shared libraries first before
static ones. In the meson.build itself, one can use the static keyword
to control if a static library will be tried first but there's no simple
way for an end user performing a build to switch back and forth at will.
Let's cover this usecase by adding an option that allows a user to
specify if they want dependency lookups to try static or shared
libraries first. The writer of the meson.build can manually specify the
static keyword where appropriate which will override the value of this
option.

I suppose this needs test cases to go with it? I was a bit lost on where exactly tests should be made/created so that was left out for now (guidance would be appreciated).

Fixes #2816
Fixes #4276
Fixes #6109
Fixes #6629
Fixes #7621

@Dudemanguy Dudemanguy requested a review from jpakkane as a code owner November 21, 2021 20:34
@codecov
Copy link

codecov bot commented Nov 21, 2021

Codecov Report

Merging #9603 (2a12518) into master (acef5a9) will increase coverage by 0.00%.
The diff coverage is 75.00%.

Impacted file tree graph

@@           Coverage Diff           @@
##           master    #9603   +/-   ##
=======================================
  Coverage   67.80%   67.80%           
=======================================
  Files         400      400           
  Lines       85522    85532   +10     
  Branches    18825    18827    +2     
=======================================
+ Hits        57987    57997   +10     
+ Misses      23035    23033    -2     
- Partials     4500     4502    +2     
Impacted Files Coverage Δ
mesonbuild/coredata.py 83.74% <ø> (ø)
mesonbuild/dependencies/__init__.py 100.00% <ø> (ø)
mesonbuild/dependencies/misc.py 55.30% <0.00%> (+0.15%) ⬆️
mesonbuild/mesonlib/universal.py 81.61% <ø> (+0.23%) ⬆️
mesonbuild/interpreter/compiler.py 93.27% <50.00%> (-0.38%) ⬇️
mesonbuild/dependencies/base.py 85.07% <100.00%> (ø)
mesonbuild/dependencies/hdf5.py 85.98% <100.00%> (ø)
mesonbuild/dependencies/scalapack.py 38.15% <100.00%> (+1.67%) ⬆️
mesonbuild/scripts/vcstagger.py 87.50% <0.00%> (-4.17%) ⬇️
interpreter/compiler.py 93.27% <0.00%> (-0.38%) ⬇️
... and 6 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update acef5a9...2a12518. Read the comment docs.

@eli-schwartz
Copy link
Member

This would probably solve:

#2816
#4276
#6109
#6629
#7621

@Dudemanguy Dudemanguy force-pushed the prefer_static branch 2 times, most recently from e19f693 to af20ebe Compare November 21, 2021 23:09
@Dudemanguy
Copy link
Contributor Author

Fixed the tests.

Copy link
Member

@eli-schwartz eli-schwartz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks like a nice change to make.

While we are here, though, there are a couple things that should be cleaned up on general principle, and if you do clean them up, it means actually implementing this new feature changes fewer lines. With that in mind...

@@ -51,7 +51,8 @@ def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.
newinc = [] # type: T.List[str]
for arg in self.compile_args:
if arg.startswith('-I'):
stem = 'static' if kwargs.get('static', False) else 'shared'
static_opt = environment.coredata.get_option(OptionKey('prefer_static'))
stem = 'static' if kwargs.get('static', static_opt) else 'shared'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kwargs.get('static', False) seems sub-optimal and as a general cleanup we can probably use self.static here (as anywhere that inherits from ExternalDependency).

args = self.get_config_value(['-show', '-c'], 'args')[1:]
args += self.get_config_value(['-show', '-noshlib' if kwargs.get('static', False) else '-shlib'], 'args')[1:]
args += self.get_config_value(['-show', '-noshlib' if kwargs.get('static', static_opt) else '-shlib'], 'args')[1:]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likewise here.

@@ -175,7 +175,7 @@ def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.
return

self.name = 'python3'
self.static = kwargs.get('static', False)
self.static = kwargs.get('static', environment.coredata.get_option(mesonlib.OptionKey('prefer_static')))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems odd! Why does this line exist, it seems to be literally overriding the existing self.static attribute...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean that this is attribute is already inherited from base.py? Yeah, I can just delete the line in that case.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is exactly what I mean. :)

@@ -537,7 +537,7 @@ def shaderc_factory(env: 'Environment',
shared_libs = ['shaderc']
static_libs = ['shaderc_combined', 'shaderc_static']

if kwargs.get('static', False):
if kwargs.get('static', env.coredata.get_option(mesonlib.OptionKey('prefer_static'))):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This, however, is a function, not a class, so kwargs.get() is correct as is your modification.

static = Mesonlib.LibType.STATIC if kwargs.get('static', False) else Mesonlib.LibType.SHARED
get_option = environment.coredata.get_option
static_opt = kwargs.get('static', get_option(Mesonlib.OptionKey('prefer_static'))
static = Mesonlib.LibType.STATIC if static_opt else Mesonlib.LibType.SHARED
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this change still be here? All of this is comments so I guess it doesn't matter too much, but I don't want to add wrong things in here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this documentation is, in part, showing how it all fits together. So I believe it is correct to demonstrate the underlying implementation. IIRC a major motivation in adding this comment section was so that we could move from one core dev understanding how the mesonbuild/dependencies/ directory works, to multiple core devs understanding.

After all, there is also a self.libtype which can technically be used too, but that doesn't obsolete the comment tutorial either.

@lgtm-com
Copy link

lgtm-com bot commented Jan 11, 2022

This pull request introduces 1 alert when merging 92dd836 into e77582b - view on LGTM.com

new alerts:

  • 1 for Unused import

@Dudemanguy
Copy link
Contributor Author

Split this into two commits now and rebased.

@xclaesse
Copy link
Member

I haven't looked at code, does it cover both dependency() and find_library()? This new option is better than nothing but unfortunately it's a all-or-nothing option. Ideally we should have more fine grained way of telling which deps should be static and which should be shared.

A long time ago I made that attempt: #4276, and a few others, but we never agreed on a good solution.

The use-case I still have is when you build an app (e.g. GStreamer) for a platform that provide shared libs for some basic deps (e.g. zlib). In that case I want to use the shared libs for stuff provided by the device's base platform and static link everything else into my app.

@xclaesse
Copy link
Member

That said, since we had that use-case for years and we never found an elegant enough solution, I wouldn't block this PR that already covers a good part of the use-case.

@Dudemanguy
Copy link
Contributor Author

I haven't looked at code, does it cover both dependency() and find_library()?

That's a really good point. This does not cover find_library() and it really should. I'll fix that.

@Dudemanguy Dudemanguy force-pushed the prefer_static branch 2 times, most recently from 8392fe9 to b183005 Compare January 21, 2022 03:47
@Dudemanguy
Copy link
Contributor Author

Dudemanguy commented Jan 21, 2022

I added support to find_library now. I noticed that static works differently in find_library than it does in dependency. In dependency, it's merely just a preference and always tries the fallback if it fails. However in find_library, explicitly setting the static kwarg makes it a hard value (i.e. it will either only try static or only try shared). If you just don't set anything (i.e. the default), then it acts as a prefer shared. So the only thing that was missing was a prefer static (but fallback to shared) setting. That was just another elif statement.

In a couple of spots, kwargs.get('static', False) was being
unneccesarily used. In these spots, we can just use self.static instead
which is already inherited from the ExternalDependency. In additional,
the python system dependency oddly has a kwargs.get('static', False)
line which overrides the self.static in that dependency for no real
reason. Delete this line too.
By default, meson will try to look for shared libraries first before
static ones. In the meson.build itself, one can use the static keyword
to control if a static library will be tried first but there's no simple
way for an end user performing a build to switch back and forth at will.
Let's cover this usecase by adding an option that allows a user to
specify if they want dependency lookups to try static or shared
libraries first. The writer of the meson.build can manually specify the
static keyword where appropriate which will override the value of this
option.
@ePirat
Copy link
Contributor

ePirat commented Feb 23, 2022

This would be an incredibly useful to have feature for VLC's WIP meson port, currently we clutter every dependency and find_library with the static kwarg to get this ability.

@xclaesse
Copy link
Member

xclaesse commented Feb 24, 2022

Throwing just an idea: what I often want is use shared libraries from the system, and if not found build a static fallback subproject. Not sure how we could try to express that use-case, -Dprefer_static=subprojects ?

@eli-schwartz
Copy link
Member

Perhaps the prefer_static option should cause all subprojects to default to static lookup? IIRC we already special case dependency('foo', static: true) to pass default_library=static as a subproject default option. Perhaps we should check this option there too in the case that the static kwarg is None.

@xclaesse
Copy link
Member

xclaesse commented Feb 24, 2022

IIRC we already special case dependency('foo', static: true) to pass default_library=static as a subproject default option

Yes we do that, so if I understand correctly prefer_static as proposed would already build static subprojects. However my use-case is a little bit different: I build GStreamer against a platform SDK that contains a few basic libraries (e.g. zlib, openssl) and I want to use the shared libraries provided by the platform for them. But everything else that is not part of the SDK is built as subproject and those would be nice to be static.

So dependency('zlib', fallback: 'zlib') with -Dprefer_static=subprojects would return the shared lib from system, or static lib from fallback subproject. If we make that option a combo [true, false, subprojects] instead of boolean, it should actually be pretty easy to implement. That said, it can also be extended later.

@Dudemanguy
Copy link
Contributor Author

Dudemanguy commented Feb 24, 2022

Yes we do that, so if I understand correctly prefer_static as proposed would already build static subprojects.

Well this PR currently only touches code related to dependency and find_library. I'm not sure if that's all that is required and the subproject case automatically inherits the method or if more changes are required.

So dependency('zlib', fallback: 'zlib') with -Dprefer_static=subprojects would return the shared lib from system, or static lib from fallback subproject.

If such an option is added, would it make sense to turn the static kwarg to a combo option like that as well? The main intent of this PR was to simply mimic the static kwarg but on a global level, so I would think any new options should also propagate downwards.

@Dudemanguy
Copy link
Contributor Author

@xclaesse: Just revisiting this one, but if I understand correctly, would your usecase be covered if prefer_static is allowed to be set per-subproject like default_library? That way you could just set per subproject options for those to be static and everything else would do shared lookups. I can add a commit for that. It's not complicated.

As a sidenote, I finally got around to confirming that yes, subprojects do inherit the prefer_static argument so they all do static lookups as well (as expected).

@Tachi107
Copy link
Contributor

Throwing just an idea: what I often want is use shared libraries from the system, and if not found build a static fallback subproject. Not sure how we could try to express that use-case, -Dprefer_static=subprojects ?

Doesn't dependency('name', default_options: 'default_library=static') already cover this use case?

@xclaesse
Copy link
Member

xclaesse commented Apr 30, 2022

Yes, but it means editing entry dependency() calls. I would like instead a global switch for that. Preferring static or shared is often a user choice rather than a project choice.

@xclaesse
Copy link
Member

xclaesse commented May 3, 2022

Doesn't dependency('name', default_options: 'default_library=static') already cover this use case?

Re-thinking about this, subprojects inherit default_library=static from main project by default, so as long as it's fine to also have the main project built with default_library=static my use-case is already covered. More fine grained would still be nice, but probably out of scope for this PR.

Ultimately, we could add a list of libs/deps in native/cross file that tells exactly which one should be static.

@Dudemanguy
Copy link
Contributor Author

Anything else that this PR needs?

@eli-schwartz
Copy link
Member

No, I don't think so. And it seems we're all in agreement that this option is useful as it stands.

@eli-schwartz eli-schwartz merged commit 557680f into mesonbuild:master May 4, 2022
@Dudemanguy
Copy link
Contributor Author

Thanks!

@Dudemanguy Dudemanguy deleted the prefer_static branch May 4, 2022 03:22
leotaku added a commit to leotaku/tomie that referenced this pull request Jul 14, 2022
@sertonix
Copy link
Contributor

sertonix commented Jul 29, 2024

Could this be added to the documentation? The reference manual doesn't mention prefer_static at all: https://mesonbuild.com/Reference-manual_functions.html#dependency

Ref #3084

@Dudemanguy
Copy link
Contributor Author

Dudemanguy commented Jul 29, 2024

It's a built-in option. You can see it here. https://mesonbuild.com/Builtin-options.html#core-options

@eli-schwartz
Copy link
Member

I have no objection to also adding a reference to the builtin option, in the documentation for dependency(). ;)

@sertonix would you like to submit a patch for this?

sertonix added a commit to sertonix/meson that referenced this pull request Jul 30, 2024
sertonix added a commit to sertonix/meson that referenced this pull request Jul 31, 2024
jpakkane pushed a commit that referenced this pull request Aug 4, 2024
serebit pushed a commit to serebit/meson that referenced this pull request Feb 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Feature wish: Option to force static:true for all dependency() calls
6 participants