From 6d83f4572d2cbf5bd2560dc85e7aa5a3e287e1f8 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Wed, 1 May 2024 12:17:27 -0700 Subject: [PATCH] More Meson work (#1025) This is follow up work to my previous series. I've tried to make the Meson build mirror the CMake build more closely. I've also made an attempt at adding some instructions to the documents on using Meson. --------- Signed-off-by: Henry Schreiner Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Henry Schreiner --- azure-pipelines.yml | 3 +- book/chapters/installation.md | 28 ++++++++++++- meson.build | 77 +++++++++++++++++++++++++++++++---- meson_options.txt | 2 + single-include/meson.build | 23 +++++++++++ tests/meson.build | 1 + tests/mesonTest/meson.build | 4 +- 7 files changed, 127 insertions(+), 11 deletions(-) create mode 100644 single-include/meson.build diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 647c7982..c2cbb7a5 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -100,7 +100,8 @@ jobs: displayName: generate test directories - script: ln -s "$(pwd)" tests/mesonTest/subprojects/CLI11 displayName: generate CLI11 symlink - - script: meson build + # Ensure that Meson doesn't use cmake or pkgconfig to find CLI11 + - script: meson setup build --force-fallback-for=CLI11 displayName: Run meson to generate build workingDirectory: tests/mesonTest - script: ninja -C tests/mesonTest/build diff --git a/book/chapters/installation.md b/book/chapters/installation.md index e1678a52..467638a0 100644 --- a/book/chapters/installation.md +++ b/book/chapters/installation.md @@ -51,7 +51,7 @@ If the CMake option `CLI11_PRECOMPILED` is set then the library is compiled into a static library. This can be used to improve compile times if CLI11 is included in many different parts of a project. -### Global Headers +#### Global Headers Use `CLI/*.hpp` files stored in a shared folder. You could check out the git repository to a system-wide folder, for example `/opt/`. With CMake, you could @@ -194,6 +194,32 @@ default to off if CLI11 is used as a subdirectory in another project. nothing special about this container. Alpine is being used because it is small, modern, and fast. Commands are similar on any other platform. +## Meson support + +### Global Headers from pkg-config + +If CLI11 is installed globally, then nothing more than `dependency('CLI11')` is +required. If it installed in a non-default search path, then setting the +`PKG_CONFIG_PATH` environment variable of the `--pkg-config-path` option to +`meson setup` is all that's required. + +### Using Meson's subprojects + +Meson has a system called +[wraps](https://mesonbuild.com/Wrap-dependency-system-manual.html), which allow +Meson to fetch sources, configure, and build dependencies as part of a main +project. This is the mechanism that Meson recommends for projects to use, as it +allows updating the dependency transparently, and allows packagers to have fine +grained control on the use of subprojects vs system provided dependencies. +Simply run `meson wrap install cli11` to install the `cli11.wrap` file, and +commit it, if desired. + +It is also possible to use git submodules. This is generally discouraged by +Meson upstream, but may be appropriate if a project needs to build with multiple +build systems and wishes to share subprojects between them. As long as the +submodule is in the parent project's subproject directory nothing additional is +needed. + ## Installing cli11 using vcpkg You can download and install cli11 using the diff --git a/meson.build b/meson.build index 1b6d98e9..004bd615 100644 --- a/meson.build +++ b/meson.build @@ -7,9 +7,78 @@ project('CLI11', ['cpp'], cxx = meson.get_compiler('cpp') +use_single_header = get_option('single-file-header') +use_precompiled = get_option('precompiled') + +if use_precompiled and use_single_header + error('Options "single-file"header" and "precompiled" are mutually exclusive') +endif + +cli11_headers = files( + 'include/CLI/App.hpp', + 'include/CLI/Argv.hpp', + 'include/CLI/CLI.hpp', + 'include/CLI/Config.hpp', + 'include/CLI/ConfigFwd.hpp', + 'include/CLI/Encoding.hpp', + 'include/CLI/Error.hpp', + 'include/CLI/Formatter.hpp', + 'include/CLI/FormatterFwd.hpp', + 'include/CLI/Macros.hpp', + 'include/CLI/Option.hpp', + 'include/CLI/Split.hpp', + 'include/CLI/StringTools.hpp', + 'include/CLI/TypeTools.hpp', + 'include/CLI/Validators.hpp', + 'include/CLI/Version.hpp', +) + +cli11_impl_headers = files( + 'include/CLI/impl/App_inl.hpp', + 'include/CLI/impl/Argv_inl.hpp', + 'include/CLI/impl/Config_inl.hpp', + 'include/CLI/impl/Encoding_inl.hpp', + 'include/CLI/impl/Formatter_inl.hpp', + 'include/CLI/impl/Option_inl.hpp', + 'include/CLI/impl/Split_inl.hpp', + 'include/CLI/impl/StringTools_inl.hpp', + 'include/CLI/impl/Validators_inl.hpp', +) + +subdir('single-include') + CLI11_inc = include_directories(['include']) +warnings = ['-Wshadow', '-Wsign-conversion', '-Wswitch-enum'] +if cxx.get_id() == 'gcc' and cxx.version().version_compare('>=4.9') + warnings += '-Weffc++' +endif +if cxx.get_id() == 'clang' + warnings += [ + '-Wcast-align', + '-Wimplicit-atomic-properties', + '-Wmissing-declarations', + '-Woverlength-strings', + '-Wstrict-selector-match', + '-Wundeclared-selector', + ] +endif +add_project_arguments(cxx.get_supported_arguments(warnings), language: 'cpp') + +if use_precompiled + libcli11 = static_library( + 'CLI11', + 'src/Precompile.cpp', + include_directories : CLI11_inc, + cpp_args : ['-DCLI11_COMPILE'], + ) +else + libcli11 = [] +endif + CLI11_dep = declare_dependency( + sources : single_header, + link_with : libcli11, include_directories : CLI11_inc, version : meson.project_version(), ) @@ -17,11 +86,5 @@ CLI11_dep = declare_dependency( meson.override_dependency('CLI11', CLI11_dep) if get_option('tests') - warnings = ['-Wshadow', '-Wsign-conversion', '-Wswitch-enum'] - if cxx.get_id() == 'gcc' and cxx.version().version_compare('>=4.9') - warnings += '-Weffc++' - endif - add_project_arguments(cxx.get_supported_arguments(warnings), language: 'cpp') - - subdir('tests') + subdir('tests') endif diff --git a/meson_options.txt b/meson_options.txt index dd4654d4..f32583d8 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1 +1,3 @@ option('tests', type: 'boolean', value: false, description: 'Build CLI11 tests') +option('single-file-header', type: 'boolean', value: false, description : 'Generate a single header file.') +option('precompiled', type: 'boolean', value: false, description : 'Generate a precompiled static library instead of a header-only') diff --git a/single-include/meson.build b/single-include/meson.build new file mode 100644 index 00000000..ee58adf6 --- /dev/null +++ b/single-include/meson.build @@ -0,0 +1,23 @@ +# Because Meson does not allow outputs to be placed in subfolders, we must have +# meson.build here when generating the single file header so that it is placced +# in the correct location. + +prog_python = find_program('python') + +single_main_file = files('CLI11.hpp.in') + +if use_single_header + single_header = custom_target( + 'CLI11.hpp', + input: [files('../scripts/MakeSingleHeader.py'), cli11_headers, cli11_impl_headers], + output: 'CLI11.hpp', + command : [prog_python, '@INPUT@', '--main', single_main_file, '--output', '@OUTPUT@'], + depend_files: [single_main_file], + ) +else + # the `declare_dependency` needs to have the single_header source as a source + # dependency, to ensure that the generator runs before any attempts to include + # the header happen. Adding an empty list is an idiomatic way to ensure the + # variable exists but does nothing + single_header = [] +endif diff --git a/tests/meson.build b/tests/meson.build index 7fd05a4b..510bfced 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -58,6 +58,7 @@ testnames = [ ['ComplexTypeTest', {}], ['TrueFalseTest', {}], ['OptionGroupTest', {}], + ['EncodingTest', {}], # multi-only ['TimerTest', {}], # link_test diff --git a/tests/mesonTest/meson.build b/tests/mesonTest/meson.build index 56ebadb6..9fa9d385 100644 --- a/tests/mesonTest/meson.build +++ b/tests/mesonTest/meson.build @@ -1,5 +1,5 @@ -project('mesonTest', ['c', 'cpp'], default_options: ['cpp_std=c++11']) +project('mesonTest', ['cpp'], default_options: ['cpp_std=c++11']) -cli11_dep = subproject('CLI11').get_variable('CLI11_dep') +cli11_dep = dependency('CLI11') mainExe = executable('main', ['main.cpp'], dependencies: [cli11_dep])