-
-
Notifications
You must be signed in to change notification settings - Fork 649
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
Add meson build system #2637
Add meson build system #2637
Conversation
Hi @tintou, Thank you for this PR. Yes, we've been talking about switching build systems on libvips/devchat and meson is one of the front runners. If we can make this work well, we'd like to get rid of autotools completely. Anyway, thumbs up from me and I'll try to find time to try this out. |
if (glib_dep.version().version_compare('>=2.48')) | ||
cfg_var.set('HAVE_CHECKED_MUL', '1') | ||
endif | ||
if (glib_dep.version().version_compare('>=2.62')) | ||
cfg_var.set('HAVE_DATE_TIME_FORMAT_ISO8601', '1') | ||
endif |
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.
Note to myself: we can also swap these defines in config.h
with the GLIB_CHECK_VERSION
macro. That is:
#ifndef HAVE_CHECKED_MUL
->#if !GLIB_CHECK_VERSION( 2, 48, 0 )
#ifdef HAVE_DATE_TIME_FORMAT_ISO8601
->#if GLIB_CHECK_VERSION( 2, 62, 0 )
e52d680
to
efe3b12
Compare
test_fuzz = configure_file( | ||
input: 'test_fuzz.sh', | ||
output: 'test_fuzz.sh', | ||
copy: true, |
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.
Do you actually need this file? It does nothing other than define $ASAN_OPTIONS $UBSAN_OPTIONS $VIPS_WARNING and then run each of fuzz_execs in turn. You could easily implement that directly in meson. There's an env
kwarg:
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.
it might not be needed but I'm starting with a 1:1 port and we can simplify it once it is done 😃
0225ba8
to
9b8f3a0
Compare
bc2a4d0
to
36e6270
Compare
3a17198
to
c5f57c8
Compare
I think that I got almost everything covered, I only have to add the Doxygen support and it'll be ready for review |
It is now ready for review |
Thank you Corentin, I'm +1 for having to maintain configuration for only one build tool and am happy with meson as the replacement for autotools. To test this, I think we should ensure at least the following scripts/repos can successfully build libvips with meson/ninja. These scripts generate various combinations of binaries, shared and static libraries, using both native and cross compilation with gcc and clang on x64 and ARM64 machines, so I'd expect them to catch most things that might be missing. Do we want to remove autotools as part of this PR, or in a follow up? |
I don't mind. Maybe in a follow-up? It would make this PR easier to work with if it's a bit smaller. |
I'll test this today.
I don't mind either. A tick–tock strategy (as noted in #2538 (comment)) is probably more appropriate for downstream packagers. |
It's failing for me on ubuntu 21.10:
Something odd about |
The specific manner in which it succeeds for me is instructive.
|
f6915a6
to
ab8f3e5
Compare
Allows to use the Meson build system to build the project.
subdir('doc') | ||
endif | ||
subdir('cplusplus') | ||
subdir('man') |
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.
Would it be possible to wrap each of these last 5 subdir
directives ("man" through to "fuzz") with their own boolean options, defaulting to true, to allow building only the shared/static libraries without tools and tests? This is based on a discussion at lovell/sharp-libvips#127 (comment)
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 don't really see the point e.g. "man" just creates installation rules which have no build time effect, only an install-time effect. You can use meson install --tags runtime
to avoid installing any files tagged as man
, see https://mesonbuild.com/Installing.html#installation-tags for details.
For the other directories, they actually do create build rules, but those could for the most part be defined with build_by_default: false
if you don't want to make everyone automatically build them (they could be built by name if desired).
Granted Meson currently doesn't respect build_by_default for test executables, ideally they should not be built by ninja all
in that case but still get built by e.g. ninja test-prereq
and pulled in as a dependency of ninja test
. However, this theoretical test-prereq
is instead merged into all
and that's a bit annoying. We do intend to fix it, there's a WIP PR for it somewhere... in the meantime many people do have one project option "tests=false" which disables descending into tests/meson.build
or what have you.
Adding 5 different options seems like a lot of cognitive overhead for very little gain.
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.
Thank you, I agree, options fatigue is a real thing. Meson's use of a human-readable meson_options.txt
file and its ability to fail a build when it sees unknown options is a huge improvement. I wasn't aware of the predefined --tags
, very useful, thanks. I'd be happy with a single tests
boolean option, which I guess would prevent descent into the test
and fuzz
subdirs.
if librsvg_dep.version().version_compare('>=2.46') | ||
cfg_var.set('HAVE_RSVG_HANDLE_RENDER_DOCUMENT', '1') | ||
endif | ||
zlib_dep = dependency('zlib', version: '>=0.4', required: get_option('zlib')) |
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 we need to add zlib_dep = disabler()
outside this if-statement as well. Otherwise it would fail when configuring with -Drsvg=disabled
(noticed this on the WebAssembly build of libvips).
libvips/include/vips/meson.build:86:0: ERROR: Unknown variable "zlib_dep".
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.
A disabler is functionally identical to dependency('', required: false)
except for the special feature of disabling any meson.build statement that tries to use it directly rather than via the .found()
method.
This doesn't directly matter in the current PR, but may or may not be desirable in the general sense.
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.
In meson 0.59.0, you can use this: https://mesonbuild.com/Reference-manual_returned_feature.html#featurerequire
want_zlib = get_option('zlib').require(
librsvg_dep.found() and cairo_dep.found(),
error_message: 'librsvg and cairo not found'
)
This would then error out if -Dzlib=enabled
with the error message:
Feature zlib cannot be enabled: librsvg and cairo not found
Then you just search for zlib in the main flow, not inside an if block.
Currently if you define zlib as enabled but librsvg and/or cairo are optional + they aren't found, zlib simply gets ignored. Alas, that's the best you can do while still building with the version of Meson available on Debian stable. Perhaps add a comment to migrate to .require()
once the minimum version of Meson is updated?
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.
+1 for a comment to migrate to .require()
once we upgraded our minimum version to Meson 0.59.
Note to myself: the module logic here:
if gmodule_dep.get_variable(pkgconfig: 'gmodule_supported') != 'false'
modules_enabled = get_option('modules').enabled() or get_option('modules').auto()
elif get_option('modules').enabled()
error('GModule is not supported on your system, please reconfigure with -Dmodules=disabled')
else
modules_enabled = false
endif
could also be replaced with:
modules_enabled = get_option('modules').require(
gmodule_dep.get_variable(pkgconfig: 'gmodule_supported') != 'false',
error_message: 'GModule is not supported on your system, please reconfigure with -Dmodules=disabled
).allowed()
by then.
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.
Oh ha, that code is even more gnarly, fortunately Meson 0.59 can save us from complicated scripting logic.
] | ||
|
||
foreach tool : tools | ||
executable(tool, |
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.
Indentation is missing here.
script_data = configuration_data() | ||
script_data.set('prefix', get_option('prefix')) | ||
foreach script : scripts | ||
configure_file( |
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.
ditto.
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.
LGTM! The final comments can also be incorporated later.
cc = meson.get_compiler('c') | ||
cpp = meson.get_compiler('cpp') | ||
|
||
glib_dep = dependency('glib-2.0') |
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.
Note to myself: minimum required GLib version is missing here.
glib_dep = dependency('glib-2.0') | |
glib_dep = dependency('glib-2.0', version: '>=2.40') |
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.
Sorry, I didn't approve earlier. Looks good for my uses.
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.
Thank you!
OK, let's merge! Thank you very much for doing all this work, @tintou -- it's great improvement (something we've been avoiding for years) and I expect it'll be the main feature of 8.13. I'll add your name to the changelog with a large credit (hope that's OK). And thank you for your advice and assistance @eli-schwartz! |
I made an issue for tracking any small snags we find with the new build system here: #2650 Let's shift any discussion to that issue (this PR is large enough already). |
It is my pleasure to offer advice and reviews to people migrating to / updating their usage of meson. :) (Seriously. Feel free to |
Does this mean we can more easily compile statically linked libvips? When I try to cross-compile sharp with zig in centos7, I get the error: CC="zig cc -target x86_64-macos" CXX="zig c++ -target x86_64-macos" npx node-gyp rebuild
COPY Release/nothing.a
CXX(target) Release/obj.target/sharp-linux-x64/src/common.o
../src/common.cc:24:10: fatal error: 'vips/vips8' file not found
#include <vips/vips8>
^~~~~~~~~~~~
1 error generated.
make: *** [Release/obj.target/sharp-linux-x64/src/common.o] Error 1 I guess this is because the libvips that sharp relies on are dynamically linked. |
You can make a static library very simply with most build systems. With autotools try:
With meson it's:
Then compile a program with eg.:
I think you'll find the difficulty comes in making static versions of all the things that libvips depends on. |
@jcupitt Thanks for your reply, I found someone using staticx to do this, can you see if this way can make libvips dependencies static? |
staticx doesn't use static libraries, confusingly -- it's more like an executable zip file. You should be able to use it on any vips binary. That dockerfile is interesting, I'll try it here. |
I alluded to it earlier in this PR, but you can make static versions of all the things libvips depends on, using Meson subprojects:
And while this doesn't cover every one of libvips' dependencies, it covers a bunch of them and more could be added to the wrapdb. There is one slight flaw: checking for gmodule_supported doesn't (currently) work from a glib subproject, since the latest stable release of glib has to support versions of Meson too old to have support for defining variables in a declare_dependency. And this project is slightly too backwards compatible to support getting that variable anyway. The meson.build could be slightly tweaked to not actually check this in the -gmodule_dep = dependency('gmodule-no-export-2.0')
+gmodule_dep = dependency('gmodule-no-export-2.0', required: get_option('modules')) And change: if gmodule_dep.get_variable('gmodule_supported') != 'false'
modules_enabled = get_option('modules').enabled() or get_option('modules').auto()
elif get_option('modules').enabled()
error('GModule is not supported on your system, please reconfigure with -Dmodules=disabled')
else
modules_enabled = false
endif to (first two lines changed) if gmodule_dep.found() and gmodule_dep.get_variable('gmodule_supported') != 'false'
modules_enabled = true
elif get_option('modules').enabled()
error('GModule is not supported on your system, please reconfigure with -Dmodules=disabled')
else
modules_enabled = false
endif It's normally guaranteed to be found if glib is found at all. But if you explicitly disable it, then you:
|
@eli-schwartz huh that's interesting. It sounds like it'd be useful a little way down the line. |
Allows to use the Meson build system to build the project.
Note: This PR isn't complete yet but is opened to show the interest in using the meson build system.