From 3990754bf55727ef5593769b48f0a03c6b7a3671 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Mon, 1 Mar 2021 22:05:19 -0500 Subject: [PATCH] Allow add_dist_script() in subprojects Fixes: #8440. --- docs/markdown/Reference-manual.md | 21 +++++++++++++------ docs/markdown/snippets/dist_script.md | 14 +++++++++++++ mesonbuild/interpreter.py | 3 ++- mesonbuild/mdist.py | 16 +++++++++----- run_unittests.py | 4 ++++ test cases/unit/35 dist script/meson.build | 2 ++ .../subprojects/sub/dist-script.py | 12 +++++++++++ .../subprojects/sub/meson.build | 11 ++++++++++ .../subprojects/sub/meson_options.txt | 1 + .../35 dist script/subprojects/sub/prog.c | 1 + 10 files changed, 73 insertions(+), 12 deletions(-) create mode 100644 docs/markdown/snippets/dist_script.md create mode 100644 test cases/unit/35 dist script/subprojects/sub/dist-script.py create mode 100644 test cases/unit/35 dist script/subprojects/sub/meson.build create mode 100644 test cases/unit/35 dist script/subprojects/sub/meson_options.txt create mode 100644 test cases/unit/35 dist script/subprojects/sub/prog.c diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index d81be4756..6e18e6852 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -1907,16 +1907,25 @@ the following methods. archived. Note that this runs the script file that is in the _staging_ directory, not the one in the source directory. If the script file can not be found in the staging directory, it is a hard - error. This command can only invoked from the main project, calling - it from a subproject is a hard error. *(since 0.49.0)* Accepts multiple arguments - for the script. *(since 0.54.0)* The `MESON_SOURCE_ROOT` and `MESON_BUILD_ROOT` - environment variables are set when dist scripts are run. - + error. The `MESON_DIST_ROOT` environment variables is set when dist scripts is + run. + *(since 0.49.0)* Accepts multiple arguments for the script. + *(since 0.54.0)* The `MESON_SOURCE_ROOT` and `MESON_BUILD_ROOT` + environment variables are set when dist scripts are run. They are path to the + root source and build directory of the main project, even when the script + comes from a subproject. *(since 0.55.0)* The output of `configure_file`, `files`, and `find_program` as well as strings. - *(since 0.57.0)* `file` objects and the output of `configure_file` may be used as the `script_name` parameter. + *(since 0.58.0)* This command can be invoked from a subproject, it was a hard + error in earlier versions. Subproject dist scripts will only be executed + when running `meson dist --include-subprojects`. `MESON_PROJECT_SOURCE_ROOT`, + `MESON_PROJECT_BUILD_ROOT` and `MESON_PROJECT_DIST_ROOT` environment + variables are set when dist scripts are run. They are identical to + `MESON_SOURCE_ROOT`, `MESON_BUILD_ROOT` and `MESON_DIST_ROOT` for main project + scripts, but for subproject scripts they have the path to the root of the + subproject appended, usually `subprojects/`. - `add_install_script(script_name, arg1, arg2, ...)`: causes the script given as an argument to be run during the install step, this script diff --git a/docs/markdown/snippets/dist_script.md b/docs/markdown/snippets/dist_script.md new file mode 100644 index 000000000..93b97aafe --- /dev/null +++ b/docs/markdown/snippets/dist_script.md @@ -0,0 +1,14 @@ +## `meson.add_dist_script()` allowd in subprojects + +`meson.add_dist_script()` can now be invoked from a subproject, it was a hard +error in earlier versions. Subproject dist scripts will only be executed +when running `meson dist --include-subprojects`. `MESON_PROJECT_SOURCE_ROOT`, +`MESON_PROJECT_BUILD_ROOT` and `MESON_PROJECT_DIST_ROOT` environment variables +are set when dist scripts are run. They are identical to `MESON_SOURCE_ROOT`, +`MESON_BUILD_ROOT` and `MESON_DIST_ROOT` for main project scripts, but for +subproject scripts they have the path to the root of the subproject appended, +usually `subprojects/`. + +Note that existing dist scripts likely need to be modified to use those new +environment variables instead of `MESON_DIST_ROOT` to work properly when used +from a subproject. diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index ac0d786c6..6a51f3d99 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -2028,7 +2028,8 @@ class MesonMain(InterpreterObject): FeatureNew.single_use('Passing file object to script parameter of add_dist_script', '0.57.0', self.interpreter.subproject) if self.interpreter.subproject != '': - raise InterpreterException('add_dist_script may not be used in a subproject.') + FeatureNew.single_use('Calling "add_dist_script" in a subproject', + '0.58.0', self.interpreter.subproject) script_args = self._process_script_args('add_dist_script', args[1:], allow_built=True) script = self._find_source_script(args[0], script_args) self.build.dist_scripts.append(script) diff --git a/mesonbuild/mdist.py b/mesonbuild/mdist.py index 3085f44f1..36bad71b6 100644 --- a/mesonbuild/mdist.py +++ b/mesonbuild/mdist.py @@ -78,13 +78,19 @@ def process_submodules(dirname): del_gitfiles(os.path.join(dirname, v)) -def run_dist_scripts(src_root, bld_root, dist_root, dist_scripts): +def run_dist_scripts(src_root, bld_root, dist_root, dist_scripts, subprojects): assert(os.path.isabs(dist_root)) env = {} env['MESON_DIST_ROOT'] = dist_root env['MESON_SOURCE_ROOT'] = src_root env['MESON_BUILD_ROOT'] = bld_root for d in dist_scripts: + if d.subproject and d.subproject not in subprojects: + continue + subdir = subprojects.get(d.subproject, '') + env['MESON_PROJECT_DIST_ROOT'] = os.path.join(dist_root, subdir) + env['MESON_PROJECT_SOURCE_ROOT'] = os.path.join(src_root, subdir) + env['MESON_PROJECT_BUILD_ROOT'] = os.path.join(bld_root, subdir) name = ' '.join(d.cmd_args) print(f'Running custom dist script {name!r}') try: @@ -141,7 +147,7 @@ def git_clone(src_root, distdir): def create_dist_git(dist_name, archives, src_root, bld_root, dist_sub, dist_scripts, subprojects): distdir = os.path.join(dist_sub, dist_name) git_clone(src_root, distdir) - for path in subprojects: + for path in subprojects.values(): sub_src_root = os.path.join(src_root, path) sub_distdir = os.path.join(distdir, path) if os.path.exists(sub_distdir): @@ -150,7 +156,7 @@ def create_dist_git(dist_name, archives, src_root, bld_root, dist_sub, dist_scri git_clone(sub_src_root, sub_distdir) else: shutil.copytree(sub_src_root, sub_distdir) - run_dist_scripts(src_root, bld_root, distdir, dist_scripts) + run_dist_scripts(src_root, bld_root, distdir, dist_scripts, subprojects) output_names = [] for a in archives: compressed_name = distdir + archive_extension[a] @@ -278,13 +284,13 @@ def run(options): archives = determine_archives_to_generate(options) - subprojects = [] + subprojects = {} extra_meson_args = [] if options.include_subprojects: subproject_dir = os.path.join(src_root, b.subproject_dir) for sub in b.subprojects: directory = wrap.get_directory(subproject_dir, sub) - subprojects.append(os.path.join(b.subproject_dir, directory)) + subprojects[sub] = os.path.join(b.subproject_dir, directory) extra_meson_args.append('-Dwrap_mode=nodownload') if is_git(src_root): diff --git a/run_unittests.py b/run_unittests.py index 03e931a9b..82689be8a 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -3189,6 +3189,10 @@ class AllPlatformTests(BasePlatformTests): _git_init(project_dir) self.init(project_dir) self.build('dist') + + self.new_builddir() + self.init(project_dir, extra_args=['-Dsub:broken_dist_script=false']) + self._run(self.meson_command + ['dist', '--include-subprojects'], workdir=self.builddir) except PermissionError: # When run under Windows CI, something (virus scanner?) # holds on to the git files so cleaning up the dir diff --git a/test cases/unit/35 dist script/meson.build b/test cases/unit/35 dist script/meson.build index 2ae943845..8db42358a 100644 --- a/test cases/unit/35 dist script/meson.build +++ b/test cases/unit/35 dist script/meson.build @@ -6,3 +6,5 @@ test('compare', exe) meson.add_dist_script('replacer.py', '"incorrect"', '"correct"') meson.add_dist_script(find_program('replacer.py'), '"incorrect"', '"correct"') + +subproject('sub') diff --git a/test cases/unit/35 dist script/subprojects/sub/dist-script.py b/test cases/unit/35 dist script/subprojects/sub/dist-script.py new file mode 100644 index 000000000..1274f291b --- /dev/null +++ b/test cases/unit/35 dist script/subprojects/sub/dist-script.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python3 + +import os +import pathlib +import sys + +assert sys.argv[1] == 'success' + +source_root = pathlib.Path(os.environ['MESON_PROJECT_DIST_ROOT']) +modfile = source_root / 'prog.c' +with modfile.open('w') as f: + f.write('int main(){return 0;}') diff --git a/test cases/unit/35 dist script/subprojects/sub/meson.build b/test cases/unit/35 dist script/subprojects/sub/meson.build new file mode 100644 index 000000000..612861310 --- /dev/null +++ b/test cases/unit/35 dist script/subprojects/sub/meson.build @@ -0,0 +1,11 @@ +project('sub') + +if get_option('broken_dist_script') + # Make sure we can add a dist script in a subproject, but it won't be run + # if not using --include-subprojects. + meson.add_dist_script('dist-script.py', 'broken') +else + # The dist script replace prog.c with something that actually build. + meson.add_dist_script('dist-script.py', 'success') + executable('prog', 'prog.c') +endif diff --git a/test cases/unit/35 dist script/subprojects/sub/meson_options.txt b/test cases/unit/35 dist script/subprojects/sub/meson_options.txt new file mode 100644 index 000000000..8f52e0f87 --- /dev/null +++ b/test cases/unit/35 dist script/subprojects/sub/meson_options.txt @@ -0,0 +1 @@ +option('broken_dist_script', type: 'boolean', value: true) diff --git a/test cases/unit/35 dist script/subprojects/sub/prog.c b/test cases/unit/35 dist script/subprojects/sub/prog.c new file mode 100644 index 000000000..049b36ab2 --- /dev/null +++ b/test cases/unit/35 dist script/subprojects/sub/prog.c @@ -0,0 +1 @@ +#error This should be replaced by a program during dist