diff --git a/mesonbuild/cargo/interpreter.py b/mesonbuild/cargo/interpreter.py index 1423d7629..c3d728bd7 100644 --- a/mesonbuild/cargo/interpreter.py +++ b/mesonbuild/cargo/interpreter.py @@ -124,13 +124,13 @@ class PackageState: def has_both_machines(self) -> bool: return bool(self.cfg.host and self.cfg.build) - def get_env_dict(self, environment: Environment, subdir: str) -> T.Dict[str, str]: + def get_env_dict(self, environment: Environment, subdir: str, build_subdir: str) -> T.Dict[str, str]: """Get environment variables for this package.""" # Common variables for build.rs and crates # https://doc.rust-lang.org/cargo/reference/environment-variables.html # OUT_DIR is the directory where build.rs generate files. In our case, # it's the directory where meson/meson.build places generated files. - out_dir = os.path.join(environment.build_dir, subdir, 'meson') + out_dir = os.path.join(environment.build_dir, build_subdir, 'meson') os.makedirs(out_dir, exist_ok=True) version_arr = self.manifest.package.version.split('.') version_arr += [''] * (4 - len(version_arr)) diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index daf426b36..caea50305 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -2864,7 +2864,7 @@ class Interpreter(InterpreterBase, HoldableObject): raise InvalidArguments(f'Build subdir "{build_subdir}" in "{target}" exists in source tree.') if '..' in build_subdir: raise InvalidArguments(f'Build subdir "{build_subdir}" in "{target}" contains ..') - self.create_build_subdir(os.path.join(self.subdir, build_subdir)) + self.create_build_subdir(os.path.join(self.current_build_dir(), build_subdir)) @TypedArgs( 'configure_file', @@ -2971,7 +2971,7 @@ class Interpreter(InterpreterBase, HoldableObject): build_subdir = kwargs['build_subdir'] self.validate_build_subdir(build_subdir, output) - ofile_rpath = os.path.join(self.subdir, build_subdir, output) + ofile_rpath = os.path.join(self.current_build_dir(), build_subdir, output) if ofile_rpath in self.configure_file_outputs: mesonbuildfile = os.path.join(self.subdir, 'meson.build') current_call = f"{mesonbuildfile}:{self.current_node.lineno}" @@ -3058,7 +3058,7 @@ class Interpreter(InterpreterBase, HoldableObject): elif kwargs['copy']: if len(inputs_abs) != 1: raise InterpreterException('Exactly one input file must be given in copy mode') - self.create_build_subdir(self.subdir) + self.create_build_subdir(self.current_build_dir()) shutil.copyfile(inputs_abs[0], ofile_abs) src_stat = os.stat(inputs_abs[0]) os.utime(ofile_abs, ns=(src_stat.st_atime_ns, src_stat.st_mtime_ns)) @@ -3083,7 +3083,7 @@ class Interpreter(InterpreterBase, HoldableObject): install_tag = kwargs['install_tag'] self.build.data.append(build.Data([cfile], idir, idir_name, install_mode, self.subproject, install_tag=install_tag, data_type='configure')) - return mesonlib.File.from_built_file(self.subdir, output) + return mesonlib.File.from_built_file(self.current_build_dir(), output) def extract_incdirs(self, prospectives: T.List[T.Union[str, build.IncludeDirs]], is_d_import_dirs: bool = False @@ -3569,7 +3569,7 @@ class Interpreter(InterpreterBase, HoldableObject): self.environment.build_dir) results.append(mesonlib.File.from_built_relative(rel)) else: - results.append(mesonlib.File.from_built_file(self.subdir, s)) + results.append(mesonlib.File.from_built_file(self.current_build_dir(), s)) continue except SandboxViolationError: if not self.relaxed(InterpreterRuleRelaxation.ALLOW_SANDBOX_VIOLATION): @@ -4232,6 +4232,16 @@ class Interpreter(InterpreterBase, HoldableObject): def is_subproject(self) -> bool: return self.subproject != '' + def current_build_dir(self) -> str: + """Return the directory of the current meson.build in the build tree, relative to the build directory. + + Unlike self.subdir, which is relative to the source tree, this has a different + prefix for subprojects that are built for the build machine. + """ + project = self.current_build_project() + # self.subdir is always inside the directory of the subproject. + return project.builddir + self.subdir[len(project.subdir):] + @TypedArgs( 'set_variable', pos_types=[ diff --git a/mesonbuild/interpreter/mesonmain.py b/mesonbuild/interpreter/mesonmain.py index d36966579..eafcf83e3 100644 --- a/mesonbuild/interpreter/mesonmain.py +++ b/mesonbuild/interpreter/mesonmain.py @@ -202,7 +202,7 @@ class MesonMain(MesonInterpreterObject): @InterpreterObject.method('current_build_dir') def current_build_dir_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str: src = self.interpreter.environment.build_dir - sub = self.interpreter.subdir + sub = self.interpreter.current_build_dir() if sub == '': return src return os.path.join(src, sub) diff --git a/mesonbuild/modules/__init__.py b/mesonbuild/modules/__init__.py index 3c5e5c538..29f934ee4 100644 --- a/mesonbuild/modules/__init__.py +++ b/mesonbuild/modules/__init__.py @@ -42,6 +42,7 @@ class ModuleState: self.subproject_dir = interpreter.subproject_dir self.subproject = interpreter.subproject self.subdir = interpreter.subdir + self.current_build_dir = interpreter.current_build_dir() self.root_subdir = interpreter.root_subdir self.environment = interpreter.environment self.project_name = interpreter.active_projectname @@ -72,7 +73,7 @@ class ModuleState: dirs_str.extend([f'{prefix}{i}' for i in dirs.abs_string_list(srcdir, builddir)]) if implicit: - build_cur_dir = os.path.normpath(os.path.join(builddir, self.subdir)) + build_cur_dir = os.path.normpath(os.path.join(builddir, self.current_build_dir)) dirs_str.append(f'{prefix}{build_cur_dir}') source_cur_dir = os.path.normpath(os.path.join(srcdir, self.subdir)) dirs_str.append(f'{prefix}{source_cur_dir}') diff --git a/mesonbuild/modules/_qt.py b/mesonbuild/modules/_qt.py index fdbf2ffc4..c8f50c2e4 100644 --- a/mesonbuild/modules/_qt.py +++ b/mesonbuild/modules/_qt.py @@ -375,7 +375,7 @@ class QtBaseModule(ExtensionModule): path_from_rcc = os.path.normpath(os.path.join(rcc_dirname, resource_path)) # a) if path_from_rcc.startswith(state.environment.build_dir): - result.append(File(is_built=True, subdir=state.subdir, fname=resource_path)) + result.append(File(is_built=True, subdir=state.current_build_dir, fname=resource_path)) # b) else: result.append(File(is_built=False, subdir=state.subdir, fname=path_from_rcc)) @@ -706,7 +706,7 @@ class QtBaseModule(ExtensionModule): raise MesonException('qt.compile_translations: Cannot specify both ts_files and qresource') if os.path.dirname(qresource) != '': raise MesonException('qt.compile_translations: qresource file name must not contain a subdirectory.') - qresource_file = File.from_built_file(state.subdir, qresource) + qresource_file = File.from_built_file(state.current_build_dir, qresource) infile_abs = os.path.join(state.environment.source_dir, qresource_file.relative_name()) outfile_abs = os.path.join(state.environment.build_dir, qresource_file.relative_name()) os.makedirs(os.path.dirname(outfile_abs), exist_ok=True) @@ -773,7 +773,7 @@ class QtBaseModule(ExtensionModule): content_files.append(s) elif isinstance(s, build.GeneratedList): for gen_src in s.get_outputs(): - content_files.append(File.from_built_file(state.subdir, gen_src)) + content_files.append(File.from_built_file(state.current_build_dir, gen_src)) else: content_files.append(File.from_source_file( state.environment.get_source_dir(), @@ -784,7 +784,7 @@ class QtBaseModule(ExtensionModule): def _gen_qrc(self, state: ModuleState, kwargs: GenQrcKwArgs) -> File: - fileout = File.from_built_file(state.subdir, kwargs['output']) + fileout = File.from_built_file(state.current_build_dir, kwargs['output']) fileout_abs = os.path.join(state.environment.build_dir, fileout.relative_name()) if not os.path.isdir(state.environment.build_dir): os.mkdir(state.environment.build_dir) @@ -813,7 +813,7 @@ class QtBaseModule(ExtensionModule): #Foo.Bar/1.0 foo.bar/auto foo.bar import_re = re.compile(r'^(' + _MODULE_NAME_RE + r')(/((\d+(\.\d+)?)|auto))?$') - fileout = File.from_built_file(state.subdir, kwargs['output']) + fileout = File.from_built_file(state.current_build_dir, kwargs['output']) fileout_abs = os.path.join(state.environment.build_dir, fileout.relative_name()) if not os.path.isdir(state.environment.build_dir): os.mkdir(state.environment.build_dir) diff --git a/mesonbuild/modules/cmake.py b/mesonbuild/modules/cmake.py index 655e8e211..d82a05c75 100644 --- a/mesonbuild/modules/cmake.py +++ b/mesonbuild/modules/cmake.py @@ -395,7 +395,7 @@ class CmakeModule(ExtensionModule): name = kwargs['name'] - (ofile_path, ofile_fname) = os.path.split(os.path.join(state.subdir, f'{name}Config.cmake')) + (ofile_path, ofile_fname) = os.path.split(os.path.join(state.current_build_dir, f'{name}Config.cmake')) ofile_abs = os.path.join(state.environment.build_dir, ofile_path, ofile_fname) install_dir = kwargs['install_dir'] diff --git a/mesonbuild/modules/external_project.py b/mesonbuild/modules/external_project.py index 13187cd07..737bd6197 100644 --- a/mesonbuild/modules/external_project.py +++ b/mesonbuild/modules/external_project.py @@ -64,6 +64,7 @@ class ExternalProject(NewExtensionModule): }) self.subdir = Path(state.subdir) + self.current_build_dir = Path(state.current_build_dir) self.project_version = state.project_version self.subproject = state.subproject self.env = state.environment @@ -74,8 +75,8 @@ class ExternalProject(NewExtensionModule): self.user_env = env self.src_dir = Path(self.env.get_source_dir(), self.subdir) - self.build_dir = Path(self.env.get_build_dir(), self.subdir, 'build') - self.install_dir = Path(self.env.get_build_dir(), self.subdir, 'dist') + self.build_dir = Path(self.env.get_build_dir(), self.current_build_dir, 'build') + self.install_dir = Path(self.env.get_build_dir(), self.current_build_dir, 'dist') _p = self.env.coredata.optstore.get_value_for(OptionKey('prefix')) assert isinstance(_p, str), 'for mypy' self.prefix = Path(_p) @@ -261,7 +262,7 @@ class ExternalProject(NewExtensionModule): description='Generating external project {}', ) - idir = build.InstallDir(self.subdir.as_posix(), + idir = build.InstallDir(self.current_build_dir.as_posix(), Path('dist', self.rel_prefix).as_posix(), install_dir='.', install_dir_name='.', diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index 604d57547..cbd66eaf7 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -1212,7 +1212,7 @@ class GnomeModule(ExtensionModule): girfile = f'{ns}-{nsversion}.gir' srcdir = os.path.join(state.environment.get_source_dir(), state.subdir) - builddir = os.path.join(state.environment.get_build_dir(), state.subdir) + builddir = os.path.join(state.environment.get_build_dir(), state.current_build_dir) depends: T.List[TargetDepends] = [] # hack - this cast represents how sources are defined for the @@ -1285,7 +1285,8 @@ class GnomeModule(ExtensionModule): if self._gir_has_option('--sources-top-dirs'): scan_command += ['--sources-top-dirs', os.path.join(state.environment.get_source_dir(), state.root_subdir)] - scan_command += ['--sources-top-dirs', os.path.join(state.environment.get_build_dir(), state.root_subdir)] + scan_command += ['--sources-top-dirs', os.path.join(state.environment.get_build_dir(), + state.current_build_project.builddir)] if kwargs['doc_format'] is not None and self._gir_has_option('--doc-format'): scan_command += ['--doc-format', kwargs['doc_format']] @@ -1323,7 +1324,7 @@ class GnomeModule(ExtensionModule): typelib_target = self._make_typelib_target( state, typelib_output, typelib_cmd, generated_files, kwargs) - self._devenv_prepend('GI_TYPELIB_PATH', os.path.join(state.environment.get_build_dir(), state.subdir)) + self._devenv_prepend('GI_TYPELIB_PATH', os.path.join(state.environment.get_build_dir(), state.current_build_dir)) rv = [scan_target, typelib_target] @@ -1332,7 +1333,7 @@ class GnomeModule(ExtensionModule): @TypedArgs('gnome.compile_schemas', kw_types=[_BUILD_BY_DEFAULT.evolve(since='0.40.0'), DEPEND_FILES_KW]) def compile_schemas(self, state: 'ModuleState', args: T.List['TYPE_var'], kwargs: 'CompileSchemas') -> ModuleReturnValue: srcdir = os.path.join(state.build_to_src, state.subdir) - outdir = state.subdir + outdir = state.current_build_dir cmd: CommandList = [self._find_tool(state, 'glib-compile-schemas'), '--targetdir', outdir, srcdir] if state.subdir == '': @@ -1351,7 +1352,7 @@ class GnomeModule(ExtensionModule): depend_files=state._interpreter.source_strings_to_files(kwargs['depend_files']), description='Compiling gschemas {}', ) - self._devenv_prepend('GSETTINGS_SCHEMA_DIR', os.path.join(state.environment.get_build_dir(), state.subdir)) + self._devenv_prepend('GSETTINGS_SCHEMA_DIR', os.path.join(state.environment.get_build_dir(), state.current_build_dir)) return ModuleReturnValue(target_g, [target_g]) @TypedArgs( @@ -1569,6 +1570,7 @@ class GnomeModule(ExtensionModule): '--sourcedir=' + state.environment.get_source_dir(), '--builddir=' + state.environment.get_build_dir(), '--subdir=' + state.subdir, + '--build-subdir=' + state.current_build_dir, '--headerdirs', *header_dirs, '--mainfile=' + main_file, '--modulename=' + modulename, @@ -1642,7 +1644,7 @@ class GnomeModule(ExtensionModule): check_env = ['DOC_MODULE=' + modulename, 'DOC_MAIN_SGML_FILE=' + main_file] check_args = (targetname + '-check', check_cmd) - check_workdir = os.path.join(state.environment.get_build_dir(), state.subdir) + check_workdir = os.path.join(state.environment.get_build_dir(), state.current_build_dir) state.test(check_args, env=check_env, workdir=check_workdir, depends=[custom_target]) res: T.List[T.Union[build.Target, mesonlib.ExecutableSerialisation]] = [custom_target, alias_target] if kwargs['install']: @@ -2324,7 +2326,7 @@ class GnomeModule(ExtensionModule): def generate_vapi(self, state: 'ModuleState', args: T.Tuple[str], kwargs: 'GenerateVapi') -> ModuleReturnValue: created_values: T.List[T.Union[Dependency, build.Data]] = [] library = args[0] - build_dir = os.path.join(state.environment.get_build_dir(), state.subdir) + build_dir = os.path.join(state.environment.get_build_dir(), state.current_build_dir) source_dir = os.path.join(state.environment.get_source_dir(), state.subdir) pkg_cmd, vapi_depends, vapi_packages, vapi_includes, packages = self._extract_vapi_packages(state, kwargs['packages']) cmd: CommandList = [state.find_program('vapigen'), '--quiet', f'--library={library}', f'--directory={build_dir}'] @@ -2344,7 +2346,7 @@ class GnomeModule(ExtensionModule): elif isinstance(i, GirTarget): link_with += self._get_vapi_link_with(i) subdir = os.path.join(state.environment.get_build_dir(), - i.get_subdir()) + i.get_builddir()) gir_file = os.path.join(subdir, i.get_outputs()[0]) cmd.append(gir_file) inputs.append(i) diff --git a/mesonbuild/modules/hotdoc.py b/mesonbuild/modules/hotdoc.py index 03e742372..edfe30fd2 100644 --- a/mesonbuild/modules/hotdoc.py +++ b/mesonbuild/modules/hotdoc.py @@ -85,10 +85,11 @@ class HotdocTargetBuilder: self.builddir = state.environment.get_build_dir() self.sourcedir = state.environment.get_source_dir() self.subdir = state.subdir + self.current_build_dir = state.current_build_dir self.build_command = state.environment.get_build_command() self.cmd: T.List[TYPE_var] = ['conf', '--project-name', name, "--disable-incremental-build", - '--output', os.path.join(self.builddir, self.subdir, self.name + '-doc')] + '--output', os.path.join(self.builddir, self.current_build_dir, self.name + '-doc')] self._extra_extension_paths: set[str] = set() self.extra_depends: list[build.BuildTargetProto] = [] @@ -170,7 +171,7 @@ class HotdocTargetBuilder: value = self.kwargs.pop('gi_c_source_roots') value.extend([ os.path.join(self.sourcedir, self.state.root_subdir), - os.path.join(self.builddir, self.state.root_subdir) + os.path.join(self.builddir, self.state.current_build_project.builddir) ]) self.cmd += ['--gi-c-source-roots'] + value @@ -279,7 +280,7 @@ class HotdocTargetBuilder: if not os.path.isdir(_dir): raise InvalidArguments(f'"{_dir}" is not a directory.') - return os.path.relpath(_dir, os.path.join(self.builddir, self.subdir)) + return os.path.relpath(_dir, os.path.join(self.builddir, self.current_build_dir)) def check_forbidden_args(self) -> None: for arg in ['conf_file']: @@ -306,15 +307,15 @@ class HotdocTargetBuilder: fullname = self.name + '-doc' hotdoc_config_name = fullname + '.json' hotdoc_config_path = os.path.join( - self.builddir, self.subdir, hotdoc_config_name) + self.builddir, self.current_build_dir, hotdoc_config_name) with open(hotdoc_config_path, 'w', encoding='utf-8') as f: f.write('{}') self.cmd += ['--conf-file', hotdoc_config_path] - self.include_paths.add(os.path.join(self.builddir, self.subdir)) + self.include_paths.add(os.path.join(self.builddir, self.current_build_dir)) self.include_paths.add(os.path.join(self.sourcedir, self.subdir)) - depfile = os.path.join(self.builddir, self.subdir, self.name + '.deps') + depfile = os.path.join(self.builddir, self.current_build_dir, self.name + '.deps') self.cmd += ['--deps-file-dest', depfile] for path in self.include_paths: @@ -326,13 +327,13 @@ class HotdocTargetBuilder: target_cmd = self.build_command + ["--internal", "hotdoc"] + \ self.hotdoc.get_command() + ['run', '--conf-file', hotdoc_config_name] + \ - ['--builddir', os.path.join(self.builddir, self.subdir)] + ['--builddir', os.path.join(self.builddir, self.current_build_dir)] target = HotdocTarget(fullname, subdir=self.subdir, environment=self.state.environment, hotdoc_conf=File.from_built_file( - self.subdir, hotdoc_config_name), + self.current_build_dir, hotdoc_config_name), extra_extension_paths=self._extra_extension_paths, extra_assets=self._extra_assets, subprojects=self._subprojects, @@ -367,7 +368,7 @@ class HotdocTargetBuilder: "--install", install_from, "--docdir", install_to, '--name', self.name, - '--builddir', os.path.join(self.builddir, self.subdir)] + + '--builddir', os.path.join(self.builddir, self.current_build_dir)] + self.hotdoc.get_command() + ['run', '--conf-file', hotdoc_config_name]) install_script.tag = 'doc' diff --git a/mesonbuild/modules/i18n.py b/mesonbuild/modules/i18n.py index c1db30bd4..0cbfe055c 100644 --- a/mesonbuild/modules/i18n.py +++ b/mesonbuild/modules/i18n.py @@ -246,10 +246,10 @@ class XgettextProgram: if estimated_cmdline_length < mesonlib.get_rsp_threshold(): return None - rsp_file = Path(self.interpreter.environment.build_dir, self.interpreter.subdir, name+'.rsp') + rsp_file = Path(self.interpreter.environment.build_dir, self.interpreter.current_build_dir(), name+'.rsp') rsp_file.write_text(source_list, encoding='utf-8') - return mesonlib.File.from_built_file(self.interpreter.subdir, rsp_file.name) + return mesonlib.File.from_built_file(self.interpreter.current_build_dir(), rsp_file.name) @staticmethod def _get_source_id(sources: T.Iterable[SourcesType]) -> T.Iterable[str]: diff --git a/mesonbuild/modules/rust.py b/mesonbuild/modules/rust.py index 272ed8526..5389a37d7 100644 --- a/mesonbuild/modules/rust.py +++ b/mesonbuild/modules/rust.py @@ -296,7 +296,7 @@ class RustCrate(ModuleObject): @TypedArgs('rust_crate.env') def env_method(self, state: ModuleState, args: T.List, kwargs: TYPE_kwargs) -> T.Dict[str, str]: """Returns environment variables for this package.""" - return self.package.get_env_dict(state.environment, state.subdir) + return self.package.get_env_dict(state.environment, state.subdir, state.current_build_dir) @TypedArgs('rust_crate.rust_dependency_map') def rust_dependency_map_method(self, state: ModuleState, args: T.List, kwargs: TYPE_kwargs) -> T.Dict[str, str]: diff --git a/mesonbuild/modules/snippets.py b/mesonbuild/modules/snippets.py index 8d5f88abc..84fff23cf 100644 --- a/mesonbuild/modules/snippets.py +++ b/mesonbuild/modules/snippets.py @@ -100,9 +100,9 @@ class SnippetsModule(NewExtensionModule): # define {api} {api}_IMPORT extern #endif ''') - header_path = Path(state.environment.get_build_dir(), state.subdir, header_name) + header_path = Path(state.environment.get_build_dir(), state.current_build_dir, header_name) header_path.write_text(content, encoding='utf-8') - return mesonlib.File.from_built_file(state.subdir, header_name) + return mesonlib.File.from_built_file(state.current_build_dir, header_name) def initialize(*args: T.Any, **kwargs: T.Any) -> SnippetsModule: return SnippetsModule() diff --git a/test cases/native/10 native subproject/subprojects/both/main.c b/test cases/native/10 native subproject/subprojects/both/main.c index 26ff829eb..90cf90499 100644 --- a/test cases/native/10 native subproject/subprojects/both/main.c +++ b/test cases/native/10 native subproject/subprojects/both/main.c @@ -1,3 +1,9 @@ +#include "config.h" + +#if IS_CROSS_BUILD != EXPECTED_CROSS_BUILD +#error "config.h was generated for the wrong machine" +#endif + #ifndef GLOBAL_CROSS_BUILD #error "add_global_arguments() was not applied" #endif diff --git a/test cases/native/10 native subproject/subprojects/both/meson.build b/test cases/native/10 native subproject/subprojects/both/meson.build index 63caf904e..98e128ebb 100644 --- a/test cases/native/10 native subproject/subprojects/both/meson.build +++ b/test cases/native/10 native subproject/subprojects/both/meson.build @@ -1,6 +1,7 @@ project('both', 'c') cross = meson.is_cross_build() ? 1 : 0 +configure_file(output : 'config.h', configuration : {'IS_CROSS_BUILD': cross}) add_project_arguments(f'-DPROJECT_CROSS_BUILD=@cross@', language : 'c') e = executable('main', 'main.c', c_args : f'-DEXPECTED_CROSS_BUILD=@cross@')