From 7516508547524c53d99178f26d2df5f0cd6e8396 Mon Sep 17 00:00:00 2001 From: Mykola Dolhyi <0xb000@gmail.com> Date: Thu, 27 Jun 2024 19:10:02 +0300 Subject: [PATCH 001/302] Refactor duplicated quoting code for XCode backend XCode project file contains dictionary-like structures. Strings for the mapped values have to be quoted if these include special characters. Previously this quoting was happening in-place, before adding a new value to the dictionary. This produce big amounts of boilerplate error-prone code. For example if there are targets whose names contain special characters (grpc++ in my case), produced file will be invalid. This moves checking and quoting subroutine to the PbxDictItem class, eliminating the need to do this on the caller side. [Kin](https://github.com/Serchinastico/Kin) tool was used to validate produced PBXProj files. --- mesonbuild/backend/xcodebackend.py | 60 ++++++++++++++++++------------ 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/mesonbuild/backend/xcodebackend.py b/mesonbuild/backend/xcodebackend.py index 69a544b240a0..66d42b30a551 100644 --- a/mesonbuild/backend/xcodebackend.py +++ b/mesonbuild/backend/xcodebackend.py @@ -138,7 +138,11 @@ def write(self, ofile: T.TextIO, indent_level: int) -> None: class PbxDictItem: def __init__(self, key: str, value: T.Union[PbxArray, PbxDict, str, int], comment: str = ''): self.key = key - self.value = value + if isinstance(value, str): + self.value = self.quote_value(value) + else: + self.value = value + if comment: if '/*' in comment: self.comment = comment @@ -147,6 +151,17 @@ def __init__(self, key: str, value: T.Union[PbxArray, PbxDict, str, int], commen else: self.comment = comment + def quote_value(self, value: str) -> str: + quoted = f'"{value}"' + + if len(value) == 0: + return quoted + + if set(' +@').isdisjoint(value) or value[0] == '"': + return value + + return quoted + class PbxDict: def __init__(self) -> None: # This class is a bit weird, because we want to write PBX dicts in @@ -826,7 +841,7 @@ def generate_pbx_container_item_proxy(self, objects_dict: PbxDict) -> None: proxy_dict.add_item('containerPortal', self.project_uid, 'Project object') proxy_dict.add_item('proxyType', '1') proxy_dict.add_item('remoteGlobalIDString', self.native_targets[t]) - proxy_dict.add_item('remoteInfo', '"' + t + '"') + proxy_dict.add_item('remoteInfo', t) def generate_pbx_file_reference(self, objects_dict: PbxDict) -> None: for tname, t in self.build_targets.items(): @@ -859,17 +874,17 @@ def generate_pbx_file_reference(self, objects_dict: PbxDict) -> None: path = s objects_dict.add_item(idval, src_dict, fullpath) src_dict.add_item('isa', 'PBXFileReference') - src_dict.add_item('explicitFileType', '"' + xcodetype + '"') + src_dict.add_item('explicitFileType', xcodetype) src_dict.add_item('fileEncoding', '4') if in_build_dir: - src_dict.add_item('name', '"' + name + '"') + src_dict.add_item('name', name) # This makes no sense. This should say path instead of name # but then the path gets added twice. - src_dict.add_item('path', '"' + name + '"') + src_dict.add_item('path', name) src_dict.add_item('sourceTree', 'BUILD_ROOT') else: - src_dict.add_item('name', '"' + name + '"') - src_dict.add_item('path', '"' + path + '"') + src_dict.add_item('name', name) + src_dict.add_item('path', path) src_dict.add_item('sourceTree', 'SOURCE_ROOT') generator_id = 0 @@ -886,7 +901,7 @@ def generate_pbx_file_reference(self, objects_dict: PbxDict) -> None: xcodetype = self.get_xcodetype(o) rel_name = mesonlib.relpath(o, self.environment.get_source_dir()) odict.add_item('isa', 'PBXFileReference') - odict.add_item('explicitFileType', '"' + xcodetype + '"') + odict.add_item('explicitFileType', xcodetype) odict.add_item('fileEncoding', '4') odict.add_item('name', f'"{name}"') odict.add_item('path', f'"{rel_name}"') @@ -910,7 +925,7 @@ def generate_pbx_file_reference(self, objects_dict: PbxDict) -> None: name = os.path.basename(o) objects_dict.add_item(idval, o_dict, fullpath) o_dict.add_item('isa', 'PBXFileReference') - o_dict.add_item('explicitFileType', '"' + self.get_xcodetype(o) + '"') + o_dict.add_item('explicitFileType', self.get_xcodetype(o)) o_dict.add_item('fileEncoding', '4') o_dict.add_item('name', f'"{name}"') o_dict.add_item('path', f'"{rel_name}"') @@ -929,9 +944,9 @@ def generate_pbx_file_reference(self, objects_dict: PbxDict) -> None: path = e objects_dict.add_item(idval, e_dict, fullpath) e_dict.add_item('isa', 'PBXFileReference') - e_dict.add_item('explicitFileType', '"' + xcodetype + '"') - e_dict.add_item('name', '"' + name + '"') - e_dict.add_item('path', '"' + path + '"') + e_dict.add_item('explicitFileType', xcodetype) + e_dict.add_item('name', name) + e_dict.add_item('path', path) e_dict.add_item('sourceTree', 'SOURCE_ROOT') for tname, idval in self.target_filemap.items(): target_dict = PbxDict() @@ -949,11 +964,8 @@ def generate_pbx_file_reference(self, objects_dict: PbxDict) -> None: typestr = self.get_xcodetype(fname) path = '"%s"' % t.get_filename() target_dict.add_item('isa', 'PBXFileReference') - target_dict.add_item('explicitFileType', '"' + typestr + '"') - if ' ' in path and path[0] != '"': - target_dict.add_item('path', f'"{path}"') - else: - target_dict.add_item('path', path) + target_dict.add_item('explicitFileType', typestr) + target_dict.add_item('path', path) target_dict.add_item('refType', reftype) target_dict.add_item('sourceTree', 'BUILT_PRODUCTS_DIR') @@ -971,7 +983,7 @@ def generate_pbx_file_reference(self, objects_dict: PbxDict) -> None: custom_dict = PbxDict() typestr = self.get_xcodetype(s) custom_dict.add_item('isa', 'PBXFileReference') - custom_dict.add_item('explicitFileType', '"' + typestr + '"') + custom_dict.add_item('explicitFileType', typestr) custom_dict.add_item('name', f'"{s}"') custom_dict.add_item('path', f'"{s}"') custom_dict.add_item('refType', 0) @@ -981,7 +993,7 @@ def generate_pbx_file_reference(self, objects_dict: PbxDict) -> None: custom_dict = PbxDict() typestr = self.get_xcodetype(o) custom_dict.add_item('isa', 'PBXFileReference') - custom_dict.add_item('explicitFileType', '"' + typestr + '"') + custom_dict.add_item('explicitFileType', typestr) custom_dict.add_item('name', o) custom_dict.add_item('path', f'"{os.path.join(self.src_to_build, o)}"') custom_dict.add_item('refType', 0) @@ -993,7 +1005,7 @@ def generate_pbx_file_reference(self, objects_dict: PbxDict) -> None: buildfile_dict = PbxDict() typestr = self.get_xcodetype(buildfile) buildfile_dict.add_item('isa', 'PBXFileReference') - buildfile_dict.add_item('explicitFileType', '"' + typestr + '"') + buildfile_dict.add_item('explicitFileType', typestr) buildfile_dict.add_item('name', f'"{basename}"') buildfile_dict.add_item('path', f'"{buildfile}"') buildfile_dict.add_item('refType', 0) @@ -1277,8 +1289,8 @@ def generate_pbx_project(self, objects_dict: PbxDict) -> None: project_dict.add_item('compatibilityVersion', f'"{self.xcodeversion}"') project_dict.add_item('hasScannedForEncodings', 0) project_dict.add_item('mainGroup', self.maingroup_id) - project_dict.add_item('projectDirPath', '"' + self.environment.get_source_dir() + '"') - project_dict.add_item('projectRoot', '""') + project_dict.add_item('projectDirPath', self.environment.get_source_dir()) + project_dict.add_item('projectRoot', '') targets_arr = PbxArray() project_dict.add_item('targets', targets_arr) targets_arr.add_item(self.all_id, 'ALL_BUILD') @@ -1429,7 +1441,7 @@ def generate_single_generator_phase(self, tname, t, genlist, generator_id, objec else: q.append(c) quoted_cmds.append(' '.join(q)) - cmdstr = '"' + ' && '.join(quoted_cmds) + '"' + cmdstr = ' && '.join(quoted_cmds) gen_dict.add_item('shellScript', cmdstr) gen_dict.add_item('showEnvVarsInLog', 0) @@ -1799,7 +1811,7 @@ def add_otherargs(self, settings_dict, langargs): if ' ' in a or "'" in a: a = r'\"' + a + r'\"' quoted_args.append(a) - settings_dict.add_item(f'OTHER_{langname}FLAGS', '"' + ' '.join(quoted_args) + '"') + settings_dict.add_item(f'OTHER_{langname}FLAGS', ' '.join(quoted_args)) def generate_xc_configurationList(self, objects_dict: PbxDict) -> None: # FIXME: sort items From a9bc6cc3b67b10bddc38ab35cf530443e4abf019 Mon Sep 17 00:00:00 2001 From: Mykola <0xb000@gmail.com> Date: Thu, 27 Jun 2024 20:01:23 +0300 Subject: [PATCH 002/302] Change empty string check approach Review suggestion Co-authored-by: Dylan Baker --- mesonbuild/backend/xcodebackend.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/backend/xcodebackend.py b/mesonbuild/backend/xcodebackend.py index 66d42b30a551..14d244379e11 100644 --- a/mesonbuild/backend/xcodebackend.py +++ b/mesonbuild/backend/xcodebackend.py @@ -154,7 +154,7 @@ def __init__(self, key: str, value: T.Union[PbxArray, PbxDict, str, int], commen def quote_value(self, value: str) -> str: quoted = f'"{value}"' - if len(value) == 0: + if not value: return quoted if set(' +@').isdisjoint(value) or value[0] == '"': From 25c5d74cbc48d7e610633c9a29992b61b95ec401 Mon Sep 17 00:00:00 2001 From: Mykola Dolhyi <0xb000@gmail.com> Date: Fri, 28 Jun 2024 13:02:43 +0300 Subject: [PATCH 003/302] Remove redundant quoting boilerplate on .add_item A follow-up to the PbxDictItem refactoring. This removes extra type casting and string formatting before inserting values to the PbxDict. --- mesonbuild/backend/xcodebackend.py | 142 ++++++++++++++--------------- 1 file changed, 70 insertions(+), 72 deletions(-) diff --git a/mesonbuild/backend/xcodebackend.py b/mesonbuild/backend/xcodebackend.py index 14d244379e11..caeb136a9110 100644 --- a/mesonbuild/backend/xcodebackend.py +++ b/mesonbuild/backend/xcodebackend.py @@ -157,7 +157,7 @@ def quote_value(self, value: str) -> str: if not value: return quoted - if set(' +@').isdisjoint(value) or value[0] == '"': + if set(' +@$<>/').isdisjoint(value) or value[0] == '"': return value return quoted @@ -626,7 +626,8 @@ def generate_pbx_aggregate_target(self, objects_dict: PbxDict) -> None: elif isinstance(t, build.BuildTarget): target_dependencies.append(self.pbx_dep_map[t.get_id()]) aggregated_targets = [] - aggregated_targets.append((self.all_id, 'ALL_BUILD', + aggregated_targets.append((self.all_id, + 'ALL_BUILD', self.all_buildconf_id, [], [self.regen_dependency_id] + target_dependencies + custom_target_dependencies)) @@ -682,8 +683,8 @@ def generate_pbx_aggregate_target(self, objects_dict: PbxDict) -> None: agt_dict.add_item('dependencies', dep_arr) for td in dependencies: dep_arr.add_item(td, 'PBXTargetDependency') - agt_dict.add_item('name', f'"{name}"') - agt_dict.add_item('productName', f'"{name}"') + agt_dict.add_item('name', name) + agt_dict.add_item('productName', name) objects_dict.add_item(t[0], agt_dict, name) def generate_pbx_build_file(self, objects_dict: PbxDict) -> None: @@ -784,7 +785,7 @@ def generate_pbx_build_style(self, objects_dict: PbxDict) -> None: settings_dict = PbxDict() styledict.add_item('buildSettings', settings_dict) settings_dict.add_item('COPY_PHASE_STRIP', 'NO') - styledict.add_item('name', f'"{name}"') + styledict.add_item('name', name) def to_shell_script(self, args: CompilerArgs) -> str: quoted_cmd = [] @@ -803,13 +804,13 @@ def generate_pbx_build_rule(self, objects_dict: PbxDict) -> None: buildrule.add_item('compilerSpec', 'com.apple.compilers.proxy.script') if compiler.get_id() != 'yasm': # Yasm doesn't generate escaped build rules - buildrule.add_item('dependencyFile', '"$(DERIVED_FILE_DIR)/$(INPUT_FILE_BASE).d"') + buildrule.add_item('dependencyFile', '$(DERIVED_FILE_DIR)/$(INPUT_FILE_BASE).d') buildrule.add_item('fileType', NEEDS_CUSTOM_RULES[language]) inputfiles = PbxArray() buildrule.add_item('inputFiles', inputfiles) buildrule.add_item('isEditable', '0') outputfiles = PbxArray() - outputfiles.add_item('"$(DERIVED_FILE_DIR)/$(INPUT_FILE_BASE).o"') + outputfiles.add_item('$(DERIVED_FILE_DIR)/$(INPUT_FILE_BASE).o') buildrule.add_item('outputFiles', outputfiles) # Do NOT use this parameter. Xcode will accept it from the UI, # but the parser will break down inconsistently upon next @@ -903,8 +904,8 @@ def generate_pbx_file_reference(self, objects_dict: PbxDict) -> None: odict.add_item('isa', 'PBXFileReference') odict.add_item('explicitFileType', xcodetype) odict.add_item('fileEncoding', '4') - odict.add_item('name', f'"{name}"') - odict.add_item('path', f'"{rel_name}"') + odict.add_item('name', name) + odict.add_item('path', rel_name) odict.add_item('sourceTree', 'SOURCE_ROOT') generator_id += 1 @@ -927,8 +928,8 @@ def generate_pbx_file_reference(self, objects_dict: PbxDict) -> None: o_dict.add_item('isa', 'PBXFileReference') o_dict.add_item('explicitFileType', self.get_xcodetype(o)) o_dict.add_item('fileEncoding', '4') - o_dict.add_item('name', f'"{name}"') - o_dict.add_item('path', f'"{rel_name}"') + o_dict.add_item('name', name) + o_dict.add_item('path', rel_name) o_dict.add_item('sourceTree', 'SOURCE_ROOT') for e in t.extra_files: @@ -984,8 +985,8 @@ def generate_pbx_file_reference(self, objects_dict: PbxDict) -> None: typestr = self.get_xcodetype(s) custom_dict.add_item('isa', 'PBXFileReference') custom_dict.add_item('explicitFileType', typestr) - custom_dict.add_item('name', f'"{s}"') - custom_dict.add_item('path', f'"{s}"') + custom_dict.add_item('name', s) + custom_dict.add_item('path', s) custom_dict.add_item('refType', 0) custom_dict.add_item('sourceTree', 'SOURCE_ROOT') objects_dict.add_item(self.fileref_ids[(tname, s)], custom_dict) @@ -995,7 +996,7 @@ def generate_pbx_file_reference(self, objects_dict: PbxDict) -> None: custom_dict.add_item('isa', 'PBXFileReference') custom_dict.add_item('explicitFileType', typestr) custom_dict.add_item('name', o) - custom_dict.add_item('path', f'"{os.path.join(self.src_to_build, o)}"') + custom_dict.add_item('path', os.path.join(self.src_to_build, o)) custom_dict.add_item('refType', 0) custom_dict.add_item('sourceTree', 'SOURCE_ROOT') objects_dict.add_item(self.custom_target_output_fileref[o], custom_dict) @@ -1006,8 +1007,8 @@ def generate_pbx_file_reference(self, objects_dict: PbxDict) -> None: typestr = self.get_xcodetype(buildfile) buildfile_dict.add_item('isa', 'PBXFileReference') buildfile_dict.add_item('explicitFileType', typestr) - buildfile_dict.add_item('name', f'"{basename}"') - buildfile_dict.add_item('path', f'"{buildfile}"') + buildfile_dict.add_item('name', basename) + buildfile_dict.add_item('path', buildfile) buildfile_dict.add_item('refType', 0) buildfile_dict.add_item('sourceTree', 'SOURCE_ROOT') objects_dict.add_item(self.fileref_ids[buildfile], buildfile_dict) @@ -1048,7 +1049,7 @@ def generate_pbx_group(self, objects_dict: PbxDict) -> None: main_children.add_item(resources_id, 'Resources') main_children.add_item(products_id, 'Products') main_children.add_item(frameworks_id, 'Frameworks') - main_dict.add_item('sourceTree', '""') + main_dict.add_item('sourceTree', '') self.add_projecttree(objects_dict, projecttree_id) @@ -1058,7 +1059,7 @@ def generate_pbx_group(self, objects_dict: PbxDict) -> None: resource_children = PbxArray() resource_dict.add_item('children', resource_children) resource_dict.add_item('name', 'Resources') - resource_dict.add_item('sourceTree', '""') + resource_dict.add_item('sourceTree', '') frameworks_dict = PbxDict() objects_dict.add_item(frameworks_id, frameworks_dict, 'Frameworks') @@ -1074,7 +1075,7 @@ def generate_pbx_group(self, objects_dict: PbxDict) -> None: frameworks_children.add_item(self.native_frameworks_fileref[f], f) frameworks_dict.add_item('name', 'Frameworks') - frameworks_dict.add_item('sourceTree', '""') + frameworks_dict.add_item('sourceTree', '') for tname, t in self.custom_targets.items(): target_dict = PbxDict() @@ -1084,10 +1085,10 @@ def generate_pbx_group(self, objects_dict: PbxDict) -> None: target_dict.add_item('children', target_children) target_children.add_item(target_src_map[tname], 'Source files') if t.subproject: - target_dict.add_item('name', f'"{t.subproject} • {t.name}"') + target_dict.add_item('name', f'{t.subproject} • {t.name}') else: - target_dict.add_item('name', f'"{t.name}"') - target_dict.add_item('sourceTree', '""') + target_dict.add_item('name', t.name) + target_dict.add_item('sourceTree', '') source_files_dict = PbxDict() objects_dict.add_item(target_src_map[tname], source_files_dict, 'Source files') source_files_dict.add_item('isa', 'PBXGroup') @@ -1101,8 +1102,8 @@ def generate_pbx_group(self, objects_dict: PbxDict) -> None: else: continue source_file_children.add_item(self.fileref_ids[(tname, s)], s) - source_files_dict.add_item('name', '"Source files"') - source_files_dict.add_item('sourceTree', '""') + source_files_dict.add_item('name', 'Source files') + source_files_dict.add_item('sourceTree', '') # And finally products product_dict = PbxDict() @@ -1113,7 +1114,7 @@ def generate_pbx_group(self, objects_dict: PbxDict) -> None: for t in self.build_targets: product_children.add_item(self.target_filemap[t], t) product_dict.add_item('name', 'Products') - product_dict.add_item('sourceTree', '""') + product_dict.add_item('sourceTree', '') def write_group_target_entry(self, objects_dict, t): tid = t.get_id() @@ -1123,8 +1124,8 @@ def write_group_target_entry(self, objects_dict, t): target_dict.add_item('isa', 'PBXGroup') target_children = PbxArray() target_dict.add_item('children', target_children) - target_dict.add_item('name', f'"{t} · target"') - target_dict.add_item('sourceTree', '""') + target_dict.add_item('name', f'{t} · target') + target_dict.add_item('sourceTree', '') source_files_dict = PbxDict() for s in t.sources: if isinstance(s, mesonlib.File): @@ -1151,8 +1152,8 @@ def write_group_target_entry(self, objects_dict, t): else: continue target_children.add_item(self.fileref_ids[(tid, e)], e) - source_files_dict.add_item('name', '"Source files"') - source_files_dict.add_item('sourceTree', '""') + source_files_dict.add_item('name', 'Source files') + source_files_dict.add_item('sourceTree', '') return group_id def add_projecttree(self, objects_dict, projecttree_id) -> None: @@ -1161,8 +1162,8 @@ def add_projecttree(self, objects_dict, projecttree_id) -> None: root_dict.add_item('isa', 'PBXGroup') target_children = PbxArray() root_dict.add_item('children', target_children) - root_dict.add_item('name', '"Project root"') - root_dict.add_item('sourceTree', '""') + root_dict.add_item('name', 'Project root') + root_dict.add_item('sourceTree', '') project_tree = self.generate_project_tree() self.write_tree(objects_dict, project_tree, target_children, '') @@ -1176,8 +1177,8 @@ def write_tree(self, objects_dict, tree_node, children_array, current_subdir) -> children_array.add_item(subdir_id) subdir_dict.add_item('isa', 'PBXGroup') subdir_dict.add_item('children', subdir_children) - subdir_dict.add_item('name', f'"{subdir_name}"') - subdir_dict.add_item('sourceTree', '""') + subdir_dict.add_item('name', subdir_name) + subdir_dict.add_item('sourceTree', '') self.write_tree(objects_dict, subdir_node, subdir_children, os.path.join(current_subdir, subdir_name)) for target in tree_node.targets: group_id = self.write_group_target_entry(objects_dict, target) @@ -1259,8 +1260,8 @@ def generate_pbx_native_target(self, objects_dict: PbxDict) -> None: generator_id += 1 - ntarget_dict.add_item('name', f'"{tname}"') - ntarget_dict.add_item('productName', f'"{tname}"') + ntarget_dict.add_item('name', tname) + ntarget_dict.add_item('productName', tname) ntarget_dict.add_item('productReference', self.target_filemap[tname], tname) if isinstance(t, build.Executable): typestr = 'com.apple.product-type.tool' @@ -1286,7 +1287,7 @@ def generate_pbx_project(self, objects_dict: PbxDict) -> None: project_dict.add_item('buildStyles', style_arr) for name, idval in self.buildstylemap.items(): style_arr.add_item(idval, name) - project_dict.add_item('compatibilityVersion', f'"{self.xcodeversion}"') + project_dict.add_item('compatibilityVersion', self.xcodeversion) project_dict.add_item('hasScannedForEncodings', 0) project_dict.add_item('mainGroup', self.maingroup_id) project_dict.add_item('projectDirPath', self.environment.get_source_dir()) @@ -1319,7 +1320,7 @@ def generate_test_shell_build_phase(self, objects_dict: PbxDict) -> None: shell_dict.add_item('shellPath', '/bin/sh') cmd = mesonlib.get_meson_command() + ['test', '--no-rebuild', '-C', self.environment.get_build_dir()] cmdstr = ' '.join(["'%s'" % i for i in cmd]) - shell_dict.add_item('shellScript', f'"{cmdstr}"') + shell_dict.add_item('shellScript', cmdstr) shell_dict.add_item('showEnvVarsInLog', 0) def generate_regen_shell_build_phase(self, objects_dict: PbxDict) -> None: @@ -1334,7 +1335,7 @@ def generate_regen_shell_build_phase(self, objects_dict: PbxDict) -> None: shell_dict.add_item('shellPath', '/bin/sh') cmd = mesonlib.get_meson_command() + ['--internal', 'regencheck', os.path.join(self.environment.get_build_dir(), 'meson-private')] cmdstr = ' '.join(["'%s'" % i for i in cmd]) - shell_dict.add_item('shellScript', f'"{cmdstr}"') + shell_dict.add_item('shellScript', cmdstr) shell_dict.add_item('showEnvVarsInLog', 0) def generate_custom_target_shell_build_phases(self, objects_dict: PbxDict) -> None: @@ -1358,7 +1359,7 @@ def generate_custom_target_shell_build_phases(self, objects_dict: PbxDict) -> No custom_dict.add_item('name', '"Generate {}."'.format(ofilenames[0])) custom_dict.add_item('outputPaths', outarray) for o in ofilenames: - outarray.add_item(f'"{os.path.join(self.environment.get_build_dir(), o)}"') + outarray.add_item(os.path.join(self.environment.get_build_dir(), o)) custom_dict.add_item('runOnlyForDeploymentPostprocessing', 0) custom_dict.add_item('shellPath', '/bin/sh') workdir = self.environment.get_build_dir() @@ -1366,7 +1367,7 @@ def generate_custom_target_shell_build_phases(self, objects_dict: PbxDict) -> No for c in fixed_cmd: quoted_cmd.append(c.replace('"', chr(92) + '"')) cmdstr = ' '.join([f"\\'{x}\\'" for x in quoted_cmd]) - custom_dict.add_item('shellScript', f'"cd \'{workdir}\'; {cmdstr}"') + custom_dict.add_item('shellScript', f'cd \'{workdir}\'; {cmdstr}') custom_dict.add_item('showEnvVarsInLog', 0) def generate_generator_target_shell_build_phases(self, objects_dict: PbxDict) -> None: @@ -1392,21 +1393,21 @@ def generate_single_generator_phase(self, tname, t, genlist, generator_id, objec workdir = self.environment.get_build_dir() target_private_dir = self.relpath(self.get_target_private_dir(t), self.get_target_dir(t)) gen_dict = PbxDict() - objects_dict.add_item(self.shell_targets[(tname, generator_id)], gen_dict, f'"Generator {generator_id}/{tname}"') + objects_dict.add_item(self.shell_targets[(tname, generator_id)], gen_dict, f'Generator {generator_id}/{tname}') infilelist = genlist.get_inputs() outfilelist = genlist.get_outputs() gen_dict.add_item('isa', 'PBXShellScriptBuildPhase') gen_dict.add_item('buildActionMask', 2147483647) gen_dict.add_item('files', PbxArray()) gen_dict.add_item('inputPaths', PbxArray()) - gen_dict.add_item('name', f'"Generator {generator_id}/{tname}"') + gen_dict.add_item('name', f'Generator {generator_id}/{tname}') commands = [["cd", workdir]] # Array of arrays, each one a single command, will get concatenated below. k = (tname, generator_id) ofile_abs = self.generator_outputs[k] outarray = PbxArray() gen_dict.add_item('outputPaths', outarray) for of in ofile_abs: - outarray.add_item(f'"{of}"') + outarray.add_item(of) for i in infilelist: # This might be needed to be added to inputPaths. It's not done yet as it is # unclear whether it is necessary, what actually happens when it is defined @@ -1511,14 +1512,14 @@ def generate_xc_build_configuration(self, objects_dict: PbxDict) -> None: bt_dict.add_item('isa', 'XCBuildConfiguration') settings_dict = PbxDict() bt_dict.add_item('buildSettings', settings_dict) - settings_dict.add_item('ARCHS', f'"{self.arch}"') - settings_dict.add_item('BUILD_DIR', f'"{self.environment.get_build_dir()}"') - settings_dict.add_item('BUILD_ROOT', '"$(BUILD_DIR)"') + settings_dict.add_item('ARCHS', self.arch) + settings_dict.add_item('BUILD_DIR', self.environment.get_build_dir()) + settings_dict.add_item('BUILD_ROOT', '$(BUILD_DIR)') settings_dict.add_item('ONLY_ACTIVE_ARCH', 'YES') settings_dict.add_item('SWIFT_VERSION', '5.0') - settings_dict.add_item('SDKROOT', '"macosx"') - settings_dict.add_item('OBJROOT', '"$(BUILD_DIR)/build"') - bt_dict.add_item('name', f'"{buildtype}"') + settings_dict.add_item('SDKROOT', 'macosx') + settings_dict.add_item('OBJROOT', '$(BUILD_DIR)/build') + bt_dict.add_item('name', buildtype) # Then the all target. for buildtype in self.buildtypes: @@ -1531,7 +1532,7 @@ def generate_xc_build_configuration(self, objects_dict: PbxDict) -> None: warn_array.add_item('"$(inherited)"') settings_dict.add_item('WARNING_CFLAGS', warn_array) - bt_dict.add_item('name', f'"{buildtype}"') + bt_dict.add_item('name', buildtype) # Then the test target. for buildtype in self.buildtypes: @@ -1543,7 +1544,7 @@ def generate_xc_build_configuration(self, objects_dict: PbxDict) -> None: warn_array = PbxArray() settings_dict.add_item('WARNING_CFLAGS', warn_array) warn_array.add_item('"$(inherited)"') - bt_dict.add_item('name', f'"{buildtype}"') + bt_dict.add_item('name', buildtype) # Now finally targets. for target_name, target in self.build_targets.items(): @@ -1555,10 +1556,10 @@ def generate_xc_build_configuration(self, objects_dict: PbxDict) -> None: bt_dict.add_item('isa', 'XCBuildConfiguration') settings_dict = PbxDict() bt_dict.add_item('buildSettings', settings_dict) - settings_dict.add_item('ARCHS', f'"{self.arch}"') + settings_dict.add_item('ARCHS', self.arch) settings_dict.add_item('ONLY_ACTIVE_ARCH', 'YES') - settings_dict.add_item('SDKROOT', '"macosx"') - bt_dict.add_item('name', f'"{buildtype}"') + settings_dict.add_item('SDKROOT', 'macosx') + bt_dict.add_item('name', buildtype) def determine_internal_dep_link_args(self, target, buildtype): links_dylib = False @@ -1725,11 +1726,11 @@ def generate_single_build_target(self, objects_dict, target_name, target) -> Non bt_dict.add_item('buildSettings', settings_dict) settings_dict.add_item('COMBINE_HIDPI_IMAGES', 'YES') if isinstance(target, build.SharedModule): - settings_dict.add_item('DYLIB_CURRENT_VERSION', '""') - settings_dict.add_item('DYLIB_COMPATIBILITY_VERSION', '""') + settings_dict.add_item('DYLIB_CURRENT_VERSION', '') + settings_dict.add_item('DYLIB_COMPATIBILITY_VERSION', '') else: if dylib_version is not None: - settings_dict.add_item('DYLIB_CURRENT_VERSION', f'"{dylib_version}"') + settings_dict.add_item('DYLIB_CURRENT_VERSION', str(dylib_version)) if target.prefix: settings_dict.add_item('EXECUTABLE_PREFIX', target.prefix) if target.suffix: @@ -1752,8 +1753,8 @@ def generate_single_build_target(self, objects_dict, target_name, target) -> Non mlog.warning(f'Unsupported Xcode configuration: More than 1 precompiled header found "{pchs!s}". Target "{target.name}" might not compile correctly.') relative_pch_path = os.path.join(target.get_subdir(), pchs[0]) # Path relative to target so it can be used with "$(PROJECT_DIR)" settings_dict.add_item('GCC_PRECOMPILE_PREFIX_HEADER', 'YES') - settings_dict.add_item('GCC_PREFIX_HEADER', f'"$(PROJECT_DIR)/{relative_pch_path}"') - settings_dict.add_item('GCC_PREPROCESSOR_DEFINITIONS', '""') + settings_dict.add_item('GCC_PREFIX_HEADER', f'$(PROJECT_DIR)/{relative_pch_path}') + settings_dict.add_item('GCC_PREPROCESSOR_DEFINITIONS', '') settings_dict.add_item('GCC_SYMBOLS_PRIVATE_EXTERN', 'NO') header_arr = PbxArray() unquoted_headers = [] @@ -1766,27 +1767,24 @@ def generate_single_build_target(self, objects_dict, target_name, target) -> Non i = os.path.normpath(i) unquoted_headers.append(i) for i in unquoted_headers: - header_arr.add_item(f'"\\"{i}\\""') + header_arr.add_item(f'"{i}"') settings_dict.add_item('HEADER_SEARCH_PATHS', header_arr) - settings_dict.add_item('INSTALL_PATH', f'"{install_path}"') - settings_dict.add_item('LIBRARY_SEARCH_PATHS', '""') + settings_dict.add_item('INSTALL_PATH', install_path) + settings_dict.add_item('LIBRARY_SEARCH_PATHS', '') if isinstance(target, build.SharedModule): settings_dict.add_item('LIBRARY_STYLE', 'BUNDLE') settings_dict.add_item('MACH_O_TYPE', 'mh_bundle') elif isinstance(target, build.SharedLibrary): settings_dict.add_item('LIBRARY_STYLE', 'DYNAMIC') self.add_otherargs(settings_dict, langargs) - settings_dict.add_item('OTHER_LDFLAGS', f'"{ldstr}"') - settings_dict.add_item('OTHER_REZFLAGS', '""') - if ' ' in product_name: - settings_dict.add_item('PRODUCT_NAME', f'"{product_name}"') - else: - settings_dict.add_item('PRODUCT_NAME', product_name) - settings_dict.add_item('SECTORDER_FLAGS', '""') + settings_dict.add_item('OTHER_LDFLAGS', ldstr) + settings_dict.add_item('OTHER_REZFLAGS', '') + settings_dict.add_item('PRODUCT_NAME', product_name) + settings_dict.add_item('SECTORDER_FLAGS', '') if is_swift and bridging_header: - settings_dict.add_item('SWIFT_OBJC_BRIDGING_HEADER', f'"{bridging_header}"') - settings_dict.add_item('BUILD_DIR', f'"{symroot}"') - settings_dict.add_item('OBJROOT', f'"{symroot}/build"') + settings_dict.add_item('SWIFT_OBJC_BRIDGING_HEADER', bridging_header) + settings_dict.add_item('BUILD_DIR', symroot) + settings_dict.add_item('OBJROOT', f'{symroot}/build') sysheader_arr = PbxArray() # XCode will change every -I flag that points inside these directories # to an -isystem. Thus set nothing in it since we control our own From 814e58153743b743cf356717b999ef06a3edc68c Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Wed, 10 Jul 2024 21:26:32 +0300 Subject: [PATCH 004/302] Bump version number for new development. --- mesonbuild/coredata.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 642e33455bd9..0688e41b1bc9 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -72,7 +72,7 @@ class SharedCMDOptions(Protocol): # # Pip requires that RCs are named like this: '0.1.0.rc1' # But the corresponding Git tag needs to be '0.1.0rc1' -version = '1.5.0' +version = '1.5.99' # The next stable version when we are in dev. This is used to allow projects to # require meson version >=1.2.0 when using 1.1.99. FeatureNew won't warn when From 9a60deff0a4178e9b608fa76ff0bc06617d89540 Mon Sep 17 00:00:00 2001 From: Andres Freund Date: Mon, 8 Jul 2024 21:54:53 -0700 Subject: [PATCH 005/302] cmake dependency: Fix accidental use of T.Optional in warning message 09b53c534f seems to have done an over-eager search-replace. --- mesonbuild/dependencies/cmake.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/dependencies/cmake.py b/mesonbuild/dependencies/cmake.py index 66d331925574..5493e94ba79d 100644 --- a/mesonbuild/dependencies/cmake.py +++ b/mesonbuild/dependencies/cmake.py @@ -525,7 +525,7 @@ def _detect_dep(self, name: str, package_version: str, modules: T.List[T.Tuple[s for i, required in modules: if i not in self.traceparser.targets: if not required: - mlog.warning('CMake: T.Optional module', mlog.bold(self._original_module_name(i)), 'for', mlog.bold(name), 'was not found') + mlog.warning('CMake: Optional module', mlog.bold(self._original_module_name(i)), 'for', mlog.bold(name), 'was not found') continue raise self._gen_exception('CMake: invalid module {} for {}.\n' 'Try to explicitly specify one or more targets with the "modules" property.\n' From 47fd13aefcb3f1b9494b0b248073ed6e388b1dac Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Wed, 10 Jul 2024 21:32:35 +0300 Subject: [PATCH 006/302] tests: Clean up leftover files from source dirs. --- data/test.schema.json | 6 ++++++ mesonbuild/utils/universal.py | 6 +++--- run_project_tests.py | 15 ++++++++++++++- .../153 wrap file should not failed/test.json | 3 +++ .../common/258 subsubproject inplace/test.json | 3 +++ test cases/rust/25 cargo lock/test.json | 3 +++ 6 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 test cases/common/153 wrap file should not failed/test.json create mode 100644 test cases/common/258 subsubproject inplace/test.json create mode 100644 test cases/rust/25 cargo lock/test.json diff --git a/data/test.schema.json b/data/test.schema.json index 705413363771..e87e7d03a9e5 100644 --- a/data/test.schema.json +++ b/data/test.schema.json @@ -178,6 +178,12 @@ "items": { "type": "string" } + }, + "cleanup": { + "type": "array", + "items": { + "type": "string" + } } } } diff --git a/mesonbuild/utils/universal.py b/mesonbuild/utils/universal.py index 6aee268ee21b..4f18ec11bbf0 100644 --- a/mesonbuild/utils/universal.py +++ b/mesonbuild/utils/universal.py @@ -1788,7 +1788,7 @@ def get_filenames_templates_dict(inputs: T.List[str], outputs: T.List[str]) -> T return values -def _make_tree_writable(topdir: str) -> None: +def _make_tree_writable(topdir: T.Union[str, Path]) -> None: # Ensure all files and directories under topdir are writable # (and readable) by owner. for d, _, files in os.walk(topdir): @@ -1799,7 +1799,7 @@ def _make_tree_writable(topdir: str) -> None: os.chmod(fpath, os.stat(fpath).st_mode | stat.S_IWRITE | stat.S_IREAD) -def windows_proof_rmtree(f: str) -> None: +def windows_proof_rmtree(f: T.Union[str, Path]) -> None: # On Windows if anyone is holding a file open you can't # delete it. As an example an anti virus scanner might # be scanning files you are trying to delete. The only @@ -1826,7 +1826,7 @@ def windows_proof_rmtree(f: str) -> None: shutil.rmtree(f) -def windows_proof_rm(fpath: str) -> None: +def windows_proof_rm(fpath: T.Union[str, Path]) -> None: """Like windows_proof_rmtree, but for a single file.""" if os.path.isfile(fpath): os.chmod(fpath, os.stat(fpath).st_mode | stat.S_IWRITE | stat.S_IREAD) diff --git a/run_project_tests.py b/run_project_tests.py index 974273fc790e..a1feecdfc9ee 100755 --- a/run_project_tests.py +++ b/run_project_tests.py @@ -278,6 +278,7 @@ def __init__(self, path: Path, name: T.Optional[str], args: T.List[str], skip: b self.stdout: T.List[T.Dict[str, str]] = [] self.skip_category = skip_category self.skip_expected = False + self.cleanup: T.List[str] = [] # Always print a stack trace for Meson exceptions self.env['MESON_FORCE_BACKTRACE'] = '1' @@ -844,6 +845,8 @@ def load_test_json(t: TestDef, stdout_mandatory: bool, skip_category: bool = Fal (t.skip, t.skip_expected) = _skip_keys(test_def) + cleanup = test_def.get('cleanup', []) + # Skip tests if the tool requirements are not met if 'tools' in test_def: assert isinstance(test_def['tools'], dict) @@ -859,6 +862,7 @@ def load_test_json(t: TestDef, stdout_mandatory: bool, skip_category: bool = Fal t.installed_files = installed t.do_not_set_opts = do_not_set_opts t.stdout = stdout + t.cleanup = cleanup return [t] new_opt_list: T.List[T.List[T.Tuple[str, str, bool, bool]]] @@ -928,6 +932,8 @@ def load_test_json(t: TestDef, stdout_mandatory: bool, skip_category: bool = Fal test.do_not_set_opts = do_not_set_opts test.stdout = stdout test.skip_expected = skip_expected or t.skip_expected + test.cleanup = cleanup + all_tests.append(test) return all_tests @@ -1393,6 +1399,13 @@ def tqdm_print(*args: mlog.TV_Loggable, sep: str = ' ') -> None: else: f.update_log(TestStatus.OK) passing_tests += 1 + for cleanup_path in t.cleanup: + assert not os.path.isabs(cleanup_path) + abspath = t.path / cleanup_path + if abspath.is_file(): + mesonlib.windows_proof_rm(abspath) + else: + mesonlib.windows_proof_rmtree(abspath) conf_time += result.conftime build_time += result.buildtime test_time += result.testtime @@ -1550,7 +1563,7 @@ def get_version(t: ToolInfo) -> str: print() tmpdir = list(Path('.').glob('test cases/**/*install functions and follow symlinks')) -assert(len(tmpdir) == 1) +assert len(tmpdir) == 1 symlink_test_dir = tmpdir[0] symlink_file1 = symlink_test_dir / 'foo/link1' symlink_file2 = symlink_test_dir / 'foo/link2.h' diff --git a/test cases/common/153 wrap file should not failed/test.json b/test cases/common/153 wrap file should not failed/test.json new file mode 100644 index 000000000000..7763d6ebc502 --- /dev/null +++ b/test cases/common/153 wrap file should not failed/test.json @@ -0,0 +1,3 @@ +{ + "cleanup": ["subprojects/foo-1.0-patchfile"] +} diff --git a/test cases/common/258 subsubproject inplace/test.json b/test cases/common/258 subsubproject inplace/test.json new file mode 100644 index 000000000000..bf083966c031 --- /dev/null +++ b/test cases/common/258 subsubproject inplace/test.json @@ -0,0 +1,3 @@ +{ + "cleanup": ["subprojects/subsub.wrap"] +} diff --git a/test cases/rust/25 cargo lock/test.json b/test cases/rust/25 cargo lock/test.json new file mode 100644 index 000000000000..6e2a1ca1d0a2 --- /dev/null +++ b/test cases/rust/25 cargo lock/test.json @@ -0,0 +1,3 @@ +{ + "cleanup": ["subprojects/bar-0.1"] +} From 43bcaacfc9f6ed6217d2b4e3956fa3cffc207998 Mon Sep 17 00:00:00 2001 From: Alyssa Ross Date: Wed, 10 Jul 2024 11:27:32 +0200 Subject: [PATCH 007/302] docs: explain not to use extern crate in Rust code --- docs/markdown/Rust.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/markdown/Rust.md b/docs/markdown/Rust.md index 151aac080464..74f68442c638 100644 --- a/docs/markdown/Rust.md +++ b/docs/markdown/Rust.md @@ -5,6 +5,24 @@ short-description: Working with Rust in Meson # Using Rust with Meson +## Avoid using `extern crate` + +Meson can't track dependency information for crates linked by rustc as +a result of `extern crate` statements in Rust source code. If your +crate dependencies are properly expressed in Meson, there should be no +need for `extern crate` statements in your Rust code. + +An example of the problems with `extern crate` is that if you delete a +crate from a Meson build file, other crates that depend on that crate +using `extern crate` might continue linking with the leftover rlib of +the deleted crate rather than failing to build, until the build +directory is cleaned. + +This limitation could be resolved in future with rustc improvements, +for example if the [`-Z +binary-dep-depinfo`](https://github.com/rust-lang/rust/issues/63012) +feature is stabilized. + ## Mixing Rust and non-Rust sources Meson currently does not support creating a single target with Rust and non Rust From 2ad1113b7ebf09c08ae6df89e1e8d8bf1960a24a Mon Sep 17 00:00:00 2001 From: Benjamin Gilbert Date: Sat, 27 Apr 2024 06:32:11 -0500 Subject: [PATCH 008/302] tests: add werror tests for several languages --- test cases/failing build/10 nasm werror/meson.build | 8 ++++++++ test cases/failing build/10 nasm werror/test.asm | 8 ++++++++ test cases/failing build/11 objc werror/meson.build | 5 +++++ test cases/failing build/11 objc werror/test.m | 5 +++++ test cases/failing build/12 objcpp werror/meson.build | 5 +++++ test cases/failing build/12 objcpp werror/test.mm | 8 ++++++++ test cases/failing build/13 rust werror/meson.build | 8 ++++++++ test cases/failing build/13 rust werror/test.rs | 4 ++++ test cases/failing build/14 swift werror/meson.build | 5 +++++ test cases/failing build/14 swift werror/test.swift | 2 ++ test cases/failing build/5 c werror/meson.build | 2 ++ test cases/failing build/5 c werror/test.c | 3 +++ test cases/failing build/6 cpp werror/meson.build | 2 ++ test cases/failing build/6 cpp werror/test.cpp | 3 +++ test cases/failing build/7 csharp werror/meson.build | 8 ++++++++ test cases/failing build/7 csharp werror/test.cs | 8 ++++++++ test cases/failing build/8 fortran werror/meson.build | 5 +++++ test cases/failing build/8 fortran werror/test.f90 | 4 ++++ test cases/failing build/9 java werror/Test.java | 5 +++++ test cases/failing build/9 java werror/meson.build | 8 ++++++++ 20 files changed, 106 insertions(+) create mode 100644 test cases/failing build/10 nasm werror/meson.build create mode 100644 test cases/failing build/10 nasm werror/test.asm create mode 100644 test cases/failing build/11 objc werror/meson.build create mode 100644 test cases/failing build/11 objc werror/test.m create mode 100644 test cases/failing build/12 objcpp werror/meson.build create mode 100644 test cases/failing build/12 objcpp werror/test.mm create mode 100644 test cases/failing build/13 rust werror/meson.build create mode 100644 test cases/failing build/13 rust werror/test.rs create mode 100644 test cases/failing build/14 swift werror/meson.build create mode 100644 test cases/failing build/14 swift werror/test.swift create mode 100644 test cases/failing build/5 c werror/meson.build create mode 100644 test cases/failing build/5 c werror/test.c create mode 100644 test cases/failing build/6 cpp werror/meson.build create mode 100644 test cases/failing build/6 cpp werror/test.cpp create mode 100644 test cases/failing build/7 csharp werror/meson.build create mode 100644 test cases/failing build/7 csharp werror/test.cs create mode 100644 test cases/failing build/8 fortran werror/meson.build create mode 100644 test cases/failing build/8 fortran werror/test.f90 create mode 100644 test cases/failing build/9 java werror/Test.java create mode 100644 test cases/failing build/9 java werror/meson.build diff --git a/test cases/failing build/10 nasm werror/meson.build b/test cases/failing build/10 nasm werror/meson.build new file mode 100644 index 000000000000..d0c056a5debe --- /dev/null +++ b/test cases/failing build/10 nasm werror/meson.build @@ -0,0 +1,8 @@ +project('test', default_options: ['werror=true']) +if meson.backend().startswith('vs') + error('MESON_SKIP_TEST: VS backend does not recognise NASM yet') +endif +if not add_languages('nasm', required: false) + error('MESON_SKIP_TEST: nasm not found') +endif +executable('prog', 'test.asm') diff --git a/test cases/failing build/10 nasm werror/test.asm b/test cases/failing build/10 nasm werror/test.asm new file mode 100644 index 000000000000..2f7a7d6c3a4d --- /dev/null +++ b/test cases/failing build/10 nasm werror/test.asm @@ -0,0 +1,8 @@ +SECTION .text +global main +main: + mov ebx,0 + mov eax,1 + int 0x80 + +%warning oops diff --git a/test cases/failing build/11 objc werror/meson.build b/test cases/failing build/11 objc werror/meson.build new file mode 100644 index 000000000000..9f8e47828bbc --- /dev/null +++ b/test cases/failing build/11 objc werror/meson.build @@ -0,0 +1,5 @@ +project('test', default_options: ['werror=true']) +if not add_languages('objc', required: false) + error('MESON_SKIP_TEST: Objective C not found') +endif +executable('prog', 'test.m') diff --git a/test cases/failing build/11 objc werror/test.m b/test cases/failing build/11 objc werror/test.m new file mode 100644 index 000000000000..b03db466ad0c --- /dev/null +++ b/test cases/failing build/11 objc werror/test.m @@ -0,0 +1,5 @@ +#import + +int main(void) { + return 1 / 0; +} diff --git a/test cases/failing build/12 objcpp werror/meson.build b/test cases/failing build/12 objcpp werror/meson.build new file mode 100644 index 000000000000..5bc9bee2177d --- /dev/null +++ b/test cases/failing build/12 objcpp werror/meson.build @@ -0,0 +1,5 @@ +project('test', default_options: ['werror=true']) +if not add_languages('objcpp', required: false) + error('MESON_SKIP_TEST: Objective C++ not found') +endif +executable('prog', 'test.mm') diff --git a/test cases/failing build/12 objcpp werror/test.mm b/test cases/failing build/12 objcpp werror/test.mm new file mode 100644 index 000000000000..732cffa3ff17 --- /dev/null +++ b/test cases/failing build/12 objcpp werror/test.mm @@ -0,0 +1,8 @@ +#import + +class MyClass { +}; + +int main(void) { + return 1 / 0; +} diff --git a/test cases/failing build/13 rust werror/meson.build b/test cases/failing build/13 rust werror/meson.build new file mode 100644 index 000000000000..fd11de141f95 --- /dev/null +++ b/test cases/failing build/13 rust werror/meson.build @@ -0,0 +1,8 @@ +project('test', default_options: ['werror=true']) +if meson.backend() != 'ninja' + error('MESON_SKIP_TEST: Rust requires Ninja backend') +endif +if not add_languages('rust', required: false) + error('MESON_SKIP_TEST: Rust not found') +endif +executable('prog', 'test.rs') diff --git a/test cases/failing build/13 rust werror/test.rs b/test cases/failing build/13 rust werror/test.rs new file mode 100644 index 000000000000..c0e42233623c --- /dev/null +++ b/test cases/failing build/13 rust werror/test.rs @@ -0,0 +1,4 @@ +#[warn(unconditional_panic)] +fn main() { + println!("Hello, world {}!", 1 / 0); +} diff --git a/test cases/failing build/14 swift werror/meson.build b/test cases/failing build/14 swift werror/meson.build new file mode 100644 index 000000000000..1d827517efed --- /dev/null +++ b/test cases/failing build/14 swift werror/meson.build @@ -0,0 +1,5 @@ +project('test', default_options: ['werror=true']) +if not add_languages('swift', required: false) + error('MESON_SKIP_TEST: Swift not found') +endif +executable('prog', 'test.swift') diff --git a/test cases/failing build/14 swift werror/test.swift b/test cases/failing build/14 swift werror/test.swift new file mode 100644 index 000000000000..b569811d80a2 --- /dev/null +++ b/test cases/failing build/14 swift werror/test.swift @@ -0,0 +1,2 @@ +#warning("oops") +print("Hello, World!") diff --git a/test cases/failing build/5 c werror/meson.build b/test cases/failing build/5 c werror/meson.build new file mode 100644 index 000000000000..ff6026afaa21 --- /dev/null +++ b/test cases/failing build/5 c werror/meson.build @@ -0,0 +1,2 @@ +project('test', 'c', default_options: ['werror=true']) +executable('prog', 'test.c') diff --git a/test cases/failing build/5 c werror/test.c b/test cases/failing build/5 c werror/test.c new file mode 100644 index 000000000000..f0b7f0baa3d4 --- /dev/null +++ b/test cases/failing build/5 c werror/test.c @@ -0,0 +1,3 @@ +int main(int argc, char **argv) { + return 1 / 0; +} diff --git a/test cases/failing build/6 cpp werror/meson.build b/test cases/failing build/6 cpp werror/meson.build new file mode 100644 index 000000000000..0d1c4c5ba38b --- /dev/null +++ b/test cases/failing build/6 cpp werror/meson.build @@ -0,0 +1,2 @@ +project('test', 'cpp', default_options: ['werror=true']) +executable('prog', 'test.cpp') diff --git a/test cases/failing build/6 cpp werror/test.cpp b/test cases/failing build/6 cpp werror/test.cpp new file mode 100644 index 000000000000..f0b7f0baa3d4 --- /dev/null +++ b/test cases/failing build/6 cpp werror/test.cpp @@ -0,0 +1,3 @@ +int main(int argc, char **argv) { + return 1 / 0; +} diff --git a/test cases/failing build/7 csharp werror/meson.build b/test cases/failing build/7 csharp werror/meson.build new file mode 100644 index 000000000000..8e73c6ab9fc0 --- /dev/null +++ b/test cases/failing build/7 csharp werror/meson.build @@ -0,0 +1,8 @@ +project('test', default_options: ['werror=true']) +if meson.backend() != 'ninja' + error('MESON_SKIP_TEST: C# requires Ninja backend') +endif +if not add_languages('cs', required: false) + error('MESON_SKIP_TEST: C# not found') +endif +executable('prog', 'test.cs') diff --git a/test cases/failing build/7 csharp werror/test.cs b/test cases/failing build/7 csharp werror/test.cs new file mode 100644 index 000000000000..262f4d180258 --- /dev/null +++ b/test cases/failing build/7 csharp werror/test.cs @@ -0,0 +1,8 @@ +namespace HelloWorld { + class Hello { + static void Main(string[] args) { + int w = 0; // unused + System.Console.WriteLine("Hello World!"); + } + } +} diff --git a/test cases/failing build/8 fortran werror/meson.build b/test cases/failing build/8 fortran werror/meson.build new file mode 100644 index 000000000000..9cccbecb2bd6 --- /dev/null +++ b/test cases/failing build/8 fortran werror/meson.build @@ -0,0 +1,5 @@ +project('test', default_options: ['warning_level=3', 'werror=true']) +if not add_languages('fortran', required: false) + error('MESON_SKIP_TEST: Fortran not found') +endif +executable('prog', 'test.f90') diff --git a/test cases/failing build/8 fortran werror/test.f90 b/test cases/failing build/8 fortran werror/test.f90 new file mode 100644 index 000000000000..78edb8d782f4 --- /dev/null +++ b/test cases/failing build/8 fortran werror/test.f90 @@ -0,0 +1,4 @@ +program main +integer :: i +print *, ii +end program diff --git a/test cases/failing build/9 java werror/Test.java b/test cases/failing build/9 java werror/Test.java new file mode 100644 index 000000000000..3bfb2d0f0875 --- /dev/null +++ b/test cases/failing build/9 java werror/Test.java @@ -0,0 +1,5 @@ +public class Test { + public static void main(String args[]) { + System.out.println(1 / 0); + } +} diff --git a/test cases/failing build/9 java werror/meson.build b/test cases/failing build/9 java werror/meson.build new file mode 100644 index 000000000000..392325988e5d --- /dev/null +++ b/test cases/failing build/9 java werror/meson.build @@ -0,0 +1,8 @@ +project('test', default_options: ['werror=true']) +if meson.backend() != 'ninja' + error('MESON_SKIP_TEST: Java requires Ninja backend') +endif +if not add_languages('java', required: false) + error('MESON_SKIP_TEST: Java not found') +endif +jar('prog', 'Test.java') From 0fade02fe26d89d54cccc711b4d8a29143ebea8a Mon Sep 17 00:00:00 2001 From: Cepsylon Date: Thu, 27 Jun 2024 20:47:25 +0200 Subject: [PATCH 009/302] backend: xcode fix map access in generate_pbx_sources_build_phase for CustomTargetIndex Fix incorrect map access to custom_target_output_buildfile in CustomTargetIndex case. Map keys are file names with the path appended, but the used keys were just the file name. This led to crashes. --- mesonbuild/backend/xcodebackend.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mesonbuild/backend/xcodebackend.py b/mesonbuild/backend/xcodebackend.py index 69a544b240a0..344ac1f8216e 100644 --- a/mesonbuild/backend/xcodebackend.py +++ b/mesonbuild/backend/xcodebackend.py @@ -1454,7 +1454,9 @@ def generate_pbx_sources_build_phase(self, objects_dict: PbxDict) -> None: file_arr.add_item(self.custom_target_output_buildfile[o], os.path.join(self.environment.get_build_dir(), o)) elif isinstance(gt, build.CustomTargetIndex): + output_dir = self.get_custom_target_output_dir(gt) for o in gt.get_outputs(): + o = os.path.join(output_dir, o) file_arr.add_item(self.custom_target_output_buildfile[o], os.path.join(self.environment.get_build_dir(), o)) elif isinstance(gt, build.GeneratedList): From f01ae52bc224e46661e0ee4404c949e4e27773a8 Mon Sep 17 00:00:00 2001 From: Randy Eckenrode Date: Wed, 3 Apr 2024 17:35:56 -0400 Subject: [PATCH 010/302] dependencies: find extraframeworks on case-sensitive filesystems Fixes a test failure on case-sensitive filesystems when a CMake dependency is turned into an Apple framework. --- mesonbuild/dependencies/framework.py | 9 +++++++-- test cases/osx/11 case sensitive apfs/meson.build | 5 +++++ test cases/osx/11 case sensitive apfs/prog.c | 3 +++ test cases/osx/11 case sensitive apfs/test.json | 5 +++++ 4 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 test cases/osx/11 case sensitive apfs/meson.build create mode 100644 test cases/osx/11 case sensitive apfs/prog.c create mode 100644 test cases/osx/11 case sensitive apfs/test.json diff --git a/mesonbuild/dependencies/framework.py b/mesonbuild/dependencies/framework.py index 3c880c7430af..1fbd628235ba 100644 --- a/mesonbuild/dependencies/framework.py +++ b/mesonbuild/dependencies/framework.py @@ -47,6 +47,7 @@ def detect(self, name: str, paths: T.List[str]) -> None: framework_path = self._get_framework_path(p, name) if framework_path is None: continue + framework_name = framework_path.stem # We want to prefer the specified paths (in order) over the system # paths since these are "extra" frameworks. # For example, Python2's framework is in /System/Library/Frameworks and @@ -54,11 +55,15 @@ def detect(self, name: str, paths: T.List[str]) -> None: # Python.framework. We need to know for sure that the framework was # found in the path we expect. allow_system = p in self.system_framework_paths - args = self.clib_compiler.find_framework(name, self.env, [p], allow_system) + args = self.clib_compiler.find_framework(framework_name, self.env, [p], allow_system) if args is None: continue self.link_args = args self.framework_path = framework_path.as_posix() + # The search is done case-insensitively, so the found name may differ + # from the one that was requested. Setting the name ensures the correct + # one is used when linking on case-sensitive filesystems. + self.name = framework_name self.compile_args = ['-F' + self.framework_path] # We need to also add -I includes to the framework because all # cross-platform projects such as OpenGL, Python, Qt, GStreamer, @@ -74,7 +79,7 @@ def _get_framework_path(self, path: str, name: str) -> T.Optional[Path]: p = Path(path) lname = name.lower() for d in p.glob('*.framework/'): - if lname == d.name.rsplit('.', 1)[0].lower(): + if lname == d.stem.lower(): return d return None diff --git a/test cases/osx/11 case sensitive apfs/meson.build b/test cases/osx/11 case sensitive apfs/meson.build new file mode 100644 index 000000000000..dd566b185f28 --- /dev/null +++ b/test cases/osx/11 case sensitive apfs/meson.build @@ -0,0 +1,5 @@ +project('case-sensitive APFS with extra frameworks test', 'c') + +dep = dependency('FoUnDaTiOn') + +exe = executable('prog', 'prog.c', install : true, dependencies: dep) diff --git a/test cases/osx/11 case sensitive apfs/prog.c b/test cases/osx/11 case sensitive apfs/prog.c new file mode 100644 index 000000000000..9b6bdc2ec2f0 --- /dev/null +++ b/test cases/osx/11 case sensitive apfs/prog.c @@ -0,0 +1,3 @@ +int main(void) { + return 0; +} diff --git a/test cases/osx/11 case sensitive apfs/test.json b/test cases/osx/11 case sensitive apfs/test.json new file mode 100644 index 000000000000..a883714eaa27 --- /dev/null +++ b/test cases/osx/11 case sensitive apfs/test.json @@ -0,0 +1,5 @@ +{ + "installed": [ + {"type": "file", "file": "usr/bin/prog"} + ] +} From 50704bced3775e9bc5b34f4295e282bfac7253f0 Mon Sep 17 00:00:00 2001 From: Mads Andreasen Date: Sun, 7 Apr 2024 16:12:50 +0200 Subject: [PATCH 011/302] Replace exe_exists function with shutil.which() The documentation for subprocess.run at https://docs.python.org/3/library/subprocess.html#popen-constructor has a warning, pointing to using shutil.which() instead of subprocess.run for detecting if exe files exists on the path. shutil.which() is used in many places already. --- mesonbuild/environment.py | 6 +++--- mesonbuild/scripts/coverage.py | 4 ++-- mesonbuild/utils/universal.py | 11 ++--------- unittests/internaltests.py | 5 +++++ 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index be40dbcfd4be..63499676dbf0 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -109,13 +109,13 @@ def detect_llvm_cov(suffix: T.Optional[str] = None): tool = 'llvm-cov' else: tool = f'llvm-cov-{suffix}' - if mesonlib.exe_exists([tool, '--version']): + if shutil.which(tool) is not None: return tool else: # Otherwise guess in the dark tools = get_llvm_tool_names('llvm-cov') for tool in tools: - if mesonlib.exe_exists([tool, '--version']): + if shutil.which(tool): return tool return None @@ -139,7 +139,7 @@ def compute_llvm_suffix(coredata: coredata.CoreData): def detect_lcov_genhtml(lcov_exe: str = 'lcov', genhtml_exe: str = 'genhtml'): lcov_exe, lcov_version = detect_lcov(lcov_exe) - if not mesonlib.exe_exists([genhtml_exe, '--version']): + if shutil.which(genhtml_exe) is None: genhtml_exe = None return lcov_exe, lcov_version, genhtml_exe diff --git a/mesonbuild/scripts/coverage.py b/mesonbuild/scripts/coverage.py index 17a4a10ae55f..f01946944afe 100644 --- a/mesonbuild/scripts/coverage.py +++ b/mesonbuild/scripts/coverage.py @@ -5,7 +5,7 @@ from mesonbuild import environment, mesonlib -import argparse, re, sys, os, subprocess, pathlib, stat +import argparse, re, sys, os, subprocess, pathlib, stat, shutil import typing as T def coverage(outputs: T.List[str], source_root: str, subproject_root: str, build_root: str, log_dir: str, use_llvm_cov: bool, @@ -17,7 +17,7 @@ def coverage(outputs: T.List[str], source_root: str, subproject_root: str, build gcovr_exe = None else: gcovr_exe, gcovr_version = environment.detect_gcovr(gcovr_exe) - if llvm_cov_exe == '' or not mesonlib.exe_exists([llvm_cov_exe, '--version']): + if llvm_cov_exe == '' or shutil.which(llvm_cov_exe) is None: llvm_cov_exe = None lcov_exe, lcov_version, genhtml_exe = environment.detect_lcov_genhtml() diff --git a/mesonbuild/utils/universal.py b/mesonbuild/utils/universal.py index 4f18ec11bbf0..21173f5dfcd4 100644 --- a/mesonbuild/utils/universal.py +++ b/mesonbuild/utils/universal.py @@ -98,7 +98,6 @@ class _VerPickleLoadable(Protocol): 'do_conf_file', 'do_conf_str', 'do_replacement', - 'exe_exists', 'expand_arguments', 'extract_as_list', 'first', @@ -683,14 +682,8 @@ def is_qnx() -> bool: def is_aix() -> bool: return platform.system().lower() == 'aix' -def exe_exists(arglist: T.List[str]) -> bool: - try: - if subprocess.run(arglist, timeout=10).returncode == 0: - return True - except (FileNotFoundError, subprocess.TimeoutExpired): - pass - return False - +def exe_exists(exe: str) -> bool: + return shutil.which(exe) is not None @lru_cache(maxsize=None) def darwin_get_object_archs(objpath: str) -> 'ImmutableListProtocol[str]': diff --git a/unittests/internaltests.py b/unittests/internaltests.py index fe9f0d4f5cfa..2c3bcfda38e4 100644 --- a/unittests/internaltests.py +++ b/unittests/internaltests.py @@ -39,6 +39,7 @@ from mesonbuild.dependencies.pkgconfig import PkgConfigDependency, PkgConfigInterface, PkgConfigCLI from mesonbuild.programs import ExternalProgram import mesonbuild.modules.pkgconfig +from mesonbuild import utils from run_tests import ( @@ -813,6 +814,10 @@ def test_msvc_toolset_version(self): self.assertTrue(vctools_ver.startswith(toolset_ver), msg=f'{vctools_ver!r} does not start with {toolset_ver!r}') + def test_exe_exists(self): + self.assertTrue(utils.universal.exe_exists('python3')) + self.assertFalse(utils.universal.exe_exists('command_that_does_not_exist')) + def test_split_args(self): split_args = mesonbuild.mesonlib.split_args join_args = mesonbuild.mesonlib.join_args From 8e3f609e730645ca37dcb2a4291bd6514ccea2f3 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sat, 29 Jun 2024 12:41:50 +0300 Subject: [PATCH 012/302] Move project option detection into OptionStore. --- mesonbuild/ast/introspection.py | 2 +- mesonbuild/backend/ninjabackend.py | 2 +- mesonbuild/coredata.py | 6 +++--- mesonbuild/interpreter/interpreter.py | 4 ++-- mesonbuild/mconf.py | 6 +++--- mesonbuild/mintro.py | 2 +- mesonbuild/optinterpreter.py | 6 ++++-- mesonbuild/options.py | 8 ++++++++ mesonbuild/utils/universal.py | 4 ++-- unittests/platformagnostictests.py | 7 +++++-- 10 files changed, 30 insertions(+), 17 deletions(-) diff --git a/mesonbuild/ast/introspection.py b/mesonbuild/ast/introspection.py index 11975109d480..07f82dfe681a 100644 --- a/mesonbuild/ast/introspection.py +++ b/mesonbuild/ast/introspection.py @@ -105,7 +105,7 @@ def func_project(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[st if not os.path.exists(optfile): optfile = os.path.join(self.source_root, self.subdir, 'meson_options.txt') if os.path.exists(optfile): - oi = optinterpreter.OptionInterpreter(self.subproject) + oi = optinterpreter.OptionInterpreter(self.coredata.optstore, self.subproject) oi.process(optfile) assert isinstance(proj_name, str), 'for mypy' self.coredata.update_project_options(oi.options, T.cast('SubProject', proj_name)) diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index eabe75865d2c..456615eedb89 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -3603,7 +3603,7 @@ def generate_gcov_clean(self) -> None: def get_user_option_args(self): cmds = [] for k, v in self.environment.coredata.optstore.items(): - if k.is_project(): + if self.environment.coredata.optstore.is_project_option(k): cmds.append('-D' + str(k) + '=' + (v.value if isinstance(v.value, str) else str(v.value).lower())) # The order of these arguments must be the same between runs of Meson # to ensure reproducible output. The order we pass them shouldn't diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 0688e41b1bc9..30048b1c8548 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -584,7 +584,7 @@ def get_external_link_args(self, for_machine: MachineChoice, lang: str) -> T.Lis def update_project_options(self, project_options: 'MutableKeyedOptionDictType', subproject: SubProject) -> None: for key, value in project_options.items(): - if not key.is_project(): + if not self.optstore.is_project_option(key): continue if key not in self.optstore: self.optstore.add_project_option(key, value) @@ -608,7 +608,7 @@ def update_project_options(self, project_options: 'MutableKeyedOptionDictType', # Find any extranious keys for this project and remove them for key in self.optstore.keys() - project_options.keys(): - if key.is_project() and key.subproject == subproject: + if self.optstore.is_project_option(key) and key.subproject == subproject: self.optstore.remove(key) def is_cross_build(self, when_building_for: MachineChoice = MachineChoice.HOST) -> bool: @@ -906,7 +906,7 @@ def __getitem__(self, key: OptionKey) -> options.UserOption: # FIXME: This is fundamentally the same algorithm than interpreter.get_option_internal(). # We should try to share the code somehow. key = key.evolve(subproject=self.subproject) - if not key.is_project(): + if not key.is_project_hack_for_optionsview(): opt = self.original_options.get(key) if opt is None or opt.yielding: key2 = key.as_root() diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index 13f7f224dcc7..742d24c89b22 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -1051,7 +1051,7 @@ def _do_subproject_cargo(self, subp_name: str, subdir: str, def get_option_internal(self, optname: str) -> options.UserOption: key = OptionKey.from_string(optname).evolve(subproject=self.subproject) - if not key.is_project(): + if not self.environment.coredata.optstore.is_project_option(key): for opts in [self.coredata.optstore, compilers.base_options]: v = opts.get(key) if v is None or v.yielding: @@ -1198,7 +1198,7 @@ def func_project(self, node: mparser.FunctionNode, args: T.Tuple[str, T.List[str # We want fast not cryptographically secure, this is just to # see if the option file has changed self.coredata.options_files[self.subproject] = (option_file, hashlib.sha1(f.read()).hexdigest()) - oi = optinterpreter.OptionInterpreter(self.subproject) + oi = optinterpreter.OptionInterpreter(self.environment.coredata.optstore, self.subproject) oi.process(option_file) self.coredata.update_project_options(oi.options, self.subproject) self.add_build_def_file(option_file) diff --git a/mesonbuild/mconf.py b/mesonbuild/mconf.py index da96ac41ff3b..1294479d6390 100644 --- a/mesonbuild/mconf.py +++ b/mesonbuild/mconf.py @@ -92,7 +92,7 @@ def __init__(self, build_dir: str): with open(opfile, 'rb') as f: ophash = hashlib.sha1(f.read()).hexdigest() if ophash != conf_options[1]: - oi = OptionInterpreter(sub) + oi = OptionInterpreter(self.coredata.optstore, sub) oi.process(opfile) self.coredata.update_project_options(oi.options, sub) self.coredata.options_files[sub] = (opfile, ophash) @@ -101,7 +101,7 @@ def __init__(self, build_dir: str): if not os.path.exists(opfile): opfile = os.path.join(self.source_dir, 'meson_options.txt') if os.path.exists(opfile): - oi = OptionInterpreter(sub) + oi = OptionInterpreter(self.coredata.optstore, sub) oi.process(opfile) self.coredata.update_project_options(oi.options, sub) with open(opfile, 'rb') as f: @@ -284,7 +284,7 @@ def print_default_values_warning() -> None: build_core_options = self.split_options_per_subproject({k: v for k, v in core_options.items() if k.machine is MachineChoice.BUILD}) host_compiler_options = self.split_options_per_subproject({k: v for k, v in self.coredata.optstore.items() if k.is_compiler() and k.machine is MachineChoice.HOST}) build_compiler_options = self.split_options_per_subproject({k: v for k, v in self.coredata.optstore.items() if k.is_compiler() and k.machine is MachineChoice.BUILD}) - project_options = self.split_options_per_subproject({k: v for k, v in self.coredata.optstore.items() if k.is_project()}) + project_options = self.split_options_per_subproject({k: v for k, v in self.coredata.optstore.items() if self.coredata.optstore.is_project_option(k)}) show_build_options = self.default_values_only or self.build.environment.is_cross_build() self.add_section('Main project options') diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py index dea67d82e1cd..17d1b08fb320 100644 --- a/mesonbuild/mintro.py +++ b/mesonbuild/mintro.py @@ -335,7 +335,7 @@ def add_keys(opts: 'T.Union[dict[OptionKey, UserOption[Any]], cdata.KeyedOptionD 'compiler', ) add_keys(dir_options, 'directory') - add_keys({k: v for k, v in coredata.optstore.items() if k.is_project()}, 'user') + add_keys({k: v for k, v in coredata.optstore.items() if coredata.optstore.is_project_option(k)}, 'user') add_keys(test_options, 'test') return optlist diff --git a/mesonbuild/optinterpreter.py b/mesonbuild/optinterpreter.py index ffa46cda650e..a456a182bf4f 100644 --- a/mesonbuild/optinterpreter.py +++ b/mesonbuild/optinterpreter.py @@ -18,6 +18,7 @@ from .interpreterbase import TYPE_var, TYPE_kwargs from .interpreterbase import SubProject from typing_extensions import TypedDict, Literal + from .options import OptionStore _DEPRECATED_ARGS = T.Union[bool, str, T.Dict[str, str], T.List[str]] @@ -64,7 +65,7 @@ class OptionException(mesonlib.MesonException): class OptionInterpreter: - def __init__(self, subproject: 'SubProject') -> None: + def __init__(self, optionstore: 'OptionStore', subproject: 'SubProject') -> None: self.options: 'coredata.MutableKeyedOptionDictType' = {} self.subproject = subproject self.option_types: T.Dict[str, T.Callable[..., options.UserOption]] = { @@ -75,6 +76,7 @@ def __init__(self, subproject: 'SubProject') -> None: 'array': self.string_array_parser, 'feature': self.feature_parser, } + self.optionstore = optionstore def process(self, option_file: str) -> None: try: @@ -189,7 +191,7 @@ def func_option(self, args: T.Tuple[str], kwargs: 'FuncOptionArgs') -> None: if optname_regex.search(opt_name) is not None: raise OptionException('Option names can only contain letters, numbers or dashes.') key = mesonlib.OptionKey.from_string(opt_name).evolve(subproject=self.subproject) - if not key.is_project(): + if self.optionstore.is_reserved_name(key): raise OptionException('Option name %s is reserved.' % opt_name) opt_type = kwargs['type'] diff --git a/mesonbuild/options.py b/mesonbuild/options.py index d83a312886d5..e88710d086f1 100644 --- a/mesonbuild/options.py +++ b/mesonbuild/options.py @@ -8,6 +8,7 @@ from .mesonlib import ( HoldableObject, OptionKey, + OptionType, default_prefix, default_datadir, default_includedir, @@ -536,3 +537,10 @@ def setdefault(self, k, o): def get(self, *args, **kwargs) -> UserOption: return self.d.get(*args, **kwargs) + + def is_project_option(self, key: OptionKey) -> bool: + """Convenience method to check if this is a project option.""" + return key.type is OptionType.PROJECT + + def is_reserved_name(self, key: OptionKey) -> bool: + return not self.is_project_option(key) diff --git a/mesonbuild/utils/universal.py b/mesonbuild/utils/universal.py index 21173f5dfcd4..080f2a76d8f6 100644 --- a/mesonbuild/utils/universal.py +++ b/mesonbuild/utils/universal.py @@ -2399,8 +2399,8 @@ def is_compiler(self) -> bool: """Convenience method to check if this is a builtin option.""" return self.type is OptionType.COMPILER - def is_project(self) -> bool: - """Convenience method to check if this is a project option.""" + def is_project_hack_for_optionsview(self) -> bool: + """This method will be removed once we can delete OptionsView.""" return self.type is OptionType.PROJECT def is_base(self) -> bool: diff --git a/unittests/platformagnostictests.py b/unittests/platformagnostictests.py index fe598a72bb80..4ac4b7a556c6 100644 --- a/unittests/platformagnostictests.py +++ b/unittests/platformagnostictests.py @@ -18,6 +18,7 @@ from mesonbuild.mesonlib import EnvironmentVariables, ExecutableSerialisation, MesonException, is_linux, python_command from mesonbuild.mformat import match_path from mesonbuild.optinterpreter import OptionInterpreter, OptionException +from mesonbuild.options import OptionStore from run_tests import Backend @skipIf(is_ci() and not is_linux(), "Run only on fast platforms") @@ -35,7 +36,8 @@ def test_relative_find_program(self): self.init(testdir, workdir=testdir) def test_invalid_option_names(self): - interp = OptionInterpreter('') + store = OptionStore() + interp = OptionInterpreter(store, '') def write_file(code: str): with tempfile.NamedTemporaryFile('w', dir=self.builddir, encoding='utf-8', delete=False) as f: @@ -68,7 +70,8 @@ def write_file(code: str): def test_option_validation(self): """Test cases that are not catch by the optinterpreter itself.""" - interp = OptionInterpreter('') + store = OptionStore() + interp = OptionInterpreter(store, '') def write_file(code: str): with tempfile.NamedTemporaryFile('w', dir=self.builddir, encoding='utf-8', delete=False) as f: From 0c36ace4b783f17dd7c60eefd7aca8b4556c519a Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sat, 29 Jun 2024 18:14:00 +0300 Subject: [PATCH 013/302] Move base option check into OptionStore. --- mesonbuild/mconf.py | 2 +- mesonbuild/mintro.py | 2 +- mesonbuild/options.py | 4 ++++ mesonbuild/utils/universal.py | 4 ---- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mesonbuild/mconf.py b/mesonbuild/mconf.py index 1294479d6390..dd11e2ddb7b1 100644 --- a/mesonbuild/mconf.py +++ b/mesonbuild/mconf.py @@ -292,7 +292,7 @@ def print_default_values_warning() -> None: if show_build_options: self.print_options('', build_core_options['']) self.print_options('Backend options', {k: v for k, v in self.coredata.optstore.items() if k.is_backend()}) - self.print_options('Base options', {k: v for k, v in self.coredata.optstore.items() if k.is_base()}) + self.print_options('Base options', {k: v for k, v in self.coredata.optstore.items() if self.coredata.optstore.is_base_option(k)}) self.print_options('Compiler options', host_compiler_options.get('', {})) if show_build_options: self.print_options('', build_compiler_options.get('', {})) diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py index 17d1b08fb320..a49c6e1373de 100644 --- a/mesonbuild/mintro.py +++ b/mesonbuild/mintro.py @@ -329,7 +329,7 @@ def add_keys(opts: 'T.Union[dict[OptionKey, UserOption[Any]], cdata.KeyedOptionD add_keys(core_options, 'core') add_keys({k: v for k, v in coredata.optstore.items() if k.is_backend()}, 'backend') - add_keys({k: v for k, v in coredata.optstore.items() if k.is_base()}, 'base') + add_keys({k: v for k, v in coredata.optstore.items() if coredata.optstore.is_base_option(k)}, 'base') add_keys( {k: v for k, v in sorted(coredata.optstore.items(), key=lambda i: i[0].machine) if k.is_compiler()}, 'compiler', diff --git a/mesonbuild/options.py b/mesonbuild/options.py index e88710d086f1..87f82ba63f10 100644 --- a/mesonbuild/options.py +++ b/mesonbuild/options.py @@ -544,3 +544,7 @@ def is_project_option(self, key: OptionKey) -> bool: def is_reserved_name(self, key: OptionKey) -> bool: return not self.is_project_option(key) + + def is_base_option(self, key: OptionKey) -> bool: + """Convenience method to check if this is a base option.""" + return key.type is OptionType.BASE diff --git a/mesonbuild/utils/universal.py b/mesonbuild/utils/universal.py index 080f2a76d8f6..31f67693a415 100644 --- a/mesonbuild/utils/universal.py +++ b/mesonbuild/utils/universal.py @@ -2403,10 +2403,6 @@ def is_project_hack_for_optionsview(self) -> bool: """This method will be removed once we can delete OptionsView.""" return self.type is OptionType.PROJECT - def is_base(self) -> bool: - """Convenience method to check if this is a base option.""" - return self.type is OptionType.BASE - def pickle_load(filename: str, object_name: str, object_type: T.Type[_PL], suggest_reconfigure: bool = True) -> _PL: load_fail_msg = f'{object_name} file {filename!r} is corrupted.' From 472d8852e9d9b21d0a20f52d37915127e556e8d9 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sat, 29 Jun 2024 18:29:52 +0300 Subject: [PATCH 014/302] Move backend option check into OptionStore. --- mesonbuild/ast/introspection.py | 2 +- mesonbuild/interpreter/interpreter.py | 2 +- mesonbuild/mconf.py | 2 +- mesonbuild/mintro.py | 2 +- mesonbuild/options.py | 4 ++++ mesonbuild/utils/universal.py | 4 ---- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/mesonbuild/ast/introspection.py b/mesonbuild/ast/introspection.py index 07f82dfe681a..412070dcd6ee 100644 --- a/mesonbuild/ast/introspection.py +++ b/mesonbuild/ast/introspection.py @@ -130,7 +130,7 @@ def func_project(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[st self.do_subproject(SubProject(i)) self.coredata.init_backend_options(self.backend) - options = {k: v for k, v in self.environment.options.items() if k.is_backend()} + options = {k: v for k, v in self.environment.options.items() if self.environment.coredata.optstore.is_backend_option(k)} self.coredata.set_options(options) self._add_languages(proj_langs, True, MachineChoice.HOST) diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index 742d24c89b22..aac63b157ac4 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -1148,7 +1148,7 @@ def set_backend(self) -> None: if self.environment.first_invocation: self.coredata.init_backend_options(backend_name) - options = {k: v for k, v in self.environment.options.items() if k.is_backend()} + options = {k: v for k, v in self.environment.options.items() if self.environment.coredata.optstore.is_backend_option(k)} self.coredata.set_options(options) @typed_pos_args('project', str, varargs=str) diff --git a/mesonbuild/mconf.py b/mesonbuild/mconf.py index dd11e2ddb7b1..0f345d96a750 100644 --- a/mesonbuild/mconf.py +++ b/mesonbuild/mconf.py @@ -291,7 +291,7 @@ def print_default_values_warning() -> None: self.print_options('Core options', host_core_options['']) if show_build_options: self.print_options('', build_core_options['']) - self.print_options('Backend options', {k: v for k, v in self.coredata.optstore.items() if k.is_backend()}) + self.print_options('Backend options', {k: v for k, v in self.coredata.optstore.items() if self.coredata.optstore.is_backend_option(k)}) self.print_options('Base options', {k: v for k, v in self.coredata.optstore.items() if self.coredata.optstore.is_base_option(k)}) self.print_options('Compiler options', host_compiler_options.get('', {})) if show_build_options: diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py index a49c6e1373de..da1afdbd5f5e 100644 --- a/mesonbuild/mintro.py +++ b/mesonbuild/mintro.py @@ -328,7 +328,7 @@ def add_keys(opts: 'T.Union[dict[OptionKey, UserOption[Any]], cdata.KeyedOptionD optlist.append(optdict) add_keys(core_options, 'core') - add_keys({k: v for k, v in coredata.optstore.items() if k.is_backend()}, 'backend') + add_keys({k: v for k, v in coredata.optstore.items() if coredata.optstore.is_backend_option(k)}, 'backend') add_keys({k: v for k, v in coredata.optstore.items() if coredata.optstore.is_base_option(k)}, 'base') add_keys( {k: v for k, v in sorted(coredata.optstore.items(), key=lambda i: i[0].machine) if k.is_compiler()}, diff --git a/mesonbuild/options.py b/mesonbuild/options.py index 87f82ba63f10..4af9c97ac8bc 100644 --- a/mesonbuild/options.py +++ b/mesonbuild/options.py @@ -548,3 +548,7 @@ def is_reserved_name(self, key: OptionKey) -> bool: def is_base_option(self, key: OptionKey) -> bool: """Convenience method to check if this is a base option.""" return key.type is OptionType.BASE + + def is_backend_option(self, key: OptionKey) -> bool: + """Convenience method to check if this is a backend option.""" + return key.type is OptionType.BACKEND diff --git a/mesonbuild/utils/universal.py b/mesonbuild/utils/universal.py index 31f67693a415..97cc0dc3a6e0 100644 --- a/mesonbuild/utils/universal.py +++ b/mesonbuild/utils/universal.py @@ -2387,10 +2387,6 @@ def as_host(self) -> 'OptionKey': """Convenience method for key.evolve(machine=MachineChoice.HOST).""" return self.evolve(machine=MachineChoice.HOST) - def is_backend(self) -> bool: - """Convenience method to check if this is a backend option.""" - return self.type is OptionType.BACKEND - def is_builtin(self) -> bool: """Convenience method to check if this is a builtin option.""" return self.type is OptionType.BUILTIN From 5c6e9d2d8fa25d62f1d249d265611a6dbbc03a4b Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sat, 29 Jun 2024 18:42:40 +0300 Subject: [PATCH 015/302] Move builtin option check into OptionStore. --- mesonbuild/coredata.py | 4 ++-- mesonbuild/mconf.py | 2 +- mesonbuild/mintro.py | 2 +- mesonbuild/options.py | 4 ++++ mesonbuild/utils/universal.py | 4 ---- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 30048b1c8548..ded230418923 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -453,7 +453,7 @@ def get_option(self, key: OptionKey) -> T.Union[T.List[str], str, int, bool]: def set_option(self, key: OptionKey, value, first_invocation: bool = False) -> bool: dirty = False - if key.is_builtin(): + if self.optstore.is_builtin_option(key): if key.name == 'prefix': value = self.sanitize_prefix(value) else: @@ -694,7 +694,7 @@ def set_default_options(self, default_options: T.MutableMapping[OptionKey, str], # Always test this using the HOST machine, as many builtin options # are not valid for the BUILD machine, but the yielding value does # not differ between them even when they are valid for both. - if subproject and k.is_builtin() and self.optstore.get_value_object(k.evolve(subproject='', machine=MachineChoice.HOST)).yielding: + if subproject and self.optstore.is_builtin_option(k) and self.optstore.get_value_object(k.evolve(subproject='', machine=MachineChoice.HOST)).yielding: continue # Skip base, compiler, and backend options, they are handled when # adding languages and setting backend. diff --git a/mesonbuild/mconf.py b/mesonbuild/mconf.py index 0f345d96a750..0d73b5be2a86 100644 --- a/mesonbuild/mconf.py +++ b/mesonbuild/mconf.py @@ -277,7 +277,7 @@ def print_default_values_warning() -> None: if self.build and k.module not in self.build.modules: continue module_options[k.module][k] = v - elif k.is_builtin(): + elif self.coredata.optstore.is_builtin_option(k): core_options[k] = v host_core_options = self.split_options_per_subproject({k: v for k, v in core_options.items() if k.machine is MachineChoice.HOST}) diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py index da1afdbd5f5e..7fecfd01f0ed 100644 --- a/mesonbuild/mintro.py +++ b/mesonbuild/mintro.py @@ -298,7 +298,7 @@ def list_buildoptions(coredata: cdata.CoreData, subprojects: T.Optional[T.List[s dir_options[k] = v elif k in test_option_names: test_options[k] = v - elif k.is_builtin(): + elif coredata.optstore.is_builtin_option(k): core_options[k] = v if not v.yielding: for s in subprojects: diff --git a/mesonbuild/options.py b/mesonbuild/options.py index 4af9c97ac8bc..4b9e61f43b7f 100644 --- a/mesonbuild/options.py +++ b/mesonbuild/options.py @@ -545,6 +545,10 @@ def is_project_option(self, key: OptionKey) -> bool: def is_reserved_name(self, key: OptionKey) -> bool: return not self.is_project_option(key) + def is_builtin_option(self, key: OptionKey) -> bool: + """Convenience method to check if this is a builtin option.""" + return key.type is OptionType.BUILTIN + def is_base_option(self, key: OptionKey) -> bool: """Convenience method to check if this is a base option.""" return key.type is OptionType.BASE diff --git a/mesonbuild/utils/universal.py b/mesonbuild/utils/universal.py index 97cc0dc3a6e0..5f533f23743f 100644 --- a/mesonbuild/utils/universal.py +++ b/mesonbuild/utils/universal.py @@ -2387,10 +2387,6 @@ def as_host(self) -> 'OptionKey': """Convenience method for key.evolve(machine=MachineChoice.HOST).""" return self.evolve(machine=MachineChoice.HOST) - def is_builtin(self) -> bool: - """Convenience method to check if this is a builtin option.""" - return self.type is OptionType.BUILTIN - def is_compiler(self) -> bool: """Convenience method to check if this is a builtin option.""" return self.type is OptionType.COMPILER From c2552527fb2f607052c7aed633b67dbb19f06e38 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sat, 29 Jun 2024 18:50:31 +0300 Subject: [PATCH 016/302] Move compiler option check into OptionStore. --- mesonbuild/mconf.py | 4 ++-- mesonbuild/mintro.py | 2 +- mesonbuild/options.py | 4 ++++ mesonbuild/utils/universal.py | 4 ---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/mesonbuild/mconf.py b/mesonbuild/mconf.py index 0d73b5be2a86..0a88e57edef2 100644 --- a/mesonbuild/mconf.py +++ b/mesonbuild/mconf.py @@ -282,8 +282,8 @@ def print_default_values_warning() -> None: host_core_options = self.split_options_per_subproject({k: v for k, v in core_options.items() if k.machine is MachineChoice.HOST}) build_core_options = self.split_options_per_subproject({k: v for k, v in core_options.items() if k.machine is MachineChoice.BUILD}) - host_compiler_options = self.split_options_per_subproject({k: v for k, v in self.coredata.optstore.items() if k.is_compiler() and k.machine is MachineChoice.HOST}) - build_compiler_options = self.split_options_per_subproject({k: v for k, v in self.coredata.optstore.items() if k.is_compiler() and k.machine is MachineChoice.BUILD}) + host_compiler_options = self.split_options_per_subproject({k: v for k, v in self.coredata.optstore.items() if self.coredata.optstore.is_compiler_option(k) and k.machine is MachineChoice.HOST}) + build_compiler_options = self.split_options_per_subproject({k: v for k, v in self.coredata.optstore.items() if self.coredata.optstore.is_compiler_option(k) and k.machine is MachineChoice.BUILD}) project_options = self.split_options_per_subproject({k: v for k, v in self.coredata.optstore.items() if self.coredata.optstore.is_project_option(k)}) show_build_options = self.default_values_only or self.build.environment.is_cross_build() diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py index 7fecfd01f0ed..718bfb029f18 100644 --- a/mesonbuild/mintro.py +++ b/mesonbuild/mintro.py @@ -331,7 +331,7 @@ def add_keys(opts: 'T.Union[dict[OptionKey, UserOption[Any]], cdata.KeyedOptionD add_keys({k: v for k, v in coredata.optstore.items() if coredata.optstore.is_backend_option(k)}, 'backend') add_keys({k: v for k, v in coredata.optstore.items() if coredata.optstore.is_base_option(k)}, 'base') add_keys( - {k: v for k, v in sorted(coredata.optstore.items(), key=lambda i: i[0].machine) if k.is_compiler()}, + {k: v for k, v in sorted(coredata.optstore.items(), key=lambda i: i[0].machine) if coredata.optstore.is_compiler_option(k)}, 'compiler', ) add_keys(dir_options, 'directory') diff --git a/mesonbuild/options.py b/mesonbuild/options.py index 4b9e61f43b7f..631868628f0e 100644 --- a/mesonbuild/options.py +++ b/mesonbuild/options.py @@ -556,3 +556,7 @@ def is_base_option(self, key: OptionKey) -> bool: def is_backend_option(self, key: OptionKey) -> bool: """Convenience method to check if this is a backend option.""" return key.type is OptionType.BACKEND + + def is_compiler_option(self, key: OptionKey) -> bool: + """Convenience method to check if this is a compiler option.""" + return key.type is OptionType.COMPILER diff --git a/mesonbuild/utils/universal.py b/mesonbuild/utils/universal.py index 5f533f23743f..4db209a73fbb 100644 --- a/mesonbuild/utils/universal.py +++ b/mesonbuild/utils/universal.py @@ -2387,10 +2387,6 @@ def as_host(self) -> 'OptionKey': """Convenience method for key.evolve(machine=MachineChoice.HOST).""" return self.evolve(machine=MachineChoice.HOST) - def is_compiler(self) -> bool: - """Convenience method to check if this is a builtin option.""" - return self.type is OptionType.COMPILER - def is_project_hack_for_optionsview(self) -> bool: """This method will be removed once we can delete OptionsView.""" return self.type is OptionType.PROJECT From 0d7bb776e2d97d406b726b90090bbfa8df13232b Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sun, 30 Jun 2024 13:16:42 +0300 Subject: [PATCH 017/302] Move OptionKey in the option source file. --- mesonbuild/ast/introspection.py | 3 +- mesonbuild/backend/backends.py | 6 +- mesonbuild/backend/ninjabackend.py | 3 +- mesonbuild/backend/vs2010backend.py | 3 +- mesonbuild/backend/xcodebackend.py | 3 +- mesonbuild/build.py | 4 +- mesonbuild/cargo/interpreter.py | 3 +- mesonbuild/cmake/common.py | 3 +- mesonbuild/cmake/executor.py | 3 +- mesonbuild/cmake/interpreter.py | 3 +- mesonbuild/compilers/asm.py | 3 +- mesonbuild/compilers/compilers.py | 4 +- mesonbuild/compilers/cuda.py | 3 +- mesonbuild/compilers/d.py | 3 +- mesonbuild/compilers/mixins/arm.py | 2 +- mesonbuild/compilers/mixins/clang.py | 2 +- mesonbuild/compilers/mixins/elbrus.py | 3 +- mesonbuild/compilers/mixins/emscripten.py | 2 +- mesonbuild/compilers/mixins/gnu.py | 2 +- mesonbuild/compilers/mixins/intel.py | 3 +- mesonbuild/compilers/mixins/metrowerks.py | 3 +- mesonbuild/compilers/mixins/pgi.py | 2 +- mesonbuild/compilers/mixins/visualstudio.py | 5 +- mesonbuild/compilers/objc.py | 2 +- mesonbuild/compilers/objcpp.py | 2 +- mesonbuild/compilers/rust.py | 3 +- mesonbuild/compilers/vala.py | 3 +- mesonbuild/coredata.py | 4 +- mesonbuild/dependencies/base.py | 4 +- mesonbuild/dependencies/boost.py | 3 +- mesonbuild/dependencies/dub.py | 3 +- mesonbuild/dependencies/misc.py | 3 +- mesonbuild/dependencies/pkgconfig.py | 3 +- mesonbuild/dependencies/python.py | 7 +- mesonbuild/dependencies/qt.py | 5 +- mesonbuild/dependencies/scalapack.py | 2 +- mesonbuild/environment.py | 3 +- mesonbuild/interpreter/compiler.py | 2 +- mesonbuild/interpreter/dependencyfallbacks.py | 3 +- mesonbuild/interpreter/interpreter.py | 3 +- mesonbuild/interpreter/kwargs.py | 3 +- mesonbuild/interpreter/mesonmain.py | 3 +- mesonbuild/interpreter/type_checking.py | 3 +- mesonbuild/mcompile.py | 5 +- mesonbuild/mconf.py | 3 +- mesonbuild/mdevenv.py | 3 +- mesonbuild/mdist.py | 3 +- mesonbuild/minit.py | 3 +- mesonbuild/minstall.py | 3 +- mesonbuild/mintro.py | 2 +- mesonbuild/modules/__init__.py | 5 +- mesonbuild/modules/cmake.py | 7 +- mesonbuild/modules/external_project.py | 3 +- mesonbuild/modules/gnome.py | 11 +- mesonbuild/modules/hotdoc.py | 3 +- mesonbuild/modules/i18n.py | 3 +- mesonbuild/modules/pkgconfig.py | 11 +- mesonbuild/modules/python.py | 7 +- mesonbuild/msetup.py | 11 +- mesonbuild/mtest.py | 3 +- mesonbuild/munstable_coredata.py | 3 +- mesonbuild/optinterpreter.py | 3 +- mesonbuild/options.py | 238 +++++++++++++- mesonbuild/scripts/regen_checker.py | 2 +- mesonbuild/utils/universal.py | 292 ++++-------------- run_tests.py | 3 +- unittests/allplatformstests.py | 3 +- unittests/datatests.py | 5 +- unittests/helpers.py | 3 +- unittests/internaltests.py | 4 +- unittests/linuxliketests.py | 3 +- unittests/windowstests.py | 3 +- 72 files changed, 445 insertions(+), 338 deletions(-) diff --git a/mesonbuild/ast/introspection.py b/mesonbuild/ast/introspection.py index 412070dcd6ee..89df1d25a86a 100644 --- a/mesonbuild/ast/introspection.py +++ b/mesonbuild/ast/introspection.py @@ -15,7 +15,8 @@ from ..build import Executable, Jar, SharedLibrary, SharedModule, StaticLibrary from ..compilers import detect_compiler_for from ..interpreterbase import InvalidArguments, SubProject -from ..mesonlib import MachineChoice, OptionKey +from ..mesonlib import MachineChoice +from ..options import OptionKey from ..mparser import BaseNode, ArithmeticNode, ArrayNode, ElementaryNode, IdNode, FunctionNode, StringNode from .interpreter import AstInterpreter diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index b664300f4006..0defad63e6fd 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -27,8 +27,10 @@ from ..compilers import LANGUAGES_USING_LDFLAGS, detect from ..mesonlib import ( File, MachineChoice, MesonException, OrderedSet, - ExecutableSerialisation, classify_unity_sources, OptionKey + ExecutableSerialisation, classify_unity_sources, ) +from ..options import OptionKey + if T.TYPE_CHECKING: from .._typing import ImmutableListProtocol @@ -1677,7 +1679,7 @@ def guess_install_tag(self, fname: str, outdir: T.Optional[str] = None) -> T.Opt bindir = Path(prefix, self.environment.get_bindir()) libdir = Path(prefix, self.environment.get_libdir()) incdir = Path(prefix, self.environment.get_includedir()) - _ldir = self.environment.coredata.get_option(mesonlib.OptionKey('localedir')) + _ldir = self.environment.coredata.get_option(OptionKey('localedir')) assert isinstance(_ldir, str), 'for mypy' localedir = Path(prefix, _ldir) dest_path = Path(prefix, outdir, Path(fname).name) if outdir else Path(prefix, fname) diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 456615eedb89..d46dfacbaeb6 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -31,7 +31,8 @@ File, LibType, MachineChoice, MesonBugException, MesonException, OrderedSet, PerMachine, ProgressBar, quote_arg ) -from ..mesonlib import get_compiler_for_source, has_path_sep, OptionKey +from ..mesonlib import get_compiler_for_source, has_path_sep +from ..options import OptionKey from .backends import CleanTrees from ..build import GeneratedList, InvalidArguments diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py index 496e8ffed404..2187b8fa02cc 100644 --- a/mesonbuild/backend/vs2010backend.py +++ b/mesonbuild/backend/vs2010backend.py @@ -19,8 +19,9 @@ from .. import compilers from .. import mesonlib from ..mesonlib import ( - File, MesonBugException, MesonException, replace_if_different, OptionKey, version_compare, MachineChoice + File, MesonBugException, MesonException, replace_if_different, version_compare, MachineChoice ) +from ..options import OptionKey from ..environment import Environment, build_filename from .. import coredata diff --git a/mesonbuild/backend/xcodebackend.py b/mesonbuild/backend/xcodebackend.py index f98ba7983932..e1e8c58542c8 100644 --- a/mesonbuild/backend/xcodebackend.py +++ b/mesonbuild/backend/xcodebackend.py @@ -11,7 +11,8 @@ from .. import mesonlib from .. import mlog from ..arglist import CompilerArgs -from ..mesonlib import MesonBugException, MesonException, OptionKey +from ..mesonlib import MesonBugException, MesonException +from ..options import OptionKey if T.TYPE_CHECKING: from ..build import BuildTarget diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 071dbdfd4562..c86b6661336c 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -23,9 +23,11 @@ File, MesonException, MachineChoice, PerMachine, OrderedSet, listify, extract_as_list, typeslistify, stringlistify, classify_unity_sources, get_filenames_templates_dict, substitute_values, has_path_sep, - OptionKey, PerMachineDefaultable, + PerMachineDefaultable, MesonBugException, EnvironmentVariables, pickle_load, ) +from .options import OptionKey + from .compilers import ( is_header, is_object, is_source, clink_langs, sort_clink, all_languages, is_known_suffix, detect_static_linker diff --git a/mesonbuild/cargo/interpreter.py b/mesonbuild/cargo/interpreter.py index 33b9d6073e4b..6c84672bcd6a 100644 --- a/mesonbuild/cargo/interpreter.py +++ b/mesonbuild/cargo/interpreter.py @@ -23,7 +23,8 @@ from . import builder from . import version -from ..mesonlib import MesonException, Popen_safe, OptionKey +from ..mesonlib import MesonException, Popen_safe +from ..options import OptionKey from .. import coredata, options, mlog from ..wrap.wrap import PackageDefinition diff --git a/mesonbuild/cmake/common.py b/mesonbuild/cmake/common.py index ad4ec6b1a002..d9ff559971f7 100644 --- a/mesonbuild/cmake/common.py +++ b/mesonbuild/cmake/common.py @@ -3,7 +3,8 @@ from __future__ import annotations -from ..mesonlib import MesonException, OptionKey +from ..mesonlib import MesonException +from ..options import OptionKey from .. import mlog from pathlib import Path import typing as T diff --git a/mesonbuild/cmake/executor.py b/mesonbuild/cmake/executor.py index 392063d58590..cbe75f36c688 100644 --- a/mesonbuild/cmake/executor.py +++ b/mesonbuild/cmake/executor.py @@ -10,7 +10,8 @@ import os from .. import mlog -from ..mesonlib import PerMachine, Popen_safe, version_compare, is_windows, OptionKey +from ..mesonlib import PerMachine, Popen_safe, version_compare, is_windows +from ..options import OptionKey from ..programs import find_external_program, NonExistingExternalProgram if T.TYPE_CHECKING: diff --git a/mesonbuild/cmake/interpreter.py b/mesonbuild/cmake/interpreter.py index f67591f68b98..5e6cde653516 100644 --- a/mesonbuild/cmake/interpreter.py +++ b/mesonbuild/cmake/interpreter.py @@ -18,7 +18,8 @@ from .traceparser import CMakeTraceParser from .tracetargets import resolve_cmake_trace_targets from .. import mlog, mesonlib -from ..mesonlib import MachineChoice, OrderedSet, path_is_in_root, relative_to_if_possible, OptionKey +from ..mesonlib import MachineChoice, OrderedSet, path_is_in_root, relative_to_if_possible +from ..options import OptionKey from ..mesondata import DataFile from ..compilers.compilers import assembler_suffixes, lang_suffixes, header_suffixes, obj_suffixes, lib_suffixes, is_header from ..programs import ExternalProgram diff --git a/mesonbuild/compilers/asm.py b/mesonbuild/compilers/asm.py index e25f18d6746d..cefda765f881 100644 --- a/mesonbuild/compilers/asm.py +++ b/mesonbuild/compilers/asm.py @@ -3,7 +3,8 @@ import os import typing as T -from ..mesonlib import EnvironmentException, OptionKey, get_meson_command +from ..mesonlib import EnvironmentException, get_meson_command +from ..options import OptionKey from .compilers import Compiler from .mixins.metrowerks import MetrowerksCompiler, mwasmarm_instruction_set_args, mwasmeppc_instruction_set_args diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 08a596c7078c..215946a7e663 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -19,9 +19,11 @@ from ..mesonlib import ( HoldableObject, EnvironmentException, MesonException, - Popen_safe_logged, LibType, TemporaryDirectoryWinProof, OptionKey, + Popen_safe_logged, LibType, TemporaryDirectoryWinProof, ) +from ..options import OptionKey + from ..arglist import CompilerArgs if T.TYPE_CHECKING: diff --git a/mesonbuild/compilers/cuda.py b/mesonbuild/compilers/cuda.py index dc9cf8addd35..e991683a7af6 100644 --- a/mesonbuild/compilers/cuda.py +++ b/mesonbuild/compilers/cuda.py @@ -13,8 +13,9 @@ from .. import mlog from ..mesonlib import ( EnvironmentException, Popen_safe, - is_windows, LibType, version_compare, OptionKey + is_windows, LibType, version_compare ) +from ..options import OptionKey from .compilers import Compiler if T.TYPE_CHECKING: diff --git a/mesonbuild/compilers/d.py b/mesonbuild/compilers/d.py index 46cffdd0fc43..9420d7af3bbd 100644 --- a/mesonbuild/compilers/d.py +++ b/mesonbuild/compilers/d.py @@ -12,8 +12,9 @@ from ..arglist import CompilerArgs from ..linkers import RSPFileSyntax from ..mesonlib import ( - EnvironmentException, version_compare, OptionKey, is_windows + EnvironmentException, version_compare, is_windows ) +from ..options import OptionKey from . import compilers from .compilers import ( diff --git a/mesonbuild/compilers/mixins/arm.py b/mesonbuild/compilers/mixins/arm.py index 942156fab1a9..a70ec4ff95fb 100644 --- a/mesonbuild/compilers/mixins/arm.py +++ b/mesonbuild/compilers/mixins/arm.py @@ -10,7 +10,7 @@ from ... import mesonlib from ...linkers.linkers import ArmClangDynamicLinker -from ...mesonlib import OptionKey +from ...options import OptionKey from ..compilers import clike_debug_args from .clang import clang_color_args diff --git a/mesonbuild/compilers/mixins/clang.py b/mesonbuild/compilers/mixins/clang.py index a799e06a3c8e..1d286388279a 100644 --- a/mesonbuild/compilers/mixins/clang.py +++ b/mesonbuild/compilers/mixins/clang.py @@ -12,7 +12,7 @@ from ... import mesonlib from ...linkers.linkers import AppleDynamicLinker, ClangClDynamicLinker, LLVMDynamicLinker, GnuGoldDynamicLinker, \ MoldDynamicLinker, MSVCDynamicLinker -from ...mesonlib import OptionKey +from ...options import OptionKey from ..compilers import CompileCheckMode from .gnu import GnuLikeCompiler diff --git a/mesonbuild/compilers/mixins/elbrus.py b/mesonbuild/compilers/mixins/elbrus.py index 71cf722c8192..7f853f221bbd 100644 --- a/mesonbuild/compilers/mixins/elbrus.py +++ b/mesonbuild/compilers/mixins/elbrus.py @@ -13,7 +13,8 @@ from .gnu import GnuLikeCompiler from .gnu import gnu_optimization_args -from ...mesonlib import Popen_safe, OptionKey +from ...mesonlib import Popen_safe +from ...options import OptionKey if T.TYPE_CHECKING: from ...environment import Environment diff --git a/mesonbuild/compilers/mixins/emscripten.py b/mesonbuild/compilers/mixins/emscripten.py index 6b7f087ba6e1..f8d15634470c 100644 --- a/mesonbuild/compilers/mixins/emscripten.py +++ b/mesonbuild/compilers/mixins/emscripten.py @@ -11,7 +11,7 @@ from ... import coredata from ... import options from ... import mesonlib -from ...mesonlib import OptionKey +from ...options import OptionKey from ...mesonlib import LibType from mesonbuild.compilers.compilers import CompileCheckMode diff --git a/mesonbuild/compilers/mixins/gnu.py b/mesonbuild/compilers/mixins/gnu.py index 4a9eb8848489..7b72496ef32c 100644 --- a/mesonbuild/compilers/mixins/gnu.py +++ b/mesonbuild/compilers/mixins/gnu.py @@ -16,7 +16,7 @@ from ... import mesonlib from ... import mlog -from ...mesonlib import OptionKey +from ...options import OptionKey from mesonbuild.compilers.compilers import CompileCheckMode if T.TYPE_CHECKING: diff --git a/mesonbuild/compilers/mixins/intel.py b/mesonbuild/compilers/mixins/intel.py index 902cc748145f..32cbdf010539 100644 --- a/mesonbuild/compilers/mixins/intel.py +++ b/mesonbuild/compilers/mixins/intel.py @@ -18,6 +18,7 @@ from ..compilers import CompileCheckMode from .gnu import GnuLikeCompiler from .visualstudio import VisualStudioLikeCompiler +from ...options import OptionKey if T.TYPE_CHECKING: from ...environment import Environment @@ -66,7 +67,7 @@ def __init__(self) -> None: # It does have IPO, which serves much the same purpose as LOT, but # there is an unfortunate rule for using IPO (you can't control the # name of the output file) which break assumptions meson makes - self.base_options = {mesonlib.OptionKey(o) for o in [ + self.base_options = {OptionKey(o) for o in [ 'b_pch', 'b_lundef', 'b_asneeded', 'b_pgo', 'b_coverage', 'b_ndebug', 'b_staticpic', 'b_pie']} self.lang_header = 'none' diff --git a/mesonbuild/compilers/mixins/metrowerks.py b/mesonbuild/compilers/mixins/metrowerks.py index 4be27c5dac32..8934e8376f42 100644 --- a/mesonbuild/compilers/mixins/metrowerks.py +++ b/mesonbuild/compilers/mixins/metrowerks.py @@ -8,7 +8,8 @@ import os import typing as T -from ...mesonlib import EnvironmentException, OptionKey +from ...mesonlib import EnvironmentException +from ...options import OptionKey if T.TYPE_CHECKING: from ...envconfig import MachineInfo diff --git a/mesonbuild/compilers/mixins/pgi.py b/mesonbuild/compilers/mixins/pgi.py index 71ad81f38a01..50335c895cc5 100644 --- a/mesonbuild/compilers/mixins/pgi.py +++ b/mesonbuild/compilers/mixins/pgi.py @@ -10,7 +10,7 @@ from pathlib import Path from ..compilers import clike_debug_args, clike_optimization_args -from ...mesonlib import OptionKey +from ...options import OptionKey if T.TYPE_CHECKING: from ...environment import Environment diff --git a/mesonbuild/compilers/mixins/visualstudio.py b/mesonbuild/compilers/mixins/visualstudio.py index 907ea07f0c7b..4ec22a0f28d0 100644 --- a/mesonbuild/compilers/mixins/visualstudio.py +++ b/mesonbuild/compilers/mixins/visualstudio.py @@ -15,6 +15,7 @@ from ... import mesonlib from ... import mlog from mesonbuild.compilers.compilers import CompileCheckMode +from ...options import OptionKey if T.TYPE_CHECKING: from ...environment import Environment @@ -110,7 +111,7 @@ class VisualStudioLikeCompiler(Compiler, metaclass=abc.ABCMeta): INVOKES_LINKER = False def __init__(self, target: str): - self.base_options = {mesonlib.OptionKey(o) for o in ['b_pch', 'b_ndebug', 'b_vscrt']} # FIXME add lto, pgo and the like + self.base_options = {OptionKey(o) for o in ['b_pch', 'b_ndebug', 'b_vscrt']} # FIXME add lto, pgo and the like self.target = target self.is_64 = ('x64' in target) or ('x86_64' in target) # do some canonicalization of target machine @@ -125,7 +126,7 @@ def __init__(self, target: str): else: self.machine = target if mesonlib.version_compare(self.version, '>=19.28.29910'): # VS 16.9.0 includes cl 19.28.29910 - self.base_options.add(mesonlib.OptionKey('b_sanitize')) + self.base_options.add(OptionKey('b_sanitize')) assert self.linker is not None self.linker.machine = self.machine diff --git a/mesonbuild/compilers/objc.py b/mesonbuild/compilers/objc.py index c63f288e314a..7846f04f4295 100644 --- a/mesonbuild/compilers/objc.py +++ b/mesonbuild/compilers/objc.py @@ -7,7 +7,7 @@ from .. import coredata from .. import options -from ..mesonlib import OptionKey +from ..options import OptionKey from .compilers import Compiler from .mixins.clike import CLikeCompiler diff --git a/mesonbuild/compilers/objcpp.py b/mesonbuild/compilers/objcpp.py index e24406c32cc5..af10c838906f 100644 --- a/mesonbuild/compilers/objcpp.py +++ b/mesonbuild/compilers/objcpp.py @@ -7,7 +7,7 @@ from .. import coredata from .. import options -from ..mesonlib import OptionKey +from ..options import OptionKey from .mixins.clike import CLikeCompiler from .compilers import Compiler diff --git a/mesonbuild/compilers/rust.py b/mesonbuild/compilers/rust.py index b130c58ee307..7c5bf529bc29 100644 --- a/mesonbuild/compilers/rust.py +++ b/mesonbuild/compilers/rust.py @@ -10,7 +10,8 @@ import typing as T from .. import options -from ..mesonlib import EnvironmentException, MesonException, Popen_safe_logged, OptionKey +from ..mesonlib import EnvironmentException, MesonException, Popen_safe_logged +from ..options import OptionKey from .compilers import Compiler, clike_debug_args if T.TYPE_CHECKING: diff --git a/mesonbuild/compilers/vala.py b/mesonbuild/compilers/vala.py index 2e35db109560..f890ea81568f 100644 --- a/mesonbuild/compilers/vala.py +++ b/mesonbuild/compilers/vala.py @@ -8,7 +8,8 @@ from .. import mlog from .. import mesonlib -from ..mesonlib import EnvironmentException, version_compare, LibType, OptionKey +from ..mesonlib import EnvironmentException, version_compare, LibType +from ..options import OptionKey from .compilers import CompileCheckMode, Compiler from ..arglist import CompilerArgs diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index ded230418923..1659d5180c98 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -18,10 +18,12 @@ MesonBugException, MesonException, MachineChoice, PerMachine, PerMachineDefaultable, - OptionKey, OptionType, stringlistify, + stringlistify, pickle_load ) +from .options import OptionKey, OptionType + from .machinefile import CmdLineFileParser import ast diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 9b218c6432b8..08e81f0d79d5 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -14,8 +14,8 @@ from .. import mlog, mesonlib from ..compilers import clib_langs -from ..mesonlib import LibType, MachineChoice, MesonException, HoldableObject, OptionKey -from ..mesonlib import version_compare_many +from ..mesonlib import LibType, MachineChoice, MesonException, HoldableObject, version_compare_many +from ..options import OptionKey #from ..interpreterbase import FeatureDeprecated, FeatureNew if T.TYPE_CHECKING: diff --git a/mesonbuild/dependencies/boost.py b/mesonbuild/dependencies/boost.py index 7a461637c4a9..87f8db9203eb 100644 --- a/mesonbuild/dependencies/boost.py +++ b/mesonbuild/dependencies/boost.py @@ -11,6 +11,7 @@ from .. import mlog from .. import mesonlib +from ..options import OptionKey from .base import DependencyException, SystemDependency from .detect import packages @@ -340,7 +341,7 @@ def get_link_args(self) -> T.List[str]: class BoostDependency(SystemDependency): def __init__(self, environment: Environment, kwargs: T.Dict[str, T.Any]) -> None: super().__init__('boost', environment, kwargs, language='cpp') - buildtype = environment.coredata.get_option(mesonlib.OptionKey('buildtype')) + buildtype = environment.coredata.get_option(OptionKey('buildtype')) assert isinstance(buildtype, str) self.debug = buildtype.startswith('debug') self.multithreading = kwargs.get('threading', 'multi') == 'multi' diff --git a/mesonbuild/dependencies/dub.py b/mesonbuild/dependencies/dub.py index e4f09d4d36f0..0d25c31352ec 100644 --- a/mesonbuild/dependencies/dub.py +++ b/mesonbuild/dependencies/dub.py @@ -5,7 +5,8 @@ from .base import ExternalDependency, DependencyException, DependencyTypeName from .pkgconfig import PkgConfigDependency -from ..mesonlib import (Popen_safe, OptionKey, join_args, version_compare) +from ..mesonlib import (Popen_safe, join_args, version_compare) +from ..options import OptionKey from ..programs import ExternalProgram from .. import mlog import re diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py index 4011c60fb189..b5c40984a8e7 100644 --- a/mesonbuild/dependencies/misc.py +++ b/mesonbuild/dependencies/misc.py @@ -17,6 +17,7 @@ from .detect import packages from .factory import DependencyFactory, factory_methods from .pkgconfig import PkgConfigDependency +from ..options import OptionKey if T.TYPE_CHECKING: from ..environment import Environment @@ -541,7 +542,7 @@ def shaderc_factory(env: 'Environment', shared_libs = ['shaderc'] static_libs = ['shaderc_combined', 'shaderc_static'] - if kwargs.get('static', env.coredata.get_option(mesonlib.OptionKey('prefer_static'))): + if kwargs.get('static', env.coredata.get_option(OptionKey('prefer_static'))): c = [functools.partial(PkgConfigDependency, name, env, kwargs) for name in static_libs + shared_libs] else: diff --git a/mesonbuild/dependencies/pkgconfig.py b/mesonbuild/dependencies/pkgconfig.py index a87f413ad9df..9d47155a23d4 100644 --- a/mesonbuild/dependencies/pkgconfig.py +++ b/mesonbuild/dependencies/pkgconfig.py @@ -6,7 +6,8 @@ from pathlib import Path from .base import ExternalDependency, DependencyException, sort_libpaths, DependencyTypeName -from ..mesonlib import EnvironmentVariables, OptionKey, OrderedSet, PerMachine, Popen_safe, Popen_safe_logged, MachineChoice, join_args +from ..mesonlib import EnvironmentVariables, OrderedSet, PerMachine, Popen_safe, Popen_safe_logged, MachineChoice, join_args +from ..options import OptionKey from ..programs import find_external_program, ExternalProgram from .. import mlog from pathlib import PurePath diff --git a/mesonbuild/dependencies/python.py b/mesonbuild/dependencies/python.py index 883a29ad97f2..fff4aaa9e849 100644 --- a/mesonbuild/dependencies/python.py +++ b/mesonbuild/dependencies/python.py @@ -16,6 +16,7 @@ from .pkgconfig import PkgConfigDependency from ..environment import detect_cpu_family from ..programs import ExternalProgram +from ..options import OptionKey if T.TYPE_CHECKING: from typing_extensions import TypedDict @@ -240,13 +241,13 @@ def get_windows_link_args(self, limited_api: bool) -> T.Optional[T.List[str]]: # Python itself (except with pybind11, which has an ugly # hack to work around this) - so emit a warning to explain # the cause of the expected link error. - buildtype = self.env.coredata.get_option(mesonlib.OptionKey('buildtype')) + buildtype = self.env.coredata.get_option(OptionKey('buildtype')) assert isinstance(buildtype, str) - debug = self.env.coredata.get_option(mesonlib.OptionKey('debug')) + debug = self.env.coredata.get_option(OptionKey('debug')) # `debugoptimized` buildtype may not set debug=True currently, see gh-11645 is_debug_build = debug or buildtype == 'debug' vscrt_debug = False - if mesonlib.OptionKey('b_vscrt') in self.env.coredata.optstore: + if OptionKey('b_vscrt') in self.env.coredata.optstore: vscrt = self.env.coredata.optstore.get_value('b_vscrt') if vscrt in {'mdd', 'mtd', 'from_buildtype', 'static_from_buildtype'}: vscrt_debug = True diff --git a/mesonbuild/dependencies/qt.py b/mesonbuild/dependencies/qt.py index 86e32140e924..1b60deb8afd2 100644 --- a/mesonbuild/dependencies/qt.py +++ b/mesonbuild/dependencies/qt.py @@ -19,6 +19,7 @@ from .factory import DependencyFactory from .. import mlog from .. import mesonlib +from ..options import OptionKey if T.TYPE_CHECKING: from ..compilers import Compiler @@ -296,8 +297,8 @@ def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]): # Use the buildtype by default, but look at the b_vscrt option if the # compiler supports it. - is_debug = self.env.coredata.get_option(mesonlib.OptionKey('buildtype')) == 'debug' - if mesonlib.OptionKey('b_vscrt') in self.env.coredata.optstore: + is_debug = self.env.coredata.get_option(OptionKey('buildtype')) == 'debug' + if OptionKey('b_vscrt') in self.env.coredata.optstore: if self.env.coredata.optstore.get_value('b_vscrt') in {'mdd', 'mtd'}: is_debug = True modules_lib_suffix = _get_modules_lib_suffix(self.version, self.env.machines[self.for_machine], is_debug) diff --git a/mesonbuild/dependencies/scalapack.py b/mesonbuild/dependencies/scalapack.py index bfc83b138f42..e50338710dd3 100644 --- a/mesonbuild/dependencies/scalapack.py +++ b/mesonbuild/dependencies/scalapack.py @@ -8,7 +8,7 @@ import os import typing as T -from ..mesonlib import OptionKey +from ..options import OptionKey from .base import DependencyMethods from .cmake import CMakeDependency from .detect import packages diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 63499676dbf0..62498498dabd 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -17,9 +17,10 @@ from .mesonlib import ( MesonException, MachineChoice, Popen_safe, PerMachine, - PerMachineDefaultable, PerThreeMachineDefaultable, split_args, quote_arg, OptionKey, + PerMachineDefaultable, PerThreeMachineDefaultable, split_args, quote_arg, search_version, MesonBugException ) +from .options import OptionKey from . import mlog from .programs import ExternalProgram diff --git a/mesonbuild/interpreter/compiler.py b/mesonbuild/interpreter/compiler.py index 1bdb321e47e8..90514446bb12 100644 --- a/mesonbuild/interpreter/compiler.py +++ b/mesonbuild/interpreter/compiler.py @@ -22,7 +22,7 @@ FeatureNew, FeatureNewKwargs, disablerIfNotFound, InterpreterException) from ..interpreterbase.decorators import ContainerTypeInfo, typed_kwargs, KwargInfo, typed_pos_args -from ..mesonlib import OptionKey +from ..options import OptionKey from .interpreterobjects import (extract_required_kwarg, extract_search_dirs) from .type_checking import REQUIRED_KW, in_set_validator, NoneType diff --git a/mesonbuild/interpreter/dependencyfallbacks.py b/mesonbuild/interpreter/dependencyfallbacks.py index d5e0740e0974..fd8a025ea220 100644 --- a/mesonbuild/interpreter/dependencyfallbacks.py +++ b/mesonbuild/interpreter/dependencyfallbacks.py @@ -5,7 +5,8 @@ from .. import dependencies from .. import build from ..wrap import WrapMode -from ..mesonlib import OptionKey, extract_as_list, stringlistify, version_compare_many, listify +from ..mesonlib import extract_as_list, stringlistify, version_compare_many, listify +from ..options import OptionKey from ..dependencies import Dependency, DependencyException, NotFoundDependency from ..interpreterbase import (MesonInterpreterObject, FeatureNew, InterpreterException, InvalidArguments) diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index aac63b157ac4..95d85ac07ebf 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -19,8 +19,9 @@ from ..wrap import wrap, WrapMode from .. import mesonlib from ..mesonlib import (EnvironmentVariables, ExecutableSerialisation, MesonBugException, MesonException, HoldableObject, - FileMode, MachineChoice, OptionKey, listify, + FileMode, MachineChoice, listify, extract_as_list, has_path_sep, path_is_in_root, PerMachine) +from ..options import OptionKey from ..programs import ExternalProgram, NonExistingExternalProgram from ..dependencies import Dependency from ..depfile import DepFile diff --git a/mesonbuild/interpreter/kwargs.py b/mesonbuild/interpreter/kwargs.py index 85779bc00b08..abac410d319f 100644 --- a/mesonbuild/interpreter/kwargs.py +++ b/mesonbuild/interpreter/kwargs.py @@ -13,7 +13,8 @@ from .. import options from ..compilers import Compiler from ..dependencies.base import Dependency -from ..mesonlib import EnvironmentVariables, MachineChoice, File, FileMode, FileOrString, OptionKey +from ..mesonlib import EnvironmentVariables, MachineChoice, File, FileMode, FileOrString +from ..options import OptionKey from ..modules.cmake import CMakeSubprojectOptions from ..programs import ExternalProgram from .type_checking import PkgConfigDefineType, SourcesVarargsType diff --git a/mesonbuild/interpreter/mesonmain.py b/mesonbuild/interpreter/mesonmain.py index 4d1f427da210..31ef544cdc6a 100644 --- a/mesonbuild/interpreter/mesonmain.py +++ b/mesonbuild/interpreter/mesonmain.py @@ -11,7 +11,8 @@ from .. import build from .. import mlog, coredata -from ..mesonlib import MachineChoice, OptionKey +from ..mesonlib import MachineChoice +from ..options import OptionKey from ..programs import OverrideProgram, ExternalProgram from ..interpreter.type_checking import ENV_KW, ENV_METHOD_KW, ENV_SEPARATOR_KW, env_convertor_with_method from ..interpreterbase import (MesonInterpreterObject, FeatureNew, FeatureDeprecated, diff --git a/mesonbuild/interpreter/type_checking.py b/mesonbuild/interpreter/type_checking.py index 2856136361f8..0d92a3dbf7cc 100644 --- a/mesonbuild/interpreter/type_checking.py +++ b/mesonbuild/interpreter/type_checking.py @@ -15,7 +15,8 @@ from ..dependencies import Dependency, InternalDependency from ..interpreterbase.decorators import KwargInfo, ContainerTypeInfo from ..mesonlib import (File, FileMode, MachineChoice, listify, has_path_sep, - OptionKey, EnvironmentVariables) + EnvironmentVariables) +from ..options import OptionKey from ..programs import ExternalProgram # Helper definition for type checks that are `Optional[T]` diff --git a/mesonbuild/mcompile.py b/mesonbuild/mcompile.py index b07b60a9e984..2f5708c86521 100644 --- a/mesonbuild/mcompile.py +++ b/mesonbuild/mcompile.py @@ -16,6 +16,7 @@ from . import mlog from . import mesonlib +from .options import OptionKey from .mesonlib import MesonException, RealPathAction, join_args, listify_array_value, setup_vsenv from mesonbuild.environment import detect_ninja from mesonbuild import build @@ -354,14 +355,14 @@ def run(options: 'argparse.Namespace') -> int: b = build.load(options.wd) cdata = b.environment.coredata - need_vsenv = T.cast('bool', cdata.get_option(mesonlib.OptionKey('vsenv'))) + need_vsenv = T.cast('bool', cdata.get_option(OptionKey('vsenv'))) if setup_vsenv(need_vsenv): mlog.log(mlog.green('INFO:'), 'automatically activated MSVC compiler environment') cmd: T.List[str] = [] env: T.Optional[T.Dict[str, str]] = None - backend = cdata.get_option(mesonlib.OptionKey('backend')) + backend = cdata.get_option(OptionKey('backend')) assert isinstance(backend, str) mlog.log(mlog.green('INFO:'), 'autodetecting backend as', backend) if backend == 'ninja': diff --git a/mesonbuild/mconf.py b/mesonbuild/mconf.py index 0a88e57edef2..bd54251bd6d9 100644 --- a/mesonbuild/mconf.py +++ b/mesonbuild/mconf.py @@ -20,7 +20,8 @@ from . import mintro from . import mlog from .ast import AstIDGenerator, IntrospectionInterpreter -from .mesonlib import MachineChoice, OptionKey +from .mesonlib import MachineChoice +from .options import OptionKey from .optinterpreter import OptionInterpreter if T.TYPE_CHECKING: diff --git a/mesonbuild/mdevenv.py b/mesonbuild/mdevenv.py index cc69fb6e084b..064cf5ed6f89 100644 --- a/mesonbuild/mdevenv.py +++ b/mesonbuild/mdevenv.py @@ -9,8 +9,9 @@ from pathlib import Path from . import build, minstall -from .mesonlib import (EnvironmentVariables, MesonException, is_windows, setup_vsenv, OptionKey, +from .mesonlib import (EnvironmentVariables, MesonException, is_windows, setup_vsenv, get_wine_shortpath, MachineChoice, relpath) +from .options import OptionKey from . import mlog diff --git a/mesonbuild/mdist.py b/mesonbuild/mdist.py index e4606306b6d2..b1d8f6780933 100644 --- a/mesonbuild/mdist.py +++ b/mesonbuild/mdist.py @@ -23,7 +23,8 @@ from pathlib import Path from mesonbuild.environment import Environment, detect_ninja from mesonbuild.mesonlib import (MesonException, RealPathAction, get_meson_command, quiet_git, - windows_proof_rmtree, setup_vsenv, OptionKey) + windows_proof_rmtree, setup_vsenv) +from .options import OptionKey from mesonbuild.msetup import add_arguments as msetup_argparse from mesonbuild.wrap import wrap from mesonbuild import mlog, build, coredata diff --git a/mesonbuild/minit.py b/mesonbuild/minit.py index cb5de231e419..70f184d02ebd 100644 --- a/mesonbuild/minit.py +++ b/mesonbuild/minit.py @@ -20,6 +20,7 @@ from mesonbuild.environment import detect_ninja from mesonbuild.templates.mesontemplates import create_meson_build from mesonbuild.templates.samplefactory import sample_generator +from mesonbuild.options import OptionKey if T.TYPE_CHECKING: import argparse @@ -192,7 +193,7 @@ def run(options: Arguments) -> int: raise SystemExit b = build.load(options.builddir) - need_vsenv = T.cast('bool', b.environment.coredata.get_option(mesonlib.OptionKey('vsenv'))) + need_vsenv = T.cast('bool', b.environment.coredata.get_option(OptionKey('vsenv'))) vsenv_active = mesonlib.setup_vsenv(need_vsenv) if vsenv_active: mlog.log(mlog.green('INFO:'), 'automatically activated MSVC compiler environment') diff --git a/mesonbuild/minstall.py b/mesonbuild/minstall.py index 36284f0affb5..e5901c45ae85 100644 --- a/mesonbuild/minstall.py +++ b/mesonbuild/minstall.py @@ -18,7 +18,8 @@ from . import build, environment from .backend.backends import InstallData from .mesonlib import (MesonException, Popen_safe, RealPathAction, is_windows, - is_aix, setup_vsenv, pickle_load, is_osx, OptionKey) + is_aix, setup_vsenv, pickle_load, is_osx) +from .options import OptionKey from .scripts import depfixer, destdir_join from .scripts.meson_exe import run_exe try: diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py index 718bfb029f18..ef2169bf4dd1 100644 --- a/mesonbuild/mintro.py +++ b/mesonbuild/mintro.py @@ -25,7 +25,7 @@ from .dependencies import Dependency from . import environment from .interpreterbase import ObjectHolder -from .mesonlib import OptionKey +from .options import OptionKey from .mparser import FunctionNode, ArrayNode, ArgumentNode, StringNode if T.TYPE_CHECKING: diff --git a/mesonbuild/modules/__init__.py b/mesonbuild/modules/__init__.py index 046c530a8404..e1b9eb27b1ba 100644 --- a/mesonbuild/modules/__init__.py +++ b/mesonbuild/modules/__init__.py @@ -8,6 +8,7 @@ import typing as T from .. import build, mesonlib +from ..options import OptionKey from ..build import IncludeDirs from ..interpreterbase.decorators import noKwargs, noPosargs from ..mesonlib import relpath, HoldableObject, MachineChoice @@ -134,13 +135,13 @@ def get_option(self, name: str, subproject: str = '', machine: MachineChoice = MachineChoice.HOST, lang: T.Optional[str] = None, module: T.Optional[str] = None) -> T.Union[T.List[str], str, int, bool]: - return self.environment.coredata.get_option(mesonlib.OptionKey(name, subproject, machine, lang, module)) + return self.environment.coredata.get_option(OptionKey(name, subproject, machine, lang, module)) def is_user_defined_option(self, name: str, subproject: str = '', machine: MachineChoice = MachineChoice.HOST, lang: T.Optional[str] = None, module: T.Optional[str] = None) -> bool: - key = mesonlib.OptionKey(name, subproject, machine, lang, module) + key = OptionKey(name, subproject, machine, lang, module) return key in self._interpreter.user_defined_options.cmd_line_options def process_include_dirs(self, dirs: T.Iterable[T.Union[str, IncludeDirs]]) -> T.Iterable[IncludeDirs]: diff --git a/mesonbuild/modules/cmake.py b/mesonbuild/modules/cmake.py index b9161021d917..4fda7b30d003 100644 --- a/mesonbuild/modules/cmake.py +++ b/mesonbuild/modules/cmake.py @@ -10,6 +10,7 @@ from . import ExtensionModule, ModuleReturnValue, ModuleObject, ModuleInfo from .. import build, mesonlib, mlog, dependencies +from ..options import OptionKey from ..cmake import TargetOptions, cmake_defines_to_args from ..interpreter import SubprojectHolder from ..interpreter.type_checking import REQUIRED_KW, INSTALL_DIR_KW, NoneType, in_set_validator @@ -299,7 +300,7 @@ def write_basic_package_version_file(self, state: ModuleState, args: TYPE_var, k pkgroot = pkgroot_name = kwargs['install_dir'] if pkgroot is None: - pkgroot = os.path.join(state.environment.coredata.get_option(mesonlib.OptionKey('libdir')), 'cmake', name) + pkgroot = os.path.join(state.environment.coredata.get_option(OptionKey('libdir')), 'cmake', name) pkgroot_name = os.path.join('{libdir}', 'cmake', name) template_file = os.path.join(self.cmake_root, 'Modules', f'BasicConfigVersion-{compatibility}.cmake.in') @@ -370,14 +371,14 @@ def configure_package_config_file(self, state: ModuleState, args: TYPE_var, kwar install_dir = kwargs['install_dir'] if install_dir is None: - install_dir = os.path.join(state.environment.coredata.get_option(mesonlib.OptionKey('libdir')), 'cmake', name) + install_dir = os.path.join(state.environment.coredata.get_option(OptionKey('libdir')), 'cmake', name) conf = kwargs['configuration'] if isinstance(conf, dict): FeatureNew.single_use('cmake.configure_package_config_file dict as configuration', '0.62.0', state.subproject, location=state.current_node) conf = build.ConfigurationData(conf) - prefix = state.environment.coredata.get_option(mesonlib.OptionKey('prefix')) + prefix = state.environment.coredata.get_option(OptionKey('prefix')) abs_install_dir = install_dir if not os.path.isabs(abs_install_dir): abs_install_dir = os.path.join(prefix, install_dir) diff --git a/mesonbuild/modules/external_project.py b/mesonbuild/modules/external_project.py index 5fdb0214c539..fb82a384d919 100644 --- a/mesonbuild/modules/external_project.py +++ b/mesonbuild/modules/external_project.py @@ -19,7 +19,8 @@ from ..interpreter.type_checking import ENV_KW, DEPENDS_KW from ..interpreterbase.decorators import ContainerTypeInfo, KwargInfo, typed_kwargs, typed_pos_args from ..mesonlib import (EnvironmentException, MesonException, Popen_safe, MachineChoice, - get_variable_regex, do_replacement, join_args, OptionKey) + get_variable_regex, do_replacement, join_args) +from ..options import OptionKey if T.TYPE_CHECKING: from typing_extensions import TypedDict diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index cab7c76a3d86..37a8b5105f30 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -31,6 +31,7 @@ from ..mesonlib import ( MachineChoice, MesonException, OrderedSet, Popen_safe, join_args, quote_arg ) +from ..options import OptionKey from ..programs import OverrideProgram from ..scripts.gettext import read_linguas @@ -516,7 +517,7 @@ def compile_resources(self, state: 'ModuleState', args: T.Tuple[str, 'FileOrStri if gresource: # Only one target for .gresource files return ModuleReturnValue(target_c, [target_c]) - install_dir = kwargs['install_dir'] or state.environment.coredata.get_option(mesonlib.OptionKey('includedir')) + install_dir = kwargs['install_dir'] or state.environment.coredata.get_option(OptionKey('includedir')) assert isinstance(install_dir, str), 'for mypy' target_h = GResourceHeaderTarget( f'{target_name}_h', @@ -905,7 +906,7 @@ def _get_langs_compilers_flags(state: 'ModuleState', langs_compilers: T.List[T.T cflags += state.global_args[lang] if state.project_args.get(lang): cflags += state.project_args[lang] - if mesonlib.OptionKey('b_sanitize') in compiler.base_options: + if OptionKey('b_sanitize') in compiler.base_options: sanitize = state.environment.coredata.optstore.get_value('b_sanitize') cflags += compiler.sanitizer_compile_args(sanitize) sanitize = sanitize.split(',') @@ -1642,7 +1643,7 @@ def gdbus_codegen(self, state: 'ModuleState', args: T.Tuple[str, T.Optional[T.Un targets = [] install_header = kwargs['install_header'] - install_dir = kwargs['install_dir'] or state.environment.coredata.get_option(mesonlib.OptionKey('includedir')) + install_dir = kwargs['install_dir'] or state.environment.coredata.get_option(OptionKey('includedir')) assert isinstance(install_dir, str), 'for mypy' output = namebase + '.c' @@ -1954,7 +1955,7 @@ def _make_mkenum_impl( ) -> build.CustomTarget: real_cmd: T.List[T.Union[str, 'ToolType']] = [self._find_tool(state, 'glib-mkenums')] real_cmd.extend(cmd) - _install_dir = install_dir or state.environment.coredata.get_option(mesonlib.OptionKey('includedir')) + _install_dir = install_dir or state.environment.coredata.get_option(OptionKey('includedir')) assert isinstance(_install_dir, str), 'for mypy' return CustomTarget( @@ -2166,7 +2167,7 @@ def generate_vapi(self, state: 'ModuleState', args: T.Tuple[str], kwargs: 'Gener cmd.append(gir_file) vapi_output = library + '.vapi' - datadir = state.environment.coredata.get_option(mesonlib.OptionKey('datadir')) + datadir = state.environment.coredata.get_option(OptionKey('datadir')) assert isinstance(datadir, str), 'for mypy' install_dir = kwargs['install_dir'] or os.path.join(datadir, 'vala', 'vapi') diff --git a/mesonbuild/modules/hotdoc.py b/mesonbuild/modules/hotdoc.py index fc8832efcba8..50b5fe6f2fed 100644 --- a/mesonbuild/modules/hotdoc.py +++ b/mesonbuild/modules/hotdoc.py @@ -20,6 +20,7 @@ from ..interpreter.type_checking import NoneType from ..mesonlib import File, MesonException from ..programs import ExternalProgram +from ..options import OptionKey if T.TYPE_CHECKING: from typing_extensions import TypedDict @@ -330,7 +331,7 @@ def make_targets(self) -> T.Tuple[HotdocTarget, mesonlib.ExecutableSerialisation for path in self.include_paths: self.cmd.extend(['--include-path', path]) - if self.state.environment.coredata.get_option(mesonlib.OptionKey('werror', subproject=self.state.subproject)): + if self.state.environment.coredata.get_option(OptionKey('werror', subproject=self.state.subproject)): self.cmd.append('--fatal-warnings') self.generate_hotdoc_config() diff --git a/mesonbuild/modules/i18n.py b/mesonbuild/modules/i18n.py index 27c9dc00e9b8..551e0b36fab6 100644 --- a/mesonbuild/modules/i18n.py +++ b/mesonbuild/modules/i18n.py @@ -10,6 +10,7 @@ from . import ExtensionModule, ModuleReturnValue, ModuleInfo from .. import build from .. import mesonlib +from ..options import OptionKey from .. import mlog from ..interpreter.type_checking import CT_BUILD_BY_DEFAULT, CT_INPUT_KW, INSTALL_TAG_KW, OUTPUT_KW, INSTALL_DIR_KW, INSTALL_KW, NoneType, in_set_validator from ..interpreterbase import FeatureNew, InvalidArguments @@ -277,7 +278,7 @@ def gettext(self, state: 'ModuleState', args: T.Tuple[str], kwargs: 'Gettext') - targets.append(pottarget) install = kwargs['install'] - install_dir = kwargs['install_dir'] or state.environment.coredata.get_option(mesonlib.OptionKey('localedir')) + install_dir = kwargs['install_dir'] or state.environment.coredata.get_option(OptionKey('localedir')) assert isinstance(install_dir, str), 'for mypy' if not languages: languages = read_linguas(path.join(state.environment.source_dir, state.subdir)) diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index 1a730707986f..d66c2a901ca4 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -13,6 +13,7 @@ from .. import build from .. import dependencies from .. import mesonlib +from ..options import OptionKey from .. import mlog from ..options import BUILTIN_DIR_OPTIONS from ..dependencies.pkgconfig import PkgConfigDependency, PkgConfigInterface @@ -482,7 +483,7 @@ def _generate_pkgconfig_file(self, state: ModuleState, deps: DependenciesHelper, srcdir = PurePath(state.environment.get_source_dir()) else: outdir = state.environment.scratch_dir - prefix = PurePath(_as_str(coredata.get_option(mesonlib.OptionKey('prefix')))) + prefix = PurePath(_as_str(coredata.get_option(OptionKey('prefix')))) if pkgroot: pkgroot_ = PurePath(pkgroot) if not pkgroot_.is_absolute(): @@ -499,7 +500,7 @@ def _generate_pkgconfig_file(self, state: ModuleState, deps: DependenciesHelper, if optname == 'prefix': ofile.write('prefix={}\n'.format(self._escape(prefix))) else: - dirpath = PurePath(_as_str(coredata.get_option(mesonlib.OptionKey(optname)))) + dirpath = PurePath(_as_str(coredata.get_option(OptionKey(optname)))) ofile.write('{}={}\n'.format(optname, self._escape('${prefix}' / dirpath))) if uninstalled and not dataonly: ofile.write('srcdir={}\n'.format(self._escape(srcdir))) @@ -694,13 +695,13 @@ def parse_variable_list(vardict: T.Dict[str, str]) -> T.List[T.Tuple[str, str]]: pkgroot = pkgroot_name = kwargs['install_dir'] or default_install_dir if pkgroot is None: if mesonlib.is_freebsd(): - pkgroot = os.path.join(_as_str(state.environment.coredata.get_option(mesonlib.OptionKey('prefix'))), 'libdata', 'pkgconfig') + pkgroot = os.path.join(_as_str(state.environment.coredata.get_option(OptionKey('prefix'))), 'libdata', 'pkgconfig') pkgroot_name = os.path.join('{prefix}', 'libdata', 'pkgconfig') elif mesonlib.is_haiku(): - pkgroot = os.path.join(_as_str(state.environment.coredata.get_option(mesonlib.OptionKey('prefix'))), 'develop', 'lib', 'pkgconfig') + pkgroot = os.path.join(_as_str(state.environment.coredata.get_option(OptionKey('prefix'))), 'develop', 'lib', 'pkgconfig') pkgroot_name = os.path.join('{prefix}', 'develop', 'lib', 'pkgconfig') else: - pkgroot = os.path.join(_as_str(state.environment.coredata.get_option(mesonlib.OptionKey('libdir'))), 'pkgconfig') + pkgroot = os.path.join(_as_str(state.environment.coredata.get_option(OptionKey('libdir'))), 'pkgconfig') pkgroot_name = os.path.join('{libdir}', 'pkgconfig') relocatable = state.get_option('relocatable', module='pkgconfig') self._generate_pkgconfig_file(state, deps, subdirs, name, description, url, diff --git a/mesonbuild/modules/python.py b/mesonbuild/modules/python.py index 013723da09df..dec77e24948c 100644 --- a/mesonbuild/modules/python.py +++ b/mesonbuild/modules/python.py @@ -22,7 +22,8 @@ InvalidArguments, typed_pos_args, typed_kwargs, KwargInfo, FeatureNew, FeatureNewKwargs, disablerIfNotFound ) -from ..mesonlib import MachineChoice, OptionKey +from ..mesonlib import MachineChoice +from ..options import OptionKey from ..programs import ExternalProgram, NonExistingExternalProgram if T.TYPE_CHECKING: @@ -112,7 +113,7 @@ class PythonInstallation(_ExternalProgramHolder['PythonExternalProgram']): def __init__(self, python: 'PythonExternalProgram', interpreter: 'Interpreter'): _ExternalProgramHolder.__init__(self, python, interpreter) info = python.info - prefix = self.interpreter.environment.coredata.get_option(mesonlib.OptionKey('prefix')) + prefix = self.interpreter.environment.coredata.get_option(OptionKey('prefix')) assert isinstance(prefix, str), 'for mypy' self.variables = info['variables'] self.suffix = info['suffix'] @@ -373,7 +374,7 @@ def __init__(self, interpreter: 'Interpreter') -> None: def _get_install_scripts(self) -> T.List[mesonlib.ExecutableSerialisation]: backend = self.interpreter.backend ret = [] - optlevel = self.interpreter.environment.coredata.get_option(mesonlib.OptionKey('bytecompile', module='python')) + optlevel = self.interpreter.environment.coredata.get_option(OptionKey('bytecompile', module='python')) if optlevel == -1: return ret if not any(PythonExternalProgram.run_bytecompile.values()): diff --git a/mesonbuild/msetup.py b/mesonbuild/msetup.py index 47b40af331c3..5dfda67056be 100644 --- a/mesonbuild/msetup.py +++ b/mesonbuild/msetup.py @@ -11,6 +11,7 @@ from . import build, coredata, environment, interpreter, mesonlib, mintro, mlog from .mesonlib import MesonException +from .options import OptionKey if T.TYPE_CHECKING: from typing_extensions import Protocol @@ -320,10 +321,10 @@ def run_genvslite_setup(options: CMDOptions) -> None: # invoke the appropriate 'meson compile ...' build commands upon the normal visual studio build/rebuild/clean actions, instead of using # the native VS/msbuild system. builddir_prefix = options.builddir - genvsliteval = options.cmd_line_options.pop(mesonlib.OptionKey('genvslite')) + genvsliteval = options.cmd_line_options.pop(OptionKey('genvslite')) # The command line may specify a '--backend' option, which doesn't make sense in conjunction with # '--genvslite', where we always want to use a ninja back end - - k_backend = mesonlib.OptionKey('backend') + k_backend = OptionKey('backend') if k_backend in options.cmd_line_options.keys(): if options.cmd_line_options[k_backend] != 'ninja': raise MesonException('Explicitly specifying a backend option with \'genvslite\' is not necessary ' @@ -336,12 +337,12 @@ def run_genvslite_setup(options: CMDOptions) -> None: for buildtypestr in buildtypes_list: options.builddir = f'{builddir_prefix}_{buildtypestr}' # E.g. builddir_release - options.cmd_line_options[mesonlib.OptionKey('buildtype')] = buildtypestr + options.cmd_line_options[OptionKey('buildtype')] = buildtypestr app = MesonApp(options) vslite_ctx[buildtypestr] = app.generate(capture=True) #Now for generating the 'lite' solution and project files, which will use these builds we've just set up, above. options.builddir = f'{builddir_prefix}_vs' - options.cmd_line_options[mesonlib.OptionKey('genvslite')] = genvsliteval + options.cmd_line_options[OptionKey('genvslite')] = genvsliteval app = MesonApp(options) app.generate(capture=False, vslite_ctx=vslite_ctx) @@ -357,7 +358,7 @@ def run(options: T.Union[CMDOptions, T.List[str]]) -> int: # lie options.pager = False - if mesonlib.OptionKey('genvslite') in options.cmd_line_options.keys(): + if OptionKey('genvslite') in options.cmd_line_options.keys(): run_genvslite_setup(options) else: app = MesonApp(options) diff --git a/mesonbuild/mtest.py b/mesonbuild/mtest.py index c0ddb30bacf7..a2a6067fa116 100644 --- a/mesonbuild/mtest.py +++ b/mesonbuild/mtest.py @@ -35,8 +35,9 @@ from . import mlog from .coredata import MesonVersionMismatchException, major_versions_differ from .coredata import version as coredata_version -from .mesonlib import (MesonException, OptionKey, OrderedSet, RealPathAction, +from .mesonlib import (MesonException, OrderedSet, RealPathAction, get_wine_shortpath, join_args, split_args, setup_vsenv) +from .options import OptionKey from .mintro import get_infodir, load_info_file from .programs import ExternalProgram from .backend.backends import TestProtocol, TestSerialisation diff --git a/mesonbuild/munstable_coredata.py b/mesonbuild/munstable_coredata.py index df045a104636..409b514b608e 100644 --- a/mesonbuild/munstable_coredata.py +++ b/mesonbuild/munstable_coredata.py @@ -5,7 +5,8 @@ from . import coredata as cdata -from .mesonlib import MachineChoice, OptionKey +from .mesonlib import MachineChoice +from .options import OptionKey import os.path import pprint diff --git a/mesonbuild/optinterpreter.py b/mesonbuild/optinterpreter.py index a456a182bf4f..a22152829b42 100644 --- a/mesonbuild/optinterpreter.py +++ b/mesonbuild/optinterpreter.py @@ -9,6 +9,7 @@ from . import coredata from . import options from . import mesonlib +from .options import OptionKey from . import mparser from . import mlog from .interpreterbase import FeatureNew, FeatureDeprecated, typed_pos_args, typed_kwargs, ContainerTypeInfo, KwargInfo @@ -190,7 +191,7 @@ def func_option(self, args: T.Tuple[str], kwargs: 'FuncOptionArgs') -> None: opt_name = args[0] if optname_regex.search(opt_name) is not None: raise OptionException('Option names can only contain letters, numbers or dashes.') - key = mesonlib.OptionKey.from_string(opt_name).evolve(subproject=self.subproject) + key = OptionKey.from_string(opt_name).evolve(subproject=self.subproject) if self.optionstore.is_reserved_name(key): raise OptionException('Option name %s is reserved.' % opt_name) diff --git a/mesonbuild/options.py b/mesonbuild/options.py index 631868628f0e..f7195173f9d1 100644 --- a/mesonbuild/options.py +++ b/mesonbuild/options.py @@ -3,12 +3,12 @@ from collections import OrderedDict from itertools import chain +from functools import total_ordering import argparse +import enum from .mesonlib import ( HoldableObject, - OptionKey, - OptionType, default_prefix, default_datadir, default_includedir, @@ -21,6 +21,7 @@ default_sysconfdir, MesonException, listify_array_value, + MachineChoice, ) from . import mlog @@ -38,6 +39,239 @@ buildtypelist = ['plain', 'debug', 'debugoptimized', 'release', 'minsize', 'custom'] +class OptionType(enum.IntEnum): + + """Enum used to specify what kind of argument a thing is.""" + + BUILTIN = 0 + BACKEND = 1 + BASE = 2 + COMPILER = 3 + PROJECT = 4 + +def _classify_argument(key: 'OptionKey') -> OptionType: + """Classify arguments into groups so we know which dict to assign them to.""" + + if key.name.startswith('b_'): + return OptionType.BASE + elif key.lang is not None: + return OptionType.COMPILER + elif key.name in _BUILTIN_NAMES or key.module: + return OptionType.BUILTIN + elif key.name.startswith('backend_'): + assert key.machine is MachineChoice.HOST, str(key) + return OptionType.BACKEND + else: + assert key.machine is MachineChoice.HOST, str(key) + return OptionType.PROJECT + +# This is copied from coredata. There is no way to share this, because this +# is used in the OptionKey constructor, and the coredata lists are +# OptionKeys... +_BUILTIN_NAMES = { + 'prefix', + 'bindir', + 'datadir', + 'includedir', + 'infodir', + 'libdir', + 'licensedir', + 'libexecdir', + 'localedir', + 'localstatedir', + 'mandir', + 'sbindir', + 'sharedstatedir', + 'sysconfdir', + 'auto_features', + 'backend', + 'buildtype', + 'debug', + 'default_library', + 'errorlogs', + 'genvslite', + 'install_umask', + 'layout', + 'optimization', + 'prefer_static', + 'stdsplit', + 'strip', + 'unity', + 'unity_size', + 'warning_level', + 'werror', + 'wrap_mode', + 'force_fallback_for', + 'pkg_config_path', + 'cmake_prefix_path', + 'vsenv', +} + +@total_ordering +class OptionKey: + + """Represents an option key in the various option dictionaries. + + This provides a flexible, powerful way to map option names from their + external form (things like subproject:build.option) to something that + internally easier to reason about and produce. + """ + + __slots__ = ['name', 'subproject', 'machine', 'lang', '_hash', 'type', 'module'] + + name: str + subproject: str + machine: MachineChoice + lang: T.Optional[str] + _hash: int + type: OptionType + module: T.Optional[str] + + def __init__(self, name: str, subproject: str = '', + machine: MachineChoice = MachineChoice.HOST, + lang: T.Optional[str] = None, + module: T.Optional[str] = None, + _type: T.Optional[OptionType] = None): + # the _type option to the constructor is kinda private. We want to be + # able tos ave the state and avoid the lookup function when + # pickling/unpickling, but we need to be able to calculate it when + # constructing a new OptionKey + object.__setattr__(self, 'name', name) + object.__setattr__(self, 'subproject', subproject) + object.__setattr__(self, 'machine', machine) + object.__setattr__(self, 'lang', lang) + object.__setattr__(self, 'module', module) + object.__setattr__(self, '_hash', hash((name, subproject, machine, lang, module))) + if _type is None: + _type = _classify_argument(self) + object.__setattr__(self, 'type', _type) + + def __setattr__(self, key: str, value: T.Any) -> None: + raise AttributeError('OptionKey instances do not support mutation.') + + def __getstate__(self) -> T.Dict[str, T.Any]: + return { + 'name': self.name, + 'subproject': self.subproject, + 'machine': self.machine, + 'lang': self.lang, + '_type': self.type, + 'module': self.module, + } + + def __setstate__(self, state: T.Dict[str, T.Any]) -> None: + """De-serialize the state of a pickle. + + This is very clever. __init__ is not a constructor, it's an + initializer, therefore it's safe to call more than once. We create a + state in the custom __getstate__ method, which is valid to pass + splatted to the initializer. + """ + # Mypy doesn't like this, because it's so clever. + self.__init__(**state) # type: ignore + + def __hash__(self) -> int: + return self._hash + + def _to_tuple(self) -> T.Tuple[str, OptionType, str, str, MachineChoice, str]: + return (self.subproject, self.type, self.lang or '', self.module or '', self.machine, self.name) + + def __eq__(self, other: object) -> bool: + if isinstance(other, OptionKey): + return self._to_tuple() == other._to_tuple() + return NotImplemented + + def __lt__(self, other: object) -> bool: + if isinstance(other, OptionKey): + return self._to_tuple() < other._to_tuple() + return NotImplemented + + def __str__(self) -> str: + out = self.name + if self.lang: + out = f'{self.lang}_{out}' + if self.machine is MachineChoice.BUILD: + out = f'build.{out}' + if self.module: + out = f'{self.module}.{out}' + if self.subproject: + out = f'{self.subproject}:{out}' + return out + + def __repr__(self) -> str: + return f'OptionKey({self.name!r}, {self.subproject!r}, {self.machine!r}, {self.lang!r}, {self.module!r}, {self.type!r})' + + @classmethod + def from_string(cls, raw: str) -> 'OptionKey': + """Parse the raw command line format into a three part tuple. + + This takes strings like `mysubproject:build.myoption` and Creates an + OptionKey out of them. + """ + try: + subproject, raw2 = raw.split(':') + except ValueError: + subproject, raw2 = '', raw + + module = None + for_machine = MachineChoice.HOST + try: + prefix, raw3 = raw2.split('.') + if prefix == 'build': + for_machine = MachineChoice.BUILD + else: + module = prefix + except ValueError: + raw3 = raw2 + + from .compilers import all_languages + if any(raw3.startswith(f'{l}_') for l in all_languages): + lang, opt = raw3.split('_', 1) + else: + lang, opt = None, raw3 + assert ':' not in opt + assert '.' not in opt + + return cls(opt, subproject, for_machine, lang, module) + + def evolve(self, name: T.Optional[str] = None, subproject: T.Optional[str] = None, + machine: T.Optional[MachineChoice] = None, lang: T.Optional[str] = '', + module: T.Optional[str] = '') -> 'OptionKey': + """Create a new copy of this key, but with altered members. + + For example: + >>> a = OptionKey('foo', '', MachineChoice.Host) + >>> b = OptionKey('foo', 'bar', MachineChoice.Host) + >>> b == a.evolve(subproject='bar') + True + """ + # We have to be a little clever with lang here, because lang is valid + # as None, for non-compiler options + return OptionKey( + name if name is not None else self.name, + subproject if subproject is not None else self.subproject, + machine if machine is not None else self.machine, + lang if lang != '' else self.lang, + module if module != '' else self.module + ) + + def as_root(self) -> 'OptionKey': + """Convenience method for key.evolve(subproject='').""" + return self.evolve(subproject='') + + def as_build(self) -> 'OptionKey': + """Convenience method for key.evolve(machine=MachineChoice.BUILD).""" + return self.evolve(machine=MachineChoice.BUILD) + + def as_host(self) -> 'OptionKey': + """Convenience method for key.evolve(machine=MachineChoice.HOST).""" + return self.evolve(machine=MachineChoice.HOST) + + def is_project_hack_for_optionsview(self) -> bool: + """This method will be removed once we can delete OptionsView.""" + return self.type is OptionType.PROJECT + + class UserOption(T.Generic[_T], HoldableObject): def __init__(self, name: str, description: str, choices: T.Optional[T.Union[str, T.List[_T]]], yielding: bool, diff --git a/mesonbuild/scripts/regen_checker.py b/mesonbuild/scripts/regen_checker.py index e638f50f6e65..fc69ed7d50a1 100644 --- a/mesonbuild/scripts/regen_checker.py +++ b/mesonbuild/scripts/regen_checker.py @@ -8,7 +8,7 @@ import typing as T from ..coredata import CoreData from ..backend.backends import RegenInfo -from ..mesonlib import OptionKey +from ..options import OptionKey # This could also be used for XCode. diff --git a/mesonbuild/utils/universal.py b/mesonbuild/utils/universal.py index 4db209a73fbb..b5310b8c3100 100644 --- a/mesonbuild/utils/universal.py +++ b/mesonbuild/utils/universal.py @@ -15,7 +15,7 @@ import abc import platform, subprocess, operator, os, shlex, shutil, re import collections -from functools import lru_cache, wraps, total_ordering +from functools import lru_cache, wraps from itertools import tee from tempfile import TemporaryDirectory, NamedTemporaryFile import typing as T @@ -67,9 +67,7 @@ class _VerPickleLoadable(Protocol): 'EnvironmentException', 'FileOrString', 'GitException', - 'OptionKey', 'dump_conf_header', - 'OptionType', 'OrderedSet', 'PerMachine', 'PerMachineDefaultable', @@ -1981,7 +1979,58 @@ class LibType(enum.IntEnum): class ProgressBarFallback: # lgtm [py/iter-returns-non-self] ''' - Fallback progress bar implementation when tqdm is not found + Fallback progress bar implementation when tqdm is not foundclass OptionType(enum.IntEnum): + + """Enum used to specify what kind of argument a thing is.""" + + BUILTIN = 0 + BACKEND = 1 + BASE = 2 + COMPILER = 3 + PROJECT = 4 + +# This is copied from coredata. There is no way to share this, because this +# is used in the OptionKey constructor, and the coredata lists are +# OptionKeys... +_BUILTIN_NAMES = { + 'prefix', + 'bindir', + 'datadir', + 'includedir', + 'infodir', + 'libdir', + 'licensedir', + 'libexecdir', + 'localedir', + 'localstatedir', + 'mandir', + 'sbindir', + 'sharedstatedir', + 'sysconfdir', + 'auto_features', + 'backend', + 'buildtype', + 'debug', + 'default_library', + 'errorlogs', + 'genvslite', + 'install_umask', + 'layout', + 'optimization', + 'prefer_static', + 'stdsplit', + 'strip', + 'unity', + 'unity_size', + 'warning_level', + 'werror', + 'wrap_mode', + 'force_fallback_for', + 'pkg_config_path', + 'cmake_prefix_path', + 'vsenv', +} + Since this class is not an actual iterator, but only provides a minimal fallback, it is safe to ignore the 'Iterator does not return self from @@ -2157,241 +2206,6 @@ def wrapper(*args: T.Any, **kwargs: T.Any) -> T.List[_T]: return wrapper -class OptionType(enum.IntEnum): - - """Enum used to specify what kind of argument a thing is.""" - - BUILTIN = 0 - BACKEND = 1 - BASE = 2 - COMPILER = 3 - PROJECT = 4 - -# This is copied from coredata. There is no way to share this, because this -# is used in the OptionKey constructor, and the coredata lists are -# OptionKeys... -_BUILTIN_NAMES = { - 'prefix', - 'bindir', - 'datadir', - 'includedir', - 'infodir', - 'libdir', - 'licensedir', - 'libexecdir', - 'localedir', - 'localstatedir', - 'mandir', - 'sbindir', - 'sharedstatedir', - 'sysconfdir', - 'auto_features', - 'backend', - 'buildtype', - 'debug', - 'default_library', - 'errorlogs', - 'genvslite', - 'install_umask', - 'layout', - 'optimization', - 'prefer_static', - 'stdsplit', - 'strip', - 'unity', - 'unity_size', - 'warning_level', - 'werror', - 'wrap_mode', - 'force_fallback_for', - 'pkg_config_path', - 'cmake_prefix_path', - 'vsenv', -} - - -def _classify_argument(key: 'OptionKey') -> OptionType: - """Classify arguments into groups so we know which dict to assign them to.""" - - if key.name.startswith('b_'): - return OptionType.BASE - elif key.lang is not None: - return OptionType.COMPILER - elif key.name in _BUILTIN_NAMES or key.module: - return OptionType.BUILTIN - elif key.name.startswith('backend_'): - assert key.machine is MachineChoice.HOST, str(key) - return OptionType.BACKEND - else: - assert key.machine is MachineChoice.HOST, str(key) - return OptionType.PROJECT - - -@total_ordering -class OptionKey: - - """Represents an option key in the various option dictionaries. - - This provides a flexible, powerful way to map option names from their - external form (things like subproject:build.option) to something that - internally easier to reason about and produce. - """ - - __slots__ = ['name', 'subproject', 'machine', 'lang', '_hash', 'type', 'module'] - - name: str - subproject: str - machine: MachineChoice - lang: T.Optional[str] - _hash: int - type: OptionType - module: T.Optional[str] - - def __init__(self, name: str, subproject: str = '', - machine: MachineChoice = MachineChoice.HOST, - lang: T.Optional[str] = None, - module: T.Optional[str] = None, - _type: T.Optional[OptionType] = None): - # the _type option to the constructor is kinda private. We want to be - # able tos ave the state and avoid the lookup function when - # pickling/unpickling, but we need to be able to calculate it when - # constructing a new OptionKey - object.__setattr__(self, 'name', name) - object.__setattr__(self, 'subproject', subproject) - object.__setattr__(self, 'machine', machine) - object.__setattr__(self, 'lang', lang) - object.__setattr__(self, 'module', module) - object.__setattr__(self, '_hash', hash((name, subproject, machine, lang, module))) - if _type is None: - _type = _classify_argument(self) - object.__setattr__(self, 'type', _type) - - def __setattr__(self, key: str, value: T.Any) -> None: - raise AttributeError('OptionKey instances do not support mutation.') - - def __getstate__(self) -> T.Dict[str, T.Any]: - return { - 'name': self.name, - 'subproject': self.subproject, - 'machine': self.machine, - 'lang': self.lang, - '_type': self.type, - 'module': self.module, - } - - def __setstate__(self, state: T.Dict[str, T.Any]) -> None: - """De-serialize the state of a pickle. - - This is very clever. __init__ is not a constructor, it's an - initializer, therefore it's safe to call more than once. We create a - state in the custom __getstate__ method, which is valid to pass - splatted to the initializer. - """ - # Mypy doesn't like this, because it's so clever. - self.__init__(**state) # type: ignore - - def __hash__(self) -> int: - return self._hash - - def _to_tuple(self) -> T.Tuple[str, OptionType, str, str, MachineChoice, str]: - return (self.subproject, self.type, self.lang or '', self.module or '', self.machine, self.name) - - def __eq__(self, other: object) -> bool: - if isinstance(other, OptionKey): - return self._to_tuple() == other._to_tuple() - return NotImplemented - - def __lt__(self, other: object) -> bool: - if isinstance(other, OptionKey): - return self._to_tuple() < other._to_tuple() - return NotImplemented - - def __str__(self) -> str: - out = self.name - if self.lang: - out = f'{self.lang}_{out}' - if self.machine is MachineChoice.BUILD: - out = f'build.{out}' - if self.module: - out = f'{self.module}.{out}' - if self.subproject: - out = f'{self.subproject}:{out}' - return out - - def __repr__(self) -> str: - return f'OptionKey({self.name!r}, {self.subproject!r}, {self.machine!r}, {self.lang!r}, {self.module!r}, {self.type!r})' - - @classmethod - def from_string(cls, raw: str) -> 'OptionKey': - """Parse the raw command line format into a three part tuple. - - This takes strings like `mysubproject:build.myoption` and Creates an - OptionKey out of them. - """ - try: - subproject, raw2 = raw.split(':') - except ValueError: - subproject, raw2 = '', raw - - module = None - for_machine = MachineChoice.HOST - try: - prefix, raw3 = raw2.split('.') - if prefix == 'build': - for_machine = MachineChoice.BUILD - else: - module = prefix - except ValueError: - raw3 = raw2 - - from ..compilers import all_languages - if any(raw3.startswith(f'{l}_') for l in all_languages): - lang, opt = raw3.split('_', 1) - else: - lang, opt = None, raw3 - assert ':' not in opt - assert '.' not in opt - - return cls(opt, subproject, for_machine, lang, module) - - def evolve(self, name: T.Optional[str] = None, subproject: T.Optional[str] = None, - machine: T.Optional[MachineChoice] = None, lang: T.Optional[str] = '', - module: T.Optional[str] = '') -> 'OptionKey': - """Create a new copy of this key, but with altered members. - - For example: - >>> a = OptionKey('foo', '', MachineChoice.Host) - >>> b = OptionKey('foo', 'bar', MachineChoice.Host) - >>> b == a.evolve(subproject='bar') - True - """ - # We have to be a little clever with lang here, because lang is valid - # as None, for non-compiler options - return OptionKey( - name if name is not None else self.name, - subproject if subproject is not None else self.subproject, - machine if machine is not None else self.machine, - lang if lang != '' else self.lang, - module if module != '' else self.module - ) - - def as_root(self) -> 'OptionKey': - """Convenience method for key.evolve(subproject='').""" - return self.evolve(subproject='') - - def as_build(self) -> 'OptionKey': - """Convenience method for key.evolve(machine=MachineChoice.BUILD).""" - return self.evolve(machine=MachineChoice.BUILD) - - def as_host(self) -> 'OptionKey': - """Convenience method for key.evolve(machine=MachineChoice.HOST).""" - return self.evolve(machine=MachineChoice.HOST) - - def is_project_hack_for_optionsview(self) -> bool: - """This method will be removed once we can delete OptionsView.""" - return self.type is OptionType.PROJECT - - def pickle_load(filename: str, object_name: str, object_type: T.Type[_PL], suggest_reconfigure: bool = True) -> _PL: load_fail_msg = f'{object_name} file {filename!r} is corrupted.' extra_msg = ' Consider reconfiguring the directory with "meson setup --reconfigure".' if suggest_reconfigure else '' diff --git a/run_tests.py b/run_tests.py index 8ab53a1a5c80..87a8f1314ae3 100755 --- a/run_tests.py +++ b/run_tests.py @@ -35,7 +35,8 @@ from mesonbuild.environment import Environment, detect_ninja, detect_machine_info from mesonbuild.coredata import version as meson_version from mesonbuild.options import backendlist -from mesonbuild.mesonlib import OptionKey, setup_vsenv +from mesonbuild.mesonlib import setup_vsenv +from mesonbuild.options import OptionKey if T.TYPE_CHECKING: from mesonbuild.coredata import SharedCMDOptions diff --git a/unittests/allplatformstests.py b/unittests/allplatformstests.py index e912e943977e..5e1635378cff 100644 --- a/unittests/allplatformstests.py +++ b/unittests/allplatformstests.py @@ -31,9 +31,10 @@ BuildDirLock, MachineChoice, is_windows, is_osx, is_cygwin, is_dragonflybsd, is_sunos, windows_proof_rmtree, python_command, version_compare, split_args, quote_arg, relpath, is_linux, git, search_version, do_conf_file, do_conf_str, default_prefix, - MesonException, EnvironmentException, OptionKey, + MesonException, EnvironmentException, windows_proof_rm ) +from mesonbuild.options import OptionKey from mesonbuild.programs import ExternalProgram from mesonbuild.compilers.mixins.clang import ClangCompiler diff --git a/unittests/datatests.py b/unittests/datatests.py index b7b2d322a5ed..73b937d43da5 100644 --- a/unittests/datatests.py +++ b/unittests/datatests.py @@ -18,9 +18,8 @@ import mesonbuild.modules.gnome from mesonbuild.interpreter import Interpreter from mesonbuild.ast import AstInterpreter -from mesonbuild.mesonlib import ( - MachineChoice, OptionKey -) +from mesonbuild.mesonlib import MachineChoice +from mesonbuild.options import OptionKey from mesonbuild.compilers import ( detect_c_compiler, detect_cpp_compiler ) diff --git a/unittests/helpers.py b/unittests/helpers.py index 7483f51b75df..761241308ef1 100644 --- a/unittests/helpers.py +++ b/unittests/helpers.py @@ -11,9 +11,10 @@ from mesonbuild.compilers import detect_c_compiler, compiler_from_language from mesonbuild.mesonlib import ( - MachineChoice, is_osx, is_cygwin, EnvironmentException, OptionKey, MachineChoice, + MachineChoice, is_osx, is_cygwin, EnvironmentException, MachineChoice, OrderedSet ) +from mesonbuild.options import OptionKey from run_tests import get_fake_env diff --git a/unittests/internaltests.py b/unittests/internaltests.py index 2c3bcfda38e4..109f28ca11e2 100644 --- a/unittests/internaltests.py +++ b/unittests/internaltests.py @@ -32,9 +32,9 @@ from mesonbuild.interpreterbase import typed_pos_args, InvalidArguments, typed_kwargs, ContainerTypeInfo, KwargInfo from mesonbuild.mesonlib import ( LibType, MachineChoice, PerMachine, Version, is_windows, is_osx, - is_cygwin, is_openbsd, search_version, MesonException, OptionKey, - OptionType + is_cygwin, is_openbsd, search_version, MesonException, ) +from mesonbuild.options import OptionKey, OptionType from mesonbuild.interpreter.type_checking import in_set_validator, NoneType from mesonbuild.dependencies.pkgconfig import PkgConfigDependency, PkgConfigInterface, PkgConfigCLI from mesonbuild.programs import ExternalProgram diff --git a/unittests/linuxliketests.py b/unittests/linuxliketests.py index ea86784892f3..6a751dd51d07 100644 --- a/unittests/linuxliketests.py +++ b/unittests/linuxliketests.py @@ -25,8 +25,9 @@ from mesonbuild.mesonlib import ( MachineChoice, is_windows, is_osx, is_cygwin, is_openbsd, is_haiku, is_sunos, windows_proof_rmtree, version_compare, is_linux, - OptionKey, EnvironmentException + EnvironmentException ) +from mesonbuild.options import OptionKey from mesonbuild.compilers import ( detect_c_compiler, detect_cpp_compiler, compiler_from_language, ) diff --git a/unittests/windowstests.py b/unittests/windowstests.py index fc56eaa984c6..8448ab1649cc 100644 --- a/unittests/windowstests.py +++ b/unittests/windowstests.py @@ -17,8 +17,9 @@ import mesonbuild.modules.gnome from mesonbuild.mesonlib import ( MachineChoice, is_windows, is_cygwin, python_command, version_compare, - EnvironmentException, OptionKey + EnvironmentException ) +from mesonbuild.options import OptionKey from mesonbuild.compilers import ( detect_c_compiler, detect_d_compiler, compiler_from_language, ) From 85483295867dbc0c2ab1357b9fe0ca40e320e8a3 Mon Sep 17 00:00:00 2001 From: Zhipeng Xue <543984341@qq.com> Date: Thu, 11 Jul 2024 17:00:41 +0800 Subject: [PATCH 018/302] Fix Type hints --- mesonbuild/environment.py | 2 +- run_tests.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 62498498dabd..1dcd2291d428 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -154,7 +154,7 @@ def find_coverage_tools(coredata: coredata.CoreData) -> T.Tuple[T.Optional[str], return gcovr_exe, gcovr_version, lcov_exe, lcov_version, genhtml_exe, llvm_cov_exe -def detect_ninja(version: str = '1.8.2', log: bool = False) -> T.List[str]: +def detect_ninja(version: str = '1.8.2', log: bool = False) -> T.Optional[T.List[str]]: r = detect_ninja_command_and_version(version, log) return r[0] if r else None diff --git a/run_tests.py b/run_tests.py index 87a8f1314ae3..36ec689e1054 100755 --- a/run_tests.py +++ b/run_tests.py @@ -284,7 +284,7 @@ def get_backend_commands(backend: Backend, debug: bool = False) -> \ raise AssertionError(f'Unknown backend: {backend!r}') return cmd, clean_cmd, test_cmd, install_cmd, uninstall_cmd -def run_mtest_inprocess(commandlist: T.List[str]) -> T.Tuple[int, str, str]: +def run_mtest_inprocess(commandlist: T.List[str]) -> T.Tuple[int, str]: out = StringIO() with mock.patch.object(sys, 'stdout', out), mock.patch.object(sys, 'stderr', out): returncode = mtest.run_with_args(commandlist) From cfc2f33ca020df51eabe84a1da2ca9dce6f48ca0 Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Thu, 11 Jul 2024 14:29:23 +0100 Subject: [PATCH 019/302] docs: Fix typo in subdir_done() description --- docs/yaml/functions/subdir_done.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/yaml/functions/subdir_done.yaml b/docs/yaml/functions/subdir_done.yaml index 1e2a3493ad83..51fd6c9dcda3 100644 --- a/docs/yaml/functions/subdir_done.yaml +++ b/docs/yaml/functions/subdir_done.yaml @@ -5,7 +5,7 @@ description: | Stops further interpretation of the Meson script file from the point of the invocation. All steps executed up to this point are valid and will be executed by Meson. This means that all targets defined before - the call of [[subdir_done]] will be build. + the call of [[subdir_done]] will be built. If the current script was called by `subdir` the execution returns to the calling directory and continues as if the script had reached the @@ -20,5 +20,5 @@ example: | executable('exe2', 'exe2.cpp') ``` - The executable `exe1` will be build, while the executable `exe2` is not - build. + The executable `exe1` will be built, while the executable `exe2` is not + built. From f978b26fd6718cbf7fc178174352c46eae779e23 Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Thu, 11 Jul 2024 14:29:34 +0100 Subject: [PATCH 020/302] docs: Add some commas to subdir_done() description It's subjective but I think that breaking the sentences in this way makes them easier to follow. --- docs/yaml/functions/subdir_done.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/yaml/functions/subdir_done.yaml b/docs/yaml/functions/subdir_done.yaml index 51fd6c9dcda3..bf8dc51411f3 100644 --- a/docs/yaml/functions/subdir_done.yaml +++ b/docs/yaml/functions/subdir_done.yaml @@ -7,9 +7,9 @@ description: | will be executed by Meson. This means that all targets defined before the call of [[subdir_done]] will be built. - If the current script was called by `subdir` the execution returns to + If the current script was called by `subdir`, the execution returns to the calling directory and continues as if the script had reached the - end. If the current script is the top level script Meson configures + end. If the current script is the top level script, Meson configures the project as defined up to this point. example: | From f15963194f50c08b3bef4cbf454bb54937d1ea19 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Fri, 12 Jul 2024 13:37:43 +0300 Subject: [PATCH 021/302] Rename langopt method The public facing name of language options is compiler option, so let's standardise on that. --- mesonbuild/compilers/c.py | 66 ++++++++++---------- mesonbuild/compilers/compilers.py | 2 +- mesonbuild/compilers/cpp.py | 100 +++++++++++++++--------------- mesonbuild/compilers/cuda.py | 8 +-- mesonbuild/compilers/cython.py | 8 +-- mesonbuild/compilers/fortran.py | 16 ++--- mesonbuild/compilers/rust.py | 4 +- 7 files changed, 102 insertions(+), 102 deletions(-) diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index cbc1bea95d6e..bfadcdb35920 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -95,7 +95,7 @@ def has_header_symbol(self, hname: str, symbol: str, prefix: str, def get_options(self) -> 'MutableKeyedOptionDictType': opts = super().get_options() - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') opts.update({ key: options.UserStdOption('C', _ALL_STDS), }) @@ -128,7 +128,7 @@ def get_options(self) -> 'MutableKeyedOptionDictType': stds += ['c2x'] if version_compare(self.version, self._C23_VERSION): stds += ['c23'] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std_opt = opts[key] assert isinstance(std_opt, options.UserStdOption), 'for mypy' std_opt.set_versions(stds, gnu=True) @@ -157,7 +157,7 @@ def get_options(self) -> 'MutableKeyedOptionDictType': self.update_options( opts, self.create_option(options.UserArrayOption, - self.form_langopt_key('winlibs'), + self.form_compileropt_key('winlibs'), 'Standard Win libraries to link against', gnu_winlibs), ) @@ -165,7 +165,7 @@ def get_options(self) -> 'MutableKeyedOptionDictType': def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std = options.get_value(key) if std != 'none': args.append('-std=' + std) @@ -174,7 +174,7 @@ def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str] def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: if self.info.is_windows() or self.info.is_cygwin(): # without a typedict mypy can't understand this. - key = self.form_langopt_key('winlibs') + key = self.form_compileropt_key('winlibs') libs = options.get_value(key).copy() assert isinstance(libs, list) for l in libs: @@ -250,7 +250,7 @@ def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_ def get_options(self) -> 'MutableKeyedOptionDictType': opts = CCompiler.get_options(self) - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std_opt = opts[key] assert isinstance(std_opt, options.UserStdOption), 'for mypy' std_opt.set_versions(['c90', 'c99', 'c11'], gnu=True) @@ -258,7 +258,7 @@ def get_options(self) -> 'MutableKeyedOptionDictType': def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std = options.get_value(key) if std != 'none': args.append('-std=' + std) @@ -302,7 +302,7 @@ def get_options(self) -> 'MutableKeyedOptionDictType': stds += ['c2x'] if version_compare(self.version, self._C23_VERSION): stds += ['c23'] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std_opt = opts[key] assert isinstance(std_opt, options.UserStdOption), 'for mypy' std_opt.set_versions(stds, gnu=True) @@ -318,7 +318,7 @@ def get_options(self) -> 'MutableKeyedOptionDictType': def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std = options.get_value(key) if std != 'none': args.append('-std=' + std) @@ -327,7 +327,7 @@ def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str] def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: if self.info.is_windows() or self.info.is_cygwin(): # without a typeddict mypy can't figure this out - key = self.form_langopt_key('winlibs') + key = self.form_compileropt_key('winlibs') libs: T.List[str] = options.get_value(key).copy() assert isinstance(libs, list) for l in libs: @@ -384,7 +384,7 @@ def get_options(self) -> 'MutableKeyedOptionDictType': stds += ['c90', 'c1x', 'gnu90', 'gnu1x', 'iso9899:2011'] if version_compare(self.version, '>=1.26.00'): stds += ['c17', 'c18', 'iso9899:2017', 'iso9899:2018', 'gnu17', 'gnu18'] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std_opt = opts[key] assert isinstance(std_opt, options.UserStdOption), 'for mypy' std_opt.set_versions(stds) @@ -424,7 +424,7 @@ def get_options(self) -> 'MutableKeyedOptionDictType': stds = ['c89', 'c99'] if version_compare(self.version, '>=16.0.0'): stds += ['c11'] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std_opt = opts[key] assert isinstance(std_opt, options.UserStdOption), 'for mypy' std_opt.set_versions(stds, gnu=True) @@ -432,7 +432,7 @@ def get_options(self) -> 'MutableKeyedOptionDictType': def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std = options.get_value(key) if std != 'none': args.append('-std=' + std) @@ -453,7 +453,7 @@ def get_options(self) -> MutableKeyedOptionDictType: super().get_options(), self.create_option( options.UserArrayOption, - self.form_langopt_key('winlibs'), + self.form_compileropt_key('winlibs'), 'Windows libs to link against.', msvc_winlibs, ), @@ -461,7 +461,7 @@ def get_options(self) -> MutableKeyedOptionDictType: def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: # need a TypeDict to make this work - key = self.form_langopt_key('winlibs') + key = self.form_compileropt_key('winlibs') libs = options.get_value(key).copy() assert isinstance(libs, list) for l in libs: @@ -490,7 +490,7 @@ def get_options(self) -> 'MutableKeyedOptionDictType': stds += ['c11'] if version_compare(self.version, self._C17_VERSION): stds += ['c17', 'c18'] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std_opt = opts[key] assert isinstance(std_opt, options.UserStdOption), 'for mypy' std_opt.set_versions(stds, gnu=True, gnu_deprecated=True) @@ -498,7 +498,7 @@ def get_options(self) -> 'MutableKeyedOptionDictType': def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std = options.get_value(key) # As of MVSC 16.8, /std:c11 and /std:c17 are the only valid C standard options. if std == 'c11': @@ -519,7 +519,7 @@ def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoic ClangClCompiler.__init__(self, target) def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std = options.get_value(key) if std != "none": return [f'/clang:-std={std}'] @@ -541,7 +541,7 @@ def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoic def get_options(self) -> 'MutableKeyedOptionDictType': opts = super().get_options() - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') # To shut up mypy. if isinstance(opts, dict): raise RuntimeError('This is a transitory issue that should not happen. Please report with full backtrace.') @@ -552,7 +552,7 @@ def get_options(self) -> 'MutableKeyedOptionDictType': def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std = options.get_value(key) if std == 'c89': mlog.log("ICL doesn't explicitly implement c89, setting the standard to 'none', which is close.", once=True) @@ -578,7 +578,7 @@ def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_ def get_options(self) -> 'MutableKeyedOptionDictType': opts = CCompiler.get_options(self) - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std_opt = opts[key] assert isinstance(std_opt, options.UserStdOption), 'for mypy' std_opt.set_versions(['c89', 'c99', 'c11']) @@ -586,7 +586,7 @@ def get_options(self) -> 'MutableKeyedOptionDictType': def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std = options.get_value(key) if std != 'none': args.append('--' + std) @@ -608,7 +608,7 @@ def get_always_args(self) -> T.List[str]: def get_options(self) -> 'MutableKeyedOptionDictType': opts = CCompiler.get_options(self) - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std_opt = opts[key] assert isinstance(std_opt, options.UserStdOption), 'for mypy' std_opt.set_versions(['c89', 'c99']) @@ -619,7 +619,7 @@ def get_no_stdinc_args(self) -> T.List[str]: def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std = options.get_value(key) if std == 'c89': args.append('-lang=c') @@ -656,7 +656,7 @@ def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_ def get_options(self) -> 'MutableKeyedOptionDictType': opts = CCompiler.get_options(self) - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std_opt = opts[key] assert isinstance(std_opt, options.UserStdOption), 'for mypy' std_opt.set_versions(['c89', 'c99'], gnu=True) @@ -667,7 +667,7 @@ def get_no_stdinc_args(self) -> T.List[str]: def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std = options.get_value(key) if std != 'none': args.append('-ansi') @@ -702,7 +702,7 @@ def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_ def get_options(self) -> 'MutableKeyedOptionDictType': opts = CCompiler.get_options(self) - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std_opt = opts[key] assert isinstance(std_opt, options.UserStdOption), 'for mypy' std_opt.set_versions(['c89', 'c99']) @@ -740,7 +740,7 @@ def get_always_args(self) -> T.List[str]: def get_options(self) -> 'MutableKeyedOptionDictType': opts = CCompiler.get_options(self) - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std_opt = opts[key] assert isinstance(std_opt, options.UserStdOption), 'for mypy' std_opt.set_versions(['c89', 'c99', 'c11']) @@ -751,7 +751,7 @@ def get_no_stdinc_args(self) -> T.List[str]: def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std = options.get_value(key) if std != 'none': args.append('--' + std) @@ -781,13 +781,13 @@ def get_instruction_set_args(self, instruction_set: str) -> T.Optional[T.List[st def get_options(self) -> 'MutableKeyedOptionDictType': opts = CCompiler.get_options(self) c_stds = ['c99'] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') opts[key].choices = ['none'] + c_stds return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std = options.get_value(key) if std != 'none': args.append('-lang') @@ -811,13 +811,13 @@ def get_instruction_set_args(self, instruction_set: str) -> T.Optional[T.List[st def get_options(self) -> 'MutableKeyedOptionDictType': opts = CCompiler.get_options(self) c_stds = ['c99'] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') opts[key].choices = ['none'] + c_stds return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std = options.get_value(key) if std != 'none': args.append('-lang ' + std) diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 215946a7e663..247d7e1c0f41 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -1354,7 +1354,7 @@ def get_preprocessor(self) -> Compiler: """ raise EnvironmentException(f'{self.get_id()} does not support preprocessor') - def form_langopt_key(self, basename: str) -> OptionKey: + def form_compileropt_key(self, basename: str) -> OptionKey: return OptionKey(basename, machine=self.for_machine, lang=self.language) def get_global_options(lang: str, diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py index 5e8947bcec58..ed840e6d53c2 100644 --- a/mesonbuild/compilers/cpp.py +++ b/mesonbuild/compilers/cpp.py @@ -173,7 +173,7 @@ def _find_best_cpp_std(self, cpp_std: str) -> str: def get_options(self) -> 'MutableKeyedOptionDictType': opts = super().get_options() - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') opts.update({ key: options.UserStdOption('C++', _ALL_STDS), }) @@ -243,16 +243,16 @@ def get_options(self) -> 'MutableKeyedOptionDictType': self.update_options( opts, self.create_option(options.UserComboOption, - self.form_langopt_key('eh'), + self.form_compileropt_key('eh'), 'C++ exception handling type.', ['none', 'default', 'a', 's', 'sc'], 'default'), self.create_option(options.UserBooleanOption, - self.form_langopt_key('rtti'), + self.form_compileropt_key('rtti'), 'Enable RTTI', True), self.create_option(options.UserBooleanOption, - self.form_langopt_key('debugstl'), + self.form_compileropt_key('debugstl'), 'STL debug mode', False), ) @@ -263,14 +263,14 @@ def get_options(self) -> 'MutableKeyedOptionDictType': cppstd_choices.append('c++23') if version_compare(self.version, self._CPP26_VERSION): cppstd_choices.append('c++26') - std_opt = opts[self.form_langopt_key('std')] + std_opt = opts[self.form_compileropt_key('std')] assert isinstance(std_opt, options.UserStdOption), 'for mypy' std_opt.set_versions(cppstd_choices, gnu=True) if self.info.is_windows() or self.info.is_cygwin(): self.update_options( opts, self.create_option(options.UserArrayOption, - self.form_langopt_key('winlibs'), + self.form_compileropt_key('winlibs'), 'Standard Win libraries to link against', gnu_winlibs), ) @@ -278,15 +278,15 @@ def get_options(self) -> 'MutableKeyedOptionDictType': def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std = options.get_value(key) if std != 'none': args.append(self._find_best_cpp_std(std)) - key = self.form_langopt_key('eh') + key = self.form_compileropt_key('eh') non_msvc_eh_options(options.get_value(key), args) - key = self.form_langopt_key('debugstl') + key = self.form_compileropt_key('debugstl') if options.get_value(key): args.append('-D_GLIBCXX_DEBUG=1') @@ -296,7 +296,7 @@ def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str] if version_compare(self.version, '>=18'): args.append('-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG') - key = self.form_langopt_key('rtti') + key = self.form_compileropt_key('rtti') if not options.get_value(key): args.append('-fno-rtti') @@ -305,7 +305,7 @@ def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str] def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: if self.info.is_windows() or self.info.is_cygwin(): # without a typedict mypy can't understand this. - key = self.form_langopt_key('winlibs') + key = self.form_compileropt_key('winlibs') libs = options.get_value(key).copy() assert isinstance(libs, list) for l in libs: @@ -365,7 +365,7 @@ def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_ def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std = options.get_value(key) if std != 'none': args.append(self._find_best_cpp_std(std)) @@ -393,7 +393,7 @@ def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_ def get_options(self) -> 'MutableKeyedOptionDictType': opts = CPPCompiler.get_options(self) - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') self.update_options( opts, self.create_option(options.UserComboOption, @@ -409,12 +409,12 @@ def get_options(self) -> 'MutableKeyedOptionDictType': def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std = options.get_value(key) if std != 'none': args.append('-std=' + std) - key = self.form_langopt_key('eh') + key = self.form_compileropt_key('eh') non_msvc_eh_options(options.get_value(key), args) return args @@ -442,21 +442,21 @@ def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_ self.supported_warn_args(gnu_cpp_warning_args))} def get_options(self) -> 'MutableKeyedOptionDictType': - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') opts = CPPCompiler.get_options(self) self.update_options( opts, self.create_option(options.UserComboOption, - self.form_langopt_key('eh'), + self.form_compileropt_key('eh'), 'C++ exception handling type.', ['none', 'default', 'a', 's', 'sc'], 'default'), self.create_option(options.UserBooleanOption, - self.form_langopt_key('rtti'), + self.form_compileropt_key('rtti'), 'Enable RTTI', True), self.create_option(options.UserBooleanOption, - self.form_langopt_key('debugstl'), + self.form_compileropt_key('debugstl'), 'STL debug mode', False), ) @@ -483,7 +483,7 @@ def get_options(self) -> 'MutableKeyedOptionDictType': def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std = options.get_value(key) if std != 'none': args.append(self._find_best_cpp_std(std)) @@ -500,7 +500,7 @@ def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str] def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: if self.info.is_windows() or self.info.is_cygwin(): # without a typedict mypy can't understand this. - key = self.form_langopt_key('winlibs') + key = self.form_compileropt_key('winlibs') libs = options.get_value(key).copy() assert isinstance(libs, list) for l in libs: @@ -583,16 +583,16 @@ def get_options(self) -> 'MutableKeyedOptionDictType': if version_compare(self.version, '>=1.26.00'): cpp_stds += ['c++20'] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') self.update_options( opts, self.create_option(options.UserComboOption, - self.form_langopt_key('eh'), + self.form_compileropt_key('eh'), 'C++ exception handling type.', ['none', 'default', 'a', 's', 'sc'], 'default'), self.create_option(options.UserBooleanOption, - self.form_langopt_key('debugstl'), + self.form_compileropt_key('debugstl'), 'STL debug mode', False), ) @@ -616,15 +616,15 @@ def has_function(self, funcname: str, prefix: str, env: 'Environment', *, # Elbrus C++ compiler does not support RTTI, so don't check for it. def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std = options.get_value(key) if std.value != 'none': args.append(self._find_best_cpp_std(std.value)) - key = self.form_langopt_key('eh') + key = self.form_compileropt_key('eh') non_msvc_eh_options(options.get_value(key), args) - key = self.form_langopt_key('debugstl') + key = self.form_compileropt_key('debugstl') if options.get_value(key): args.append('-D_GLIBCXX_DEBUG=1') return args @@ -664,20 +664,20 @@ def get_options(self) -> 'MutableKeyedOptionDictType': c_stds += ['c++2a'] g_stds += ['gnu++2a'] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') self.update_options( opts, self.create_option(options.UserComboOption, - self.form_langopt_key('eh'), + self.form_compileropt_key('eh'), 'C++ exception handling type.', ['none', 'default', 'a', 's', 'sc'], 'default'), self.create_option(options.UserBooleanOption, - self.form_langopt_key('rtti'), + self.form_compileropt_key('rtti'), 'Enable RTTI', True), self.create_option(options.UserBooleanOption, - self.form_langopt_key('debugstl'), + self.form_compileropt_key('debugstl'), 'STL debug mode', False), ) @@ -688,7 +688,7 @@ def get_options(self) -> 'MutableKeyedOptionDictType': def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std = options.get_value(key) if std != 'none': remap_cpp03 = { @@ -733,24 +733,24 @@ class VisualStudioLikeCPPCompilerMixin(CompilerMixinBase): def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: # need a typeddict for this - key = self.form_langopt_key('winlibs') + key = self.form_compileropt_key('winlibs') return T.cast('T.List[str]', options.get_value(key)[:]) def _get_options_impl(self, opts: 'MutableKeyedOptionDictType', cpp_stds: T.List[str]) -> 'MutableKeyedOptionDictType': - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') self.update_options( opts, self.create_option(options.UserComboOption, - self.form_langopt_key('eh'), + self.form_compileropt_key('eh'), 'C++ exception handling type.', ['none', 'default', 'a', 's', 'sc'], 'default'), self.create_option(options.UserBooleanOption, - self.form_langopt_key('rtti'), + self.form_compileropt_key('rtti'), 'Enable RTTI', True), self.create_option(options.UserArrayOption, - self.form_langopt_key('winlibs'), + self.form_compileropt_key('winlibs'), 'Windows libs to link against.', msvc_winlibs), ) @@ -761,9 +761,9 @@ def _get_options_impl(self, opts: 'MutableKeyedOptionDictType', cpp_stds: T.List def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') - eh = options.get_value(self.form_langopt_key('eh')) + eh = options.get_value(self.form_compileropt_key('eh')) if eh == 'default': args.append('/EHsc') elif eh == 'none': @@ -771,7 +771,7 @@ def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str] else: args.append('/EH' + eh) - if not options.get_value(self.form_langopt_key('rtti')): + if not options.get_value(self.form_compileropt_key('rtti')): args.append('/GR-') permissive, ver = self.VC_VERSION_MAP[options.get_value(key)] @@ -801,7 +801,7 @@ def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str] # which means setting the C++ standard version to C++14, in compilers that support it # (i.e., after VS2015U3) # if one is using anything before that point, one cannot set the standard. - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') if options.get_value(key) in {'vc++11', 'c++11'}: mlog.warning(self.id, 'does not support C++11;', 'attempting best effort; setting the standard to C++14', @@ -848,7 +848,7 @@ def get_options(self) -> 'MutableKeyedOptionDictType': return self._get_options_impl(super().get_options(), cpp_stds) def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') if options.get_value(key) != 'none' and version_compare(self.version, '<19.00.24210'): mlog.warning('This version of MSVC does not support cpp_std arguments', fatal=False) options = copy.copy(options) @@ -917,14 +917,14 @@ def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_ def get_options(self) -> 'MutableKeyedOptionDictType': opts = CPPCompiler.get_options(self) - std_opt = self.form_langopt_key('std') + std_opt = self.form_compileropt_key('std') assert isinstance(std_opt, options.UserStdOption), 'for mypy' std_opt.set_versions(['c++03', 'c++11']) return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std = options.get_value(key) if std == 'c++11': args.append('--cpp11') @@ -978,7 +978,7 @@ def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_ def get_options(self) -> 'MutableKeyedOptionDictType': opts = CPPCompiler.get_options(self) - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std_opt = opts[key] assert isinstance(std_opt, options.UserStdOption), 'for mypy' std_opt.set_versions(['c++03']) @@ -986,7 +986,7 @@ def get_options(self) -> 'MutableKeyedOptionDictType': def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std = options.get_value(key) if std != 'none': args.append('--' + std) @@ -1021,13 +1021,13 @@ def get_instruction_set_args(self, instruction_set: str) -> T.Optional[T.List[st def get_options(self) -> 'MutableKeyedOptionDictType': opts = CPPCompiler.get_options(self) - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') opts[key].choices = ['none'] return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std = options.get_value(key) if std != 'none': args.append('-lang') @@ -1050,13 +1050,13 @@ def get_instruction_set_args(self, instruction_set: str) -> T.Optional[T.List[st def get_options(self) -> 'MutableKeyedOptionDictType': opts = CPPCompiler.get_options(self) - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') opts[key].choices = ['none'] return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std = options.get_value(key) if std != 'none': args.append('-lang ' + std) diff --git a/mesonbuild/compilers/cuda.py b/mesonbuild/compilers/cuda.py index e991683a7af6..9af15422b821 100644 --- a/mesonbuild/compilers/cuda.py +++ b/mesonbuild/compilers/cuda.py @@ -646,12 +646,12 @@ def get_options(self) -> 'MutableKeyedOptionDictType': return self.update_options( super().get_options(), self.create_option(options.UserComboOption, - self.form_langopt_key('std'), + self.form_compileropt_key('std'), 'C++ language standard to use with CUDA', cpp_stds, 'none'), self.create_option(options.UserStringOption, - self.form_langopt_key('ccbindir'), + self.form_compileropt_key('ccbindir'), 'CUDA non-default toolchain directory to use (-ccbin)', ''), ) @@ -675,7 +675,7 @@ def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str] # the combination of CUDA version and MSVC version; the --std= is thus ignored # and attempting to use it will result in a warning: https://stackoverflow.com/a/51272091/741027 if not is_windows(): - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std = options.get_value(key) if std != 'none': args.append('--std=' + std) @@ -795,7 +795,7 @@ def get_dependency_link_args(self, dep: 'Dependency') -> T.List[str]: return self._to_host_flags(super().get_dependency_link_args(dep), _Phase.LINKER) def get_ccbin_args(self, ccoptions: 'KeyedOptionDictType') -> T.List[str]: - key = self.form_langopt_key('ccbindir') + key = self.form_compileropt_key('ccbindir') ccbindir = ccoptions.get_value(key) if isinstance(ccbindir, str) and ccbindir != '': return [self._shield_nvcc_list_arg('-ccbin='+ccbindir, False)] diff --git a/mesonbuild/compilers/cython.py b/mesonbuild/compilers/cython.py index 7c1128692e40..5cc0200458fa 100644 --- a/mesonbuild/compilers/cython.py +++ b/mesonbuild/compilers/cython.py @@ -70,12 +70,12 @@ def get_options(self) -> 'MutableKeyedOptionDictType': return self.update_options( super().get_options(), self.create_option(options.UserComboOption, - self.form_langopt_key('version'), + self.form_compileropt_key('version'), 'Python version to target', ['2', '3'], '3'), self.create_option(options.UserComboOption, - self.form_langopt_key('language'), + self.form_compileropt_key('language'), 'Output C or C++ files', ['c', 'cpp'], 'c'), @@ -83,10 +83,10 @@ def get_options(self) -> 'MutableKeyedOptionDictType': def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] - key = self.form_langopt_key('version') + key = self.form_compileropt_key('version') version = options.get_value(key) args.append(f'-{version}') - key = self.form_langopt_key('language') + key = self.form_compileropt_key('language') lang = options.get_value(key) if lang == 'cpp': args.append('--cplus') diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py index 3e332381d53b..a6e3f0b219d2 100644 --- a/mesonbuild/compilers/fortran.py +++ b/mesonbuild/compilers/fortran.py @@ -115,7 +115,7 @@ def get_options(self) -> 'MutableKeyedOptionDictType': return self.update_options( super().get_options(), self.create_option(options.UserComboOption, - self.form_langopt_key('std'), + self.form_compileropt_key('std'), 'Fortran language standard to use', ['none'], 'none'), @@ -147,13 +147,13 @@ def get_options(self) -> 'MutableKeyedOptionDictType': fortran_stds += ['f2008'] if version_compare(self.version, '>=8.0.0'): fortran_stds += ['f2018'] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') opts[key].choices = ['none'] + fortran_stds return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std = options.get_value(key) if std != 'none': args.append('-std=' + std) @@ -205,7 +205,7 @@ def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoic def get_options(self) -> 'MutableKeyedOptionDictType': opts = FortranCompiler.get_options(self) fortran_stds = ['f95', 'f2003', 'f2008', 'gnu', 'legacy', 'f2008ts'] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') opts[key].choices = ['none'] + fortran_stds return opts @@ -284,13 +284,13 @@ def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoic def get_options(self) -> 'MutableKeyedOptionDictType': opts = FortranCompiler.get_options(self) - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') opts[key].choices = ['none', 'legacy', 'f95', 'f2003', 'f2008', 'f2018'] return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std = options.get_value(key) stds = {'legacy': 'none', 'f95': 'f95', 'f2003': 'f03', 'f2008': 'f08', 'f2018': 'f18'} if std != 'none': @@ -339,13 +339,13 @@ def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoic def get_options(self) -> 'MutableKeyedOptionDictType': opts = FortranCompiler.get_options(self) - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') opts[key].choices = ['none', 'legacy', 'f95', 'f2003', 'f2008', 'f2018'] return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std = options.get_value(key) stds = {'legacy': 'none', 'f95': 'f95', 'f2003': 'f03', 'f2008': 'f08', 'f2018': 'f18'} if std != 'none': diff --git a/mesonbuild/compilers/rust.py b/mesonbuild/compilers/rust.py index 7c5bf529bc29..7bcab3ab46ce 100644 --- a/mesonbuild/compilers/rust.py +++ b/mesonbuild/compilers/rust.py @@ -160,7 +160,7 @@ def use_linker_args(cls, linker: str, version: str) -> T.List[str]: def get_options(self) -> MutableKeyedOptionDictType: return dict((self.create_option(options.UserComboOption, - self.form_langopt_key('std'), + self.form_compileropt_key('std'), 'Rust edition to use', ['none', '2015', '2018', '2021'], 'none'),)) @@ -173,7 +173,7 @@ def get_dependency_compile_args(self, dep: 'Dependency') -> T.List[str]: def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] - key = self.form_langopt_key('std') + key = self.form_compileropt_key('std') std = options.get_value(key) if std != 'none': args.append('--edition=' + std) From 4172cbd0fba77540490c370dda074f03ca4b9c33 Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Fri, 12 Jul 2024 10:05:45 -0700 Subject: [PATCH 022/302] docs: mention cython_args in cython reference docs --- docs/markdown/Cython.md | 12 ++++++++++++ docs/markdown/Python-module.md | 2 ++ 2 files changed, 14 insertions(+) diff --git a/docs/markdown/Cython.md b/docs/markdown/Cython.md index 304275043dcc..1491dc4fc4e5 100644 --- a/docs/markdown/Cython.md +++ b/docs/markdown/Cython.md @@ -32,6 +32,18 @@ py.extension_module( ) ``` +You can pass arguments accepted by the `cython` CLI script with the +`cython_args` argument: + +```meson +py.extension_module( + 'foo-bounds' + 'foo.pyx', + dependencies : dep_py, + cython_args : ['-Xboundscheck=False'], +) +``` + ## C++ intermediate support *(New in 0.60.0)* diff --git a/docs/markdown/Python-module.md b/docs/markdown/Python-module.md index c02eed91d596..f3ee9ffc5a98 100644 --- a/docs/markdown/Python-module.md +++ b/docs/markdown/Python-module.md @@ -121,6 +121,8 @@ Additionally, the following diverge from [[shared_module]]'s default behavior: - `gnu_symbol_visibility`: if unset, it will default to `'hidden'` on versions of Python that support this (the python headers define `PyMODINIT_FUNC` has default visibility). + +Note that Cython support uses `extension_module`, see [the reference for Cython](Cython.md). *since 0.63.0* `extension_module` automatically adds a dependency to the library if one is not explicitly provided. To support older versions, the user may need to From f5d66b4932f94fbe78058e617c2d83a454107008 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20K=C3=A4ssens?= Date: Fri, 12 Jul 2024 11:21:54 +0200 Subject: [PATCH 023/302] backend/backends: Fix type assertions in backend Test dependencies can be of type CustomTargetIndex, similar to other targets. --- mesonbuild/backend/backends.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index 0defad63e6fd..c6fe4f0a9c9c 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -1171,7 +1171,7 @@ def extract_dll_paths(cls, target: build.BuildTarget) -> T.Set[str]: def determine_windows_extra_paths( self, target: T.Union[build.BuildTarget, build.CustomTarget, build.CustomTargetIndex, programs.ExternalProgram, mesonlib.File, str], - extra_bdeps: T.Sequence[T.Union[build.BuildTarget, build.CustomTarget]]) -> T.List[str]: + extra_bdeps: T.Sequence[T.Union[build.BuildTarget, build.CustomTarget, build.CustomTargetIndex]]) -> T.List[str]: """On Windows there is no such thing as an rpath. We must determine all locations of DLLs that this exe @@ -1231,7 +1231,7 @@ def create_test_serialisation(self, tests: T.List['Test']) -> T.List[TestSeriali exe_wrapper = self.environment.get_exe_wrapper() machine = self.environment.machines[exe.for_machine] if machine.is_windows() or machine.is_cygwin(): - extra_bdeps: T.List[T.Union[build.BuildTarget, build.CustomTarget]] = [] + extra_bdeps: T.List[T.Union[build.BuildTarget, build.CustomTarget, build.CustomTargetIndex]] = [] if isinstance(exe, build.CustomTarget): extra_bdeps = list(exe.get_transitive_build_target_deps()) extra_paths = self.determine_windows_extra_paths(exe, extra_bdeps) @@ -1428,7 +1428,7 @@ def get_testlike_targets(self, benchmark: bool = False) -> T.OrderedDict[str, T. continue result[arg.get_id()] = arg for dep in t.depends: - assert isinstance(dep, (build.CustomTarget, build.BuildTarget)) + assert isinstance(dep, (build.CustomTarget, build.BuildTarget, build.CustomTargetIndex)) result[dep.get_id()] = dep return result From 8e89a38737281f7618a1284fe9e68eb6bb1fe99d Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 23 Apr 2024 15:29:41 -0700 Subject: [PATCH 024/302] tests: rename poorly named function and add report argument The poorly named `print_tool_versions()` doesn't just print the tools versions, it finds them and populates a global table, without which some tests will fail. Rename the function and add a `report` argument so that calls can decide whether they want to have the printed message, because the single runner doesn't in quick mode. --- run_project_tests.py | 9 +++++++-- run_single_test.py | 6 +++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/run_project_tests.py b/run_project_tests.py index a1feecdfc9ee..7551c8da96c5 100755 --- a/run_project_tests.py +++ b/run_project_tests.py @@ -1513,7 +1513,7 @@ class ToolInfo(T.NamedTuple): regex: T.Pattern match_group: int -def print_tool_versions() -> None: +def detect_tools(report: bool = True) -> None: tools: T.List[ToolInfo] = [ ToolInfo( 'ninja', @@ -1553,6 +1553,11 @@ def get_version(t: ToolInfo) -> str: return f'{exe} (unknown)' + if not report: + for tool in tools: + get_version(tool) + return + print() print('tools') print() @@ -1646,7 +1651,7 @@ def setup_symlinks() -> None: print('VSCMD version', os.environ['VSCMD_VER']) setup_commands(options.backend) detect_system_compiler(options) - print_tool_versions() + detect_tools() script_dir = os.path.split(__file__)[0] if script_dir != '': os.chdir(script_dir) diff --git a/run_single_test.py b/run_single_test.py index 8db9b402d90a..0b4750b76d1b 100755 --- a/run_single_test.py +++ b/run_single_test.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 -# Copyright © 2021-2023 Intel Corporation +# Copyright © 2021-2024 Intel Corporation """Script for running a single project test. @@ -15,7 +15,7 @@ from mesonbuild import mlog from run_tests import handle_meson_skip_test from run_project_tests import TestDef, load_test_json, run_test, BuildStep -from run_project_tests import setup_commands, detect_system_compiler, print_tool_versions +from run_project_tests import setup_commands, detect_system_compiler, detect_tools if T.TYPE_CHECKING: from run_project_tests import CompilerArgumentType @@ -47,7 +47,7 @@ def main() -> None: setup_commands(args.backend) if not args.quick: detect_system_compiler(args) - print_tool_versions() + detect_tools(not args.quick) test = TestDef(args.case, args.case.stem, []) tests = load_test_json(test, False) From 8a8a3a0578fd8d5a8720a7a706f6f3b99e857f9c Mon Sep 17 00:00:00 2001 From: Alyssa Ross Date: Fri, 12 Jul 2024 16:11:31 +0200 Subject: [PATCH 025/302] tests: skip framework recasting if CMake unavailable --- test cases/osx/9 framework recasting/meson.build | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test cases/osx/9 framework recasting/meson.build b/test cases/osx/9 framework recasting/meson.build index 83fe19ed0a28..bf8a5e63ad89 100644 --- a/test cases/osx/9 framework recasting/meson.build +++ b/test cases/osx/9 framework recasting/meson.build @@ -1,5 +1,9 @@ project('framework recasting', 'c', 'cpp') +if not find_program('cmake', required: false).found() + error('MESON_SKIP_TEST cmake binary not available.') +endif + x = dependency('OpenAL', method: 'cmake') y = executable('tt', files('main.cpp'), dependencies: x) From 9cc94a16ab837e85c47a818668b98a110fbabc48 Mon Sep 17 00:00:00 2001 From: Christoph Reiter Date: Sat, 13 Jul 2024 14:26:08 +0200 Subject: [PATCH 026/302] tests: try to fix ubuntu bionic tests by forcing an older nodejs --- .github/workflows/os_comp.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/os_comp.yml b/.github/workflows/os_comp.yml index 1d779842e27a..4fa4a87ed15d 100644 --- a/.github/workflows/os_comp.yml +++ b/.github/workflows/os_comp.yml @@ -26,6 +26,12 @@ on: - ".github/workflows/os_comp.yml" - "run*tests.py" +# make GHA actions use node16 which still works with bionic +# See https://github.blog/changelog/2024-03-07-github-actions-all-actions-will-run-on-node20-instead-of-node16-by-default/ +# Unclear how long this will work though +env: + ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true + permissions: contents: read From 44323fffead913d0a3c52647ba63a236924c7b78 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 12 Jul 2024 16:12:09 -0700 Subject: [PATCH 027/302] test/rust: Replace gcc -m argument with a -f argument -m arguments aren't portable across architectures. -fipa-pta will hopefully be portable for GCC, but also not implemented by clang. Fixes: #13417 --- test cases/rust/12 bindgen/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test cases/rust/12 bindgen/meson.build b/test cases/rust/12 bindgen/meson.build index 09cb02a6d319..57e44a0635c6 100644 --- a/test cases/rust/12 bindgen/meson.build +++ b/test cases/rust/12 bindgen/meson.build @@ -15,7 +15,7 @@ endif cc_id = meson.get_compiler('c').get_id() compiler_specific_args = [] if cc_id == 'gcc' - compiler_specific_args = ['-mtls-dialect=gnu2'] + compiler_specific_args = ['-fipa-pta'] elif cc_id == 'msvc' compiler_specific_args = ['/fp:fast'] endif From b1f4e1495d4f03f4ef68d59535bd954686def3af Mon Sep 17 00:00:00 2001 From: Tristan Partin Date: Thu, 11 Jul 2024 10:18:34 -0500 Subject: [PATCH 028/302] Fix failing tests for zlib-ng Fedora, at the very least, now packages zlib-ng as zlib. This means the version reported for the dependency is now X.Y.Z.zlib-ng by pkgconfig whereas the test expected X.Y.Z. Make the version check work for both regular zlib and zlib-ng. --- .../linuxlike/1 pkg-config/prog-checkver.c | 29 ++++++++++++++++++- .../13 cmake dependency/prog-checkver.c | 29 ++++++++++++++++++- 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/test cases/linuxlike/1 pkg-config/prog-checkver.c b/test cases/linuxlike/1 pkg-config/prog-checkver.c index ea1ed32f4ffa..fe705d45da99 100644 --- a/test cases/linuxlike/1 pkg-config/prog-checkver.c +++ b/test cases/linuxlike/1 pkg-config/prog-checkver.c @@ -1,11 +1,38 @@ #include +#include #include #include +static bool check_version(const char *zlib_ver, const char *found_zlib) { +#ifdef ZLIBNG_VERSION + const char *ptr = strstr(zlib_ver, found_zlib); + + // If the needle isn't found or the needle isn't at the start, fail. + if (ptr == NULL || ptr != zlib_ver) + return false; + + /* In zlib-ng, ZLIB_VERSION is of the form X.Y.Z.zlib-ng. This will move the + * pointer to the start of the suffix, .zlib-ng. We know that at this point + * that FOUND_ZLIB is the start of ZLIB_VERSION, so compare the rest. + */ + ptr += strlen(found_zlib); + if (strcmp(ptr, ".zlib-ng") != 0) + return false; +#else + if (strcmp(zlib_ver, found_zlib) != 0) + return false; +#endif + + return true; +} + int main(void) { void * something = deflate; - if(strcmp(ZLIB_VERSION, FOUND_ZLIB) != 0) { + if (!check_version(ZLIB_VERSION, FOUND_ZLIB)) { printf("Meson found '%s' but zlib is '%s'\n", FOUND_ZLIB, ZLIB_VERSION); +#ifdef ZLIBNG_VERSION + puts("Note that in the case of zlib-ng, a version suffix of .zlib-ng is expected\n"); +#endif return 2; } if(something != 0) diff --git a/test cases/linuxlike/13 cmake dependency/prog-checkver.c b/test cases/linuxlike/13 cmake dependency/prog-checkver.c index ea1ed32f4ffa..fe705d45da99 100644 --- a/test cases/linuxlike/13 cmake dependency/prog-checkver.c +++ b/test cases/linuxlike/13 cmake dependency/prog-checkver.c @@ -1,11 +1,38 @@ #include +#include #include #include +static bool check_version(const char *zlib_ver, const char *found_zlib) { +#ifdef ZLIBNG_VERSION + const char *ptr = strstr(zlib_ver, found_zlib); + + // If the needle isn't found or the needle isn't at the start, fail. + if (ptr == NULL || ptr != zlib_ver) + return false; + + /* In zlib-ng, ZLIB_VERSION is of the form X.Y.Z.zlib-ng. This will move the + * pointer to the start of the suffix, .zlib-ng. We know that at this point + * that FOUND_ZLIB is the start of ZLIB_VERSION, so compare the rest. + */ + ptr += strlen(found_zlib); + if (strcmp(ptr, ".zlib-ng") != 0) + return false; +#else + if (strcmp(zlib_ver, found_zlib) != 0) + return false; +#endif + + return true; +} + int main(void) { void * something = deflate; - if(strcmp(ZLIB_VERSION, FOUND_ZLIB) != 0) { + if (!check_version(ZLIB_VERSION, FOUND_ZLIB)) { printf("Meson found '%s' but zlib is '%s'\n", FOUND_ZLIB, ZLIB_VERSION); +#ifdef ZLIBNG_VERSION + puts("Note that in the case of zlib-ng, a version suffix of .zlib-ng is expected\n"); +#endif return 2; } if(something != 0) From 6165db80bb0d014d9d1fc0d3f8a9d78e92492b94 Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Fri, 12 Jul 2024 22:00:46 -0500 Subject: [PATCH 029/302] cmake: Only propagate interface link flags in dep CMake has two target properties, LINK_OPTIONS and INTERFACE_LINK_OPTIONS. The former is for link flags that apply only to the target (PRIVATE). The latter is used for link flags that propagate to dependents (PUBLIC or INTERFACE). Meson currently propagates all flags, PUBLIC and PRIVATE, as part of the generated dependency() which causes problems when some of the private flags are highly disruptive, e.g. `-Wl,--version-script`. Tease apart the two kinds of link flags and, for non-static libraries, only propagate the PUBLIC/INTERFACE flags and not the PRIVATE ones. --- .../snippets/cmake_only_public_link_flags_in_dep.md | 8 ++++++++ mesonbuild/cmake/interpreter.py | 10 +++++++++- mesonbuild/cmake/tracetargets.py | 4 +++- 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 docs/markdown/snippets/cmake_only_public_link_flags_in_dep.md diff --git a/docs/markdown/snippets/cmake_only_public_link_flags_in_dep.md b/docs/markdown/snippets/cmake_only_public_link_flags_in_dep.md new file mode 100644 index 000000000000..83ccfd439166 --- /dev/null +++ b/docs/markdown/snippets/cmake_only_public_link_flags_in_dep.md @@ -0,0 +1,8 @@ +## Dependencies from CMake subprojects now use only PUBLIC link flags + +Any [[@dep]] obtained from a CMake subproject (or `.wrap` with `method = cmake`) +now only includes link flags marked in CMake as `PUBLIC` or `INTERFACE`. +Flags marked as `PRIVATE` are now only applied when building the subproject +library and not when using it as a dependency. This better matches how CMake +handles link flags and fixes link errors when using some CMake projects as +subprojects. diff --git a/mesonbuild/cmake/interpreter.py b/mesonbuild/cmake/interpreter.py index 5e6cde653516..1f82f875b32a 100644 --- a/mesonbuild/cmake/interpreter.py +++ b/mesonbuild/cmake/interpreter.py @@ -223,6 +223,7 @@ def __init__(self, target: CMakeTarget, env: 'Environment', for_machine: Machine self.install_dir: T.Optional[Path] = None self.link_libraries = target.link_libraries self.link_flags = target.link_flags + target.link_lang_flags + self.public_link_flags: T.List[str] = [] self.depends_raw: T.List[str] = [] self.depends: T.List[T.Union[ConverterTarget, ConverterCustomTarget]] = [] @@ -347,6 +348,7 @@ def postprocess(self, output_target_map: OutputTargetMap, root_src_dir: Path, su rtgt = resolve_cmake_trace_targets(self.cmake_name, trace, self.env) self.includes += [Path(x) for x in rtgt.include_directories] self.link_flags += rtgt.link_flags + self.public_link_flags += rtgt.public_link_flags self.public_compile_opts += rtgt.public_compile_opts self.link_libraries += rtgt.libraries @@ -1167,12 +1169,18 @@ def process_target(tgt: ConverterTarget) -> None: # declare_dependency kwargs dep_kwargs: TYPE_mixed_kwargs = { - 'link_args': tgt.link_flags + tgt.link_libraries, 'link_with': id_node(tgt_var), 'compile_args': tgt.public_compile_opts, 'include_directories': id_node(inc_var), } + # Static libraries need all link options and transient dependencies, but other + # libraries should only use the link flags from INTERFACE_LINK_OPTIONS. + if tgt_func == 'static_library': + dep_kwargs['link_args'] = tgt.link_flags + tgt.link_libraries + else: + dep_kwargs['link_args'] = tgt.public_link_flags + if dependencies: generated += dependencies diff --git a/mesonbuild/cmake/tracetargets.py b/mesonbuild/cmake/tracetargets.py index 5a9d35284e29..2cc0c1722c3a 100644 --- a/mesonbuild/cmake/tracetargets.py +++ b/mesonbuild/cmake/tracetargets.py @@ -42,6 +42,7 @@ class ResolvedTarget: def __init__(self) -> None: self.include_directories: T.List[str] = [] self.link_flags: T.List[str] = [] + self.public_link_flags: T.List[str] = [] self.public_compile_opts: T.List[str] = [] self.libraries: T.List[str] = [] @@ -111,7 +112,8 @@ def resolve_cmake_trace_targets(target_name: str, res.include_directories += [x for x in tgt.properties['INTERFACE_INCLUDE_DIRECTORIES'] if x] if 'INTERFACE_LINK_OPTIONS' in tgt.properties: - res.link_flags += [x for x in tgt.properties['INTERFACE_LINK_OPTIONS'] if x] + res.public_link_flags += [x for x in tgt.properties['INTERFACE_LINK_OPTIONS'] if x] + res.link_flags += res.public_link_flags if 'INTERFACE_COMPILE_DEFINITIONS' in tgt.properties: res.public_compile_opts += ['-D' + re.sub('^-D', '', x) for x in tgt.properties['INTERFACE_COMPILE_DEFINITIONS'] if x] From 066cf804bb3981db64043dc5f3f03a9d493d27d6 Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Fri, 12 Jul 2024 21:55:58 -0500 Subject: [PATCH 030/302] tests: Extend cmake test with -Wl,--version-script This tests that CMake link flags marked as PRIVATE are not propagated through the generated Meson dependency. -Wl,--version-script is used as the "poison" here, the build ultimately fails if it appears in the shared_library() link command. --- test cases/cmake/2 advanced/main3.cpp | 6 ++++++ test cases/cmake/2 advanced/meson.build | 2 ++ test cases/cmake/2 advanced/slib.cpp | 14 ++++++++++++++ .../2 advanced/subprojects/cmMod/CMakeLists.txt | 7 +++++++ .../cmake/2 advanced/subprojects/cmMod/vers.map | 7 +++++++ 5 files changed, 36 insertions(+) create mode 100644 test cases/cmake/2 advanced/main3.cpp create mode 100644 test cases/cmake/2 advanced/slib.cpp create mode 100644 test cases/cmake/2 advanced/subprojects/cmMod/vers.map diff --git a/test cases/cmake/2 advanced/main3.cpp b/test cases/cmake/2 advanced/main3.cpp new file mode 100644 index 000000000000..a82c9bd1d266 --- /dev/null +++ b/test cases/cmake/2 advanced/main3.cpp @@ -0,0 +1,6 @@ +extern void slib(); + +int main() { + slib(); + return 0; +} diff --git a/test cases/cmake/2 advanced/meson.build b/test cases/cmake/2 advanced/meson.build index b301bfe42ab5..39da0c6adfc9 100644 --- a/test cases/cmake/2 advanced/meson.build +++ b/test cases/cmake/2 advanced/meson.build @@ -15,6 +15,8 @@ sub_sta = sub_pro.dependency('cmModLibStatic') # Build some files exe1 = executable('main1', ['main.cpp'], dependencies: [sub_dep]) exe2 = executable('main2', ['main.cpp'], dependencies: [sub_sta]) +slib = shared_library('slib', ['slib.cpp'], dependencies: [sub_dep]) +exe3 = executable('main3', ['main3.cpp'], link_with: slib) test('test1', exe1) test('test2', exe2) diff --git a/test cases/cmake/2 advanced/slib.cpp b/test cases/cmake/2 advanced/slib.cpp new file mode 100644 index 000000000000..a3395e5e15dc --- /dev/null +++ b/test cases/cmake/2 advanced/slib.cpp @@ -0,0 +1,14 @@ +#include +#include +#include "config.h" + +#if CONFIG_OPT != 42 +#error "Invalid value of CONFIG_OPT" +#endif + +using namespace std; + +void slib(void) { + cmModClass obj("Hello from lib"); + cout << obj.getStr() << endl; +} diff --git a/test cases/cmake/2 advanced/subprojects/cmMod/CMakeLists.txt b/test cases/cmake/2 advanced/subprojects/cmMod/CMakeLists.txt index 07501174990c..7af9e6b97119 100644 --- a/test cases/cmake/2 advanced/subprojects/cmMod/CMakeLists.txt +++ b/test cases/cmake/2 advanced/subprojects/cmMod/CMakeLists.txt @@ -17,6 +17,13 @@ generate_export_header(cmModLib) set_target_properties(cmModLib PROPERTIES VERSION 1.0.1) +include(CheckLinkerFlag) +check_linker_flag(CXX "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/vers.map" HAS_VER_SCRIPT) +if(HAS_VER_SCRIPT) + target_link_options(cmModLib PRIVATE + "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/vers.map") +endif() + add_executable(testEXE main.cpp "${CMAKE_CURRENT_BINARY_DIR}/config.h") target_link_libraries(cmModLib ZLIB::ZLIB) diff --git a/test cases/cmake/2 advanced/subprojects/cmMod/vers.map b/test cases/cmake/2 advanced/subprojects/cmMod/vers.map new file mode 100644 index 000000000000..316d05254c11 --- /dev/null +++ b/test cases/cmake/2 advanced/subprojects/cmMod/vers.map @@ -0,0 +1,7 @@ +{ + global: + extern "C++" { + cmModClass::*; + }; + local: *; +}; From 2fd7d64a50aa4f8a76d5b9ca13f7d8f8f40b959c Mon Sep 17 00:00:00 2001 From: Alyssa Ross Date: Sun, 14 Jul 2024 17:39:30 +0200 Subject: [PATCH 031/302] Revert "Support armel/armhf builds on native arm64 hosts." This reverts commit cc201a539674babf46f726859587afb5ed6a6867. It's true that some aarch64 CPUs can run 32-bit ARM code, but some (especially high-end ones, those most likely to be running builds) cannot. It's better to assume that they can't, so builds don't unnecessarily fail due to attempting to run a sanity check executable. --- mesonbuild/environment.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 1dcd2291d428..640c1b892cef 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -513,8 +513,7 @@ def machine_info_can_run(machine_info: MachineInfo): return \ (machine_info.cpu_family == true_build_cpu_family) or \ ((true_build_cpu_family == 'x86_64') and (machine_info.cpu_family == 'x86')) or \ - ((true_build_cpu_family == 'mips64') and (machine_info.cpu_family == 'mips')) or \ - ((true_build_cpu_family == 'aarch64') and (machine_info.cpu_family == 'arm')) + ((true_build_cpu_family == 'mips64') and (machine_info.cpu_family == 'mips')) class Environment: private_dir = 'meson-private' From 2a8bb3b9f10f180c50930db92eaf23e8c4c9b81a Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Mon, 15 Jul 2024 17:19:42 -0400 Subject: [PATCH 032/302] tests: short-circuit tests that require cmake, faster We have two ways of marking a test as skipped: - raise MESON_SKIP_TEST - declare that the tools it needs in test.json are unavailable Doing the former requires performing the configure stage including e.g. language setup. In several cases we weren't even getting this far anyway since we used both mechanisms (the cmake category has a category-wide skip for this, in fact). In some case, we were missing test.json declaring it skippable; add this. --- test cases/cmake/11 cmake_module_path/meson.build | 4 ---- test cases/cmake/22 cmake module/meson.build | 5 ----- .../failing build/3 cmake subproject isolation/meson.build | 4 ---- .../failing/109 cmake executable dependency/meson.build | 4 ---- test cases/failing/109 cmake executable dependency/test.json | 2 +- test cases/failing/119 cmake subproject error/meson.build | 4 ---- test cases/failing/119 cmake subproject error/test.json | 2 +- test cases/linuxlike/13 cmake dependency/meson.build | 5 +---- test cases/linuxlike/13 cmake dependency/test.json | 5 ++++- test cases/osx/9 framework recasting/meson.build | 4 ---- test cases/osx/9 framework recasting/test.json | 5 +++++ 11 files changed, 12 insertions(+), 32 deletions(-) create mode 100644 test cases/osx/9 framework recasting/test.json diff --git a/test cases/cmake/11 cmake_module_path/meson.build b/test cases/cmake/11 cmake_module_path/meson.build index e201936964ba..2e835fba1d3b 100644 --- a/test cases/cmake/11 cmake_module_path/meson.build +++ b/test cases/cmake/11 cmake_module_path/meson.build @@ -3,10 +3,6 @@ project('user CMake find_package module using cmake_module_path', ['c', 'cpp'], meson_version: '>= 0.55.0') -if not find_program('cmake', required: false).found() - error('MESON_SKIP_TEST cmake binary not available.') -endif - # NOTE: can't request Python3 via dependency('Python3', method: 'cmake') # Meson intercepts and wants "method: auto" diff --git a/test cases/cmake/22 cmake module/meson.build b/test cases/cmake/22 cmake module/meson.build index 68f9993a69ec..581804f66ce5 100644 --- a/test cases/cmake/22 cmake module/meson.build +++ b/test cases/cmake/22 cmake module/meson.build @@ -4,11 +4,6 @@ if build_machine.system() == 'cygwin' error('MESON_SKIP_TEST CMake is broken on Cygwin.') endif -cmake_bin = find_program('cmake', required: false) -if not cmake_bin.found() - error('MESON_SKIP_TEST CMake not installed.') -endif - cc = meson.get_compiler('c') if cc.get_id() == 'clang-cl' and meson.backend() == 'ninja' and build_machine.system() == 'windows' error('MESON_SKIP_TEST CMake installation nor operational for vs2017 clangclx64ninja') diff --git a/test cases/failing build/3 cmake subproject isolation/meson.build b/test cases/failing build/3 cmake subproject isolation/meson.build index e60633595529..2351ec54be4b 100644 --- a/test cases/failing build/3 cmake subproject isolation/meson.build +++ b/test cases/failing build/3 cmake subproject isolation/meson.build @@ -1,9 +1,5 @@ project('subproject isolation', ['c', 'cpp']) -if not find_program('cmake', required: false).found() - error('MESON_SKIP_TEST CMake is not installed') -endif - incdir = meson.source_root() / 'incDir' cm = import('cmake') diff --git a/test cases/failing/109 cmake executable dependency/meson.build b/test cases/failing/109 cmake executable dependency/meson.build index 48d8fcbb637c..0fc0f9b6a6e8 100644 --- a/test cases/failing/109 cmake executable dependency/meson.build +++ b/test cases/failing/109 cmake executable dependency/meson.build @@ -1,9 +1,5 @@ project('cmake-executable-dependency', 'c') -if not find_program('cmake', required: false).found() - error('MESON_SKIP_TEST CMake is not installed') -endif - cmake = import('cmake') cmlib = cmake.subproject('cmlib') maind = cmlib.dependency('main') diff --git a/test cases/failing/109 cmake executable dependency/test.json b/test cases/failing/109 cmake executable dependency/test.json index f7c477555694..92a6ee1c5916 100644 --- a/test cases/failing/109 cmake executable dependency/test.json +++ b/test cases/failing/109 cmake executable dependency/test.json @@ -1,7 +1,7 @@ { "stdout": [ { - "line": "test cases/failing/109 cmake executable dependency/meson.build:9:14: ERROR: main is an executable and does not support the dependency() method. Use target() instead." + "line": "test cases/failing/109 cmake executable dependency/meson.build:5:14: ERROR: main is an executable and does not support the dependency() method. Use target() instead." } ], "tools": { diff --git a/test cases/failing/119 cmake subproject error/meson.build b/test cases/failing/119 cmake subproject error/meson.build index a308239fc7cf..9304af7e874c 100644 --- a/test cases/failing/119 cmake subproject error/meson.build +++ b/test cases/failing/119 cmake subproject error/meson.build @@ -1,8 +1,4 @@ project('cmake-executable-dependency') -if not find_program('cmake', required: false).found() - error('MESON_SKIP_TEST CMake is not installed') -endif - cmake = import('cmake') cmlib = cmake.subproject('cmlib') diff --git a/test cases/failing/119 cmake subproject error/test.json b/test cases/failing/119 cmake subproject error/test.json index 625e45175fc1..d8271a22a065 100644 --- a/test cases/failing/119 cmake subproject error/test.json +++ b/test cases/failing/119 cmake subproject error/test.json @@ -1,7 +1,7 @@ { "stdout": [ { - "line": "test cases/failing/119 cmake subproject error/meson.build:8:14: ERROR: Failed to configure the CMake subproject: Fancy error message" + "line": "test cases/failing/119 cmake subproject error/meson.build:4:14: ERROR: Failed to configure the CMake subproject: Fancy error message" } ], "tools": { diff --git a/test cases/linuxlike/13 cmake dependency/meson.build b/test cases/linuxlike/13 cmake dependency/meson.build index f612e1d52d6d..812dcf9c5c19 100644 --- a/test cases/linuxlike/13 cmake dependency/meson.build +++ b/test cases/linuxlike/13 cmake dependency/meson.build @@ -2,10 +2,7 @@ # due to use of setup_env.json project('external CMake dependency', ['c', 'cpp']) -cmake = find_program('cmake', required: false) -if not cmake.found() - error('MESON_SKIP_TEST cmake binary not available.') -endif +cmake = find_program('cmake') # Zlib is probably on all dev machines. diff --git a/test cases/linuxlike/13 cmake dependency/test.json b/test cases/linuxlike/13 cmake dependency/test.json index 484ce202cfbc..208b59193835 100644 --- a/test cases/linuxlike/13 cmake dependency/test.json +++ b/test cases/linuxlike/13 cmake dependency/test.json @@ -10,5 +10,8 @@ { "line": " ['CMMesonTESTf1::evil_non_standard_target']" } - ] + ], + "tools": { + "cmake": ">=3.11" + } } diff --git a/test cases/osx/9 framework recasting/meson.build b/test cases/osx/9 framework recasting/meson.build index bf8a5e63ad89..83fe19ed0a28 100644 --- a/test cases/osx/9 framework recasting/meson.build +++ b/test cases/osx/9 framework recasting/meson.build @@ -1,9 +1,5 @@ project('framework recasting', 'c', 'cpp') -if not find_program('cmake', required: false).found() - error('MESON_SKIP_TEST cmake binary not available.') -endif - x = dependency('OpenAL', method: 'cmake') y = executable('tt', files('main.cpp'), dependencies: x) diff --git a/test cases/osx/9 framework recasting/test.json b/test cases/osx/9 framework recasting/test.json new file mode 100644 index 000000000000..77003c4dc3f6 --- /dev/null +++ b/test cases/osx/9 framework recasting/test.json @@ -0,0 +1,5 @@ +{ + "tools": { + "cmake": ">=3.11" + } +} From d9e2dd6c806b5edf0f686c088fff2b3836ba1624 Mon Sep 17 00:00:00 2001 From: Christoph Reiter Date: Thu, 11 Jul 2024 22:31:39 +0200 Subject: [PATCH 033/302] Revert various cross compile changes c1076241af11f10acac28d771688bb54c6b0b340 changed the logic in multiple places, in particular it looks like it was assumed that is_cross is always the same as need_exe_wrapper(), but that's not true. Also the commit only talks about mypy, so this was definitely not intended. This reverts all the cases where need_exe_wrapper() was introduced back to is_cross. The change in backends.py could be a correct simplification, but I don't know the code base enough, so reverting that too. See #13403 and #13410 --- mesonbuild/backend/backends.py | 3 ++- mesonbuild/compilers/cuda.py | 4 ++-- mesonbuild/compilers/d.py | 2 +- mesonbuild/compilers/mixins/clike.py | 4 ++-- mesonbuild/compilers/rust.py | 2 +- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index c6fe4f0a9c9c..8c4003b731e3 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -570,7 +570,8 @@ def get_executable_serialisation( else: extra_paths = [] - if self.environment.need_exe_wrapper(exe_for_machine): + is_cross_built = not self.environment.machines.matches_build_machine(exe_for_machine) + if is_cross_built and self.environment.need_exe_wrapper(): if not self.environment.has_exe_wrapper(): msg = 'An exe_wrapper is needed but was not found. Please define one ' \ 'in cross file and check the command and/or add it to PATH.' diff --git a/mesonbuild/compilers/cuda.py b/mesonbuild/compilers/cuda.py index 9af15422b821..2fd6d17c94f7 100644 --- a/mesonbuild/compilers/cuda.py +++ b/mesonbuild/compilers/cuda.py @@ -553,7 +553,7 @@ def sanity_check(self, work_dir: str, env: 'Environment') -> None: flags += self.get_ccbin_args(env.coredata.optstore) # If cross-compiling, we can't run the sanity check, only compile it. - if env.need_exe_wrapper(self.for_machine) and not env.has_exe_wrapper(): + if self.is_cross and not env.has_exe_wrapper(): # Linking cross built apps is painful. You can't really # tell if you should use -nostdlib or not and for example # on OSX the compiler binary is the same but you need @@ -575,7 +575,7 @@ def sanity_check(self, work_dir: str, env: 'Environment') -> None: raise EnvironmentException(f'Compiler {self.name_string()} cannot compile programs.') # Run sanity check (if possible) - if env.need_exe_wrapper(self.for_machine): + if self.is_cross: if not env.has_exe_wrapper(): return else: diff --git a/mesonbuild/compilers/d.py b/mesonbuild/compilers/d.py index 9420d7af3bbd..67aa2b1eb2c6 100644 --- a/mesonbuild/compilers/d.py +++ b/mesonbuild/compilers/d.py @@ -456,7 +456,7 @@ def sanity_check(self, work_dir: str, environment: 'Environment') -> None: if pc.returncode != 0: raise EnvironmentException('D compiler %s cannot compile programs.' % self.name_string()) - if environment.need_exe_wrapper(self.for_machine): + if self.is_cross: if not environment.has_exe_wrapper(): # Can't check if the binaries run so we have to assume they do return diff --git a/mesonbuild/compilers/mixins/clike.py b/mesonbuild/compilers/mixins/clike.py index 70e81a4b85d9..1fddb0f95dd1 100644 --- a/mesonbuild/compilers/mixins/clike.py +++ b/mesonbuild/compilers/mixins/clike.py @@ -278,7 +278,7 @@ def _sanity_check_impl(self, work_dir: str, environment: 'Environment', mode = CompileCheckMode.LINK if self.is_cross: binname += '_cross' - if environment.need_exe_wrapper(self.for_machine) and not environment.has_exe_wrapper(): + if not environment.has_exe_wrapper(): # Linking cross built C/C++ apps is painful. You can't really # tell if you should use -nostdlib or not and for example # on OSX the compiler binary is the same but you need @@ -308,7 +308,7 @@ def _sanity_check_impl(self, work_dir: str, environment: 'Environment', if pc.returncode != 0: raise mesonlib.EnvironmentException(f'Compiler {self.name_string()} cannot compile programs.') # Run sanity check - if environment.need_exe_wrapper(self.for_machine): + if self.is_cross: if not environment.has_exe_wrapper(): # Can't check if the binaries run so we have to assume they do return diff --git a/mesonbuild/compilers/rust.py b/mesonbuild/compilers/rust.py index 7bcab3ab46ce..d071559da118 100644 --- a/mesonbuild/compilers/rust.py +++ b/mesonbuild/compilers/rust.py @@ -87,7 +87,7 @@ def sanity_check(self, work_dir: str, environment: 'Environment') -> None: if pc.returncode != 0: raise EnvironmentException(f'Rust compiler {self.name_string()} cannot compile programs.') self._native_static_libs(work_dir, source_name) - if environment.need_exe_wrapper(self.for_machine): + if self.is_cross: if not environment.has_exe_wrapper(): # Can't check if the binaries run so we have to assume they do return From 76bd5548ae185e10a6cf3925980e8a18955e5c66 Mon Sep 17 00:00:00 2001 From: Christoph Reiter Date: Fri, 12 Jul 2024 06:34:32 +0200 Subject: [PATCH 034/302] Revert logic also in followup commit In 8d7ffe6e863834f0190e need_exe_wrapper() use was copied which was just reverted, so replace with is_cross there too, to keep things in sync. --- mesonbuild/compilers/d.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/compilers/d.py b/mesonbuild/compilers/d.py index 67aa2b1eb2c6..d8b252a94668 100644 --- a/mesonbuild/compilers/d.py +++ b/mesonbuild/compilers/d.py @@ -448,7 +448,7 @@ def sanity_check(self, work_dir: str, environment: 'Environment') -> None: compile_cmdlist = self.exelist + self.get_output_args(output_name) + self._get_target_arch_args() + [source_name] # If cross-compiling, we can't run the sanity check, only compile it. - if environment.need_exe_wrapper(self.for_machine) and not environment.has_exe_wrapper(): + if self.is_cross and not environment.has_exe_wrapper(): compile_cmdlist += self.get_compile_only_args() pc = subprocess.Popen(compile_cmdlist, cwd=work_dir) From a51d5f36da85c1652c20254a522a9448147c4fbf Mon Sep 17 00:00:00 2001 From: Christoph Reiter Date: Fri, 12 Jul 2024 07:17:12 +0200 Subject: [PATCH 035/302] Make sure machine_info_can_run() isn't called on incomplete MachineInfo If need_exe_wrapper() is called while figuring out the language compiler, the MachineInfo isn't complete yet, so machine_info_can_run() would return False despite not cross compiling. Make sure this fails loudly. --- mesonbuild/environment.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 640c1b892cef..de4dec8fe287 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -510,6 +510,7 @@ def machine_info_can_run(machine_info: MachineInfo): if machine_info.system != detect_system(): return False true_build_cpu_family = detect_cpu_family({}) + assert machine_info.cpu_family is not None, 'called on incomplete machine_info' return \ (machine_info.cpu_family == true_build_cpu_family) or \ ((true_build_cpu_family == 'x86_64') and (machine_info.cpu_family == 'x86')) or \ From 4b31974ec5d73afd8deb5b89b35ad917ebef05ba Mon Sep 17 00:00:00 2001 From: Tristan Partin Date: Tue, 16 Jul 2024 10:02:34 -0500 Subject: [PATCH 036/302] Fix the zlib-ng failing tests, for real I failed to properly account for the case in which the two string are completely equal. --- .../linuxlike/1 pkg-config/prog-checkver.c | 17 ++++++++++------- .../13 cmake dependency/prog-checkver.c | 17 ++++++++++------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/test cases/linuxlike/1 pkg-config/prog-checkver.c b/test cases/linuxlike/1 pkg-config/prog-checkver.c index fe705d45da99..14d574642923 100644 --- a/test cases/linuxlike/1 pkg-config/prog-checkver.c +++ b/test cases/linuxlike/1 pkg-config/prog-checkver.c @@ -4,6 +4,12 @@ #include static bool check_version(const char *zlib_ver, const char *found_zlib) { + if (zlib_ver == found_zlib) + return true; + + if (strcmp(zlib_ver, found_zlib) == 0) + return true; + #ifdef ZLIBNG_VERSION const char *ptr = strstr(zlib_ver, found_zlib); @@ -16,14 +22,11 @@ static bool check_version(const char *zlib_ver, const char *found_zlib) { * that FOUND_ZLIB is the start of ZLIB_VERSION, so compare the rest. */ ptr += strlen(found_zlib); - if (strcmp(ptr, ".zlib-ng") != 0) - return false; -#else - if (strcmp(zlib_ver, found_zlib) != 0) - return false; + if (strcmp(ptr, ".zlib-ng") == 0) + return true; #endif - return true; + return false; } int main(void) { @@ -31,7 +34,7 @@ int main(void) { if (!check_version(ZLIB_VERSION, FOUND_ZLIB)) { printf("Meson found '%s' but zlib is '%s'\n", FOUND_ZLIB, ZLIB_VERSION); #ifdef ZLIBNG_VERSION - puts("Note that in the case of zlib-ng, a version suffix of .zlib-ng is expected\n"); + puts("Note that in the case of zlib-ng, a version suffix of .zlib-ng is expected"); #endif return 2; } diff --git a/test cases/linuxlike/13 cmake dependency/prog-checkver.c b/test cases/linuxlike/13 cmake dependency/prog-checkver.c index fe705d45da99..14d574642923 100644 --- a/test cases/linuxlike/13 cmake dependency/prog-checkver.c +++ b/test cases/linuxlike/13 cmake dependency/prog-checkver.c @@ -4,6 +4,12 @@ #include static bool check_version(const char *zlib_ver, const char *found_zlib) { + if (zlib_ver == found_zlib) + return true; + + if (strcmp(zlib_ver, found_zlib) == 0) + return true; + #ifdef ZLIBNG_VERSION const char *ptr = strstr(zlib_ver, found_zlib); @@ -16,14 +22,11 @@ static bool check_version(const char *zlib_ver, const char *found_zlib) { * that FOUND_ZLIB is the start of ZLIB_VERSION, so compare the rest. */ ptr += strlen(found_zlib); - if (strcmp(ptr, ".zlib-ng") != 0) - return false; -#else - if (strcmp(zlib_ver, found_zlib) != 0) - return false; + if (strcmp(ptr, ".zlib-ng") == 0) + return true; #endif - return true; + return false; } int main(void) { @@ -31,7 +34,7 @@ int main(void) { if (!check_version(ZLIB_VERSION, FOUND_ZLIB)) { printf("Meson found '%s' but zlib is '%s'\n", FOUND_ZLIB, ZLIB_VERSION); #ifdef ZLIBNG_VERSION - puts("Note that in the case of zlib-ng, a version suffix of .zlib-ng is expected\n"); + puts("Note that in the case of zlib-ng, a version suffix of .zlib-ng is expected"); #endif return 2; } From ff2a6d999ac9d3f28cc479531e006ad8f937cb45 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 9 Jul 2024 13:59:17 -0700 Subject: [PATCH 037/302] run_tests: add annotations to get_fake_env --- run_tests.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/run_tests.py b/run_tests.py index 36ec689e1054..d32a5ac74caf 100755 --- a/run_tests.py +++ b/run_tests.py @@ -148,7 +148,8 @@ def get_fake_options(prefix: str = '') -> SharedCMDOptions: opts.cmd_line_options = {} return opts -def get_fake_env(sdir='', bdir=None, prefix='', opts=None): +def get_fake_env(sdir: str = '', bdir: T.Optional[str] = None, prefix: str = '', + opts: T.Optional[SharedCMDOptions] = None) -> Environment: if opts is None: opts = get_fake_options(prefix) env = Environment(sdir, bdir, opts) From 978a58ea1ebd8274a43cbe5a624b4a8d45bdef65 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 9 Jul 2024 14:21:37 -0700 Subject: [PATCH 038/302] unittests: Add type annotations to the helpers module --- run_mypy.py | 1 + unittests/helpers.py | 83 +++++++++++++++++++++++++++----------------- 2 files changed, 53 insertions(+), 31 deletions(-) diff --git a/run_mypy.py b/run_mypy.py index 35a90e8e9f35..f72e96b3d3a2 100755 --- a/run_mypy.py +++ b/run_mypy.py @@ -84,6 +84,7 @@ 'tools', 'docs/genrefman.py', 'docs/refman', + 'unittests/helpers.py', ] if os.name == 'posix': diff --git a/unittests/helpers.py b/unittests/helpers.py index 761241308ef1..5e919295515d 100644 --- a/unittests/helpers.py +++ b/unittests/helpers.py @@ -1,3 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright © 2024 Intel Corporation + +from __future__ import annotations import subprocess import os import shutil @@ -17,20 +21,25 @@ from mesonbuild.options import OptionKey from run_tests import get_fake_env +if T.TYPE_CHECKING: + from typing_extensions import ParamSpec + + P = ParamSpec('P') + R = T.TypeVar('R') + -def is_ci(): - if os.environ.get('MESON_CI_JOBNAME') not in {None, 'thirdparty'}: - return True - return False +def is_ci() -> bool: + return os.environ.get('MESON_CI_JOBNAME', 'thirdparty') != 'thirdparty' -def skip_if_not_base_option(feature): + +def skip_if_not_base_option(feature: str) -> T.Callable[[T.Callable[P, R]], T.Callable[P, R]]: """Skip tests if The compiler does not support a given base option. for example, ICC doesn't currently support b_sanitize. """ - def actual(f): + def actual(f: T.Callable[P, R]) -> T.Callable[P, R]: @functools.wraps(f) - def wrapped(*args, **kwargs): + def wrapped(*args: P.args, **kwargs: P.kwargs) -> R: env = get_fake_env() cc = detect_c_compiler(env, MachineChoice.HOST) key = OptionKey(feature) @@ -41,7 +50,8 @@ def wrapped(*args, **kwargs): return wrapped return actual -def skipIfNoPkgconfig(f): + +def skipIfNoPkgconfig(f: T.Callable[P, R]) -> T.Callable[P, R]: ''' Skip this test if no pkg-config is found, unless we're on CI. This allows users to run our test suite without having @@ -51,19 +61,20 @@ def skipIfNoPkgconfig(f): Note: Yes, we provide pkg-config even while running Windows CI ''' @functools.wraps(f) - def wrapped(*args, **kwargs): + def wrapped(*args: P.args, **kwargs: P.kwargs) -> R: if not is_ci() and shutil.which('pkg-config') is None: raise unittest.SkipTest('pkg-config not found') return f(*args, **kwargs) return wrapped -def skipIfNoPkgconfigDep(depname): + +def skipIfNoPkgconfigDep(depname: str) -> T.Callable[[T.Callable[P, R]], T.Callable[P, R]]: ''' Skip this test if the given pkg-config dep is not found, unless we're on CI. ''' - def wrapper(func): + def wrapper(func: T.Callable[P, R]) -> T.Callable[P, R]: @functools.wraps(func) - def wrapped(*args, **kwargs): + def wrapped(*args: P.args, **kwargs: P.kwargs) -> R: if not is_ci() and shutil.which('pkg-config') is None: raise unittest.SkipTest('pkg-config not found') if not is_ci() and subprocess.call(['pkg-config', '--exists', depname]) != 0: @@ -72,7 +83,8 @@ def wrapped(*args, **kwargs): return wrapped return wrapper -def skip_if_no_cmake(f): + +def skip_if_no_cmake(f: T.Callable[P, R]) -> T.Callable[P, R]: ''' Skip this test if no cmake is found, unless we're on CI. This allows users to run our test suite without having @@ -80,16 +92,17 @@ def skip_if_no_cmake(f): silently skip the test because of misconfiguration. ''' @functools.wraps(f) - def wrapped(*args, **kwargs): + def wrapped(*args: P.args, **kwargs: P.kwargs) -> R: if not is_ci() and shutil.which('cmake') is None: raise unittest.SkipTest('cmake not found') return f(*args, **kwargs) return wrapped -def skip_if_not_language(lang: str): - def wrapper(func): + +def skip_if_not_language(lang: str) -> T.Callable[[T.Callable[P, R]], T.Callable[P, R]]: + def wrapper(func: T.Callable[P, R]) -> T.Callable[P, R]: @functools.wraps(func) - def wrapped(*args, **kwargs): + def wrapped(*args: P.args, **kwargs: P.kwargs) -> R: try: compiler_from_language(get_fake_env(), lang, MachineChoice.HOST) except EnvironmentException: @@ -98,13 +111,14 @@ def wrapped(*args, **kwargs): return wrapped return wrapper -def skip_if_env_set(key): + +def skip_if_env_set(key: str) -> T.Callable[[T.Callable[P, R]], T.Callable[P, R]]: ''' Skip a test if a particular env is set, except when running under CI ''' - def wrapper(func): + def wrapper(func: T.Callable[P, R]) -> T.Callable[P, R]: @functools.wraps(func) - def wrapped(*args, **kwargs): + def wrapped(*args: P.args, **kwargs: P.kwargs) -> R: old = None if key in os.environ: if not is_ci(): @@ -118,26 +132,27 @@ def wrapped(*args, **kwargs): return wrapped return wrapper -def skipIfNoExecutable(exename): + +def skipIfNoExecutable(exename: str) -> T.Callable[[T.Callable[P, R]], T.Callable[P, R]]: ''' Skip this test if the given executable is not found. ''' - def wrapper(func): + def wrapper(func: T.Callable[P, R]) -> T.Callable[P, R]: @functools.wraps(func) - def wrapped(*args, **kwargs): + def wrapped(*args: P.args, **kwargs: P.kwargs) -> R: if shutil.which(exename) is None: raise unittest.SkipTest(exename + ' not found') return func(*args, **kwargs) return wrapped return wrapper -def is_tarball(): - if not os.path.isdir('docs'): - return True - return False + +def is_tarball() -> bool: + return not os.path.isdir('docs') + @contextmanager -def chdir(path: str): +def chdir(path: str) -> T.Iterator[None]: curdir = os.getcwd() os.chdir(path) try: @@ -145,6 +160,7 @@ def chdir(path: str): finally: os.chdir(curdir) + def get_dynamic_section_entry(fname: str, entry: str) -> T.Optional[str]: if is_cygwin() or is_osx(): raise unittest.SkipTest('Test only applicable to ELF platforms') @@ -162,9 +178,11 @@ def get_dynamic_section_entry(fname: str, entry: str) -> T.Optional[str]: return str(m.group(1)) return None # The file did not contain the specified entry. + def get_soname(fname: str) -> T.Optional[str]: return get_dynamic_section_entry(fname, 'soname') + def get_rpath(fname: str) -> T.Optional[str]: raw = get_dynamic_section_entry(fname, r'(?:rpath|runpath)') # Get both '' and None here @@ -178,11 +196,12 @@ def get_rpath(fname: str) -> T.Optional[str]: return None return final + def get_classpath(fname: str) -> T.Optional[str]: with zipfile.ZipFile(fname) as zip: with zip.open('META-INF/MANIFEST.MF') as member: contents = member.read().decode().strip() - lines = [] + lines: T.List[str] = [] for line in contents.splitlines(): if line.startswith(' '): # continuation line @@ -194,6 +213,7 @@ def get_classpath(fname: str) -> T.Optional[str]: } return manifest.get('class-path') + def get_path_without_cmd(cmd: str, path: str) -> str: pathsep = os.pathsep paths = OrderedSet([Path(p).resolve() for p in path.split(pathsep)]) @@ -206,10 +226,11 @@ def get_path_without_cmd(cmd: str, path: str) -> str: path = pathsep.join([str(p) for p in paths]) return path -def xfail_if_jobname(name: str): + +def xfail_if_jobname(name: str) -> T.Callable[[T.Callable[P, R]], T.Callable[P, R]]: if os.environ.get('MESON_CI_JOBNAME') == name: return unittest.expectedFailure - def wrapper(func): + def wrapper(func: T.Callable[P, R]) -> T.Callable[P, R]: return func return wrapper From de8e3d65e06f91f0927e84dbf215a298b73590b8 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Thu, 11 Jul 2024 16:26:32 +0300 Subject: [PATCH 039/302] Remove option type from OptionKey and get it from OptionStore instead. --- mesonbuild/coredata.py | 22 ++++++---- mesonbuild/options.py | 76 ++++++++++++++-------------------- unittests/allplatformstests.py | 2 +- unittests/internaltests.py | 14 +++---- 4 files changed, 54 insertions(+), 60 deletions(-) diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 1659d5180c98..5150e6927c2c 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -22,7 +22,7 @@ pickle_load ) -from .options import OptionKey, OptionType +from .options import OptionKey from .machinefile import CmdLineFileParser @@ -586,8 +586,6 @@ def get_external_link_args(self, for_machine: MachineChoice, lang: str) -> T.Lis def update_project_options(self, project_options: 'MutableKeyedOptionDictType', subproject: SubProject) -> None: for key, value in project_options.items(): - if not self.optstore.is_project_option(key): - continue if key not in self.optstore: self.optstore.add_project_option(key, value) continue @@ -654,7 +652,7 @@ def set_options(self, opts_to_set: T.Dict[OptionKey, T.Any], subproject: str = ' continue elif k in self.optstore: dirty |= self.set_option(k, v, first_invocation) - elif k.machine != MachineChoice.BUILD and k.type != OptionType.COMPILER: + elif k.machine != MachineChoice.BUILD and not self.optstore.is_compiler_option(k): unknown_options.append(k) if unknown_options: unknown_options_str = ', '.join(sorted(str(s) for s in unknown_options)) @@ -700,9 +698,9 @@ def set_default_options(self, default_options: T.MutableMapping[OptionKey, str], continue # Skip base, compiler, and backend options, they are handled when # adding languages and setting backend. - if k.type in {OptionType.COMPILER, OptionType.BACKEND}: + if self.optstore.is_compiler_option(k) or self.optstore.is_backend_option(k): continue - if k.type == OptionType.BASE and k.as_root() in base_options: + if self.optstore.is_base_option(k) and k.as_root() in base_options: # set_options will report unknown base options continue options[k] = v @@ -908,7 +906,17 @@ def __getitem__(self, key: OptionKey) -> options.UserOption: # FIXME: This is fundamentally the same algorithm than interpreter.get_option_internal(). # We should try to share the code somehow. key = key.evolve(subproject=self.subproject) - if not key.is_project_hack_for_optionsview(): + if not isinstance(self.original_options, options.OptionStore): + # This is only used by CUDA currently. + # This entire class gets removed when option refactor + # is finished. + if '_' in key.name or key.lang is not None: + is_project_option = False + else: + sys.exit(f'FAIL {key}.') + else: + is_project_option = self.original_options.is_project_option(key) + if not is_project_option: opt = self.original_options.get(key) if opt is None or opt.yielding: key2 = key.as_root() diff --git a/mesonbuild/options.py b/mesonbuild/options.py index f7195173f9d1..013fd1ad6196 100644 --- a/mesonbuild/options.py +++ b/mesonbuild/options.py @@ -5,7 +5,6 @@ from itertools import chain from functools import total_ordering import argparse -import enum from .mesonlib import ( HoldableObject, @@ -39,32 +38,6 @@ buildtypelist = ['plain', 'debug', 'debugoptimized', 'release', 'minsize', 'custom'] -class OptionType(enum.IntEnum): - - """Enum used to specify what kind of argument a thing is.""" - - BUILTIN = 0 - BACKEND = 1 - BASE = 2 - COMPILER = 3 - PROJECT = 4 - -def _classify_argument(key: 'OptionKey') -> OptionType: - """Classify arguments into groups so we know which dict to assign them to.""" - - if key.name.startswith('b_'): - return OptionType.BASE - elif key.lang is not None: - return OptionType.COMPILER - elif key.name in _BUILTIN_NAMES or key.module: - return OptionType.BUILTIN - elif key.name.startswith('backend_'): - assert key.machine is MachineChoice.HOST, str(key) - return OptionType.BACKEND - else: - assert key.machine is MachineChoice.HOST, str(key) - return OptionType.PROJECT - # This is copied from coredata. There is no way to share this, because this # is used in the OptionKey constructor, and the coredata lists are # OptionKeys... @@ -117,21 +90,19 @@ class OptionKey: internally easier to reason about and produce. """ - __slots__ = ['name', 'subproject', 'machine', 'lang', '_hash', 'type', 'module'] + __slots__ = ['name', 'subproject', 'machine', 'lang', '_hash', 'module'] name: str subproject: str machine: MachineChoice lang: T.Optional[str] _hash: int - type: OptionType module: T.Optional[str] def __init__(self, name: str, subproject: str = '', machine: MachineChoice = MachineChoice.HOST, lang: T.Optional[str] = None, - module: T.Optional[str] = None, - _type: T.Optional[OptionType] = None): + module: T.Optional[str] = None): # the _type option to the constructor is kinda private. We want to be # able tos ave the state and avoid the lookup function when # pickling/unpickling, but we need to be able to calculate it when @@ -142,9 +113,6 @@ def __init__(self, name: str, subproject: str = '', object.__setattr__(self, 'lang', lang) object.__setattr__(self, 'module', module) object.__setattr__(self, '_hash', hash((name, subproject, machine, lang, module))) - if _type is None: - _type = _classify_argument(self) - object.__setattr__(self, 'type', _type) def __setattr__(self, key: str, value: T.Any) -> None: raise AttributeError('OptionKey instances do not support mutation.') @@ -155,7 +123,6 @@ def __getstate__(self) -> T.Dict[str, T.Any]: 'subproject': self.subproject, 'machine': self.machine, 'lang': self.lang, - '_type': self.type, 'module': self.module, } @@ -173,8 +140,8 @@ def __setstate__(self, state: T.Dict[str, T.Any]) -> None: def __hash__(self) -> int: return self._hash - def _to_tuple(self) -> T.Tuple[str, OptionType, str, str, MachineChoice, str]: - return (self.subproject, self.type, self.lang or '', self.module or '', self.machine, self.name) + def _to_tuple(self) -> T.Tuple[str, str, str, MachineChoice, str]: + return (self.subproject, self.lang or '', self.module or '', self.machine, self.name) def __eq__(self, other: object) -> bool: if isinstance(other, OptionKey): @@ -199,7 +166,7 @@ def __str__(self) -> str: return out def __repr__(self) -> str: - return f'OptionKey({self.name!r}, {self.subproject!r}, {self.machine!r}, {self.lang!r}, {self.module!r}, {self.type!r})' + return f'OptionKey({self.name!r}, {self.subproject!r}, {self.machine!r}, {self.lang!r}, {self.module!r})' @classmethod def from_string(cls, raw: str) -> 'OptionKey': @@ -269,7 +236,8 @@ def as_host(self) -> 'OptionKey': def is_project_hack_for_optionsview(self) -> bool: """This method will be removed once we can delete OptionsView.""" - return self.type is OptionType.PROJECT + import sys + sys.exit('FATAL internal error. This should not make it into an actual release. File a bug.') class UserOption(T.Generic[_T], HoldableObject): @@ -712,6 +680,7 @@ def add_to_argparse(self, name: str, parser: argparse.ArgumentParser, help_suffi class OptionStore: def __init__(self): self.d: T.Dict['OptionKey', 'UserOption[T.Any]'] = {} + self.project_options = set() def __len__(self): return len(self.d) @@ -734,6 +703,7 @@ def add_system_option(self, key: T.Union[OptionKey, str], valobj: 'UserOption[T. def add_project_option(self, key: T.Union[OptionKey, str], valobj: 'UserOption[T.Any]'): key = self.ensure_key(key) self.d[key] = valobj + self.project_options.add(key) def set_value(self, key: T.Union[OptionKey, str], new_value: 'T.Any') -> bool: key = self.ensure_key(key) @@ -774,23 +744,39 @@ def get(self, *args, **kwargs) -> UserOption: def is_project_option(self, key: OptionKey) -> bool: """Convenience method to check if this is a project option.""" - return key.type is OptionType.PROJECT + return key in self.project_options def is_reserved_name(self, key: OptionKey) -> bool: - return not self.is_project_option(key) + if key.name in _BUILTIN_NAMES: + return True + # FIXME, this hack is needed until the lang field is removed from OptionKey. + if key.lang is not None: + return True + if '_' not in key.name: + return False + prefix = key.name.split('_')[0] + # Pylint seems to think that it is faster to build a set object + # and all related work just to test whether a string has one of two + # values. It is not, thank you very much. + if prefix in ('b', 'backend'): # pylint: disable=R6201 + return True + from .compilers import all_languages + if prefix in all_languages: + return True + return False def is_builtin_option(self, key: OptionKey) -> bool: """Convenience method to check if this is a builtin option.""" - return key.type is OptionType.BUILTIN + return key.name in _BUILTIN_NAMES or key.module def is_base_option(self, key: OptionKey) -> bool: """Convenience method to check if this is a base option.""" - return key.type is OptionType.BASE + return key.name.startswith('b_') def is_backend_option(self, key: OptionKey) -> bool: """Convenience method to check if this is a backend option.""" - return key.type is OptionType.BACKEND + return key.name.startswith('backend_') def is_compiler_option(self, key: OptionKey) -> bool: """Convenience method to check if this is a compiler option.""" - return key.type is OptionType.COMPILER + return key.lang is not None diff --git a/unittests/allplatformstests.py b/unittests/allplatformstests.py index 5e1635378cff..b96925e6aa40 100644 --- a/unittests/allplatformstests.py +++ b/unittests/allplatformstests.py @@ -3758,9 +3758,9 @@ def test_summary(self): User defined options backend : ''' + self.backend_name + ''' + enabled_opt : enabled libdir : lib prefix : /usr - enabled_opt : enabled python : ''' + sys.executable + ''' ''') expected_lines = expected.split('\n')[1:] diff --git a/unittests/internaltests.py b/unittests/internaltests.py index 109f28ca11e2..bbdf2d9b7334 100644 --- a/unittests/internaltests.py +++ b/unittests/internaltests.py @@ -34,7 +34,7 @@ LibType, MachineChoice, PerMachine, Version, is_windows, is_osx, is_cygwin, is_openbsd, search_version, MesonException, ) -from mesonbuild.options import OptionKey, OptionType +from mesonbuild.options import OptionKey from mesonbuild.interpreter.type_checking import in_set_validator, NoneType from mesonbuild.dependencies.pkgconfig import PkgConfigDependency, PkgConfigInterface, PkgConfigCLI from mesonbuild.programs import ExternalProgram @@ -1704,16 +1704,16 @@ def test_major_versions_differ(self) -> None: def test_option_key_from_string(self) -> None: cases = [ - ('c_args', OptionKey('args', lang='c', _type=OptionType.COMPILER)), - ('build.cpp_args', OptionKey('args', machine=MachineChoice.BUILD, lang='cpp', _type=OptionType.COMPILER)), - ('prefix', OptionKey('prefix', _type=OptionType.BUILTIN)), - ('made_up', OptionKey('made_up', _type=OptionType.PROJECT)), + ('c_args', OptionKey('args', lang='c')), + ('build.cpp_args', OptionKey('args', machine=MachineChoice.BUILD, lang='cpp')), + ('prefix', OptionKey('prefix')), + ('made_up', OptionKey('made_up')), # TODO: the from_String method should be splitting the prefix off of # these, as we have the type already, but it doesn't. For now have a # test so that we don't change the behavior un-intentionally - ('b_lto', OptionKey('b_lto', _type=OptionType.BASE)), - ('backend_startup_project', OptionKey('backend_startup_project', _type=OptionType.BACKEND)), + ('b_lto', OptionKey('b_lto')), + ('backend_startup_project', OptionKey('backend_startup_project')), ] for raw, expected in cases: From 61c742fae9ec74e81b3bb3caf815cf49992fb93c Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Fri, 12 Jul 2024 20:57:04 +0300 Subject: [PATCH 040/302] Remove language (AKA compiler) type from OptionKey. --- mesonbuild/backend/ninjabackend.py | 4 +- mesonbuild/backend/vs2010backend.py | 6 +-- mesonbuild/build.py | 14 +++++- mesonbuild/cmake/interpreter.py | 2 +- mesonbuild/compilers/c.py | 2 +- mesonbuild/compilers/compilers.py | 8 ++-- mesonbuild/compilers/cpp.py | 16 ++++--- mesonbuild/compilers/cuda.py | 2 +- mesonbuild/compilers/mixins/elbrus.py | 2 +- mesonbuild/compilers/mixins/emscripten.py | 4 +- mesonbuild/compilers/objc.py | 4 +- mesonbuild/compilers/objcpp.py | 4 +- mesonbuild/coredata.py | 14 +++--- mesonbuild/environment.py | 9 ++-- mesonbuild/modules/__init__.py | 5 +-- mesonbuild/modules/rust.py | 4 +- mesonbuild/options.py | 52 ++++++++++++----------- run_tests.py | 2 +- unittests/allplatformstests.py | 8 ++-- unittests/internaltests.py | 6 +-- unittests/linuxliketests.py | 2 +- 21 files changed, 93 insertions(+), 77 deletions(-) diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index d46dfacbaeb6..e1c6d0ca863b 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -1091,7 +1091,7 @@ def should_use_dyndeps_for_target(self, target: 'build.BuildTarget') -> bool: cpp = target.compilers['cpp'] if cpp.get_id() != 'msvc': return False - cppversion = target.get_option(OptionKey('std', machine=target.for_machine, lang='cpp')) + cppversion = target.get_option(OptionKey('cpp_std', machine=target.for_machine)) if cppversion not in ('latest', 'c++latest', 'vc++latest'): return False if not mesonlib.current_vs_supports_modules(): @@ -1783,7 +1783,7 @@ def generate_cython_transpile(self, target: build.BuildTarget) -> \ args += self.build.get_project_args(cython, target.subproject, target.for_machine) args += target.get_extra_args('cython') - ext = target.get_option(OptionKey('language', machine=target.for_machine, lang='cython')) + ext = target.get_option(OptionKey('cython_language', machine=target.for_machine)) pyx_sources = [] # Keep track of sources we're adding to build diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py index 2187b8fa02cc..a12963cdee06 100644 --- a/mesonbuild/backend/vs2010backend.py +++ b/mesonbuild/backend/vs2010backend.py @@ -1011,8 +1011,8 @@ def get_args_defines_and_inc_dirs(self, target, compiler, generated_files_includ file_args[l] += args # Compile args added from the env or cross file: CFLAGS/CXXFLAGS, etc. We want these # to override all the defaults, but not the per-target compile args. - for l in file_args.keys(): - file_args[l] += target.get_option(OptionKey('args', machine=target.for_machine, lang=l)) + for lang in file_args.keys(): + file_args[lang] += target.get_option(OptionKey(f'{lang}_args', machine=target.for_machine)) for args in file_args.values(): # This is where Visual Studio will insert target_args, target_defines, # etc, which are added later from external deps (see below). @@ -1340,7 +1340,7 @@ def add_non_makefile_vcxproj_elements( # Exception handling has to be set in the xml in addition to the "AdditionalOptions" because otherwise # cl will give warning D9025: overriding '/Ehs' with cpp_eh value if 'cpp' in target.compilers: - eh = target.get_option(OptionKey('eh', machine=target.for_machine, lang='cpp')) + eh = target.get_option(OptionKey('cpp_eh', machine=target.for_machine)) if eh == 'a': ET.SubElement(clconf, 'ExceptionHandling').text = 'Async' elif eh == 's': diff --git a/mesonbuild/build.py b/mesonbuild/build.py index c86b6661336c..f40e8f70eaa7 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -652,10 +652,20 @@ def process_kwargs_base(self, kwargs: T.Dict[str, T.Any]) -> None: self.set_option_overrides(self.parse_overrides(kwargs)) + def is_compiler_option_hack(self, key): + # FIXME this method must be deleted when OptionsView goes away. + # At that point the build target only stores the original string. + # The decision on how to use those pieces of data is done elsewhere. + from .compilers import all_languages + if '_' not in key.name: + return False + prefix = key.name.split('_')[0] + return prefix in all_languages + def set_option_overrides(self, option_overrides: T.Dict[OptionKey, str]) -> None: self.options.overrides = {} for k, v in option_overrides.items(): - if k.lang: + if self.is_compiler_option_hack(k): self.options.overrides[k.evolve(machine=self.for_machine)] = v else: self.options.overrides[k] = v @@ -1002,7 +1012,7 @@ def process_compilers(self) -> T.List[str]: if 'vala' in self.compilers and 'c' not in self.compilers: self.compilers['c'] = self.all_compilers['c'] if 'cython' in self.compilers: - key = OptionKey('language', machine=self.for_machine, lang='cython') + key = OptionKey('cython_language', machine=self.for_machine) value = self.get_option(key) try: diff --git a/mesonbuild/cmake/interpreter.py b/mesonbuild/cmake/interpreter.py index 1f82f875b32a..7071fe4f8a4f 100644 --- a/mesonbuild/cmake/interpreter.py +++ b/mesonbuild/cmake/interpreter.py @@ -535,7 +535,7 @@ def _all_source_suffixes(self) -> 'ImmutableListProtocol[str]': @lru_cache(maxsize=None) def _all_lang_stds(self, lang: str) -> 'ImmutableListProtocol[str]': try: - res = self.env.coredata.optstore.get_value_object(OptionKey('std', machine=MachineChoice.BUILD, lang=lang)).choices + res = self.env.coredata.optstore.get_value_object(OptionKey(f'{lang}_std', machine=MachineChoice.BUILD)).choices except KeyError: return [] diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index bfadcdb35920..819ef8bb8628 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -310,7 +310,7 @@ def get_options(self) -> 'MutableKeyedOptionDictType': self.update_options( opts, self.create_option(options.UserArrayOption, - key.evolve('winlibs'), + key.evolve('c_winlibs'), 'Standard Win libraries to link against', gnu_winlibs), ) diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 247d7e1c0f41..7057fc2a2662 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -1355,7 +1355,7 @@ def get_preprocessor(self) -> Compiler: raise EnvironmentException(f'{self.get_id()} does not support preprocessor') def form_compileropt_key(self, basename: str) -> OptionKey: - return OptionKey(basename, machine=self.for_machine, lang=self.language) + return OptionKey(f'{self.language}_{basename}', machine=self.for_machine) def get_global_options(lang: str, comp: T.Type[Compiler], @@ -1363,9 +1363,9 @@ def get_global_options(lang: str, env: 'Environment') -> 'dict[OptionKey, options.UserOption[Any]]': """Retrieve options that apply to all compilers for a given language.""" description = f'Extra arguments passed to the {lang}' - argkey = OptionKey('args', lang=lang, machine=for_machine) - largkey = argkey.evolve('link_args') - envkey = argkey.evolve('env_args') + argkey = OptionKey(f'{lang}_args', machine=for_machine) + largkey = argkey.evolve(f'{lang}_link_args') + envkey = argkey.evolve(f'{lang}_env_args') comp_key = argkey if argkey in env.options else envkey diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py index ed840e6d53c2..1f095245514c 100644 --- a/mesonbuild/compilers/cpp.py +++ b/mesonbuild/compilers/cpp.py @@ -475,7 +475,7 @@ def get_options(self) -> 'MutableKeyedOptionDictType': self.update_options( opts, self.create_option(options.UserArrayOption, - key.evolve('winlibs'), + key.evolve('cpp_winlibs'), 'Standard Win libraries to link against', gnu_winlibs), ) @@ -483,17 +483,21 @@ def get_options(self) -> 'MutableKeyedOptionDictType': def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] - key = self.form_compileropt_key('std') - std = options.get_value(key) + stdkey = self.form_compileropt_key('std') + ehkey = self.form_compileropt_key('eh') + rttikey = self.form_compileropt_key('rtti') + debugstlkey = self.form_compileropt_key('debugstl') + + std = options.get_value(stdkey) if std != 'none': args.append(self._find_best_cpp_std(std)) - non_msvc_eh_options(options.get_value(key.evolve('eh')), args) + non_msvc_eh_options(options.get_value(ehkey), args) - if not options.get_value(key.evolve('rtti')): + if not options.get_value(rttikey): args.append('-fno-rtti') - if options.get_value(key.evolve('debugstl')): + if options.get_value(debugstlkey): args.append('-D_GLIBCXX_DEBUG=1') return args diff --git a/mesonbuild/compilers/cuda.py b/mesonbuild/compilers/cuda.py index 2fd6d17c94f7..090c1ab94bae 100644 --- a/mesonbuild/compilers/cuda.py +++ b/mesonbuild/compilers/cuda.py @@ -664,7 +664,7 @@ def _to_host_compiler_options(self, master_options: 'KeyedOptionDictType') -> 'K # We must strip the -std option from the host compiler option set, as NVCC has # its own -std flag that may not agree with the host compiler's. host_options = {key: master_options.get(key, opt) for key, opt in self.host_compiler.get_options().items()} - std_key = OptionKey('std', machine=self.for_machine, lang=self.host_compiler.language) + std_key = OptionKey(f'{self.host_compiler.language}_std', machine=self.for_machine) overrides = {std_key: 'none'} # To shut up mypy. return coredata.OptionsView(host_options, overrides=overrides) diff --git a/mesonbuild/compilers/mixins/elbrus.py b/mesonbuild/compilers/mixins/elbrus.py index 7f853f221bbd..66f419cf02d8 100644 --- a/mesonbuild/compilers/mixins/elbrus.py +++ b/mesonbuild/compilers/mixins/elbrus.py @@ -85,7 +85,7 @@ def get_pch_suffix(self) -> str: def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] - std = options.get_value(OptionKey('std', lang=self.language, machine=self.for_machine)) + std = options.get_value(OptionKey(f'{self.language}_std', machine=self.for_machine)) if std != 'none': args.append('-std=' + std) return args diff --git a/mesonbuild/compilers/mixins/emscripten.py b/mesonbuild/compilers/mixins/emscripten.py index f8d15634470c..33b6134a344f 100644 --- a/mesonbuild/compilers/mixins/emscripten.py +++ b/mesonbuild/compilers/mixins/emscripten.py @@ -51,7 +51,7 @@ def _get_compile_output(self, dirname: str, mode: CompileCheckMode) -> str: def thread_link_flags(self, env: 'Environment') -> T.List[str]: args = ['-pthread'] - count: int = env.coredata.optstore.get_value(OptionKey('thread_count', lang=self.language, machine=self.for_machine)) + count: int = env.coredata.optstore.get_value(OptionKey(f'{self.language}_thread_count', machine=self.for_machine)) if count: args.append(f'-sPTHREAD_POOL_SIZE={count}') return args @@ -61,7 +61,7 @@ def get_options(self) -> coredata.MutableKeyedOptionDictType: super().get_options(), self.create_option( options.UserIntegerOption, - OptionKey('thread_count', machine=self.for_machine, lang=self.language), + OptionKey(f'{self.language}_thread_count', machine=self.for_machine), 'Number of threads to use in web assembly, set to 0 to disable', (0, None, 4), # Default was picked at random ), diff --git a/mesonbuild/compilers/objc.py b/mesonbuild/compilers/objc.py index 7846f04f4295..37958d8a00c1 100644 --- a/mesonbuild/compilers/objc.py +++ b/mesonbuild/compilers/objc.py @@ -82,7 +82,7 @@ def get_options(self) -> 'coredata.MutableKeyedOptionDictType': return self.update_options( super().get_options(), self.create_option(options.UserComboOption, - OptionKey('std', machine=self.for_machine, lang='c'), + OptionKey('c_std', machine=self.for_machine), 'C language standard to use', ['none', 'c89', 'c99', 'c11', 'c17', 'gnu89', 'gnu99', 'gnu11', 'gnu17'], 'none'), @@ -90,7 +90,7 @@ def get_options(self) -> 'coredata.MutableKeyedOptionDictType': def get_option_compile_args(self, options: 'coredata.KeyedOptionDictType') -> T.List[str]: args = [] - std = options.get_value(OptionKey('std', machine=self.for_machine, lang='c')) + std = options.get_value(OptionKey('c_std', machine=self.for_machine)) if std != 'none': args.append('-std=' + std) return args diff --git a/mesonbuild/compilers/objcpp.py b/mesonbuild/compilers/objcpp.py index af10c838906f..6388d41c3f37 100644 --- a/mesonbuild/compilers/objcpp.py +++ b/mesonbuild/compilers/objcpp.py @@ -82,7 +82,7 @@ def get_options(self) -> coredata.MutableKeyedOptionDictType: return self.update_options( super().get_options(), self.create_option(options.UserComboOption, - OptionKey('std', machine=self.for_machine, lang='cpp'), + OptionKey('cpp_std', machine=self.for_machine), 'C++ language standard to use', ['none', 'c++98', 'c++11', 'c++14', 'c++17', 'c++20', 'c++2b', 'gnu++98', 'gnu++11', 'gnu++14', 'gnu++17', 'gnu++20', @@ -92,7 +92,7 @@ def get_options(self) -> coredata.MutableKeyedOptionDictType: def get_option_compile_args(self, options: 'coredata.KeyedOptionDictType') -> T.List[str]: args = [] - std = options.get_value(OptionKey('std', machine=self.for_machine, lang='cpp')) + std = options.get_value(OptionKey('cpp_std', machine=self.for_machine)) if std != 'none': args.append('-std=' + std) return args diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 5150e6927c2c..8c797cdb80c9 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -568,20 +568,19 @@ def _set_others_from_buildtype(self, value: str) -> bool: return dirty - @staticmethod - def is_per_machine_option(optname: OptionKey) -> bool: + def is_per_machine_option(self, optname: OptionKey) -> bool: if optname.as_host() in options.BUILTIN_OPTIONS_PER_MACHINE: return True - return optname.lang is not None + return self.optstore.is_compiler_option(optname) def get_external_args(self, for_machine: MachineChoice, lang: str) -> T.List[str]: # mypy cannot analyze type of OptionKey - key = OptionKey('args', machine=for_machine, lang=lang) + key = OptionKey(f'{lang}_args', machine=for_machine) return T.cast('T.List[str]', self.optstore.get_value(key)) def get_external_link_args(self, for_machine: MachineChoice, lang: str) -> T.List[str]: # mypy cannot analyze type of OptionKey - key = OptionKey('link_args', machine=for_machine, lang=lang) + key = OptionKey(f'{lang}_link_args', machine=for_machine) return T.cast('T.List[str]', self.optstore.get_value(key)) def update_project_options(self, project_options: 'MutableKeyedOptionDictType', subproject: SubProject) -> None: @@ -732,7 +731,8 @@ def add_lang_args(self, lang: str, comp: T.Type['Compiler'], # These options are all new at this point, because the compiler is # responsible for adding its own options, thus calling # `self.optstore.update()`` is perfectly safe. - self.optstore.update(compilers.get_global_options(lang, comp, for_machine, env)) + for gopt_key, gopt_valobj in compilers.get_global_options(lang, comp, for_machine, env).items(): + self.optstore.add_compiler_option(lang, gopt_key, gopt_valobj) def process_compiler_options(self, lang: str, comp: Compiler, env: Environment, subproject: str) -> None: from . import compilers @@ -924,7 +924,7 @@ def __getitem__(self, key: OptionKey) -> options.UserOption: # to hold overrides. if isinstance(self.original_options, options.OptionStore): if key2 not in self.original_options: - raise KeyError + raise KeyError(f'{key} {key2}') opt = self.original_options.get_value_object(key2) else: opt = self.original_options[key2] diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index de4dec8fe287..d316f4f6634b 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -743,14 +743,12 @@ def _set_default_options_from_env(self) -> None: # if it changes on future invocations. if self.first_invocation: if keyname == 'ldflags': - key = OptionKey('link_args', machine=for_machine, lang='c') # needs a language to initialize properly for lang in compilers.compilers.LANGUAGES_USING_LDFLAGS: - key = key.evolve(lang=lang) + key = OptionKey(name=f'{lang}_link_args', machine=for_machine) env_opts[key].extend(p_list) elif keyname == 'cppflags': - key = OptionKey('env_args', machine=for_machine, lang='c') for lang in compilers.compilers.LANGUAGES_USING_CPPFLAGS: - key = key.evolve(lang=lang) + key = OptionKey(f'{lang}_env_args', machine=for_machine) env_opts[key].extend(p_list) else: key = OptionKey.from_string(keyname).evolve(machine=for_machine) @@ -770,7 +768,8 @@ def _set_default_options_from_env(self) -> None: # We still use the original key as the base here, as # we want to inherit the machine and the compiler # language - key = key.evolve('env_args') + lang = key.name.split('_', 1)[0] + key = key.evolve(f'{lang}_env_args') env_opts[key].extend(p_list) # Only store options that are not already in self.options, diff --git a/mesonbuild/modules/__init__.py b/mesonbuild/modules/__init__.py index e1b9eb27b1ba..94d7e5da6885 100644 --- a/mesonbuild/modules/__init__.py +++ b/mesonbuild/modules/__init__.py @@ -133,15 +133,14 @@ def test(self, args: T.Tuple[str, T.Union[build.Executable, build.Jar, 'External def get_option(self, name: str, subproject: str = '', machine: MachineChoice = MachineChoice.HOST, - lang: T.Optional[str] = None, module: T.Optional[str] = None) -> T.Union[T.List[str], str, int, bool]: - return self.environment.coredata.get_option(OptionKey(name, subproject, machine, lang, module)) + return self.environment.coredata.get_option(OptionKey(name, subproject, machine, module)) def is_user_defined_option(self, name: str, subproject: str = '', machine: MachineChoice = MachineChoice.HOST, lang: T.Optional[str] = None, module: T.Optional[str] = None) -> bool: - key = OptionKey(name, subproject, machine, lang, module) + key = OptionKey(name, subproject, machine, module) return key in self._interpreter.user_defined_options.cmd_line_options def process_include_dirs(self, dirs: T.Iterable[T.Union[str, IncludeDirs]]) -> T.Iterable[IncludeDirs]: diff --git a/mesonbuild/modules/rust.py b/mesonbuild/modules/rust.py index a8e22541c164..2e5f16f3c459 100644 --- a/mesonbuild/modules/rust.py +++ b/mesonbuild/modules/rust.py @@ -269,7 +269,7 @@ def bindgen(self, state: ModuleState, args: T.List, kwargs: FuncBindgen) -> Modu raise InterpreterException(f'Unknown file type extension for: {name}') # We only want include directories and defines, other things may not be valid - cargs = state.get_option('args', state.subproject, lang=language) + cargs = state.get_option(f'{language}_args', state.subproject) assert isinstance(cargs, list), 'for mypy' for a in itertools.chain(state.global_args.get(language, []), state.project_args.get(language, []), cargs): if a.startswith(('-I', '/I', '-D', '/D', '-U', '/U')): @@ -280,7 +280,7 @@ def bindgen(self, state: ModuleState, args: T.List, kwargs: FuncBindgen) -> Modu # Add the C++ standard to the clang arguments. Attempt to translate VS # extension versions into the nearest standard version - std = state.get_option('std', lang=language) + std = state.get_option(f'{language}_std') assert isinstance(std, str), 'for mypy' if std.startswith('vc++'): if std.endswith('latest'): diff --git a/mesonbuild/options.py b/mesonbuild/options.py index 013fd1ad6196..e50aa431f1c5 100644 --- a/mesonbuild/options.py +++ b/mesonbuild/options.py @@ -90,18 +90,16 @@ class OptionKey: internally easier to reason about and produce. """ - __slots__ = ['name', 'subproject', 'machine', 'lang', '_hash', 'module'] + __slots__ = ['name', 'subproject', 'machine', '_hash', 'module'] name: str subproject: str machine: MachineChoice - lang: T.Optional[str] _hash: int module: T.Optional[str] def __init__(self, name: str, subproject: str = '', machine: MachineChoice = MachineChoice.HOST, - lang: T.Optional[str] = None, module: T.Optional[str] = None): # the _type option to the constructor is kinda private. We want to be # able tos ave the state and avoid the lookup function when @@ -110,9 +108,8 @@ def __init__(self, name: str, subproject: str = '', object.__setattr__(self, 'name', name) object.__setattr__(self, 'subproject', subproject) object.__setattr__(self, 'machine', machine) - object.__setattr__(self, 'lang', lang) object.__setattr__(self, 'module', module) - object.__setattr__(self, '_hash', hash((name, subproject, machine, lang, module))) + object.__setattr__(self, '_hash', hash((name, subproject, machine, module))) def __setattr__(self, key: str, value: T.Any) -> None: raise AttributeError('OptionKey instances do not support mutation.') @@ -122,7 +119,6 @@ def __getstate__(self) -> T.Dict[str, T.Any]: 'name': self.name, 'subproject': self.subproject, 'machine': self.machine, - 'lang': self.lang, 'module': self.module, } @@ -141,7 +137,7 @@ def __hash__(self) -> int: return self._hash def _to_tuple(self) -> T.Tuple[str, str, str, MachineChoice, str]: - return (self.subproject, self.lang or '', self.module or '', self.machine, self.name) + return (self.subproject, self.module or '', self.machine, self.name) def __eq__(self, other: object) -> bool: if isinstance(other, OptionKey): @@ -155,8 +151,6 @@ def __lt__(self, other: object) -> bool: def __str__(self) -> str: out = self.name - if self.lang: - out = f'{self.lang}_{out}' if self.machine is MachineChoice.BUILD: out = f'build.{out}' if self.module: @@ -166,7 +160,7 @@ def __str__(self) -> str: return out def __repr__(self) -> str: - return f'OptionKey({self.name!r}, {self.subproject!r}, {self.machine!r}, {self.lang!r}, {self.module!r})' + return f'OptionKey({self.name!r}, {self.subproject!r}, {self.machine!r}, {self.module!r})' @classmethod def from_string(cls, raw: str) -> 'OptionKey': @@ -191,18 +185,14 @@ def from_string(cls, raw: str) -> 'OptionKey': except ValueError: raw3 = raw2 - from .compilers import all_languages - if any(raw3.startswith(f'{l}_') for l in all_languages): - lang, opt = raw3.split('_', 1) - else: - lang, opt = None, raw3 + opt = raw3 assert ':' not in opt assert '.' not in opt - return cls(opt, subproject, for_machine, lang, module) + return cls(opt, subproject, for_machine, module) def evolve(self, name: T.Optional[str] = None, subproject: T.Optional[str] = None, - machine: T.Optional[MachineChoice] = None, lang: T.Optional[str] = '', + machine: T.Optional[MachineChoice] = None, module: T.Optional[str] = '') -> 'OptionKey': """Create a new copy of this key, but with altered members. @@ -218,7 +208,6 @@ def evolve(self, name: T.Optional[str] = None, subproject: T.Optional[str] = Non name if name is not None else self.name, subproject if subproject is not None else self.subproject, machine if machine is not None else self.machine, - lang if lang != '' else self.lang, module if module != '' else self.module ) @@ -681,6 +670,10 @@ class OptionStore: def __init__(self): self.d: T.Dict['OptionKey', 'UserOption[T.Any]'] = {} self.project_options = set() + self.all_languages = set() + from .compilers import all_languages + for lang in all_languages: + self.all_languages.add(lang) def __len__(self): return len(self.d) @@ -698,8 +691,15 @@ def get_value(self, key: T.Union[OptionKey, str]) -> 'T.Any': def add_system_option(self, key: T.Union[OptionKey, str], valobj: 'UserOption[T.Any]'): key = self.ensure_key(key) + assert isinstance(valobj, UserOption) self.d[key] = valobj + def add_compiler_option(self, language: str, key: T.Union[OptionKey, str], valobj: 'UserOption[T.Any]'): + key = self.ensure_key(key) + if not key.name.startswith(language + '_'): + raise MesonException(f'Internal error: all compiler option names must start with language prefix. ({key.name} vs {language}_)') + self.add_system_option(key, valobj) + def add_project_option(self, key: T.Union[OptionKey, str], valobj: 'UserOption[T.Any]'): key = self.ensure_key(key) self.d[key] = valobj @@ -733,6 +733,7 @@ def values(self): def items(self) -> ItemsView['OptionKey', 'UserOption[T.Any]']: return self.d.items() + # FIXME: this method must be deleted and users moved to use "add_xxx_option"s instead. def update(self, *args, **kwargs): return self.d.update(*args, **kwargs) @@ -749,9 +750,6 @@ def is_project_option(self, key: OptionKey) -> bool: def is_reserved_name(self, key: OptionKey) -> bool: if key.name in _BUILTIN_NAMES: return True - # FIXME, this hack is needed until the lang field is removed from OptionKey. - if key.lang is not None: - return True if '_' not in key.name: return False prefix = key.name.split('_')[0] @@ -760,8 +758,7 @@ def is_reserved_name(self, key: OptionKey) -> bool: # values. It is not, thank you very much. if prefix in ('b', 'backend'): # pylint: disable=R6201 return True - from .compilers import all_languages - if prefix in all_languages: + if prefix in self.all_languages: return True return False @@ -779,4 +776,11 @@ def is_backend_option(self, key: OptionKey) -> bool: def is_compiler_option(self, key: OptionKey) -> bool: """Convenience method to check if this is a compiler option.""" - return key.lang is not None + + # FIXME, duplicate of is_reserved_name above. Should maybe store a cache instead. + if '_' not in key.name: + return False + prefix = key.name.split('_')[0] + if prefix in self.all_languages: + return True + return False diff --git a/run_tests.py b/run_tests.py index d32a5ac74caf..4e22028b830c 100755 --- a/run_tests.py +++ b/run_tests.py @@ -153,7 +153,7 @@ def get_fake_env(sdir: str = '', bdir: T.Optional[str] = None, prefix: str = '', if opts is None: opts = get_fake_options(prefix) env = Environment(sdir, bdir, opts) - env.coredata.optstore.set_value_object(OptionKey('args', lang='c'), FakeCompilerOptions()) + env.coredata.optstore.set_value_object(OptionKey('c_args'), FakeCompilerOptions()) env.machines.host.cpu_family = 'x86_64' # Used on macOS inside find_library # Invalidate cache when using a different Environment object. clear_meson_configure_class_caches() diff --git a/unittests/allplatformstests.py b/unittests/allplatformstests.py index b96925e6aa40..726252611fb7 100644 --- a/unittests/allplatformstests.py +++ b/unittests/allplatformstests.py @@ -2725,11 +2725,11 @@ def test_command_line(self): # c_args value should be parsed with split_args self.init(testdir, extra_args=['-Dc_args=-Dfoo -Dbar "-Dthird=one two"', '--fatal-meson-warnings']) obj = mesonbuild.coredata.load(self.builddir) - self.assertEqual(obj.optstore.get_value(OptionKey('args', lang='c')), ['-Dfoo', '-Dbar', '-Dthird=one two']) + self.assertEqual(obj.optstore.get_value(OptionKey('c_args')), ['-Dfoo', '-Dbar', '-Dthird=one two']) self.setconf('-Dc_args="foo bar" one two') obj = mesonbuild.coredata.load(self.builddir) - self.assertEqual(obj.optstore.get_value(OptionKey('args', lang='c')), ['foo bar', 'one', 'two']) + self.assertEqual(obj.optstore.get_value(OptionKey('c_args')), ['foo bar', 'one', 'two']) self.wipe() self.init(testdir, extra_args=['-Dset_percent_opt=myoption%', '--fatal-meson-warnings']) @@ -2748,7 +2748,7 @@ def test_command_line(self): self.assertEqual(obj.optstore.get_value('bindir'), 'bar') self.assertEqual(obj.optstore.get_value('buildtype'), 'release') self.assertEqual(obj.optstore.get_value('b_sanitize'), 'thread') - self.assertEqual(obj.optstore.get_value(OptionKey('args', lang='c')), ['-Dbar']) + self.assertEqual(obj.optstore.get_value(OptionKey('c_args')), ['-Dbar']) self.setconf(['--bindir=bar', '--bindir=foo', '-Dbuildtype=release', '-Dbuildtype=plain', '-Db_sanitize=thread', '-Db_sanitize=address', @@ -2757,7 +2757,7 @@ def test_command_line(self): self.assertEqual(obj.optstore.get_value('bindir'), 'foo') self.assertEqual(obj.optstore.get_value('buildtype'), 'plain') self.assertEqual(obj.optstore.get_value('b_sanitize'), 'address') - self.assertEqual(obj.optstore.get_value(OptionKey('args', lang='c')), ['-Dfoo']) + self.assertEqual(obj.optstore.get_value(OptionKey('c_args')), ['-Dfoo']) self.wipe() except KeyError: # Ignore KeyError, it happens on CI for compilers that does not diff --git a/unittests/internaltests.py b/unittests/internaltests.py index bbdf2d9b7334..ada6602eefcf 100644 --- a/unittests/internaltests.py +++ b/unittests/internaltests.py @@ -626,7 +626,7 @@ def create_static_lib(name): env = get_fake_env() compiler = detect_c_compiler(env, MachineChoice.HOST) env.coredata.compilers.host = {'c': compiler} - env.coredata.optstore.set_value_object(OptionKey('link_args', lang='c'), FakeCompilerOptions()) + env.coredata.optstore.set_value_object(OptionKey('c_link_args'), FakeCompilerOptions()) p1 = Path(tmpdir) / '1' p2 = Path(tmpdir) / '2' p1.mkdir() @@ -1704,8 +1704,8 @@ def test_major_versions_differ(self) -> None: def test_option_key_from_string(self) -> None: cases = [ - ('c_args', OptionKey('args', lang='c')), - ('build.cpp_args', OptionKey('args', machine=MachineChoice.BUILD, lang='cpp')), + ('c_args', OptionKey('c_args')), + ('build.cpp_args', OptionKey('cpp_args', machine=MachineChoice.BUILD)), ('prefix', OptionKey('prefix')), ('made_up', OptionKey('made_up')), diff --git a/unittests/linuxliketests.py b/unittests/linuxliketests.py index 6a751dd51d07..16997e393339 100644 --- a/unittests/linuxliketests.py +++ b/unittests/linuxliketests.py @@ -486,7 +486,7 @@ def _test_stds_impl(self, testdir: str, compiler: 'Compiler') -> None: # Check that all the listed -std=xxx options for this compiler work just fine when used # https://en.wikipedia.org/wiki/Xcode#Latest_versions # https://www.gnu.org/software/gcc/projects/cxx-status.html - key = OptionKey('std', lang=compiler.language) + key = OptionKey(f'{compiler.language}_std') for v in compiler.get_options()[key].choices: # we do it like this to handle gnu++17,c++17 and gnu17,c17 cleanly # thus, C++ first From 6e200222957063819a00e3bf767ce28b7489c31f Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sun, 14 Jul 2024 19:33:41 +0300 Subject: [PATCH 041/302] Remove module type from OptionKey. --- mesonbuild/coredata.py | 6 ++- mesonbuild/mconf.py | 7 +-- mesonbuild/modules/__init__.py | 10 ++--- mesonbuild/modules/pkgconfig.py | 2 +- mesonbuild/modules/python.py | 10 ++--- mesonbuild/options.py | 78 +++++++++++++++++++++------------ unittests/datatests.py | 4 +- 7 files changed, 72 insertions(+), 45 deletions(-) diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 8c797cdb80c9..f9d209913004 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -422,7 +422,11 @@ def add_builtin_option(opts_map: 'MutableKeyedOptionDictType', key: OptionKey, value = opts_map.get_value(key.as_root()) else: value = None - opts_map.add_system_option(key, opt.init_option(key, value, options.default_prefix())) + if key.has_module_prefix(): + modulename = key.get_module_prefix() + opts_map.add_module_option(modulename, key, opt.init_option(key, value, options.default_prefix())) + else: + opts_map.add_system_option(key, opt.init_option(key, value, options.default_prefix())) def init_backend_options(self, backend_name: str) -> None: if backend_name == 'ninja': diff --git a/mesonbuild/mconf.py b/mesonbuild/mconf.py index bd54251bd6d9..6cb64e1c428d 100644 --- a/mesonbuild/mconf.py +++ b/mesonbuild/mconf.py @@ -272,12 +272,13 @@ def print_default_values_warning() -> None: dir_options[k] = v elif k in test_option_names: test_options[k] = v - elif k.module: + elif k.has_module_prefix(): # Ignore module options if we did not use that module during # configuration. - if self.build and k.module not in self.build.modules: + modname = k.get_module_prefix() + if self.build and modname not in self.build.modules: continue - module_options[k.module][k] = v + module_options[modname][k] = v elif self.coredata.optstore.is_builtin_option(k): core_options[k] = v diff --git a/mesonbuild/modules/__init__.py b/mesonbuild/modules/__init__.py index 94d7e5da6885..3fe4956c75e5 100644 --- a/mesonbuild/modules/__init__.py +++ b/mesonbuild/modules/__init__.py @@ -132,15 +132,13 @@ def test(self, args: T.Tuple[str, T.Union[build.Executable, build.Jar, 'External self._interpreter.func_test(self.current_node, real_args, kwargs) def get_option(self, name: str, subproject: str = '', - machine: MachineChoice = MachineChoice.HOST, - module: T.Optional[str] = None) -> T.Union[T.List[str], str, int, bool]: - return self.environment.coredata.get_option(OptionKey(name, subproject, machine, module)) + machine: MachineChoice = MachineChoice.HOST) -> T.Union[T.List[str], str, int, bool]: + return self.environment.coredata.get_option(OptionKey(name, subproject, machine)) def is_user_defined_option(self, name: str, subproject: str = '', machine: MachineChoice = MachineChoice.HOST, - lang: T.Optional[str] = None, - module: T.Optional[str] = None) -> bool: - key = OptionKey(name, subproject, machine, module) + lang: T.Optional[str] = None) -> bool: + key = OptionKey(name, subproject, machine) return key in self._interpreter.user_defined_options.cmd_line_options def process_include_dirs(self, dirs: T.Iterable[T.Union[str, IncludeDirs]]) -> T.Iterable[IncludeDirs]: diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index d66c2a901ca4..16c8c079846d 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -703,7 +703,7 @@ def parse_variable_list(vardict: T.Dict[str, str]) -> T.List[T.Tuple[str, str]]: else: pkgroot = os.path.join(_as_str(state.environment.coredata.get_option(OptionKey('libdir'))), 'pkgconfig') pkgroot_name = os.path.join('{libdir}', 'pkgconfig') - relocatable = state.get_option('relocatable', module='pkgconfig') + relocatable = state.get_option('pkgconfig.relocatable') self._generate_pkgconfig_file(state, deps, subdirs, name, description, url, version, pcfile, conflicts, variables, unescaped_variables, False, dataonly, diff --git a/mesonbuild/modules/python.py b/mesonbuild/modules/python.py index dec77e24948c..1b7a05640374 100644 --- a/mesonbuild/modules/python.py +++ b/mesonbuild/modules/python.py @@ -83,13 +83,13 @@ def _get_path(self, state: T.Optional['ModuleState'], key: str) -> str: if not state: # This happens only from run_project_tests.py return rel_path - value = T.cast('str', state.get_option(f'{key}dir', module='python')) + value = T.cast('str', state.get_option(f'python.{key}dir')) if value: - if state.is_user_defined_option('install_env', module='python'): + if state.is_user_defined_option('python.install_env'): raise mesonlib.MesonException(f'python.{key}dir and python.install_env are mutually exclusive') return value - install_env = state.get_option('install_env', module='python') + install_env = state.get_option('python.install_env') if install_env == 'auto': install_env = 'venv' if self.info['is_venv'] else 'system' @@ -169,7 +169,7 @@ def extension_module_method(self, args: T.Tuple[str, T.List[BuildTargetSource]], self.current_node) limited_api_version = kwargs.pop('limited_api') - allow_limited_api = self.interpreter.environment.coredata.get_option(OptionKey('allow_limited_api', module='python')) + allow_limited_api = self.interpreter.environment.coredata.get_option(OptionKey('python.allow_limited_api')) if limited_api_version != '' and allow_limited_api: target_suffix = self.limited_api_suffix @@ -374,7 +374,7 @@ def __init__(self, interpreter: 'Interpreter') -> None: def _get_install_scripts(self) -> T.List[mesonlib.ExecutableSerialisation]: backend = self.interpreter.backend ret = [] - optlevel = self.interpreter.environment.coredata.get_option(OptionKey('bytecompile', module='python')) + optlevel = self.interpreter.environment.coredata.get_option(OptionKey('python.bytecompile')) if optlevel == -1: return ret if not any(PythonExternalProgram.run_bytecompile.values()): diff --git a/mesonbuild/options.py b/mesonbuild/options.py index e50aa431f1c5..912cfa23b978 100644 --- a/mesonbuild/options.py +++ b/mesonbuild/options.py @@ -90,17 +90,15 @@ class OptionKey: internally easier to reason about and produce. """ - __slots__ = ['name', 'subproject', 'machine', '_hash', 'module'] + __slots__ = ['name', 'subproject', 'machine', '_hash'] name: str subproject: str machine: MachineChoice _hash: int - module: T.Optional[str] def __init__(self, name: str, subproject: str = '', - machine: MachineChoice = MachineChoice.HOST, - module: T.Optional[str] = None): + machine: MachineChoice = MachineChoice.HOST): # the _type option to the constructor is kinda private. We want to be # able tos ave the state and avoid the lookup function when # pickling/unpickling, but we need to be able to calculate it when @@ -108,8 +106,7 @@ def __init__(self, name: str, subproject: str = '', object.__setattr__(self, 'name', name) object.__setattr__(self, 'subproject', subproject) object.__setattr__(self, 'machine', machine) - object.__setattr__(self, 'module', module) - object.__setattr__(self, '_hash', hash((name, subproject, machine, module))) + object.__setattr__(self, '_hash', hash((name, subproject, machine))) def __setattr__(self, key: str, value: T.Any) -> None: raise AttributeError('OptionKey instances do not support mutation.') @@ -119,7 +116,6 @@ def __getstate__(self) -> T.Dict[str, T.Any]: 'name': self.name, 'subproject': self.subproject, 'machine': self.machine, - 'module': self.module, } def __setstate__(self, state: T.Dict[str, T.Any]) -> None: @@ -137,7 +133,7 @@ def __hash__(self) -> int: return self._hash def _to_tuple(self) -> T.Tuple[str, str, str, MachineChoice, str]: - return (self.subproject, self.module or '', self.machine, self.name) + return (self.subproject, self.machine, self.name) def __eq__(self, other: object) -> bool: if isinstance(other, OptionKey): @@ -153,14 +149,12 @@ def __str__(self) -> str: out = self.name if self.machine is MachineChoice.BUILD: out = f'build.{out}' - if self.module: - out = f'{self.module}.{out}' if self.subproject: out = f'{self.subproject}:{out}' return out def __repr__(self) -> str: - return f'OptionKey({self.name!r}, {self.subproject!r}, {self.machine!r}, {self.module!r})' + return f'OptionKey({self.name!r}, {self.subproject!r}, {self.machine!r})' @classmethod def from_string(cls, raw: str) -> 'OptionKey': @@ -174,26 +168,24 @@ def from_string(cls, raw: str) -> 'OptionKey': except ValueError: subproject, raw2 = '', raw - module = None for_machine = MachineChoice.HOST try: prefix, raw3 = raw2.split('.') if prefix == 'build': for_machine = MachineChoice.BUILD else: - module = prefix + raw3 = raw2 except ValueError: raw3 = raw2 opt = raw3 assert ':' not in opt - assert '.' not in opt + assert opt.count('.') < 2 - return cls(opt, subproject, for_machine, module) + return cls(opt, subproject, for_machine) def evolve(self, name: T.Optional[str] = None, subproject: T.Optional[str] = None, - machine: T.Optional[MachineChoice] = None, - module: T.Optional[str] = '') -> 'OptionKey': + machine: T.Optional[MachineChoice] = None) -> 'OptionKey': """Create a new copy of this key, but with altered members. For example: @@ -208,7 +200,6 @@ def evolve(self, name: T.Optional[str] = None, subproject: T.Optional[str] = Non name if name is not None else self.name, subproject if subproject is not None else self.subproject, machine if machine is not None else self.machine, - module if module != '' else self.module ) def as_root(self) -> 'OptionKey': @@ -228,6 +219,20 @@ def is_project_hack_for_optionsview(self) -> bool: import sys sys.exit('FATAL internal error. This should not make it into an actual release. File a bug.') + def has_module_prefix(self) -> bool: + return '.' in self.name + + def get_module_prefix(self) -> T.Optional[str]: + if self.has_module_prefix(): + return self.name.split('.', 1)[0] + return None + + def without_module_prefix(self) -> 'OptionKey': + if self.has_module_prefix(): + newname = self.name.split('.', 1)[1] + return self.evolve(newname) + return self + class UserOption(T.Generic[_T], HoldableObject): def __init__(self, name: str, description: str, choices: T.Optional[T.Union[str, T.List[_T]]], @@ -633,19 +638,19 @@ def add_to_argparse(self, name: str, parser: argparse.ArgumentParser, help_suffi (OptionKey('vsenv'), BuiltinOption(UserBooleanOption, 'Activate Visual Studio environment', False, readonly=True)), # Pkgconfig module - (OptionKey('relocatable', module='pkgconfig'), + (OptionKey('pkgconfig.relocatable'), BuiltinOption(UserBooleanOption, 'Generate pkgconfig files as relocatable', False)), # Python module - (OptionKey('bytecompile', module='python'), + (OptionKey('python.bytecompile'), BuiltinOption(UserIntegerOption, 'Whether to compile bytecode', (-1, 2, 0))), - (OptionKey('install_env', module='python'), + (OptionKey('python.install_env'), BuiltinOption(UserComboOption, 'Which python environment to install to', 'prefix', choices=['auto', 'prefix', 'system', 'venv'])), - (OptionKey('platlibdir', module='python'), + (OptionKey('python.platlibdir'), BuiltinOption(UserStringOption, 'Directory for site-specific, platform-specific files.', '')), - (OptionKey('purelibdir', module='python'), + (OptionKey('python.purelibdir'), BuiltinOption(UserStringOption, 'Directory for site-specific, non-platform-specific files.', '')), - (OptionKey('allow_limited_api', module='python'), + (OptionKey('python.allow_limited_api'), BuiltinOption(UserBooleanOption, 'Whether to allow use of the Python Limited API', True)), ]) @@ -662,8 +667,8 @@ def add_to_argparse(self, name: str, parser: argparse.ArgumentParser, help_suffi OptionKey('sysconfdir'): {'/usr': '/etc'}, OptionKey('localstatedir'): {'/usr': '/var', '/usr/local': '/var/local'}, OptionKey('sharedstatedir'): {'/usr': '/var/lib', '/usr/local': '/var/local/lib'}, - OptionKey('platlibdir', module='python'): {}, - OptionKey('purelibdir', module='python'): {}, + OptionKey('python.platlibdir'): {}, + OptionKey('python.purelibdir'): {}, } class OptionStore: @@ -671,6 +676,7 @@ def __init__(self): self.d: T.Dict['OptionKey', 'UserOption[T.Any]'] = {} self.project_options = set() self.all_languages = set() + self.module_options = set() from .compilers import all_languages for lang in all_languages: self.all_languages.add(lang) @@ -690,6 +696,12 @@ def get_value(self, key: T.Union[OptionKey, str]) -> 'T.Any': return self.get_value_object(key).value def add_system_option(self, key: T.Union[OptionKey, str], valobj: 'UserOption[T.Any]'): + key = self.ensure_key(key) + if '.' in key.name: + raise MesonException(f'Internal error: non-module option has a period in its name {key.name}.') + self.add_system_option_internal(key, valobj) + + def add_system_option_internal(self, key: T.Union[OptionKey, str], valobj: 'UserOption[T.Any]'): key = self.ensure_key(key) assert isinstance(valobj, UserOption) self.d[key] = valobj @@ -705,6 +717,15 @@ def add_project_option(self, key: T.Union[OptionKey, str], valobj: 'UserOption[T self.d[key] = valobj self.project_options.add(key) + def add_module_option(self, modulename: str, key: T.Union[OptionKey, str], valobj: 'UserOption[T.Any]'): + key = self.ensure_key(key) + if key.name.startswith('build.'): + raise MesonException('FATAL internal error: somebody goofed option handling.') + if not key.name.startswith(modulename + '.'): + raise MesonException('Internal error: module option name {key.name} does not start with module prefix {modulename}.') + self.add_system_option_internal(key, valobj) + self.module_options.add(key) + def set_value(self, key: T.Union[OptionKey, str], new_value: 'T.Any') -> bool: key = self.ensure_key(key) return self.d[key].set_value(new_value) @@ -764,7 +785,7 @@ def is_reserved_name(self, key: OptionKey) -> bool: def is_builtin_option(self, key: OptionKey) -> bool: """Convenience method to check if this is a builtin option.""" - return key.name in _BUILTIN_NAMES or key.module + return key.name in _BUILTIN_NAMES or self.is_module_option(key) def is_base_option(self, key: OptionKey) -> bool: """Convenience method to check if this is a base option.""" @@ -784,3 +805,6 @@ def is_compiler_option(self, key: OptionKey) -> bool: if prefix in self.all_languages: return True return False + + def is_module_option(self, key: OptionKey) -> bool: + return key in self.module_options diff --git a/unittests/datatests.py b/unittests/datatests.py index 73b937d43da5..cb6542db8f71 100644 --- a/unittests/datatests.py +++ b/unittests/datatests.py @@ -139,8 +139,8 @@ def test_builtin_options_documented(self): found_entries |= options self.assertEqual(found_entries, { - *(str(k.evolve(module=None)) for k in mesonbuild.options.BUILTIN_OPTIONS), - *(str(k.evolve(module=None)) for k in mesonbuild.options.BUILTIN_OPTIONS_PER_MACHINE), + *(str(k.without_module_prefix()) for k in mesonbuild.options.BUILTIN_OPTIONS), + *(str(k.without_module_prefix()) for k in mesonbuild.options.BUILTIN_OPTIONS_PER_MACHINE), }) # Check that `buildtype` table inside `Core options` matches how From a05f6a260ef4882f82da38ff1818ca8391b15bd8 Mon Sep 17 00:00:00 2001 From: Alyssa Ross Date: Tue, 16 Jul 2024 10:21:43 +0200 Subject: [PATCH 042/302] rust: recursively pull proc-macro deps for rust targets aee941559 ("rust: recursively pull proc-macro dependencies as well") had to be reverted (in a66cb97e8) because it broke Mesa cross compilation. This happened because a C shared library was linked with a Rust C-ABI static library, which caused it to inherit the proc macro dependency the Rust static library was linked with. The right way to handle this is for only Rust targets to inherit proc macro dependencies from static libraries they link with. A Rust executable, library, or whatever will need the proc macros its Rust dependencies use, as illustrated in the test case that I've reintroduced here. I've verified that Mesa still cross compiles correctly with this change. The same failure was also identified by the "rust/21 transitive dependencies" test case, but only when cross compiling, so it wasn't caught by CI. Co-authored-by: Xavier Claessens --- mesonbuild/build.py | 10 +++++----- test cases/rust/18 proc-macro/lib.rs | 8 ++++++++ test cases/rust/18 proc-macro/meson.build | 11 +++++++++++ test cases/rust/18 proc-macro/subdir/meson.build | 1 + .../rust/18 proc-macro/transitive-proc-macro.rs | 7 +++++++ .../rust/21 transitive dependencies/meson.build | 1 + 6 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 test cases/rust/18 proc-macro/lib.rs create mode 100644 test cases/rust/18 proc-macro/subdir/meson.build create mode 100644 test cases/rust/18 proc-macro/transitive-proc-macro.rs diff --git a/mesonbuild/build.py b/mesonbuild/build.py index f40e8f70eaa7..42f1dcc9c2f9 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -1292,10 +1292,10 @@ def get_dependencies(self) -> OrderedSet[BuildTargetTypes]: if t not in result: result.add(t) if isinstance(t, StaticLibrary): - t.get_dependencies_recurse(result) + t.get_dependencies_recurse(result, include_proc_macros = self.uses_rust()) return result - def get_dependencies_recurse(self, result: OrderedSet[BuildTargetTypes], include_internals: bool = True) -> None: + def get_dependencies_recurse(self, result: OrderedSet[BuildTargetTypes], include_internals: bool = True, include_proc_macros: bool = False) -> None: # self is always a static library because we don't need to pull dependencies # of shared libraries. If self is installed (not internal) it already # include objects extracted from all its internal dependencies so we can @@ -1304,14 +1304,14 @@ def get_dependencies_recurse(self, result: OrderedSet[BuildTargetTypes], include for t in self.link_targets: if t in result: continue - if t.rust_crate_type == 'proc-macro': + if not include_proc_macros and t.rust_crate_type == 'proc-macro': continue if include_internals or not t.is_internal(): result.add(t) if isinstance(t, StaticLibrary): - t.get_dependencies_recurse(result, include_internals) + t.get_dependencies_recurse(result, include_internals, include_proc_macros) for t in self.link_whole_targets: - t.get_dependencies_recurse(result, include_internals) + t.get_dependencies_recurse(result, include_internals, include_proc_macros) def get_source_subdir(self): return self.subdir diff --git a/test cases/rust/18 proc-macro/lib.rs b/test cases/rust/18 proc-macro/lib.rs new file mode 100644 index 000000000000..5242886cc5e4 --- /dev/null +++ b/test cases/rust/18 proc-macro/lib.rs @@ -0,0 +1,8 @@ +extern crate proc_macro_examples; +use proc_macro_examples::make_answer; + +make_answer!(); + +pub fn func() -> u32 { + answer() +} diff --git a/test cases/rust/18 proc-macro/meson.build b/test cases/rust/18 proc-macro/meson.build index c5f0dfc82aee..e8b28eda144e 100644 --- a/test cases/rust/18 proc-macro/meson.build +++ b/test cases/rust/18 proc-macro/meson.build @@ -31,3 +31,14 @@ main = executable( ) test('main_test2', main) + +subdir('subdir') + +staticlib = static_library('staticlib', 'lib.rs', + link_with: pm_in_subdir, + rust_dependency_map : {'proc_macro_examples3' : 'proc_macro_examples'} +) + +executable('transitive-proc-macro', 'transitive-proc-macro.rs', + link_with: staticlib, +) diff --git a/test cases/rust/18 proc-macro/subdir/meson.build b/test cases/rust/18 proc-macro/subdir/meson.build new file mode 100644 index 000000000000..04842c431e78 --- /dev/null +++ b/test cases/rust/18 proc-macro/subdir/meson.build @@ -0,0 +1 @@ +pm_in_subdir = rust.proc_macro('proc_macro_examples3', '../proc.rs') diff --git a/test cases/rust/18 proc-macro/transitive-proc-macro.rs b/test cases/rust/18 proc-macro/transitive-proc-macro.rs new file mode 100644 index 000000000000..4c804b3b6f4d --- /dev/null +++ b/test cases/rust/18 proc-macro/transitive-proc-macro.rs @@ -0,0 +1,7 @@ +extern crate staticlib; +use staticlib::func; + + +fn main() { + assert_eq!(42, func()); +} diff --git a/test cases/rust/21 transitive dependencies/meson.build b/test cases/rust/21 transitive dependencies/meson.build index 37687fd4db2f..3b1f3d63cd4d 100644 --- a/test cases/rust/21 transitive dependencies/meson.build +++ b/test cases/rust/21 transitive dependencies/meson.build @@ -21,6 +21,7 @@ foo = static_library('foo-rs', 'foo.rs', rust_abi: 'c', link_with: pm, ) +shared_library('shared', 'foo.c', link_with : foo) exe = executable('footest', 'foo.c', link_with: foo, ) From 377548fc5a97df6c86ae3b466740e23bdd45c02d Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Wed, 17 Jul 2024 23:59:03 +0300 Subject: [PATCH 043/302] Add script that builds releases. --- packaging/builddist.sh | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100755 packaging/builddist.sh diff --git a/packaging/builddist.sh b/packaging/builddist.sh new file mode 100755 index 000000000000..8a83c48bec05 --- /dev/null +++ b/packaging/builddist.sh @@ -0,0 +1,20 @@ +#!/usr/bin/zsh + +# This script must be run from the source root. + +set -e + +GENDIR=distgendir + +rm -rf dist +rm -rf $GENDIR +mkdir dist +mkdir $GENDIR +cp -r .git $GENDIR +cd $GENDIR +git reset --hard +#python3 setup.py sdist bdist +python3 setup.py sdist +cp dist/* ../dist +cd .. +rm -rf $GENDIR From 864919973f73ec2c6ae6ca01be7fe5e8b950df12 Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Wed, 17 Jul 2024 17:07:23 -0400 Subject: [PATCH 044/302] update script to build releases, to also build wheels The commented-out command used "bdist", which produces a "dumb" format (that's what the setuptools docs call it! it's an alias for "bdist_dumb"). A tarball that can be extracted to / and installs a system image containing e.g. /usr/lib/python3.12 and /usr/share/, but no metadata outside of that. It apparently may have also generated a wheel at some point? But current versions of setuptools do no such thing. And wheels are what we actually want, since we uploaded them for years and they are faster for PyPI users to install. The canonical command name for producing wheels is actually "bdist_wheel" instead of "bdist_dumb". No clue what setuptools changed, about the latter, but the former definitely works. --- packaging/builddist.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packaging/builddist.sh b/packaging/builddist.sh index 8a83c48bec05..edcf3ec09b94 100755 --- a/packaging/builddist.sh +++ b/packaging/builddist.sh @@ -13,8 +13,7 @@ mkdir $GENDIR cp -r .git $GENDIR cd $GENDIR git reset --hard -#python3 setup.py sdist bdist -python3 setup.py sdist +python3 setup.py sdist bdist_wheel cp dist/* ../dist cd .. rm -rf $GENDIR From 2548f921a29babe665593e5dcf401eb27aedd174 Mon Sep 17 00:00:00 2001 From: Enrico Zini Date: Thu, 18 Jul 2024 15:47:57 +0200 Subject: [PATCH 045/302] Link include_directories to implicit_include_directories --- docs/markdown/Include-directories.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/markdown/Include-directories.md b/docs/markdown/Include-directories.md index 6dfed5e48ae2..f9850ac91451 100644 --- a/docs/markdown/Include-directories.md +++ b/docs/markdown/Include-directories.md @@ -27,4 +27,6 @@ proper compiler flags to make it all work. Another thing to note is that `include_directories` adds both the source directory and corresponding build directory to include path, so -you don't have to care. +you don't have to care. If it turns out you don't want it after all, this can +be disabled with the `implicit_include_directories` argument to the [build +function](Reference-manual_functions.md) you use. From 7a306e1a46a91dadb77656a6998a8dcaa6482b8f Mon Sep 17 00:00:00 2001 From: Sam James Date: Sun, 14 Jul 2024 23:33:05 +0100 Subject: [PATCH 046/302] compilers: handle -Wno-attributes= for GCC For other reasons, Meson transforms "-Wno-x" into "-Wx -Wno-x" for GCC, but this breaks with "-Wno-attributes=x" with: ``` cc1plus: error: arguments ignored for '-Wattributes='; use '-Wno-attributes=' instead ``` Suppress that workaround for -Wno-attributes=. Closes: https://github.com/mesonbuild/meson/issues/13022 --- mesonbuild/compilers/mixins/clike.py | 6 ++++-- test cases/common/104 has arg/meson.build | 6 ++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/mesonbuild/compilers/mixins/clike.py b/mesonbuild/compilers/mixins/clike.py index 1fddb0f95dd1..9f5fc505277d 100644 --- a/mesonbuild/compilers/mixins/clike.py +++ b/mesonbuild/compilers/mixins/clike.py @@ -1268,8 +1268,10 @@ def _has_multi_arguments(self, args: T.List[str], env: 'Environment', code: str) for arg in args: # some compilers, e.g. GCC, don't warn for unsupported warning-disable # flags, so when we are testing a flag like "-Wno-forgotten-towel", also - # check the equivalent enable flag too "-Wforgotten-towel" - if arg.startswith('-Wno-'): + # check the equivalent enable flag too "-Wforgotten-towel". + # Make an exception for -Wno-attributes=x as -Wattributes=x is invalid + # for GCC at least. + if arg.startswith('-Wno-') and not arg.startswith('-Wno-attributes='): new_args.append('-W' + arg[5:]) if arg.startswith('-Wl,'): mlog.warning(f'{arg} looks like a linker argument, ' diff --git a/test cases/common/104 has arg/meson.build b/test cases/common/104 has arg/meson.build index ba0731111d21..c85ec9f25ab8 100644 --- a/test cases/common/104 has arg/meson.build +++ b/test cases/common/104 has arg/meson.build @@ -52,6 +52,12 @@ if cc.get_id() == 'gcc' assert(not cc.has_multi_arguments(['-Wno-pragmas', '-Wno-lol-meson-test-flags']), 'should error out even if some -Wno args are valid') endif +if cpp.get_id() == 'gcc' and cpp.version().version_compare('>=12.1.0') + # Handle special -Wno-attributes=foo where -Wattributes=foo is invalid + # i.e. our usual -Wno-foo -Wfoo hack doesn't work for -Wattributes=foo. + assert(cpp.has_argument('-Wno-attributes=meson::i_do_not_exist')) +endif + if cc.get_id() == 'clang' and cc.version().version_compare('<=4.0.0') # 4.0.0 does not support -fpeel-loops. Newer versions may. # Please adjust above version number as new versions of clang are released. From 96f20d5b372b9982c153b114eb3726fbbecb7542 Mon Sep 17 00:00:00 2001 From: RaviRahar Date: Fri, 19 Jul 2024 11:53:56 +0530 Subject: [PATCH 047/302] modules/gnome: gnome.compile_resources() must have 'install_dir' if installing Since they do not implement a default install dir like BuildTargets do. gnome.compile_resources() would result in an unhandled python exception when missing install_dir argument together with providing following arguments: gresource_bundle: true install: true closes: https://github.com/mesonbuild/meson/issues/13447 Signed-off-by: RaviRahar --- mesonbuild/modules/gnome.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index 37a8b5105f30..24ab50efcdda 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -479,8 +479,11 @@ def compile_resources(self, state: 'ModuleState', args: T.Tuple[str, 'FileOrStri else: raise MesonException('Compiling GResources into code is only supported in C and C++ projects') - if kwargs['install'] and not gresource: - raise MesonException('The install kwarg only applies to gresource bundles, see install_header') + if kwargs['install']: + if not gresource: + raise MesonException('The install kwarg only applies to gresource bundles, see install_header') + elif not kwargs['install_dir']: + raise MesonException('gnome.compile_resources: "install_dir" keyword argument must be set when "install" is true.') install_header = kwargs['install_header'] if install_header and gresource: From d587fb587d2d32963a7b5f6dfe45895a5e1e6076 Mon Sep 17 00:00:00 2001 From: Mads Andreasen Date: Sun, 21 Jul 2024 15:28:33 +0200 Subject: [PATCH 048/302] Remove the exe_exists function This function is no longer used since shutil.which() is used instead. --- mesonbuild/utils/universal.py | 3 --- unittests/internaltests.py | 4 ---- 2 files changed, 7 deletions(-) diff --git a/mesonbuild/utils/universal.py b/mesonbuild/utils/universal.py index b5310b8c3100..574bcb51f654 100644 --- a/mesonbuild/utils/universal.py +++ b/mesonbuild/utils/universal.py @@ -680,9 +680,6 @@ def is_qnx() -> bool: def is_aix() -> bool: return platform.system().lower() == 'aix' -def exe_exists(exe: str) -> bool: - return shutil.which(exe) is not None - @lru_cache(maxsize=None) def darwin_get_object_archs(objpath: str) -> 'ImmutableListProtocol[str]': ''' diff --git a/unittests/internaltests.py b/unittests/internaltests.py index ada6602eefcf..fa0e440d3583 100644 --- a/unittests/internaltests.py +++ b/unittests/internaltests.py @@ -814,10 +814,6 @@ def test_msvc_toolset_version(self): self.assertTrue(vctools_ver.startswith(toolset_ver), msg=f'{vctools_ver!r} does not start with {toolset_ver!r}') - def test_exe_exists(self): - self.assertTrue(utils.universal.exe_exists('python3')) - self.assertFalse(utils.universal.exe_exists('command_that_does_not_exist')) - def test_split_args(self): split_args = mesonbuild.mesonlib.split_args join_args = mesonbuild.mesonlib.join_args From bc56a2c3469def7fafbdb38da6691cccb171e739 Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Sun, 21 Jul 2024 03:52:07 -0400 Subject: [PATCH 049/302] compilers: fix partial refactor of coredata options Fallout from the OptionStore refactor, and specifically commit 9a6fcd4d9a0c7bb248c5d0587632b741a3301e03. The `std` object was migrated from having an option itself, to having the value fetched and saved directly. In most cases, this also meant avoiding `.value`, but in a couple cases this refactor went overlooked, and crashed at runtime. Only affects Elbrus and Intel C++ compilers, seemingly. Fixes #13401 --- mesonbuild/compilers/cpp.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py index 1f095245514c..f9ebf08da8e8 100644 --- a/mesonbuild/compilers/cpp.py +++ b/mesonbuild/compilers/cpp.py @@ -622,8 +622,8 @@ def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str] args: T.List[str] = [] key = self.form_compileropt_key('std') std = options.get_value(key) - if std.value != 'none': - args.append(self._find_best_cpp_std(std.value)) + if std != 'none': + args.append(self._find_best_cpp_std(std)) key = self.form_compileropt_key('eh') non_msvc_eh_options(options.get_value(key), args) @@ -699,7 +699,7 @@ def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str] 'c++03': 'c++98', 'gnu++03': 'gnu++98' } - args.append('-std=' + remap_cpp03.get(std.value, std)) + args.append('-std=' + remap_cpp03.get(std, std)) if options.get_value(key.evolve('eh')) == 'none': args.append('-fno-exceptions') if not options.get_value(key.evolve('rtti')): From 9a6adc1e36f594e0970080ba091e971f44f774b4 Mon Sep 17 00:00:00 2001 From: Joey Pabalinas Date: Sat, 20 Jul 2024 04:34:13 -1000 Subject: [PATCH 050/302] zsh: Add new vs backends Signed-off-by: Joey Pabalinas --- data/shell-completions/zsh/_meson | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/shell-completions/zsh/_meson b/data/shell-completions/zsh/_meson index 7d6d89b7ef73..6c7810c8c155 100644 --- a/data/shell-completions/zsh/_meson +++ b/data/shell-completions/zsh/_meson @@ -29,7 +29,7 @@ local curcontext="$curcontext" state line local -i ret -local __meson_backends="(ninja xcode ${(j. .)${:-vs{,2010,2015,2017}}})" +local __meson_backends="(ninja "${(j. .)${:-vs{,2010,2015,2017,2019,2022}}}" xcode none)" local __meson_build_types="(plain debug debugoptimized minsize release)" local __meson_wrap_modes="(WrapMode.{default,nofallback,nodownload,forcefallback})" local __meson_dist_formats=("xztar" "bztar" "gztar" "zip") From 7f5262b483f84c2430f67d48b54e8702ba4b1e27 Mon Sep 17 00:00:00 2001 From: Joey Pabalinas Date: Sat, 20 Jul 2024 04:34:38 -1000 Subject: [PATCH 051/302] zsh: Fix spelling errors Signed-off-by: Joey Pabalinas --- data/shell-completions/zsh/_meson | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/data/shell-completions/zsh/_meson b/data/shell-completions/zsh/_meson index 6c7810c8c155..949f9783092a 100644 --- a/data/shell-completions/zsh/_meson +++ b/data/shell-completions/zsh/_meson @@ -370,7 +370,7 @@ _arguments \ ) if (( CURRENT == 2 )); then - _describe -t commands "Meson subproject subcommands" commands + _describe -t commands "Meson subprojects subcommands" commands else local curcontext="$curcontext" cmd="${${commands[(r)$words[2]:*]%%:*}}" @@ -381,7 +381,7 @@ _arguments \ _meson-subprojects-$cmd fi else - _message "unknown meson subproject command: $words[2]" + _message "unknown meson subprojects command: $words[2]" fi fi @@ -392,7 +392,7 @@ _arguments \ local -a specs=( "$__meson_cd" '--clean[Clean the build directory]' - '(-j --jobs)'{'-j','--jobs'}'=[the number fo work jobs to run (if supported)]:_guard "[0-9]#" "number of jobs"' + '(-j --jobs)'{'-j','--jobs'}'=[the number of work jobs to run (if supported)]:_guard "[0-9]#" "number of jobs"' '(-l --load-average)'{'-l','--load-average'}'=[the system load average to try to maintain (if supported)]:_guard "[0-9]#" "load average"' '(-v --verbose)'{'-v','--verbose'}'[Show more output]' '--ninja-args=[Arguments to pass to ninja (only when using ninja)]' From 8554699c42faddd1f0775871d6dca8195a366f24 Mon Sep 17 00:00:00 2001 From: Joey Pabalinas Date: Sat, 20 Jul 2024 04:34:59 -1000 Subject: [PATCH 052/302] zsh: Add completions for {rewrite,devenv,env2mfile,format,help} subcommands Signed-off-by: Joey Pabalinas --- data/shell-completions/zsh/_meson | 97 +++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/data/shell-completions/zsh/_meson b/data/shell-completions/zsh/_meson index 949f9783092a..a016ce006558 100644 --- a/data/shell-completions/zsh/_meson +++ b/data/shell-completions/zsh/_meson @@ -81,6 +81,11 @@ local -a meson_commands=( 'wrap:manage source dependencies' 'subprojects:manage subprojects' 'compile:Build the project' +'rewrite:Modify the project definition' +'devenv:Run commands in developer environment' +'env2mfile:Convert current environment to a cross or native file' +'format:Format meson source file' +'help:Print help of a subcommand' ) (( $+functions[__meson_is_build_dir] )) || __meson_is_build_dir() { @@ -403,6 +408,98 @@ _arguments \ "${(@)specs}" } +# TODO: implement rewrite sub-commands properly +(( $+functions[_meson-rewrite-target] )) || _meson-rewrite-target() { +_arguments \ + '(: -)'{'--help','-h'}'[show a help message and quit]' \ +} + +(( $+functions[_meson-rewrite-kwargs] )) || _meson-rewrite-kwargs() { +_arguments \ + '(: -)'{'--help','-h'}'[show a help message and quit]' \ +} + +(( $+functions[_meson-rewrite-default-options] )) || _meson-rewrite-default-options() { +_arguments \ + '(: -)'{'--help','-h'}'[show a help message and quit]' \ +} + +(( $+functions[_meson-rewrite-command] )) || _meson-rewrite-command() { +_arguments \ + '(: -)'{'--help','-h'}'[show a help message and quit]' \ +} + +(( $+functions[_meson-rewrite] )) || _meson-rewrite() { + local -a commands=( + 'target:Modify a target' + 'kwargs:Modify keyword arguments' + 'default-options:Modify the project default options' + 'command:Execute a JSON array of commands' + ) + + if (( CURRENT == 2 )); then + _describe -t commands "Meson rewrite subcommands" commands + else + local curcontext="$curcontext" + cmd="${${commands[(r)$words[2]:*]%%:*}}" + if [[ $cmd == status ]]; then + _message "no options" + else + _meson-rewrite-$cmd + fi + fi + +} + +(( $+functions[_meson-devenv] )) || _meson-devenv() { + local curcontext="$curcontext" + local -a specs=( + "$__meson_cd" + '--clean=[Clean the build directory]' + '(-w workdir)'{'-w','--workdir'}'=[Directory to cd into before running (default: builddir, Since 1.0.0)]:target dir:_directories' + '--dump=[Only print required environment (Since 0.62.0) Takes an optional file path (Since 1.1.0)]:dump path:_files' + '--dump-format=[Format used with --dump (Since 1.1.0)]:format:(sh export vscode)' + ) +_arguments \ + '(: -)'{'--help','-h'}'[show a help message and quit]' \ + "${(@)specs}" +} + +(( $+functions[_meson-env2mfile] )) || _meson-env2mfile() { + local curcontext="$curcontext" + local -a specs=( + '--debarch=[The dpkg architecture to generate.]' + '--gccsuffix=[A particular gcc version suffix if necessary.]' + '-o=[The output file.]:file:_files' + '--cross=[Generate a cross compilation file.]' + '--native=[Generate a native compilation file.]' + '--system=[Define system for cross compilation.]' + '--subsystem=[Define subsystem for cross compilation.]' + '--kernel=[Define kernel for cross compilation.]' + '--cpu=[Define cpu for cross compilation.]' + '--cpu-family=[Define cpu family for cross compilation.]' + '--endian=[Define endianness for cross compilation.]:endianness:(big little)' + ) +_arguments \ + '(: -)'{'--help','-h'}'[show a help message and quit]' \ + "${(@)specs}" +} + +(( $+functions[_meson-format] )) || _meson-format() { + local curcontext="$curcontext" + local -a specs=( + '(-q --check-only)'{'-q','--check-only'}'=[exit with 1 if files would be modified by meson format]' + '(-i --inplace)'{'-i','--inplace'}'=[format files in-place]' + '(-r --recursive)'{'-r','--recursive'}'=[recurse subdirs (requires --check-only or --inplace option)]' + '(-c --configuration)'{'-c','--configuration'}'=[read configuration from meson.format]' + '(-e --editor-config)'{'-e','--editor-config'}'=[try to read configuration from .editorconfig]' + '(-o --output)'{'-o','--output'}'=[output file (implies having exactly one input)]' + ) +_arguments \ + '(: -)'{'--help','-h'}'[show a help message and quit]' \ + "${(@)specs}" +} + if [[ $service != meson ]]; then _call_function ret _$service return ret From 9459bd8bd42759c47c9248fdaa8bc9071fcff49b Mon Sep 17 00:00:00 2001 From: Joey Pabalinas Date: Sat, 20 Jul 2024 06:11:34 -1000 Subject: [PATCH 053/302] zsh: Fix incorrect __meson_wrap_modes expansion Signed-off-by: Joey Pabalinas --- data/shell-completions/zsh/_meson | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/shell-completions/zsh/_meson b/data/shell-completions/zsh/_meson index a016ce006558..8178060b4eda 100644 --- a/data/shell-completions/zsh/_meson +++ b/data/shell-completions/zsh/_meson @@ -31,7 +31,7 @@ local -i ret local __meson_backends="(ninja "${(j. .)${:-vs{,2010,2015,2017,2019,2022}}}" xcode none)" local __meson_build_types="(plain debug debugoptimized minsize release)" -local __meson_wrap_modes="(WrapMode.{default,nofallback,nodownload,forcefallback})" +local __meson_wrap_modes="(default nofallback nodownload forcefallback nopromote)" local __meson_dist_formats=("xztar" "bztar" "gztar" "zip") local __meson_cd='-C[change into this directory before running]:target dir:_directories' local -a __meson_common=( From 2d98cfd4735b87178a931e80f7bf9c8d7bcb689c Mon Sep 17 00:00:00 2001 From: LegStrong Date: Mon, 22 Jul 2024 10:54:33 +0800 Subject: [PATCH 054/302] docs: make tutorial compatible with GLib versions older than 2.74 --- docs/markdown/Tutorial.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/markdown/Tutorial.md b/docs/markdown/Tutorial.md index 4a2725503bea..7aff164a266a 100644 --- a/docs/markdown/Tutorial.md +++ b/docs/markdown/Tutorial.md @@ -143,7 +143,11 @@ int main(int argc, char **argv) GtkApplication *app; int status; +#if GLIB_CHECK_VERSION(2, 74, 0) app = gtk_application_new(NULL, G_APPLICATION_DEFAULT_FLAGS); +#else + app = gtk_application_new(NULL, G_APPLICATION_FLAGS_NONE); +#endif g_signal_connect(app, "activate", G_CALLBACK(activate), NULL); status = g_application_run(G_APPLICATION(app), argc, argv); g_object_unref(app); From 86d142666a4517c9c5694c87dc92589214be920f Mon Sep 17 00:00:00 2001 From: Pino Toscano Date: Sat, 20 Jul 2024 23:21:44 +0200 Subject: [PATCH 055/302] cmake: extend library pattern to work on GNU/Hurd as well The existing "*-linux-gnu*" works on the Debian multiarch model for Linux architectures; tweak it to be "*-gnu*" so it works also for Hurd architectures. This makes the cmake-based search of dependencies work on Debian GNU/Hurd. --- mesonbuild/dependencies/data/CMakePathInfo.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/dependencies/data/CMakePathInfo.txt b/mesonbuild/dependencies/data/CMakePathInfo.txt index 662ec58363e2..c3d8c59a145b 100644 --- a/mesonbuild/dependencies/data/CMakePathInfo.txt +++ b/mesonbuild/dependencies/data/CMakePathInfo.txt @@ -13,7 +13,7 @@ list(APPEND TMP_PATHS_LIST ${CMAKE_SYSTEM_APPBUNDLE_PATH}) set(LIB_ARCH_LIST) if(CMAKE_LIBRARY_ARCHITECTURE_REGEX) - file(GLOB implicit_dirs RELATIVE /lib /lib/*-linux-gnu* ) + file(GLOB implicit_dirs RELATIVE /lib /lib/*-gnu* ) foreach(dir ${implicit_dirs}) if("${dir}" MATCHES "${CMAKE_LIBRARY_ARCHITECTURE_REGEX}") list(APPEND LIB_ARCH_LIST "${dir}") From e9037e7b9ff81febbcef860dbfa785464ba3b457 Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Mon, 22 Jul 2024 11:56:55 -0400 Subject: [PATCH 056/302] mdist: don't fail on readonly source trees In commit c9aa4aff66ebbbcd3eed3da8fbc3af0e0a8b90a2 we added a refresh call to git to catch cases where checking for uncommitted changes would misfire. Unfortunately, that refresh performs a write operation, which in turn misfires on readonly media. We don't actually care about the return value of the refresh, since its purpose is solely to make the next command more accurate -- so ignore it. Fixes: c9aa4aff66ebbbcd3eed3da8fbc3af0e0a8b90a2 Fixes: #13461 --- mesonbuild/mdist.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mesonbuild/mdist.py b/mesonbuild/mdist.py index b1d8f6780933..0c82cd3ef596 100644 --- a/mesonbuild/mdist.py +++ b/mesonbuild/mdist.py @@ -141,7 +141,9 @@ def git_root(self, dir_: str) -> Path: def have_dirty_index(self) -> bool: '''Check whether there are uncommitted changes in git''' - subprocess.check_call(['git', '-C', self.src_root, 'update-index', '-q', '--refresh']) + # Optimistically call update-index, and disregard its return value. It could be read-only, + # and only the output of diff-index matters. + subprocess.call(['git', '-C', self.src_root, 'update-index', '-q', '--refresh']) ret = subprocess.call(['git', '-C', self.src_root, 'diff-index', '--quiet', 'HEAD']) return ret == 1 From fa70974a647db90864df4af6172cf7766f79857b Mon Sep 17 00:00:00 2001 From: Charles Brunet Date: Mon, 22 Jul 2024 14:32:52 -0400 Subject: [PATCH 057/302] Remove reference to GPL in test files We have permission to use that file. Fixes #13442. --- test cases/format/1 default/crazy_comments.meson | 2 +- test cases/format/2 muon/crazy_comments.meson | 2 +- test cases/format/3 editorconfig/crazy_comments.meson | 2 +- test cases/format/4 config/crazy_comments.meson | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test cases/format/1 default/crazy_comments.meson b/test cases/format/1 default/crazy_comments.meson index f391ca28c263..f7ed67101bfd 100644 --- a/test cases/format/1 default/crazy_comments.meson +++ b/test cases/format/1 default/crazy_comments.meson @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Stone Tickle -# SPDX-License-Identifier: GPL-3.0-only +# This file is used from muon sources, with permission project('a') diff --git a/test cases/format/2 muon/crazy_comments.meson b/test cases/format/2 muon/crazy_comments.meson index 5ebda7d63655..fe5ae1402df5 100644 --- a/test cases/format/2 muon/crazy_comments.meson +++ b/test cases/format/2 muon/crazy_comments.meson @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Stone Tickle -# SPDX-License-Identifier: GPL-3.0-only +# This file is used from muon sources, with permission project('a') diff --git a/test cases/format/3 editorconfig/crazy_comments.meson b/test cases/format/3 editorconfig/crazy_comments.meson index 788ea1c88dff..f9fdc8848d54 100644 --- a/test cases/format/3 editorconfig/crazy_comments.meson +++ b/test cases/format/3 editorconfig/crazy_comments.meson @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Stone Tickle -# SPDX-License-Identifier: GPL-3.0-only +# This file is used from muon sources, with permission project('a') diff --git a/test cases/format/4 config/crazy_comments.meson b/test cases/format/4 config/crazy_comments.meson index 557d5d409f65..71ae8f97fdd0 100644 --- a/test cases/format/4 config/crazy_comments.meson +++ b/test cases/format/4 config/crazy_comments.meson @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Stone Tickle -# SPDX-License-Identifier: GPL-3.0-only +# This file is used from muon sources, with permission project('a') From a97de6b527c0109112909af8f29e8d262a87c247 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Mon, 22 Jul 2024 08:46:18 +0300 Subject: [PATCH 058/302] Ensure override var exists. Closes #13402. --- mesonbuild/coredata.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index f9d209913004..83e83e728727 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -12,7 +12,7 @@ from itertools import chain from pathlib import PurePath from collections import OrderedDict, abc -from dataclasses import dataclass +import dataclasses from .mesonlib import ( MesonBugException, @@ -895,7 +895,7 @@ def parse_cmd_line_options(args: SharedCMDOptions) -> None: args.cmd_line_options[key] = value delattr(args, name) -@dataclass +@dataclasses.dataclass class OptionsView(abc.Mapping): '''A view on an options dictionary for a given subproject and with overrides. ''' @@ -904,7 +904,7 @@ class OptionsView(abc.Mapping): # python 3.8 or typing_extensions original_options: T.Union[KeyedOptionDictType, 'dict[OptionKey, UserOption[Any]]'] subproject: T.Optional[str] = None - overrides: T.Optional[T.Mapping[OptionKey, T.Union[str, int, bool, T.List[str]]]] = None + overrides: T.Optional[T.Mapping[OptionKey, T.Union[str, int, bool, T.List[str]]]] = dataclasses.field(default_factory=dict) def __getitem__(self, key: OptionKey) -> options.UserOption: # FIXME: This is fundamentally the same algorithm than interpreter.get_option_internal(). From 93f5ceb9eebfee229c15b31b935d8df6ad642a0b Mon Sep 17 00:00:00 2001 From: Monson Shao Date: Sun, 14 Jul 2024 21:58:03 +0800 Subject: [PATCH 059/302] depfixer: deduplicate rpaths on darwin Duplicated -delete_rpath arguments will cause macOS's install_name_tool failed. --- mesonbuild/scripts/depfixer.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/mesonbuild/scripts/depfixer.py b/mesonbuild/scripts/depfixer.py index f0166bdc3481..641689f9318d 100644 --- a/mesonbuild/scripts/depfixer.py +++ b/mesonbuild/scripts/depfixer.py @@ -379,11 +379,14 @@ def fix_elf(fname: str, rpath_dirs_to_remove: T.Set[bytes], new_rpath: T.Optiona # note: e.get_rpath() and e.get_runpath() may be useful e.fix_rpath(fname, rpath_dirs_to_remove, new_rpath) -def get_darwin_rpaths(fname: str) -> T.List[str]: +def get_darwin_rpaths(fname: str) -> OrderedSet[str]: p, out, _ = Popen_safe(['otool', '-l', fname], stderr=subprocess.DEVNULL) if p.returncode != 0: raise subprocess.CalledProcessError(p.returncode, p.args, out) - result = [] + # Need to deduplicate rpaths, as macOS's install_name_tool + # is *very* allergic to duplicate -delete_rpath arguments + # when calling depfixer on installation. + result = OrderedSet() current_cmd = 'FOOBAR' for line in out.split('\n'): line = line.strip() @@ -394,7 +397,7 @@ def get_darwin_rpaths(fname: str) -> T.List[str]: current_cmd = value if key == 'path' and current_cmd == 'LC_RPATH': rp = value.split('(', 1)[0].strip() - result.append(rp) + result.add(rp) return result def fix_darwin(fname: str, rpath_dirs_to_remove: T.Set[bytes], new_rpath: str, final_path: str, install_name_mappings: T.Dict[str, str]) -> None: From f76f9ddf28f16704b9d91066f6cc151fc78329e1 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 23 Jul 2024 14:12:35 -0700 Subject: [PATCH 060/302] depfixer: Add missing annotation that breaks mypy check --- mesonbuild/scripts/depfixer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/scripts/depfixer.py b/mesonbuild/scripts/depfixer.py index 641689f9318d..db9c97d98c6a 100644 --- a/mesonbuild/scripts/depfixer.py +++ b/mesonbuild/scripts/depfixer.py @@ -386,7 +386,7 @@ def get_darwin_rpaths(fname: str) -> OrderedSet[str]: # Need to deduplicate rpaths, as macOS's install_name_tool # is *very* allergic to duplicate -delete_rpath arguments # when calling depfixer on installation. - result = OrderedSet() + result: OrderedSet[str] = OrderedSet() current_cmd = 'FOOBAR' for line in out.split('\n'): line = line.strip() From 0c93149f09bbeedd03c70abc7b6d652b8e9ee9fa Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Tue, 23 Jul 2024 17:42:27 -0400 Subject: [PATCH 061/302] CI: skip LTO tests on cygwin A GCC update broke this and is being investigated Bug: #13465 --- unittests/allplatformstests.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/unittests/allplatformstests.py b/unittests/allplatformstests.py index 726252611fb7..40085983710a 100644 --- a/unittests/allplatformstests.py +++ b/unittests/allplatformstests.py @@ -1337,6 +1337,7 @@ def test_source_generator_program_cause_rebuild(self): self.utime(os.path.join(testdir, 'srcgen.py')) self.assertRebuiltTarget('basic') + @skipIf(is_ci() and is_cygwin(), 'A GCC update on 2024-07-21 has broken LTO and is being investigated') def test_static_library_lto(self): ''' Test that static libraries can be built with LTO and linked to @@ -1353,6 +1354,7 @@ def test_static_library_lto(self): self.build() self.run_tests() + @skipIf(is_ci() and is_cygwin(), 'A GCC update on 2024-07-21 has broken LTO and is being investigated') @skip_if_not_base_option('b_lto_threads') def test_lto_threads(self): testdir = os.path.join(self.common_test_dir, '6 linkshared') From 7bd00a38f90bb24400e8cbcc510f01c95d119949 Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Mon, 24 Jun 2024 16:43:31 -0400 Subject: [PATCH 062/302] CI: arch: fix failing to detect any glib ecosystem tools Due to reasons, Arch has chosen to split out the glib2 package into a glib2-devel package containing a small handful of python programs. The references to these programs are contained in the main glib2 package, so meson fails a lot in CI with e.g. ``` test cases/frameworks/7 gnome/gdbus/meson.build:1:18: ERROR: Dependency 'gio-2.0' tool variable 'gdbus_codegen' contains erroneous value: '/usr/bin/gdbus-codegen' This is a distributor issue -- please report it to your gio-2.0 provider. ``` --- ci/ciimage/arch/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/ciimage/arch/install.sh b/ci/ciimage/arch/install.sh index 76eb8cd37aeb..da55f1beee1f 100755 --- a/ci/ciimage/arch/install.sh +++ b/ci/ciimage/arch/install.sh @@ -11,7 +11,7 @@ pkgs=( ninja make git sudo fakeroot autoconf automake patch libelf gcc gcc-fortran gcc-objc vala rust bison flex cython go dlang-dmd mono boost qt5-base gtkmm3 gtest gmock protobuf gobject-introspection - itstool gtk3 java-environment=8 gtk-doc llvm clang sdl2 graphviz + itstool glib2-devel gtk3 java-environment=8 gtk-doc llvm clang sdl2 graphviz doxygen vulkan-validation-layers openssh mercurial gtk-sharp-2 qt5-tools libwmf cmake netcdf-fortran openmpi nasm gnustep-base gettext python-lxml hotdoc rust-bindgen qt6-base qt6-tools wayland wayland-protocols From 4205c1ea23b2dc881105ef158eb5cb441380f9ee Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Fri, 16 Feb 2024 00:14:18 -0500 Subject: [PATCH 063/302] CI: gentoo: avoid bloating up the image with cache data --- ci/ciimage/gentoo/install.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ci/ciimage/gentoo/install.sh b/ci/ciimage/gentoo/install.sh index 8f7aa33f5d17..5a8f680700a3 100755 --- a/ci/ciimage/gentoo/install.sh +++ b/ci/ciimage/gentoo/install.sh @@ -158,3 +158,11 @@ install_python_packages python3 -m pip install "${base_python_pkgs[@]}" echo "source /etc/profile" >> /ci/env_vars.sh + +# Cleanup to avoid including large contents in the docker image. +# We don't need cache files that are side artifacts of installing packages. +# We also don't need the gentoo tree -- the official docker image doesn't +# either, and expects you to use emerge-webrsync once you need it. +rm -rf /var/cache/binpkgs +rm -rf /var/cache/distfiles +rm -rf /var/db/repos/gentoo From f009ccb81bde95a414ca071aadfe24b44b39398b Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Wed, 24 Jul 2024 12:23:41 -0400 Subject: [PATCH 064/302] CI: arch: do not package up source files for stepping through code with gdb makepkg can do this, if when building packages from source you enable debug. This is apparently being shipped in the /etc/makepkg.conf in docker containers, which means building AUR packages now requires installing debugedit, and then bloating your container with /usr/src/debug. We really do not want that. Reconfigure so that we do not, in fact, need that. --- ci/ciimage/arch/install.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ci/ciimage/arch/install.sh b/ci/ciimage/arch/install.sh index da55f1beee1f..8f5245149688 100755 --- a/ci/ciimage/arch/install.sh +++ b/ci/ciimage/arch/install.sh @@ -41,6 +41,9 @@ useradd -m $AUR_USER echo "${AUR_USER}:" | chpasswd -e echo "$AUR_USER ALL = NOPASSWD: ALL" >> /etc/sudoers +# fix installing packages from source, attempting to install debug info +sed -i '/OPTIONS/{s|debug|!debug|}' /etc/makepkg.conf + # Install yay su $AUR_USER -c 'cd; git clone https://aur.archlinux.org/yay.git' su $AUR_USER -c 'cd; cd yay; makepkg' From 4842b8bcb37fe98f48b08e99210e04640380bffb Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Thu, 25 Jul 2024 09:02:01 -0700 Subject: [PATCH 065/302] backend/ninja: fix off-by-one in cmd length estimate This causes us to not count the spaces between arguments, thereby undercounting the number of elements. This is extra important because we previously double counted all actual characters, covering this issue up. Fixes: cf0fecfce ("backend/ninja: Fix bug in NinjaRule.length_estimate") --- mesonbuild/backend/ninjabackend.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index e1c6d0ca863b..552ddee1244e 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -292,7 +292,7 @@ def length_estimate(self, infiles: str, outfiles: str, estimate = len(command) for m in re.finditer(r'(\${\w+}|\$\w+)?[^$]*', command): if m.start(1) != -1: - estimate -= m.end(1) - m.start(1) + 1 + estimate -= m.end(1) - m.start(1) chunk = m.group(1) if chunk[1] == '{': chunk = chunk[2:-1] From a544c750b1d6d6d6cd3e617da6a060f3e5662a6a Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Thu, 25 Jul 2024 09:08:01 -0700 Subject: [PATCH 066/302] backend/ninja: use 32k byte limit for command lines on !Windows At an OS level, Unix-like OSes usually have very large or even unlimited sized command line limits. In practice, however, many applications do not handle this (intentionally or otherwise). Notably Wine has the same limits Windows does, 32,768 characters. Because we previously double counted most characters, we papered over most situations that we would need an RSP file on Unix-like OSes with Wine. To fix this issue I have set the command line limit to 32k, this is still a massive command line to pass without an RSP file, and will only cause the use of an RSP file where it is not strictly necessary in a small number of cases, but will fix Wine applications. Projects who wish to not use an RSP file can still set the MESON_RSP_THRESHOLD environment variable to a very large number instead. Fixes: #13414 Fixes: cf0fecfce ("backend/ninja: Fix bug in NinjaRule.length_estimate") --- mesonbuild/backend/ninjabackend.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 552ddee1244e..b67d8619f5ee 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -99,10 +99,11 @@ def get_rsp_threshold() -> int: # and that has a limit of 8k. limit = 8192 else: - # On Linux, ninja always passes the commandline as a single - # big string to /bin/sh, and the kernel limits the size of a - # single argument; see MAX_ARG_STRLEN - limit = 131072 + # Unix-like OSes usualy have very large command line limits, (On Linux, + # for example, this is limited by the kernel's MAX_ARG_STRLEN). However, + # some programs place much lower limits, notably Wine which enforces a + # 32k limit like Windows. Therefore, we limit the command line to 32k. + limit = 32768 # Be conservative limit = limit // 2 return int(os.environ.get('MESON_RSP_THRESHOLD', limit)) From 8a202de6ec763284cbb7160b9d43d5e7e0703f19 Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Thu, 25 Jul 2024 16:05:25 +0530 Subject: [PATCH 067/302] wrap: Use OSError instead of URLError for exception handling URLError is a subclass of OSError and intermittent server errors can manifest as OSError while reading instead of a URLError while establishing a connection, which will cause the fallback url to be ignored: ``` Looking for a fallback subproject for the dependency gudev-1.0 Downloading libgudev source from https://gitlab.gnome.org/GNOME/libgudev/-/archive/238/libgudev-238.tar.bz2 HTTP Error 404: Not Found WARNING: failed to download with error: could not get https://gitlab.gnome.org/GNOME/libgudev/-/archive/238/libgudev-238.tar.bz2 is the internet available?. Trying after a delay... HTTP Error 404: Not Found WARNING: failed to download with error: could not get https://gitlab.gnome.org/GNOME/libgudev/-/archive/238/libgudev-238.tar.bz2 is the internet available?. Trying after a delay... HTTP Error 404: Not Found WARNING: failed to download with error: could not get https://gitlab.gnome.org/GNOME/libgudev/-/archive/238/libgudev-238.tar.bz2 is the internet available?. Trying after a delay... WARNING: failed to download with error: The read operation timed out. Trying after a delay... WARNING: failed to download with error: The read operation timed out. Trying after a delay... ERROR: Unhandled python OSError. This is probably not a Meson bug, but an issue with your build environment. ``` --- mesonbuild/wrap/wrap.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mesonbuild/wrap/wrap.py b/mesonbuild/wrap/wrap.py index 4e98c600cf87..3fe40ed9f322 100644 --- a/mesonbuild/wrap/wrap.py +++ b/mesonbuild/wrap/wrap.py @@ -76,9 +76,9 @@ def open_wrapdburl(urlstring: str, allow_insecure: bool = False, have_opt: bool if has_ssl: try: return T.cast('http.client.HTTPResponse', urllib.request.urlopen(urllib.parse.urlunparse(url), timeout=REQ_TIMEOUT)) - except urllib.error.URLError as excp: + except OSError as excp: msg = f'WrapDB connection failed to {urlstring} with error {excp}.' - if isinstance(excp.reason, ssl.SSLCertVerificationError): + if isinstance(excp, urllib.error.URLError) and isinstance(excp.reason, ssl.SSLCertVerificationError): if allow_insecure: mlog.warning(f'{msg}\n\n Proceeding without authentication.') else: @@ -95,7 +95,7 @@ def open_wrapdburl(urlstring: str, allow_insecure: bool = False, have_opt: bool nossl_url = url._replace(scheme='http') try: return T.cast('http.client.HTTPResponse', urllib.request.urlopen(urllib.parse.urlunparse(nossl_url), timeout=REQ_TIMEOUT)) - except urllib.error.URLError as excp: + except OSError as excp: raise WrapException(f'WrapDB connection failed to {urlstring} with error {excp}') def get_releases_data(allow_insecure: bool) -> bytes: @@ -704,7 +704,7 @@ def get_data(self, urlstring: str) -> T.Tuple[str, str]: try: req = urllib.request.Request(urlstring, headers=headers) resp = urllib.request.urlopen(req, timeout=REQ_TIMEOUT) - except urllib.error.URLError as e: + except OSError as e: mlog.log(str(e)) raise WrapException(f'could not get {urlstring} is the internet available?') with contextlib.closing(resp) as resp, tmpfile as tmpfile: From 8d2a41cfdcb3edfa041e8cd26d8f84cfb684b747 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Wed, 24 Jul 2024 11:22:06 -0700 Subject: [PATCH 068/302] backends/ninja: Add annotation for NinjaBuildElement.rule This is a bit of a hack, since the rule is added outside of the `__init__` method, and that's probably bad. But at least we can get some additional help by telling type checkers what it will be --- mesonbuild/backend/ninjabackend.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index b67d8619f5ee..20ba67fff0ff 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -306,6 +306,9 @@ def length_estimate(self, infiles: str, outfiles: str, return estimate class NinjaBuildElement: + + rule: NinjaRule + def __init__(self, all_outputs: T.Set[str], outfilenames, rulename, infilenames, implicit_outs=None): self.implicit_outfilenames = implicit_outs or [] if isinstance(outfilenames, str): From 065288eac5384704c4f745b726dd277da2855418 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Wed, 24 Jul 2024 11:23:38 -0700 Subject: [PATCH 069/302] backends/ninja: fix annotation of NinjaBuildElement.add_item The `elems` annotation was invalid --- mesonbuild/backend/ninjabackend.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 20ba67fff0ff..fb9a04efb0f8 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -339,7 +339,7 @@ def add_orderdep(self, dep): else: self.orderdeps.add(dep) - def add_item(self, name: str, elems: T.Union[str, T.List[str, CompilerArgs]]) -> None: + def add_item(self, name: str, elems: T.Union[str, T.List[str], CompilerArgs]) -> None: # Always convert from GCC-style argument naming to the naming used by the # current compiler. Also filter system include paths, deduplicate, etc. if isinstance(elems, CompilerArgs): From 9d6191cfb425235df8a9167651563ef0ee481ac9 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Wed, 24 Jul 2024 11:58:09 -0700 Subject: [PATCH 070/302] backends/base: fix annotation for as_meson_exe_cmdline It returns (list[str], str) --- mesonbuild/backend/backends.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index 8c4003b731e3..9b26d9e6caf5 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -597,7 +597,7 @@ def as_meson_exe_cmdline(self, exe: T.Union[str, mesonlib.File, build.BuildTarge feed: T.Optional[str] = None, force_serialize: bool = False, env: T.Optional[mesonlib.EnvironmentVariables] = None, - verbose: bool = False) -> T.Tuple[T.Sequence[T.Union[str, File, build.Target, programs.ExternalProgram]], str]: + verbose: bool = False) -> T.Tuple[T.List[str], str]: ''' Serialize an executable for running with a generator or a custom target ''' From dcefe67b89afba67323e626e45d1208776a9fc3e Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Wed, 24 Jul 2024 11:58:58 -0700 Subject: [PATCH 071/302] backends/ninja: Add annotation for generate_coverage_commands --- mesonbuild/backend/ninjabackend.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index fb9a04efb0f8..65f6ea1958af 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -1245,7 +1245,7 @@ def generate_run_target(self, target: build.RunTarget): self.add_build(elem) self.processed_targets.add(target.get_id()) - def generate_coverage_command(self, elem, outputs: T.List[str], gcovr_exe: T.Optional[str], llvm_cov_exe: T.Optional[str]): + def generate_coverage_command(self, elem: NinjaBuildElement, outputs: T.List[str], gcovr_exe: T.Optional[str], llvm_cov_exe: T.Optional[str]): targets = self.build.get_targets().values() use_llvm_cov = False exe_args = [] From 6258f0dc86188570e7d00316557bfb85948ed290 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jannik=20Gl=C3=BCckert?= Date: Mon, 22 Jul 2024 00:17:32 +0200 Subject: [PATCH 072/302] coverage: improve llvm-cov detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jannik Glückert --- mesonbuild/environment.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index d316f4f6634b..c26516215b6b 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -149,6 +149,9 @@ def find_coverage_tools(coredata: coredata.CoreData) -> T.Tuple[T.Optional[str], gcovr_exe, gcovr_version = detect_gcovr() llvm_cov_exe = detect_llvm_cov(compute_llvm_suffix(coredata)) + # Some platforms may provide versioned clang but only non-versioned llvm utils + if llvm_cov_exe is None: + llvm_cov_exe = detect_llvm_cov('') lcov_exe, lcov_version, genhtml_exe = detect_lcov_genhtml() From 541fee0c3c495ff20cd771c12a71370d1062296b Mon Sep 17 00:00:00 2001 From: Mateusz Patyk Date: Mon, 15 Jul 2024 20:17:41 +0200 Subject: [PATCH 073/302] mtest: remove superfluous '\r' from read_decode() On Windows, the output read from the stream has '\r\n', which in .txt, .json and console logger (when captured to a file) translates to '\n\n'. This results in every log line being separated by an empty line. --- mesonbuild/mtest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/mtest.py b/mesonbuild/mtest.py index a2a6067fa116..9975afa22a9b 100644 --- a/mesonbuild/mtest.py +++ b/mesonbuild/mtest.py @@ -1194,7 +1194,7 @@ async def read_decode(reader: asyncio.StreamReader, except asyncio.LimitOverrunError as e: line_bytes = await reader.readexactly(e.consumed) if line_bytes: - line = decode(line_bytes) + line = decode(line_bytes).replace('\r\n', '\n') stdo_lines.append(line) if console_mode is ConsoleUser.STDOUT: print(line, end='', flush=True) From 1e26a884814b4d3a0bd09780443972b215724959 Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Fri, 14 Jun 2024 23:59:41 +1100 Subject: [PATCH 074/302] add initial support for llvm-flang --- docs/markdown/Contributing.md | 4 +- docs/markdown/Reference-tables.md | 3 +- docs/markdown/snippets/llvm_flang.md | 9 +++++ mesonbuild/compilers/detect.py | 28 ++++++++++++-- mesonbuild/compilers/fortran.py | 56 +++++++++++++++++++++++++++- run_project_tests.py | 1 + 6 files changed, 92 insertions(+), 9 deletions(-) create mode 100644 docs/markdown/snippets/llvm_flang.md diff --git a/docs/markdown/Contributing.md b/docs/markdown/Contributing.md index 731abc87d89a..8f796ab65530 100644 --- a/docs/markdown/Contributing.md +++ b/docs/markdown/Contributing.md @@ -150,8 +150,8 @@ Subsets of project tests can be selected with time when only a certain part of Meson is being tested. For example, a useful and easy contribution to Meson is making sure the full set of compilers is supported. One could for example test -various Fortran compilers by setting `FC=ifort` or `FC=flang` or similar -with `./run_project_test.py --only fortran`. +various Fortran compilers by setting `FC=ifort`, `FC=flang` or +`FC=flang-new` or similar with `./run_project_test.py --only fortran`. Some families of tests require a particular backend to run. For example, all the CUDA project tests run and pass on Windows via `./run_project_tests.py --only cuda --backend ninja` diff --git a/docs/markdown/Reference-tables.md b/docs/markdown/Reference-tables.md index 2357ff459af4..67eccb4a2465 100644 --- a/docs/markdown/Reference-tables.md +++ b/docs/markdown/Reference-tables.md @@ -15,7 +15,7 @@ These are return values of the `get_id` (Compiler family) and | clang-cl | The Clang compiler (MSVC compatible driver) | msvc | | dmd | D lang reference compiler | | | emscripten| Emscripten WASM compiler | | -| flang | Flang Fortran compiler | | +| flang | Classic Flang Fortran compiler | | | g95 | The G95 Fortran compiler | | | gcc | The GNU Compiler Collection | gcc | | intel | Intel compiler (Linux and Mac) | gcc | @@ -24,6 +24,7 @@ These are return values of the `get_id` (Compiler family) and | intel-llvm-cl | Intel oneAPI LLVM-based compiler (Windows) | msvc | | lcc | Elbrus C/C++/Fortran Compiler | | | llvm | LLVM-based compiler (Swift, D) | | +| llvm-flang| Flang Fortran compiler (LLVM-based) | | | mono | Xamarin C# compiler | | | mwccarm | Metrowerks C/C++ compiler for Embedded ARM | | | mwcceppc | Metrowerks C/C++ compiler for Embedded PowerPC | | diff --git a/docs/markdown/snippets/llvm_flang.md b/docs/markdown/snippets/llvm_flang.md new file mode 100644 index 000000000000..4575fe054ca9 --- /dev/null +++ b/docs/markdown/snippets/llvm_flang.md @@ -0,0 +1,9 @@ +## Support for LLVM-based flang compiler + +Added basic handling for the [flang](https://flang.llvm.org/docs/) compiler +that's now part of LLVM. It is the successor of another compiler named +[flang](https://github.com/flang-compiler/flang) by largely the same +group of developers, who now refer to the latter as "classic flang". + +Meson already supports classic flang, and the LLVM-based flang now +uses the compiler-id `'llvm-flang'`. diff --git a/mesonbuild/compilers/detect.py b/mesonbuild/compilers/detect.py index 3a678211c5a1..c796c2f38aac 100644 --- a/mesonbuild/compilers/detect.py +++ b/mesonbuild/compilers/detect.py @@ -45,7 +45,8 @@ defaults['c'] = ['icl', 'cl', 'cc', 'gcc', 'clang', 'clang-cl', 'pgcc'] # There is currently no pgc++ for Windows, only for Mac and Linux. defaults['cpp'] = ['icl', 'cl', 'c++', 'g++', 'clang++', 'clang-cl'] - defaults['fortran'] = ['ifort', 'gfortran', 'flang', 'pgfortran', 'g95'] + # the binary flang-new will be renamed to flang in the foreseeable future + defaults['fortran'] = ['ifort', 'gfortran', 'flang-new', 'flang', 'pgfortran', 'g95'] defaults['objc'] = ['clang-cl', 'gcc'] defaults['objcpp'] = ['clang-cl', 'g++'] defaults['cs'] = ['csc', 'mcs'] @@ -60,7 +61,8 @@ defaults['cpp'] = ['c++', 'g++', 'clang++', 'nvc++', 'pgc++', 'icpc', 'icpx'] defaults['objc'] = ['clang', 'gcc'] defaults['objcpp'] = ['clang++', 'g++'] - defaults['fortran'] = ['gfortran', 'flang', 'nvfortran', 'pgfortran', 'ifort', 'ifx', 'g95'] + # the binary flang-new will be renamed to flang in the foreseeable future + defaults['fortran'] = ['gfortran', 'flang-new', 'flang', 'nvfortran', 'pgfortran', 'ifort', 'ifx', 'g95'] defaults['cs'] = ['mcs', 'csc'] defaults['d'] = ['ldc2', 'ldc', 'gdc', 'dmd'] defaults['java'] = ['javac'] @@ -659,6 +661,13 @@ def detect_fortran_compiler(env: 'Environment', for_machine: MachineChoice) -> C info = env.machines[for_machine] cls: T.Type[FortranCompiler] for compiler in compilers: + # capture help text for possible fallback + try: + _, help_out, _ = Popen_safe_logged(compiler + ['--help'], msg='Detecting compiler via') + except OSError as e: + popen_exceptions[join_args(compiler + ['--help'])] = e + help_out = '' + for arg in ['--version', '-V']: try: p, out, err = Popen_safe_logged(compiler + [arg], msg='Detecting compiler via') @@ -776,8 +785,7 @@ def detect_fortran_compiler(env: 'Environment', for_machine: MachineChoice) -> C compiler, version, for_machine, is_cross, info, full_version=full_version, linker=linker) - if 'flang' in out or 'clang' in out: - cls = fortran.FlangFortranCompiler + def _get_linker_try_windows(cls: T.Type['Compiler']) -> T.Optional['DynamicLinker']: linker = None if 'windows' in out or env.machines[for_machine].is_windows(): # If we're in a MINGW context this actually will use a gnu @@ -793,6 +801,18 @@ def detect_fortran_compiler(env: 'Environment', for_machine: MachineChoice) -> C if linker is None: linker = guess_nix_linker(env, compiler, cls, version, for_machine) + return linker + + if 'flang-new' in out or 'flang LLVM compiler' in help_out: + cls = fortran.LlvmFlangFortranCompiler + linker = _get_linker_try_windows(cls) + return cls( + compiler, version, for_machine, is_cross, info, + full_version=full_version, linker=linker) + + if 'flang' in out or 'clang' in out: + cls = fortran.ClassicFlangFortranCompiler + linker = _get_linker_try_windows(cls) return cls( compiler, version, for_machine, is_cross, info, full_version=full_version, linker=linker) diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py index a6e3f0b219d2..a99a95ce37ba 100644 --- a/mesonbuild/compilers/fortran.py +++ b/mesonbuild/compilers/fortran.py @@ -430,7 +430,7 @@ def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoic 'everything': default_warn_args + ['-Mdclchk']} -class FlangFortranCompiler(ClangCompiler, FortranCompiler): +class ClassicFlangFortranCompiler(ClangCompiler, FortranCompiler): id = 'flang' @@ -460,10 +460,62 @@ def language_stdlib_only_link_flags(self, env: 'Environment') -> T.List[str]: search_dirs.append(f'-L{d}') return search_dirs + ['-lflang', '-lpgmath'] -class ArmLtdFlangFortranCompiler(FlangFortranCompiler): + +class ArmLtdFlangFortranCompiler(ClassicFlangFortranCompiler): id = 'armltdflang' + +class LlvmFlangFortranCompiler(ClangCompiler, FortranCompiler): + + id = 'llvm-flang' + + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: 'MachineInfo', linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): + FortranCompiler.__init__(self, exelist, version, for_machine, + is_cross, info, linker=linker, + full_version=full_version) + ClangCompiler.__init__(self, {}) + default_warn_args = ['-Wall'] + self.warn_args = {'0': [], + '1': default_warn_args, + '2': default_warn_args, + '3': default_warn_args, + 'everything': default_warn_args} + + def get_colorout_args(self, colortype: str) -> T.List[str]: + # not yet supported, see https://github.com/llvm/llvm-project/issues/89888 + return [] + + def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: + # not yet supported, see https://github.com/llvm/llvm-project/issues/89888 + return [] + + def get_module_outdir_args(self, path: str) -> T.List[str]: + # different syntax from classic flang (which supported `-module`), see + # https://github.com/llvm/llvm-project/issues/66969 + return ['-module-dir', path] + + def gnu_symbol_visibility_args(self, vistype: str) -> T.List[str]: + # flang doesn't support symbol visibility flag yet, see + # https://github.com/llvm/llvm-project/issues/92459 + return [] + + def language_stdlib_only_link_flags(self, env: 'Environment') -> T.List[str]: + # matching setup from ClassicFlangFortranCompiler + search_dirs: T.List[str] = [] + for d in self.get_compiler_dirs(env, 'libraries'): + search_dirs.append(f'-L{d}') + # does not automatically link to Fortran_main anymore after + # https://github.com/llvm/llvm-project/commit/9d6837d595719904720e5ff68ec1f1a2665bdc2f + # note that this changed again in flang 19 with + # https://github.com/llvm/llvm-project/commit/8d5386669ed63548daf1bee415596582d6d78d7d; + # it seems flang 18 doesn't work if something accidentally includes a program unit, see + # https://github.com/llvm/llvm-project/issues/92496 + return search_dirs + ['-lFortranRuntime', '-lFortranDecimal'] + + class Open64FortranCompiler(FortranCompiler): id = 'open64' diff --git a/run_project_tests.py b/run_project_tests.py index 7551c8da96c5..fe1f46f7eefa 100755 --- a/run_project_tests.py +++ b/run_project_tests.py @@ -1086,6 +1086,7 @@ def detect_tests_to_run(only: T.Dict[str, T.List[str]], use_tmp: bool) -> T.List """ skip_fortran = not(shutil.which('gfortran') or + shutil.which('flang-new') or shutil.which('flang') or shutil.which('pgfortran') or shutil.which('nagfor') or From cc0332288aaf653cfb780591ba52502e556f43ab Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Fri, 26 Jul 2024 06:24:09 +0530 Subject: [PATCH 075/302] ci: Update to checkout@v4 to squelch node warnings Keep using v3 for Bionic because of https://github.com/mesonbuild/meson/pull/13424 --- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/cygwin.yml | 2 +- .github/workflows/file_format.yml | 2 +- .github/workflows/images.yml | 1 + .github/workflows/lint.yml | 6 +++--- .github/workflows/macos.yml | 6 +++--- .github/workflows/msys2.yml | 2 +- .github/workflows/nonnative.yml | 2 +- .github/workflows/os_comp.yml | 5 +++-- .github/workflows/stable_builddir.yml | 2 +- .github/workflows/unusedargs_missingreturn.yml | 4 ++-- .github/workflows/website.yml | 2 +- 12 files changed, 19 insertions(+), 17 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 455a9d418c2b..49a159cfd620 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -17,7 +17,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Initialize CodeQL uses: github/codeql-action/init@v2 diff --git a/.github/workflows/cygwin.yml b/.github/workflows/cygwin.yml index c6f3dc416687..a5a664648cf4 100644 --- a/.github/workflows/cygwin.yml +++ b/.github/workflows/cygwin.yml @@ -49,7 +49,7 @@ jobs: - run: git config --global core.autocrlf input - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: cygwin/cygwin-install-action@master with: diff --git a/.github/workflows/file_format.yml b/.github/workflows/file_format.yml index 429fc91107ad..aa421100c71d 100644 --- a/.github/workflows/file_format.yml +++ b/.github/workflows/file_format.yml @@ -13,7 +13,7 @@ jobs: format: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: python-version: '3.x' diff --git a/.github/workflows/images.yml b/.github/workflows/images.yml index dd91898efc24..d20f7e5ced02 100644 --- a/.github/workflows/images.yml +++ b/.github/workflows/images.yml @@ -45,6 +45,7 @@ jobs: - { name: Ubuntu Bionic, id: bionic } - { name: Ubuntu Rolling, id: ubuntu-rolling } steps: + # Need v3 because of bionic - uses: actions/checkout@v3 # Login to dockerhub diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index e8cd37341762..8e4c4ced8693 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -22,7 +22,7 @@ jobs: pylint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: python-version: '3.x' @@ -32,7 +32,7 @@ jobs: flake8: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: python-version: '3.x' @@ -42,7 +42,7 @@ jobs: mypy: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: python-version: '3.x' diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 3b726315537a..0217ac99f45c 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -31,7 +31,7 @@ jobs: unittests-appleclang: runs-on: macos-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: python-version: '3.x' @@ -81,7 +81,7 @@ jobs: HOMEBREW_NO_AUTO_UPDATE: 1 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # Avoid picking up an older version of LLVM that does not work. - run: brew update # github actions overwrites brew's python. Force it to reassert itself, by running in a separate step. @@ -132,7 +132,7 @@ jobs: env: HOMEBREW_NO_AUTO_UPDATE: 1 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: python-version: '3.x' diff --git a/.github/workflows/msys2.yml b/.github/workflows/msys2.yml index 278954c393d6..6d44989ab1a1 100644 --- a/.github/workflows/msys2.yml +++ b/.github/workflows/msys2.yml @@ -61,7 +61,7 @@ jobs: shell: msys2 {0} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: msys2/setup-msys2@v2 with: diff --git a/.github/workflows/nonnative.yml b/.github/workflows/nonnative.yml index 1ad9e35bb0e0..2712d1032935 100644 --- a/.github/workflows/nonnative.yml +++ b/.github/workflows/nonnative.yml @@ -37,7 +37,7 @@ jobs: apt-get -y purge clang gcc gdc apt-get -y autoremove python3 -m pip install coverage - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Run tests run: bash -c 'source /ci/env_vars.sh; cd $GITHUB_WORKSPACE; ./tools/run_with_cov.py ./run_tests.py $CI_ARGS --cross ubuntu-armhf.json --cross-only' diff --git a/.github/workflows/os_comp.yml b/.github/workflows/os_comp.yml index 4fa4a87ed15d..05e4f072deb6 100644 --- a/.github/workflows/os_comp.yml +++ b/.github/workflows/os_comp.yml @@ -54,6 +54,7 @@ jobs: MESON_CI_JOBNAME: linux-${{ matrix.cfg.id }}-gcc steps: + # Need v3 because of bionic - uses: actions/checkout@v3 - name: Run tests # All environment variables are stored inside the docker image in /ci/env_vars.sh @@ -80,7 +81,7 @@ jobs: MESON_CI_JOBNAME_UPDATE: linux-arch-gcc-pypy steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Run tests run: | source /ci/env_vars.sh @@ -134,7 +135,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Run tests shell: bash diff --git a/.github/workflows/stable_builddir.yml b/.github/workflows/stable_builddir.yml index 5da321d18bce..ae2951801cef 100644 --- a/.github/workflows/stable_builddir.yml +++ b/.github/workflows/stable_builddir.yml @@ -14,7 +14,7 @@ jobs: env: TESTDIR: "manual tests/13 builddir upgrade" steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: install ninja run: sudo apt-get -y install build-essential ninja-build - name: Fetch tags and unshallow diff --git a/.github/workflows/unusedargs_missingreturn.yml b/.github/workflows/unusedargs_missingreturn.yml index d823c310e7c2..6c16fa33a1fe 100644 --- a/.github/workflows/unusedargs_missingreturn.yml +++ b/.github/workflows/unusedargs_missingreturn.yml @@ -44,7 +44,7 @@ jobs: linux: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: python-version: '3.x' @@ -71,7 +71,7 @@ jobs: windows: runs-on: windows-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: python-version: '3.x' diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml index 2c76d87846b8..206734e85a96 100644 --- a/.github/workflows/website.yml +++ b/.github/workflows/website.yml @@ -32,7 +32,7 @@ jobs: HAS_SSH_KEY: ${{ secrets.WEBSITE_PRIV_KEY != '' }} runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/cache/restore@v3 id: restore-cache From b7e94d2ea00025a5e444ac9589043a4cfacd81b3 Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Fri, 26 Jul 2024 06:29:36 +0530 Subject: [PATCH 076/302] ci: Update codeql-analysis action to fix deprecations --- .github/workflows/codeql-analysis.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 49a159cfd620..6a78a36c62a2 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -20,14 +20,13 @@ jobs: uses: actions/checkout@v4 - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: # bypass cache: https://github.com/github/codeql-action/issues/1445 - tools: latest + tools: linked config-file: .github/codeql/codeql-config.yml languages: python # we have none - setup-python-dependencies: false - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 From d077c2f5f61eebaabf98b0be7dea0d83502d8c13 Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Fri, 26 Jul 2024 07:59:49 +0530 Subject: [PATCH 077/302] ci: update actions/cache to v4 to fix deprecations --- .github/workflows/cygwin.yml | 4 ++-- .github/workflows/website.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/cygwin.yml b/.github/workflows/cygwin.yml index a5a664648cf4..2498f7b570eb 100644 --- a/.github/workflows/cygwin.yml +++ b/.github/workflows/cygwin.yml @@ -39,7 +39,7 @@ jobs: MESON_CI_JOBNAME: cygwin-${{ matrix.NAME }} steps: - - uses: actions/cache/restore@v3 + - uses: actions/cache/restore@v4 id: restore-cache with: # should use 'pip3 cache dir' to discover this path @@ -83,7 +83,7 @@ jobs: python3 -m pip --disable-pip-version-check install gcovr fastjsonschema pefile pytest pytest-subtests pytest-xdist coverage shell: C:\cygwin\bin\bash.exe --noprofile --norc -o igncr -eo pipefail '{0}' - - uses: actions/cache/save@v3 + - uses: actions/cache/save@v4 with: # should use 'pip3 cache dir' to discover this path path: C:\cygwin\home\runneradmin\.cache\pip diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml index 206734e85a96..fdb7d1400919 100644 --- a/.github/workflows/website.yml +++ b/.github/workflows/website.yml @@ -34,7 +34,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: actions/cache/restore@v3 + - uses: actions/cache/restore@v4 id: restore-cache with: # should use 'pip3 cache dir' to discover this path @@ -47,7 +47,7 @@ jobs: sudo apt-get -y install python3-pip ninja-build libjson-glib-dev pip install hotdoc chevron strictyaml - - uses: actions/cache/save@v3 + - uses: actions/cache/save@v4 with: # should use 'pip3 cache dir' to discover this path path: ~/.cache/pip From fb108e69b1418aa4598502d4e7f5efcb8af80564 Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Fri, 26 Jul 2024 08:00:01 +0530 Subject: [PATCH 078/302] ci: Update actions/setup-python to v5 to fix deprecations --- .github/workflows/file_format.yml | 2 +- .github/workflows/lint.yml | 6 +++--- .github/workflows/macos.yml | 4 ++-- .github/workflows/unusedargs_missingreturn.yml | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/file_format.yml b/.github/workflows/file_format.yml index aa421100c71d..d61d634c0315 100644 --- a/.github/workflows/file_format.yml +++ b/.github/workflows/file_format.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: '3.x' - run: python3 ./run_format_tests.py diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 8e4c4ced8693..5c6d56de30e9 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: '3.x' - run: python -m pip install pylint @@ -33,7 +33,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: '3.x' - run: python -m pip install flake8 @@ -43,7 +43,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: '3.x' # Pin mypy to version 1.8, so we retain the ability to lint for Python 3.7 diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 0217ac99f45c..e7d1a7872920 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -32,7 +32,7 @@ jobs: runs-on: macos-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: '3.x' - run: | @@ -133,7 +133,7 @@ jobs: HOMEBREW_NO_AUTO_UPDATE: 1 steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: '3.x' - run: python -m pip install -e . diff --git a/.github/workflows/unusedargs_missingreturn.yml b/.github/workflows/unusedargs_missingreturn.yml index 6c16fa33a1fe..72f39b511f45 100644 --- a/.github/workflows/unusedargs_missingreturn.yml +++ b/.github/workflows/unusedargs_missingreturn.yml @@ -45,7 +45,7 @@ jobs: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: '3.x' - name: Install Compilers @@ -72,7 +72,7 @@ jobs: runs-on: windows-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: '3.x' From 2daf5f7c9d825e9c130be9bf4c6234edf30859d9 Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Fri, 26 Jul 2024 08:02:47 +0530 Subject: [PATCH 079/302] ci: Update actions/upload-artifact to v4 to fix deprecations --- .github/workflows/cygwin.yml | 2 +- .github/workflows/macos.yml | 4 ++-- .github/workflows/msys2.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/cygwin.yml b/.github/workflows/cygwin.yml index 2498f7b570eb..d4c0ba53b20f 100644 --- a/.github/workflows/cygwin.yml +++ b/.github/workflows/cygwin.yml @@ -99,7 +99,7 @@ jobs: SKIP_STATIC_BOOST: 1 shell: C:\cygwin\bin\bash.exe --noprofile --norc -o igncr -eo pipefail '{0}' - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: ${{ matrix.NAME }} path: meson-test-run.* diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index e7d1a7872920..88acbef90206 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -145,13 +145,13 @@ jobs: - run: ln -sfn /usr/local/Cellar/qt@4/4.8.7_6.reinstall /usr/local/Cellar/qt@4/4.8.7_6 - run: meson setup "test cases/frameworks/4 qt" build -Drequired=qt4 - run: meson compile -C build - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 if: failure() with: name: Qt4_Mac_build path: build/meson-logs/meson-log.txt - run: meson test -C build -v - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 if: failure() with: name: Qt4_Mac_test diff --git a/.github/workflows/msys2.yml b/.github/workflows/msys2.yml index 6d44989ab1a1..3b518fee7607 100644 --- a/.github/workflows/msys2.yml +++ b/.github/workflows/msys2.yml @@ -127,7 +127,7 @@ jobs: MSYSTEM= python3 ./tools/run_with_cov.py run_tests.py --backend=ninja - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: ${{ matrix.NAME }} path: meson-test-run.* From 433c13c5c4e72e5d04d6955b790c548bf7e2ad24 Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Mon, 29 Jul 2024 01:51:20 -0400 Subject: [PATCH 080/302] various low-hanging typing fruit ninjabackend.py goes down from 322 type errors to 253, mainly by marking functions as returning None. --- mesonbuild/backend/ninjabackend.py | 112 +++++++++++++++-------------- 1 file changed, 57 insertions(+), 55 deletions(-) diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 65f6ea1958af..b43b8bbe43c0 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -45,6 +45,7 @@ from ..linkers.linkers import DynamicLinker, StaticLinker from ..compilers.cs import CsCompiler from ..compilers.fortran import FortranCompiler + from ..mesonlib import FileOrString CommandArgOrStr = T.List[T.Union['NinjaCommandArg', str]] RUST_EDITIONS = Literal['2015', '2018', '2021'] @@ -333,7 +334,7 @@ def add_dep(self, dep: T.Union[str, T.List[str]]) -> None: else: self.deps.add(dep) - def add_orderdep(self, dep): + def add_orderdep(self, dep) -> None: if isinstance(dep, list): self.orderdeps.update(dep) else: @@ -351,7 +352,7 @@ def add_item(self, name: str, elems: T.Union[str, T.List[str], CompilerArgs]) -> if name == 'DEPFILE': self.elems.append((name + '_UNQUOTED', elems)) - def _should_use_rspfile(self): + def _should_use_rspfile(self) -> bool: # 'phony' is a rule built-in to ninja if self.rulename == 'phony': return False @@ -366,14 +367,14 @@ def _should_use_rspfile(self): outfilenames, self.elems) >= rsp_threshold - def count_rule_references(self): + def count_rule_references(self) -> None: if self.rulename != 'phony': if self._should_use_rspfile(): self.rule.rsprefcount += 1 else: self.rule.refcount += 1 - def write(self, outfile): + def write(self, outfile: T.TextIO) -> None: if self.output_errors: raise MesonException(self.output_errors) ins = ' '.join([ninja_quote(i, True) for i in self.infilenames]) @@ -432,7 +433,7 @@ def write(self, outfile): outfile.write(line) outfile.write('\n') - def check_outputs(self): + def check_outputs(self) -> None: for n in self.outfilenames: if n in self.all_outputs: self.output_errors = f'Multiple producers for Ninja target "{n}". Please rename your targets.' @@ -713,7 +714,7 @@ def generate_rust_project_json(self) -> None: f, indent=4) # http://clang.llvm.org/docs/JSONCompilationDatabase.html - def generate_compdb(self): + def generate_compdb(self) -> None: rules = [] # TODO: Rather than an explicit list here, rules could be marked in the # rule store as being wanted in compdb @@ -735,10 +736,10 @@ def generate_compdb(self): # Get all generated headers. Any source file might need them so # we need to add an order dependency to them. - def get_generated_headers(self, target): + def get_generated_headers(self, target: build.BuildTarget) -> T.List[FileOrString]: if hasattr(target, 'cached_generated_headers'): return target.cached_generated_headers - header_deps = [] + header_deps: T.List[FileOrString] = [] # XXX: Why don't we add deps to CustomTarget headers here? for genlist in target.get_generated_sources(): if isinstance(genlist, (build.CustomTarget, build.CustomTargetIndex)): @@ -798,7 +799,7 @@ def get_target_source_can_unity(self, target, source): return True def create_target_source_introspection(self, target: build.Target, comp: compilers.Compiler, parameters, sources, generated_sources, - unity_sources: T.Optional[T.List[mesonlib.FileOrString]] = None): + unity_sources: T.Optional[T.List[FileOrString]] = None) -> None: ''' Adds the source file introspection information for a language of a target @@ -837,7 +838,7 @@ def create_target_source_introspection(self, target: build.Target, comp: compile } tgt[id_hash] = src_block - def compute_path(file: mesonlib.FileOrString) -> str: + def compute_path(file: FileOrString) -> str: """ Make source files absolute """ if isinstance(file, File): return file.absolute_path(self.source_dir, self.build_dir) @@ -848,7 +849,7 @@ def compute_path(file: mesonlib.FileOrString) -> str: if unity_sources: src_block['unity_sources'].extend(compute_path(x) for x in unity_sources) - def create_target_linker_introspection(self, target: build.Target, linker: T.Union[Compiler, StaticLinker], parameters): + def create_target_linker_introspection(self, target: build.Target, linker: T.Union[Compiler, StaticLinker], parameters) -> None: tid = target.get_id() tgt = self.introspection_data[tid] lnk_hash = tuple(parameters) @@ -868,7 +869,7 @@ def create_target_linker_introspection(self, target: build.Target, linker: T.Uni } tgt[lnk_hash] = lnk_block - def generate_target(self, target): + def generate_target(self, target) -> None: if isinstance(target, build.BuildTarget): os.makedirs(self.get_target_private_dir_abs(target), exist_ok=True) if isinstance(target, build.CustomTarget): @@ -1108,7 +1109,7 @@ def generate_dependency_scan_target(self, target: build.BuildTarget, compiled_sources: T.List[str], source2object: T.Dict[str, str], generated_source_files: T.List[mesonlib.File], - object_deps: T.List['mesonlib.FileOrString']) -> None: + object_deps: T.List[FileOrString]) -> None: if not self.should_use_dyndeps_for_target(target): return self._uses_dyndeps = True @@ -1152,12 +1153,12 @@ def select_sources_to_scan(self, compiled_sources: T.List[str] elif ext.lower() in compilers.lang_suffixes['fortran']: yield source, 'fortran' - def process_target_dependencies(self, target): + def process_target_dependencies(self, target) -> None: for t in target.get_dependencies(): if t.get_id() not in self.processed_targets: self.generate_target(t) - def custom_target_generator_inputs(self, target): + def custom_target_generator_inputs(self, target) -> None: for s in target.sources: if isinstance(s, build.GeneratedList): self.generate_genlist_for_target(s, target) @@ -1173,7 +1174,7 @@ def unwrap_dep_list(self, target): deps.append(os.path.join(self.get_target_dir(i), output)) return deps - def generate_custom_target(self, target: build.CustomTarget): + def generate_custom_target(self, target: build.CustomTarget) -> None: self.custom_target_generator_inputs(target) (srcs, ofilenames, cmd) = self.eval_custom_target_command(target) deps = self.unwrap_dep_list(target) @@ -1215,14 +1216,14 @@ def generate_custom_target(self, target: build.CustomTarget): self.add_build(elem) self.processed_targets.add(target.get_id()) - def build_run_target_name(self, target): + def build_run_target_name(self, target) -> str: if target.subproject != '': subproject_prefix = f'{target.subproject}@@' else: subproject_prefix = '' return f'{subproject_prefix}{target.name}' - def generate_run_target(self, target: build.RunTarget): + def generate_run_target(self, target: build.RunTarget) -> None: target_name = self.build_run_target_name(target) if not target.command: # This is an alias target, it has no command, it just depends on @@ -1245,7 +1246,8 @@ def generate_run_target(self, target: build.RunTarget): self.add_build(elem) self.processed_targets.add(target.get_id()) - def generate_coverage_command(self, elem: NinjaBuildElement, outputs: T.List[str], gcovr_exe: T.Optional[str], llvm_cov_exe: T.Optional[str]): + def generate_coverage_command(self, elem: NinjaBuildElement, outputs: T.List[str], + gcovr_exe: T.Optional[str], llvm_cov_exe: T.Optional[str]) -> None: targets = self.build.get_targets().values() use_llvm_cov = False exe_args = [] @@ -1272,14 +1274,14 @@ def generate_coverage_command(self, elem: NinjaBuildElement, outputs: T.List[str exe_args + (['--use-llvm-cov'] if use_llvm_cov else [])) - def generate_coverage_rules(self, gcovr_exe: T.Optional[str], gcovr_version: T.Optional[str], llvm_cov_exe: T.Optional[str]): + def generate_coverage_rules(self, gcovr_exe: T.Optional[str], gcovr_version: T.Optional[str], llvm_cov_exe: T.Optional[str]) -> None: e = self.create_phony_target('coverage', 'CUSTOM_COMMAND', 'PHONY') self.generate_coverage_command(e, [], gcovr_exe, llvm_cov_exe) e.add_item('description', 'Generates coverage reports') self.add_build(e) self.generate_coverage_legacy_rules(gcovr_exe, gcovr_version, llvm_cov_exe) - def generate_coverage_legacy_rules(self, gcovr_exe: T.Optional[str], gcovr_version: T.Optional[str], llvm_cov_exe: T.Optional[str]): + def generate_coverage_legacy_rules(self, gcovr_exe: T.Optional[str], gcovr_version: T.Optional[str], llvm_cov_exe: T.Optional[str]) -> None: e = self.create_phony_target('coverage-html', 'CUSTOM_COMMAND', 'PHONY') self.generate_coverage_command(e, ['--html'], gcovr_exe, llvm_cov_exe) e.add_item('description', 'Generates HTML coverage report') @@ -1302,7 +1304,7 @@ def generate_coverage_legacy_rules(self, gcovr_exe: T.Optional[str], gcovr_versi e.add_item('description', 'Generates Sonarqube XML coverage report') self.add_build(e) - def generate_install(self): + def generate_install(self) -> None: self.create_install_data_files() elem = self.create_phony_target('install', 'CUSTOM_COMMAND', 'PHONY') elem.add_dep('all') @@ -1311,7 +1313,7 @@ def generate_install(self): elem.add_item('pool', 'console') self.add_build(elem) - def generate_tests(self): + def generate_tests(self) -> None: self.serialize_tests() cmd = self.environment.get_build_command(True) + ['test', '--no-rebuild'] if not self.environment.coredata.get_option(OptionKey('stdsplit')): @@ -1334,7 +1336,7 @@ def generate_tests(self): elem.add_item('pool', 'console') self.add_build(elem) - def generate_rules(self): + def generate_rules(self) -> None: self.rules = [] self.ruledict = {} @@ -1409,7 +1411,7 @@ def generate_phony(self) -> None: elem = NinjaBuildElement(self.all_outputs, 'PHONY', 'phony', '') self.add_build(elem) - def generate_jar_target(self, target: build.Jar): + def generate_jar_target(self, target: build.Jar) -> None: fname = target.get_filename() outname_rel = os.path.join(self.get_target_dir(target), fname) src_list = target.get_sources() @@ -1463,7 +1465,7 @@ def generate_jar_target(self, target: build.Jar): # Create introspection information self.create_target_source_introspection(target, compiler, compile_args, src_list, gen_src_list) - def generate_cs_resource_tasks(self, target): + def generate_cs_resource_tasks(self, target) -> T.Tuple[T.List[str], T.List[str]]: args = [] deps = [] for r in target.resources: @@ -1484,7 +1486,7 @@ def generate_cs_resource_tasks(self, target): args.append(a) return args, deps - def generate_cs_target(self, target: build.BuildTarget): + def generate_cs_target(self, target: build.BuildTarget) -> None: fname = target.get_filename() outname_rel = os.path.join(self.get_target_dir(target), fname) src_list = target.get_sources() @@ -1529,7 +1531,7 @@ def generate_cs_target(self, target: build.BuildTarget): self.generate_generator_list_rules(target) self.create_target_source_introspection(target, compiler, commands, rel_srcs, generated_rel_srcs) - def determine_java_compile_args(self, target, compiler): + def determine_java_compile_args(self, target, compiler) -> T.List[str]: args = [] args = self.generate_basic_compiler_args(target, compiler) args += target.get_java_args() @@ -1569,13 +1571,13 @@ def generate_java_compile(self, srcs, target, compiler, args): self.add_build(element) return plain_class_paths - def generate_java_link(self): + def generate_java_link(self) -> None: rule = 'java_LINKER' command = ['jar', '$ARGS'] description = 'Creating JAR $out' self.add_rule(NinjaRule(rule, command, [], description)) - def determine_dep_vapis(self, target): + def determine_dep_vapis(self, target) -> T.List[str]: """ Peek into the sources of BuildTargets we're linking with, and if any of them was built with Vala, assume that it also generated a .vapi file of @@ -1838,7 +1840,7 @@ def generate_cython_transpile(self, target: build.BuildTarget) -> \ return static_sources, generated_sources, cython_sources - def _generate_copy_target(self, src: 'mesonlib.FileOrString', output: Path) -> None: + def _generate_copy_target(self, src: FileOrString, output: Path) -> None: """Create a target to copy a source file from one location to another.""" if isinstance(src, File): instr = src.absolute_path(self.environment.source_dir, self.environment.build_dir) @@ -2191,7 +2193,7 @@ def split_swift_generated_sources(self, target): others.append(i) return srcs, others - def generate_swift_target(self, target): + def generate_swift_target(self, target) -> None: module_name = self.target_swift_modulename(target) swiftc = target.compilers['swift'] abssrc = [] @@ -2296,7 +2298,7 @@ def _rsp_options(self, tool: T.Union['Compiler', 'StaticLinker', 'DynamicLinker' options['rspfile_quote_style'] = tool.rsp_file_syntax() return options - def generate_static_link_rules(self): + def generate_static_link_rules(self) -> None: num_pools = self.environment.coredata.optstore.get_value('backend_max_links') if 'java' in self.environment.coredata.compilers.host: self.generate_java_link() @@ -2344,7 +2346,7 @@ def generate_static_link_rules(self): options = self._rsp_options(static_linker) self.add_rule(NinjaRule(rule, cmdlist, args, description, **options, extra=pool)) - def generate_dynamic_link_rules(self): + def generate_dynamic_link_rules(self) -> None: num_pools = self.environment.coredata.optstore.get_value('backend_max_links') for for_machine in MachineChoice: complist = self.environment.coredata.compilers[for_machine] @@ -2383,7 +2385,7 @@ def generate_dynamic_link_rules(self): synstat = 'restat = 1' self.add_rule(NinjaRule(symrule, symcmd, [], syndesc, extra=synstat)) - def generate_java_compile_rule(self, compiler): + def generate_java_compile_rule(self, compiler) -> None: rule = self.compiler_to_rule_name(compiler) command = compiler.get_exelist() + ['$ARGS', '$in'] description = 'Compiling Java sources for $FOR_JAR' @@ -2398,7 +2400,7 @@ def generate_cs_compile_rule(self, compiler: 'CsCompiler') -> None: rspable=mesonlib.is_windows(), rspfile_quote_style=compiler.rsp_file_syntax())) - def generate_vala_compile_rules(self, compiler): + def generate_vala_compile_rules(self, compiler) -> None: rule = self.compiler_to_rule_name(compiler) command = compiler.get_exelist() + ['$ARGS', '$in'] description = 'Compiling Vala source $in' @@ -2419,7 +2421,7 @@ def generate_cython_compile_rules(self, compiler: 'Compiler') -> None: depfile=depfile, extra='restat = 1')) - def generate_rust_compile_rules(self, compiler): + def generate_rust_compile_rules(self, compiler) -> None: rule = self.compiler_to_rule_name(compiler) command = compiler.get_exelist() + ['$ARGS', '$in'] description = 'Compiling Rust source $in' @@ -2428,7 +2430,7 @@ def generate_rust_compile_rules(self, compiler): self.add_rule(NinjaRule(rule, command, [], description, deps=depstyle, depfile=depfile)) - def generate_swift_compile_rules(self, compiler): + def generate_swift_compile_rules(self, compiler) -> None: rule = self.compiler_to_rule_name(compiler) full_exe = self.environment.get_build_command() + [ '--internal', @@ -2459,7 +2461,7 @@ def generate_fortran_dep_hack(self, crstr: str) -> None: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) self.add_rule(NinjaRule(rule, cmd, [], 'Dep hack', extra='restat = 1')) - def generate_llvm_ir_compile_rule(self, compiler): + def generate_llvm_ir_compile_rule(self, compiler) -> None: if self.created_llvm_ir_rule[compiler.for_machine]: return rule = self.get_compiler_rule_name('llvm_ir', compiler.for_machine) @@ -2472,7 +2474,7 @@ def generate_llvm_ir_compile_rule(self, compiler): self.add_rule(NinjaRule(rule, command, args, description, **options)) self.created_llvm_ir_rule[compiler.for_machine] = True - def generate_compile_rule_for(self, langname, compiler): + def generate_compile_rule_for(self, langname: str, compiler: Compiler) -> None: if langname == 'java': self.generate_java_compile_rule(compiler) return @@ -2518,7 +2520,7 @@ def generate_compile_rule_for(self, langname, compiler): self.add_rule(NinjaRule(rule, command, args, description, **options, deps=deps, depfile=depfile)) - def generate_pch_rule_for(self, langname, compiler): + def generate_pch_rule_for(self, langname: str, compiler: Compiler) -> None: if langname not in {'c', 'cpp'}: return rule = self.compiler_to_pch_rule_name(compiler) @@ -2544,7 +2546,7 @@ def generate_pch_rule_for(self, langname, compiler): self.add_rule(NinjaRule(rule, command, [], description, deps=deps, depfile=depfile)) - def generate_scanner_rules(self): + def generate_scanner_rules(self) -> None: rulename = 'depscan' if rulename in self.ruledict: # Scanning command is the same for native and cross compilation. @@ -2556,7 +2558,7 @@ def generate_scanner_rules(self): rule = NinjaRule(rulename, command, args, description) self.add_rule(rule) - def generate_compile_rules(self): + def generate_compile_rules(self) -> None: for for_machine in MachineChoice: clist = self.environment.coredata.compilers[for_machine] for langname, compiler in clist.items(): @@ -2567,7 +2569,7 @@ def generate_compile_rules(self): for mode in compiler.get_modes(): self.generate_compile_rule_for(langname, mode) - def generate_generator_list_rules(self, target): + def generate_generator_list_rules(self, target) -> None: # CustomTargets have already written their rules and # CustomTargetIndexes don't actually get generated, so write rules for # GeneratedLists here @@ -2652,7 +2654,7 @@ def generate_genlist_for_target(self, genlist: build.GeneratedList, target: buil elem.add_item('COMMAND', cmdlist) self.add_build(elem) - def scan_fortran_module_outputs(self, target): + def scan_fortran_module_outputs(self, target) -> None: """ Find all module and submodule made available in a Fortran code file. """ @@ -2794,7 +2796,7 @@ def get_link_debugfile_args(self, linker: T.Union[Compiler, StaticLinker], targe return linker.get_link_debugfile_args(filename) return [] - def generate_llvm_ir_compile(self, target, src: mesonlib.FileOrString): + def generate_llvm_ir_compile(self, target, src: FileOrString): base_proxy = target.get_options() compiler = get_compiler_for_source(target.compilers.values(), src) commands = compiler.compiler_args() @@ -2954,9 +2956,9 @@ def generate_common_compile_args_per_src_type(self, target: build.BuildTarget) - def generate_single_compile(self, target: build.BuildTarget, src, is_generated: bool = False, header_deps=None, - order_deps: T.Optional[T.List['mesonlib.FileOrString']] = None, + order_deps: T.Optional[T.List[FileOrString]] = None, extra_args: T.Optional[T.List[str]] = None, - unity_sources: T.Optional[T.List[mesonlib.FileOrString]] = None, + unity_sources: T.Optional[T.List[FileOrString]] = None, ) -> T.Tuple[str, str]: """ Compiles C/C++, ObjC/ObjC++, Fortran, and D sources @@ -3098,7 +3100,7 @@ def quote_make_target(targetName: str) -> str: assert isinstance(rel_src, str) return (rel_obj, rel_src.replace('\\', '/')) - def add_dependency_scanner_entries_to_element(self, target: build.BuildTarget, compiler, element, src): + def add_dependency_scanner_entries_to_element(self, target: build.BuildTarget, compiler, element, src) -> None: if not self.should_use_dyndeps_for_target(target): return if isinstance(target, build.CompileTarget): @@ -3123,7 +3125,7 @@ def add_header_deps(self, target, ninja_element, header_deps): d = os.path.join(self.get_target_private_dir(target), d) ninja_element.add_dep(d) - def has_dir_part(self, fname: mesonlib.FileOrString) -> bool: + def has_dir_part(self, fname: FileOrString) -> bool: # FIXME FIXME: The usage of this is a terrible and unreliable hack if isinstance(fname, File): return fname.subdir != '' @@ -3230,7 +3232,7 @@ def get_target_shsym_filename(self, target): targetdir = self.get_target_private_dir(target) return os.path.join(targetdir, target.get_filename() + '.symbols') - def generate_shsym(self, target): + def generate_shsym(self, target) -> None: target_file = self.get_target_filename(target) symname = self.get_target_shsym_filename(target) elem = NinjaBuildElement(self.all_outputs, symname, 'SHSYM', target_file) @@ -3240,7 +3242,7 @@ def generate_shsym(self, target): elem.add_item('CROSS', '--cross-host=' + self.environment.machines[target.for_machine].system) self.add_build(elem) - def get_import_filename(self, target): + def get_import_filename(self, target) -> str: return os.path.join(self.get_target_dir(target), target.import_filename) def get_target_type_link_args(self, target, linker): @@ -3295,7 +3297,7 @@ def get_target_type_link_args_post_dependencies(self, target, linker): commands += linker.get_win_subsystem_args(target.win_subsystem) return commands - def get_link_whole_args(self, linker, target): + def get_link_whole_args(self, linker: DynamicLinker, target): use_custom = False if linker.id == 'msvc': # Expand our object lists manually if we are on pre-Visual Studio 2015 Update 2 @@ -3565,7 +3567,7 @@ def get_dependency_filename(self, t): self.environment.get_build_dir()) return self.get_target_filename(t) - def generate_shlib_aliases(self, target, outdir): + def generate_shlib_aliases(self, target, outdir) -> None: for alias, to, tag in target.get_aliases(): aliasfile = os.path.join(outdir, alias) abs_aliasfile = os.path.join(self.environment.get_build_dir(), outdir, alias) @@ -3605,7 +3607,7 @@ def generate_gcov_clean(self) -> None: gcda_elem.add_item('description', 'Deleting gcda files') self.add_build(gcda_elem) - def get_user_option_args(self): + def get_user_option_args(self) -> T.List[str]: cmds = [] for k, v in self.environment.coredata.optstore.items(): if self.environment.coredata.optstore.is_project_option(k): From f2de6dfd1041ef2e62b41d437da2d62af4a4d437 Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Mon, 25 Dec 2023 02:42:55 -0500 Subject: [PATCH 081/302] mypy: fix broken logic checks that used "if func" It's always true because the func is always a real, truthy func object. In the cmake case, the logic seems to be broken because if a path is not a file, then that includes the case where it does not exist. It also clearly meant "or" instead of "and". What actually ended up happening was that this check never fired at all. Because "if not func and not ..." would always fail, because "not func" is always false. Maybe we don't need this logic at all... --- mesonbuild/cmake/traceparser.py | 2 +- mesonbuild/dependencies/boost.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mesonbuild/cmake/traceparser.py b/mesonbuild/cmake/traceparser.py index 69e4131823fa..bc18b51a5b4d 100644 --- a/mesonbuild/cmake/traceparser.py +++ b/mesonbuild/cmake/traceparser.py @@ -165,7 +165,7 @@ def requires_stderr(self) -> bool: def parse(self, trace: T.Optional[str] = None) -> None: # First load the trace (if required) if not self.requires_stderr(): - if not self.trace_file_path.exists and not self.trace_file_path.is_file(): + if not self.trace_file_path.is_file(): raise CMakeException(f'CMake: Trace file "{self.trace_file_path!s}" not found') trace = self.trace_file_path.read_text(errors='ignore', encoding='utf-8') if not trace: diff --git a/mesonbuild/dependencies/boost.py b/mesonbuild/dependencies/boost.py index 87f8db9203eb..19d492977973 100644 --- a/mesonbuild/dependencies/boost.py +++ b/mesonbuild/dependencies/boost.py @@ -261,7 +261,7 @@ def update_vers(new_vers: str) -> None: update_vers(i[2:]) elif i.isdigit(): update_vers(i) - elif len(i) >= 3 and i[0].isdigit and i[2].isdigit() and i[1] == '.': + elif len(i) >= 3 and i[0].isdigit() and i[2].isdigit() and i[1] == '.': update_vers(i) else: other_tags += [i] From ec0da1defabfd84c0aaf4a863de1a6a41f202076 Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Mon, 29 Jul 2024 23:03:47 -0400 Subject: [PATCH 082/302] mypy: reduce layers of indirection to ensure narrower type inference We have a function that wraps two others because it first checks whether the input is static or shared. By the same token, it has to return types valid for either. We already *know* that we are a shared library, so we can and should use the real function directly, which is both a micro-optimization of function call overhead, and fixes a mypy "union-attr" error. --- mesonbuild/backend/ninjabackend.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index b43b8bbe43c0..783cd78b5aa2 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -3712,7 +3712,7 @@ def generate_ending(self) -> None: #Add archive file if shared library in AIX for build all. if isinstance(t, build.SharedLibrary) and t.aix_so_archive: if self.environment.machines[t.for_machine].is_aix(): - linker, stdlib_args = self.determine_linker_and_stdlib_args(t) + linker, stdlib_args = t.get_clink_dynamic_linker_and_stdlibs() t.get_outputs()[0] = linker.get_archive_name(t.get_outputs()[0]) targetlist.append(os.path.join(self.get_target_dir(t), t.get_outputs()[0])) From 823779a9b1b39afb061d9ecf597aa96ab2ceb07b Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Mon, 29 Jul 2024 23:17:22 -0400 Subject: [PATCH 083/302] mypy: add annotation for object attribute used as a private cache via hasattr If it exists, we want to know it has the right type when we use it in ninjabackend.py. --- mesonbuild/build.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 42f1dcc9c2f9..3107673a75c1 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -721,6 +721,9 @@ class BuildTarget(Target): ('cpp', 'cuda'), ]) + # This is used by the backend to cache complex computation. + cached_generated_headers: T.Optional[T.List[FileOrString]] + def __init__( self, name: str, From 574fbe7d95cc8f82492ff60fe34868def749c4f1 Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Tue, 30 Jul 2024 00:20:07 -0400 Subject: [PATCH 084/302] backends: start disentangling some hairy global annotations create_target_linker_introspection is only ever called from one place, which passes in CompilerArgs. This was implemented in commit 5eb55075baa2883170a3d0cf3c0621aae56a1632 which performed this conversion as a preventative measure, since its type was not obvious (and thereby modified the *type* of the variable in place). --- mesonbuild/backend/ninjabackend.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 783cd78b5aa2..a911c90e0222 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -46,6 +46,7 @@ from ..compilers.cs import CsCompiler from ..compilers.fortran import FortranCompiler from ..mesonlib import FileOrString + from .backends import TargetIntrospectionData CommandArgOrStr = T.List[T.Union['NinjaCommandArg', str]] RUST_EDITIONS = Literal['2015', '2018', '2021'] @@ -495,12 +496,12 @@ def __init__(self, build: T.Optional[build.Build], interpreter: T.Optional[Inter super().__init__(build, interpreter) self.name = 'ninja' self.ninja_filename = 'build.ninja' - self.fortran_deps = {} + self.fortran_deps: T.Dict[str, T.Dict[str, File]] = {} self.all_outputs: T.Set[str] = set() self.introspection_data = {} self.created_llvm_ir_rule = PerMachine(False, False) self.rust_crates: T.Dict[str, RustCrate] = {} - self.implicit_meson_outs = [] + self.implicit_meson_outs: T.List[str] = [] self._uses_dyndeps = False # nvcc chokes on thin archives: # nvlink fatal : Could not open input file 'libfoo.a.p' @@ -849,14 +850,13 @@ def compute_path(file: FileOrString) -> str: if unity_sources: src_block['unity_sources'].extend(compute_path(x) for x in unity_sources) - def create_target_linker_introspection(self, target: build.Target, linker: T.Union[Compiler, StaticLinker], parameters) -> None: + def create_target_linker_introspection(self, target: build.Target, linker: T.Union[Compiler, StaticLinker], parameters: CompilerArgs) -> None: tid = target.get_id() tgt = self.introspection_data[tid] lnk_hash = tuple(parameters) lnk_block = tgt.get(lnk_hash, None) if lnk_block is None: - if isinstance(parameters, CompilerArgs): - parameters = parameters.to_native(copy=True) + paramlist = parameters.to_native(copy=True) if isinstance(linker, Compiler): linkers = linker.get_linker_exelist() @@ -865,7 +865,7 @@ def create_target_linker_introspection(self, target: build.Target, linker: T.Uni lnk_block = { 'linker': linkers, - 'parameters': parameters, + 'parameters': paramlist, } tgt[lnk_hash] = lnk_block @@ -3763,7 +3763,7 @@ def generate_ending(self) -> None: elem = NinjaBuildElement(self.all_outputs, deps, 'phony', '') self.add_build(elem) - def get_introspection_data(self, target_id: str, target: build.Target) -> T.List[T.Dict[str, T.Union[bool, str, T.List[T.Union[str, T.Dict[str, T.Union[str, T.List[str], bool]]]]]]]: + def get_introspection_data(self, target_id: str, target: build.Target) -> T.List[TargetIntrospectionData]: data = self.introspection_data.get(target_id) if not data: return super().get_introspection_data(target_id, target) @@ -3771,7 +3771,7 @@ def get_introspection_data(self, target_id: str, target: build.Target) -> T.List return list(data.values()) -def _scan_fortran_file_deps(src: Path, srcdir: Path, dirname: Path, tdeps, compiler) -> T.List[str]: +def _scan_fortran_file_deps(src: Path, srcdir: Path, dirname: Path, tdeps: T.Dict[str, File], compiler: FortranCompiler) -> T.List[str]: """ scan a Fortran file for dependencies. Needs to be distinct from target to allow for recursion induced by `include` statements.er From 4a352dd8bdb083b2d75994fe1b0ba27242a7ce61 Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Tue, 4 Jun 2024 22:05:57 -0400 Subject: [PATCH 085/302] flake8: move unused typing-only imports to TYPE_CHECKING --- mesonbuild/ast/interpreter.py | 2 +- mesonbuild/compilers/compilers.py | 7 +++---- mesonbuild/compilers/d.py | 2 +- mesonbuild/compilers/mixins/emscripten.py | 2 +- mesonbuild/compilers/objc.py | 2 +- mesonbuild/compilers/objcpp.py | 2 +- mesonbuild/compilers/vala.py | 2 +- mesonbuild/coredata.py | 2 +- mesonbuild/mformat.py | 2 +- mesonbuild/modules/python3.py | 3 ++- mesonbuild/optinterpreter.py | 2 +- 11 files changed, 14 insertions(+), 14 deletions(-) diff --git a/mesonbuild/ast/interpreter.py b/mesonbuild/ast/interpreter.py index 15d279350eaa..5edd9b3d972c 100644 --- a/mesonbuild/ast/interpreter.py +++ b/mesonbuild/ast/interpreter.py @@ -43,7 +43,6 @@ NotNode, PlusAssignmentNode, TernaryNode, - TestCaseClauseNode, ) if T.TYPE_CHECKING: @@ -57,6 +56,7 @@ IfClauseNode, IndexNode, OrNode, + TestCaseClauseNode, UMinusNode, ) diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 7057fc2a2662..e4e5b6f34ffb 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -12,7 +12,6 @@ from dataclasses import dataclass from functools import lru_cache -from .. import coredata from .. import mlog from .. import mesonlib from .. import options @@ -27,7 +26,7 @@ from ..arglist import CompilerArgs if T.TYPE_CHECKING: - from typing import Any + from .. import coredata from ..build import BuildTarget, DFeatures from ..coredata import MutableKeyedOptionDictType, KeyedOptionDictType from ..envconfig import MachineInfo @@ -1360,7 +1359,7 @@ def form_compileropt_key(self, basename: str) -> OptionKey: def get_global_options(lang: str, comp: T.Type[Compiler], for_machine: MachineChoice, - env: 'Environment') -> 'dict[OptionKey, options.UserOption[Any]]': + env: 'Environment') -> dict[OptionKey, options.UserOption[T.Any]]: """Retrieve options that apply to all compilers for a given language.""" description = f'Extra arguments passed to the {lang}' argkey = OptionKey(f'{lang}_args', machine=for_machine) @@ -1390,6 +1389,6 @@ def get_global_options(lang: str, # autotools compatibility. largs.extend_value(comp_options) - opts: 'dict[OptionKey, options.UserOption[Any]]' = {argkey: cargs, largkey: largs} + opts: dict[OptionKey, options.UserOption[T.Any]] = {argkey: cargs, largkey: largs} return opts diff --git a/mesonbuild/compilers/d.py b/mesonbuild/compilers/d.py index d8b252a94668..8ee6ebf651c5 100644 --- a/mesonbuild/compilers/d.py +++ b/mesonbuild/compilers/d.py @@ -16,7 +16,6 @@ ) from ..options import OptionKey -from . import compilers from .compilers import ( clike_debug_args, Compiler, @@ -26,6 +25,7 @@ from .mixins.gnu import gnu_common_warning_args if T.TYPE_CHECKING: + from . import compilers from ..build import DFeatures from ..dependencies import Dependency from ..envconfig import MachineInfo diff --git a/mesonbuild/compilers/mixins/emscripten.py b/mesonbuild/compilers/mixins/emscripten.py index 33b6134a344f..64315ae96797 100644 --- a/mesonbuild/compilers/mixins/emscripten.py +++ b/mesonbuild/compilers/mixins/emscripten.py @@ -8,7 +8,6 @@ import os.path import typing as T -from ... import coredata from ... import options from ... import mesonlib from ...options import OptionKey @@ -16,6 +15,7 @@ from mesonbuild.compilers.compilers import CompileCheckMode if T.TYPE_CHECKING: + from ... import coredata from ...environment import Environment from ...compilers.compilers import Compiler from ...dependencies import Dependency diff --git a/mesonbuild/compilers/objc.py b/mesonbuild/compilers/objc.py index 37958d8a00c1..97550c2ea251 100644 --- a/mesonbuild/compilers/objc.py +++ b/mesonbuild/compilers/objc.py @@ -5,7 +5,6 @@ import typing as T -from .. import coredata from .. import options from ..options import OptionKey @@ -15,6 +14,7 @@ from .mixins.clang import ClangCompiler if T.TYPE_CHECKING: + from .. import coredata from ..envconfig import MachineInfo from ..environment import Environment from ..linkers.linkers import DynamicLinker diff --git a/mesonbuild/compilers/objcpp.py b/mesonbuild/compilers/objcpp.py index 6388d41c3f37..973d7bb0cfb8 100644 --- a/mesonbuild/compilers/objcpp.py +++ b/mesonbuild/compilers/objcpp.py @@ -5,7 +5,6 @@ import typing as T -from .. import coredata from .. import options from ..options import OptionKey @@ -15,6 +14,7 @@ from .mixins.clang import ClangCompiler if T.TYPE_CHECKING: + from .. import coredata from ..envconfig import MachineInfo from ..environment import Environment from ..linkers.linkers import DynamicLinker diff --git a/mesonbuild/compilers/vala.py b/mesonbuild/compilers/vala.py index f890ea81568f..a1d57b38cb8e 100644 --- a/mesonbuild/compilers/vala.py +++ b/mesonbuild/compilers/vala.py @@ -11,9 +11,9 @@ from ..mesonlib import EnvironmentException, version_compare, LibType from ..options import OptionKey from .compilers import CompileCheckMode, Compiler -from ..arglist import CompilerArgs if T.TYPE_CHECKING: + from ..arglist import CompilerArgs from ..coredata import KeyedOptionDictType from ..envconfig import MachineInfo from ..environment import Environment diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 83e83e728727..276c3a67807b 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -27,12 +27,12 @@ from .machinefile import CmdLineFileParser import ast -import argparse import enum import shlex import typing as T if T.TYPE_CHECKING: + import argparse from typing_extensions import Protocol from typing import Any diff --git a/mesonbuild/mformat.py b/mesonbuild/mformat.py index 42f562e7f278..33ee69d3cc1b 100644 --- a/mesonbuild/mformat.py +++ b/mesonbuild/mformat.py @@ -3,7 +3,6 @@ from __future__ import annotations -import argparse import re import typing as T from configparser import ConfigParser, MissingSectionHeaderError, ParsingError @@ -19,6 +18,7 @@ from .environment import build_filename if T.TYPE_CHECKING: + import argparse from typing_extensions import Literal diff --git a/mesonbuild/modules/python3.py b/mesonbuild/modules/python3.py index 45ad850aa129..2e6779ab2b5f 100644 --- a/mesonbuild/modules/python3.py +++ b/mesonbuild/modules/python3.py @@ -7,7 +7,7 @@ import typing as T from .. import mesonlib -from . import ExtensionModule, ModuleInfo, ModuleState +from . import ExtensionModule, ModuleInfo from ..build import ( BuildTarget, CustomTarget, CustomTargetIndex, ExtractedObjects, GeneratedList, SharedModule, StructuredSources, known_shmod_kwargs @@ -17,6 +17,7 @@ from ..programs import ExternalProgram if T.TYPE_CHECKING: + from . import ModuleState from ..interpreter.interpreter import BuildTargetSource from ..interpreter.kwargs import SharedModule as SharedModuleKW diff --git a/mesonbuild/optinterpreter.py b/mesonbuild/optinterpreter.py index a22152829b42..4688ee4c4f49 100644 --- a/mesonbuild/optinterpreter.py +++ b/mesonbuild/optinterpreter.py @@ -6,7 +6,6 @@ import re import typing as T -from . import coredata from . import options from . import mesonlib from .options import OptionKey @@ -16,6 +15,7 @@ from .interpreter.type_checking import NoneType, in_set_validator if T.TYPE_CHECKING: + from . import coredata from .interpreterbase import TYPE_var, TYPE_kwargs from .interpreterbase import SubProject from typing_extensions import TypedDict, Literal From a59231ff4a30f686306662e1298c69fd2459dec8 Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Sun, 11 Feb 2024 19:50:26 -0500 Subject: [PATCH 086/302] compilers: simplify CompileResult / RunResult by using dataclasses None sentinel is replaced by field(), so we don't need to declare it Optional anymore. --- mesonbuild/compilers/compilers.py | 37 +++++++++++++------------------ 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index e4e5b6f34ffb..e797cf16a4a2 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -9,7 +9,7 @@ import enum import itertools import typing as T -from dataclasses import dataclass +from dataclasses import dataclass, field from functools import lru_cache from .. import mlog @@ -406,34 +406,27 @@ def get_base_link_args(options: 'KeyedOptionDictType', linker: 'Compiler', class CrossNoRunException(MesonException): pass +@dataclass class RunResult(HoldableObject): - def __init__(self, compiled: bool, returncode: int = 999, - stdout: str = 'UNDEFINED', stderr: str = 'UNDEFINED', - cached: bool = False): - self.compiled = compiled - self.returncode = returncode - self.stdout = stdout - self.stderr = stderr - self.cached = cached + compiled: bool + returncode: int = 999 + stdout: str = 'UNDEFINED' + stderr: str = 'UNDEFINED' + cached: bool = False +@dataclass class CompileResult(HoldableObject): """The result of Compiler.compiles (and friends).""" - def __init__(self, stdo: T.Optional[str] = None, stde: T.Optional[str] = None, - command: T.Optional[T.List[str]] = None, - returncode: int = 999, - input_name: T.Optional[str] = None, - output_name: T.Optional[str] = None, - cached: bool = False): - self.stdout = stdo - self.stderr = stde - self.input_name = input_name - self.output_name = output_name - self.command = command or [] - self.cached = cached - self.returncode = returncode + stdout: T.Optional[str] = None + stderr: T.Optional[str] = None + command: T.List[str] = field(default_factory=list) + returncode: int = 999 + input_name: T.Optional[str] = None + output_name: T.Optional[str] = None + cached: bool = False class Compiler(HoldableObject, metaclass=abc.ABCMeta): From 28ab1ce39a7889c681cf6874f9062baa97b1f5f7 Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Sun, 11 Feb 2024 20:19:27 -0500 Subject: [PATCH 087/302] compilers: straighten out CompileResult according to how it is actually used In particular, it is only ever constructed once, and all but two of its arguments are always passed. So there's no reason or valid justification to initialize them as None or pretend that you have to check them for None values. Nor in fact does the command list need to be a default_factory. There are also two instance attributes which it is never instantiated with, but which are tracked after the fact. Don't add this to the signature for `__init__` as that is misleading. --- mesonbuild/compilers/compilers.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index e797cf16a4a2..3dcf496d4bbb 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -420,13 +420,13 @@ class CompileResult(HoldableObject): """The result of Compiler.compiles (and friends).""" - stdout: T.Optional[str] = None - stderr: T.Optional[str] = None - command: T.List[str] = field(default_factory=list) - returncode: int = 999 - input_name: T.Optional[str] = None - output_name: T.Optional[str] = None - cached: bool = False + stdout: str + stderr: str + command: T.List[str] + returncode: int + input_name: str + output_name: T.Optional[str] = field(default=None, init=False) + cached: bool = field(default=False, init=False) class Compiler(HoldableObject, metaclass=abc.ABCMeta): From 077d540c10a103fd5a41d0747b8140fef87b02ef Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Sun, 28 Jul 2024 13:37:35 -0400 Subject: [PATCH 088/302] unittests: fix EncodingWarnings. minus 123 warnings collected by pytest --- unittests/baseplatformtests.py | 4 ++-- unittests/helpers.py | 2 +- unittests/linuxliketests.py | 2 +- unittests/machinefiletests.py | 2 +- unittests/rewritetests.py | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/unittests/baseplatformtests.py b/unittests/baseplatformtests.py index 6e6a01d40fd3..5976335144c9 100644 --- a/unittests/baseplatformtests.py +++ b/unittests/baseplatformtests.py @@ -364,14 +364,14 @@ def introspect(self, args): if isinstance(args, str): args = [args] out = subprocess.check_output(self.mintro_command + args + [self.builddir], - universal_newlines=True) + encoding='utf-8', universal_newlines=True) return json.loads(out) def introspect_directory(self, directory, args): if isinstance(args, str): args = [args] out = subprocess.check_output(self.mintro_command + args + [directory], - universal_newlines=True) + encoding='utf-8', universal_newlines=True) try: obj = json.loads(out) except Exception as e: diff --git a/unittests/helpers.py b/unittests/helpers.py index 5e919295515d..2f97ab1d4f91 100644 --- a/unittests/helpers.py +++ b/unittests/helpers.py @@ -167,7 +167,7 @@ def get_dynamic_section_entry(fname: str, entry: str) -> T.Optional[str]: try: raw_out = subprocess.check_output(['readelf', '-d', fname], - universal_newlines=True) + encoding='utf-8', universal_newlines=True) except FileNotFoundError: # FIXME: Try using depfixer.py:Elf() as a fallback raise unittest.SkipTest('readelf not found') diff --git a/unittests/linuxliketests.py b/unittests/linuxliketests.py index 16997e393339..cfad8fece55e 100644 --- a/unittests/linuxliketests.py +++ b/unittests/linuxliketests.py @@ -1703,7 +1703,7 @@ def test_prelinking(self): p = subprocess.run([ar, 't', outlib], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, - text=True, timeout=1) + encoding='utf-8', text=True, timeout=1) obj_files = p.stdout.strip().split('\n') self.assertEqual(len(obj_files), 1) self.assertTrue(obj_files[0].endswith('-prelink.o')) diff --git a/unittests/machinefiletests.py b/unittests/machinefiletests.py index 5ff862cdcfb1..8de0c602da5c 100644 --- a/unittests/machinefiletests.py +++ b/unittests/machinefiletests.py @@ -50,7 +50,7 @@ def is_real_gnu_compiler(path): ''' if not path: return False - out = subprocess.check_output([path, '--version'], universal_newlines=True, stderr=subprocess.STDOUT) + out = subprocess.check_output([path, '--version'], encoding='utf-8', universal_newlines=True, stderr=subprocess.STDOUT) return 'Free Software Foundation' in out cross_dir = Path(__file__).parent.parent / 'cross' diff --git a/unittests/rewritetests.py b/unittests/rewritetests.py index af5e204dcb47..a9e72b369180 100644 --- a/unittests/rewritetests.py +++ b/unittests/rewritetests.py @@ -28,7 +28,7 @@ def rewrite_raw(self, directory, args): if isinstance(args, str): args = [args] command = self.rewrite_command + ['--verbose', '--skip', '--sourcedir', directory] + args - p = subprocess.run(command, capture_output=True, text=True, timeout=60) + p = subprocess.run(command, capture_output=True, encoding='utf-8', text=True, timeout=60) print('STDOUT:') print(p.stdout) print('STDERR:') From a05b790d6600586449471d3fe957442896dec2a7 Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Mon, 29 Jul 2024 11:00:54 -0400 Subject: [PATCH 089/302] mdist: correctly detect dirty hg repos with non-English locale The command we use to heuristically parse whether it is dirty by interpreting prose descriptions of the repository state, is vulnerable to changes in locale resulting in failing to match the English word that means it is clean. Unfortunately, I am no mercurial expert so I am unaware if mercurial supports scripting, like git does. Perhaps the technology simply does not exist. A quick attempt at searching for the answer turned nothing up. It appears that #4278 had good cause indeed for using this prose parsing command. So, we simply sanitize the environment due to lack of any better idea. Bug: https://bugs.gentoo.org/936670 --- mesonbuild/mdist.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mesonbuild/mdist.py b/mesonbuild/mdist.py index 0c82cd3ef596..8e35bb8e8333 100644 --- a/mesonbuild/mdist.py +++ b/mesonbuild/mdist.py @@ -223,7 +223,9 @@ def create_dist(self, archives: T.List[str]) -> T.List[str]: class HgDist(Dist): def have_dirty_index(self) -> bool: '''Check whether there are uncommitted changes in hg''' - out = subprocess.check_output(['hg', '-R', self.src_root, 'summary']) + env = os.environ.copy() + env['LC_ALL'] = 'C' + out = subprocess.check_output(['hg', '-R', self.src_root, 'summary'], env=env) return b'commit: (clean)' not in out def create_dist(self, archives: T.List[str]) -> T.List[str]: From 03a8f35031c9ae0ded162f8b228c5b3f04643632 Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Mon, 29 Jul 2024 21:22:37 -0400 Subject: [PATCH 090/302] tests: nasm: make it easier to debug generator() style build By default, we build with debug info which can be useful for investigating why a test segfaults instead of either passing or failing. The nasm language hooks this up, but using nasm as a generator program does not. Bug: https://bugs.gentoo.org/936911 --- test cases/nasm/1 configure file/meson.build | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test cases/nasm/1 configure file/meson.build b/test cases/nasm/1 configure file/meson.build index fac46a687331..abe7bb30f98c 100644 --- a/test cases/nasm/1 configure file/meson.build +++ b/test cases/nasm/1 configure file/meson.build @@ -24,10 +24,16 @@ conf = configuration_data() conf.set('HELLO', 0) +debug_nasm = [] +if get_option('debug') + debug_nasm = ['-g'] +endif + asm_gen = generator(nasm, output : '@BASENAME@.o', arguments : [ '-f', asm_format, + debug_nasm, '-i', meson.current_source_dir() + '/', '-i', join_paths(meson.current_source_dir(), ''), '-P', join_paths(meson.current_build_dir(), 'config.asm'), From a51be6b1c77cba06bec3f27cdb846e825e958c55 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 30 Jul 2024 13:30:16 -0700 Subject: [PATCH 091/302] backend/ninja: stop adding random attributes to BuildTargets Instead of storing the generated header cache in the Target, store it in the NinjaBackend, as it really is just data for the NinjaBackend to use. --- mesonbuild/backend/ninjabackend.py | 8 +++++--- mesonbuild/build.py | 3 --- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index a911c90e0222..1eeda96a8ce8 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -503,6 +503,7 @@ def __init__(self, build: T.Optional[build.Build], interpreter: T.Optional[Inter self.rust_crates: T.Dict[str, RustCrate] = {} self.implicit_meson_outs: T.List[str] = [] self._uses_dyndeps = False + self._generated_header_cache: T.Dict[str, T.List[FileOrString]] = {} # nvcc chokes on thin archives: # nvlink fatal : Could not open input file 'libfoo.a.p' # nvlink fatal : elfLink internal error @@ -738,8 +739,9 @@ def generate_compdb(self) -> None: # Get all generated headers. Any source file might need them so # we need to add an order dependency to them. def get_generated_headers(self, target: build.BuildTarget) -> T.List[FileOrString]: - if hasattr(target, 'cached_generated_headers'): - return target.cached_generated_headers + tid = target.get_id() + if tid in self._generated_header_cache: + return self._generated_header_cache[tid] header_deps: T.List[FileOrString] = [] # XXX: Why don't we add deps to CustomTarget headers here? for genlist in target.get_generated_sources(): @@ -757,7 +759,7 @@ def get_generated_headers(self, target: build.BuildTarget) -> T.List[FileOrStrin header_deps += self.get_generated_headers(dep) if isinstance(target, build.CompileTarget): header_deps.extend(target.get_generated_headers()) - target.cached_generated_headers = header_deps + self._generated_header_cache[tid] = header_deps return header_deps def get_target_generated_sources(self, target: build.BuildTarget) -> T.MutableMapping[str, File]: diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 3107673a75c1..42f1dcc9c2f9 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -721,9 +721,6 @@ class BuildTarget(Target): ('cpp', 'cuda'), ]) - # This is used by the backend to cache complex computation. - cached_generated_headers: T.Optional[T.List[FileOrString]] - def __init__( self, name: str, From bdc2f2774c35ad2c81e3fea8621fdff6905c021b Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Mon, 29 Jul 2024 09:03:01 +0530 Subject: [PATCH 092/302] Fix some small typing issues in interpreter.py --- mesonbuild/build.py | 2 +- mesonbuild/interpreter/interpreter.py | 13 ++++++++++--- mesonbuild/interpreter/kwargs.py | 1 + 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 42f1dcc9c2f9..b9cc42721fc5 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -238,7 +238,7 @@ class Build: def __init__(self, environment: environment.Environment): self.version = coredata.version self.project_name = 'name of master project' - self.project_version = None + self.project_version: T.Optional[str] = None self.environment = environment self.projects = {} self.targets: 'T.OrderedDict[str, T.Union[CustomTarget, BuildTarget]]' = OrderedDict() diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index 95d85ac07ebf..9a524037af41 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -636,7 +636,7 @@ def func_import(self, node: mparser.BaseNode, args: T.Tuple[str], ext_module = NotFoundExtensionModule(real_modname) else: ext_module = module.initialize(self) - assert isinstance(ext_module, (ExtensionModule, NewExtensionModule)) + assert isinstance(ext_module, (ExtensionModule, NewExtensionModule)), 'for mypy' self.build.modules.append(real_modname) if ext_module.INFO.added: FeatureNew.single_use(f'module {ext_module.INFO.name}', ext_module.INFO.added, self.subproject, location=node) @@ -877,6 +877,7 @@ def disabled_subproject(self, subp_name: str, disabled_feature: T.Optional[str] def do_subproject(self, subp_name: str, kwargs: kwtypes.DoSubproject, force_method: T.Optional[wrap.Method] = None) -> SubprojectHolder: disabled, required, feature = extract_required_kwarg(kwargs, self.subproject) if disabled: + assert feature, 'for mypy' mlog.log('Subproject', mlog.bold(subp_name), ':', 'skipped: feature', mlog.bold(feature), 'disabled') return self.disabled_subproject(subp_name, disabled_feature=feature) @@ -1234,6 +1235,7 @@ def func_project(self, node: mparser.FunctionNode, args: T.Tuple[str, T.List[str self.active_projectname = proj_name version = kwargs['version'] + assert version is not None, 'for mypy' if isinstance(version, mesonlib.File): FeatureNew.single_use('version from file', '0.57.0', self.subproject, location=node) self.add_build_def_file(version) @@ -1291,6 +1293,7 @@ def func_project(self, node: mparser.FunctionNode, args: T.Tuple[str, T.List[str subdir = os.path.join(self.subdir, spdirname) r = wrap.Resolver(self.environment.get_source_dir(), subdir, self.subproject, wrap_mode) if self.is_subproject(): + assert self.environment.wrap_resolver is not None, 'for mypy' self.environment.wrap_resolver.merge_wraps(r) else: self.environment.wrap_resolver = r @@ -1305,7 +1308,9 @@ def func_project(self, node: mparser.FunctionNode, args: T.Tuple[str, T.List[str # vs backend version we need. But after setting default_options in case # the project sets vs backend by default. backend = self.coredata.get_option(OptionKey('backend')) + assert backend is None or isinstance(backend, str), 'for mypy' vsenv = self.coredata.get_option(OptionKey('vsenv')) + assert isinstance(vsenv, bool), 'for mypy' force_vsenv = vsenv or backend.startswith('vs') mesonlib.setup_vsenv(force_vsenv) @@ -1324,6 +1329,7 @@ def func_add_languages(self, node: mparser.FunctionNode, args: T.Tuple[T.List[st native = kwargs['native'] if disabled: + assert feature, 'for mypy' for lang in sorted(langs, key=compilers.sort_clink): mlog.log('Compiler for language', mlog.bold(lang), 'skipped: feature', mlog.bold(feature), 'disabled') return False @@ -1725,7 +1731,7 @@ def check_program_version(self, progobj: T.Union[ExternalProgram, build.Executab interp = self.subprojects[progobj.subproject].held_object else: interp = self - assert isinstance(interp, Interpreter) + assert isinstance(interp, Interpreter), 'for mypy' version = interp.project_version else: version = progobj.get_version(self) @@ -1770,6 +1776,7 @@ def func_find_program(self, node: mparser.BaseNode, args: T.Tuple[T.List[mesonli ) -> T.Union['build.Executable', ExternalProgram, 'OverrideProgram']: disabled, required, feature = extract_required_kwarg(kwargs, self.subproject) if disabled: + assert feature, 'for mypy' mlog.log('Program', mlog.bold(' '.join(args[0])), 'skipped: feature', mlog.bold(feature), 'disabled') return self.notfound_program(args[0]) @@ -1812,7 +1819,7 @@ def func_dependency(self, node: mparser.BaseNode, args: T.Tuple[T.List[str]], kw if not_found_message: self.message_impl([not_found_message]) raise - assert isinstance(d, Dependency) + assert isinstance(d, Dependency), 'for mypy' if not d.found() and not_found_message: self.message_impl([not_found_message]) # Ensure the correct include type diff --git a/mesonbuild/interpreter/kwargs.py b/mesonbuild/interpreter/kwargs.py index abac410d319f..461ddc9bfbe9 100644 --- a/mesonbuild/interpreter/kwargs.py +++ b/mesonbuild/interpreter/kwargs.py @@ -211,6 +211,7 @@ class Project(TypedDict): meson_version: T.Optional[str] default_options: T.Dict[OptionKey, T.Union[str, int, bool, T.List[str]]] license: T.List[str] + license_files: T.List[str] subproject_dir: str From fa4f2339465ce3d755e2df802ebd5aa962e2ad27 Mon Sep 17 00:00:00 2001 From: Charles Brunet Date: Thu, 1 Aug 2024 11:44:59 -0400 Subject: [PATCH 093/302] mformat: fix formatting of empty build file Running meson format multiple times on an empty file was adding a new line each time, which is bad for pre-commit checks... --- mesonbuild/mformat.py | 2 ++ unittests/platformagnostictests.py | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/mesonbuild/mformat.py b/mesonbuild/mformat.py index 33ee69d3cc1b..bb93f47ef50c 100644 --- a/mesonbuild/mformat.py +++ b/mesonbuild/mformat.py @@ -396,6 +396,8 @@ def visit_CodeBlockNode(self, node: mparser.CodeBlockNode) -> None: if node.lines: self.move_whitespaces(node.lines[-1], node) else: + node.whitespaces.value = node.pre_whitespaces.value + node.whitespaces.value + node.pre_whitespaces.value = '' node.whitespaces.accept(self) if node.condition_level == 0 and self.config.insert_final_newline: diff --git a/unittests/platformagnostictests.py b/unittests/platformagnostictests.py index 4ac4b7a556c6..c8f594d465ef 100644 --- a/unittests/platformagnostictests.py +++ b/unittests/platformagnostictests.py @@ -16,7 +16,7 @@ from .baseplatformtests import BasePlatformTests from .helpers import is_ci from mesonbuild.mesonlib import EnvironmentVariables, ExecutableSerialisation, MesonException, is_linux, python_command -from mesonbuild.mformat import match_path +from mesonbuild.mformat import Formatter, match_path from mesonbuild.optinterpreter import OptionInterpreter, OptionException from mesonbuild.options import OptionStore from run_tests import Backend @@ -336,7 +336,13 @@ def test_editorconfig_match_path(self): for filename, pattern, expected in cases: self.assertTrue(match_path(filename, pattern) is expected, f'{filename} -> {pattern}') - + + def test_format_empty_file(self) -> None: + formatter = Formatter(None, use_editor_config=False, fetch_subdirs=False) + for code in ('', '\n'): + formatted = formatter.format(code, Path()) + self.assertEqual('\n', formatted) + def test_error_configuring_subdir(self): testdir = os.path.join(self.common_test_dir, '152 index customtarget') out = self.init(os.path.join(testdir, 'subdir'), allow_fail=True) From fdf8605b840892156ed7021a259761d32900fabc Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Mon, 29 Jul 2024 14:20:33 +0100 Subject: [PATCH 094/302] CI: Adjust path filters to run tests on Cygwin when unittests change --- .github/workflows/cygwin.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/cygwin.yml b/.github/workflows/cygwin.yml index d4c0ba53b20f..ecbe7e21e3ba 100644 --- a/.github/workflows/cygwin.yml +++ b/.github/workflows/cygwin.yml @@ -13,12 +13,14 @@ on: paths: - "mesonbuild/**" - "test cases/**" + - "unittests/**" - ".github/workflows/cygwin.yml" - "run*tests.py" pull_request: paths: - "mesonbuild/**" - "test cases/**" + - "unittests/**" - ".github/workflows/cygwin.yml" - "run*tests.py" From 97fc2a160c545d061db64bc9d80366e1da7cf713 Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Mon, 29 Jul 2024 16:36:40 +0100 Subject: [PATCH 095/302] CI: Install make on Cygwin Test '230 external project' uses make, but is too dumb to use the platform conventions for shared library names in installed files expected by shared_lib, so special case that. --- .github/workflows/cygwin.yml | 1 + test cases/common/230 external project/test.json | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/cygwin.yml b/.github/workflows/cygwin.yml index ecbe7e21e3ba..d819f802f1fe 100644 --- a/.github/workflows/cygwin.yml +++ b/.github/workflows/cygwin.yml @@ -69,6 +69,7 @@ jobs: libgtk3-devel libxml2-devel libxslt-devel + make ninja python2-devel python3-devel diff --git a/test cases/common/230 external project/test.json b/test cases/common/230 external project/test.json index 4888e8752327..4df7d4ac57ff 100644 --- a/test cases/common/230 external project/test.json +++ b/test cases/common/230 external project/test.json @@ -1,6 +1,7 @@ { "installed": [ - { "type": "shared_lib", "file": "usr/lib/foo" }, + { "type": "shared_lib", "file": "usr/lib/foo", "platform": "!cygwin" }, + { "type": "file", "file": "usr/lib/libfoo.dll", "platform": "cygwin" }, { "type": "file", "file": "usr/include/libfoo.h" }, { "type": "file", "file": "usr/lib/pkgconfig/somelib.pc" } ] From 2f49804cc2d817dc164f32f331449de4689ac185 Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Sun, 28 Jul 2024 22:27:49 +0100 Subject: [PATCH 096/302] Revert "CI: skip LTO tests on cygwin" This reverts commit 0c93149f09bbeedd03c70abc7b6d652b8e9ee9fa. --- unittests/allplatformstests.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/unittests/allplatformstests.py b/unittests/allplatformstests.py index 40085983710a..726252611fb7 100644 --- a/unittests/allplatformstests.py +++ b/unittests/allplatformstests.py @@ -1337,7 +1337,6 @@ def test_source_generator_program_cause_rebuild(self): self.utime(os.path.join(testdir, 'srcgen.py')) self.assertRebuiltTarget('basic') - @skipIf(is_ci() and is_cygwin(), 'A GCC update on 2024-07-21 has broken LTO and is being investigated') def test_static_library_lto(self): ''' Test that static libraries can be built with LTO and linked to @@ -1354,7 +1353,6 @@ def test_static_library_lto(self): self.build() self.run_tests() - @skipIf(is_ci() and is_cygwin(), 'A GCC update on 2024-07-21 has broken LTO and is being investigated') @skip_if_not_base_option('b_lto_threads') def test_lto_threads(self): testdir = os.path.join(self.common_test_dir, '6 linkshared') From 3587786a3cf5dd06aa4cab2b6abb36bfd7c7eca0 Mon Sep 17 00:00:00 2001 From: James Knight Date: Sun, 4 Aug 2024 00:02:05 -0400 Subject: [PATCH 097/302] minstall: update symlink install message presentation Updating the log message generated when installing a symbolic link. The new message format may be a bit more clear on the link being created. Signed-off-by: James Knight --- mesonbuild/minstall.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/minstall.py b/mesonbuild/minstall.py index e5901c45ae85..418124c64512 100644 --- a/mesonbuild/minstall.py +++ b/mesonbuild/minstall.py @@ -442,7 +442,7 @@ def do_symlink(self, target: str, link: str, destdir: str, full_dst_dir: str, al raise MesonException(f'Destination {link!r} already exists and is not a symlink') self.remove(link) if not self.printed_symlink_error: - self.log(f'Installing symlink pointing to {target} to {link}') + self.log(f'Installing symlink: {link} → {target}') try: self.symlink(target, link, target_is_directory=os.path.isdir(abs_target)) except (NotImplementedError, OSError): From 839fef4a710ab15a6401c1a5f3e1cfbeae9c432c Mon Sep 17 00:00:00 2001 From: Sertonix Date: Tue, 30 Jul 2024 17:19:15 +0200 Subject: [PATCH 098/302] docs: document prefer_static effect on dependency() Ref https://github.com/mesonbuild/meson/pull/9603 --- docs/yaml/functions/dependency.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/yaml/functions/dependency.yaml b/docs/yaml/functions/dependency.yaml index 74981b2d9f89..a19deab8fa22 100644 --- a/docs/yaml/functions/dependency.yaml +++ b/docs/yaml/functions/dependency.yaml @@ -169,7 +169,6 @@ kwargs: static: type: bool - default: false description: | Tells the dependency provider to try to get static libraries instead of dynamic ones (note that this is not supported @@ -178,6 +177,9 @@ kwargs: *Since 0.60.0* it also sets `default_library` option accordingly on the fallback subproject if it was not set explicitly in `default_options` keyword argument. + *Since 0.63.0* when the `prefer_static` option is set to `true` the default + value is `true` otherwise the default value is `false`. + version: type: list[str] | str since: 0.37.0 From fec6cf6d267ebd7f14e6a1ad78cfa418fd0c68dd Mon Sep 17 00:00:00 2001 From: Marvin Scholz Date: Mon, 5 Aug 2024 20:52:55 +0200 Subject: [PATCH 099/302] docs: fix example for feature.require The example incorrectly uses `then` after the if condition, which is incorrect meson syntax as meson does not support a `then` keyword. --- docs/yaml/objects/feature.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/yaml/objects/feature.yaml b/docs/yaml/objects/feature.yaml index 3e0ae69df1e0..fad6cd5e7bda 100644 --- a/docs/yaml/objects/feature.yaml +++ b/docs/yaml/objects/feature.yaml @@ -89,7 +89,7 @@ methods: ``` if get_option('directx').require(host_machine.system() == 'windows', - error_message: 'DirectX only available on Windows').allowed() then + error_message: 'DirectX only available on Windows').allowed() src += ['directx.c'] config.set10('HAVE_DIRECTX', true) endif From 8882d8be6a7de07d19c1d3908da43cba60f7d37b Mon Sep 17 00:00:00 2001 From: andy5995 Date: Sun, 10 Mar 2024 03:53:44 -0500 Subject: [PATCH 100/302] Add Zig to ubuntu-rolling image Signed-off-by: Eli Schwartz [Eli: do not add to CI tests as this is only a preparatory PR] --- ci/ciimage/ubuntu-rolling/install.sh | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/ci/ciimage/ubuntu-rolling/install.sh b/ci/ciimage/ubuntu-rolling/install.sh index e1747034fe36..63e497073ad9 100755 --- a/ci/ciimage/ubuntu-rolling/install.sh +++ b/ci/ciimage/ubuntu-rolling/install.sh @@ -27,6 +27,7 @@ pkgs=( bindgen itstool openjdk-11-jre + jq ) sed -i '/^Types: deb/s/deb/deb deb-src/' /etc/apt/sources.list.d/ubuntu.sources @@ -58,6 +59,29 @@ source "$HOME/.cargo/env" rustup target add x86_64-pc-windows-gnu rustup target add arm-unknown-linux-gnueabihf +# Zig +# Use the GitHub API to get the latest release information +LATEST_RELEASE=$(wget -qO- "https://api.github.com/repos/ziglang/zig/releases/latest") +ZIGVER=$(echo "$LATEST_RELEASE" | jq -r '.tag_name') +ZIG_BASE="zig-linux-x86_64-$ZIGVER" +wget "https://ziglang.org/download/$ZIGVER/$ZIG_BASE.tar.xz" +tar xf "$ZIG_BASE.tar.xz" +rm -rf "$ZIG_BASE.tar.xz" +cd "$ZIG_BASE" + +# As mentioned in the Zig readme, the binary and files under lib can be copied +# https://github.com/ziglang/zig?tab=readme-ov-file#installation +mv zig /usr/bin +mv lib /usr/lib/zig + +# Copy the LICENSE +mkdir -p /usr/share/doc/zig +cp LICENSE /usr/share/doc/zig + +# Remove what's left of the directory +cd .. +rm -rf "$ZIG_BASE" + # cleanup apt-get -y clean apt-get -y autoclean From 21eda4dd3b0c497daa44cb0afe370520805e4735 Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Thu, 25 Jul 2024 12:33:47 -0400 Subject: [PATCH 101/302] CI: mark arch as skipping frameworks/libgcrypt They have recently upgraded to libgcrypt 1.11 and it has inherited the gpg suite migration to pkg-config. --- test cases/frameworks/24 libgcrypt/test.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test cases/frameworks/24 libgcrypt/test.json b/test cases/frameworks/24 libgcrypt/test.json index 23af7d93189d..9c282daa86e7 100644 --- a/test cases/frameworks/24 libgcrypt/test.json +++ b/test cases/frameworks/24 libgcrypt/test.json @@ -1,3 +1,3 @@ { - "expect_skip_on_jobname": ["azure", "cygwin", "msys2"] + "expect_skip_on_jobname": ["arch", "azure", "cygwin", "msys2"] } From 02e4138e102decfae694d6bc8b4e0e6d4a4db8c7 Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Tue, 6 Aug 2024 01:54:28 -0400 Subject: [PATCH 102/302] Revert "minstall: update symlink install message presentation" This reverts commit 3587786a3cf5dd06aa4cab2b6abb36bfd7c7eca0. No unicode, thanks. Fixes #13519 --- mesonbuild/minstall.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/minstall.py b/mesonbuild/minstall.py index 418124c64512..e5901c45ae85 100644 --- a/mesonbuild/minstall.py +++ b/mesonbuild/minstall.py @@ -442,7 +442,7 @@ def do_symlink(self, target: str, link: str, destdir: str, full_dst_dir: str, al raise MesonException(f'Destination {link!r} already exists and is not a symlink') self.remove(link) if not self.printed_symlink_error: - self.log(f'Installing symlink: {link} → {target}') + self.log(f'Installing symlink pointing to {target} to {link}') try: self.symlink(target, link, target_is_directory=os.path.isdir(abs_target)) except (NotImplementedError, OSError): From 0579c42182f1cf0c2bedca2b982e2b97a5fcd07b Mon Sep 17 00:00:00 2001 From: Remi Thebault Date: Thu, 18 May 2023 20:53:13 +0200 Subject: [PATCH 103/302] dependencies/dub: Correctly handle dub >= 1.35 as well as older dub - check version of DUB for compatibility with Meson - use "cacheArtifactPath" to locate DUB libraries in the cache - propose `dub build --deep` command to Meson users for missing DUB packages Depending on DUB version, it will look either in the old cache structure or use this new `dub describe` entry. --- mesonbuild/dependencies/dub.py | 224 +++++++++++++++++++++++---------- 1 file changed, 157 insertions(+), 67 deletions(-) diff --git a/mesonbuild/dependencies/dub.py b/mesonbuild/dependencies/dub.py index 0d25c31352ec..1c904ab2a5af 100644 --- a/mesonbuild/dependencies/dub.py +++ b/mesonbuild/dependencies/dub.py @@ -15,13 +15,59 @@ import typing as T if T.TYPE_CHECKING: + from typing_extensions import TypedDict + from ..environment import Environment + # Definition of what `dub describe` returns (only the fields used by Meson) + class DubDescription(TypedDict): + platform: T.List[str] + architecture: T.List[str] + buildType: str + packages: T.List[DubPackDesc] + targets: T.List[DubTargetDesc] + + class DubPackDesc(TypedDict): + name: str + version: str + active: bool + configuration: str + path: str + targetType: str + targetFileName: str + + class DubTargetDesc(TypedDict): + rootPackage: str + linkDependencies: T.List[str] + buildSettings: DubBuildSettings + cacheArtifactPath: str + + class DubBuildSettings(TypedDict): + importPaths: T.List[str] + stringImportPaths: T.List[str] + versions: T.List[str] + mainSourceFile: str + sourceFiles: T.List[str] + dflags: T.List[str] + libs: T.List[str] + lflags: T.List[str] + + class FindTargetEntry(TypedDict): + search: str + artifactPath: str class DubDependency(ExternalDependency): # dub program and version class_dubbin: T.Optional[T.Tuple[ExternalProgram, str]] = None class_dubbin_searched = False + class_cache_dir = '' + + # Map Meson Compiler ID's to Dub Compiler ID's + _ID_MAP: T.Mapping[str, str] = { + 'dmd': 'dmd', + 'gcc': 'gdc', + 'llvm': 'ldc', + } def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]): super().__init__(DependencyTypeName('dub'), environment, kwargs, language='d') @@ -48,11 +94,20 @@ def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T. assert isinstance(self.dubbin, ExternalProgram) - # Check if Dub version is compatible with Meson - if version_compare(dubver, '>1.31.1'): + # Check if Dub's compatibility with Meson + self._search_in_cache = version_compare(dubver, '<=1.31.1') + self._use_cache_describe = version_compare(dubver, '>=1.35.0') + self._dub_has_build_deep = version_compare(dubver, '>=1.35.0') + + if not self._search_in_cache and not self._use_cache_describe: if self.required: raise DependencyException( - f"DUB version {dubver} is not compatible with Meson (can't locate artifacts in Dub cache)") + f'DUB version {dubver} is not compatible with Meson' + " (can't locate artifacts in DUB's cache). Upgrade to Dub >= 1.35.") + else: + mlog.warning(f'DUB dependency {name} not found because Dub {dubver} ' + "is not compatible with Meson. (Can't locate artifacts in DUB's cache)." + ' Upgrade to Dub >= 1.35') self.is_found = False return @@ -80,6 +135,20 @@ def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T. elif dub_buildtype == 'minsize': dub_buildtype = 'release' + # A command that might be useful in case of missing DUB package + def dub_build_deep_command() -> str: + if self._dub_has_build_deep: + cmd = ['dub', 'build', '--deep'] + else: + cmd = ['dub', 'run', '--yes', 'dub-build-deep', '--'] + + return join_args(cmd + [ + main_pack_spec, + '--arch=' + dub_arch, + '--compiler=' + self.compiler.get_exelist()[-1], + '--build=' + dub_buildtype + ]) + # Ask dub for the package describe_cmd = [ 'describe', main_pack_spec, '--arch=' + dub_arch, @@ -90,37 +159,31 @@ def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T. if ret != 0: mlog.debug('DUB describe failed: ' + err) if 'locally' in err: - fetch_cmd = ['dub', 'fetch', main_pack_spec] mlog.error(mlog.bold(main_pack_spec), 'is not present locally. You may try the following command:') - mlog.log(mlog.bold(join_args(fetch_cmd))) + mlog.log(mlog.bold(dub_build_deep_command())) self.is_found = False return - # A command that might be useful in case of missing DUB package - def dub_build_deep_command() -> str: - cmd = [ - 'dub', 'run', 'dub-build-deep', '--yes', '--', main_pack_spec, - '--arch=' + dub_arch, '--compiler=' + self.compiler.get_exelist()[-1], - '--build=' + dub_buildtype - ] - return join_args(cmd) - - dub_comp_id = self.compiler.get_id().replace('llvm', 'ldc').replace('gcc', 'gdc') - description = json.loads(res) + dub_comp_id = self._ID_MAP[self.compiler.get_id()] + description: DubDescription = json.loads(res) self.compile_args = [] self.link_args = self.raw_link_args = [] show_buildtype_warning = False - def find_package_target(pkg: T.Dict[str, str]) -> bool: + # collect all targets + targets = {t['rootPackage']: t for t in description['targets']} + + def find_package_target(pkg: DubPackDesc) -> bool: nonlocal show_buildtype_warning # try to find a static library in a DUB folder corresponding to # version, configuration, compiler, arch and build-type # if can find, add to link_args. # link_args order is meaningful, so this function MUST be called in the right order pack_id = f'{pkg["name"]}@{pkg["version"]}' - (tgt_file, compatibilities) = self._find_compatible_package_target(description, pkg, dub_comp_id) + tgt_desc = targets[pkg['name']] + (tgt_file, compatibilities) = self._find_target_in_cache(description, pkg, tgt_desc, dub_comp_id) if tgt_file is None: if not compatibilities: mlog.error(mlog.bold(pack_id), 'not found') @@ -133,7 +196,7 @@ def find_package_target(pkg: T.Dict[str, str]) -> bool: mlog.error(mlog.bold(pack_id), 'found but not compiled for', mlog.bold(dub_arch)) elif 'platform' not in compatibilities: mlog.error(mlog.bold(pack_id), 'found but not compiled for', - mlog.bold(description['platform'].join('.'))) + mlog.bold('.'.join(description['platform']))) elif 'configuration' not in compatibilities: mlog.error(mlog.bold(pack_id), 'found but not compiled for the', mlog.bold(pkg['configuration']), 'configuration') @@ -161,7 +224,7 @@ def find_package_target(pkg: T.Dict[str, str]) -> bool: # 1 self.is_found = False - packages = {} + packages: T.Dict[str, DubPackDesc] = {} for pkg in description['packages']: packages[pkg['name']] = pkg @@ -185,11 +248,6 @@ def find_package_target(pkg: T.Dict[str, str]) -> bool: self.version = pkg['version'] self.pkg = pkg - # collect all targets - targets = {} - for tgt in description['targets']: - targets[tgt['rootPackage']] = tgt - if name not in targets: self.is_found = False if self.pkg['targetType'] == 'sourceLibrary': @@ -291,13 +349,22 @@ def find_package_target(pkg: T.Dict[str, str]) -> bool: # compiler, architecture, configuration... # It returns (target|None, {compatibilities}) # If None is returned for target, compatibilities will list what other targets were found without full compatibility - def _find_compatible_package_target(self, jdesc: T.Dict[str, str], jpack: T.Dict[str, str], dub_comp_id: str) -> T.Tuple[str, T.Set[str]]: - dub_build_path = os.path.join(jpack['path'], '.dub', 'build') + def _find_target_in_cache(self, desc: DubDescription, pkg_desc: DubPackDesc, + tgt_desc: DubTargetDesc, dub_comp_id: str + ) -> T.Tuple[T.Optional[str], T.Set[str]]: + mlog.debug('Searching in DUB cache for compatible', pkg_desc['targetFileName']) + + # recent DUB versions include a direct path to a compatible cached artifact + if self._use_cache_describe: + tgt_file = tgt_desc['cacheArtifactPath'] + if os.path.exists(tgt_file): + return (tgt_file, {'configuration', 'platform', 'arch', 'compiler', 'compiler_version', 'build_type'}) + else: + return (None, set()) - if not os.path.exists(dub_build_path): - return (None, None) + assert self._search_in_cache - # try to find a dir like library-debug-linux.posix-x86_64-ldc_2081-EF934983A3319F8F8FF2F0E107A363BA + # try to find a string like library-debug-linux.posix-x86_64-ldc_2081-EF934983A3319F8F8FF2F0E107A363BA # fields are: # - configuration @@ -307,40 +374,16 @@ def _find_compatible_package_target(self, jdesc: T.Dict[str, str], jpack: T.Dict # - compiler id (dmd, ldc, gdc) # - compiler version or frontend id or frontend version? - conf = jpack['configuration'] - build_type = jdesc['buildType'] - platforms = jdesc['platform'] - archs = jdesc['architecture'] - - # Get D frontend version implemented in the compiler, or the compiler version itself - # gdc doesn't support this - comp_versions = [] - - if dub_comp_id != 'gdc': - comp_versions.append(self.compiler.version) - - ret, res = self._call_compbin(['--version'])[0:2] - if ret != 0: - mlog.error('Failed to run {!r}', mlog.bold(dub_comp_id)) - return (None, None) - d_ver_reg = re.search('v[0-9].[0-9][0-9][0-9].[0-9]', res) # Ex.: v2.081.2 - - if d_ver_reg is not None: - frontend_version = d_ver_reg.group() - frontend_id = frontend_version.rsplit('.', 1)[0].replace( - 'v', '').replace('.', '') # Fix structure. Ex.: 2081 - comp_versions.extend([frontend_version, frontend_id]) - - compatibilities: T.Set[str] = set() + comp_versions = self._get_comp_versions_to_find(dub_comp_id) # build_type is not in check_list because different build types might be compatible. # We do show a WARNING that the build type is not the same. # It might be critical in release builds, and acceptable otherwise - check_list = ('configuration', 'platform', 'arch', 'compiler', 'compiler_version') - - for entry in os.listdir(dub_build_path): + check_list = {'configuration', 'platform', 'arch', 'compiler', 'compiler_version'} + compatibilities: T.Set[str] = set() - target = os.path.join(dub_build_path, entry, jpack['targetFileName']) + for entry in self._cache_entries(pkg_desc): + target = entry['artifactPath'] if not os.path.exists(target): # unless Dub and Meson are racing, the target file should be present # when the directory is present @@ -350,33 +393,80 @@ def _find_compatible_package_target(self, jdesc: T.Dict[str, str], jpack: T.Dict # we build a new set for each entry, because if this target is returned # we want to return only the compatibilities associated to this target # otherwise we could miss the WARNING about build_type - comps = set() + comps: T.Set[str] = set() + + search = entry['search'] + + mlog.debug('searching compatibility in ' + search) + mlog.debug('compiler_versions', comp_versions) - if conf in entry: + if pkg_desc['configuration'] in search: comps.add('configuration') - if build_type in entry: + if desc['buildType'] in search: comps.add('build_type') - if all(platform in entry for platform in platforms): + if all(platform in search for platform in desc['platform']): comps.add('platform') - if all(arch in entry for arch in archs): + if all(arch in search for arch in desc['architecture']): comps.add('arch') - if dub_comp_id in entry: + if dub_comp_id in search: comps.add('compiler') - if dub_comp_id == 'gdc' or any(cv in entry for cv in comp_versions): + if not comp_versions or any(cv in search for cv in comp_versions): comps.add('compiler_version') - if all(key in comps for key in check_list): + if check_list.issubset(comps): + mlog.debug('Found', target) return (target, comps) else: compatibilities = set.union(compatibilities, comps) return (None, compatibilities) + def _cache_entries(self, pkg_desc: DubPackDesc) -> T.List[FindTargetEntry]: + # the "old" cache is the `.dub` directory in every package of ~/.dub/packages + dub_build_path = os.path.join(pkg_desc['path'], '.dub', 'build') + + if not os.path.exists(dub_build_path): + mlog.warning('No such cache folder:', dub_build_path) + return [] + + mlog.debug('Checking in DUB cache folder', dub_build_path) + + return [ + { + 'search': dir_entry, + 'artifactPath': os.path.join(dub_build_path, dir_entry, pkg_desc['targetFileName']) + } + for dir_entry in os.listdir(dub_build_path) + ] + + def _get_comp_versions_to_find(self, dub_comp_id: str) -> T.List[str]: + # Get D frontend version implemented in the compiler, or the compiler version itself + # gdc doesn't support this + + if dub_comp_id == 'gdc': + return [] + + comp_versions = [self.compiler.version] + + ret, res = self._call_compbin(['--version'])[0:2] + if ret != 0: + mlog.error('Failed to run', mlog.bold(' '.join(self.dubbin.get_command() + ['--version']))) + return [] + d_ver_reg = re.search('v[0-9].[0-9][0-9][0-9].[0-9]', res) # Ex.: v2.081.2 + + if d_ver_reg is not None: + frontend_version = d_ver_reg.group() + frontend_id = frontend_version.rsplit('.', 1)[0].replace( + 'v', '').replace('.', '') # Fix structure. Ex.: 2081 + comp_versions.extend([frontend_version, frontend_id]) + + return comp_versions + def _call_dubbin(self, args: T.List[str], env: T.Optional[T.Dict[str, str]] = None) -> T.Tuple[int, str, str]: assert isinstance(self.dubbin, ExternalProgram) p, out, err = Popen_safe(self.dubbin.get_command() + args, env=env) From 5035726fa86cf90e8871315b0386b43ec565331a Mon Sep 17 00:00:00 2001 From: Remi Thebault Date: Thu, 18 May 2023 21:20:12 +0200 Subject: [PATCH 104/302] modules/dlang: Use the DubDependency.class_dubbin correctly Which was broken because of DubDependency.class_dubbin typing change. Passed under radar because Dub tests were deactivated in the same PR. --- mesonbuild/modules/dlang.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mesonbuild/modules/dlang.py b/mesonbuild/modules/dlang.py index 34fea9081f85..966b0703d417 100644 --- a/mesonbuild/modules/dlang.py +++ b/mesonbuild/modules/dlang.py @@ -28,8 +28,8 @@ def __init__(self, interpreter): }) def _init_dub(self, state): - if DlangModule.class_dubbin is None: - self.dubbin = DubDependency.class_dubbin + if DlangModule.class_dubbin is None and DubDependency.class_dubbin is not None: + self.dubbin = DubDependency.class_dubbin[0] DlangModule.class_dubbin = self.dubbin else: self.dubbin = DlangModule.class_dubbin From 29176464defade51f18a316a5d0b0c9642e0931e Mon Sep 17 00:00:00 2001 From: Remi Thebault Date: Thu, 18 May 2023 21:20:31 +0200 Subject: [PATCH 105/302] reactivate dub tests Closes: https://github.com/mesonbuild/meson/pull/12143 --- test cases/d/11 dub/meson.build | 7 +++++-- test cases/d/14 dub with deps/meson.build | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/test cases/d/11 dub/meson.build b/test cases/d/11 dub/meson.build index 3bb3d56c0d91..91955710e709 100644 --- a/test cases/d/11 dub/meson.build +++ b/test cases/d/11 dub/meson.build @@ -1,12 +1,15 @@ project('dub-example', 'd') -error('MESON_SKIP_TEST: Dub support is broken at the moment (#11773)') - dub_exe = find_program('dub', required : false) if not dub_exe.found() error('MESON_SKIP_TEST: Dub not found') endif +dub_ver = dub_exe.version() +if dub_ver.version_compare('>1.31.1') and dub_ver.version_compare('<1.35.0') + error('MESON_SKIP_TEST: Incompatible Dub version ' + dub_ver) +endif + urld_dep = dependency('urld', method: 'dub') test_exe = executable('test-urld', 'test.d', dependencies: urld_dep) diff --git a/test cases/d/14 dub with deps/meson.build b/test cases/d/14 dub with deps/meson.build index c8e472bffc3d..2e3bce87d37d 100644 --- a/test cases/d/14 dub with deps/meson.build +++ b/test cases/d/14 dub with deps/meson.build @@ -1,12 +1,15 @@ project('dub-with-deps-example', ['d']) -error('MESON_SKIP_TEST: Dub support is broken at the moment (#11773)') - dub_exe = find_program('dub', required : false) if not dub_exe.found() error('MESON_SKIP_TEST: Dub not found') endif +dub_ver = dub_exe.version() +if dub_ver.version_compare('>1.31.1') and dub_ver.version_compare('<1.35.0') + error('MESON_SKIP_TEST: Incompatible Dub version') +endif + if meson.get_compiler('d').get_id() == 'gcc' error('MESON_SKIP_TEST: can\'t build dependencies with GDC') elif meson.get_compiler('d').get_id() == 'llvm' From a5211a15207a2e6e30e213c5530a5d1bf5c2531c Mon Sep 17 00:00:00 2001 From: Sam James Date: Tue, 6 Aug 2024 06:53:05 +0100 Subject: [PATCH 106/302] ci: fix dub tests on Windows This fixes a pesky failure in vs2019 vc2019x64ninja for d/11 dub: ``` Searching in DUB cache for compatible urld.lib WARNING: No such cache folder: C:\Users\VssAdministrator\AppData\Local\dub\packages\urld-2.1.1\urld\.dub\build ERROR: urld@2.1.1 not found You may try the following command to install the necessary DUB libraries: dub run --yes dub-build-deep -- urld --arch=x86_64 --compiler=dmd --build=debug Run-time dependency urld found: NO test cases\d\11 dub\meson.build:13:11: ERROR: Dependency "urld" not found ``` Follow dub's advice by installing urld in ci/run.ps1 before the testsuite; we were already doing this for ubuntu, opensuse, and even recommending it in our docs before now: * ci/ciimage/ubuntu-rolling/install.sh * ci/ciimage/opensuse/install.sh * docs/markdown/Dependencies.md We also bump to 'ci4' which has newer D added (from the cidata repo). --- ci/run.ps1 | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/ci/run.ps1 b/ci/run.ps1 index 596253fe2d62..3fc06fdaf1b1 100644 --- a/ci/run.ps1 +++ b/ci/run.ps1 @@ -50,7 +50,7 @@ function DownloadFile([String] $Source, [String] $Destination) { if (($env:backend -eq 'ninja') -and ($env:arch -ne 'arm64')) { $dmd = $true } else { $dmd = $false } -DownloadFile -Source https://github.com/mesonbuild/cidata/releases/download/ci3/ci_data.zip -Destination $env:AGENT_WORKFOLDER\ci_data.zip +DownloadFile -Source https://github.com/mesonbuild/cidata/releases/download/ci4/ci_data.zip -Destination $env:AGENT_WORKFOLDER\ci_data.zip echo "Extracting ci_data.zip" Expand-Archive $env:AGENT_WORKFOLDER\ci_data.zip -DestinationPath $env:AGENT_WORKFOLDER\ci_data & "$env:AGENT_WORKFOLDER\ci_data\install.ps1" -Arch $env:arch -Compiler $env:compiler -Boost $true -DMD $dmd @@ -87,6 +87,44 @@ if ($env:backend -eq 'ninja') { MSBuild /version } +# This mirrors the D logic in cidata/build_win32.sh +if ($dmd) { + if ($Arch -eq "x64") { + $dmdArch = "x86_64" + } else { + $dmdArch = "x86_mscoff" + } + + $ScriptDir = Split-Path $script:MyInvocation.MyCommand.Path + $env:Path = "$ScriptDir;$env:Path" + $dmd_bin = Join-Path $ScriptDir "dmd2\windows\bin" + $env:Path = $env:Path + ";" + $dmd_bin + + $i = 1 + while ($i -le 5) { + # Needed for d/11 dub to use the 'urld' library + dub run --yes dub-build-deep -- urld --arch=$dmdArch --compiler=dmd --build=debug + if ($LastExitCode -eq 0) { + break + } + + $i = $i + 1 + Start-Sleep -Seconds 2 + } + + $i = 1 + while ($i -le 5) { + # XXX: Sometimes (?) we need this older version when the whole testsuite is run + dub run --yes dub-build-deep -- urld@2.1.1 --arch=$dmdArch --compiler=dmd --build=debug + if ($LastExitCode -eq 0) { + break + } + + $i = $i + 1 + Start-Sleep -Seconds 2 + } +} + echo "" echo "Python version:" python --version From 3702b4bdb3645a2e7ef5a067ed21ad6accf0bc93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= Date: Mon, 13 May 2024 15:38:50 +0200 Subject: [PATCH 107/302] compilers: change get_argument_syntax to static method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows to get this fixed value before the class is initialized. Signed-off-by: Kacper Michajłow --- mesonbuild/compilers/asm.py | 3 ++- mesonbuild/compilers/compilers.py | 3 ++- mesonbuild/compilers/mixins/gnu.py | 3 ++- mesonbuild/compilers/mixins/visualstudio.py | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/mesonbuild/compilers/asm.py b/mesonbuild/compilers/asm.py index cefda765f881..8cd5e28dc47f 100644 --- a/mesonbuild/compilers/asm.py +++ b/mesonbuild/compilers/asm.py @@ -158,7 +158,8 @@ class MasmCompiler(Compiler): def get_compile_only_args(self) -> T.List[str]: return ['/c'] - def get_argument_syntax(self) -> str: + @staticmethod + def get_argument_syntax() -> str: return 'msvc' def needs_static_linker(self) -> bool: diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 3dcf496d4bbb..b9605ccaedcb 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -963,7 +963,8 @@ def get_pie_args(self) -> T.List[str]: def get_pie_link_args(self) -> T.List[str]: return self.linker.get_pie_args() - def get_argument_syntax(self) -> str: + @staticmethod + def get_argument_syntax() -> str: """Returns the argument family type. Compilers fall into families if they try to emulate the command line diff --git a/mesonbuild/compilers/mixins/gnu.py b/mesonbuild/compilers/mixins/gnu.py index 7b72496ef32c..62f55543a0a7 100644 --- a/mesonbuild/compilers/mixins/gnu.py +++ b/mesonbuild/compilers/mixins/gnu.py @@ -420,7 +420,8 @@ def gen_vs_module_defs_args(self, defsfile: str) -> T.List[str]: # For other targets, discard the .def file. return [] - def get_argument_syntax(self) -> str: + @staticmethod + def get_argument_syntax() -> str: return 'gcc' def get_profile_generate_args(self) -> T.List[str]: diff --git a/mesonbuild/compilers/mixins/visualstudio.py b/mesonbuild/compilers/mixins/visualstudio.py index 4ec22a0f28d0..f095b95e27a9 100644 --- a/mesonbuild/compilers/mixins/visualstudio.py +++ b/mesonbuild/compilers/mixins/visualstudio.py @@ -362,7 +362,8 @@ def has_func_attribute(self, name: str, env: 'Environment') -> T.Tuple[bool, boo # false without compiling anything return name in {'dllimport', 'dllexport'}, False - def get_argument_syntax(self) -> str: + @staticmethod + def get_argument_syntax() -> str: return 'msvc' def symbols_have_underscore_prefix(self, env: 'Environment') -> bool: From 43b80e02ce0e87dfcf069111e62ad8eff4435d6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= Date: Sat, 22 Apr 2023 00:09:13 +0200 Subject: [PATCH 108/302] linkers: Fix RSP syntax for linkers invoked with clang MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: #8981 Fixes: 2be074b1d445fcd30535bcf7518f8ce0738bcbf3 Signed-off-by: Kacper Michajłow --- mesonbuild/linkers/detect.py | 15 ++++++++++++--- mesonbuild/linkers/linkers.py | 16 ++++++++++------ 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/mesonbuild/linkers/detect.py b/mesonbuild/linkers/detect.py index cd3c7b2efd0f..0dce5ad501b1 100644 --- a/mesonbuild/linkers/detect.py +++ b/mesonbuild/linkers/detect.py @@ -3,6 +3,7 @@ from __future__ import annotations +from .base import RSPFileSyntax from .. import mlog from ..mesonlib import ( EnvironmentException, @@ -40,6 +41,11 @@ def guess_win_linker(env: 'Environment', compiler: T.List[str], comp_class: T.Ty from . import linkers env.coredata.add_lang_args(comp_class.language, comp_class, for_machine, env) + if invoked_directly or comp_class.get_argument_syntax() == 'msvc': + rsp_syntax = RSPFileSyntax.MSVC + else: + rsp_syntax = RSPFileSyntax.GCC + # Explicitly pass logo here so that we can get the version of link.exe if not use_linker_prefix or comp_class.LINKER_PREFIX is None: check_args = ['/logo', '--version'] @@ -71,7 +77,8 @@ def guess_win_linker(env: 'Environment', compiler: T.List[str], comp_class: T.Ty elif not invoked_directly: return linkers.ClangClDynamicLinker( for_machine, override, exelist=compiler, prefix=comp_class.LINKER_PREFIX, - version=search_version(o), direct=False, machine=None) + version=search_version(o), direct=False, machine=None, + rsp_syntax=rsp_syntax) if value is not None and invoked_directly: compiler = value @@ -82,7 +89,8 @@ def guess_win_linker(env: 'Environment', compiler: T.List[str], comp_class: T.Ty return linkers.ClangClDynamicLinker( for_machine, [], prefix=comp_class.LINKER_PREFIX if use_linker_prefix else [], - exelist=compiler, version=search_version(o), direct=invoked_directly) + exelist=compiler, version=search_version(o), direct=invoked_directly, + rsp_syntax=rsp_syntax) elif 'OPTLINK' in o: # Optlink's stdout *may* begin with a \r character. return linkers.OptlinkDynamicLinker(compiler, for_machine, version=search_version(o)) @@ -97,7 +105,8 @@ def guess_win_linker(env: 'Environment', compiler: T.List[str], comp_class: T.Ty return linkers.MSVCDynamicLinker( for_machine, [], machine=target, exelist=compiler, prefix=comp_class.LINKER_PREFIX if use_linker_prefix else [], - version=search_version(out), direct=invoked_directly) + version=search_version(out), direct=invoked_directly, + rsp_syntax=rsp_syntax) elif 'GNU coreutils' in o: import shutil fullpath = shutil.which(compiler[0]) diff --git a/mesonbuild/linkers/linkers.py b/mesonbuild/linkers/linkers.py index c3750ccc372f..18157a36be63 100644 --- a/mesonbuild/linkers/linkers.py +++ b/mesonbuild/linkers/linkers.py @@ -1274,11 +1274,13 @@ def _apply_prefix(self, arg: T.Union[str, T.List[str]]) -> T.List[str]: ... def __init__(self, exelist: T.List[str], for_machine: mesonlib.MachineChoice, prefix_arg: T.Union[str, T.List[str]], always_args: T.List[str], *, - version: str = 'unknown version', direct: bool = True, machine: str = 'x86'): + version: str = 'unknown version', direct: bool = True, machine: str = 'x86', + rsp_syntax: RSPFileSyntax = RSPFileSyntax.MSVC): # There's no way I can find to make mypy understand what's going on here super().__init__(exelist, for_machine, prefix_arg, always_args, version=version) self.machine = machine self.direct = direct + self.rsp_syntax = rsp_syntax def invoked_by_compiler(self) -> bool: return not self.direct @@ -1322,7 +1324,7 @@ def import_library_args(self, implibname: str) -> T.List[str]: return self._apply_prefix(['/IMPLIB:' + implibname]) def rsp_file_syntax(self) -> RSPFileSyntax: - return RSPFileSyntax.MSVC + return self.rsp_syntax class MSVCDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker): @@ -1335,9 +1337,10 @@ def __init__(self, for_machine: mesonlib.MachineChoice, always_args: T.List[str] exelist: T.Optional[T.List[str]] = None, prefix: T.Union[str, T.List[str]] = '', machine: str = 'x86', version: str = 'unknown version', - direct: bool = True): + direct: bool = True, rsp_syntax: RSPFileSyntax = RSPFileSyntax.MSVC): super().__init__(exelist or ['link.exe'], for_machine, - prefix, always_args, machine=machine, version=version, direct=direct) + prefix, always_args, machine=machine, version=version, direct=direct, + rsp_syntax=rsp_syntax) def get_always_args(self) -> T.List[str]: return self._apply_prefix(['/release']) + super().get_always_args() @@ -1359,9 +1362,10 @@ def __init__(self, for_machine: mesonlib.MachineChoice, always_args: T.List[str] exelist: T.Optional[T.List[str]] = None, prefix: T.Union[str, T.List[str]] = '', machine: str = 'x86', version: str = 'unknown version', - direct: bool = True): + direct: bool = True, rsp_syntax: RSPFileSyntax = RSPFileSyntax.MSVC): super().__init__(exelist or ['lld-link.exe'], for_machine, - prefix, always_args, machine=machine, version=version, direct=direct) + prefix, always_args, machine=machine, version=version, direct=direct, + rsp_syntax=rsp_syntax) def get_output_args(self, outputname: str) -> T.List[str]: # If we're being driven indirectly by clang just skip /MACHINE From 81b151f61138357950330f26b601e0b345bf77fa Mon Sep 17 00:00:00 2001 From: Jonathan Schleifer Date: Sun, 4 Aug 2024 14:55:33 +0200 Subject: [PATCH 109/302] Fix compiling ObjC/ObjC++ on Windows/MinGW Co-Authored-By: L. E. Segovia --- mesonbuild/cmake/toolchain.py | 2 ++ mesonbuild/compilers/detect.py | 4 ++-- mesonbuild/compilers/mixins/clang.py | 2 ++ mesonbuild/compilers/mixins/visualstudio.py | 2 ++ mesonbuild/linkers/linkers.py | 3 +++ test cases/cmake/24 mixing languages/meson.build | 6 ++++++ .../24 mixing languages/subprojects/cmTest/CMakeLists.txt | 2 +- test cases/failing build/11 objc werror/meson.build | 3 +++ test cases/failing build/12 objcpp werror/meson.build | 3 +++ test cases/objc/1 simple/meson.build | 4 ++++ test cases/objc/2 nsstring/meson.build | 4 ++++ test cases/objc/3 objc args/meson.build | 4 ++++ test cases/objc/4 c++ project objc subproject/meson.build | 4 ++++ .../subprojects/foo/meson.build | 4 ++++ test cases/objc/5 objfw/meson.build | 4 ++++ test cases/objcpp/1 simple/meson.build | 4 ++++ test cases/objcpp/2 objc++ args/meson.build | 4 ++++ test cases/objcpp/3 objfw/meson.build | 4 ++++ 18 files changed, 60 insertions(+), 3 deletions(-) diff --git a/mesonbuild/cmake/toolchain.py b/mesonbuild/cmake/toolchain.py index 1aad0bc3b5bc..89d5d84449e0 100644 --- a/mesonbuild/cmake/toolchain.py +++ b/mesonbuild/cmake/toolchain.py @@ -188,6 +188,8 @@ def make_abs(exe: str) -> str: defaults[prefix + 'COMPILER'] = exe_list if comp_obj.get_id() == 'clang-cl': defaults['CMAKE_LINKER'] = comp_obj.get_linker_exelist() + if lang.startswith('objc') and comp_obj.get_id().startswith('clang'): + defaults[f'{prefix}FLAGS'] = ['-D__STDC__=1'] return defaults diff --git a/mesonbuild/compilers/detect.py b/mesonbuild/compilers/detect.py index c796c2f38aac..2e6b88dfc1ca 100644 --- a/mesonbuild/compilers/detect.py +++ b/mesonbuild/compilers/detect.py @@ -47,8 +47,8 @@ defaults['cpp'] = ['icl', 'cl', 'c++', 'g++', 'clang++', 'clang-cl'] # the binary flang-new will be renamed to flang in the foreseeable future defaults['fortran'] = ['ifort', 'gfortran', 'flang-new', 'flang', 'pgfortran', 'g95'] - defaults['objc'] = ['clang-cl', 'gcc'] - defaults['objcpp'] = ['clang-cl', 'g++'] + defaults['objc'] = ['clang', 'clang-cl', 'gcc'] + defaults['objcpp'] = ['clang++', 'clang-cl', 'g++'] defaults['cs'] = ['csc', 'mcs'] else: if platform.machine().lower() == 'e2k': diff --git a/mesonbuild/compilers/mixins/clang.py b/mesonbuild/compilers/mixins/clang.py index 1d286388279a..a0d3d5ffb069 100644 --- a/mesonbuild/compilers/mixins/clang.py +++ b/mesonbuild/compilers/mixins/clang.py @@ -58,6 +58,8 @@ def __init__(self, defines: T.Optional[T.Dict[str, str]]): # linkers don't have base_options. if isinstance(self.linker, AppleDynamicLinker): self.base_options.add(OptionKey('b_bitcode')) + elif isinstance(self.linker, MSVCDynamicLinker): + self.base_options.add(OptionKey('b_vscrt')) # All Clang backends can also do LLVM IR self.can_compile_suffixes.add('ll') diff --git a/mesonbuild/compilers/mixins/visualstudio.py b/mesonbuild/compilers/mixins/visualstudio.py index f095b95e27a9..78d62cb4293c 100644 --- a/mesonbuild/compilers/mixins/visualstudio.py +++ b/mesonbuild/compilers/mixins/visualstudio.py @@ -383,6 +383,8 @@ def symbols_have_underscore_prefix(self, env: 'Environment') -> bool: # As a last resort, try search in a compiled binary return self._symbols_have_underscore_prefix_searchbin(env) + def get_pie_args(self) -> T.List[str]: + return [] class MSVCCompiler(VisualStudioLikeCompiler): diff --git a/mesonbuild/linkers/linkers.py b/mesonbuild/linkers/linkers.py index 18157a36be63..d00fd7a4b139 100644 --- a/mesonbuild/linkers/linkers.py +++ b/mesonbuild/linkers/linkers.py @@ -1326,6 +1326,9 @@ def import_library_args(self, implibname: str) -> T.List[str]: def rsp_file_syntax(self) -> RSPFileSyntax: return self.rsp_syntax + def get_pie_args(self) -> T.List[str]: + return [] + class MSVCDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker): diff --git a/test cases/cmake/24 mixing languages/meson.build b/test cases/cmake/24 mixing languages/meson.build index 55d7a7d68bc9..a4662fe37c0c 100644 --- a/test cases/cmake/24 mixing languages/meson.build +++ b/test cases/cmake/24 mixing languages/meson.build @@ -7,6 +7,12 @@ if not add_languages('objc', required : false) error('MESON_SKIP_TEST: No ObjC compiler') endif +objc = meson.get_compiler('objc') +c = meson.get_compiler('c') +if c.get_argument_syntax() != objc.get_argument_syntax() + error('MESON_SKIP_TEST: cmake cannot mix compiler types on Windows') +endif + cm = import('cmake') sub_pro = cm.subproject('cmTest') diff --git a/test cases/cmake/24 mixing languages/subprojects/cmTest/CMakeLists.txt b/test cases/cmake/24 mixing languages/subprojects/cmTest/CMakeLists.txt index 80a256f0db1d..a1886115bf5f 100644 --- a/test cases/cmake/24 mixing languages/subprojects/cmTest/CMakeLists.txt +++ b/test cases/cmake/24 mixing languages/subprojects/cmTest/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) -project(cmTest) +project(cmTest LANGUAGES C OBJC) include_directories(${CMAKE_CURRENT_BINARY_DIR}) diff --git a/test cases/failing build/11 objc werror/meson.build b/test cases/failing build/11 objc werror/meson.build index 9f8e47828bbc..5e83d3850bd4 100644 --- a/test cases/failing build/11 objc werror/meson.build +++ b/test cases/failing build/11 objc werror/meson.build @@ -2,4 +2,7 @@ project('test', default_options: ['werror=true']) if not add_languages('objc', required: false) error('MESON_SKIP_TEST: Objective C not found') endif +if get_option('backend').startswith('vs') + error('MESON_SKIP_TEST: objcpp is not supported by vs backend') +endif executable('prog', 'test.m') diff --git a/test cases/failing build/12 objcpp werror/meson.build b/test cases/failing build/12 objcpp werror/meson.build index 5bc9bee2177d..ee0d7cdba850 100644 --- a/test cases/failing build/12 objcpp werror/meson.build +++ b/test cases/failing build/12 objcpp werror/meson.build @@ -2,4 +2,7 @@ project('test', default_options: ['werror=true']) if not add_languages('objcpp', required: false) error('MESON_SKIP_TEST: Objective C++ not found') endif +if get_option('backend').startswith('vs') + error('MESON_SKIP_TEST: objcpp is not supported by vs backend') +endif executable('prog', 'test.mm') diff --git a/test cases/objc/1 simple/meson.build b/test cases/objc/1 simple/meson.build index f9d5c145025e..bb45839f184f 100644 --- a/test cases/objc/1 simple/meson.build +++ b/test cases/objc/1 simple/meson.build @@ -1,4 +1,8 @@ project('objective c', 'objc', default_options: ['c_std=c99']) +if get_option('backend').startswith('vs') + error('MESON_SKIP_TEST: objc is not supported by vs backend') +endif + exe = executable('prog', 'prog.m') test('objctest', exe) diff --git a/test cases/objc/2 nsstring/meson.build b/test cases/objc/2 nsstring/meson.build index 2c483d50d687..b12710d73f71 100644 --- a/test cases/objc/2 nsstring/meson.build +++ b/test cases/objc/2 nsstring/meson.build @@ -1,5 +1,9 @@ project('nsstring', 'objc') +if get_option('backend').startswith('vs') + error('MESON_SKIP_TEST: objc is not supported by vs backend') +endif + if host_machine.system() == 'darwin' dep = dependency('appleframeworks', modules : 'Foundation') elif host_machine.system() == 'cygwin' diff --git a/test cases/objc/3 objc args/meson.build b/test cases/objc/3 objc args/meson.build index 8887d96bc7ac..dd6f50990b31 100644 --- a/test cases/objc/3 objc args/meson.build +++ b/test cases/objc/3 objc args/meson.build @@ -1,4 +1,8 @@ project('objective c args', 'objc') +if get_option('backend').startswith('vs') + error('MESON_SKIP_TEST: objc is not supported by vs backend') +endif + exe = executable('prog', 'prog.m', objc_args : ['-DMESON_TEST']) test('objective c args', exe) diff --git a/test cases/objc/4 c++ project objc subproject/meson.build b/test cases/objc/4 c++ project objc subproject/meson.build index 8a77dedce3c4..946af11f603b 100644 --- a/test cases/objc/4 c++ project objc subproject/meson.build +++ b/test cases/objc/4 c++ project objc subproject/meson.build @@ -1,5 +1,9 @@ project('master', ['cpp']) +if get_option('backend').startswith('vs') + error('MESON_SKIP_TEST: objc is not supported by vs backend') +endif + foo = subproject('foo') dep = foo.get_variable('foo_dep') diff --git a/test cases/objc/4 c++ project objc subproject/subprojects/foo/meson.build b/test cases/objc/4 c++ project objc subproject/subprojects/foo/meson.build index 2dbf8ab26764..5f4d9fd836ba 100644 --- a/test cases/objc/4 c++ project objc subproject/subprojects/foo/meson.build +++ b/test cases/objc/4 c++ project objc subproject/subprojects/foo/meson.build @@ -1,5 +1,9 @@ project('foo', ['objc']) +if get_option('backend').startswith('vs') + error('MESON_SKIP_TEST: objc is not supported by vs backend') +endif + l = static_library('foo', 'foo.m') foo_dep = declare_dependency(link_with : l) diff --git a/test cases/objc/5 objfw/meson.build b/test cases/objc/5 objfw/meson.build index 40ddb7968db4..761b49f67e9c 100644 --- a/test cases/objc/5 objfw/meson.build +++ b/test cases/objc/5 objfw/meson.build @@ -1,5 +1,9 @@ project('objfw build tests', 'objc') +if get_option('backend').startswith('vs') + error('MESON_SKIP_TEST: objc is not supported by vs backend') +endif + objfw_dep = dependency('objfw', required: false) objfwtest_dep = dependency('objfw', modules: ['ObjFWTest'], required: false) diff --git a/test cases/objcpp/1 simple/meson.build b/test cases/objcpp/1 simple/meson.build index c9a5c8498195..c3acc879ad1e 100644 --- a/test cases/objcpp/1 simple/meson.build +++ b/test cases/objcpp/1 simple/meson.build @@ -1,4 +1,8 @@ project('Objective C++', 'objcpp', default_options: 'cpp_std=c++14') +if get_option('backend').startswith('vs') + error('MESON_SKIP_TEST: objcpp is not supported by vs backend') +endif + exe = executable('objcppprog', 'prog.mm') test('objcpp', exe) diff --git a/test cases/objcpp/2 objc++ args/meson.build b/test cases/objcpp/2 objc++ args/meson.build index e0e34b0f1e17..8797b619d3e8 100644 --- a/test cases/objcpp/2 objc++ args/meson.build +++ b/test cases/objcpp/2 objc++ args/meson.build @@ -1,4 +1,8 @@ project('objective c++ args', 'objcpp') +if get_option('backend').startswith('vs') + error('MESON_SKIP_TEST: objcpp is not supported by vs backend') +endif + exe = executable('prog', 'prog.mm', objcpp_args : ['-DMESON_OBJCPP_TEST']) test('objective c++ args', exe) diff --git a/test cases/objcpp/3 objfw/meson.build b/test cases/objcpp/3 objfw/meson.build index da14681ebf1a..3fcc84dd554b 100644 --- a/test cases/objcpp/3 objfw/meson.build +++ b/test cases/objcpp/3 objfw/meson.build @@ -1,5 +1,9 @@ project('objfw build tests', 'objcpp') +if get_option('backend').startswith('vs') + error('MESON_SKIP_TEST: objcpp is not supported by vs backend') +endif + objfw_dep = dependency('objfw', required: false) objfwtest_dep = dependency('objfw', modules: ['ObjFWTest'], required: false) From 8ef4e34cae956cb48cf0d22667c6e18af1340519 Mon Sep 17 00:00:00 2001 From: Benoit Pierre Date: Sun, 10 Sep 2023 17:22:16 +0200 Subject: [PATCH 110/302] linkers: fix LLD linker response file handling Correct base classes so GNU-like linkers all default to supporting response files. --- mesonbuild/linkers/linkers.py | 6 +++--- unittests/allplatformstests.py | 9 +++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/mesonbuild/linkers/linkers.py b/mesonbuild/linkers/linkers.py index d00fd7a4b139..0b892735953c 100644 --- a/mesonbuild/linkers/linkers.py +++ b/mesonbuild/linkers/linkers.py @@ -606,6 +606,9 @@ def _apply_prefix(self, arg: T.Union[str, T.List[str]]) -> T.List[str]: ... "boot_application": "16", } + def get_accepts_rsp(self) -> bool: + return True + def get_pie_args(self) -> T.List[str]: return ['-pie'] @@ -849,9 +852,6 @@ class GnuDynamicLinker(GnuLikeDynamicLinkerMixin, PosixDynamicLinkerMixin, Dynam """Representation of GNU ld.bfd and ld.gold.""" - def get_accepts_rsp(self) -> bool: - return True - class GnuGoldDynamicLinker(GnuDynamicLinker): diff --git a/unittests/allplatformstests.py b/unittests/allplatformstests.py index 726252611fb7..e790ca493a78 100644 --- a/unittests/allplatformstests.py +++ b/unittests/allplatformstests.py @@ -5010,3 +5010,12 @@ def test_c_cpp_stds(self): # The first supported std should be selected self.setconf('-Dcpp_std=c++11,gnu++11,vc++11') self.assertEqual(self.getconf('cpp_std'), 'c++11') + + def test_rsp_support(self): + env = get_fake_env() + cc = detect_c_compiler(env, MachineChoice.HOST) + has_rsp = cc.linker.id in { + 'ld.bfd', 'ld.gold', 'ld.lld', 'ld.mold', 'ld.qcld', 'ld.wasm', + 'link', 'lld-link', 'mwldarm', 'mwldeppc', 'optlink', 'xilink', + } + self.assertEqual(cc.linker.get_accepts_rsp(), has_rsp) From db22551ed9d2dd7889abea01cc1c7bba02bf1c75 Mon Sep 17 00:00:00 2001 From: "Dmitry V. Levin" Date: Mon, 12 Aug 2024 08:00:00 +0000 Subject: [PATCH 111/302] docs: fix a few grammar and formatting issues --- docs/markdown/Build-options.md | 2 +- docs/markdown/Configuration.md | 4 ++-- docs/markdown/Release-notes-for-0.63.0.md | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/markdown/Build-options.md b/docs/markdown/Build-options.md index 56b2693b8401..d615db6891b0 100644 --- a/docs/markdown/Build-options.md +++ b/docs/markdown/Build-options.md @@ -155,7 +155,7 @@ option('o5', type: 'boolean', deprecated: {'enabled': 'true', 'disabled': 'false ``` Since *0.63.0* the `deprecated` keyword argument can take the name of a new option -that replace this option. In that case, setting a value on the deprecated option +that replaces this option. In that case, setting a value on the deprecated option will set the value on both the old and new names, assuming they accept the same values. diff --git a/docs/markdown/Configuration.md b/docs/markdown/Configuration.md index 48f071e6c9e4..fd19e0a699bd 100644 --- a/docs/markdown/Configuration.md +++ b/docs/markdown/Configuration.md @@ -87,7 +87,7 @@ endif ## Configuring without an input file If the input file is not defined then Meson will generate a header -file all the entries in the configuration data object. The +file with all the entries in the configuration data object. The replacements are the same as when generating `#mesondefine` entries: ```meson @@ -116,7 +116,7 @@ Will produce: ## Dealing with file encodings The default Meson file encoding to configure files is utf-8. If you -need to configure a file that is not utf-8 encoded the encoding +need to configure a file that is not utf-8 encoded the `encoding` keyword will allow you to specify which file encoding to use. It is however strongly advised to convert your non utf-8 file to utf-8 whenever possible. Supported file encodings are those of python3, see diff --git a/docs/markdown/Release-notes-for-0.63.0.md b/docs/markdown/Release-notes-for-0.63.0.md index 3b47ff4eb634..ed0239e5cb20 100644 --- a/docs/markdown/Release-notes-for-0.63.0.md +++ b/docs/markdown/Release-notes-for-0.63.0.md @@ -47,7 +47,7 @@ ptr_size = meson.get_compiler('d').sizeof('void*') ## Deprecate an option and replace it with a new one The `deprecated` keyword argument can now take the name of a new option -that replace this option. In that case, setting a value on the deprecated option +that replaces this option. In that case, setting a value on the deprecated option will set the value on both the old and new names, assuming they accept the same values. From 85e92331cba16f038115be241e87634f69f74e78 Mon Sep 17 00:00:00 2001 From: Junjie Mao Date: Thu, 15 Aug 2024 19:44:08 +0800 Subject: [PATCH 112/302] compilers: do not strip '-isystem' from C build arguments Meson accidentally strips '-isystem' from C build args like ['-isystem', '/path/to/headers'] if the compiler includes the current working directory in the header search paths. The root cause is that '-isystem'[8:] evaluates to an empty string and os.path.realpath('') returns the absolute path to the current working directory, causing meson to think that '-isystem' specifies a default include path. Different compiler versions varies whether the current working directory is in its search paths. For example, on Ubuntu 21.04: # gcc -xc -v -E - gcc version 10.3.0 (Ubuntu 10.3.0-1ubuntu1) #include "..." search starts here: #include <...> search starts here: . /usr/lib/gcc/x86_64-linux-gnu/10/include /usr/local/include /usr/include/x86_64-linux-gnu /usr/include End of search list. While on Ubuntu 24.04: # gcc -xc -v -E - gcc version 13.2.0 (Ubuntu 13.2.0-23ubuntu4) ... #include "..." search starts here: #include <...> search starts here: /usr/lib/gcc/x86_64-linux-gnu/13/include /usr/local/include /usr/include/x86_64-linux-gnu /usr/include End of search list. Do not check the '-isystem=' and '-isystem/path/to/header' cases when the option is '-isystem' but the path that follows is not a default search path. Signed-off-by: Junjie Mao --- mesonbuild/compilers/mixins/clike.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mesonbuild/compilers/mixins/clike.py b/mesonbuild/compilers/mixins/clike.py index 9f5fc505277d..60a91f35557c 100644 --- a/mesonbuild/compilers/mixins/clike.py +++ b/mesonbuild/compilers/mixins/clike.py @@ -98,12 +98,12 @@ def to_native(self, copy: bool = False) -> T.List[str]: continue # Remove the -isystem and the path if the path is a default path - if (each == '-isystem' and - i < (len(new) - 1) and - self._cached_realpath(new[i + 1]) in real_default_dirs): - bad_idx_list += [i, i + 1] - elif each.startswith('-isystem=') and self._cached_realpath(each[9:]) in real_default_dirs: - bad_idx_list += [i] + if each == '-isystem': + if i < (len(new) - 1) and self._cached_realpath(new[i + 1]) in real_default_dirs: + bad_idx_list += [i, i + 1] + elif each.startswith('-isystem='): + if self._cached_realpath(each[9:]) in real_default_dirs: + bad_idx_list += [i] elif self._cached_realpath(each[8:]) in real_default_dirs: bad_idx_list += [i] for i in reversed(bad_idx_list): From 67b238d6161d79674dc513cafed5236eb255dddd Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Wed, 17 Jul 2024 09:26:50 -0700 Subject: [PATCH 113/302] unittests: fix git dist test on Windows with Python < 3.8 pathlib.Path objects are not supported in subprocess calls on Windows before Python 3.8, so we must convert to a string. --- test cases/unit/35 dist script/subprojects/sub/dist-script.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 5f1b4a12443a..5166a26f54d0 100644 --- a/test cases/unit/35 dist script/subprojects/sub/dist-script.py +++ b/test cases/unit/35 dist script/subprojects/sub/dist-script.py @@ -12,7 +12,7 @@ mesonrewrite = shlex.split(os.environ['MESONREWRITE']) rewrite_cmd = ['kwargs', 'set', 'project', '/', 'version', 'release'] -subprocess.run([*mesonrewrite, '-s', source_root, *rewrite_cmd], check=True) +subprocess.run([*mesonrewrite, '-s', str(source_root.absolute()), *rewrite_cmd], check=True) modfile = source_root / 'prog.c' with modfile.open('w') as f: From 5d322659567f004a444e0133ec40a61df5a46775 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 16 Jul 2024 11:14:06 -0700 Subject: [PATCH 114/302] unittests: use os.environ.get for MESON_UNIT_TEST_BACKEND Being unset shouldn't cause a ton of our tests to fail. --- unittests/baseplatformtests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unittests/baseplatformtests.py b/unittests/baseplatformtests.py index 5976335144c9..7ba2aaed4fed 100644 --- a/unittests/baseplatformtests.py +++ b/unittests/baseplatformtests.py @@ -52,7 +52,7 @@ def setUp(self): src_root = str(PurePath(__file__).parents[1]) self.src_root = src_root # Get the backend - self.backend_name = os.environ['MESON_UNIT_TEST_BACKEND'] + self.backend_name = os.environ.get('MESON_UNIT_TEST_BACKEND', 'ninja') backend_type = 'vs' if self.backend_name.startswith('vs') else self.backend_name self.backend = getattr(Backend, backend_type) self.meson_args = ['--backend=' + self.backend_name] From 5eb4d7336b6ab6e6bf1900bc4140783957052bc9 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 16 Jul 2024 11:19:39 -0700 Subject: [PATCH 115/302] unittests: use mock.patch.dict to deal with os.environ --- unittests/allplatformstests.py | 1 + unittests/baseplatformtests.py | 4 +--- unittests/helpers.py | 14 +++++--------- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/unittests/allplatformstests.py b/unittests/allplatformstests.py index e790ca493a78..dac7f97971d7 100644 --- a/unittests/allplatformstests.py +++ b/unittests/allplatformstests.py @@ -1055,6 +1055,7 @@ def test_internal_include_order(self): # target internal dependency wrong include_directories: source dir self.assertPathBasenameEqual(incs[8], 'sub2') + @mock.patch.dict(os.environ) def test_compiler_detection(self): ''' Test that automatic compiler detection and setting from the environment diff --git a/unittests/baseplatformtests.py b/unittests/baseplatformtests.py index 7ba2aaed4fed..ae012dadaabb 100644 --- a/unittests/baseplatformtests.py +++ b/unittests/baseplatformtests.py @@ -42,6 +42,7 @@ # e.g. for assertXXX helpers. __unittest = True +@mock.patch.dict(os.environ) class BasePlatformTests(TestCase): prefix = '/usr' libdir = 'lib' @@ -81,7 +82,6 @@ def setUp(self): self.darwin_test_dir = os.path.join(src_root, 'test cases/darwin') # Misc stuff - self.orig_env = os.environ.copy() if self.backend is Backend.ninja: self.no_rebuild_stdout = ['ninja: no work to do.', 'samu: nothing to do'] else: @@ -147,8 +147,6 @@ def tearDown(self): windows_proof_rmtree(path) except FileNotFoundError: pass - os.environ.clear() - os.environ.update(self.orig_env) super().tearDown() def _run(self, command, *, workdir=None, override_envvars: T.Optional[T.Mapping[str, str]] = None, stderr=True): diff --git a/unittests/helpers.py b/unittests/helpers.py index 2f97ab1d4f91..5cf8845b21b5 100644 --- a/unittests/helpers.py +++ b/unittests/helpers.py @@ -12,6 +12,7 @@ import zipfile from pathlib import Path from contextlib import contextmanager +from unittest import mock from mesonbuild.compilers import detect_c_compiler, compiler_from_language from mesonbuild.mesonlib import ( @@ -119,16 +120,11 @@ def skip_if_env_set(key: str) -> T.Callable[[T.Callable[P, R]], T.Callable[P, R] def wrapper(func: T.Callable[P, R]) -> T.Callable[P, R]: @functools.wraps(func) def wrapped(*args: P.args, **kwargs: P.kwargs) -> R: - old = None - if key in os.environ: - if not is_ci(): - raise unittest.SkipTest(f'Env var {key!r} set, skipping') - old = os.environ.pop(key) - try: + if key in os.environ and not is_ci(): + raise unittest.SkipTest(f'Env var {key!r} set, skipping') + with mock.patch.dict(os.environ): + os.environ.pop(key, None) return func(*args, **kwargs) - finally: - if old is not None: - os.environ[key] = old return wrapped return wrapper From e808aa161cec917aa7a6aed94fe89050950b35e1 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 16 Jul 2024 11:28:36 -0700 Subject: [PATCH 116/302] unittests: use TestCase.addCleanup for cleaning up builddirs --- unittests/baseplatformtests.py | 14 ++++---------- unittests/linuxliketests.py | 1 - 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/unittests/baseplatformtests.py b/unittests/baseplatformtests.py index ae012dadaabb..0886e5190643 100644 --- a/unittests/baseplatformtests.py +++ b/unittests/baseplatformtests.py @@ -91,7 +91,6 @@ def setUp(self): os.environ['COLUMNS'] = '80' os.environ['PYTHONIOENCODING'] = 'utf8' - self.builddirs = [] self.new_builddir() def change_builddir(self, newdir): @@ -101,7 +100,10 @@ def change_builddir(self, newdir): self.installdir = os.path.join(self.builddir, 'install') self.distdir = os.path.join(self.builddir, 'meson-dist') self.mtest_command = self.meson_command + ['test', '-C', self.builddir] - self.builddirs.append(self.builddir) + if os.path.islink(newdir): + self.addCleanup(os.unlink, self.builddir) + else: + self.addCleanup(windows_proof_rmtree, self.builddir) def new_builddir(self): # Keep builddirs inside the source tree so that virus scanners @@ -141,14 +143,6 @@ def _print_meson_log(self) -> None: if log: print(log) - def tearDown(self): - for path in self.builddirs: - try: - windows_proof_rmtree(path) - except FileNotFoundError: - pass - super().tearDown() - def _run(self, command, *, workdir=None, override_envvars: T.Optional[T.Mapping[str, str]] = None, stderr=True): ''' Run a command while printing the stdout and stderr to stdout, diff --git a/unittests/linuxliketests.py b/unittests/linuxliketests.py index cfad8fece55e..97602236df96 100644 --- a/unittests/linuxliketests.py +++ b/unittests/linuxliketests.py @@ -281,7 +281,6 @@ def test_symlink_builddir(self) -> None: symdir = f'{self.builddir}-symlink' os.symlink(self.builddir, symdir) - self.addCleanup(os.unlink, symdir) self.change_builddir(symdir) self.init(testdir) From 4b76aabe3a4dcc929edb5734b15e2468193c8879 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 16 Jul 2024 11:32:51 -0700 Subject: [PATCH 117/302] unittests: use setUpClass instead of setUp for class constant data for test attributes that are class constant. This reduces the work that must be done for each test case, allowing some of the setup work to be done once for the entire class. --- unittests/baseplatformtests.py | 67 ++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/unittests/baseplatformtests.py b/unittests/baseplatformtests.py index 0886e5190643..72ebeafe7ead 100644 --- a/unittests/baseplatformtests.py +++ b/unittests/baseplatformtests.py @@ -47,50 +47,53 @@ class BasePlatformTests(TestCase): prefix = '/usr' libdir = 'lib' - def setUp(self): - super().setUp() - self.maxDiff = None + @classmethod + def setUpClass(cls) -> None: + super().setUpClass() + cls.maxDiff = None src_root = str(PurePath(__file__).parents[1]) - self.src_root = src_root + cls.src_root = src_root # Get the backend - self.backend_name = os.environ.get('MESON_UNIT_TEST_BACKEND', 'ninja') - backend_type = 'vs' if self.backend_name.startswith('vs') else self.backend_name - self.backend = getattr(Backend, backend_type) - self.meson_args = ['--backend=' + self.backend_name] - self.meson_native_files = [] - self.meson_cross_files = [] - self.meson_command = python_command + [get_meson_script()] - self.setup_command = self.meson_command + ['setup'] + self.meson_args - self.mconf_command = self.meson_command + ['configure'] - self.mintro_command = self.meson_command + ['introspect'] - self.wrap_command = self.meson_command + ['wrap'] - self.rewrite_command = self.meson_command + ['rewrite'] + cls.backend_name = os.environ.get('MESON_UNIT_TEST_BACKEND', 'ninja') + backend_type = 'vs' if cls.backend_name.startswith('vs') else cls.backend_name + cls.backend = getattr(Backend, backend_type) + cls.meson_args = ['--backend=' + cls.backend_name] + cls.meson_command = python_command + [get_meson_script()] + cls.setup_command = cls.meson_command + ['setup'] + cls.meson_args + cls.mconf_command = cls.meson_command + ['configure'] + cls.mintro_command = cls.meson_command + ['introspect'] + cls.wrap_command = cls.meson_command + ['wrap'] + cls.rewrite_command = cls.meson_command + ['rewrite'] # Backend-specific build commands - self.build_command, self.clean_command, self.test_command, self.install_command, \ - self.uninstall_command = get_backend_commands(self.backend) + cls.build_command, cls.clean_command, cls.test_command, cls.install_command, \ + cls.uninstall_command = get_backend_commands(cls.backend) # Test directories - self.common_test_dir = os.path.join(src_root, 'test cases/common') - self.python_test_dir = os.path.join(src_root, 'test cases/python') - self.rust_test_dir = os.path.join(src_root, 'test cases/rust') - self.vala_test_dir = os.path.join(src_root, 'test cases/vala') - self.framework_test_dir = os.path.join(src_root, 'test cases/frameworks') - self.unit_test_dir = os.path.join(src_root, 'test cases/unit') - self.rewrite_test_dir = os.path.join(src_root, 'test cases/rewrite') - self.linuxlike_test_dir = os.path.join(src_root, 'test cases/linuxlike') - self.objc_test_dir = os.path.join(src_root, 'test cases/objc') - self.objcpp_test_dir = os.path.join(src_root, 'test cases/objcpp') - self.darwin_test_dir = os.path.join(src_root, 'test cases/darwin') + cls.common_test_dir = os.path.join(src_root, 'test cases/common') + cls.python_test_dir = os.path.join(src_root, 'test cases/python') + cls.rust_test_dir = os.path.join(src_root, 'test cases/rust') + cls.vala_test_dir = os.path.join(src_root, 'test cases/vala') + cls.framework_test_dir = os.path.join(src_root, 'test cases/frameworks') + cls.unit_test_dir = os.path.join(src_root, 'test cases/unit') + cls.rewrite_test_dir = os.path.join(src_root, 'test cases/rewrite') + cls.linuxlike_test_dir = os.path.join(src_root, 'test cases/linuxlike') + cls.objc_test_dir = os.path.join(src_root, 'test cases/objc') + cls.objcpp_test_dir = os.path.join(src_root, 'test cases/objcpp') + cls.darwin_test_dir = os.path.join(src_root, 'test cases/darwin') # Misc stuff - if self.backend is Backend.ninja: - self.no_rebuild_stdout = ['ninja: no work to do.', 'samu: nothing to do'] + if cls.backend is Backend.ninja: + cls.no_rebuild_stdout = ['ninja: no work to do.', 'samu: nothing to do'] else: # VS doesn't have a stable output when no changes are done # XCode backend is untested with unit tests, help welcome! - self.no_rebuild_stdout = [f'UNKNOWN BACKEND {self.backend.name!r}'] + cls.no_rebuild_stdout = [f'UNKNOWN BACKEND {cls.backend.name!r}'] os.environ['COLUMNS'] = '80' os.environ['PYTHONIOENCODING'] = 'utf8' + def setUp(self): + super().setUp() + self.meson_native_files = [] + self.meson_cross_files = [] self.new_builddir() def change_builddir(self, newdir): From 42a4d1aaa0854d376e9d28cf4b6ca93df90c8213 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Thu, 15 Aug 2024 09:13:20 -0400 Subject: [PATCH 118/302] cargo: Ignore Cargo.lock if toml implementation is missing It is only required if a Cargo subproject is actually configured. --- mesonbuild/cargo/interpreter.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/mesonbuild/cargo/interpreter.py b/mesonbuild/cargo/interpreter.py index 6c84672bcd6a..98ffa50ac09f 100644 --- a/mesonbuild/cargo/interpreter.py +++ b/mesonbuild/cargo/interpreter.py @@ -55,13 +55,17 @@ toml2json = shutil.which('toml2json') +class TomlImplementationMissing(MesonException): + pass + + def load_toml(filename: str) -> T.Dict[object, object]: if tomllib: with open(filename, 'rb') as f: raw = tomllib.load(f) else: if toml2json is None: - raise MesonException('Could not find an implementation of tomllib, nor toml2json') + raise TomlImplementationMissing('Could not find an implementation of tomllib, nor toml2json') p, out, err = Popen_safe([toml2json, filename]) if p.returncode != 0: @@ -742,7 +746,11 @@ def load_wraps(source_dir: str, subproject_dir: str) -> T.List[PackageDefinition wraps: T.List[PackageDefinition] = [] filename = os.path.join(source_dir, 'Cargo.lock') if os.path.exists(filename): - cargolock = T.cast('manifest.CargoLock', load_toml(filename)) + try: + cargolock = T.cast('manifest.CargoLock', load_toml(filename)) + except TomlImplementationMissing as e: + mlog.warning('Failed to load Cargo.lock:', str(e), fatal=False) + return wraps for package in cargolock['package']: name = package['name'] version = package['version'] From ca734222cf5e38dd7a26eeabbf4f823530d58557 Mon Sep 17 00:00:00 2001 From: Sam James Date: Fri, 16 Aug 2024 04:34:12 +0100 Subject: [PATCH 119/302] ci: try to install urld harder for opensuse, ubuntu Like in a5211a15207a2e6e30e213c5530a5d1bf5c2531c. --- ci/ciimage/opensuse/install.sh | 2 +- ci/ciimage/ubuntu-rolling/install.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/ciimage/opensuse/install.sh b/ci/ciimage/opensuse/install.sh index b0097172a8a9..91df533ba8b7 100755 --- a/ci/ciimage/opensuse/install.sh +++ b/ci/ciimage/opensuse/install.sh @@ -39,7 +39,7 @@ chmod +x /ci/env_vars.sh source /ci/env_vars.sh dub_fetch urld -dub build urld --compiler=dmd +dub build --deep urld --arch=x86_64 --compiler=dmd --build=debug dub_fetch dubtestproject dub build dubtestproject:test1 --compiler=dmd dub build dubtestproject:test2 --compiler=dmd diff --git a/ci/ciimage/ubuntu-rolling/install.sh b/ci/ciimage/ubuntu-rolling/install.sh index 63e497073ad9..b811fde47e7d 100755 --- a/ci/ciimage/ubuntu-rolling/install.sh +++ b/ci/ciimage/ubuntu-rolling/install.sh @@ -46,7 +46,7 @@ install_python_packages hotdoc # dub stuff dub_fetch urld -dub build urld --compiler=gdc +dub build --deep urld --arch=x86_64 --compiler=gdc --build=debug dub_fetch dubtestproject dub build dubtestproject:test1 --compiler=ldc2 dub build dubtestproject:test2 --compiler=ldc2 From 9f85279e30d4157d54d92f451eaecc52d9ffe506 Mon Sep 17 00:00:00 2001 From: Sam James Date: Fri, 16 Aug 2024 04:53:43 +0100 Subject: [PATCH 120/302] ci: opensuse: add setuptools `test_meson_installed` fails without setuptools: ``` $ /usr/bin/python3 run_meson_command_tests.py -v Meson build system 1.5.99 Command Tests test_meson_exe_windows (__main__.CommandTests.test_meson_exe_windows) ... skipped 'NOT IMPLEMENTED' test_meson_installed (__main__.CommandTests.test_meson_installed) ... Traceback (most recent call last): File "/meson/setup.py", line 12, in from setuptools import setup ModuleNotFoundError: No module named 'setuptools' ERROR ``` --- ci/ciimage/opensuse/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/ciimage/opensuse/install.sh b/ci/ciimage/opensuse/install.sh index 91df533ba8b7..7de18ecb646b 100755 --- a/ci/ciimage/opensuse/install.sh +++ b/ci/ciimage/opensuse/install.sh @@ -5,7 +5,7 @@ set -e source /ci/common.sh pkgs=( - python3-pip python3 python3-devel + python3-pip python3 python3-devel python3-setuptools ninja make git autoconf automake patch libjpeg-devel elfutils gcc gcc-c++ gcc-fortran gcc-objc gcc-obj-c++ vala rust bison flex curl lcov mono-core gtkmm3-devel gtest gmock protobuf-devel wxGTK3-3_2-devel gobject-introspection-devel From 9c3dcea2cda3b6eff90e72a826196bfb44d151d8 Mon Sep 17 00:00:00 2001 From: Sam James Date: Mon, 19 Aug 2024 03:46:46 +0100 Subject: [PATCH 121/302] ci: skip frameworks/17 mpi for auto/pkgconfig on Ubuntu The pkgconfig file in Debian and Ubuntu is definitely broken and we've reported it upstream, but we don't really want to keep our image building failing while we wait for that to be fixed. Skip the auto/pkgconfig test if both: a) we're on Ubuntu, and b) the .pc checksum matches a known-bad copy. I'm also CC'd to the bug to catch if it gets fixed. Bug: https://bugs.debian.org/1078026 --- test cases/frameworks/17 mpi/meson.build | 10 ++++++++++ test cases/frameworks/17 mpi/test.json | 6 ++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/test cases/frameworks/17 mpi/meson.build b/test cases/frameworks/17 mpi/meson.build index d1d89915579f..5d233bfb217e 100644 --- a/test cases/frameworks/17 mpi/meson.build +++ b/test cases/frameworks/17 mpi/meson.build @@ -32,6 +32,16 @@ test('MPI C++', execpp, timeout: 20) if add_languages('fortran', required : false) + if method in ['auto', 'pkg-config'] + # https://bugs.debian.org/1078026 + fs = import('fs') + if fs.exists('/usr/lib/x86_64-linux-gnu/pkgconfig/ompi-fort.pc') + if fs.hash('/usr/lib/x86_64-linux-gnu/pkgconfig/ompi-fort.pc', 'md5') == '0892a93630e3d3359c43c58d5a82efc0' + error('MESON_SKIP_TEST: openmpi pkgconfig file is broken on Debian/Ubuntu') + endif + endif + endif + fc = meson.get_compiler('fortran') mpif = dependency('mpi', language : 'fortran', required: false, method : method) if not fc.links('use mpi; end', dependencies: mpif, name: 'Fortran MPI') diff --git a/test cases/frameworks/17 mpi/test.json b/test cases/frameworks/17 mpi/test.json index cbd1686121c5..3a46657ef112 100644 --- a/test cases/frameworks/17 mpi/test.json +++ b/test cases/frameworks/17 mpi/test.json @@ -2,8 +2,10 @@ "matrix": { "options": { "method": [ - { "val": "auto" }, - { "val": "pkg-config" }, + { "val": "auto", + "expect_skip_on_jobname": ["ubuntu"] }, + { "val": "pkg-config", + "expect_skip_on_jobname": ["ubuntu"] }, { "val": "config-tool", "expect_skip_on_jobname": ["fedora"] }, { From cdf646feb8ab7195c0fc9bc3bdf2ac999c2097fb Mon Sep 17 00:00:00 2001 From: Sam James Date: Mon, 19 Aug 2024 06:36:35 +0100 Subject: [PATCH 122/302] ci: ubuntu: fix coverage unittests by patching/updating lcov Hack for https://github.com/linux-test-project/lcov/issues/245. I tried to backport https://github.com/linux-test-project/lcov/commit/bf135caf5f626e02191c42bd2773e08a0bb9b7e5 but had no luck (worked in one container but didn'y apply in another, whatever). This fixes the coverage unittests. >=lcov-2.1-beta works fine. The beta has landed in a beta version of Ubuntu too. Bug: https://github.com/linux-test-project/lcov/issues/245 --- ci/ciimage/ubuntu-rolling/install.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ci/ciimage/ubuntu-rolling/install.sh b/ci/ciimage/ubuntu-rolling/install.sh index b811fde47e7d..1706d837dc00 100755 --- a/ci/ciimage/ubuntu-rolling/install.sh +++ b/ci/ciimage/ubuntu-rolling/install.sh @@ -82,6 +82,13 @@ cp LICENSE /usr/share/doc/zig cd .. rm -rf "$ZIG_BASE" +# Hack for https://github.com/linux-test-project/lcov/issues/245 +# https://github.com/linux-test-project/lcov/commit/bf135caf5f626e02191c42bd2773e08a0bb9b7e5 +# XXX: Drop this once Ubuntu has lcov-2.1* +git clone https://github.com/linux-test-project/lcov +cd lcov +make install + # cleanup apt-get -y clean apt-get -y autoclean From 18f4a058bf7e4b7eb32553b10fe3a37e1c22aa15 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Mon, 19 Aug 2024 14:18:04 -0700 Subject: [PATCH 123/302] mformat: correctly handle editorconfig files without the root setting Which happens when a .editorconfig is in a subdirectory, not the root. In this case we need Set the fallback value to `False`, which is what editorconfig expects. Closes: #13568 --- mesonbuild/mformat.py | 3 ++- test cases/format/3 editorconfig/meson.build | 1 + test cases/format/3 editorconfig/subdir/.editorconfig | 2 ++ test cases/format/3 editorconfig/subdir/sub.meson | 3 +++ 4 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 test cases/format/3 editorconfig/subdir/.editorconfig create mode 100644 test cases/format/3 editorconfig/subdir/sub.meson diff --git a/mesonbuild/mformat.py b/mesonbuild/mformat.py index bb93f47ef50c..2e403016811c 100644 --- a/mesonbuild/mformat.py +++ b/mesonbuild/mformat.py @@ -823,7 +823,8 @@ def load_editor_config(self, source_file: Path) -> EditorConfig: if value is not None: setattr(config, f.name, value) - if cp.getboolean(cp.default_section, 'root'): + # Root is not required except in the top level .editorconfig. + if cp.getboolean(cp.default_section, 'root', fallback=False): break return config diff --git a/test cases/format/3 editorconfig/meson.build b/test cases/format/3 editorconfig/meson.build index b32974cb9e8e..2468411493c3 100644 --- a/test cases/format/3 editorconfig/meson.build +++ b/test cases/format/3 editorconfig/meson.build @@ -7,6 +7,7 @@ meson_files = { 'self': files('meson.build'), 'comments': files('crazy_comments.meson'), 'indentation': files('indentation.meson'), + 'subdir editorconfig': files('subdir/sub.meson'), } foreach name, f : meson_files diff --git a/test cases/format/3 editorconfig/subdir/.editorconfig b/test cases/format/3 editorconfig/subdir/.editorconfig new file mode 100644 index 000000000000..fac7a92caaba --- /dev/null +++ b/test cases/format/3 editorconfig/subdir/.editorconfig @@ -0,0 +1,2 @@ +[*] +max_line_length = 120 diff --git a/test cases/format/3 editorconfig/subdir/sub.meson b/test cases/format/3 editorconfig/subdir/sub.meson new file mode 100644 index 000000000000..623ca2836a9c --- /dev/null +++ b/test cases/format/3 editorconfig/subdir/sub.meson @@ -0,0 +1,3 @@ +project('line') + +msg = 'this is a very long line, and it should be be wrapped because we have line length limit of 120, not 60' From d9ba42217f49c4bd4caeac9050cc475e3453f75e Mon Sep 17 00:00:00 2001 From: Charles Brunet Date: Tue, 6 Aug 2024 10:15:33 -0400 Subject: [PATCH 124/302] format: fix indentation of comments Fixes #13508 - Fix indentation of comments in arrays - Fix indentation of comments in dicts - Fix indentation of comments in if clauses - Fix indentation of comments in foreach clauses --- mesonbuild/mformat.py | 31 ++++++++++++++++--- mesonbuild/mparser.py | 1 + test cases/format/1 default/indentation.meson | 17 ++++++++++ unittests/platformagnostictests.py | 15 +++++++++ 4 files changed, 59 insertions(+), 5 deletions(-) diff --git a/mesonbuild/mformat.py b/mesonbuild/mformat.py index 2e403016811c..bab3e5a17aca 100644 --- a/mesonbuild/mformat.py +++ b/mesonbuild/mformat.py @@ -372,6 +372,8 @@ def visit_ArrayNode(self, node: mparser.ArrayNode) -> None: if node.args.arguments and not node.args.is_multiline and self.config.space_array: self.add_space_after(node.lbracket) self.add_space_after(node.args) + if not node.args.arguments: + self.move_whitespaces(node.lbracket, node.args) def visit_DictNode(self, node: mparser.DictNode) -> None: super().visit_DictNode(node) @@ -388,6 +390,7 @@ def visit_CodeBlockNode(self, node: mparser.CodeBlockNode) -> None: self.in_block_comments = False else: node.pre_whitespaces = mparser.WhitespaceNode(mparser.Token('whitespace', node.filename, 0, 0, 0, (0, 0), '')) + node.pre_whitespaces.block_indent = True for i in node.lines: i.accept(self) @@ -398,7 +401,9 @@ def visit_CodeBlockNode(self, node: mparser.CodeBlockNode) -> None: else: node.whitespaces.value = node.pre_whitespaces.value + node.whitespaces.value node.pre_whitespaces.value = '' + self.in_block_comments = True node.whitespaces.accept(self) + self.in_block_comments = False if node.condition_level == 0 and self.config.insert_final_newline: self.add_nl_after(node, force=True) @@ -453,6 +458,7 @@ def visit_ForeachClauseNode(self, node: mparser.ForeachClauseNode) -> None: self.add_space_after(node.colon) node.block.whitespaces.value += node.condition_level * self.config.indent_by + node.block.whitespaces.block_indent = True self.move_whitespaces(node.endforeach, node) @@ -468,11 +474,19 @@ def visit_IfClauseNode(self, node: mparser.IfClauseNode) -> None: def visit_IfNode(self, node: mparser.IfNode) -> None: super().visit_IfNode(node) self.add_space_after(node.if_) + self.in_block_comments = True self.move_whitespaces(node.block, node) + self.in_block_comments = False + node.whitespaces.condition_level = node.condition_level + 1 + node.whitespaces.block_indent = True def visit_ElseNode(self, node: mparser.ElseNode) -> None: super().visit_ElseNode(node) + self.in_block_comments = True self.move_whitespaces(node.block, node) + self.in_block_comments = False + node.whitespaces.condition_level = node.condition_level + 1 + node.whitespaces.block_indent = True def visit_TernaryNode(self, node: mparser.TernaryNode) -> None: super().visit_TernaryNode(node) @@ -554,22 +568,28 @@ def visit_ArrayNode(self, node: mparser.ArrayNode) -> None: self.enter_node(node) if node.args.is_multiline: self.level += 1 - self.add_nl_after(node.lbracket, indent=self.level) + if node.args.arguments: + self.add_nl_after(node.lbracket, indent=self.level) + node.lbracket.accept(self) self.is_function_arguments = False node.args.accept(self) if node.args.is_multiline: self.level -= 1 + node.rbracket.accept(self) self.exit_node(node) def visit_DictNode(self, node: mparser.DictNode) -> None: self.enter_node(node) if node.args.is_multiline: self.level += 1 - self.add_nl_after(node.lcurl, indent=self.level) + if node.args.kwargs: + self.add_nl_after(node.lcurl, indent=self.level) + node.lcurl.accept(self) self.is_function_arguments = False node.args.accept(self) if node.args.is_multiline: self.level -= 1 + node.rcurl.accept(self) self.exit_node(node) def visit_MethodNode(self, node: mparser.MethodNode) -> None: @@ -599,8 +619,8 @@ def visit_WhitespaceNode(self, node: mparser.WhitespaceNode) -> None: lines = node.value.splitlines(keepends=True) if lines: indent = (node.condition_level + self.level) * self.config.indent_by - node.value = lines[0] - for line in lines[1:]: + node.value = '' if node.block_indent else lines.pop(0) + for line in lines: if '#' in line and not line.startswith(indent): node.value += indent node.value += line @@ -650,7 +670,8 @@ def visit_ArgumentNode(self, node: mparser.ArgumentNode) -> None: for comma in node.commas[arg_index:-1]: self.add_nl_after(comma, self.level) - self.add_nl_after(node, self.level - 1) + if node.arguments or node.kwargs: + self.add_nl_after(node, self.level - 1) else: if has_trailing_comma and not (node.commas[-1].whitespaces and node.commas[-1].whitespaces.value): diff --git a/mesonbuild/mparser.py b/mesonbuild/mparser.py index 50d720313495..fc37d2a54e2b 100644 --- a/mesonbuild/mparser.py +++ b/mesonbuild/mparser.py @@ -266,6 +266,7 @@ def __init__(self, token: Token[str]): super().__init__(token.lineno, token.colno, token.filename) self.value = '' self.append(token) + self.block_indent = False def append(self, token: Token[str]) -> None: self.value += token.value diff --git a/test cases/format/1 default/indentation.meson b/test cases/format/1 default/indentation.meson index b1edc3a16a52..fe78847f7667 100644 --- a/test cases/format/1 default/indentation.meson +++ b/test cases/format/1 default/indentation.meson @@ -11,7 +11,10 @@ project( ) a = [ + # comment + # comment 1, + # comment 2, 3, [ @@ -36,8 +39,13 @@ a = [ d = {} if meson.project_version().version_compare('>1.2') + # comment + # comment if meson.version().version_compare('>1.0') + # comment + # comment foreach i : a + # comment e = { 'a': 'a', 'b': 'b', @@ -69,9 +77,18 @@ if meson.project_version().version_compare('>1.2') ], } endforeach + + foreach j : a + # comment + # comment + # comment + endforeach elif 42 in d d += {'foo': 43} else # ensure else is correctly indented (issue #13316) + # comment k = 'k' + # comment + # comment endif endif diff --git a/unittests/platformagnostictests.py b/unittests/platformagnostictests.py index c8f594d465ef..7d6ffa0f9e1f 100644 --- a/unittests/platformagnostictests.py +++ b/unittests/platformagnostictests.py @@ -342,6 +342,21 @@ def test_format_empty_file(self) -> None: for code in ('', '\n'): formatted = formatter.format(code, Path()) self.assertEqual('\n', formatted) + + def test_format_indent_comment_in_brackets(self) -> None: + """Ensure comments in arrays and dicts are correctly indented""" + formatter = Formatter(None, use_editor_config=False, fetch_subdirs=False) + code = 'a = [\n # comment\n]\n' + formatted = formatter.format(code, Path()) + self.assertEqual(code, formatted) + + code = 'a = [\n # comment\n 1,\n]\n' + formatted = formatter.format(code, Path()) + self.assertEqual(code, formatted) + + code = 'a = {\n # comment\n}\n' + formatted = formatter.format(code, Path()) + self.assertEqual(code, formatted) def test_error_configuring_subdir(self): testdir = os.path.join(self.common_test_dir, '152 index customtarget') From 7280639cb5967beefa85b561dcbd096bcf05db3d Mon Sep 17 00:00:00 2001 From: Wolfgang Walther Date: Sat, 17 Aug 2024 22:47:31 +0200 Subject: [PATCH 125/302] linkers: skip -export_dynamic flag before MacOS 10.7 The flag was only introduced in ld 224.1, as mentioned in the initial PR #13291. Resolves #13543 --- mesonbuild/linkers/linkers.py | 4 +++- unittests/darwintests.py | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/mesonbuild/linkers/linkers.py b/mesonbuild/linkers/linkers.py index 0b892735953c..d011e67b9c54 100644 --- a/mesonbuild/linkers/linkers.py +++ b/mesonbuild/linkers/linkers.py @@ -840,7 +840,9 @@ def get_thinlto_cache_args(self, path: str) -> T.List[str]: return ["-Wl,-cache_path_lto," + path] def export_dynamic_args(self, env: 'Environment') -> T.List[str]: - return self._apply_prefix('-export_dynamic') + if mesonlib.version_compare(self.version, '>=224.1'): + return self._apply_prefix('-export_dynamic') + return [] class LLVMLD64DynamicLinker(AppleDynamicLinker): diff --git a/unittests/darwintests.py b/unittests/darwintests.py index afc663a57ae1..26dd996415af 100644 --- a/unittests/darwintests.py +++ b/unittests/darwintests.py @@ -4,10 +4,11 @@ import subprocess import re import os +import platform import unittest from mesonbuild.mesonlib import ( - MachineChoice, is_osx + MachineChoice, is_osx, version_compare ) from mesonbuild.compilers import ( detect_c_compiler @@ -81,6 +82,7 @@ def test_apple_bitcode_modules(self): self.build() self.run_tests() + @unittest.skipIf(version_compare(platform.mac_ver()[0], '<10.7'), '-export_dynamic was added in 10.7') def test_apple_lto_export_dynamic(self): ''' Tests that -Wl,-export_dynamic is correctly added, when export_dynamic: true is set. From ab3cfc2da1c481f52a5525e41150626a2f66de3b Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Mon, 19 Aug 2024 15:47:58 -0700 Subject: [PATCH 126/302] tests/format: Make the compare script more useful Now it will generate a diff of the expected value and what it actually got --- test cases/format/5 transform/file_compare.py | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/test cases/format/5 transform/file_compare.py b/test cases/format/5 transform/file_compare.py index 7b0d1b85668f..fd3ce10560a6 100644 --- a/test cases/format/5 transform/file_compare.py +++ b/test cases/format/5 transform/file_compare.py @@ -1,7 +1,31 @@ #!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 +# Copyright © 2024 Intel Corporation +import argparse import sys +import difflib -with open(sys.argv[1], 'r', encoding='utf-8') as f, open(sys.argv[2], 'r', encoding='utf-8') as g: - if f.read() != g.read(): - sys.exit('contents are not equal') + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument('actual', help='The transformed contents') + parser.add_argument('expected', help='the contents we expected') + args = parser.parse_args() + + with open(args.actual, 'r') as f: + actual = f.readlines() + with open(args.expected, 'r') as f: + expected = f.readlines() + + if actual == expected: + return 0 + + diff = difflib.ndiff(expected, actual) + for line in diff: + print(line, file=sys.stderr, end='') + return 1 + + +if __name__ == "__main__": + sys.exit(main()) From df706807239095ddbbfd2975b3fe067ad6b5d535 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Mon, 19 Aug 2024 15:39:53 -0700 Subject: [PATCH 127/302] mformat: A triple string with a ' in it cannot be simplified The following is valid meson: ```meson a = '''This string can't be simplified''' ``` which cannot be simplified because of the `'` in it, as ```meson a = 'This string can't be simplified' ``` Is invalid. Potentially we could convert that with escapes, but it seems reasonable to me to leave this, since it may be desirable to not have lots of escapes in a string. `'''I can't believe it's her's!'''` is much more readable than `'I can\'t believe it\'s her\'s!'`, for example. Closes: #13564 --- mesonbuild/mformat.py | 2 +- test cases/format/5 transform/default.expected.meson | 1 + test cases/format/5 transform/muon.expected.meson | 1 + test cases/format/5 transform/options.expected.meson | 1 + test cases/format/5 transform/source.meson | 1 + 5 files changed, 5 insertions(+), 1 deletion(-) diff --git a/mesonbuild/mformat.py b/mesonbuild/mformat.py index bab3e5a17aca..27f97b4fa5fb 100644 --- a/mesonbuild/mformat.py +++ b/mesonbuild/mformat.py @@ -338,7 +338,7 @@ def visit_StringNode(self, node: mparser.StringNode) -> None: self.enter_node(node) if self.config.simplify_string_literals: - if node.is_multiline and '\n' not in node.value: + if node.is_multiline and not any(x in node.value for x in ['\n', "'"]): node.is_multiline = False node.value = node.escape() diff --git a/test cases/format/5 transform/default.expected.meson b/test cases/format/5 transform/default.expected.meson index 4201053e1f18..18af2f8afa79 100644 --- a/test cases/format/5 transform/default.expected.meson +++ b/test cases/format/5 transform/default.expected.meson @@ -47,6 +47,7 @@ d = {'a': 1, 'b': 2, 'c': 3} # string conversion 'This is not a multiline' 'This is not a fstring' +'''This isn't convertible''' # group arg value arguments = [ diff --git a/test cases/format/5 transform/muon.expected.meson b/test cases/format/5 transform/muon.expected.meson index 871ce27d722d..0e6309c7f722 100644 --- a/test cases/format/5 transform/muon.expected.meson +++ b/test cases/format/5 transform/muon.expected.meson @@ -47,6 +47,7 @@ d = {'a': 1, 'b': 2, 'c': 3} # string conversion '''This is not a multiline''' f'This is not a fstring' +'''This isn't convertible''' # group arg value arguments = [ diff --git a/test cases/format/5 transform/options.expected.meson b/test cases/format/5 transform/options.expected.meson index f7f45658d5c3..9ed6ac2be5af 100644 --- a/test cases/format/5 transform/options.expected.meson +++ b/test cases/format/5 transform/options.expected.meson @@ -29,6 +29,7 @@ d = { # string conversion 'This is not a multiline' 'This is not a fstring' +'''This isn't convertible''' # group arg value arguments = [ diff --git a/test cases/format/5 transform/source.meson b/test cases/format/5 transform/source.meson index 7274d4802699..4482884052d6 100644 --- a/test cases/format/5 transform/source.meson +++ b/test cases/format/5 transform/source.meson @@ -29,6 +29,7 @@ d = {'a': 1, 'b': 2, 'c': 3} # string conversion '''This is not a multiline''' f'This is not a fstring' +'''This isn't convertible''' # group arg value arguments = ['a', '--opt_a', 'opt_a_value', 'b', 'c', '--opt_d', '--opt_e', 'opt_e_value', From 45db23394f2dc5e26050c2ede76be79c70f50ca5 Mon Sep 17 00:00:00 2001 From: slimeuniverse Date: Fri, 23 Aug 2024 17:23:20 +0300 Subject: [PATCH 128/302] Discard swiftc linker detect output "swiftc -Xlinker -v tmp.swift" command used to detect swift linker creates junk files in working directory. This fix forwards output to /dev/null --- mesonbuild/compilers/detect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/compilers/detect.py b/mesonbuild/compilers/detect.py index 2e6b88dfc1ca..72a3533ac1bb 100644 --- a/mesonbuild/compilers/detect.py +++ b/mesonbuild/compilers/detect.py @@ -1248,7 +1248,7 @@ def detect_swift_compiler(env: 'Environment', for_machine: MachineChoice) -> Com cls = SwiftCompiler linker = guess_nix_linker(env, exelist, cls, version, for_machine, - extra_args=[f.name]) + extra_args=[f.name, '-o /dev/null']) return cls( exelist, version, for_machine, is_cross, info, linker=linker) From 49cc4862e7448e2e1a879c28274ced7175100dd8 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 20 Aug 2024 12:23:49 -0700 Subject: [PATCH 129/302] mdist: don't mutate meson_command, which is supposed to be immutable --- mesonbuild/mdist.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mesonbuild/mdist.py b/mesonbuild/mdist.py index 8e35bb8e8333..05c23f53fe46 100644 --- a/mesonbuild/mdist.py +++ b/mesonbuild/mdist.py @@ -1,6 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright 2017 The Meson development team -# Copyright © 2023 Intel Corporation +# Copyright © 2023-2024 Intel Corporation from __future__ import annotations @@ -289,7 +289,7 @@ def run_dist_steps(meson_command: T.List[str], unpacked_src_dir: str, builddir: return 1 return 0 -def check_dist(packagename: str, meson_command: ImmutableListProtocol[str], extra_meson_args: T.List[str], bld_root: str, privdir: str) -> int: +def check_dist(packagename: str, _meson_command: ImmutableListProtocol[str], extra_meson_args: T.List[str], bld_root: str, privdir: str) -> int: print(f'Testing distribution package {packagename}') unpackdir = os.path.join(privdir, 'dist-unpack') builddir = os.path.join(privdir, 'dist-build') @@ -303,6 +303,7 @@ def check_dist(packagename: str, meson_command: ImmutableListProtocol[str], extr unpacked_files = glob(os.path.join(unpackdir, '*')) assert len(unpacked_files) == 1 unpacked_src_dir = unpacked_files[0] + meson_command = _meson_command.copy() meson_command += ['setup'] meson_command += create_cmdline_args(bld_root) meson_command += extra_meson_args From 0bd45b3676b6100cb58a5a15bc9e783ec1d185c1 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sat, 24 Aug 2024 00:13:30 +0300 Subject: [PATCH 130/302] Use proper array form in swiftc. --- mesonbuild/compilers/detect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/compilers/detect.py b/mesonbuild/compilers/detect.py index 72a3533ac1bb..0a95f90dd03c 100644 --- a/mesonbuild/compilers/detect.py +++ b/mesonbuild/compilers/detect.py @@ -1248,7 +1248,7 @@ def detect_swift_compiler(env: 'Environment', for_machine: MachineChoice) -> Com cls = SwiftCompiler linker = guess_nix_linker(env, exelist, cls, version, for_machine, - extra_args=[f.name, '-o /dev/null']) + extra_args=[f.name, '-o', '/dev/null']) return cls( exelist, version, for_machine, is_cross, info, linker=linker) From a57c880368379091a7fc6ee9916a5a80042e9bf2 Mon Sep 17 00:00:00 2001 From: "Mark A. Tsuchida" Date: Wed, 14 Aug 2024 13:43:22 -0500 Subject: [PATCH 131/302] Better handle CTRL-C during clang-tidy/format It was possible (with some frequency) for the clang-tidy/format target to continue starting new subprocesses after a CTRL-C, because we were not canceling the already queued tasks and waiting for all of them. This makes a best-effort attempt to cancel all further subprocesses. It is not 100%, because there is a race that is hard to avoid (without major restructuring, at least): new subprocesses may be started after KeyboardInterrupt (or any other exception) is raised but before we get to the cancellation. When the race happens, the calling ninja may exit before Meson exits, causing some output (from clang-tidy/format and Meson's traceback) to be printed after returning to the shell prompt. But this is an improvement over potentially launching all the remaining tasks after having returned to the shell, which is what used to happen rather often. In practice, it appears that we cleanly exit with a pretty high probability unless CTRL-C is hit very early after starting (presumably before the thread pool has launched subprocesses on all its threads). --- mesonbuild/scripts/run_tool.py | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/mesonbuild/scripts/run_tool.py b/mesonbuild/scripts/run_tool.py index a1641e90adb5..a84de15b12df 100644 --- a/mesonbuild/scripts/run_tool.py +++ b/mesonbuild/scripts/run_tool.py @@ -5,8 +5,8 @@ import itertools import fnmatch +import concurrent.futures from pathlib import Path -from concurrent.futures import ThreadPoolExecutor from ..compilers import lang_suffixes from ..mesonlib import quiet_git @@ -46,13 +46,27 @@ def run_tool(name: str, srcdir: Path, builddir: Path, fn: T.Callable[..., subpro suffixes = {f'.{s}' for s in suffixes} futures = [] returncode = 0 - with ThreadPoolExecutor() as e: + e = concurrent.futures.ThreadPoolExecutor() + try: for f in itertools.chain(*globs): strf = str(f) if f.is_dir() or f.suffix not in suffixes or \ any(fnmatch.fnmatch(strf, i) for i in ignore): continue futures.append(e.submit(fn, f, *args)) - if futures: - returncode = max(x.result().returncode for x in futures) + concurrent.futures.wait( + futures, + return_when=concurrent.futures.FIRST_EXCEPTION + ) + finally: + # We try to prevent new subprocesses from being started by canceling + # the futures, but this is not water-tight: some may have started + # between the wait being interrupted or exited and the futures being + # canceled. (A fundamental fix would probably require the ability to + # terminate such subprocesses upon cancellation of the future.) + for x in futures: # Python >=3.9: e.shutdown(cancel_futures=True) + x.cancel() + e.shutdown() + if futures: + returncode = max(x.result().returncode for x in futures) return returncode From 761e2470d4360032e88072718d1728e4537dbde1 Mon Sep 17 00:00:00 2001 From: "L. E. Segovia" Date: Fri, 28 Jun 2024 22:12:05 +0000 Subject: [PATCH 132/302] compilers: Allow prelinking with Apple Clang --- mesonbuild/compilers/mixins/apple.py | 4 ++++ unittests/linuxliketests.py | 7 ++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/mesonbuild/compilers/mixins/apple.py b/mesonbuild/compilers/mixins/apple.py index 98c4bfa1a18b..fc93d38a5673 100644 --- a/mesonbuild/compilers/mixins/apple.py +++ b/mesonbuild/compilers/mixins/apple.py @@ -55,3 +55,7 @@ def openmp_link_flags(self, env: Environment) -> T.List[str]: if not link: raise MesonException("Couldn't find libomp") return self.__BASE_OMP_FLAGS + link + + def get_prelink_args(self, prelink_name: str, obj_list: T.List[str]) -> T.List[str]: + # The objects are prelinked through the compiler, which injects -lSystem + return ['-nostdlib', '-r', '-o', prelink_name] + obj_list diff --git a/unittests/linuxliketests.py b/unittests/linuxliketests.py index 97602236df96..f92c992cc613 100644 --- a/unittests/linuxliketests.py +++ b/unittests/linuxliketests.py @@ -1684,9 +1684,7 @@ def test_prelinking(self): # Prelinking currently only works on recently new GNU toolchains. # Skip everything else. When support for other toolchains is added, # remove limitations as necessary. - if is_osx(): - raise SkipTest('Prelinking not supported on Darwin.') - if 'clang' in os.environ.get('CC', 'dummy'): + if 'clang' in os.environ.get('CC', 'dummy') and not is_osx(): raise SkipTest('Prelinking not supported with Clang.') testdir = os.path.join(self.unit_test_dir, '86 prelinking') env = get_fake_env(testdir, self.builddir, self.prefix) @@ -1704,8 +1702,7 @@ def test_prelinking(self): stderr=subprocess.DEVNULL, encoding='utf-8', text=True, timeout=1) obj_files = p.stdout.strip().split('\n') - self.assertEqual(len(obj_files), 1) - self.assertTrue(obj_files[0].endswith('-prelink.o')) + self.assertTrue(any(o.endswith('-prelink.o') for o in obj_files)) def do_one_test_with_nativefile(self, testdir, args): testdir = os.path.join(self.common_test_dir, testdir) From b522231c88173b69fcc8c20a337aa3e83978b3f3 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sat, 24 Aug 2024 09:34:46 +0300 Subject: [PATCH 133/302] Convert Bash usage to a Python script. --- test cases/common/41 test args/meson.build | 4 ++-- test cases/common/41 test args/pathtester.py | 11 +++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 test cases/common/41 test args/pathtester.py diff --git a/test cases/common/41 test args/meson.build b/test cases/common/41 test args/meson.build index 4894f3e163a8..7efd8d5daa90 100644 --- a/test cases/common/41 test args/meson.build +++ b/test cases/common/41 test args/meson.build @@ -38,10 +38,10 @@ test('custom target arg', tester, args : testfilect, env : env_array) env = environment() env.append('PATH', 'something') -bash = find_program('bash') +pathtester = find_program('pathtester.py') custompathtgt = custom_target('testpathappend', output : 'nothing.txt', build_always : true, - command : [bash, '-c', 'env'], + command : [pathtester], env : env) diff --git a/test cases/common/41 test args/pathtester.py b/test cases/common/41 test args/pathtester.py new file mode 100644 index 000000000000..101136611cf5 --- /dev/null +++ b/test cases/common/41 test args/pathtester.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python3 + +import sys, subprocess + +if sys.platorm() == 'win32': + cmd = ['xcopy', '/?'] +else: + cmd = ['env'] + +rc = subprocess.run(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) +sys.exit(rc.returncode) From 79c47bd9d4c080e9f13368c12233709eb4c75bbc Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sat, 24 Aug 2024 09:41:37 +0300 Subject: [PATCH 134/302] Skip symlink tests on Windows. --- .../268 install functions and follow symlinks/meson.build | 4 ++++ test cases/common/41 test args/pathtester.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) mode change 100644 => 100755 test cases/common/41 test args/pathtester.py diff --git a/test cases/common/268 install functions and follow symlinks/meson.build b/test cases/common/268 install functions and follow symlinks/meson.build index 327c02131fb3..9158ea8ee3fe 100644 --- a/test cases/common/268 install functions and follow symlinks/meson.build +++ b/test cases/common/268 install functions and follow symlinks/meson.build @@ -1,5 +1,9 @@ project('install_data following symlinks') +if build_machine.system() == 'windows' + error('MESON_SKIP_TEST symlinks (typically) do not work on Windows.') +endif + install_data( 'foo/link1', install_dir: get_option('datadir') / 'followed', diff --git a/test cases/common/41 test args/pathtester.py b/test cases/common/41 test args/pathtester.py old mode 100644 new mode 100755 index 101136611cf5..96152845d664 --- a/test cases/common/41 test args/pathtester.py +++ b/test cases/common/41 test args/pathtester.py @@ -2,7 +2,7 @@ import sys, subprocess -if sys.platorm() == 'win32': +if sys.platform == 'win32': cmd = ['xcopy', '/?'] else: cmd = ['env'] From 415ccb4b16e3432f51c8abe915fcca1494bfcc9b Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 20 Aug 2024 10:39:44 -0700 Subject: [PATCH 135/302] cmake/interpreter: clear up some ambiguous Optional handling It may have all been correct, but mypy and pyright couldn't be sure of that. --- mesonbuild/cmake/interpreter.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/mesonbuild/cmake/interpreter.py b/mesonbuild/cmake/interpreter.py index 7071fe4f8a4f..db0fc4b36606 100644 --- a/mesonbuild/cmake/interpreter.py +++ b/mesonbuild/cmake/interpreter.py @@ -135,10 +135,7 @@ def __init__(self, build_dir: Path): self.build_dir = build_dir def add(self, tgt: T.Union['ConverterTarget', 'ConverterCustomTarget']) -> None: - def assign_keys(keys: T.List[str]) -> None: - for i in [x for x in keys if x]: - self.tgt_map[i] = tgt - keys = [self._target_key(tgt.cmake_name)] + keys: T.List[T.Optional[str]] = [self._target_key(tgt.cmake_name)] if isinstance(tgt, ConverterTarget): keys += [tgt.full_name] keys += [self._rel_artifact_key(x) for x in tgt.artifacts] @@ -146,7 +143,9 @@ def assign_keys(keys: T.List[str]) -> None: if isinstance(tgt, ConverterCustomTarget): keys += [self._rel_generated_file_key(x) for x in tgt.original_outputs] keys += [self._base_generated_file_key(x) for x in tgt.original_outputs] - assign_keys(keys) + for k in keys: + if k is not None: + self.tgt_map[k] = tgt def _return_first_valid_key(self, keys: T.List[str]) -> T.Optional[T.Union['ConverterTarget', 'ConverterCustomTarget']]: for i in keys: From 08a46bb6c5aabb7fccafe95afd7b10a75e9f3e07 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 20 Aug 2024 10:42:11 -0700 Subject: [PATCH 136/302] cmake/interpreter: Fix some incorrect and missing annotations --- mesonbuild/cmake/interpreter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mesonbuild/cmake/interpreter.py b/mesonbuild/cmake/interpreter.py index db0fc4b36606..b427132f6892 100644 --- a/mesonbuild/cmake/interpreter.py +++ b/mesonbuild/cmake/interpreter.py @@ -147,7 +147,7 @@ def add(self, tgt: T.Union['ConverterTarget', 'ConverterCustomTarget']) -> None: if k is not None: self.tgt_map[k] = tgt - def _return_first_valid_key(self, keys: T.List[str]) -> T.Optional[T.Union['ConverterTarget', 'ConverterCustomTarget']]: + def _return_first_valid_key(self, keys: T.List[T.Optional[str]]) -> T.Optional[T.Union['ConverterTarget', 'ConverterCustomTarget']]: for i in keys: if i and i in self.tgt_map: return self.tgt_map[i] @@ -165,7 +165,7 @@ def executable(self, name: str) -> T.Optional['ConverterTarget']: return tgt def artifact(self, name: str) -> T.Optional[T.Union['ConverterTarget', 'ConverterCustomTarget']]: - keys = [] + keys: T.List[T.Optional[str]] = [] candidates = [name, OutputTargetMap.rm_so_version.sub('', name)] for i in lib_suffixes: if not name.endswith('.' + i): From 75e5ca58374fc7d070a6e34822046391cc5a24e5 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 20 Aug 2024 11:29:56 -0700 Subject: [PATCH 137/302] cmake/interpreter: Remove None from values we promise wont have None We've documented these lists as being `List[Path]`, but then we have the potential to insert a None into them via the `rel_path()` function, which can return `None` in some cases. Currently we fix some (but not all) of these later, but we should actually remove them from the list before we assign, so that it's actually a `List[Path]` at all times. While we're here I've simplified the logic a bit. Closes: #13551 --- mesonbuild/cmake/interpreter.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/mesonbuild/cmake/interpreter.py b/mesonbuild/cmake/interpreter.py index b427132f6892..a0fcb6972d0b 100644 --- a/mesonbuild/cmake/interpreter.py +++ b/mesonbuild/cmake/interpreter.py @@ -8,6 +8,7 @@ from functools import lru_cache from os import environ from pathlib import Path +import itertools import re import typing as T @@ -416,11 +417,14 @@ def rel_path(x: Path, is_header: bool, is_generated: bool) -> T.Optional[Path]: return x.relative_to(root_src_dir) return x + def non_optional(inputs: T.Iterable[T.Optional[Path]]) -> T.List[Path]: + return [p for p in inputs if p is not None] + build_dir_rel = self.build_dir.relative_to(Path(self.env.get_build_dir()) / subdir) - self.generated_raw = [rel_path(x, False, True) for x in self.generated_raw] - self.includes = list(OrderedSet([rel_path(x, True, False) for x in OrderedSet(self.includes)] + [build_dir_rel])) - self.sys_includes = list(OrderedSet([rel_path(x, True, False) for x in OrderedSet(self.sys_includes)])) - self.sources = [rel_path(x, False, False) for x in self.sources] + self.generated_raw = non_optional(rel_path(x, False, True) for x in self.generated_raw) + self.includes = non_optional(itertools.chain((rel_path(x, True, False) for x in OrderedSet(self.includes)), [build_dir_rel])) + self.sys_includes = non_optional(rel_path(x, True, False) for x in OrderedSet(self.sys_includes)) + self.sources = non_optional(rel_path(x, False, False) for x in self.sources) # Resolve custom targets for gen_file in self.generated_raw: @@ -430,14 +434,9 @@ def rel_path(x: Path, is_header: bool, is_generated: bool) -> T.Optional[Path]: ref = ctgt.get_ref(gen_file) assert isinstance(ref, CustomTargetReference) and ref.valid() self.generated_ctgt += [ref] - elif gen_file is not None: + else: self.generated += [gen_file] - # Remove delete entries - self.includes = [x for x in self.includes if x is not None] - self.sys_includes = [x for x in self.sys_includes if x is not None] - self.sources = [x for x in self.sources if x is not None] - # Make sure '.' is always in the include directories if Path('.') not in self.includes: self.includes += [Path('.')] From 3c0de471228420c333bb98be35a28705d0ec063d Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 31 Jul 2024 17:18:42 +1000 Subject: [PATCH 138/302] Allow external programs in test()'s 'args' parameter Although it's not especially common, there are certainly cases where it's useful to pass the path to an external program to a test program. Fixes: https://github.com/mesonbuild/meson/issues/3552 Signed-off-by: David Gibson --- .../snippets/test_args_accepts_external_program.md | 10 ++++++++++ docs/yaml/functions/benchmark.yaml | 2 +- mesonbuild/backend/backends.py | 2 ++ mesonbuild/interpreter/interpreter.py | 2 ++ mesonbuild/interpreter/interpreterobjects.py | 2 +- mesonbuild/interpreter/kwargs.py | 2 +- mesonbuild/interpreter/type_checking.py | 2 +- test cases/common/41 test args/meson.build | 4 ++++ test cases/common/41 test args/wrap.py | 6 ++++++ test cases/failing/112 run_target in test/test.json | 2 +- 10 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 docs/markdown/snippets/test_args_accepts_external_program.md create mode 100755 test cases/common/41 test args/wrap.py diff --git a/docs/markdown/snippets/test_args_accepts_external_program.md b/docs/markdown/snippets/test_args_accepts_external_program.md new file mode 100644 index 000000000000..d730ad5f3be5 --- /dev/null +++ b/docs/markdown/snippets/test_args_accepts_external_program.md @@ -0,0 +1,10 @@ +## test() and benchmark() functions accept new types + +`test` and `benchmark` now accept ExternalPrograms (as returned by +`find_program`) in the `args` list. This can be useful where the test +executable is a wrapper which invokes another program given as an +argument. + +```meson +test('some_test', find_program('sudo'), args : [ find_program('sh'), 'script.sh' ]) +``` diff --git a/docs/yaml/functions/benchmark.yaml b/docs/yaml/functions/benchmark.yaml index 0323b26e41b9..7a555a42d6a0 100644 --- a/docs/yaml/functions/benchmark.yaml +++ b/docs/yaml/functions/benchmark.yaml @@ -28,7 +28,7 @@ posargs: kwargs: args: - type: list[str | file | tgt] + type: list[str | file | tgt | external_program] description: Arguments to pass to the executable env: diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index 9b26d9e6caf5..e35660b69a51 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -1261,6 +1261,8 @@ def create_test_serialisation(self, tests: T.List['Test']) -> T.List[TestSeriali cmd_args.append(a) elif isinstance(a, (build.Target, build.CustomTargetIndex)): cmd_args.extend(self.construct_target_rel_paths(a, t.workdir)) + elif isinstance(a, programs.ExternalProgram): + cmd_args.extend(a.get_command()) else: raise MesonException('Bad object in test command.') diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index 9a524037af41..92315ff0fd31 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -2268,6 +2268,8 @@ def add_test(self, node: mparser.BaseNode, kwargs: T.Dict[str, T.Any], is_base_test: bool): if isinstance(args[1], (build.CustomTarget, build.CustomTargetIndex)): FeatureNew.single_use('test with CustomTarget as command', '1.4.0', self.subproject) + if any(isinstance(i, ExternalProgram) for i in kwargs['args']): + FeatureNew.single_use('test with external_program in args', '1.6.0', self.subproject) t = self.make_test(node, args, kwargs) if is_base_test: diff --git a/mesonbuild/interpreter/interpreterobjects.py b/mesonbuild/interpreter/interpreterobjects.py index d5c1efaa8372..bbc5b8608369 100644 --- a/mesonbuild/interpreter/interpreterobjects.py +++ b/mesonbuild/interpreter/interpreterobjects.py @@ -753,7 +753,7 @@ def __init__(self, name: str, project: str, suite: T.List[str], exe: T.Union[ExternalProgram, build.Executable, build.CustomTarget, build.CustomTargetIndex], depends: T.List[T.Union[build.CustomTarget, build.BuildTarget]], is_parallel: bool, - cmd_args: T.List[T.Union[str, mesonlib.File, build.Target]], + cmd_args: T.List[T.Union[str, mesonlib.File, build.Target, ExternalProgram]], env: mesonlib.EnvironmentVariables, should_fail: bool, timeout: int, workdir: T.Optional[str], protocol: str, priority: int, verbose: bool): diff --git a/mesonbuild/interpreter/kwargs.py b/mesonbuild/interpreter/kwargs.py index 461ddc9bfbe9..eee53c5ff413 100644 --- a/mesonbuild/interpreter/kwargs.py +++ b/mesonbuild/interpreter/kwargs.py @@ -38,7 +38,7 @@ class BaseTest(TypedDict): """Shared base for the Rust module.""" - args: T.List[T.Union[str, File, build.Target]] + args: T.List[T.Union[str, File, build.Target, ExternalProgram]] should_fail: bool timeout: int workdir: T.Optional[str] diff --git a/mesonbuild/interpreter/type_checking.py b/mesonbuild/interpreter/type_checking.py index 0d92a3dbf7cc..ed34be950065 100644 --- a/mesonbuild/interpreter/type_checking.py +++ b/mesonbuild/interpreter/type_checking.py @@ -485,7 +485,7 @@ def link_whole_validator(values: T.List[T.Union[StaticLibrary, CustomTarget, Cus PRESERVE_PATH_KW: KwargInfo[bool] = KwargInfo('preserve_path', bool, default=False, since='0.63.0') TEST_KWS: T.List[KwargInfo] = [ - KwargInfo('args', ContainerTypeInfo(list, (str, File, BuildTarget, CustomTarget, CustomTargetIndex)), + KwargInfo('args', ContainerTypeInfo(list, (str, File, BuildTarget, CustomTarget, CustomTargetIndex, ExternalProgram)), listify=True, default=[]), KwargInfo('should_fail', bool, default=False), KwargInfo('timeout', int, default=30), diff --git a/test cases/common/41 test args/meson.build b/test cases/common/41 test args/meson.build index 7efd8d5daa90..ddd369e7fc5f 100644 --- a/test cases/common/41 test args/meson.build +++ b/test cases/common/41 test args/meson.build @@ -45,3 +45,7 @@ custompathtgt = custom_target('testpathappend', build_always : true, command : [pathtester], env : env) + +# https://github.com/mesonbuild/meson/issues/3552 +wrap = find_program('wrap.py') +test('external program arg', wrap, args : [testerpy, testfile]) diff --git a/test cases/common/41 test args/wrap.py b/test cases/common/41 test args/wrap.py new file mode 100755 index 000000000000..87508e0083d3 --- /dev/null +++ b/test cases/common/41 test args/wrap.py @@ -0,0 +1,6 @@ +#!/usr/bin/env python3 + +import subprocess +import sys + +subprocess.run(sys.argv[1:]) diff --git a/test cases/failing/112 run_target in test/test.json b/test cases/failing/112 run_target in test/test.json index 100db94821d3..515897899d34 100644 --- a/test cases/failing/112 run_target in test/test.json +++ b/test cases/failing/112 run_target in test/test.json @@ -1,7 +1,7 @@ { "stdout": [ { - "line": "test cases/failing/112 run_target in test/meson.build:7:0: ERROR: test keyword argument 'args' was of type array[RunTarget] but should have been array[str | File | BuildTarget | CustomTarget | CustomTargetIndex]" + "line": "test cases/failing/112 run_target in test/meson.build:7:0: ERROR: test keyword argument 'args' was of type array[RunTarget] but should have been array[str | File | BuildTarget | CustomTarget | CustomTargetIndex | ExternalProgram]" } ] } From 1794a1e63c8a890aa924b3594946b23fcefcbc9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Piku=C5=82a?= Date: Tue, 27 Aug 2024 02:12:46 +0200 Subject: [PATCH 139/302] Extend MESON_TESTTHREADS usage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, setting `MESON_TESTTHREADS` to a number lower than 1 resulted in unexpected behavior. This commit introduces test for negative value (with fallback to 1), and fallback to core count in case it is set to 0. It improves experience in job-matrix type of CI workflows, where some jobs within the matrix require single job execution, whereas others can default to taking core count as the job count. Signed-off-by: Marek Pikuła --- docs/markdown/Unit-tests.md | 4 ++++ mesonbuild/mtest.py | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/markdown/Unit-tests.md b/docs/markdown/Unit-tests.md index b5d3a1b81831..898366095b05 100644 --- a/docs/markdown/Unit-tests.md +++ b/docs/markdown/Unit-tests.md @@ -89,6 +89,10 @@ variable `MESON_TESTTHREADS` like this. $ MESON_TESTTHREADS=5 meson test ``` +Setting `MESON_TESTTHREADS` to 0 enables the default behavior (core +count), whereas setting an invalid value results in setting the job +count to 1. + ## Priorities *(added in version 0.52.0)* diff --git a/mesonbuild/mtest.py b/mesonbuild/mtest.py index 9975afa22a9b..c417bc0b38b7 100644 --- a/mesonbuild/mtest.py +++ b/mesonbuild/mtest.py @@ -99,13 +99,17 @@ def uniwidth(s: str) -> int: def determine_worker_count() -> int: varname = 'MESON_TESTTHREADS' + num_workers = 0 if varname in os.environ: try: num_workers = int(os.environ[varname]) + if num_workers < 0: + raise ValueError except ValueError: print(f'Invalid value in {varname}, using 1 thread.') num_workers = 1 - else: + + if num_workers == 0: try: # Fails in some weird environments such as Debian # reproducible build. From 29797f92f818744adcdb354ca798036168608ac7 Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Thu, 15 Jun 2023 16:27:18 -0400 Subject: [PATCH 140/302] Feature checks: fall back to reporting insufficiently portable features When projects do not specify a minimum meson version, we used to avoid giving them the benefit of the Feature checks framework. Instead: - warn for features that were added after the most recent semver bump, since they aren't portable to the range of versions people might use these days - warn for features that were deprecated before the upcoming semver bump, i.e. all deprecated features, since they aren't portable to upcoming semver-compatible versions people might be imminently upgrading to --- .../snippets/always_report_deprecations.md | 29 ++++++++ mesonbuild/interpreter/interpreter.py | 2 + mesonbuild/interpreterbase/decorators.py | 68 ++++++++++++------- mesonbuild/utils/universal.py | 6 +- 4 files changed, 80 insertions(+), 25 deletions(-) create mode 100644 docs/markdown/snippets/always_report_deprecations.md diff --git a/docs/markdown/snippets/always_report_deprecations.md b/docs/markdown/snippets/always_report_deprecations.md new file mode 100644 index 000000000000..fbf4cdf4701e --- /dev/null +++ b/docs/markdown/snippets/always_report_deprecations.md @@ -0,0 +1,29 @@ +## Default to printing deprecations when no minimum version is specified. + +For a long time, the [[project]] function has supported specifying the minimum +`meson_version:` needed by a project. When this is used, deprecated features +from before that version produce warnings, as do features which aren't +available in all supported versions. + +When no minimum version was specified, meson didn't warn you even about +deprecated functionality that might go away in an upcoming semver major release +of meson. + +Now, meson will treat an unspecified minimum version following semver: + +- For new features introduced in the current meson semver major cycle + (currently: all features added since 1.0) a warning is printed. Features that + have been available since the initial 1.0 release are assumed to be widely + available. + +- For features that have been deprecated by any version of meson, a warning is + printed. Since no minimum version was specified, it is assumed that the + project wishes to follow the latest and greatest functionality. + +These warnings will overlap for functionality that was both deprecated and +replaced with an alternative in the current release cycle. The combination +means that projects without a minimum version specified are assumed to want +broad compatibility with the current release cycle (1.x). + +Projects that specify a minimum `meson_version:` will continue to only receive +actionable warnings based on their current minimum version. diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index 92315ff0fd31..7bcbf8c6de02 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -1178,6 +1178,8 @@ def func_project(self, node: mparser.FunctionNode, args: T.Tuple[str, T.List[str # for things like deprecation testing. if kwargs['meson_version']: self.handle_meson_version(kwargs['meson_version'], node) + else: + mesonlib.project_meson_versions[self.subproject] = mesonlib.NoProjectVersion() # Load "meson.options" before "meson_options.txt", and produce a warning if # it is being used with an old version. I have added check that if both diff --git a/mesonbuild/interpreterbase/decorators.py b/mesonbuild/interpreterbase/decorators.py index 6524aa92dd4f..fe6f6a53bd1b 100644 --- a/mesonbuild/interpreterbase/decorators.py +++ b/mesonbuild/interpreterbase/decorators.py @@ -3,7 +3,7 @@ from __future__ import annotations -from .. import mesonlib, mlog +from .. import coredata, mesonlib, mlog from .disabler import Disabler from .exceptions import InterpreterException, InvalidArguments from ._unholder import _unholder @@ -585,7 +585,7 @@ def __init__(self, feature_name: str, feature_version: str, extra_message: str = self.extra_message = extra_message @staticmethod - def get_target_version(subproject: str) -> str: + def get_target_version(subproject: str) -> T.Union[str, mesonlib.NoProjectVersion]: # Don't do any checks if project() has not been parsed yet if subproject not in mesonlib.project_meson_versions: return '' @@ -593,7 +593,7 @@ def get_target_version(subproject: str) -> str: @staticmethod @abc.abstractmethod - def check_version(target_version: str, feature_version: str) -> bool: + def check_version(target_version: T.Union[str, mesonlib.NoProjectVersion], feature_version: str) -> bool: pass def use(self, subproject: 'SubProject', location: T.Optional['mparser.BaseNode'] = None) -> None: @@ -642,15 +642,15 @@ def report(cls, subproject: str) -> None: if '\n' in warning_str: mlog.warning(warning_str) - def log_usage_warning(self, tv: str, location: T.Optional['mparser.BaseNode']) -> None: + def log_usage_warning(self, tv: T.Union[str, mesonlib.NoProjectVersion], location: T.Optional['mparser.BaseNode']) -> None: raise InterpreterException('log_usage_warning not implemented') @staticmethod - def get_warning_str_prefix(tv: str) -> str: + def get_warning_str_prefix(tv: T.Union[str, mesonlib.NoProjectVersion]) -> str: raise InterpreterException('get_warning_str_prefix not implemented') @staticmethod - def get_notice_str_prefix(tv: str) -> str: + def get_notice_str_prefix(tv: T.Union[str, mesonlib.NoProjectVersion]) -> str: raise InterpreterException('get_notice_str_prefix not implemented') def __call__(self, f: TV_func) -> TV_func: @@ -679,20 +679,32 @@ class FeatureNew(FeatureCheckBase): feature_registry = {} @staticmethod - def check_version(target_version: str, feature_version: str) -> bool: - return mesonlib.version_compare_condition_with_min(target_version, feature_version) + def check_version(target_version: T.Union[str, mesonlib.NoProjectVersion], feature_version: str) -> bool: + if isinstance(target_version, str): + return mesonlib.version_compare_condition_with_min(target_version, feature_version) + else: + # Warn for anything newer than the current semver base slot. + major = coredata.version.split('.', maxsplit=1)[0] + return mesonlib.version_compare(feature_version, f'<{major}.0') @staticmethod - def get_warning_str_prefix(tv: str) -> str: - return f'Project specifies a minimum meson_version \'{tv}\' but uses features which were added in newer versions:' + def get_warning_str_prefix(tv: T.Union[str, mesonlib.NoProjectVersion]) -> str: + if isinstance(tv, str): + return f'Project specifies a minimum meson_version \'{tv}\' but uses features which were added in newer versions:' + else: + return 'Project specifies no minimum version but uses features which were added in versions:' @staticmethod - def get_notice_str_prefix(tv: str) -> str: + def get_notice_str_prefix(tv: T.Union[str, mesonlib.NoProjectVersion]) -> str: return '' - def log_usage_warning(self, tv: str, location: T.Optional['mparser.BaseNode']) -> None: + def log_usage_warning(self, tv: T.Union[str, mesonlib.NoProjectVersion], location: T.Optional['mparser.BaseNode']) -> None: + if isinstance(tv, str): + prefix = f'Project targets {tv!r}' + else: + prefix = 'Project does not target a minimum version' args = [ - 'Project targets', f"'{tv}'", + prefix, 'but uses feature introduced in', f"'{self.feature_version}':", f'{self.feature_name}.', @@ -711,21 +723,29 @@ class FeatureDeprecated(FeatureCheckBase): emit_notice = True @staticmethod - def check_version(target_version: str, feature_version: str) -> bool: - # For deprecation checks we need to return the inverse of FeatureNew checks - return not mesonlib.version_compare_condition_with_min(target_version, feature_version) + def check_version(target_version: T.Union[str, mesonlib.NoProjectVersion], feature_version: str) -> bool: + if isinstance(target_version, str): + # For deprecation checks we need to return the inverse of FeatureNew checks + return not mesonlib.version_compare_condition_with_min(target_version, feature_version) + else: + # Always warn for functionality deprecated in the current semver slot (i.e. the current version). + return False @staticmethod - def get_warning_str_prefix(tv: str) -> str: + def get_warning_str_prefix(tv: T.Union[str, mesonlib.NoProjectVersion]) -> str: return 'Deprecated features used:' @staticmethod - def get_notice_str_prefix(tv: str) -> str: + def get_notice_str_prefix(tv: T.Union[str, mesonlib.NoProjectVersion]) -> str: return 'Future-deprecated features used:' - def log_usage_warning(self, tv: str, location: T.Optional['mparser.BaseNode']) -> None: + def log_usage_warning(self, tv: T.Union[str, mesonlib.NoProjectVersion], location: T.Optional['mparser.BaseNode']) -> None: + if isinstance(tv, str): + prefix = f'Project targets {tv!r}' + else: + prefix = 'Project does not target a minimum version' args = [ - 'Project targets', f"'{tv}'", + prefix, 'but uses feature deprecated since', f"'{self.feature_version}':", f'{self.feature_name}.', @@ -745,19 +765,19 @@ class FeatureBroken(FeatureCheckBase): unconditional = True @staticmethod - def check_version(target_version: str, feature_version: str) -> bool: + def check_version(target_version: T.Union[str, mesonlib.NoProjectVersion], feature_version: str) -> bool: # always warn for broken stuff return False @staticmethod - def get_warning_str_prefix(tv: str) -> str: + def get_warning_str_prefix(tv: T.Union[str, mesonlib.NoProjectVersion]) -> str: return 'Broken features used:' @staticmethod - def get_notice_str_prefix(tv: str) -> str: + def get_notice_str_prefix(tv: T.Union[str, mesonlib.NoProjectVersion]) -> str: return '' - def log_usage_warning(self, tv: str, location: T.Optional['mparser.BaseNode']) -> None: + def log_usage_warning(self, tv: T.Union[str, mesonlib.NoProjectVersion], location: T.Optional['mparser.BaseNode']) -> None: args = [ 'Project uses feature that was always broken,', 'and is now deprecated since', diff --git a/mesonbuild/utils/universal.py b/mesonbuild/utils/universal.py index 574bcb51f654..88d8e1f891c7 100644 --- a/mesonbuild/utils/universal.py +++ b/mesonbuild/utils/universal.py @@ -57,6 +57,7 @@ class _VerPickleLoadable(Protocol): __all__ = [ 'GIT', 'python_command', + 'NoProjectVersion', 'project_meson_versions', 'SecondLevelHolder', 'File', @@ -157,10 +158,13 @@ class _VerPickleLoadable(Protocol): ] +class NoProjectVersion: + pass + # TODO: this is such a hack, this really should be either in coredata or in the # interpreter # {subproject: project_meson_version} -project_meson_versions: T.DefaultDict[str, str] = collections.defaultdict(str) +project_meson_versions: T.Dict[str, T.Union[str, NoProjectVersion]] = {} from glob import glob From 19847ba24a5a6e7c33c4e00a49842d77f7c5a4a3 Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Thu, 29 Aug 2024 18:46:44 -0400 Subject: [PATCH 141/302] update various deprecation notices to call out meson 2.0 --- mesonbuild/build.py | 2 +- mesonbuild/environment.py | 2 +- mesonbuild/interpreter/interpreter.py | 6 +++--- mesonbuild/interpreter/interpreterobjects.py | 2 +- mesonbuild/modules/pkgconfig.py | 2 +- mesonbuild/mparser.py | 2 +- mesonbuild/options.py | 4 ++-- unittests/allplatformstests.py | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index b9cc42721fc5..a7a43b40cffe 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -1702,7 +1702,7 @@ def check_module_linking(self): else: mlog.deprecation(f'target {self.name} links against shared module {link_target.name}, which is incorrect.' '\n ' - f'This will be an error in the future, so please use shared_library() for {link_target.name} instead.' + f'This will be an error in meson 2.0, so please use shared_library() for {link_target.name} instead.' '\n ' f'If shared_module() was used for {link_target.name} because it has references to undefined symbols,' '\n ' diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index c26516215b6b..5f4de73d59e6 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -694,7 +694,7 @@ def _load_machine_file_options(self, config: 'ConfigParser', properties: Propert key = OptionKey.from_string(k) # If we're in the cross file, and there is a `build.foo` warn about that. Later we'll remove it. if machine is MachineChoice.HOST and key.machine is not machine: - mlog.deprecation('Setting build machine options in cross files, please use a native file instead, this will be removed in meson 0.60', once=True) + mlog.deprecation('Setting build machine options in cross files, please use a native file instead, this will be removed in meson 2.0', once=True) if key.subproject: raise MesonException('Do not set subproject options in [built-in options] section, use [subproject:built-in options] instead.') self.options[key.evolve(subproject=subproject, machine=machine)] = v diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index 7bcbf8c6de02..9de0f8762e17 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -256,7 +256,7 @@ class InterpreterRuleRelaxation(Enum): implicit_check_false_warning = """You should add the boolean check kwarg to the run_command call. It currently defaults to false, - but it will default to true in future releases of meson. + but it will default to true in meson 2.0. See also: https://github.com/mesonbuild/meson/issues/9300""" class Interpreter(InterpreterBase, HoldableObject): @@ -2300,7 +2300,7 @@ def func_install_headers(self, node: mparser.BaseNode, if kwargs['install_dir'] is not None: raise InterpreterException('install_headers: cannot specify both "install_dir" and "subdir". Use only "install_dir".') if os.path.isabs(install_subdir): - mlog.deprecation('Subdir keyword must not be an absolute path. This will be a hard error in the next release.') + mlog.deprecation('Subdir keyword must not be an absolute path. This will be a hard error in meson 2.0.') else: install_subdir = '' @@ -3157,7 +3157,7 @@ def source_strings_to_files(self, sources: T.List['SourceInputs'], strict: bool if not strict and s.startswith(self.environment.get_build_dir()): results.append(s) mlog.warning(f'Source item {s!r} cannot be converted to File object, because it is a generated file. ' - 'This will become a hard error in the future.', location=self.current_node) + 'This will become a hard error in meson 2.0.', location=self.current_node) else: self.validate_within_subproject(self.subdir, s) results.append(mesonlib.File.from_source_file(self.environment.source_dir, self.subdir, s)) diff --git a/mesonbuild/interpreter/interpreterobjects.py b/mesonbuild/interpreter/interpreterobjects.py index bbc5b8608369..155cfd23e56e 100644 --- a/mesonbuild/interpreter/interpreterobjects.py +++ b/mesonbuild/interpreter/interpreterobjects.py @@ -938,7 +938,7 @@ def extract_objects_method(self, args: T.Tuple[T.List[T.Union[mesonlib.FileOrStr extract_all_objects called without setting recursive keyword argument. Meson currently defaults to non-recursive to maintain backward compatibility but - the default will be changed in the future. + the default will be changed in meson 2.0. ''') ) ) diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index 16c8c079846d..61de8fc43ac1 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -127,7 +127,7 @@ def _check_generated_pc_deprecation(self, obj: T.Union[build.CustomTarget, build 'to generate() method instead of first positional ' 'argument.', 'Adding', mlog.bold(data.display_name), 'to "Requires" field, but this is a deprecated ' - 'behaviour that will change in a future version ' + 'behaviour that will change in version 2.0 ' 'of Meson. Please report the issue if this ' 'warning cannot be avoided in your case.', location=data.location) diff --git a/mesonbuild/mparser.py b/mesonbuild/mparser.py index fc37d2a54e2b..79ece3789cd6 100644 --- a/mesonbuild/mparser.py +++ b/mesonbuild/mparser.py @@ -362,7 +362,7 @@ def append(self, statement: BaseNode) -> None: def set_kwarg(self, name: IdNode, value: BaseNode) -> None: if any((isinstance(x, IdNode) and name.value == x.value) for x in self.kwargs): mlog.warning(f'Keyword argument "{name.value}" defined multiple times.', location=self) - mlog.warning('This will be an error in future Meson releases.') + mlog.warning('This will be an error in Meson 2.0.') self.kwargs[name] = value def set_kwarg_no_check(self, name: BaseNode, value: BaseNode) -> None: diff --git a/mesonbuild/options.py b/mesonbuild/options.py index 912cfa23b978..d3d0c6789c4e 100644 --- a/mesonbuild/options.py +++ b/mesonbuild/options.py @@ -409,7 +409,7 @@ def validate_value(self, value: T.Union[str, T.List[str]]) -> T.List[str]: if not self.allow_dups and len(set(newvalue)) != len(newvalue): msg = 'Duplicated values in array option is deprecated. ' \ - 'This will become a hard error in the future.' + 'This will become a hard error in meson 2.0.' mlog.deprecation(msg) for i in newvalue: if not isinstance(i, str): @@ -500,7 +500,7 @@ def validate_value(self, value: T.Union[str, T.List[str]]) -> str: mlog.deprecation( f'None of the values {candidates} are supported by the {self.lang} compiler.\n' + f'However, the deprecated {std} std currently falls back to {newstd}.\n' + - 'This will be an error in the future.\n' + + 'This will be an error in meson 2.0.\n' + 'If the project supports both GNU and MSVC compilers, a value such as\n' + '"c_std=gnu11,c11" specifies that GNU is preferred but it can safely fallback to plain c11.') return newstd diff --git a/unittests/allplatformstests.py b/unittests/allplatformstests.py index dac7f97971d7..ccd2c476a8ef 100644 --- a/unittests/allplatformstests.py +++ b/unittests/allplatformstests.py @@ -2464,7 +2464,7 @@ def test_check_module_linking(self): tdir = os.path.join(self.unit_test_dir, '30 shared_mod linking') out = self.init(tdir) msg = ('''DEPRECATION: target prog links against shared module mymod, which is incorrect. - This will be an error in the future, so please use shared_library() for mymod instead. + This will be an error in meson 2.0, so please use shared_library() for mymod instead. If shared_module() was used for mymod because it has references to undefined symbols, use shared_library() with `override_options: ['b_lundef=false']` instead.''') self.assertIn(msg, out) From 18427adbf21909f66a307a54ba4c47fd91e18fba Mon Sep 17 00:00:00 2001 From: Elliot <35050275+apache-hb@users.noreply.github.com> Date: Fri, 16 Aug 2024 11:28:48 +0100 Subject: [PATCH 142/302] Add lto support to clang-cl and lld-link Enables lto & thinlto support for clang-cl when used with lld-link. --- mesonbuild/compilers/mixins/visualstudio.py | 29 +++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/mesonbuild/compilers/mixins/visualstudio.py b/mesonbuild/compilers/mixins/visualstudio.py index 78d62cb4293c..b4677f4172ba 100644 --- a/mesonbuild/compilers/mixins/visualstudio.py +++ b/mesonbuild/compilers/mixins/visualstudio.py @@ -16,6 +16,7 @@ from ... import mlog from mesonbuild.compilers.compilers import CompileCheckMode from ...options import OptionKey +from mesonbuild.linkers.linkers import ClangClDynamicLinker if T.TYPE_CHECKING: from ...environment import Environment @@ -443,6 +444,10 @@ class ClangClCompiler(VisualStudioLikeCompiler): def __init__(self, target: str): super().__init__(target) + self.base_options.update( + {OptionKey('b_lto_threads'), OptionKey('b_lto'), OptionKey('b_lto_mode'), OptionKey('b_thinlto_cache'), + OptionKey('b_thinlto_cache_dir')}) + # Assembly self.can_compile_suffixes.add('s') self.can_compile_suffixes.add('sx') @@ -494,3 +499,27 @@ def openmp_link_flags(self, env: Environment) -> T.List[str]: if libs is None: raise mesonlib.MesonBugException('Could not find libomp') return super().openmp_link_flags(env) + libs + + def get_lto_compile_args(self, *, threads: int = 0, mode: str = 'default') -> T.List[str]: + args: T.List[str] = [] + if mode == 'thin': + # LTO data generated by clang-cl is only usable by lld-link + if not isinstance(self.linker, ClangClDynamicLinker): + raise mesonlib.MesonException(f"LLVM's ThinLTO only works with lld-link, not {self.linker.id}") + args.append(f'-flto={mode}') + else: + assert mode == 'default', 'someone forgot to wire something up' + args.extend(super().get_lto_compile_args(threads=threads)) + return args + + def get_lto_link_args(self, *, threads: int = 0, mode: str = 'default', + thinlto_cache_dir: T.Optional[str] = None) -> T.List[str]: + args = [] + if mode == 'thin' and thinlto_cache_dir is not None: + args.extend(self.linker.get_thinlto_cache_args(thinlto_cache_dir)) + # lld-link /threads:N has the same behaviour as -flto-jobs=N in lld + if threads > 0: + # clang-cl was released after clang already had LTO support, so it + # is safe to assume that all versions of clang-cl support LTO + args.append(f'/threads:{threads}') + return args From df41e7843e74ea6c2a5c98920f5bea8f1b94a064 Mon Sep 17 00:00:00 2001 From: yehor <64604791+oworope@users.noreply.github.com> Date: Sun, 1 Sep 2024 11:39:08 +0300 Subject: [PATCH 143/302] fix a typo --- docs/markdown/Dependencies.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/markdown/Dependencies.md b/docs/markdown/Dependencies.md index d91582523d44..a457342d1a9c 100644 --- a/docs/markdown/Dependencies.md +++ b/docs/markdown/Dependencies.md @@ -766,7 +766,7 @@ your own risk. ## SDL2 -SDL2 can be located using `pkg-confg`, the `sdl2-config` config tool, +SDL2 can be located using `pkg-config`, the `sdl2-config` config tool, as an OSX framework, or `cmake`. `method` may be `auto`, `config-tool`, `extraframework`, From d299add709ebaa2bdde77f7a20308a6eacda1d9a Mon Sep 17 00:00:00 2001 From: Daniele Nicolodi Date: Sun, 1 Sep 2024 17:47:53 +0200 Subject: [PATCH 144/302] intro: add install_rpath to intro-install_plan.json --- mesonbuild/mintro.py | 1 + unittests/allplatformstests.py | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py index ef2169bf4dd1..07ad533d3f05 100644 --- a/mesonbuild/mintro.py +++ b/mesonbuild/mintro.py @@ -131,6 +131,7 @@ def list_install_plan(installdata: backends.InstallData) -> T.Dict[str, T.Dict[s 'destination': target.out_name, 'tag': target.tag or None, 'subproject': target.subproject or None, + 'install_rpath': target.install_rpath or None } for target in installdata.targets }, diff --git a/unittests/allplatformstests.py b/unittests/allplatformstests.py index ccd2c476a8ef..3be97cb3b613 100644 --- a/unittests/allplatformstests.py +++ b/unittests/allplatformstests.py @@ -4645,101 +4645,121 @@ def output_name(name, type_): 'targets': { f'{self.builddir}/out1-notag.txt': { 'destination': '{datadir}/out1-notag.txt', + 'install_rpath': None, 'tag': None, 'subproject': None, }, f'{self.builddir}/out2-notag.txt': { 'destination': '{datadir}/out2-notag.txt', + 'install_rpath': None, 'tag': None, 'subproject': None, }, f'{self.builddir}/libstatic.a': { 'destination': '{libdir_static}/libstatic.a', + 'install_rpath': None, 'tag': 'devel', 'subproject': None, }, f'{self.builddir}/' + exe_name('app'): { 'destination': '{bindir}/' + exe_name('app'), + 'install_rpath': None, 'tag': 'runtime', 'subproject': None, }, f'{self.builddir}/' + exe_name('app-otherdir'): { 'destination': '{prefix}/otherbin/' + exe_name('app-otherdir'), + 'install_rpath': None, 'tag': 'runtime', 'subproject': None, }, f'{self.builddir}/subdir/' + exe_name('app2'): { 'destination': '{bindir}/' + exe_name('app2'), + 'install_rpath': None, 'tag': 'runtime', 'subproject': None, }, f'{self.builddir}/' + shared_lib_name('shared'): { 'destination': '{libdir_shared}/' + shared_lib_name('shared'), + 'install_rpath': None, 'tag': 'runtime', 'subproject': None, }, f'{self.builddir}/' + shared_lib_name('both'): { 'destination': '{libdir_shared}/' + shared_lib_name('both'), + 'install_rpath': None, 'tag': 'runtime', 'subproject': None, }, f'{self.builddir}/' + static_lib_name('both'): { 'destination': '{libdir_static}/' + static_lib_name('both'), + 'install_rpath': None, 'tag': 'devel', 'subproject': None, }, f'{self.builddir}/' + shared_lib_name('bothcustom'): { 'destination': '{libdir_shared}/' + shared_lib_name('bothcustom'), + 'install_rpath': None, 'tag': 'custom', 'subproject': None, }, f'{self.builddir}/' + static_lib_name('bothcustom'): { 'destination': '{libdir_static}/' + static_lib_name('bothcustom'), + 'install_rpath': None, 'tag': 'custom', 'subproject': None, }, f'{self.builddir}/subdir/' + shared_lib_name('both2'): { 'destination': '{libdir_shared}/' + shared_lib_name('both2'), + 'install_rpath': None, 'tag': 'runtime', 'subproject': None, }, f'{self.builddir}/subdir/' + static_lib_name('both2'): { 'destination': '{libdir_static}/' + static_lib_name('both2'), + 'install_rpath': None, 'tag': 'devel', 'subproject': None, }, f'{self.builddir}/out1-custom.txt': { 'destination': '{datadir}/out1-custom.txt', + 'install_rpath': None, 'tag': 'custom', 'subproject': None, }, f'{self.builddir}/out2-custom.txt': { 'destination': '{datadir}/out2-custom.txt', + 'install_rpath': None, 'tag': 'custom', 'subproject': None, }, f'{self.builddir}/out3-custom.txt': { 'destination': '{datadir}/out3-custom.txt', + 'install_rpath': None, 'tag': 'custom', 'subproject': None, }, f'{self.builddir}/subdir/out1.txt': { 'destination': '{datadir}/out1.txt', + 'install_rpath': None, 'tag': None, 'subproject': None, }, f'{self.builddir}/subdir/out2.txt': { 'destination': '{datadir}/out2.txt', + 'install_rpath': None, 'tag': None, 'subproject': None, }, f'{self.builddir}/out-devel.h': { 'destination': '{includedir}/out-devel.h', + 'install_rpath': None, 'tag': 'devel', 'subproject': None, }, f'{self.builddir}/out3-notag.txt': { 'destination': '{datadir}/out3-notag.txt', + 'install_rpath': None, 'tag': None, 'subproject': None, }, From 05347536628bfe85ab51b41a19d1b70a742d3bd1 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Wed, 4 Sep 2024 09:25:39 -0700 Subject: [PATCH 145/302] Add missing `__future__.annotations` imports --- mesonbuild/machinefile.py | 2 ++ mesonbuild/options.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/mesonbuild/machinefile.py b/mesonbuild/machinefile.py index afeb4d05637c..bc290bef0632 100644 --- a/mesonbuild/machinefile.py +++ b/mesonbuild/machinefile.py @@ -1,6 +1,8 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright 2013-2024 Contributors to the The Meson project +# Copyright © 2024 Intel Corporation +from __future__ import annotations import typing as T import configparser import os diff --git a/mesonbuild/options.py b/mesonbuild/options.py index d3d0c6789c4e..020c2e623cb4 100644 --- a/mesonbuild/options.py +++ b/mesonbuild/options.py @@ -1,6 +1,8 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright 2013-2024 Contributors to the The Meson project +# Copyright © 2024 Intel Corporation +from __future__ import annotations from collections import OrderedDict from itertools import chain from functools import total_ordering From 7071ee632c291a2caa1c73ca003d9829ba630a09 Mon Sep 17 00:00:00 2001 From: LIU Hao Date: Thu, 29 Aug 2024 22:27:51 +0800 Subject: [PATCH 146/302] docs: Update descriptions of `host_machine.system()` about Windows There are two environments on Windows: * When invoked in a Cygwin or MSYS2 MSYS shell, `host_machine.system()` returns `cygwin`. * When invoked in a MSYS2 MINGW32/MINGW64/UCRT64/CLANG64/etc., `host_machine.system()` returns `windows`. --- docs/markdown/Reference-tables.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/markdown/Reference-tables.md b/docs/markdown/Reference-tables.md index 67eccb4a2465..7e0d6cffc256 100644 --- a/docs/markdown/Reference-tables.md +++ b/docs/markdown/Reference-tables.md @@ -155,7 +155,7 @@ These are provided by the `.system()` method call. | Value | Comment | | ----- | ------- | | android | By convention only, subject to change | -| cygwin | The Cygwin environment for Windows | +| cygwin | Cygwin or MSYS2 environment on Windows | | darwin | Either OSX or iOS | | dragonfly | DragonFly BSD | | emscripten | Emscripten's JavaScript environment | @@ -165,7 +165,7 @@ These are provided by the `.system()` method call. | linux | | | netbsd | | | openbsd | | -| windows | Any version of Windows | +| windows | Native Windows (not Cygwin or MSYS2) | | sunos | illumos and Solaris | Any string not listed above is not guaranteed to remain stable in From 49a58cf7433e8438f9151d7b84fd2620c7e95632 Mon Sep 17 00:00:00 2001 From: sid Date: Thu, 15 Aug 2024 16:41:43 +0100 Subject: [PATCH 147/302] modules/gnome: Make 'gnome.yelp()' install actual media with symlinks In cases, when localized media files are provided by some languages, we need to use 'gnome.yelp ()' with 'symlink_media: false' which copies all files from 'C' locale in addition to the localized media. This wastes storage space. The alternative is to use 'symlink_media: true' which symlinks entirely to 'C' media files ignoring localized media files. As a middle ground, if the localized media file exists in the source tree for a language, we use that file rather than symlinking to 'C' media with the same filename even when 'symlink_media: true'. This saves storage space. If there are no localized media files in non-C language, the existing behaviour is maintained. --- mesonbuild/modules/gnome.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index 24ab50efcdda..e0c1214d0851 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -1335,15 +1335,18 @@ def yelp(self, state: 'ModuleState', args: T.Tuple[str, T.List[str]], kwargs: 'Y for i, m in enumerate(media): m_dir = os.path.dirname(m) m_install_dir = os.path.join(l_install_dir, m_dir) + try: + m_file: T.Optional[mesonlib.File] = mesonlib.File.from_source_file(state.environment.source_dir, l_subdir, m) + except MesonException: + m_file = None + l_data: T.Union[build.Data, build.SymlinkData] - if symlinks: + if symlinks and not m_file: link_target = os.path.join(os.path.relpath(c_install_dir, start=m_install_dir), m) l_data = build.SymlinkData(link_target, os.path.basename(m), m_install_dir, state.subproject, install_tag='doc') else: - try: - m_file = mesonlib.File.from_source_file(state.environment.source_dir, l_subdir, m) - except MesonException: + if not m_file: m_file = media_files[i] l_data = build.Data([m_file], m_install_dir, m_install_dir, mesonlib.FileMode(), state.subproject, install_tag='doc') From 1e6e4c8d571e3bd415f9b8285f6f33170ba81761 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Mon, 19 Aug 2024 14:29:44 -0700 Subject: [PATCH 148/302] mformat: provide nice error message instead of backtrace for invalid value I ran into this with `option = true;` (note the trailing `;`). Now we provide a nicer message instead of an uncaught Python backtrace. Closes: #13565 --- mesonbuild/mformat.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mesonbuild/mformat.py b/mesonbuild/mformat.py index 27f97b4fa5fb..567d1f46df4c 100644 --- a/mesonbuild/mformat.py +++ b/mesonbuild/mformat.py @@ -861,7 +861,11 @@ def load_configuration(self, configuration_file: T.Optional[Path]) -> FormatterC for f in fields(config): getter = f.metadata['getter'] - value = getter(cp, cp.default_section, f.name, fallback=None) + try: + value = getter(cp, cp.default_section, f.name, fallback=None) + except ValueError as e: + raise MesonException( + f'Error parsing "{str(configuration_file)}", option "{f.name}", error: "{e!s}"') if value is not None: setattr(config, f.name, value) From 3bb3d576a1f86fff2afdb345e0283da062b597df Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Wed, 4 Sep 2024 23:06:19 +0300 Subject: [PATCH 149/302] Add support for LLVM 19 in Debian. Originally from here: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1080463 --- mesonbuild/environment.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 5f4de73d59e6..fce295dbc2d7 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -196,6 +196,8 @@ def get_llvm_tool_names(tool: str) -> T.List[str]: # unless it becomes a stable release. suffixes = [ '', # base (no suffix) + '-19.1', '19.1', + '-19', '19', '-18.1', '18.1', '-18', '18', '-17', '17', @@ -217,7 +219,7 @@ def get_llvm_tool_names(tool: str) -> T.List[str]: '-3.7', '37', '-3.6', '36', '-3.5', '35', - '-19', # Debian development snapshot + '-20', # Debian development snapshot '-devel', # FreeBSD development snapshot ] names: T.List[str] = [] From 6d92547e6c78ac84dda69ac19b5586795317bac9 Mon Sep 17 00:00:00 2001 From: Benjamin Gilbert Date: Tue, 20 Aug 2024 16:07:59 -0700 Subject: [PATCH 150/302] mformat: regenerate long lines even if they're already multiline If kwargs_force_multiline is enabled, an ArgumentNode in a kwarg value can already be marked multiline by the time we notice that the line needs to be broken for length. Ensure we still break the line in this case. Fixes: #13512 --- mesonbuild/mformat.py | 5 ++--- test cases/format/4 config/indentation.meson | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/mesonbuild/mformat.py b/mesonbuild/mformat.py index 567d1f46df4c..6a28684d6210 100644 --- a/mesonbuild/mformat.py +++ b/mesonbuild/mformat.py @@ -769,9 +769,8 @@ def visit_BreakNode(self, node: mparser.BreakNode) -> None: def split_if_needed(self, node: mparser.ArgumentNode) -> None: if len(node) and not node.is_multiline and self.length > self.config.max_line_length: arg = self.argument_stack[self.level] if len(self.argument_stack) > self.level else node - if not arg.is_multiline: - arg.is_multiline = True - self.need_regenerate = True + arg.is_multiline = True + self.need_regenerate = True def visit_ArgumentNode(self, node: mparser.ArgumentNode) -> None: self.argument_stack.append(node) diff --git a/test cases/format/4 config/indentation.meson b/test cases/format/4 config/indentation.meson index 816b5f3026a1..96a977e5fb56 100644 --- a/test cases/format/4 config/indentation.meson +++ b/test cases/format/4 config/indentation.meson @@ -71,3 +71,18 @@ if meson.project_version().version_compare('>1.2') endforeach endif endif + +subproject( + '@0@-@1@-@2@-@3@'.format( + meson.project_name(), + meson.project_version(), + meson.project_build_root(), + meson.project_source_root(), + ), + default_options : [ + 'aaaaaaaa=bbbbbbbbbb', + 'cccccccccccc=ddddddddddddd', + 'eeeeeeeeeeeeeee=fffffffffffff', + 'gggggggggggggggggggggg=hhhhhhhhhhhhhhhhhhhh', + ], +) From 83f8de5357f31d6448ae033e1e8ed2b22c8c306a Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Wed, 21 Aug 2024 02:28:26 -0400 Subject: [PATCH 151/302] tests: handle uncommon architecture format for nm The zlib symbols may not be of type 'T' but rather e.g. 'D' -- instead, tell nm to emit the POSIX format and also to only emit defined symbols, not undefined ones. Then we just check if the symbol is listed at all, regardless of type. We already depend on -U elsewhere (e.g symbolextractor). There's no real replacement for it, sadly. It's also buggy in some versions of nm, so we check both its long and short options. Bug: https://bugs.gentoo.org/938259 --- .../14 static dynamic linkage/verify_static.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/test cases/linuxlike/14 static dynamic linkage/verify_static.py b/test cases/linuxlike/14 static dynamic linkage/verify_static.py index 8d16d48c989e..25e97f368bb1 100755 --- a/test cases/linuxlike/14 static dynamic linkage/verify_static.py +++ b/test cases/linuxlike/14 static dynamic linkage/verify_static.py @@ -5,8 +5,16 @@ def handle_common(path): """Handle the common case.""" - output = subprocess.check_output(['nm', path]).decode('utf-8') - if 'T zlibVersion' in output: + try: + output = subprocess.check_output(['nm', '--defined-only', '-P', '-A', path]).decode('utf-8') + except subprocess.CalledProcessError: + # some NMs only support -U. Older binutils only supports --defined-only. + output = subprocess.check_output(['nm', '-UPA', path]).decode('utf-8') + # POSIX format. Prints all *defined* symbols, looks like this: + # builddir/main_static: zlibVersion T 1190 39 + # or + # builddir/main_static: zlibVersion D 1fde0 30 + if ': zlibVersion ' in output: return 0 return 1 From 7b3169f464810dfed0daf3075a5a6e5ed91dbc9b Mon Sep 17 00:00:00 2001 From: Charles Brunet Date: Tue, 12 Dec 2023 15:09:05 -0500 Subject: [PATCH 152/302] allow internal_dependency object to carry both_lib Otherwise, the both_libs object is resolved by the interpreter and we no longer have access to it from the dependency object. --- mesonbuild/build.py | 16 ++++++++++++++-- mesonbuild/interpreter/interpreter.py | 1 + 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index a7a43b40cffe..45ff4cc2c5bc 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -137,6 +137,15 @@ def get_target_macos_dylib_install_name(ld) -> str: name.append('.dylib') return ''.join(name) + +def extract_targets_as_list( + kwargs: T.Dict[str, T.Sequence[LibTypes]], + key: T.Literal['link_with', 'link_whole'], + self_libs: T.List[LibTypes]) -> T.List[LibTypes]: + lib_list = listify(kwargs.get(key, [])) + self_libs + return [t.get_default_object() if isinstance(t, BothLibraries) else t for t in lib_list] + + class InvalidArguments(MesonException): pass @@ -782,8 +791,8 @@ def __init__( # we have to call process_compilers() first and we need to process libraries # from link_with and link_whole first. # See https://github.com/mesonbuild/meson/pull/11957#issuecomment-1629243208. - link_targets = extract_as_list(kwargs, 'link_with') + self.link_targets - link_whole_targets = extract_as_list(kwargs, 'link_whole') + self.link_whole_targets + link_targets = extract_targets_as_list(kwargs, 'link_with', self.link_targets) + link_whole_targets = extract_targets_as_list(kwargs, 'link_whole', self.link_whole_targets) self.link_targets.clear() self.link_whole_targets.clear() self.link(link_targets) @@ -2493,6 +2502,9 @@ def get_default_object(self) -> BuildTarget: return self.static raise MesonBugException(f'self._preferred_library == "{self._preferred_library}" is neither "shared" nor "static".') + def get_id(self) -> str: + return self.get_default_object().get_id() + class CommandBase: depend_files: T.List[File] diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index 9de0f8762e17..d69f569c214f 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -690,6 +690,7 @@ def func_files(self, node: mparser.FunctionNode, args: T.Tuple[T.List[str]], kwa KwargInfo('version', (str, NoneType)), KwargInfo('objects', ContainerTypeInfo(list, build.ExtractedObjects), listify=True, default=[], since='1.1.0'), ) + @noSecondLevelHolderResolving def func_declare_dependency(self, node: mparser.BaseNode, args: T.List[TYPE_var], kwargs: kwtypes.FuncDeclareDependency) -> dependencies.Dependency: deps = kwargs['dependencies'] From 2d6915a5983a64b58ecafd1b1dc92e9c48579ff2 Mon Sep 17 00:00:00 2001 From: Charles Brunet Date: Tue, 12 Dec 2023 15:49:59 -0500 Subject: [PATCH 153/302] add default_both_libraries core option --- docs/markdown/Builtin-options.md | 11 +++++ .../snippets/default_both_libraries.md | 4 ++ mesonbuild/build.py | 4 +- mesonbuild/interpreter/interpreter.py | 7 ++- mesonbuild/options.py | 2 + .../common/273 both libraries/meson.build | 44 +++++++++++++++++++ .../common/273 both libraries/src/api.h | 15 +++++++ .../common/273 both libraries/src/library.c | 10 +++++ .../common/273 both libraries/src/library.h | 5 +++ .../common/273 both libraries/src/main.c | 8 ++++ .../common/273 both libraries/test.json | 16 +++++++ 11 files changed, 123 insertions(+), 3 deletions(-) create mode 100644 docs/markdown/snippets/default_both_libraries.md create mode 100644 test cases/common/273 both libraries/meson.build create mode 100644 test cases/common/273 both libraries/src/api.h create mode 100644 test cases/common/273 both libraries/src/library.c create mode 100644 test cases/common/273 both libraries/src/library.h create mode 100644 test cases/common/273 both libraries/src/main.c create mode 100644 test cases/common/273 both libraries/test.json diff --git a/docs/markdown/Builtin-options.md b/docs/markdown/Builtin-options.md index 6adc4218bda1..178f793e483a 100644 --- a/docs/markdown/Builtin-options.md +++ b/docs/markdown/Builtin-options.md @@ -79,6 +79,7 @@ machine](#specifying-options-per-machine) section for details. | genvslite {vs2022} | vs2022 | Setup multi-builtype ninja build directories and Visual Studio solution | no | no | | buildtype {plain, debug,
debugoptimized, release, minsize, custom} | debug | Build type to use | no | no | | debug | true | Enable debug symbols and other information | no | no | +| default_both_libraries {shared, static, auto} | shared | Default library type for both_libraries | no | no | | default_library {shared, static, both} | shared | Default library type | no | yes | | errorlogs | true | Whether to print the logs from failing tests. | no | no | | install_umask {preserve, 0000-0777} | 022 | Default umask to apply on permissions of installed files | no | no | @@ -177,6 +178,16 @@ fails. `vsenv` is `true` by default when using the `vs` backend. + +#### Details for `default_both_libraries` + +Since `1.6.0`, you can select the default type of library selected when using +a `both_libraries` object. This can be either 'shared' (default value, compatible +with previous meson versions), 'static', or 'auto'. With auto, the value from +`default_library` option is used, unless it is 'both', in which case 'shared' +is used instead. + + ## Base options These are set in the same way as universal options, either by diff --git a/docs/markdown/snippets/default_both_libraries.md b/docs/markdown/snippets/default_both_libraries.md new file mode 100644 index 000000000000..279c43d22b57 --- /dev/null +++ b/docs/markdown/snippets/default_both_libraries.md @@ -0,0 +1,4 @@ +## New built-in option for default both_libraries + +`both_libraries` targets used to be considered as a shared library by default. +There is now the `default_both_libraries` option to change this default. diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 45ff4cc2c5bc..122d94774992 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -2486,8 +2486,8 @@ def get_default_install_dir(self) -> T.Union[T.Tuple[str, str], T.Tuple[None, No return self.environment.get_shared_module_dir(), '{moduledir_shared}' class BothLibraries(SecondLevelHolder): - def __init__(self, shared: SharedLibrary, static: StaticLibrary) -> None: - self._preferred_library = 'shared' + def __init__(self, shared: SharedLibrary, static: StaticLibrary, preferred_library: Literal['shared', 'static', 'auto']) -> None: + self._preferred_library = preferred_library self.shared = shared self.static = static self.subproject = self.shared.subproject diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index d69f569c214f..e3e1e5b6730b 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -3230,6 +3230,11 @@ def add_target(self, name: str, tobj: build.Target) -> None: def build_both_libraries(self, node: mparser.BaseNode, args: T.Tuple[str, SourcesVarargsType], kwargs: kwtypes.Library) -> build.BothLibraries: shared_lib = self.build_target(node, args, kwargs, build.SharedLibrary) static_lib = self.build_target(node, args, kwargs, build.StaticLibrary) + preferred_library = self.coredata.get_option(OptionKey('default_both_libraries')) + if preferred_library == 'auto': + preferred_library = self.coredata.get_option(OptionKey('default_library')) + if preferred_library == 'both': + preferred_library = 'shared' if self.backend.name == 'xcode': # Xcode is a bit special in that you can't (at least for the moment) @@ -3261,7 +3266,7 @@ def build_both_libraries(self, node: mparser.BaseNode, args: T.Tuple[str, Source # Keep only compilers used for linking static_lib.compilers = {k: v for k, v in static_lib.compilers.items() if k in compilers.clink_langs} - return build.BothLibraries(shared_lib, static_lib) + return build.BothLibraries(shared_lib, static_lib, preferred_library) def build_library(self, node: mparser.BaseNode, args: T.Tuple[str, SourcesVarargsType], kwargs: kwtypes.Library): default_library = self.coredata.get_option(OptionKey('default_library', subproject=self.subproject)) diff --git a/mesonbuild/options.py b/mesonbuild/options.py index 020c2e623cb4..f1f3554c27ea 100644 --- a/mesonbuild/options.py +++ b/mesonbuild/options.py @@ -63,6 +63,7 @@ 'buildtype', 'debug', 'default_library', + 'default_both_libraries', 'errorlogs', 'genvslite', 'install_umask', @@ -624,6 +625,7 @@ def add_to_argparse(self, name: str, parser: argparse.ArgumentParser, help_suffi (OptionKey('debug'), BuiltinOption(UserBooleanOption, 'Enable debug symbols and other information', True)), (OptionKey('default_library'), BuiltinOption(UserComboOption, 'Default library type', 'shared', choices=['shared', 'static', 'both'], yielding=False)), + (OptionKey('default_both_libraries'), BuiltinOption(UserComboOption, 'Default library type for both_libraries', 'shared', choices=['shared', 'static', 'auto'])), (OptionKey('errorlogs'), BuiltinOption(UserBooleanOption, "Whether to print the logs from failing tests", True)), (OptionKey('install_umask'), BuiltinOption(UserUmaskOption, 'Default umask to apply on permissions of installed files', '022')), (OptionKey('layout'), BuiltinOption(UserComboOption, 'Build directory layout', 'mirror', choices=['mirror', 'flat'])), diff --git a/test cases/common/273 both libraries/meson.build b/test cases/common/273 both libraries/meson.build new file mode 100644 index 000000000000..b80a9ce7d01f --- /dev/null +++ b/test cases/common/273 both libraries/meson.build @@ -0,0 +1,44 @@ +project( + 'test both libraries', + 'c', + meson_version: '>= 1.6.0', +) + +expected = 0 + + +with_library = library( + 'with_library', + files('src/library.c'), + c_shared_args: ['-DEXPORT'], +) + +with_library_dep = declare_dependency( + link_with: with_library, +) + +if get_option('default_library') == 'shared' + expected += 1 +elif get_option('default_library') == 'both' + if get_option('default_both_libraries') in ['shared', 'auto'] + expected += 1 + endif +endif + + + +mainlink = executable( + 'mainlink', + files('src/main.c'), + c_args: [f'-DEXPECTED=@expected@'], + link_with: [with_library], +) +test('link with', mainlink) + +maindep = executable( + 'maindep', + files('src/main.c'), + c_args: [f'-DEXPECTED=@expected@'], + dependencies: [with_library_dep], +) +test('use dep', maindep) diff --git a/test cases/common/273 both libraries/src/api.h b/test cases/common/273 both libraries/src/api.h new file mode 100644 index 000000000000..a20ded3642d4 --- /dev/null +++ b/test cases/common/273 both libraries/src/api.h @@ -0,0 +1,15 @@ +#pragma once + +#if defined EXPORT + #if defined _WIN32 || defined __CYGWIN__ + #define API __declspec(dllexport) + #else + #if defined __GNUC__ + #define API __attribute__((visibility("default"))) + #else + #define API + #endif + #endif +#else + #define API +#endif diff --git a/test cases/common/273 both libraries/src/library.c b/test cases/common/273 both libraries/src/library.c new file mode 100644 index 000000000000..decdb6ce9d38 --- /dev/null +++ b/test cases/common/273 both libraries/src/library.c @@ -0,0 +1,10 @@ +#include "library.h" + +int library_function(void) +{ +#if defined EXPORT + return 1; +#else + return 0; +#endif +} diff --git a/test cases/common/273 both libraries/src/library.h b/test cases/common/273 both libraries/src/library.h new file mode 100644 index 000000000000..7f57af4f136d --- /dev/null +++ b/test cases/common/273 both libraries/src/library.h @@ -0,0 +1,5 @@ +#pragma once + +#include "api.h" + +int API library_function(void); diff --git a/test cases/common/273 both libraries/src/main.c b/test cases/common/273 both libraries/src/main.c new file mode 100644 index 000000000000..340322e455ed --- /dev/null +++ b/test cases/common/273 both libraries/src/main.c @@ -0,0 +1,8 @@ +#include "library.h" + + +int main(void) +{ + int sum = library_function(); + return sum == EXPECTED ? 0 : sum; +} diff --git a/test cases/common/273 both libraries/test.json b/test cases/common/273 both libraries/test.json new file mode 100644 index 000000000000..08aa54790e46 --- /dev/null +++ b/test cases/common/273 both libraries/test.json @@ -0,0 +1,16 @@ +{ + "matrix": { + "options": { + "default_library": [ + { "val": "shared" }, + { "val": "static" }, + { "val": "both" } + ], + "default_both_libraries": [ + { "val": "shared" }, + { "val": "static" }, + { "val": "auto" } + ] + } + } +} From 0fc363021e5c2e79a68fb33e60b72b8ffd353875 Mon Sep 17 00:00:00 2001 From: Charles Brunet Date: Wed, 13 Dec 2023 11:12:00 -0500 Subject: [PATCH 154/302] auto select static or shared when linking both_libraries together --- docs/markdown/Builtin-options.md | 3 + .../snippets/default_both_libraries.md | 7 ++ mesonbuild/build.py | 35 ++++++---- mesonbuild/interpreter/interpreter.py | 10 ++- .../common/273 both libraries/meson.build | 65 +++++++++++++++---- .../common/273 both libraries/meson.options | 1 + .../273 both libraries/src/both_libraries.c | 10 +++ .../273 both libraries/src/both_libraries.h | 5 ++ .../common/273 both libraries/src/library.c | 6 +- .../common/273 both libraries/src/main.c | 2 +- .../common/273 both libraries/test.json | 4 ++ 11 files changed, 122 insertions(+), 26 deletions(-) create mode 100644 test cases/common/273 both libraries/meson.options create mode 100644 test cases/common/273 both libraries/src/both_libraries.c create mode 100644 test cases/common/273 both libraries/src/both_libraries.h diff --git a/docs/markdown/Builtin-options.md b/docs/markdown/Builtin-options.md index 178f793e483a..2018b9575aed 100644 --- a/docs/markdown/Builtin-options.md +++ b/docs/markdown/Builtin-options.md @@ -187,6 +187,9 @@ with previous meson versions), 'static', or 'auto'. With auto, the value from `default_library` option is used, unless it is 'both', in which case 'shared' is used instead. +When `default_both_libraries` is 'auto', passing a [[@both_libs]] dependecy +in [[both_libraries]] will link the static dependency with the static lib, +and the shared dependency with the shared lib. ## Base options diff --git a/docs/markdown/snippets/default_both_libraries.md b/docs/markdown/snippets/default_both_libraries.md index 279c43d22b57..dc9cb6bca3a8 100644 --- a/docs/markdown/snippets/default_both_libraries.md +++ b/docs/markdown/snippets/default_both_libraries.md @@ -2,3 +2,10 @@ `both_libraries` targets used to be considered as a shared library by default. There is now the `default_both_libraries` option to change this default. + +When `default_both_libraries` is 'auto', [[both_libraries]] with dependencies +that are [[@both_libs]] themselves will link with the same kind of library. +For example, if `libA` is a [[@both_libs]] and `libB` is a [[@both_libs]] +linked with `libA` (or with an internal dependency on `libA`), +the static lib of `libB` will link with the static lib of `libA`, and the +shared lib of `libA` will link with the shared lib of `libB`. diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 122d94774992..b86a6a2a6541 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -138,14 +138,6 @@ def get_target_macos_dylib_install_name(ld) -> str: return ''.join(name) -def extract_targets_as_list( - kwargs: T.Dict[str, T.Sequence[LibTypes]], - key: T.Literal['link_with', 'link_whole'], - self_libs: T.List[LibTypes]) -> T.List[LibTypes]: - lib_list = listify(kwargs.get(key, [])) + self_libs - return [t.get_default_object() if isinstance(t, BothLibraries) else t for t in lib_list] - - class InvalidArguments(MesonException): pass @@ -791,8 +783,8 @@ def __init__( # we have to call process_compilers() first and we need to process libraries # from link_with and link_whole first. # See https://github.com/mesonbuild/meson/pull/11957#issuecomment-1629243208. - link_targets = extract_targets_as_list(kwargs, 'link_with', self.link_targets) - link_whole_targets = extract_targets_as_list(kwargs, 'link_whole', self.link_whole_targets) + link_targets = self.extract_targets_as_list(kwargs, 'link_with') + link_whole_targets = self.extract_targets_as_list(kwargs, 'link_whole') self.link_targets.clear() self.link_whole_targets.clear() self.link(link_targets) @@ -1740,6 +1732,20 @@ def process_vs_module_defs_kw(self, kwargs: T.Dict[str, T.Any]) -> None: 'a file object, a Custom Target, or a Custom Target Index') self.process_link_depends(path) + def extract_targets_as_list(self, kwargs: T.Dict[str, T.Union[LibTypes, T.Sequence[LibTypes]]], key: T.Literal['link_with', 'link_whole']) -> T.List[LibTypes]: + bl_type = self.environment.coredata.get_option(OptionKey('default_both_libraries')) + if bl_type == 'auto': + bl_type = 'static' if isinstance(self, StaticLibrary) else 'shared' + + def _resolve_both_libs(lib: LibTypes) -> LibTypes: + if isinstance(lib, BothLibraries): + return lib.get(bl_type) + return lib + + self_libs: T.List[LibTypes] = self.link_targets if key == 'link_with' else self.link_whole_targets + lib_list = listify(kwargs.get(key, [])) + self_libs + return [_resolve_both_libs(t) for t in lib_list] + class FileInTargetPrivateDir: """Represents a file with the path '/path/to/build/target_private_dir/fname'. target_private_dir is the return value of get_target_private_dir which is e.g. 'subdir/target.p'. @@ -2495,7 +2501,14 @@ def __init__(self, shared: SharedLibrary, static: StaticLibrary, preferred_libra def __repr__(self) -> str: return f'' - def get_default_object(self) -> BuildTarget: + def get(self, lib_type: T.Literal['static', 'shared', 'auto']) -> T.Union[StaticLibrary, SharedLibrary]: + if lib_type == 'static': + return self.static + if lib_type == 'shared': + return self.shared + return self.get_default_object() + + def get_default_object(self) -> T.Union[StaticLibrary, SharedLibrary]: if self._preferred_library == 'shared': return self.shared elif self._preferred_library == 'static': diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index e3e1e5b6730b..7eac40bb85d4 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -31,7 +31,7 @@ from ..interpreterbase import Disabler, disablerIfNotFound from ..interpreterbase import FeatureNew, FeatureDeprecated, FeatureBroken, FeatureNewKwargs from ..interpreterbase import ObjectHolder, ContextManagerObject -from ..interpreterbase import stringifyUserArguments +from ..interpreterbase import stringifyUserArguments, resolve_second_level_holders from ..modules import ExtensionModule, ModuleObject, MutableModuleObject, NewExtensionModule, NotFoundExtensionModule from ..optinterpreter import optname_regex @@ -1876,6 +1876,7 @@ def func_shared_lib(self, node: mparser.BaseNode, @permittedKwargs(known_library_kwargs) @typed_pos_args('both_libraries', str, varargs=SOURCES_VARARGS) @typed_kwargs('both_libraries', *LIBRARY_KWS, allow_unknown=True) + @noSecondLevelHolderResolving def func_both_lib(self, node: mparser.BaseNode, args: T.Tuple[str, SourcesVarargsType], kwargs: kwtypes.Library) -> build.BothLibraries: @@ -1893,6 +1894,7 @@ def func_shared_module(self, node: mparser.BaseNode, @permittedKwargs(known_library_kwargs) @typed_pos_args('library', str, varargs=SOURCES_VARARGS) @typed_kwargs('library', *LIBRARY_KWS, allow_unknown=True) + @noSecondLevelHolderResolving def func_library(self, node: mparser.BaseNode, args: T.Tuple[str, SourcesVarargsType], kwargs: kwtypes.Library) -> build.Executable: @@ -1910,12 +1912,16 @@ def func_jar(self, node: mparser.BaseNode, @permittedKwargs(known_build_target_kwargs) @typed_pos_args('build_target', str, varargs=SOURCES_VARARGS) @typed_kwargs('build_target', *BUILD_TARGET_KWS, allow_unknown=True) + @noSecondLevelHolderResolving def func_build_target(self, node: mparser.BaseNode, args: T.Tuple[str, SourcesVarargsType], kwargs: kwtypes.BuildTarget ) -> T.Union[build.Executable, build.StaticLibrary, build.SharedLibrary, build.SharedModule, build.BothLibraries, build.Jar]: target_type = kwargs['target_type'] + if target_type not in {'both_libraries', 'library'}: + args, kwargs = resolve_second_level_holders(args, kwargs) + if target_type == 'executable': return self.build_target(node, args, kwargs, build.Executable) elif target_type == 'shared_library': @@ -3272,8 +3278,10 @@ def build_library(self, node: mparser.BaseNode, args: T.Tuple[str, SourcesVararg default_library = self.coredata.get_option(OptionKey('default_library', subproject=self.subproject)) assert isinstance(default_library, str), 'for mypy' if default_library == 'shared': + args, kwargs = resolve_second_level_holders(args, kwargs) return self.build_target(node, args, T.cast('kwtypes.StaticLibrary', kwargs), build.SharedLibrary) elif default_library == 'static': + args, kwargs = resolve_second_level_holders(args, kwargs) return self.build_target(node, args, T.cast('kwtypes.SharedLibrary', kwargs), build.StaticLibrary) elif default_library == 'both': return self.build_both_libraries(node, args, kwargs) diff --git a/test cases/common/273 both libraries/meson.build b/test cases/common/273 both libraries/meson.build index b80a9ce7d01f..de7668ce4e9a 100644 --- a/test cases/common/273 both libraries/meson.build +++ b/test cases/common/273 both libraries/meson.build @@ -7,38 +7,81 @@ project( expected = 0 +with_bl = both_libraries( + 'with_bl', + files('src/both_libraries.c'), + c_shared_args: ['-DEXPORT'], +) + +with_bl_dep = declare_dependency( + link_with: with_bl, +) + + +if get_option('use_dep') + lib_deps = [with_bl_dep] + lib_links = [] +else + lib_deps = [] + lib_links = [with_bl] +endif + + with_library = library( 'with_library', files('src/library.c'), c_shared_args: ['-DEXPORT'], + link_with: lib_links, + dependencies: lib_deps, ) with_library_dep = declare_dependency( link_with: with_library, ) + if get_option('default_library') == 'shared' expected += 1 + if get_option('default_both_libraries') in ['shared', 'auto'] + expected += 1 + endif elif get_option('default_library') == 'both' if get_option('default_both_libraries') in ['shared', 'auto'] + expected += 2 + endif +else + if get_option('default_both_libraries') == 'shared' expected += 1 endif endif +if get_option('use_dep') + main_deps = [with_library_dep] + main_links = [] +else + main_deps = [] + main_links = [with_library] +endif -mainlink = executable( - 'mainlink', +main = executable( + 'main', files('src/main.c'), c_args: [f'-DEXPECTED=@expected@'], - link_with: [with_library], + link_with: main_links, + dependencies: main_deps, ) -test('link with', mainlink) +test('test both libs', main) -maindep = executable( - 'maindep', - files('src/main.c'), - c_args: [f'-DEXPECTED=@expected@'], - dependencies: [with_library_dep], -) -test('use dep', maindep) + +if get_option('default_library') == 'both' and get_option('default_both_libraries') == 'auto' + # With those options, even if the both_libraries defaults to 'shared', + # 'static' version is used when linking to the static part of another both_libraries. + main_static = executable( + 'main_static', + files('src/main.c'), + c_args: [f'-DEXPECTED=0'], + link_with: with_library.get_static_lib(), + ) + test('test static', main_static) +endif diff --git a/test cases/common/273 both libraries/meson.options b/test cases/common/273 both libraries/meson.options new file mode 100644 index 000000000000..2e3c357ae0b2 --- /dev/null +++ b/test cases/common/273 both libraries/meson.options @@ -0,0 +1 @@ +option('use_dep', type: 'boolean', value: false) diff --git a/test cases/common/273 both libraries/src/both_libraries.c b/test cases/common/273 both libraries/src/both_libraries.c new file mode 100644 index 000000000000..ab1bd1fd9965 --- /dev/null +++ b/test cases/common/273 both libraries/src/both_libraries.c @@ -0,0 +1,10 @@ +#include "both_libraries.h" + +int both_libraries_function(void) +{ +#if defined EXPORT + return 1; +#else + return 0; +#endif +} diff --git a/test cases/common/273 both libraries/src/both_libraries.h b/test cases/common/273 both libraries/src/both_libraries.h new file mode 100644 index 000000000000..39c4c8430154 --- /dev/null +++ b/test cases/common/273 both libraries/src/both_libraries.h @@ -0,0 +1,5 @@ +#pragma once + +#include "api.h" + +int API both_libraries_function(void); diff --git a/test cases/common/273 both libraries/src/library.c b/test cases/common/273 both libraries/src/library.c index decdb6ce9d38..bdd965f7fb96 100644 --- a/test cases/common/273 both libraries/src/library.c +++ b/test cases/common/273 both libraries/src/library.c @@ -1,10 +1,12 @@ #include "library.h" +#include "both_libraries.h" int library_function(void) { + int sum = both_libraries_function(); #if defined EXPORT - return 1; + return sum + 1; #else - return 0; + return sum; #endif } diff --git a/test cases/common/273 both libraries/src/main.c b/test cases/common/273 both libraries/src/main.c index 340322e455ed..1b367896d189 100644 --- a/test cases/common/273 both libraries/src/main.c +++ b/test cases/common/273 both libraries/src/main.c @@ -4,5 +4,5 @@ int main(void) { int sum = library_function(); - return sum == EXPECTED ? 0 : sum; + return sum == EXPECTED ? 0 : 1; } diff --git a/test cases/common/273 both libraries/test.json b/test cases/common/273 both libraries/test.json index 08aa54790e46..2aba26e48a3a 100644 --- a/test cases/common/273 both libraries/test.json +++ b/test cases/common/273 both libraries/test.json @@ -10,6 +10,10 @@ { "val": "shared" }, { "val": "static" }, { "val": "auto" } + ], + "use_dep": [ + { "val": false }, + { "val": true } ] } } From ce1602c1ee573f98ab409bcc645d9c7a07925836 Mon Sep 17 00:00:00 2001 From: Charles Brunet Date: Wed, 13 Dec 2023 16:02:11 -0500 Subject: [PATCH 155/302] alias_target with both_libs builds both --- .../alias_target_of_both_libraries.md | 5 ++++ .../snippets/dep_as_shared_as_static.md | 8 ++++++ docs/yaml/functions/alias_target.yaml | 3 ++ docs/yaml/objects/dep.yaml | 25 +++++++++++++++++ mesonbuild/build.py | 23 +++++++++++++-- mesonbuild/dependencies/base.py | 22 +++++++++++++++ mesonbuild/interpreter/interpreter.py | 7 +++-- mesonbuild/interpreter/interpreterobjects.py | 28 +++++++++++++++++++ .../common/178 bothlibraries/meson.build | 1 + .../common/273 both libraries/meson.build | 28 ++++++++++++++++++- 10 files changed, 143 insertions(+), 7 deletions(-) create mode 100644 docs/markdown/snippets/alias_target_of_both_libraries.md create mode 100644 docs/markdown/snippets/dep_as_shared_as_static.md diff --git a/docs/markdown/snippets/alias_target_of_both_libraries.md b/docs/markdown/snippets/alias_target_of_both_libraries.md new file mode 100644 index 000000000000..ab77a6556576 --- /dev/null +++ b/docs/markdown/snippets/alias_target_of_both_libraries.md @@ -0,0 +1,5 @@ +## `alias_target` of `both_libraries` + +Previously, when passing a [[@both_libs]] object to [[alias_target]], the alias +would only point to the shared library. It now points to both the static and the +shared library. diff --git a/docs/markdown/snippets/dep_as_shared_as_static.md b/docs/markdown/snippets/dep_as_shared_as_static.md new file mode 100644 index 000000000000..a84e9eeaa182 --- /dev/null +++ b/docs/markdown/snippets/dep_as_shared_as_static.md @@ -0,0 +1,8 @@ +## New `as_static` and `as_shared` methods on internal dependencies + +[[@dep]] object returned by [[declare_dependency]] now has `.as_static()` and +`.as_shared()` methods, to convert to a dependency that prefers the `static` +or the `shared` version of the linked [[@both_libs]] target. + +When the same dependency is used without those methods, the +`default_both_libraries` option determines which version is used. diff --git a/docs/yaml/functions/alias_target.yaml b/docs/yaml/functions/alias_target.yaml index bc14f84da2fe..9833569018f7 100644 --- a/docs/yaml/functions/alias_target.yaml +++ b/docs/yaml/functions/alias_target.yaml @@ -9,6 +9,9 @@ description: | are built. Dependencies can be any build target. Since 0.60.0, this includes [[@run_tgt]]. + *Since 1.6.0* passing a [[@both_libs]] object builds both shared and + static libraries. + posargs: target_name: type: str diff --git a/docs/yaml/objects/dep.yaml b/docs/yaml/objects/dep.yaml index 76543d2c1ab9..28d93d79f7f6 100644 --- a/docs/yaml/objects/dep.yaml +++ b/docs/yaml/objects/dep.yaml @@ -221,3 +221,28 @@ methods: pkgconfig_define: type: list[str] description: See [[dep.get_pkgconfig_variable]] + + - name: as_static + returns: dep + since: 1.6.0 + description: | + Only for dependencies created with [[declare_dependency]], + returns a copy of the dependency object that prefer the `static` version + of [[both_libraries]]. + kwargs: + recursive: + type: bool + description: If true, this is recursively applied to dependencies + + - name: as_shared + returns: dep + since: 1.6.0 + description: | + Only for dependencies created with [[declare_dependency]], + returns a copy of the dependency object that prefer the `shared` version + of [[both_libraries]]. + kwargs: + recursive: + type: bool + description: If true, this is recursively applied to dependencies + \ No newline at end of file diff --git a/mesonbuild/build.py b/mesonbuild/build.py index b86a6a2a6541..5eff0ed805c5 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -1746,6 +1746,10 @@ def _resolve_both_libs(lib: LibTypes) -> LibTypes: lib_list = listify(kwargs.get(key, [])) + self_libs return [_resolve_both_libs(t) for t in lib_list] + def get(self, lib_type: T.Literal['static', 'shared', 'auto']) -> LibTypes: + """Base case used by BothLibraries""" + return self + class FileInTargetPrivateDir: """Represents a file with the path '/path/to/build/target_private_dir/fname'. target_private_dir is the return value of get_target_private_dir which is e.g. 'subdir/target.p'. @@ -2501,7 +2505,7 @@ def __init__(self, shared: SharedLibrary, static: StaticLibrary, preferred_libra def __repr__(self) -> str: return f'' - def get(self, lib_type: T.Literal['static', 'shared', 'auto']) -> T.Union[StaticLibrary, SharedLibrary]: + def get(self, lib_type: T.Literal['static', 'shared', 'auto']) -> LibTypes: if lib_type == 'static': return self.static if lib_type == 'shared': @@ -2575,6 +2579,10 @@ def get_internal_static_libraries(self) -> OrderedSet[BuildTargetTypes]: def get_internal_static_libraries_recurse(self, result: OrderedSet[BuildTargetTypes]) -> None: pass + def get(self, lib_type: T.Literal['static', 'shared', 'auto']) -> LibTypes: + """Base case used by BothLibraries""" + return self + class CustomTarget(Target, CustomTargetBase, CommandBase): typename = 'custom' @@ -2896,14 +2904,23 @@ class AliasTarget(RunTarget): typename = 'alias' - def __init__(self, name: str, dependencies: T.Sequence['Target'], + def __init__(self, name: str, dependencies: T.Sequence[T.Union[Target, BothLibraries]], subdir: str, subproject: str, environment: environment.Environment): - super().__init__(name, [], dependencies, subdir, subproject, environment) + super().__init__(name, [], list(self._deps_generator(dependencies)), subdir, subproject, environment) def __repr__(self): repr_str = "<{0} {1}>" return repr_str.format(self.__class__.__name__, self.get_id()) + @staticmethod + def _deps_generator(dependencies: T.Sequence[T.Union[Target, BothLibraries]]) -> T.Iterator[Target]: + for dep in dependencies: + if isinstance(dep, BothLibraries): + yield dep.shared + yield dep.static + else: + yield dep + class Jar(BuildTarget): known_kwargs = known_jar_kwargs diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 08e81f0d79d5..fa278d97c07f 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -248,6 +248,14 @@ def generate_system_dependency(self, include_type: str) -> 'Dependency': new_dep.include_type = self._process_include_type_kw({'include_type': include_type}) return new_dep + def get_as_static(self, recursive: bool) -> Dependency: + """Used as base case for internal_dependency""" + return self + + def get_as_shared(self, recursive: bool) -> Dependency: + """Used as base case for internal_dependency""" + return self + class InternalDependency(Dependency): def __init__(self, version: str, incdirs: T.List['IncludeDirs'], compile_args: T.List[str], link_args: T.List[str], @@ -345,6 +353,20 @@ def generate_link_whole_dependency(self) -> Dependency: new_dep.libraries = [] return new_dep + def get_as_static(self, recursive: bool) -> Dependency: + new_dep = copy.copy(self) + new_dep.libraries = [lib.get('static') for lib in self.libraries] + if recursive: + new_dep.ext_deps = [dep.get_as_static(True) for dep in self.ext_deps] + return new_dep + + def get_as_shared(self, recursive: bool) -> Dependency: + new_dep = copy.copy(self) + new_dep.libraries = [lib.get('shared') for lib in self.libraries] + if recursive: + new_dep.ext_deps = [dep.get_as_shared(True) for dep in self.ext_deps] + return new_dep + class HasNativeKwarg: def __init__(self, kwargs: T.Dict[str, T.Any]): self.for_machine = self.get_for_machine_from_kwargs(kwargs) diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index 7eac40bb85d4..bd4d1596231a 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -2165,10 +2165,11 @@ def func_run_target(self, node: mparser.FunctionNode, args: T.Tuple[str], return tg @FeatureNew('alias_target', '0.52.0') - @typed_pos_args('alias_target', str, varargs=build.Target, min_varargs=1) + @typed_pos_args('alias_target', str, varargs=(build.Target, build.BothLibraries), min_varargs=1) @noKwargs - def func_alias_target(self, node: mparser.BaseNode, args: T.Tuple[str, T.List[build.Target]], - kwargs: 'TYPE_kwargs') -> build.AliasTarget: + @noSecondLevelHolderResolving + def func_alias_target(self, node: mparser.BaseNode, args: T.Tuple[str, T.List[T.Union[build.Target, build.BothLibraries]]], + kwargs: TYPE_kwargs) -> build.AliasTarget: name, deps = args if any(isinstance(d, build.RunTarget) for d in deps): FeatureNew.single_use('alias_target that depends on run_targets', '0.60.0', self.subproject) diff --git a/mesonbuild/interpreter/interpreterobjects.py b/mesonbuild/interpreter/interpreterobjects.py index 155cfd23e56e..2cd55321bfcb 100644 --- a/mesonbuild/interpreter/interpreterobjects.py +++ b/mesonbuild/interpreter/interpreterobjects.py @@ -41,6 +41,10 @@ class EnvironmentSeparatorKW(TypedDict): separator: str + class InternalDependencyAsKW(TypedDict): + + recursive: bool + _ERROR_MSG_KW: KwargInfo[T.Optional[str]] = KwargInfo('error_message', (str, NoneType)) @@ -462,6 +466,8 @@ def __init__(self, dep: Dependency, interpreter: 'Interpreter'): 'include_type': self.include_type_method, 'as_system': self.as_system_method, 'as_link_whole': self.as_link_whole_method, + 'as_static': self.as_static_method, + 'as_shared': self.as_shared_method, }) def found(self) -> bool: @@ -580,6 +586,28 @@ def as_link_whole_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> D new_dep = self.held_object.generate_link_whole_dependency() return new_dep + @FeatureNew('dependency.as_static', '1.6.0') + @noPosargs + @typed_kwargs( + 'dependency.as_static', + KwargInfo('recursive', bool, default=False), + ) + def as_static_method(self, args: T.List[TYPE_var], kwargs: InternalDependencyAsKW) -> Dependency: + if not isinstance(self.held_object, InternalDependency): + raise InterpreterException('as_static method is only supported on declare_dependency() objects') + return self.held_object.get_as_static(kwargs['recursive']) + + @FeatureNew('dependency.as_shared', '1.6.0') + @noPosargs + @typed_kwargs( + 'dependency.as_shared', + KwargInfo('recursive', bool, default=False), + ) + def as_shared_method(self, args: T.List[TYPE_var], kwargs: InternalDependencyAsKW) -> Dependency: + if not isinstance(self.held_object, InternalDependency): + raise InterpreterException('as_shared method is only supported on declare_dependency() objects') + return self.held_object.get_as_shared(kwargs['recursive']) + _EXTPROG = T.TypeVar('_EXTPROG', bound=ExternalProgram) class _ExternalProgramHolder(ObjectHolder[_EXTPROG]): diff --git a/test cases/common/178 bothlibraries/meson.build b/test cases/common/178 bothlibraries/meson.build index 62f2061f8d67..654d94e66f80 100644 --- a/test cases/common/178 bothlibraries/meson.build +++ b/test cases/common/178 bothlibraries/meson.build @@ -2,6 +2,7 @@ project('both libraries linking test', 'c', 'cpp') both_libs = both_libraries('mylib', 'libfile.c') dep = declare_dependency(link_with: both_libs) +alias_target('alias', both_libs) exe_shared = executable('prog-shared', 'main.c', link_with : both_libs.get_shared_lib()) exe_static = executable('prog-static', 'main.c', c_args : ['-DSTATIC_COMPILATION'], diff --git a/test cases/common/273 both libraries/meson.build b/test cases/common/273 both libraries/meson.build index de7668ce4e9a..00da1c8e6cf5 100644 --- a/test cases/common/273 both libraries/meson.build +++ b/test cases/common/273 both libraries/meson.build @@ -77,11 +77,37 @@ test('test both libs', main) if get_option('default_library') == 'both' and get_option('default_both_libraries') == 'auto' # With those options, even if the both_libraries defaults to 'shared', # 'static' version is used when linking to the static part of another both_libraries. + + if get_option('use_dep') + main_static_deps = [with_library_dep.as_static(recursive: true)] + main_static_links = [] + else + main_static_deps = [] + main_static_links = [with_library.get_static_lib()] + endif main_static = executable( 'main_static', files('src/main.c'), c_args: [f'-DEXPECTED=0'], - link_with: with_library.get_static_lib(), + link_with: main_static_links, + dependencies: main_static_deps, ) test('test static', main_static) + + + if get_option('use_dep') + main_shared_deps = [with_library_dep.as_shared(recursive: true)] + main_shared_links = [] + else + main_shared_deps = [] + main_shared_links = [with_library.get_shared_lib()] + endif + main_shared = executable( + 'main_shared', + files('src/main.c'), + c_args: [f'-DEXPECTED=2'], + link_with: main_shared_links, + dependencies: main_shared_deps, + ) + test('test shared', main_shared) endif From d3ef02b2e4d312ac604c0045ec97bf35a121bab5 Mon Sep 17 00:00:00 2001 From: Charles Brunet Date: Tue, 20 Aug 2024 17:09:57 -0400 Subject: [PATCH 156/302] mformat: detect invalid config - detect unknown config keys in format config - add test for detection of invalid config values - detect invalid .editorconfig values Fixes #13569 --- mesonbuild/mformat.py | 12 +++++++--- unittests/platformagnostictests.py | 37 ++++++++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/mesonbuild/mformat.py b/mesonbuild/mformat.py index 6a28684d6210..d87674bc7ea9 100644 --- a/mesonbuild/mformat.py +++ b/mesonbuild/mformat.py @@ -839,7 +839,10 @@ def load_editor_config(self, source_file: Path) -> EditorConfig: getter = f.metadata['getter'] for section in sections: - value = getter(cp, section, f.name, fallback=None) + try: + value = getter(cp, section, f.name, fallback=None) + except ValueError as e: + raise MesonException(f'Invalid type for key "{f.name}" in "{editorconfig_file}" file:\n{e}') from e if value is not None: setattr(config, f.name, value) @@ -858,6 +861,10 @@ def load_configuration(self, configuration_file: T.Optional[Path]) -> FormatterC except ParsingError as e: raise MesonException(f'Unable to parse configuration file "{configuration_file}":\n{e}') from e + extra_keys = sorted(set(cp.defaults()).difference(f.name for f in fields(config))) + if extra_keys: + raise MesonException(f'Unknown config keys: "{", ".join(extra_keys)}" in configuration file "{configuration_file}"') + for f in fields(config): getter = f.metadata['getter'] try: @@ -992,9 +999,8 @@ def run(options: argparse.Namespace) -> int: # TODO: remove empty newlines when more than N (2...) # TODO: magic comment to prevent formatting -# TODO: handle meson.options ? # TODO: split long lines on binary operators -# TODO: align series of assignements +# TODO: align series of assignments # TODO: align comments # TODO: move comments on long lines diff --git a/unittests/platformagnostictests.py b/unittests/platformagnostictests.py index 7d6ffa0f9e1f..3ee0b458c9dd 100644 --- a/unittests/platformagnostictests.py +++ b/unittests/platformagnostictests.py @@ -15,7 +15,7 @@ from .baseplatformtests import BasePlatformTests from .helpers import is_ci -from mesonbuild.mesonlib import EnvironmentVariables, ExecutableSerialisation, MesonException, is_linux, python_command +from mesonbuild.mesonlib import EnvironmentVariables, ExecutableSerialisation, MesonException, is_linux, python_command, windows_proof_rmtree from mesonbuild.mformat import Formatter, match_path from mesonbuild.optinterpreter import OptionInterpreter, OptionException from mesonbuild.options import OptionStore @@ -336,7 +336,40 @@ def test_editorconfig_match_path(self): for filename, pattern, expected in cases: self.assertTrue(match_path(filename, pattern) is expected, f'{filename} -> {pattern}') - + + def test_format_invalid_config_key(self) -> None: + fd, fname = tempfile.mkstemp(suffix='.ini', text=True) + self.addCleanup(os.unlink, fname) + + with os.fdopen(fd, 'w', encoding='utf-8') as handle: + handle.write('not_an_option = 42\n') + + with self.assertRaises(MesonException): + Formatter(Path(fname), use_editor_config=False, fetch_subdirs=False) + + def test_format_invalid_config_value(self) -> None: + fd, fname = tempfile.mkstemp(suffix='.ini', text=True) + self.addCleanup(os.unlink, fname) + + with os.fdopen(fd, 'w', encoding='utf-8') as handle: + handle.write('max_line_length = string\n') + + with self.assertRaises(MesonException): + Formatter(Path(fname), use_editor_config=False, fetch_subdirs=False) + + def test_format_invalid_editorconfig_value(self) -> None: + dirpath = tempfile.mkdtemp() + self.addCleanup(windows_proof_rmtree, dirpath) + + editorconfig = Path(dirpath, '.editorconfig') + with open(editorconfig, 'w', encoding='utf-8') as handle: + handle.write('[*]\n') + handle.write('indent_size = string\n') + + formatter = Formatter(None, use_editor_config=True, fetch_subdirs=False) + with self.assertRaises(MesonException): + formatter.load_editor_config(editorconfig) + def test_format_empty_file(self) -> None: formatter = Formatter(None, use_editor_config=False, fetch_subdirs=False) for code in ('', '\n'): From 37c5bffbffc6a930522762838012390b80ca833e Mon Sep 17 00:00:00 2001 From: Charles Brunet Date: Tue, 20 Aug 2024 14:52:16 -0400 Subject: [PATCH 157/302] mformat: better handling of continuation lines Fixes #13566. Fixes #13567. --- mesonbuild/mformat.py | 13 ++++++++++++- mesonbuild/mparser.py | 1 + test cases/format/1 default/meson.build | 10 ++++++++++ test cases/format/1 default/meson.options | 1 + 4 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 test cases/format/1 default/meson.options diff --git a/mesonbuild/mformat.py b/mesonbuild/mformat.py index d87674bc7ea9..119c89351ec4 100644 --- a/mesonbuild/mformat.py +++ b/mesonbuild/mformat.py @@ -276,6 +276,7 @@ def exit_node(self, node: mparser.BaseNode) -> None: def move_whitespaces(self, from_node: mparser.BaseNode, to_node: mparser.BaseNode) -> None: to_node.whitespaces.value = from_node.whitespaces.value + to_node.whitespaces.value + to_node.whitespaces.is_continuation = from_node.whitespaces.is_continuation from_node.whitespaces = None to_node.whitespaces.accept(self) @@ -317,7 +318,10 @@ def visit_WhitespaceNode(self, node: mparser.WhitespaceNode) -> None: for i, line in enumerate(lines): has_nl = line.endswith('\n') line = line.strip() - if line.startswith('#'): + if line.startswith('\\'): + node.value += ' ' # add space before \ + node.is_continuation = True + elif line.startswith('#'): if not in_block_comments: node.value += self.config.indent_before_comments else: @@ -328,6 +332,8 @@ def visit_WhitespaceNode(self, node: mparser.WhitespaceNode) -> None: in_block_comments = True if node.value.endswith('\n'): node.value += self.indent_comments + if node.is_continuation: + node.value += self.config.indent_by def visit_SymbolNode(self, node: mparser.SymbolNode) -> None: super().visit_SymbolNode(node) @@ -595,6 +601,9 @@ def visit_DictNode(self, node: mparser.DictNode) -> None: def visit_MethodNode(self, node: mparser.MethodNode) -> None: self.enter_node(node) node.source_object.accept(self) + is_cont = node.source_object.whitespaces and node.source_object.whitespaces.is_continuation + if is_cont: + self.level += 1 if node.args.is_multiline: self.level += 1 self.add_nl_after(node.lpar, indent=self.level) @@ -602,6 +611,8 @@ def visit_MethodNode(self, node: mparser.MethodNode) -> None: node.args.accept(self) if node.args.is_multiline: self.level -= 1 + if is_cont: + self.level -= 1 self.exit_node(node) def visit_FunctionNode(self, node: mparser.FunctionNode) -> None: diff --git a/mesonbuild/mparser.py b/mesonbuild/mparser.py index 79ece3789cd6..4f43455468c6 100644 --- a/mesonbuild/mparser.py +++ b/mesonbuild/mparser.py @@ -267,6 +267,7 @@ def __init__(self, token: Token[str]): self.value = '' self.append(token) self.block_indent = False + self.is_continuation = False def append(self, token: Token[str]) -> None: self.value += token.value diff --git a/test cases/format/1 default/meson.build b/test cases/format/1 default/meson.build index 83ae19aa0bde..d3bb153eeb92 100644 --- a/test cases/format/1 default/meson.build +++ b/test cases/format/1 default/meson.build @@ -13,6 +13,16 @@ meson_files = { # Ensure empty function are formatted correctly on long lines a = '@0@@1@@2@@3@@4@'.format('one', 'two', 'three', 'four', 'five').strip().strip() +_opt = get_option('opt') \ + .disable_if( + true, + error_message: 'This is an error message because opt can\'t be enabled', + ) \ + .enable_if( + false, + error_message: 'This is an error message because opt can\'t be disabled', + ) + foreach name, f : meson_files test(name, meson_cmd, args: ['format', '--check-only', f]) endforeach diff --git a/test cases/format/1 default/meson.options b/test cases/format/1 default/meson.options new file mode 100644 index 000000000000..13f5e19c0e68 --- /dev/null +++ b/test cases/format/1 default/meson.options @@ -0,0 +1 @@ +option('opt', type : 'feature', value : 'auto') From 8b5e53b6547947d3560a2844dd1ec0a6137c885c Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 3 Sep 2024 15:37:19 -0700 Subject: [PATCH 158/302] machinefile: Remove unused type alias --- mesonbuild/machinefile.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/mesonbuild/machinefile.py b/mesonbuild/machinefile.py index bc290bef0632..690e1e62f82c 100644 --- a/mesonbuild/machinefile.py +++ b/mesonbuild/machinefile.py @@ -12,11 +12,8 @@ from .mesonlib import MesonException if T.TYPE_CHECKING: - from .compilers import Compiler from .coredata import StrOrBytesPath - CompilersDict = T.Dict[str, Compiler] - class CmdLineFileParser(configparser.ConfigParser): def __init__(self) -> None: From ca5490f021338095e9339c78997dcabb6759f396 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 3 Sep 2024 15:46:03 -0700 Subject: [PATCH 159/302] machinefile: Make fully typesafe With the use of `typing_extensions.TypeAlias` we can get recursive types, which solves most of the issues we had with this file. --- mesonbuild/machinefile.py | 28 ++++++++++++++++------------ run_mypy.py | 3 +++ 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/mesonbuild/machinefile.py b/mesonbuild/machinefile.py index 690e1e62f82c..a3aeae522713 100644 --- a/mesonbuild/machinefile.py +++ b/mesonbuild/machinefile.py @@ -12,8 +12,12 @@ from .mesonlib import MesonException if T.TYPE_CHECKING: + from typing_extensions import TypeAlias + from .coredata import StrOrBytesPath + SectionT: TypeAlias = T.Union[str, int, bool, T.List[str], T.List['SectionT']] + class CmdLineFileParser(configparser.ConfigParser): def __init__(self) -> None: @@ -32,8 +36,8 @@ def optionxform(self, optionstr: str) -> str: class MachineFileParser(): def __init__(self, filenames: T.List[str], sourcedir: str) -> None: self.parser = CmdLineFileParser() - self.constants: T.Dict[str, T.Union[str, bool, int, T.List[str]]] = {'True': True, 'False': False} - self.sections: T.Dict[str, T.Dict[str, T.Union[str, bool, int, T.List[str]]]] = {} + self.constants: T.Dict[str, SectionT] = {'True': True, 'False': False} + self.sections: T.Dict[str, T.Dict[str, SectionT]] = {} for fname in filenames: try: @@ -58,9 +62,9 @@ def __init__(self, filenames: T.List[str], sourcedir: str) -> None: continue self.sections[s] = self._parse_section(s) - def _parse_section(self, s: str) -> T.Dict[str, T.Union[str, bool, int, T.List[str]]]: + def _parse_section(self, s: str) -> T.Dict[str, SectionT]: self.scope = self.constants.copy() - section: T.Dict[str, T.Union[str, bool, int, T.List[str]]] = {} + section: T.Dict[str, SectionT] = {} for entry, value in self.parser.items(s): if ' ' in entry or '\t' in entry or "'" in entry or '"' in entry: raise MesonException(f'Malformed variable name {entry!r} in machine file.') @@ -79,7 +83,7 @@ def _parse_section(self, s: str) -> T.Dict[str, T.Union[str, bool, int, T.List[s self.scope[entry] = res return section - def _evaluate_statement(self, node: mparser.BaseNode) -> T.Union[str, bool, int, T.List[str]]: + def _evaluate_statement(self, node: mparser.BaseNode) -> SectionT: if isinstance(node, (mparser.StringNode)): return node.value elif isinstance(node, mparser.BooleanNode): @@ -89,7 +93,6 @@ def _evaluate_statement(self, node: mparser.BaseNode) -> T.Union[str, bool, int, elif isinstance(node, mparser.ParenthesizedNode): return self._evaluate_statement(node.inner) elif isinstance(node, mparser.ArrayNode): - # TODO: This is where recursive types would come in handy return [self._evaluate_statement(arg) for arg in node.args.arguments] elif isinstance(node, mparser.IdNode): return self.scope[node.value] @@ -97,20 +100,21 @@ def _evaluate_statement(self, node: mparser.BaseNode) -> T.Union[str, bool, int, l = self._evaluate_statement(node.left) r = self._evaluate_statement(node.right) if node.operation == 'add': - if (isinstance(l, str) and isinstance(r, str)) or \ - (isinstance(l, list) and isinstance(r, list)): + if isinstance(l, str) and isinstance(r, str): + return l + r + if isinstance(l, list) and isinstance(r, list): return l + r elif node.operation == 'div': if isinstance(l, str) and isinstance(r, str): return os.path.join(l, r) raise MesonException('Unsupported node type') -def parse_machine_files(filenames: T.List[str], sourcedir: str): +def parse_machine_files(filenames: T.List[str], sourcedir: str) -> T.Dict[str, T.Dict[str, SectionT]]: parser = MachineFileParser(filenames, sourcedir) return parser.sections class MachineFileStore: - def __init__(self, native_files, cross_files, source_dir): - self.native = MachineFileParser(native_files if native_files is not None else [], source_dir).sections - self.cross = MachineFileParser(cross_files if cross_files is not None else [], source_dir).sections + def __init__(self, native_files: T.Optional[T.List[str]], cross_files: T.Optional[T.List[str]], source_dir: str): + self.native = parse_machine_files(native_files if native_files is not None else [], source_dir) + self.cross = parse_machine_files(cross_files if cross_files is not None else [], source_dir) diff --git a/run_mypy.py b/run_mypy.py index f72e96b3d3a2..7ed9720c0b22 100755 --- a/run_mypy.py +++ b/run_mypy.py @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 +# Copyright © 2024 Intel Corporation from pathlib import Path import argparse @@ -38,6 +40,7 @@ 'mesonbuild/interpreter/mesonmain.py', 'mesonbuild/interpreter/interpreterobjects.py', 'mesonbuild/interpreter/type_checking.py', + 'mesonbuild/machinefile.py', 'mesonbuild/mcompile.py', 'mesonbuild/mdevenv.py', 'mesonbuild/utils/core.py', From d353219e175983f8ee1aa8d965953a1947d39716 Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Tue, 2 Jan 2024 17:19:19 -0500 Subject: [PATCH 160/302] run_mypy: register utils/vsenv.py, as it is type-safe --- run_mypy.py | 1 + 1 file changed, 1 insertion(+) diff --git a/run_mypy.py b/run_mypy.py index 7ed9720c0b22..9a4e241ec833 100755 --- a/run_mypy.py +++ b/run_mypy.py @@ -46,6 +46,7 @@ 'mesonbuild/utils/core.py', 'mesonbuild/utils/platform.py', 'mesonbuild/utils/universal.py', + 'mesonbuild/utils/vsenv.py', 'mesonbuild/mconf.py', 'mesonbuild/mdist.py', 'mesonbuild/mformat.py', From cd0981bb3ce1beb531ccc307b0f32392daacf7f6 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Wed, 28 Aug 2024 10:04:16 -0700 Subject: [PATCH 161/302] options: fix imports - group imports properly - dont import from typing and import typing --- mesonbuild/options.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/mesonbuild/options.py b/mesonbuild/options.py index f1f3554c27ea..72dfb61a3135 100644 --- a/mesonbuild/options.py +++ b/mesonbuild/options.py @@ -7,6 +7,7 @@ from itertools import chain from functools import total_ordering import argparse +import typing as T from .mesonlib import ( HoldableObject, @@ -24,12 +25,8 @@ listify_array_value, MachineChoice, ) - from . import mlog -import typing as T -from typing import ItemsView - DEFAULT_YIELDING = False # Can't bind this near the class method it seems, sadly. @@ -755,7 +752,7 @@ def keys(self): def values(self): return self.d.values() - def items(self) -> ItemsView['OptionKey', 'UserOption[T.Any]']: + def items(self) -> T.ItemsView['OptionKey', 'UserOption[T.Any]']: return self.d.items() # FIXME: this method must be deleted and users moved to use "add_xxx_option"s instead. From e940d58677c390d8f92b121fe35a8a8280a0c038 Mon Sep 17 00:00:00 2001 From: Zihua Wu Date: Thu, 29 Aug 2024 14:19:23 +0800 Subject: [PATCH 162/302] fix LDFLAGS for cuda LDFLAGS may contain flags that nvcc is unable to handle and these flags need to be processed before we pass them to nvcc --- mesonbuild/compilers/cuda.py | 51 ++++++++++++++++++---------------- mesonbuild/compilers/detect.py | 9 +++++- 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/mesonbuild/compilers/cuda.py b/mesonbuild/compilers/cuda.py index 090c1ab94bae..38a938f24aff 100644 --- a/mesonbuild/compilers/cuda.py +++ b/mesonbuild/compilers/cuda.py @@ -45,7 +45,7 @@ } -class _Phase(enum.Enum): +class Phase(enum.Enum): COMPILER = 'compiler' LINKER = 'linker' @@ -309,14 +309,14 @@ def get_xcompiler_val(flag: str, flagit: T.Iterator[str]) -> str: raise ValueError("-Xcompiler flag merging failed, unknown argument form!") return xflags - def _to_host_flags(self, flags: T.List[str], phase: _Phase = _Phase.COMPILER) -> T.List[str]: + @classmethod + def to_host_flags_base(cls, flags: T.List[str], phase: Phase = Phase.COMPILER, default_include_dirs: T.Optional[T.List[str]] = None) -> T.List[str]: """ Translate generic "GCC-speak" plus particular "NVCC-speak" flags to NVCC flags. NVCC's "short" flags have broad similarities to the GCC standard, but have gratuitous, irritating differences. """ - xflags = [] flagit = iter(flags) @@ -371,7 +371,7 @@ def _to_host_flags(self, flags: T.List[str], phase: _Phase = _Phase.COMPILER) -> # an exception for -D (where this would be value-changing) and -U (because # it isn't possible to define a macro with a comma in the name). - if flag in self._FLAG_PASSTHRU_NOARGS: + if flag in cls._FLAG_PASSTHRU_NOARGS: xflags.append(flag) continue @@ -404,16 +404,16 @@ def _to_host_flags(self, flags: T.List[str], phase: _Phase = _Phase.COMPILER) -> else: # -Isomething val = flag[2:] flag = flag[:2] # -I - elif flag in self._FLAG_LONG2SHORT_WITHARGS or \ - flag in self._FLAG_SHORT2LONG_WITHARGS: + elif flag in cls._FLAG_LONG2SHORT_WITHARGS or \ + flag in cls._FLAG_SHORT2LONG_WITHARGS: # This is either -o or a multi-letter flag, and it is receiving its # value isolated. try: val = next(flagit) # -o something except StopIteration: pass - elif flag.split('=', 1)[0] in self._FLAG_LONG2SHORT_WITHARGS or \ - flag.split('=', 1)[0] in self._FLAG_SHORT2LONG_WITHARGS: + elif flag.split('=', 1)[0] in cls._FLAG_LONG2SHORT_WITHARGS or \ + flag.split('=', 1)[0] in cls._FLAG_SHORT2LONG_WITHARGS: # This is either -o or a multi-letter flag, and it is receiving its # value after an = sign. flag, val = flag.split('=', 1) # -o=something @@ -442,14 +442,14 @@ def _to_host_flags(self, flags: T.List[str], phase: _Phase = _Phase.COMPILER) -> xflags.append('-prec-div=true') xflags.append('-Xcompiler='+flag) else: - xflags.append('-Xcompiler='+self._shield_nvcc_list_arg(flag)) + xflags.append('-Xcompiler='+cls._shield_nvcc_list_arg(flag)) # The above should securely handle GCC's -Wl, -Wa, -Wp, arguments. continue assert val is not None # Should only trip if there is a missing argument. # Take care of the various NVCC-supported flags that need special handling. - flag = self._FLAG_LONG2SHORT_WITHARGS.get(flag, flag) + flag = cls._FLAG_LONG2SHORT_WITHARGS.get(flag, flag) if flag in {'-include', '-isystem', '-I', '-L', '-l'}: # These flags are known to GCC, but list-valued in NVCC. They potentially @@ -461,14 +461,14 @@ def _to_host_flags(self, flags: T.List[str], phase: _Phase = _Phase.COMPILER) -> # -U with comma arguments is impossible in GCC-speak (and thus unambiguous #in NVCC-speak, albeit unportable). if len(flag) == 2: - xflags.append(flag+self._shield_nvcc_list_arg(val)) - elif flag == '-isystem' and val in self.host_compiler.get_default_include_dirs(): + xflags.append(flag+cls._shield_nvcc_list_arg(val)) + elif flag == '-isystem' and default_include_dirs is not None and val in default_include_dirs: # like GnuLikeCompiler, we have to filter out include directories specified # with -isystem that overlap with the host compiler's search path pass else: xflags.append(flag) - xflags.append(self._shield_nvcc_list_arg(val)) + xflags.append(cls._shield_nvcc_list_arg(val)) elif flag == '-O': # Handle optimization levels GCC knows about that NVCC does not. if val == 'fast': @@ -489,13 +489,16 @@ def _to_host_flags(self, flags: T.List[str], phase: _Phase = _Phase.COMPILER) -> xflags.append(flag) xflags.append(val) - return self._merge_flags(xflags) + return cls._merge_flags(xflags) + + def _to_host_flags(self, flags: T.List[str], phase: Phase = Phase.COMPILER) -> T.List[str]: + return self.to_host_flags_base(flags, phase, self.host_compiler.get_default_include_dirs()) def needs_static_linker(self) -> bool: return False def thread_link_flags(self, environment: 'Environment') -> T.List[str]: - return self._to_host_flags(self.host_compiler.thread_link_flags(environment), _Phase.LINKER) + return self._to_host_flags(self.host_compiler.thread_link_flags(environment), Phase.LINKER) def sanity_check(self, work_dir: str, env: 'Environment') -> None: mlog.debug('Sanity testing ' + self.get_display_language() + ' compiler:', ' '.join(self.exelist)) @@ -684,13 +687,13 @@ def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str] def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = self.get_ccbin_args(options) - return args + self._to_host_flags(self.host_compiler.get_option_link_args(self._to_host_compiler_options(options)), _Phase.LINKER) + return args + self._to_host_flags(self.host_compiler.get_option_link_args(self._to_host_compiler_options(options)), Phase.LINKER) def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str, suffix: str, soversion: str, darwin_versions: T.Tuple[str, str]) -> T.List[str]: return self._to_host_flags(self.host_compiler.get_soname_args( - env, prefix, shlib_name, suffix, soversion, darwin_versions), _Phase.LINKER) + env, prefix, shlib_name, suffix, soversion, darwin_versions), Phase.LINKER) def get_compile_only_args(self) -> T.List[str]: return ['-c'] @@ -729,20 +732,20 @@ def get_compile_debugfile_args(self, rel_obj: str, pch: bool = False) -> T.List[ return self._to_host_flags(self.host_compiler.get_compile_debugfile_args(rel_obj, pch)) def get_link_debugfile_args(self, targetfile: str) -> T.List[str]: - return self._to_host_flags(self.host_compiler.get_link_debugfile_args(targetfile), _Phase.LINKER) + return self._to_host_flags(self.host_compiler.get_link_debugfile_args(targetfile), Phase.LINKER) def get_depfile_suffix(self) -> str: return 'd' def get_optimization_link_args(self, optimization_level: str) -> T.List[str]: - return self._to_host_flags(self.host_compiler.get_optimization_link_args(optimization_level), _Phase.LINKER) + return self._to_host_flags(self.host_compiler.get_optimization_link_args(optimization_level), Phase.LINKER) def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str, rpath_paths: T.Tuple[str, ...], build_rpath: str, install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]: (rpath_args, rpath_dirs_to_remove) = self.host_compiler.build_rpath_args( env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath) - return (self._to_host_flags(rpath_args, _Phase.LINKER), rpath_dirs_to_remove) + return (self._to_host_flags(rpath_args, Phase.LINKER), rpath_dirs_to_remove) def linker_to_compiler_args(self, args: T.List[str]) -> T.List[str]: return args @@ -767,7 +770,7 @@ def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: return [] def get_std_exe_link_args(self) -> T.List[str]: - return self._to_host_flags(self.host_compiler.get_std_exe_link_args(), _Phase.LINKER) + return self._to_host_flags(self.host_compiler.get_std_exe_link_args(), Phase.LINKER) def find_library(self, libname: str, env: 'Environment', extra_dirs: T.List[str], libtype: LibType = LibType.PREFER_SHARED, lib_prefix_warning: bool = True) -> T.Optional[T.List[str]]: @@ -783,16 +786,16 @@ def get_crt_link_args(self, crt_val: str, buildtype: str) -> T.List[str]: host_crt_compile_args = self.host_compiler.get_crt_compile_args(crt_val, buildtype) if any(arg in {'/MDd', '/MD', '/MTd'} for arg in host_crt_compile_args): host_link_arg_overrides += ['/NODEFAULTLIB:LIBCMT.lib'] - return self._to_host_flags(host_link_arg_overrides + self.host_compiler.get_crt_link_args(crt_val, buildtype), _Phase.LINKER) + return self._to_host_flags(host_link_arg_overrides + self.host_compiler.get_crt_link_args(crt_val, buildtype), Phase.LINKER) def get_target_link_args(self, target: 'BuildTarget') -> T.List[str]: - return self._to_host_flags(super().get_target_link_args(target), _Phase.LINKER) + return self._to_host_flags(super().get_target_link_args(target), Phase.LINKER) def get_dependency_compile_args(self, dep: 'Dependency') -> T.List[str]: return self._to_host_flags(super().get_dependency_compile_args(dep)) def get_dependency_link_args(self, dep: 'Dependency') -> T.List[str]: - return self._to_host_flags(super().get_dependency_link_args(dep), _Phase.LINKER) + return self._to_host_flags(super().get_dependency_link_args(dep), Phase.LINKER) def get_ccbin_args(self, ccoptions: 'KeyedOptionDictType') -> T.List[str]: key = self.form_compileropt_key('ccbindir') diff --git a/mesonbuild/compilers/detect.py b/mesonbuild/compilers/detect.py index 0a95f90dd03c..22c5cb5aa17d 100644 --- a/mesonbuild/compilers/detect.py +++ b/mesonbuild/compilers/detect.py @@ -616,7 +616,8 @@ def detect_cpp_compiler(env: 'Environment', for_machine: MachineChoice) -> Compi return _detect_c_or_cpp_compiler(env, 'cpp', for_machine) def detect_cuda_compiler(env: 'Environment', for_machine: MachineChoice) -> Compiler: - from .cuda import CudaCompiler + from .cuda import CudaCompiler, Phase + from ..options import OptionKey from ..linkers.linkers import CudaLinker popen_exceptions = {} is_cross = env.is_cross_build(for_machine) @@ -648,6 +649,12 @@ def detect_cuda_compiler(env: 'Environment', for_machine: MachineChoice) -> Comp cpp_compiler = detect_cpp_compiler(env, for_machine) cls = CudaCompiler env.coredata.add_lang_args(cls.language, cls, for_machine, env) + key = OptionKey('cuda_link_args', machine=for_machine) + if key in env.options: + # To fix LDFLAGS issue + val = env.options[key] + assert isinstance(val, list) + env.coredata.set_options({key: cls.to_host_flags_base(val, Phase.LINKER)}) linker = CudaLinker(compiler, for_machine, CudaCompiler.LINKER_PREFIX, [], version=CudaLinker.parse_version()) return cls(ccache, compiler, version, for_machine, is_cross, host_compiler=cpp_compiler, info=info, linker=linker) raise EnvironmentException(f'Could not find suitable CUDA compiler: "{"; ".join([" ".join(c) for c in compilers])}"') From 7cf2dd6e3ff0822ba7636adbd4bb92ceb4dd7366 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Wed, 28 Aug 2024 10:20:12 -0700 Subject: [PATCH 163/302] options: fix typing issues with the OptionStore type --- mesonbuild/options.py | 44 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/mesonbuild/options.py b/mesonbuild/options.py index 72dfb61a3135..7d58de7536c1 100644 --- a/mesonbuild/options.py +++ b/mesonbuild/options.py @@ -673,16 +673,14 @@ def add_to_argparse(self, name: str, parser: argparse.ArgumentParser, help_suffi } class OptionStore: - def __init__(self): + def __init__(self) -> None: self.d: T.Dict['OptionKey', 'UserOption[T.Any]'] = {} - self.project_options = set() - self.all_languages = set() - self.module_options = set() + self.project_options: T.Set[OptionKey] = set() + self.module_options: T.Set[OptionKey] = set() from .compilers import all_languages - for lang in all_languages: - self.all_languages.add(lang) + self.all_languages = set(all_languages) - def __len__(self): + def __len__(self) -> int: return len(self.d) def ensure_key(self, key: T.Union[OptionKey, str]) -> OptionKey: @@ -696,29 +694,29 @@ def get_value_object(self, key: T.Union[OptionKey, str]) -> 'UserOption[T.Any]': def get_value(self, key: T.Union[OptionKey, str]) -> 'T.Any': return self.get_value_object(key).value - def add_system_option(self, key: T.Union[OptionKey, str], valobj: 'UserOption[T.Any]'): + def add_system_option(self, key: T.Union[OptionKey, str], valobj: 'UserOption[T.Any]') -> None: key = self.ensure_key(key) if '.' in key.name: raise MesonException(f'Internal error: non-module option has a period in its name {key.name}.') self.add_system_option_internal(key, valobj) - def add_system_option_internal(self, key: T.Union[OptionKey, str], valobj: 'UserOption[T.Any]'): + def add_system_option_internal(self, key: T.Union[OptionKey, str], valobj: 'UserOption[T.Any]') -> None: key = self.ensure_key(key) assert isinstance(valobj, UserOption) self.d[key] = valobj - def add_compiler_option(self, language: str, key: T.Union[OptionKey, str], valobj: 'UserOption[T.Any]'): + def add_compiler_option(self, language: str, key: T.Union[OptionKey, str], valobj: 'UserOption[T.Any]') -> None: key = self.ensure_key(key) if not key.name.startswith(language + '_'): raise MesonException(f'Internal error: all compiler option names must start with language prefix. ({key.name} vs {language}_)') self.add_system_option(key, valobj) - def add_project_option(self, key: T.Union[OptionKey, str], valobj: 'UserOption[T.Any]'): + def add_project_option(self, key: T.Union[OptionKey, str], valobj: 'UserOption[T.Any]') -> None: key = self.ensure_key(key) self.d[key] = valobj self.project_options.add(key) - def add_module_option(self, modulename: str, key: T.Union[OptionKey, str], valobj: 'UserOption[T.Any]'): + def add_module_option(self, modulename: str, key: T.Union[OptionKey, str], valobj: 'UserOption[T.Any]') -> None: key = self.ensure_key(key) if key.name.startswith('build.'): raise MesonException('FATAL internal error: somebody goofed option handling.') @@ -732,38 +730,38 @@ def set_value(self, key: T.Union[OptionKey, str], new_value: 'T.Any') -> bool: return self.d[key].set_value(new_value) # FIXME, this should be removed.or renamed to "change_type_of_existing_object" or something like that - def set_value_object(self, key: T.Union[OptionKey, str], new_object: 'UserOption[T.Any]') -> bool: + def set_value_object(self, key: T.Union[OptionKey, str], new_object: 'UserOption[T.Any]') -> None: key = self.ensure_key(key) self.d[key] = new_object - def remove(self, key): + def remove(self, key: OptionKey) -> None: del self.d[key] - def __contains__(self, key): + def __contains__(self, key: OptionKey) -> bool: key = self.ensure_key(key) return key in self.d - def __repr__(self): + def __repr__(self) -> str: return repr(self.d) - def keys(self): + def keys(self) -> T.KeysView[OptionKey]: return self.d.keys() - def values(self): + def values(self) -> T.ValuesView[UserOption[T.Any]]: return self.d.values() def items(self) -> T.ItemsView['OptionKey', 'UserOption[T.Any]']: return self.d.items() # FIXME: this method must be deleted and users moved to use "add_xxx_option"s instead. - def update(self, *args, **kwargs): - return self.d.update(*args, **kwargs) + def update(self, **kwargs: UserOption[T.Any]) -> None: + self.d.update(**kwargs) - def setdefault(self, k, o): + def setdefault(self, k: OptionKey, o: UserOption[T.Any]) -> UserOption[T.Any]: return self.d.setdefault(k, o) - def get(self, *args, **kwargs) -> UserOption: - return self.d.get(*args, **kwargs) + def get(self, o: OptionKey, default: T.Optional[UserOption[T.Any]] = None) -> T.Optional[UserOption[T.Any]]: + return self.d.get(o, default) def is_project_option(self, key: OptionKey) -> bool: """Convenience method to check if this is a project option.""" From 69f1679dbd32ae09237f7e2c8f76d3b6aa516378 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Wed, 4 Sep 2024 09:32:21 -0700 Subject: [PATCH 164/302] options.py: Fix Intel Copyright Which covers changes from coredata.py that were moved into this file --- mesonbuild/options.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/options.py b/mesonbuild/options.py index 7d58de7536c1..e3fe98ef99f2 100644 --- a/mesonbuild/options.py +++ b/mesonbuild/options.py @@ -1,6 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright 2013-2024 Contributors to the The Meson project -# Copyright © 2024 Intel Corporation +# Copyright © 2019-2024 Intel Corporation from __future__ import annotations from collections import OrderedDict From 53e11488d9ce01b14c2b280d66c3efeda1c60abc Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Wed, 28 Aug 2024 10:34:09 -0700 Subject: [PATCH 165/302] options: use a TypedDict for kwargs to ArgumentParser.add_argument This cleans up some more typing issues. --- mesonbuild/options.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/mesonbuild/options.py b/mesonbuild/options.py index e3fe98ef99f2..9f65cc6b7bc9 100644 --- a/mesonbuild/options.py +++ b/mesonbuild/options.py @@ -27,6 +27,16 @@ ) from . import mlog +if T.TYPE_CHECKING: + from typing_extensions import TypedDict + + class ArgparseKWs(TypedDict, total=False): + + action: str + dest: str + default: str + choices: T.List + DEFAULT_YIELDING = False # Can't bind this near the class method it seems, sadly. @@ -567,7 +577,7 @@ def prefixed_default(self, name: 'OptionKey', prefix: str = '') -> T.Any: return self.default def add_to_argparse(self, name: str, parser: argparse.ArgumentParser, help_suffix: str) -> None: - kwargs = OrderedDict() + kwargs: ArgparseKWs = {} c = self._argparse_choices() b = self._argparse_action() From 58c6b13c4e970223eae09fd88992d32cb1624ba9 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 7 Sep 2024 17:04:55 +0200 Subject: [PATCH 166/302] Fix check for 32-bit clang-cl --- mesonbuild/environment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index fce295dbc2d7..5cff86bb13c3 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -309,7 +309,7 @@ def detect_windows_arch(compilers: CompilersDict) -> str: for compiler in compilers.values(): if compiler.id == 'msvc' and (compiler.target in {'x86', '80x86'}): return 'x86' - if compiler.id == 'clang-cl' and compiler.target == 'x86': + if compiler.id == 'clang-cl' and (compiler.target in {'x86', 'i686'}): return 'x86' if compiler.id == 'gcc' and compiler.has_builtin_define('__i386__'): return 'x86' From f83dca32fe340727ada08b46d70bfc6dbba52d84 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Wed, 4 Sep 2024 09:39:38 -0700 Subject: [PATCH 167/302] interpreterbase: Use explicit `TypeAlias` annotation to allow recursive types And fix all of the issues that pop up once we remove the use of `Any`, which hides so many problems. --- mesonbuild/interpreterbase/baseobjects.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mesonbuild/interpreterbase/baseobjects.py b/mesonbuild/interpreterbase/baseobjects.py index 9a119a98a75d..a5ccccedc060 100644 --- a/mesonbuild/interpreterbase/baseobjects.py +++ b/mesonbuild/interpreterbase/baseobjects.py @@ -15,7 +15,7 @@ from contextlib import AbstractContextManager if T.TYPE_CHECKING: - from typing_extensions import Protocol + from typing_extensions import Protocol, TypeAlias # Object holders need the actual interpreter from ..interpreter import Interpreter @@ -28,8 +28,8 @@ def __call__(self, other: __T) -> 'TYPE_var': ... TV_func = T.TypeVar('TV_func', bound=T.Callable[..., T.Any]) -TYPE_elementary = T.Union[str, int, bool, T.List[T.Any], T.Dict[str, T.Any]] -TYPE_var = T.Union[TYPE_elementary, HoldableObject, 'MesonInterpreterObject'] +TYPE_elementary: TypeAlias = T.Union[str, int, bool, T.Sequence['TYPE_elementary'], T.Dict[str, 'TYPE_elementary']] +TYPE_var: TypeAlias = T.Union[TYPE_elementary, HoldableObject, 'MesonInterpreterObject', T.Sequence['TYPE_var'], T.Dict[str, 'TYPE_var']] TYPE_nvar = T.Union[TYPE_var, mparser.BaseNode] TYPE_kwargs = T.Dict[str, TYPE_var] TYPE_nkwargs = T.Dict[str, TYPE_nvar] @@ -122,7 +122,7 @@ class MutableInterpreterObject: ''' Dummy class to mark the object type as mutable ''' HoldableTypes = (HoldableObject, int, bool, str, list, dict) -TYPE_HoldableTypes = T.Union[TYPE_elementary, HoldableObject] +TYPE_HoldableTypes = T.Union[TYPE_var, HoldableObject] InterpreterObjectTypeVar = T.TypeVar('InterpreterObjectTypeVar', bound=TYPE_HoldableTypes) class ObjectHolder(InterpreterObject, T.Generic[InterpreterObjectTypeVar]): From a22a50a6739160bdf93a5a11f5026112007ccf4e Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 7 Feb 2024 11:12:22 +0100 Subject: [PATCH 168/302] compilers: avoid -Wunused-value compiler warning in CLikeCompiler.has_members() Otherwise, `CFLAGS='-Wall -Werror' meson build` can fail detection: void bar(void) { struct stat foo; foo.st_mtim.tv_nsec; } ----------- Command line: `cc ./project/build/meson-private/tmpqz_gi65d/testfile.c -o ./project/build/meson-private/tmpqz_gi65d/output.obj -c -O3 -Werror -Wall -D_FILE_OFFSET_BITS=64 -O0 -std=gnu99` -> 1 stderr: ./project/build/meson-private/tmpqz_gi65d/testfile.c: In function 'bar': ./project/build/meson-private/tmpqz_gi65d/testfile.c:45:24: error: statement with no effect [-Werror=unused-value] 45 | foo.st_mtim.tv_nsec; | ~~~~~~~~~~~^~~~~~~~ cc1: all warnings being treated as errors --- mesonbuild/compilers/mixins/clike.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mesonbuild/compilers/mixins/clike.py b/mesonbuild/compilers/mixins/clike.py index 60a91f35557c..a0d6094abb0d 100644 --- a/mesonbuild/compilers/mixins/clike.py +++ b/mesonbuild/compilers/mixins/clike.py @@ -870,11 +870,12 @@ def has_members(self, typename: str, membernames: T.List[str], if extra_args is None: extra_args = [] # Create code that accesses all members - members = ''.join(f'foo.{member};\n' for member in membernames) + members = ''.join(f'(void) ( foo.{member} );\n' for member in membernames) t = f'''{prefix} void bar(void) {{ {typename} foo; {members} + (void) foo; }}''' return self.compiles(t, env, extra_args=extra_args, dependencies=dependencies) From fa8bd9306c01a1268d1a4cd7417ad753b1aa09e1 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 7 Feb 2024 11:12:22 +0100 Subject: [PATCH 169/302] compilers: avoid -Wunused-value compiler warning in CLikeCompiler.has_type() Otherwise, `CFLAGS='-Wall -Werror' meson build` can fail detection: Running compile: Working directory: ./project/build/meson-private/tmpk86bgc04 Code: #include void bar(void) { sizeof(loff_t); } ----------- Command line: `cc ./project/build/meson-private/tmpk86bgc04/testfile.c -o ./project/build/meson-private/tmpk86bgc04/output.obj -c -Werror -Wall -D_FILE_OFFSET_BITS=64 -O0 -std=gnu99` -> 1 stderr: ./project/build/meson-private/tmpk86bgc04/testfile.c: In function 'bar': ./project/build/meson-private/tmpk86bgc04/testfile.c:3:13: error: statement with no effect [-Werror=unused-value] 3 | sizeof(loff_t); | ^~~~~~ cc1: all warnings being treated as errors ----------- Checking for type "loff_t" : NO --- mesonbuild/compilers/mixins/clike.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/compilers/mixins/clike.py b/mesonbuild/compilers/mixins/clike.py index a0d6094abb0d..e982ca023e41 100644 --- a/mesonbuild/compilers/mixins/clike.py +++ b/mesonbuild/compilers/mixins/clike.py @@ -885,7 +885,7 @@ def has_type(self, typename: str, prefix: str, env: 'Environment', dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[bool, bool]: t = f'''{prefix} void bar(void) {{ - sizeof({typename}); + (void) sizeof({typename}); }}''' return self.compiles(t, env, extra_args=extra_args, dependencies=dependencies) From 68d620ea8eeaf4e6bfb23277586a053b3b074ebb Mon Sep 17 00:00:00 2001 From: Charles Brunet Date: Tue, 10 Sep 2024 08:27:25 -0400 Subject: [PATCH 170/302] Fix typing for InternalDependency.get_as_static() and get_as_shared() --- mesonbuild/dependencies/base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index fa278d97c07f..03b2596e1582 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -353,14 +353,14 @@ def generate_link_whole_dependency(self) -> Dependency: new_dep.libraries = [] return new_dep - def get_as_static(self, recursive: bool) -> Dependency: + def get_as_static(self, recursive: bool) -> InternalDependency: new_dep = copy.copy(self) new_dep.libraries = [lib.get('static') for lib in self.libraries] if recursive: new_dep.ext_deps = [dep.get_as_static(True) for dep in self.ext_deps] return new_dep - def get_as_shared(self, recursive: bool) -> Dependency: + def get_as_shared(self, recursive: bool) -> InternalDependency: new_dep = copy.copy(self) new_dep.libraries = [lib.get('shared') for lib in self.libraries] if recursive: From 8a641cac5f7fd01c5e213c170c1babc18088369d Mon Sep 17 00:00:00 2001 From: Charles Brunet Date: Tue, 10 Sep 2024 08:20:22 -0400 Subject: [PATCH 171/302] Fix pkgconfig.generate handling of BothLibraries dependencies Was caused by 7b3169f. Fixes #13657. --- mesonbuild/modules/pkgconfig.py | 7 +++++++ .../common/278 pkgconfig-gen/meson.build | 19 +++++++++++++++++++ test cases/common/278 pkgconfig-gen/simple.c | 6 ++++++ test cases/common/278 pkgconfig-gen/simple.h | 6 ++++++ .../278 pkgconfig-gen/simple2/exports.def | 2 ++ .../278 pkgconfig-gen/simple2/meson.build | 2 ++ .../278 pkgconfig-gen/simple2/simple2.c | 5 +++++ .../278 pkgconfig-gen/simple2/simple2.h | 6 ++++++ test cases/common/278 pkgconfig-gen/test.json | 15 +++++++++++++++ 9 files changed, 68 insertions(+) create mode 100644 test cases/common/278 pkgconfig-gen/meson.build create mode 100644 test cases/common/278 pkgconfig-gen/simple.c create mode 100644 test cases/common/278 pkgconfig-gen/simple.h create mode 100644 test cases/common/278 pkgconfig-gen/simple2/exports.def create mode 100644 test cases/common/278 pkgconfig-gen/simple2/meson.build create mode 100644 test cases/common/278 pkgconfig-gen/simple2/simple2.c create mode 100644 test cases/common/278 pkgconfig-gen/simple2/simple2.h create mode 100644 test cases/common/278 pkgconfig-gen/test.json diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index 61de8fc43ac1..1bdf82931a94 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -195,6 +195,13 @@ def _process_libs( if obj.found(): if obj.objects: raise mesonlib.MesonException('.pc file cannot refer to individual object files.') + + # Ensure BothLibraries are resolved: + if self.pub_libs and isinstance(self.pub_libs[0], build.StaticLibrary): + obj = obj.get_as_static(recursive=True) + else: + obj = obj.get_as_shared(recursive=True) + processed_libs += obj.get_link_args() processed_cflags += obj.get_compile_args() self._add_lib_dependencies(obj.libraries, obj.whole_libraries, obj.ext_deps, public, private_external_deps=True) diff --git a/test cases/common/278 pkgconfig-gen/meson.build b/test cases/common/278 pkgconfig-gen/meson.build new file mode 100644 index 000000000000..3f158882f54b --- /dev/null +++ b/test cases/common/278 pkgconfig-gen/meson.build @@ -0,0 +1,19 @@ +project('pkgconfig-get', 'c') + +pkgg = import('pkgconfig') + +subdir('simple2') + +lib = library('simple', 'simple.c', dependencies: lib_dep) +libver = '1.0' +h = install_headers('simple.h') + + +pkgg.generate( + lib, + version : libver, + name : 'libsimple', + filebase : 'simple', + description : 'A simple demo library.', + libraries: [lib_dep], +) \ No newline at end of file diff --git a/test cases/common/278 pkgconfig-gen/simple.c b/test cases/common/278 pkgconfig-gen/simple.c new file mode 100644 index 000000000000..da1d909f7d26 --- /dev/null +++ b/test cases/common/278 pkgconfig-gen/simple.c @@ -0,0 +1,6 @@ +#include"simple.h" +#include + +int simple_function(void) { + return simple_simple_function(); +} diff --git a/test cases/common/278 pkgconfig-gen/simple.h b/test cases/common/278 pkgconfig-gen/simple.h new file mode 100644 index 000000000000..6896bfd17f7e --- /dev/null +++ b/test cases/common/278 pkgconfig-gen/simple.h @@ -0,0 +1,6 @@ +#ifndef SIMPLE_H_ +#define SIMPLE_H_ + +int simple_function(void); + +#endif diff --git a/test cases/common/278 pkgconfig-gen/simple2/exports.def b/test cases/common/278 pkgconfig-gen/simple2/exports.def new file mode 100644 index 000000000000..42c911b93c51 --- /dev/null +++ b/test cases/common/278 pkgconfig-gen/simple2/exports.def @@ -0,0 +1,2 @@ +EXPORTS + simple_simple_function @1 diff --git a/test cases/common/278 pkgconfig-gen/simple2/meson.build b/test cases/common/278 pkgconfig-gen/simple2/meson.build new file mode 100644 index 000000000000..c8f13c05ee9d --- /dev/null +++ b/test cases/common/278 pkgconfig-gen/simple2/meson.build @@ -0,0 +1,2 @@ +lib2 = library('simple2', 'simple2.c', vs_module_defs: 'exports.def') +lib_dep = declare_dependency(link_with: lib2, include_directories: include_directories('.')) diff --git a/test cases/common/278 pkgconfig-gen/simple2/simple2.c b/test cases/common/278 pkgconfig-gen/simple2/simple2.c new file mode 100644 index 000000000000..215b2aef8eed --- /dev/null +++ b/test cases/common/278 pkgconfig-gen/simple2/simple2.c @@ -0,0 +1,5 @@ +#include"simple2.h" + +int simple_simple_function(void) { + return 42; +} diff --git a/test cases/common/278 pkgconfig-gen/simple2/simple2.h b/test cases/common/278 pkgconfig-gen/simple2/simple2.h new file mode 100644 index 000000000000..472e135f2b61 --- /dev/null +++ b/test cases/common/278 pkgconfig-gen/simple2/simple2.h @@ -0,0 +1,6 @@ +#ifndef SIMPLE2_H_ +#define SIMPLE2_H_ + +int simple_simple_function(void); + +#endif diff --git a/test cases/common/278 pkgconfig-gen/test.json b/test cases/common/278 pkgconfig-gen/test.json new file mode 100644 index 000000000000..99b18086c0f5 --- /dev/null +++ b/test cases/common/278 pkgconfig-gen/test.json @@ -0,0 +1,15 @@ +{ + "installed": [ + { "type": "file", "file": "usr/include/simple.h"}, + { "type": "file", "file": "usr/lib/pkgconfig/simple.pc"} + ], + "matrix": { + "options": { + "default_library": [ + { "val": "shared" }, + { "val": "static" }, + { "val": "both" } + ] + } + } +} From 3aedec5b34c586b9c3a16be17d2fda353bf5fff1 Mon Sep 17 00:00:00 2001 From: Andrew McNulty Date: Sat, 7 Sep 2024 10:26:08 +0100 Subject: [PATCH 172/302] Harmonize d_import_dirs and include_directories behavior. This commit harmonizes the handling of `d_import_dirs` and `include_directories`. The treatment of `d_import_dirs` was also different depending on the context: in `declare_dependency` it was treated like the `include_directories`, but in `build_target` et al, it had special treatment. With this commit, they are all treated by the same function. The documentation has been updated to reflect this. Fixes #12742 --- docs/yaml/functions/_build_target_base.yaml | 7 ++++-- mesonbuild/interpreter/interpreter.py | 25 ++++++--------------- test cases/d/9 features/meson.build | 2 +- 3 files changed, 13 insertions(+), 21 deletions(-) diff --git a/docs/yaml/functions/_build_target_base.yaml b/docs/yaml/functions/_build_target_base.yaml index 1db49a5315a6..1721b29cfe5a 100644 --- a/docs/yaml/functions/_build_target_base.yaml +++ b/docs/yaml/functions/_build_target_base.yaml @@ -256,8 +256,11 @@ kwargs: do not support GNU visibility arguments. d_import_dirs: - type: list[str] - description: List of directories to look in for string imports used in the D programming language. + type: list[inc | str] + since: 0.62.0 + description: | + the directories to add to the string search path (i.e. `-J` switch for DMD). + Must be [[@inc]] objects or plain strings. d_unittest: type: bool diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index bd4d1596231a..9bbab5d60224 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -2801,6 +2801,12 @@ def extract_incdirs(self, kwargs, key: str = 'include_directories') -> T.List[bu if isinstance(p, build.IncludeDirs): result.append(p) elif isinstance(p, str): + if key == 'd_import_dirs' and os.path.normpath(p).startswith(self.environment.get_source_dir()): + FeatureDeprecated.single_use('Building absolute path to source dir is not supported', + '0.45', self.subproject, + 'Use a relative path instead.', + location=self.current_node) + p = os.path.relpath(p, os.path.join(self.environment.get_source_dir(), self.subdir)) result.append(self.build_incdir_object([p])) else: raise InterpreterException('Include directory objects can only be created from strings or include directories.') @@ -3400,7 +3406,7 @@ def build_target(self, node: mparser.BaseNode, args: T.Tuple[str, SourcesVarargs kwargs['language_args'][lang].extend(args) kwargs['depend_files'].extend(deps) if targetclass is not build.Jar: - self.kwarg_strings_to_includedirs(kwargs) + kwargs['d_import_dirs'] = self.extract_incdirs(kwargs, 'd_import_dirs') # Filter out kwargs from other target types. For example 'soversion' # passed to library() when default_library == 'static'. @@ -3473,23 +3479,6 @@ def build_target(self, node: mparser.BaseNode, args: T.Tuple[str, SourcesVarargs self.project_args_frozen = True return target - def kwarg_strings_to_includedirs(self, kwargs: kwtypes._BuildTarget) -> None: - if kwargs['d_import_dirs']: - items = kwargs['d_import_dirs'] - cleaned_items: T.List[build.IncludeDirs] = [] - for i in items: - if isinstance(i, str): - # BW compatibility. This was permitted so we must support it - # for a few releases so people can transition to "correct" - # path declarations. - if os.path.normpath(i).startswith(self.environment.get_source_dir()): - mlog.warning('''Building a path to the source dir is not supported. Use a relative path instead. -This will become a hard error in the future.''', location=self.current_node) - i = os.path.relpath(i, os.path.join(self.environment.get_source_dir(), self.subdir)) - i = self.build_incdir_object([i]) - cleaned_items.append(i) - kwargs['d_import_dirs'] = cleaned_items - def add_stdlib_info(self, target): for l in target.compilers.keys(): dep = self.build.stdlibs[target.for_machine].get(l, None) diff --git a/test cases/d/9 features/meson.build b/test cases/d/9 features/meson.build index 50059f169c10..065ef3a6ddef 100644 --- a/test cases/d/9 features/meson.build +++ b/test cases/d/9 features/meson.build @@ -1,4 +1,4 @@ -project('D Features', 'd', default_options : ['debug=false']) +project('D Features', 'd', meson_version: '>=1.6', default_options : ['debug=false']) dc = meson.get_compiler('d') From 4179996fefd272cc0c893b88ad17c010fa037768 Mon Sep 17 00:00:00 2001 From: spaette Date: Wed, 11 Sep 2024 13:05:04 -0500 Subject: [PATCH 173/302] Fix typos --- data/shell-completions/bash/meson | 2 +- docs/markdown/Builtin-options.md | 2 +- docs/markdown/Release-notes-for-0.51.0.md | 2 +- docs/markdown/Release-notes-for-1.0.0.md | 2 +- docs/markdown/Release-notes-for-1.2.0.md | 2 +- docs/markdown/Release-notes-for-1.3.0.md | 2 +- docs/markdown/Release-notes-for-1.5.0.md | 2 +- docs/markdown/Wrap-dependency-system-manual.md | 4 ++-- docs/refman/generatormd.py | 2 +- docs/yaml/functions/build_target.yaml | 2 +- docs/yaml/functions/install_data.yaml | 2 +- docs/yaml/objects/compiler.yaml | 2 +- mesonbuild/backend/backends.py | 2 +- mesonbuild/backend/ninjabackend.py | 4 ++-- mesonbuild/backend/vs2010backend.py | 4 ++-- mesonbuild/cargo/builder.py | 8 ++++---- mesonbuild/cargo/interpreter.py | 4 ++-- mesonbuild/cmake/generator.py | 2 +- mesonbuild/cmake/interpreter.py | 2 +- mesonbuild/compilers/detect.py | 8 ++++---- mesonbuild/dependencies/boost.py | 2 +- mesonbuild/environment.py | 4 ++-- mesonbuild/interpreter/interpreter.py | 2 +- mesonbuild/modules/__init__.py | 2 +- mesonbuild/msetup.py | 2 +- mesonbuild/options.py | 2 +- test cases/format/5 transform/genexpected.cmd | 2 +- test cases/rust/5 polyglot static/meson.build | 2 +- test cases/rust/9 unit tests/test3.rs | 2 +- unittests/baseplatformtests.py | 4 ++-- unittests/internaltests.py | 16 ++++++++-------- unittests/machinefiletests.py | 10 +++++----- 32 files changed, 55 insertions(+), 55 deletions(-) diff --git a/data/shell-completions/bash/meson b/data/shell-completions/bash/meson index 88dc15ec3225..0814342dbe2a 100644 --- a/data/shell-completions/bash/meson +++ b/data/shell-completions/bash/meson @@ -30,7 +30,7 @@ _subprojects() { local COMPREPLY=() _filedir # _filedir for whatever reason can't reason about symlinks, so -d will them. - # Filter out wrap files with this expresion. + # Filter out wrap files with this expression. IFS=$'\n' echo "${COMPREPLY[*]}" | grep -vE '\.wrap$' | xargs popd &>/dev/null } diff --git a/docs/markdown/Builtin-options.md b/docs/markdown/Builtin-options.md index 2018b9575aed..f16a46ffebea 100644 --- a/docs/markdown/Builtin-options.md +++ b/docs/markdown/Builtin-options.md @@ -187,7 +187,7 @@ with previous meson versions), 'static', or 'auto'. With auto, the value from `default_library` option is used, unless it is 'both', in which case 'shared' is used instead. -When `default_both_libraries` is 'auto', passing a [[@both_libs]] dependecy +When `default_both_libraries` is 'auto', passing a [[@both_libs]] dependency in [[both_libraries]] will link the static dependency with the static lib, and the shared dependency with the shared lib. diff --git a/docs/markdown/Release-notes-for-0.51.0.md b/docs/markdown/Release-notes-for-0.51.0.md index 635fbbdda773..d4eaa5e526b9 100644 --- a/docs/markdown/Release-notes-for-0.51.0.md +++ b/docs/markdown/Release-notes-for-0.51.0.md @@ -143,7 +143,7 @@ then invoke Meson as `meson setup builddir/ -Dcmake_prefix_path=/tmp/dep` You can tag a test as needing to fail like this: ```meson -test('shoulfail', exe, should_fail: true) +test('shouldfail', exe, should_fail: true) ``` If the test passes the problem is reported in the error logs but due diff --git a/docs/markdown/Release-notes-for-1.0.0.md b/docs/markdown/Release-notes-for-1.0.0.md index 42c05ddab3f9..2399373b1975 100644 --- a/docs/markdown/Release-notes-for-1.0.0.md +++ b/docs/markdown/Release-notes-for-1.0.0.md @@ -59,7 +59,7 @@ Any include paths in these dependencies will be passed to the underlying call to ## String arguments to the rust.bindgen include_directories argument Most other cases of include_directories accept strings as well as -`IncludeDirectory` objects, so lets do that here too for consistency. +`IncludeDirectory` objects, so let's do that here too for consistency. ## The Rust module is stable diff --git a/docs/markdown/Release-notes-for-1.2.0.md b/docs/markdown/Release-notes-for-1.2.0.md index 23312164e3f7..6e321b6d42d4 100644 --- a/docs/markdown/Release-notes-for-1.2.0.md +++ b/docs/markdown/Release-notes-for-1.2.0.md @@ -49,7 +49,7 @@ directory, instead of using Visual Studio's native engine. ## More data in introspection files - Used compilers are listed in `intro-compilers.json` -- Informations about `host`, `build` and `target` machines +- Information about `host`, `build` and `target` machines are lister in `intro-machines.json` - `intro-dependencies.json` now includes internal dependencies, and relations between dependencies. diff --git a/docs/markdown/Release-notes-for-1.3.0.md b/docs/markdown/Release-notes-for-1.3.0.md index cf6ad46ae064..1a1d048989ff 100644 --- a/docs/markdown/Release-notes-for-1.3.0.md +++ b/docs/markdown/Release-notes-for-1.3.0.md @@ -39,7 +39,7 @@ about its value. ## [[configure_file]] now has a `macro_name` parameter. -This new paramater, `macro_name` allows C macro-style include guards to be added +This new parameter, `macro_name` allows C macro-style include guards to be added to [[configure_file]]'s output when a template file is not given. This change simplifies the creation of configure files that define macros with dynamic names and want the C-style include guards. diff --git a/docs/markdown/Release-notes-for-1.5.0.md b/docs/markdown/Release-notes-for-1.5.0.md index 7dfea9af2b13..794efe47c9c1 100644 --- a/docs/markdown/Release-notes-for-1.5.0.md +++ b/docs/markdown/Release-notes-for-1.5.0.md @@ -19,7 +19,7 @@ Cargo dependencies names are now in the format `--rs`: * `x.y.z` -> 'x' * `0.x.y` -> '0.x' * `0.0.x` -> '0' - It allows to make different dependencies for uncompatible versions of the same + It allows to make different dependencies for incompatible versions of the same crate. - `-rs` suffix is added to distinguish from regular system dependencies, for example `gstreamer-1.0` is a system pkg-config dependency and `gstreamer-0.22-rs` diff --git a/docs/markdown/Wrap-dependency-system-manual.md b/docs/markdown/Wrap-dependency-system-manual.md index 3983d28771e9..60568f1d8f8d 100644 --- a/docs/markdown/Wrap-dependency-system-manual.md +++ b/docs/markdown/Wrap-dependency-system-manual.md @@ -323,7 +323,7 @@ name: * `x.y.z` -> 'x' * `0.x.y` -> '0.x' * `0.0.x` -> '0' - It allows to make different dependencies for uncompatible versions of the same + It allows to make different dependencies for incompatible versions of the same crate. - `-rs` suffix is added to distinguish from regular system dependencies, for example `gstreamer-1.0` is a system pkg-config dependency and `gstreamer-0.22-rs` @@ -359,7 +359,7 @@ the main project depends on `foo-1-rs` and `bar-1-rs`, and they both depend on configure `common-rs` with a set of features. Later, when `bar-1-rs` does a lookup for `common-1-rs` it has already been configured and the set of features cannot be changed. If `bar-1-rs` wants extra features from `common-1-rs`, Meson will error out. -It is currently the responsability of the main project to resolve those +It is currently the responsibility of the main project to resolve those issues by enabling extra features on each subproject: ```meson project(..., diff --git a/docs/refman/generatormd.py b/docs/refman/generatormd.py index 2c80ab02308e..854712d53f88 100644 --- a/docs/refman/generatormd.py +++ b/docs/refman/generatormd.py @@ -94,7 +94,7 @@ def _gen_object_file_id(self, obj: Object) -> str: def _link_to_object(self, obj: T.Union[Function, Object], in_code_block: bool = False) -> str: ''' - Generate a palaceholder tag for the function/method/object documentation. + Generate a placeholder tag for the function/method/object documentation. This tag is then replaced in the custom hotdoc plugin. ''' prefix = '#' if in_code_block else '' diff --git a/docs/yaml/functions/build_target.yaml b/docs/yaml/functions/build_target.yaml index 74d45f0070de..a56fe75feae0 100644 --- a/docs/yaml/functions/build_target.yaml +++ b/docs/yaml/functions/build_target.yaml @@ -32,7 +32,7 @@ description: | The returned object also has methods that are documented in [[@build_tgt]]. - *"jar" is deprecated because it is fundementally a different thing than the + *"jar" is deprecated because it is fundamentally a different thing than the other build_target types. posargs_inherit: _build_target_base diff --git a/docs/yaml/functions/install_data.yaml b/docs/yaml/functions/install_data.yaml index ff4f3363d6ba..9ed09a75ccc4 100644 --- a/docs/yaml/functions/install_data.yaml +++ b/docs/yaml/functions/install_data.yaml @@ -13,7 +13,7 @@ varargs: warnings: - the `install_mode` kwarg ignored integer values between 0.59.0 -- 1.1.0. - an omitted `install_dir` kwarg did not work correctly inside of a subproject until 1.3.0. - - an omitted `install_dir` kwarg did not work correctly when combined with the `preserve_path` kwarg untill 1.3.0. + - an omitted `install_dir` kwarg did not work correctly when combined with the `preserve_path` kwarg until 1.3.0. kwargs: install_dir: diff --git a/docs/yaml/objects/compiler.yaml b/docs/yaml/objects/compiler.yaml index cd988a6834cd..43831d2c1d81 100644 --- a/docs/yaml/objects/compiler.yaml +++ b/docs/yaml/objects/compiler.yaml @@ -612,7 +612,7 @@ methods: # kwargs: # checked: # type: str - # sinec: 0.59.0 + # since: 0.59.0 # default: "'off'" # description: | # Supported values: diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index e35660b69a51..079b62dbdeb9 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -1135,7 +1135,7 @@ def search_dll_path(link_arg: str) -> T.Optional[str]: if p.is_file(): p = p.parent - # Heuristic: replace *last* occurence of '/lib' + # Heuristic: replace *last* occurrence of '/lib' binpath = Path('/bin'.join(p.as_posix().rsplit('/lib', maxsplit=1))) for _ in binpath.glob('*.dll'): return str(binpath) diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 1eeda96a8ce8..91603025ba92 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -101,7 +101,7 @@ def get_rsp_threshold() -> int: # and that has a limit of 8k. limit = 8192 else: - # Unix-like OSes usualy have very large command line limits, (On Linux, + # Unix-like OSes usually have very large command line limits, (On Linux, # for example, this is limited by the kernel's MAX_ARG_STRLEN). However, # some programs place much lower limits, notably Wine which enforces a # 32k limit like Windows. Therefore, we limit the command line to 32k. @@ -3135,7 +3135,7 @@ def has_dir_part(self, fname: FileOrString) -> bool: # Fortran is a bit weird (again). When you link against a library, just compiling a source file # requires the mod files that are output when single files are built. To do this right we would need to - # scan all inputs and write out explicit deps for each file. That is stoo slow and too much effort so + # scan all inputs and write out explicit deps for each file. That is too slow and too much effort so # instead just have an ordered dependency on the library. This ensures all required mod files are created. # The real deps are then detected via dep file generation from the compiler. This breaks on compilers that # produce incorrect dep files but such is life. diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py index a12963cdee06..08a19c659e44 100644 --- a/mesonbuild/backend/vs2010backend.py +++ b/mesonbuild/backend/vs2010backend.py @@ -879,7 +879,7 @@ def add_project_nmake_defs_incs_and_opts(self, parent_node, src: str, defs_paths ET.SubElement(parent_node, 'PreprocessorDefinitions', Condition=condition).text = defs ET.SubElement(parent_node, 'AdditionalIncludeDirectories', Condition=condition).text = paths ET.SubElement(parent_node, 'AdditionalOptions', Condition=condition).text = opts - else: # Can't find bespoke nmake defs/dirs/opts fields for this extention, so just reference the project's fields + else: # Can't find bespoke nmake defs/dirs/opts fields for this extension, so just reference the project's fields ET.SubElement(parent_node, 'PreprocessorDefinitions').text = '$(NMakePreprocessorDefinitions)' ET.SubElement(parent_node, 'AdditionalIncludeDirectories').text = '$(NMakeIncludeSearchPath)' ET.SubElement(parent_node, 'AdditionalOptions').text = '$(AdditionalOptions)' @@ -1542,7 +1542,7 @@ def add_non_makefile_vcxproj_elements( # the solution's configurations. Similarly, 'ItemGroup' also doesn't support 'Condition'. So, without knowing # a better (simple) alternative, for now, we'll repoint these generated sources (which will be incorrectly # pointing to non-existent files under our '[builddir]_vs' directory) to the appropriate location under one of - # our buildtype build directores (e.g. '[builddir]_debug'). + # our buildtype build directories (e.g. '[builddir]_debug'). # This will at least allow the user to open the files of generated sources listed in the solution explorer, # once a build/compile has generated these sources. # diff --git a/mesonbuild/cargo/builder.py b/mesonbuild/cargo/builder.py index 99659da11195..112c7c580d49 100644 --- a/mesonbuild/cargo/builder.py +++ b/mesonbuild/cargo/builder.py @@ -133,7 +133,7 @@ def equal(self, lhs: mparser.BaseNode, rhs: mparser.BaseNode) -> mparser.Compari :param lhs: The left hand side of the equal :param rhs: the right hand side of the equal - :return: A compraison node + :return: A comparison node """ return mparser.ComparisonNode('==', lhs, self._symbol('=='), rhs) @@ -142,7 +142,7 @@ def not_equal(self, lhs: mparser.BaseNode, rhs: mparser.BaseNode) -> mparser.Com :param lhs: The left hand side of the "!=" :param rhs: the right hand side of the "!=" - :return: A compraison node + :return: A comparison node """ return mparser.ComparisonNode('!=', lhs, self._symbol('!='), rhs) @@ -151,7 +151,7 @@ def in_(self, lhs: mparser.BaseNode, rhs: mparser.BaseNode) -> mparser.Compariso :param lhs: The left hand side of the "in" :param rhs: the right hand side of the "in" - :return: A compraison node + :return: A comparison node """ return mparser.ComparisonNode('in', lhs, self._symbol('in'), rhs) @@ -160,7 +160,7 @@ def not_in(self, lhs: mparser.BaseNode, rhs: mparser.BaseNode) -> mparser.Compar :param lhs: The left hand side of the "not in" :param rhs: the right hand side of the "not in" - :return: A compraison node + :return: A comparison node """ return mparser.ComparisonNode('notin', lhs, self._symbol('not in'), rhs) diff --git a/mesonbuild/cargo/interpreter.py b/mesonbuild/cargo/interpreter.py index 98ffa50ac09f..5f89c05ec88b 100644 --- a/mesonbuild/cargo/interpreter.py +++ b/mesonbuild/cargo/interpreter.py @@ -106,7 +106,7 @@ def _fixup_raw_mappings(d: T.Union[manifest.BuildTarget, manifest.LibTarget, man This does the following: * replaces any `-` with `_`, cargo likes the former, but python dicts make keys with `-` in them awkward to work with - * Convert Dependndency versions from the cargo format to something meson + * Convert Dependency versions from the cargo format to something meson understands :param d: The mapping to fix @@ -732,7 +732,7 @@ def interpret(subp_name: str, subdir: str, env: Environment) -> T.Tuple[mparser. ast += _create_meson_subdir(cargo, build) # Libs are always auto-discovered and there's no other way to handle them, - # which is unfortunate for reproducability + # which is unfortunate for reproducibility if os.path.exists(os.path.join(env.source_dir, cargo.subdir, cargo.path, cargo.lib.path)): for crate_type in cargo.lib.crate_type: ast.extend(_create_lib(cargo, build, crate_type)) diff --git a/mesonbuild/cmake/generator.py b/mesonbuild/cmake/generator.py index b78860564c34..a617f8adb9b6 100644 --- a/mesonbuild/cmake/generator.py +++ b/mesonbuild/cmake/generator.py @@ -20,7 +20,7 @@ def parse_generator_expressions( '''Parse CMake generator expressions Most generator expressions are simply ignored for - simplicety, however some are required for some common + simplicity, however some are required for some common use cases. ''' diff --git a/mesonbuild/cmake/interpreter.py b/mesonbuild/cmake/interpreter.py index a0fcb6972d0b..683991c5462e 100644 --- a/mesonbuild/cmake/interpreter.py +++ b/mesonbuild/cmake/interpreter.py @@ -487,7 +487,7 @@ def process_object_libs(self, obj_target_list: T.List['ConverterTarget'], linker source_files = [x.name for x in i.sources + i.generated] for j in stem: # On some platforms (specifically looking at you Windows with vs20xy backend) CMake does - # not produce object files with the format `foo.cpp.obj`, instead it skipps the language + # not produce object files with the format `foo.cpp.obj`, instead it skips the language # suffix and just produces object files like `foo.obj`. Thus we have to do our best to # undo this step and guess the correct language suffix of the object file. This is done # by trying all language suffixes meson knows and checking if one of them fits. diff --git a/mesonbuild/compilers/detect.py b/mesonbuild/compilers/detect.py index 22c5cb5aa17d..c1d004b32169 100644 --- a/mesonbuild/compilers/detect.py +++ b/mesonbuild/compilers/detect.py @@ -39,7 +39,7 @@ if is_windows(): # Intel C and C++ compiler is icl on Windows, but icc and icpc elsewhere. # Search for icl before cl, since Intel "helpfully" provides a - # cl.exe that returns *exactly the same thing* that microsofts + # cl.exe that returns *exactly the same thing* that Microsoft's # cl.exe does, and if icl is present, it's almost certainly what # you want. defaults['c'] = ['icl', 'cl', 'cc', 'gcc', 'clang', 'clang-cl', 'pgcc'] @@ -181,7 +181,7 @@ def detect_static_linker(env: 'Environment', compiler: Compiler) -> StaticLinker else: trials = default_linkers elif compiler.id == 'intel-cl' and compiler.language == 'c': # why not cpp? Is this a bug? - # Intel has its own linker that acts like microsoft's lib + # Intel has its own linker that acts like Microsoft's lib trials = [['xilib']] elif is_windows() and compiler.id == 'pgi': # this handles cpp / nvidia HPC, in addition to just c/fortran trials = [['ar']] # For PGI on Windows, "ar" is just a wrapper calling link/lib. @@ -585,7 +585,7 @@ def sanitize(p: T.Optional[str]) -> T.Optional[str]: lnk = linkers.MetrowerksLinkerEmbeddedPowerPC mwcc_ver_match = re.search(r'Version (\d+)\.(\d+)\.?(\d+)? build (\d+)', out) - assert mwcc_ver_match is not None, 'for mypy' # because mypy *should* be complaning that this could be None + assert mwcc_ver_match is not None, 'for mypy' # because mypy *should* be complaining that this could be None compiler_version = '.'.join(x for x in mwcc_ver_match.groups() if x is not None) env.coredata.add_lang_args(cls.language, cls, for_machine, env) @@ -595,7 +595,7 @@ def sanitize(p: T.Optional[str]) -> T.Optional[str]: _, o_ld, _ = Popen_safe(ld + ['--version']) mwld_ver_match = re.search(r'Version (\d+)\.(\d+)\.?(\d+)? build (\d+)', o_ld) - assert mwld_ver_match is not None, 'for mypy' # because mypy *should* be complaning that this could be None + assert mwld_ver_match is not None, 'for mypy' # because mypy *should* be complaining that this could be None linker_version = '.'.join(x for x in mwld_ver_match.groups() if x is not None) linker = lnk(ld, for_machine, version=linker_version) diff --git a/mesonbuild/dependencies/boost.py b/mesonbuild/dependencies/boost.py index 19d492977973..870c0b16b2c3 100644 --- a/mesonbuild/dependencies/boost.py +++ b/mesonbuild/dependencies/boost.py @@ -56,7 +56,7 @@ # Mac / homebrew: libboost_.dylib + libboost_-mt.dylib (location = /usr/local/lib) # Mac / macports: libboost_.dylib + libboost_-mt.dylib (location = /opt/local/lib) # -# Its not clear that any other abi tags (e.g. -gd) are used in official packages. +# It's not clear that any other abi tags (e.g. -gd) are used in official packages. # # On Linux systems, boost libs have multithreading support enabled, but without the -mt tag. # diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 5cff86bb13c3..90c9bb911c5e 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -329,7 +329,7 @@ def detect_cpu_family(compilers: CompilersDict) -> str: """ Python is inconsistent in its platform module. It returns different values for the same cpu. - For x86 it might return 'x86', 'i686' or somesuch. + For x86 it might return 'x86', 'i686' or some such. Do some canonicalization. """ if mesonlib.is_windows(): @@ -466,7 +466,7 @@ def detect_kernel(system: str) -> T.Optional[str]: raise MesonException('Failed to run "/usr/bin/uname -o"') out = out.lower().strip() if out not in {'illumos', 'solaris'}: - mlog.warning(f'Got an unexpected value for kernel on a SunOS derived platform, expcted either "illumos" or "solaris", but got "{out}".' + mlog.warning(f'Got an unexpected value for kernel on a SunOS derived platform, expected either "illumos" or "solaris", but got "{out}".' "Please open a Meson issue with the OS you're running and the value detected for your kernel.") return None return out diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index 9bbab5d60224..eceb40a6bcbe 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -3459,7 +3459,7 @@ def build_target(self, node: mparser.BaseNode, args: T.Tuple[str, SourcesVarargs if kwargs['implib']: if kwargs['export_dynamic'] is False: - FeatureDeprecated.single_use('implib overrides explict export_dynamic off', '1.3.0', self.subproject, + FeatureDeprecated.single_use('implib overrides explicit export_dynamic off', '1.3.0', self.subproject, 'Do not set ths if want export_dynamic disabled if implib is enabled', location=node) kwargs['export_dynamic'] = True diff --git a/mesonbuild/modules/__init__.py b/mesonbuild/modules/__init__.py index 3fe4956c75e5..86dc8762e65a 100644 --- a/mesonbuild/modules/__init__.py +++ b/mesonbuild/modules/__init__.py @@ -113,7 +113,7 @@ def dependency(self, depname: str, native: bool = False, required: bool = True, if wanted: kwargs['version'] = wanted # FIXME: Even if we fix the function, mypy still can't figure out what's - # going on here. And we really dont want to call interpreter + # going on here. And we really don't want to call interpreter # implementations of meson functions anyway. return self._interpreter.func_dependency(self.current_node, [depname], kwargs) # type: ignore diff --git a/mesonbuild/msetup.py b/mesonbuild/msetup.py index 5dfda67056be..81f4af1c444f 100644 --- a/mesonbuild/msetup.py +++ b/mesonbuild/msetup.py @@ -354,7 +354,7 @@ def run(options: T.Union[CMDOptions, T.List[str]]) -> int: coredata.parse_cmd_line_options(options) # Msetup doesn't actually use this option, but we pass msetup options to - # mconf, and it does. We won't actally hit the path that uses it, but don't + # mconf, and it does. We won't actually hit the path that uses it, but don't # lie options.pager = False diff --git a/mesonbuild/options.py b/mesonbuild/options.py index 9f65cc6b7bc9..1566f940c98c 100644 --- a/mesonbuild/options.py +++ b/mesonbuild/options.py @@ -110,7 +110,7 @@ class OptionKey: def __init__(self, name: str, subproject: str = '', machine: MachineChoice = MachineChoice.HOST): # the _type option to the constructor is kinda private. We want to be - # able tos ave the state and avoid the lookup function when + # able to save the state and avoid the lookup function when # pickling/unpickling, but we need to be able to calculate it when # constructing a new OptionKey object.__setattr__(self, 'name', name) diff --git a/test cases/format/5 transform/genexpected.cmd b/test cases/format/5 transform/genexpected.cmd index de3699ddebc7..c273a99c5b84 100644 --- a/test cases/format/5 transform/genexpected.cmd +++ b/test cases/format/5 transform/genexpected.cmd @@ -1,6 +1,6 @@ @echo off REM This script generates the expected files -REM Please double-check the contents of those files before commiting them!!! +REM Please double-check the contents of those files before committing them!!! python ../../../meson.py format -o default.expected.meson source.meson python ../../../meson.py format -c muon.ini -o muon.expected.meson source.meson diff --git a/test cases/rust/5 polyglot static/meson.build b/test cases/rust/5 polyglot static/meson.build index 54f383cd3872..180f86ecb95c 100644 --- a/test cases/rust/5 polyglot static/meson.build +++ b/test cases/rust/5 polyglot static/meson.build @@ -19,7 +19,7 @@ e = executable('prog', 'prog.c', test('polyglottest', e) # Create a version that has overflow-checks on, then run a test to ensure that -# the overflow-checks is larger than the other version by some ammount +# the overflow-checks is larger than the other version by some amount r2 = static_library('stuff2', 'stuff.rs', rust_crate_type : 'staticlib', rust_args : ['-C', 'overflow-checks=on']) l2 = static_library('clib2', 'clib.c') e2 = executable('prog2', 'prog.c', link_with : [r2, l2]) diff --git a/test cases/rust/9 unit tests/test3.rs b/test cases/rust/9 unit tests/test3.rs index 6d538a059ff1..72349a63cd66 100644 --- a/test cases/rust/9 unit tests/test3.rs +++ b/test cases/rust/9 unit tests/test3.rs @@ -8,7 +8,7 @@ mod tests { use super::*; - // This is an intentinally broken test that should be turned off by extra rust arguments + // This is an intentionally broken test that should be turned off by extra rust arguments #[cfg(not(broken = "false"))] #[test] fn test_broken() { diff --git a/unittests/baseplatformtests.py b/unittests/baseplatformtests.py index 72ebeafe7ead..3770321925fa 100644 --- a/unittests/baseplatformtests.py +++ b/unittests/baseplatformtests.py @@ -496,13 +496,13 @@ def copy_srcdir(self, srcdir: str) -> str: ensures that the copied tree is deleted after running. - :param srcdir: The locaiton of the source tree to copy + :param srcdir: The location of the source tree to copy :return: The location of the copy """ dest = tempfile.mkdtemp() self.addCleanup(windows_proof_rmtree, dest) - # shutil.copytree expects the destinatin directory to not exist, Once + # shutil.copytree expects the destination directory to not exist, Once # python 3.8 is required the `dirs_exist_ok` parameter negates the need # for this dest = os.path.join(dest, 'subdir') diff --git a/unittests/internaltests.py b/unittests/internaltests.py index fa0e440d3583..310b4f680bad 100644 --- a/unittests/internaltests.py +++ b/unittests/internaltests.py @@ -1348,8 +1348,8 @@ def _(obj, node, args: T.Tuple, kwargs: T.Dict[str, T.List[str]]) -> None: def test_typed_kwarg_since(self) -> None: @typed_kwargs( 'testfunc', - KwargInfo('input', str, since='1.0', since_message='Its awesome, use it', - deprecated='2.0', deprecated_message='Its terrible, dont use it') + KwargInfo('input', str, since='1.0', since_message='It\'s awesome, use it', + deprecated='2.0', deprecated_message='It\'s terrible, don\'t use it') ) def _(obj, node, args: T.Tuple, kwargs: T.Dict[str, str]) -> None: self.assertIsInstance(kwargs['input'], str) @@ -1360,8 +1360,8 @@ def _(obj, node, args: T.Tuple, kwargs: T.Dict[str, str]) -> None: mock.patch('mesonbuild.mesonlib.project_meson_versions', {'': '0.1'}): # With Meson 0.1 it should trigger the "introduced" warning but not the "deprecated" warning _(None, mock.Mock(subproject=''), [], {'input': 'foo'}) - self.assertRegex(out.getvalue(), r'WARNING:.*introduced.*input arg in testfunc. Its awesome, use it') - self.assertNotRegex(out.getvalue(), r'WARNING:.*deprecated.*input arg in testfunc. Its terrible, dont use it') + self.assertRegex(out.getvalue(), r'WARNING:.*introduced.*input arg in testfunc. It\'s awesome, use it') + self.assertNotRegex(out.getvalue(), r'WARNING:.*deprecated.*input arg in testfunc. It\'s terrible, don\'t use it') with self.subTest('no warnings should be triggered'), \ mock.patch('sys.stdout', io.StringIO()) as out, \ @@ -1375,8 +1375,8 @@ def _(obj, node, args: T.Tuple, kwargs: T.Dict[str, str]) -> None: mock.patch('mesonbuild.mesonlib.project_meson_versions', {'': '2.0'}): # With Meson 2.0 it should trigger the "deprecated" warning but not the "introduced" warning _(None, mock.Mock(subproject=''), [], {'input': 'foo'}) - self.assertRegex(out.getvalue(), r'WARNING:.*deprecated.*input arg in testfunc. Its terrible, dont use it') - self.assertNotRegex(out.getvalue(), r'WARNING:.*introduced.*input arg in testfunc. Its awesome, use it') + self.assertRegex(out.getvalue(), r'WARNING:.*deprecated.*input arg in testfunc. It\'s terrible, don\'t use it') + self.assertNotRegex(out.getvalue(), r'WARNING:.*introduced.*input arg in testfunc. It\'s awesome, use it') def test_typed_kwarg_validator(self) -> None: @typed_kwargs( @@ -1408,7 +1408,7 @@ def test_typed_kwarg_since_values(self) -> None: @typed_kwargs( 'testfunc', KwargInfo('input', ContainerTypeInfo(list, str), listify=True, default=[], deprecated_values={'foo': '0.9'}, since_values={'bar': '1.1'}), - KwargInfo('output', ContainerTypeInfo(dict, str), default={}, deprecated_values={'foo': '0.9', 'foo2': ('0.9', 'dont use it')}, since_values={'bar': '1.1', 'bar2': ('1.1', 'use this')}), + KwargInfo('output', ContainerTypeInfo(dict, str), default={}, deprecated_values={'foo': '0.9', 'foo2': ('0.9', 'don\'t use it')}, since_values={'bar': '1.1', 'bar2': ('1.1', 'use this')}), KwargInfo('install_dir', (bool, str, NoneType), deprecated_values={False: '0.9'}), KwargInfo( 'mode', @@ -1443,7 +1443,7 @@ def _(obj, node, args: T.Tuple, kwargs: T.Dict[str, str]) -> None: with self.subTest('deprecated dict string value with msg'), mock.patch('sys.stdout', io.StringIO()) as out: _(None, mock.Mock(subproject=''), [], {'output': {'foo2': 'a'}}) - self.assertRegex(out.getvalue(), r"""WARNING:.Project targets '1.0'.*deprecated since '0.9': "testfunc" keyword argument "output" value "foo2" in dict keys. dont use it.*""") + self.assertRegex(out.getvalue(), r"""WARNING:.Project targets '1.0'.*deprecated since '0.9': "testfunc" keyword argument "output" value "foo2" in dict keys. don't use it.*""") with self.subTest('new dict string value'), mock.patch('sys.stdout', io.StringIO()) as out: _(None, mock.Mock(subproject=''), [], {'output': {'bar': 'b'}}) diff --git a/unittests/machinefiletests.py b/unittests/machinefiletests.py index 8de0c602da5c..ba9cb11530dd 100644 --- a/unittests/machinefiletests.py +++ b/unittests/machinefiletests.py @@ -330,7 +330,7 @@ def cb(comp): elif comp.id == 'gcc': if shutil.which('ifort'): # There is an ICC for windows (windows build, linux host), - # but we don't support that ATM so lets not worry about it. + # but we don't support that ATM so let's not worry about it. if is_windows(): return 'ifort', 'intel-cl' return 'ifort', 'intel' @@ -634,7 +634,7 @@ def test_bindgen_clang_arguments(self) -> None: testcase = os.path.join(self.rust_test_dir, '12 bindgen') config = self.helper_create_native_file({ - 'properties': {'bindgen_clang_arguments': 'sentinal'} + 'properties': {'bindgen_clang_arguments': 'sentinel'} }) self.init(testcase, extra_args=['--native-file', config]) @@ -642,10 +642,10 @@ def test_bindgen_clang_arguments(self) -> None: for t in targets: if t['id'].startswith('rustmod-bindgen'): args: T.List[str] = t['target_sources'][0]['compiler'] - self.assertIn('sentinal', args, msg="Did not find machine file value") + self.assertIn('sentinel', args, msg="Did not find machine file value") cargs_start = args.index('--') - sent_arg = args.index('sentinal') - self.assertLess(cargs_start, sent_arg, msg='sentinal argument does not come after "--"') + sent_arg = args.index('sentinel') + self.assertLess(cargs_start, sent_arg, msg='sentinel argument does not come after "--"') break else: self.fail('Did not find a bindgen target') From 9c6881f0e22f15ae2bdae113c1249b19843bcc6d Mon Sep 17 00:00:00 2001 From: Sam James Date: Thu, 12 Sep 2024 02:46:04 +0100 Subject: [PATCH 174/302] ci: gentoo: install dev-qt/qttools Qt 6 now has stable keywords (and has for a while). Recent stabilisation of Plasma 6 now pulls in Qt 6 in the image builder so frameworks: 4 qt fails as qttools is missing. Signed-off-by: Sam James --- ci/ciimage/gentoo/install.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ci/ciimage/gentoo/install.sh b/ci/ciimage/gentoo/install.sh index 5a8f680700a3..caf21a1fad69 100755 --- a/ci/ciimage/gentoo/install.sh +++ b/ci/ciimage/gentoo/install.sh @@ -40,8 +40,7 @@ pkgs_stable=( sci-libs/hdf5 dev-qt/linguist-tools sys-devel/llvm - # qt6 unstable - #dev-qt/qttools + dev-qt/qttools # misc app-admin/sudo From bb2adc06c0dfde48d1bdccbaa4b3f7782a017f60 Mon Sep 17 00:00:00 2001 From: spaette <111918424+spaette@users.noreply.github.com> Date: Thu, 12 Sep 2024 09:32:02 -0500 Subject: [PATCH 175/302] add epiphany --- docs/markdown/Users.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/markdown/Users.md b/docs/markdown/Users.md index 70060ab05247..0b1de42f4daa 100644 --- a/docs/markdown/Users.md +++ b/docs/markdown/Users.md @@ -62,6 +62,7 @@ topic](https://github.com/topics/meson). - [GNOME Software](https://gitlab.gnome.org/GNOME/gnome-software), an app store for GNOME - [GNOME Twitch](https://github.com/vinszent/gnome-twitch), an app for viewing Twitch streams on GNOME desktop - [GNOME Usage](https://gitlab.gnome.org/GNOME/gnome-usage), a GNOME application for visualizing system resources + - [GNOME Web](https://gitlab.gnome.org/GNOME/epiphany), a browser for a simple, clean, beautiful view of the web - [GNU FriBidi](https://github.com/fribidi/fribidi), the open source implementation of the Unicode Bidirectional Algorithm - [Graphene](https://ebassi.github.io/graphene/), a thin type library for graphics - [Grilo](https://git.gnome.org/browse/grilo) and [Grilo plugins](https://git.gnome.org/browse/grilo-plugins), the Grilo multimedia framework From 188869724ab76e1d573744395a55a910d95f8886 Mon Sep 17 00:00:00 2001 From: Andrei Horodniceanu Date: Tue, 3 Sep 2024 23:14:58 +0300 Subject: [PATCH 176/302] ci/run.ps1: Clean up D related code Bump the version of the cidata archive and remove the code that tries to setup dmd and the dub packages from run.ps1 as it doesn't work as expected (builds for x86 instead of x86_64) and cidata should already take care of them. Signed-off-by: Andrei Horodniceanu --- ci/run.ps1 | 40 +--------------------------------------- 1 file changed, 1 insertion(+), 39 deletions(-) diff --git a/ci/run.ps1 b/ci/run.ps1 index 3fc06fdaf1b1..d3fda2d8b70e 100644 --- a/ci/run.ps1 +++ b/ci/run.ps1 @@ -50,7 +50,7 @@ function DownloadFile([String] $Source, [String] $Destination) { if (($env:backend -eq 'ninja') -and ($env:arch -ne 'arm64')) { $dmd = $true } else { $dmd = $false } -DownloadFile -Source https://github.com/mesonbuild/cidata/releases/download/ci4/ci_data.zip -Destination $env:AGENT_WORKFOLDER\ci_data.zip +DownloadFile -Source https://github.com/mesonbuild/cidata/releases/download/ci5/ci_data.zip -Destination $env:AGENT_WORKFOLDER\ci_data.zip echo "Extracting ci_data.zip" Expand-Archive $env:AGENT_WORKFOLDER\ci_data.zip -DestinationPath $env:AGENT_WORKFOLDER\ci_data & "$env:AGENT_WORKFOLDER\ci_data\install.ps1" -Arch $env:arch -Compiler $env:compiler -Boost $true -DMD $dmd @@ -87,44 +87,6 @@ if ($env:backend -eq 'ninja') { MSBuild /version } -# This mirrors the D logic in cidata/build_win32.sh -if ($dmd) { - if ($Arch -eq "x64") { - $dmdArch = "x86_64" - } else { - $dmdArch = "x86_mscoff" - } - - $ScriptDir = Split-Path $script:MyInvocation.MyCommand.Path - $env:Path = "$ScriptDir;$env:Path" - $dmd_bin = Join-Path $ScriptDir "dmd2\windows\bin" - $env:Path = $env:Path + ";" + $dmd_bin - - $i = 1 - while ($i -le 5) { - # Needed for d/11 dub to use the 'urld' library - dub run --yes dub-build-deep -- urld --arch=$dmdArch --compiler=dmd --build=debug - if ($LastExitCode -eq 0) { - break - } - - $i = $i + 1 - Start-Sleep -Seconds 2 - } - - $i = 1 - while ($i -le 5) { - # XXX: Sometimes (?) we need this older version when the whole testsuite is run - dub run --yes dub-build-deep -- urld@2.1.1 --arch=$dmdArch --compiler=dmd --build=debug - if ($LastExitCode -eq 0) { - break - } - - $i = $i + 1 - Start-Sleep -Seconds 2 - } -} - echo "" echo "Python version:" python --version From 781335446064b0f6dcee3c22975dd9f575932a74 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Mon, 26 Aug 2024 12:31:14 -0700 Subject: [PATCH 177/302] cmake: actually print the cycle in the error message --- mesonbuild/cmake/interpreter.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mesonbuild/cmake/interpreter.py b/mesonbuild/cmake/interpreter.py index 683991c5462e..fafee86abd4f 100644 --- a/mesonbuild/cmake/interpreter.py +++ b/mesonbuild/cmake/interpreter.py @@ -1060,7 +1060,9 @@ def extract_tgt(tgt: T.Union[ConverterTarget, ConverterCustomTarget, CustomTarge def detect_cycle(tgt: T.Union[ConverterTarget, ConverterCustomTarget]) -> None: if tgt.name in processing: - raise CMakeException('Cycle in CMake inputs/dependencies detected') + processing.append(tgt.name) + stack = ' -> '.join(processing) + raise CMakeException(f'Cycle in CMake inputs/dependencies detected: {stack}') processing.append(tgt.name) def resolve_ctgt_ref(ref: CustomTargetReference) -> T.Union[IdNode, IndexNode]: From 050b788ed8065901e57f7422a42921bc40ebac8f Mon Sep 17 00:00:00 2001 From: Andrew McNulty Date: Sat, 14 Sep 2024 13:13:13 +0200 Subject: [PATCH 178/302] Fix various incorrect uses of `its` vs `it's`. These errors can make reading comments and documentation unnecessarily confusing for users and contributors who do not speak English as their first language. --- docs/markdown/Qt6-module.md | 4 ++-- mesonbuild/backend/xcodebackend.py | 2 +- mesonbuild/compilers/detect.py | 4 ++-- mesonbuild/dependencies/base.py | 6 +++--- mesonbuild/dependencies/configtool.py | 2 +- mesonbuild/interpreter/kwargs.py | 2 +- mesonbuild/mconf.py | 2 +- mesonbuild/modules/rust.py | 4 ++-- mesonbuild/programs.py | 2 +- 9 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/markdown/Qt6-module.md b/docs/markdown/Qt6-module.md index 0a453dd41443..673b4999630d 100644 --- a/docs/markdown/Qt6-module.md +++ b/docs/markdown/Qt6-module.md @@ -20,7 +20,7 @@ Compiles Qt's resources collection files (.qrc) into c++ files for compilation. It takes no positional arguments, and the following keyword arguments: - `name` (string | empty): if provided a single .cpp file will be generated, and the output of all qrc files will be combined in this file, otherwise - each qrc file be written to it's own cpp file. + each qrc file be written to its own cpp file. - `sources` (File | string | custom_target | custom_target index | generator_output)[]: A list of sources to be transpiled. Required, must have at least one source
*New in 0.60.0*: support for custom_target, custom_target_index, and generator_output. @@ -111,7 +111,7 @@ This method takes the following keyword arguments: directory. For instance, when a file called `subdir/one.input` is processed it generates a file `{target private directory}/subdir/one.out` when `true`, and `{target private directory}/one.out` when `false` (default). - + It returns an array of targets and sources to pass to a compilation target. ## compile_translations diff --git a/mesonbuild/backend/xcodebackend.py b/mesonbuild/backend/xcodebackend.py index e1e8c58542c8..fc490c1b5d35 100644 --- a/mesonbuild/backend/xcodebackend.py +++ b/mesonbuild/backend/xcodebackend.py @@ -423,7 +423,7 @@ def generate_build_phase_map(self) -> None: # generate id for our own target-name t.buildphasemap = {} t.buildphasemap[tname] = self.gen_id() - # each target can have it's own Frameworks/Sources/..., generate id's for those + # each target can have its own Frameworks/Sources/..., generate id's for those t.buildphasemap['Frameworks'] = self.gen_id() t.buildphasemap['Resources'] = self.gen_id() t.buildphasemap['Sources'] = self.gen_id() diff --git a/mesonbuild/compilers/detect.py b/mesonbuild/compilers/detect.py index c1d004b32169..41ecf25288a7 100644 --- a/mesonbuild/compilers/detect.py +++ b/mesonbuild/compilers/detect.py @@ -280,7 +280,7 @@ def _detect_c_or_cpp_compiler(env: 'Environment', lang: str, for_machine: Machin compiler_name = os.path.basename(compiler[0]) if any(os.path.basename(x) in {'cl', 'cl.exe', 'clang-cl', 'clang-cl.exe'} for x in compiler): - # Watcom C provides it's own cl.exe clone that mimics an older + # Watcom C provides its own cl.exe clone that mimics an older # version of Microsoft's compiler. Since Watcom's cl.exe is # just a wrapper, we skip using it if we detect its presence # so as not to confuse Meson when configuring for MSVC. @@ -1026,7 +1026,7 @@ def detect_rust_compiler(env: 'Environment', for_machine: MachineChoice) -> Rust version = search_version(out) cls: T.Type[RustCompiler] = rust.RustCompiler - # Clippy is a wrapper around rustc, but it doesn't have rustc in it's + # Clippy is a wrapper around rustc, but it doesn't have rustc in its # output. We can otherwise treat it as rustc. if 'clippy' in out: # clippy returns its own version and not the rustc version by diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 03b2596e1582..4803e6dce5c9 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -157,7 +157,7 @@ def get_compile_args(self) -> T.List[str]: return self.compile_args def get_all_compile_args(self) -> T.List[str]: - """Get the compile arguments from this dependency and it's sub dependencies.""" + """Get the compile arguments from this dependency and its sub dependencies.""" return list(itertools.chain(self.get_compile_args(), *(d.get_all_compile_args() for d in self.ext_deps))) @@ -167,7 +167,7 @@ def get_link_args(self, language: T.Optional[str] = None, raw: bool = False) -> return self.link_args def get_all_link_args(self) -> T.List[str]: - """Get the link arguments from this dependency and it's sub dependencies.""" + """Get the link arguments from this dependency and its sub dependencies.""" return list(itertools.chain(self.get_link_args(), *(d.get_all_link_args() for d in self.ext_deps))) @@ -213,7 +213,7 @@ def get_partial_dependency(self, *, compile_args: bool = False, compile_args -- any compile args link_args -- any link args - Additionally the new dependency will have the version parameter of it's + Additionally the new dependency will have the version parameter of its parent (if any) and the requested values of any dependencies will be added as well. """ diff --git a/mesonbuild/dependencies/configtool.py b/mesonbuild/dependencies/configtool.py index 679c69f5d9be..f49c16d4a307 100644 --- a/mesonbuild/dependencies/configtool.py +++ b/mesonbuild/dependencies/configtool.py @@ -22,7 +22,7 @@ class ConfigToolDependency(ExternalDependency): Takes the following extra keys in kwargs that it uses internally: :tools List[str]: A list of tool names to use - :version_arg str: The argument to pass to the tool to get it's version + :version_arg str: The argument to pass to the tool to get its version :skip_version str: The argument to pass to the tool to ignore its version (if ``version_arg`` fails, but it may start accepting it in the future) Because some tools are stupid and don't accept --version diff --git a/mesonbuild/interpreter/kwargs.py b/mesonbuild/interpreter/kwargs.py index eee53c5ff413..25c40a0d4438 100644 --- a/mesonbuild/interpreter/kwargs.py +++ b/mesonbuild/interpreter/kwargs.py @@ -71,7 +71,7 @@ class ExtractRequired(TypedDict): """Keyword Arguments consumed by the `extract_required_kwargs` function. Any function that uses the `required` keyword argument which accepts either - a boolean or a feature option should inherit it's arguments from this class. + a boolean or a feature option should inherit its arguments from this class. """ required: T.Union[bool, options.UserFeatureOption] diff --git a/mesonbuild/mconf.py b/mesonbuild/mconf.py index 6cb64e1c428d..3a6343ba1233 100644 --- a/mesonbuild/mconf.py +++ b/mesonbuild/mconf.py @@ -141,7 +141,7 @@ def print_aligned(self) -> None: This prints the generated output in an aligned, pretty form. it aims for a total width of 160 characters, but will use whatever the tty - reports it's value to be. Though this is much wider than the standard + reports its value to be. Though this is much wider than the standard 80 characters of terminals, and even than the newer 120, compressing it to those lengths makes the output hard to read. diff --git a/mesonbuild/modules/rust.py b/mesonbuild/modules/rust.py index 2e5f16f3c459..1368c4c1970f 100644 --- a/mesonbuild/modules/rust.py +++ b/mesonbuild/modules/rust.py @@ -86,7 +86,7 @@ def __init__(self, interpreter: Interpreter) -> None: def test(self, state: ModuleState, args: T.Tuple[str, BuildTarget], kwargs: FuncTest) -> ModuleReturnValue: """Generate a rust test target from a given rust target. - Rust puts it's unitests inside it's main source files, unlike most + Rust puts its unitests inside its main source files, unlike most languages that put them in external files. This means that normally you have to define two separate targets with basically the same arguments to get tests: @@ -207,7 +207,7 @@ def test(self, state: ModuleState, args: T.Tuple[str, BuildTarget], kwargs: Func DEPENDENCIES_KW.evolve(since='1.0.0'), ) def bindgen(self, state: ModuleState, args: T.List, kwargs: FuncBindgen) -> ModuleReturnValue: - """Wrapper around bindgen to simplify it's use. + """Wrapper around bindgen to simplify its use. The main thing this simplifies is the use of `include_directory` objects, instead of having to pass a plethora of `-I` arguments. diff --git a/mesonbuild/programs.py b/mesonbuild/programs.py index fbe241d99607..8f7d1c36c3f3 100644 --- a/mesonbuild/programs.py +++ b/mesonbuild/programs.py @@ -119,7 +119,7 @@ def get_version(self, interpreter: T.Optional['Interpreter'] = None) -> str: @classmethod def from_bin_list(cls, env: 'Environment', for_machine: MachineChoice, name: str) -> 'ExternalProgram': # There is a static `for_machine` for this class because the binary - # always runs on the build platform. (It's host platform is our build + # always runs on the build platform. (Its host platform is our build # platform.) But some external programs have a target platform, so this # is what we are specifying here. command = env.lookup_binary_entry(for_machine, name) From 74dd77ed81c90e3655b3dff5bfe98410a85dd4f0 Mon Sep 17 00:00:00 2001 From: Andrew McNulty Date: Sat, 7 Sep 2024 13:19:01 +0100 Subject: [PATCH 179/302] Prevent raw exception during project() If a user imports a module and invokes a method on it, a raw Python exception is raised to the user. This commit adds a check to ensure that in this case an appropriate exception is raised instead. A test has been added to ensure that this exception is in fact raised on offending code. Fixes: #11393, #5134 --- mesonbuild/interpreter/interpreterobjects.py | 6 +++++- .../failing/132 module use inside project decl/meson.build | 6 ++++++ .../failing/132 module use inside project decl/test.json | 7 +++++++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 test cases/failing/132 module use inside project decl/meson.build create mode 100644 test cases/failing/132 module use inside project decl/test.json diff --git a/mesonbuild/interpreter/interpreterobjects.py b/mesonbuild/interpreter/interpreterobjects.py index 2cd55321bfcb..1d602828587f 100644 --- a/mesonbuild/interpreter/interpreterobjects.py +++ b/mesonbuild/interpreter/interpreterobjects.py @@ -12,7 +12,7 @@ from .. import build from .. import mlog -from ..modules import ModuleReturnValue, ModuleObject, ModuleState, ExtensionModule +from ..modules import ModuleReturnValue, ModuleObject, ModuleState, ExtensionModule, NewExtensionModule from ..backend.backends import TestProtocol from ..interpreterbase import ( ContainerTypeInfo, KwargInfo, MesonOperator, @@ -872,6 +872,10 @@ def method_call(self, method_name: str, args: T.List[TYPE_var], kwargs: TYPE_kwa args = flatten(args) if not getattr(method, 'no-second-level-holder-flattening', False): args, kwargs = resolve_second_level_holders(args, kwargs) + if not self.interpreter.active_projectname: + assert isinstance(modobj, (ExtensionModule, NewExtensionModule)), 'for mypy' + full_method_name = f'{modobj.INFO.name}.{method_name}' + raise mesonlib.MesonException(f'Module methods ({full_method_name}) cannot be invoked during project declaration.') state = ModuleState(self.interpreter) # Many modules do for example self.interpreter.find_program_impl(), # so we have to ensure they use the current interpreter and not the one diff --git a/test cases/failing/132 module use inside project decl/meson.build b/test cases/failing/132 module use inside project decl/meson.build new file mode 100644 index 000000000000..8f82a5d3089b --- /dev/null +++ b/test cases/failing/132 module use inside project decl/meson.build @@ -0,0 +1,6 @@ +# GH issue 11393 +project('module use inside project decl', 'c', + version: run_command( + import('python').find_installation('python3') + ) +) diff --git a/test cases/failing/132 module use inside project decl/test.json b/test cases/failing/132 module use inside project decl/test.json new file mode 100644 index 000000000000..33e377b842f3 --- /dev/null +++ b/test cases/failing/132 module use inside project decl/test.json @@ -0,0 +1,7 @@ +{ + "stdout": [ + { + "line": "test cases/failing/132 module use inside project decl/meson.build:4:21: ERROR: Module methods (python.find_installation) cannot be invoked during project declaration." + } + ] + } From 2b80d4cca174916a4b6d0c47c54ad56795741bb6 Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Wed, 24 Jan 2024 22:16:49 -0500 Subject: [PATCH 180/302] When configuring fails in Github Actions, print folded logs A common, and challenging, issue in CI runners is debugging issues when you know the information you want to check, but it's in the log file which you don't have because remote CI machines. There are various edge cases where this is especially hard to solve, such as inside of `pip install` where the build directory with the log file is automatically cleaned up. But it's never really *easy* when you don't expect it, and the best case scenario is your iteration time gets cut in half as you hurriedly go add some `cat`s to your CI scripts. Meson can, at least sometimes, detect platforms where text can be emitted inside of "folds", which are auto-collapsed and don't obscure the general output, but when clicked will expand the logfile contents. Hook this up. We start off with a Github Actions implementation. We had some internal code used by our own project tests runner, which can be utilized. Also permit forcing it via an environment variable, in case autodetection fails and you just want to force *something*, especially when meson is called a couple layers deep inside some other tool. --- mesonbuild/mesonmain.py | 3 +++ mesonbuild/mlog.py | 31 ++++++++++++++++++++++++++++++- run_project_tests.py | 11 +++-------- 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py index c486dd846cb9..faa0f426d82a 100644 --- a/mesonbuild/mesonmain.py +++ b/mesonbuild/mesonmain.py @@ -27,6 +27,9 @@ def errorhandler(e: Exception, command: str) -> int: logfile = mlog.shutdown() if logfile is not None: mlog.log("\nA full log can be found at", mlog.bold(logfile)) + contents = mlog.ci_fold_file(logfile, f'CI platform detected, click here for {os.path.basename(logfile)} contents.') + if contents: + print(contents) if os.environ.get('MESON_FORCE_BACKTRACE'): raise e return 1 diff --git a/mesonbuild/mlog.py b/mesonbuild/mlog.py index a8b0185371d1..bc8faeba7d06 100644 --- a/mesonbuild/mlog.py +++ b/mesonbuild/mlog.py @@ -22,8 +22,9 @@ from pathlib import Path if T.TYPE_CHECKING: - from ._typing import StringProtocol, SizedStringProtocol + from typing_extensions import Literal + from ._typing import StringProtocol, SizedStringProtocol from .mparser import BaseNode TV_Loggable = T.Union[str, 'AnsiDecorator', StringProtocol] @@ -75,6 +76,7 @@ def setup_console() -> None: pass _in_ci = 'CI' in os.environ +_ci_is_github = 'GITHUB_ACTIONS' in os.environ class _Severity(enum.Enum): @@ -540,3 +542,30 @@ def code_line(text: str, line: str, colno: int) -> str: :return: A formatted string of the text, line, and a caret """ return f'{text}\n{line}\n{" " * colno}^' + +@T.overload +def ci_fold_file(fname: T.Union[str, os.PathLike], banner: str, force: Literal[True] = True) -> str: ... + +@T.overload +def ci_fold_file(fname: T.Union[str, os.PathLike], banner: str, force: Literal[False] = False) -> T.Optional[str]: ... + +def ci_fold_file(fname: T.Union[str, os.PathLike], banner: str, force: bool = False) -> T.Optional[str]: + if not _in_ci and not force: + return None + + if _ci_is_github: + header = f'::group::==== {banner} ====' + footer = '::endgroup::' + elif force: + header = banner + footer = '' + elif 'MESON_FORCE_SHOW_LOGS' in os.environ: + header = f'==== Forcing display of logs for {os.path.basename(fname)} ====' + footer = '' + else: + # only github is implemented + return None + + with open(fname, 'r', encoding='utf-8') as f: + data = f.read() + return f'{header}\n{data}\n{footer}\n' diff --git a/run_project_tests.py b/run_project_tests.py index fe1f46f7eefa..831b947ccca4 100755 --- a/run_project_tests.py +++ b/run_project_tests.py @@ -306,7 +306,6 @@ def __lt__(self, other: object) -> bool: failing_logs: T.List[str] = [] print_debug = 'MESON_PRINT_TEST_OUTPUT' in os.environ under_ci = 'CI' in os.environ -ci_is_github = 'GITHUB_ACTIONS' in os.environ raw_ci_jobname = os.environ.get('MESON_CI_JOBNAME', None) ci_jobname = raw_ci_jobname if raw_ci_jobname != 'thirdparty' else None do_debug = under_ci or print_debug @@ -438,16 +437,12 @@ def log_text_file(logfile: T.TextIO, testdir: Path, result: TestResult) -> None: def _run_ci_include(args: T.List[str]) -> str: - header = f'Included file {args[0]}:' - footer = '' - if ci_is_github: - header = f'::group::==== {header} ====' - footer = '::endgroup::' if not args: return 'At least one parameter required' + + header = f'Included file {args[0]}:' try: - data = Path(args[0]).read_text(errors='ignore', encoding='utf-8') - return f'{header}\n{data}\n{footer}\n' + return mlog.ci_fold_file(args[0], header, force=True) except Exception: return 'Failed to open {}\n'.format(args[0]) From 9cb9ad88da3e837086753af03813b1f173a6d831 Mon Sep 17 00:00:00 2001 From: Andrew McNulty Date: Tue, 17 Sep 2024 00:28:34 +0100 Subject: [PATCH 181/302] compilers: Pass mode to determine_args, not its string value We always pass the string value of the mode to determine_args, which causes the check on the mode argument inside determine_args to always evaluate to false. Fix this by passing the mode itself, not its value. --- mesonbuild/compilers/mixins/clike.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/compilers/mixins/clike.py b/mesonbuild/compilers/mixins/clike.py index e982ca023e41..f0515a9bdcb4 100644 --- a/mesonbuild/compilers/mixins/clike.py +++ b/mesonbuild/compilers/mixins/clike.py @@ -417,7 +417,7 @@ def build_wrapper_args(self, env: 'Environment', else: # TODO: we want to do this in the caller extra_args = mesonlib.listify(extra_args) - extra_args = mesonlib.listify([e(mode.value) if callable(e) else e for e in extra_args]) + extra_args = mesonlib.listify([e(mode) if callable(e) else e for e in extra_args]) if dependencies is None: dependencies = [] From 81c50885689488d701ec442d08234b442e975d78 Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Mon, 2 Sep 2024 15:40:28 -0400 Subject: [PATCH 182/302] mdist: detect pathological git repo cases and show a slightly better error When `meson dist` fails with the error: ``` Dist currently only works with Git or Mercurial repos ``` It is sometimes inaccurate, since a git repo may exist but be nonfunctional. Offer some better guidance in that case. Fixes: #10866 --- mesonbuild/mdist.py | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/mesonbuild/mdist.py b/mesonbuild/mdist.py index 05c23f53fe46..01b40dfd720d 100644 --- a/mesonbuild/mdist.py +++ b/mesonbuild/mdist.py @@ -22,7 +22,7 @@ from glob import glob from pathlib import Path from mesonbuild.environment import Environment, detect_ninja -from mesonbuild.mesonlib import (MesonException, RealPathAction, get_meson_command, quiet_git, +from mesonbuild.mesonlib import (GIT, MesonException, RealPathAction, get_meson_command, quiet_git, windows_proof_rmtree, setup_vsenv) from .options import OptionKey from mesonbuild.msetup import add_arguments as msetup_argparse @@ -80,7 +80,36 @@ def is_git(src_root: str) -> bool: Checks if meson.build file at the root source directory is tracked by git. It could be a subproject part of the parent project git repository. ''' - return quiet_git(['ls-files', '--error-unmatch', 'meson.build'], src_root)[0] + if quiet_git(['ls-files', '--error-unmatch', 'meson.build'], src_root)[0]: + return True + + if os.path.exists(os.path.join(src_root, '.git')): + msg = 'Source tree looks like it may be a git repo, ' + if not GIT: + msg += 'but git is not installed!' + if 'GITLAB_CI' in os.environ: + msg += ' This is a gitlab bug.' + else: + msg += 'but git returned a failure. ' + p, oe = quiet_git(['status'], src_root) + if 'dubious ownership' in oe: + # For a few years now, git has absolved itself of the responsibility to implement + # robust, safe software. Instead of detecting the signs of a problematic scenario, + # they have chosen to consider many legitimate and reasonable use cases as "dangerous", + # and implemented the number one threat to security worldwide: alert fatigue. Having + # done so, they then washed their hands of the matter and permanently tabled the + # notion of adding fine-grained detection. This is not just useless, it is *worse* + # than useless. + # + # In our case, the error is triply meaningless since we are already executing build + # system commands from the same directory. Either way, reject the notion that git is + # well designed or that its error messaging is a valid approach to the problem space. + msg += 'This is a bug in git itself, please set `git config --global safe.directory "*"`' + else: + msg += 'meson.build may not have been committed to git?' + mlog.warning(msg) + return False + def is_hg(src_root: str) -> bool: return os.path.isdir(os.path.join(src_root, '.hg')) From e5d03f5e138173b03ad2b0223bbcb8f436cb3bf1 Mon Sep 17 00:00:00 2001 From: Junjie Mao Date: Thu, 19 Sep 2024 08:29:59 +0800 Subject: [PATCH 183/302] backend/ninja: Generate sysroot in rust-project.json Rust-analyzer relies on sysroot to discover its proc-macro server [1] which is typically installed at /libexec/rust-analyzer-proc-macro-srv. When used with rust-project.json, rust-analyzer expects the json file to specify sysroot and fails to launch the proc-macro server otherwise. So add sysroot to the meson-generated rust-project.json and point it to the sysroot of the detected rustc compiler. [1] https://github.com/rust-lang/rust-analyzer/blob/2024-09-16/crates/project-model/src/sysroot.rs#L175 Signed-off-by: Junjie Mao --- mesonbuild/backend/ninjabackend.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 91603025ba92..d8995f031eea 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -707,10 +707,11 @@ def generate_rust_project_json(self) -> None: return with open(os.path.join(self.environment.get_build_dir(), 'rust-project.json'), 'w', encoding='utf-8') as f: + sysroot = self.environment.coredata.compilers.host['rust'].get_sysroot() json.dump( { - "sysroot_src": os.path.join(self.environment.coredata.compilers.host['rust'].get_sysroot(), - 'lib/rustlib/src/rust/library/'), + "sysroot": sysroot, + "sysroot_src": os.path.join(sysroot, 'lib/rustlib/src/rust/library/'), "crates": [c.to_json() for c in self.rust_crates.values()], }, f, indent=4) From 19f9369b4cedab072eb7516e738a505ad635aca8 Mon Sep 17 00:00:00 2001 From: spaette Date: Fri, 13 Sep 2024 14:39:53 -0500 Subject: [PATCH 184/302] Fix typos --- docs/markdown/Release-notes-for-1.3.0.md | 4 ++-- docs/markdown/Subprojects.md | 2 +- docs/markdown/Wrap-dependency-system-manual.md | 2 +- test cases/unit/121 executable suffix/meson.build | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/markdown/Release-notes-for-1.3.0.md b/docs/markdown/Release-notes-for-1.3.0.md index 1a1d048989ff..0c7660f230ca 100644 --- a/docs/markdown/Release-notes-for-1.3.0.md +++ b/docs/markdown/Release-notes-for-1.3.0.md @@ -89,8 +89,8 @@ you to set the environment in which the generator will process inputs. In previous versions of meson, a `meson.build` file like this: ``` -exectuable('foo', 'main.c') -exectuable('foo', 'main.c', name_suffix: 'bar') +executable('foo', 'main.c') +executable('foo', 'main.c', name_suffix: 'bar') ``` would result in a configure error because meson internally used diff --git a/docs/markdown/Subprojects.md b/docs/markdown/Subprojects.md index 78239b9fc4d4..0375b5698160 100644 --- a/docs/markdown/Subprojects.md +++ b/docs/markdown/Subprojects.md @@ -300,7 +300,7 @@ types. Multiple types can be set as comma separated list e.g. `--types git,file`. *Since 0.56.0* If the subcommand fails on any subproject an error code -is returned at the end instead of retuning success. +is returned at the end instead of returning success. ### Download subprojects diff --git a/docs/markdown/Wrap-dependency-system-manual.md b/docs/markdown/Wrap-dependency-system-manual.md index 60568f1d8f8d..9bb7a842648c 100644 --- a/docs/markdown/Wrap-dependency-system-manual.md +++ b/docs/markdown/Wrap-dependency-system-manual.md @@ -379,7 +379,7 @@ Some naming conventions need to be respected: Since *1.5.0* Cargo wraps can also be provided with `Cargo.lock` file at the root of (sub)project source tree. Meson will automatically load that file and convert -it into a serie of wraps definitions. +it into a series of wraps definitions. ## Using wrapped projects diff --git a/test cases/unit/121 executable suffix/meson.build b/test cases/unit/121 executable suffix/meson.build index 8f952260cbf9..7dff9d69e1e1 100644 --- a/test cases/unit/121 executable suffix/meson.build +++ b/test cases/unit/121 executable suffix/meson.build @@ -1,3 +1,3 @@ -project('exectuable suffix', 'c') +project('executable suffix', 'c') foo = executable('foo', 'main.c') foo_bin = executable('foo', 'main.c', name_suffix: 'bin') From 5e6122b2a5804d77ad4cbff398d1193bcae2fd1e Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Thu, 19 Sep 2024 23:46:49 -0400 Subject: [PATCH 185/302] mdist: correctly detect dirty hg repos with non-English locale, redux https://www.gnu.org/software/gettext/manual/html_node/The-LANGUAGE-variable.html GNU Gettext defines a feature, whereby for translation purposes, if LC_ALL / LANG are *not* set to C, but rather define an active translation, the LANGUAGE variable can be used to specify fallback languages in a colon-separated list wherein the first option is the primary language and the rest are fallbacks. CPython, instead, checks the LANGUAGE variable first, and the first variable that has a non-null value is treated as the canonical language specification, splitted, and iterated over. LC_ALL=C is therefore totally ignored, which is a major problem, and the variables aren't checked for consistency, which is a less major problem. GNU libc documents the same behavior CPython does -- which is broken as it makes LC_ALL=C useless. POSIX issue 8 standardizes on option 3: do like GNU Gettext, except do not require the primary language in $LANGUAGE to be consistent with LANG / LC_ALL. Thus, we sanitize the environment even harder. What an absolute disaster. Even if this was fixed tomorrow we would need to maintain this hack until 2030. Bug: https://bugs.gentoo.org/936670 --- mesonbuild/mdist.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mesonbuild/mdist.py b/mesonbuild/mdist.py index 01b40dfd720d..17329009b40a 100644 --- a/mesonbuild/mdist.py +++ b/mesonbuild/mdist.py @@ -254,6 +254,9 @@ def have_dirty_index(self) -> bool: '''Check whether there are uncommitted changes in hg''' env = os.environ.copy() env['LC_ALL'] = 'C' + # cpython's gettext has a bug and uses LANGUAGE to override LC_ALL, + # contrary to the gettext spec + env.pop('LANGUAGE', None) out = subprocess.check_output(['hg', '-R', self.src_root, 'summary'], env=env) return b'commit: (clean)' not in out From d3f28217c54772c4e01ddc4708c673d73315da9a Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Wed, 18 Sep 2024 01:27:06 -0400 Subject: [PATCH 186/302] tests: only skip MPI test on Ubuntu if we are in a CI container It is genuinely horribly buggy so we don't want the testsuite to succeed. We make a special exception for the CI runner since it is a known breakage but people packaging meson should see the issue. --- test cases/frameworks/17 mpi/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test cases/frameworks/17 mpi/meson.build b/test cases/frameworks/17 mpi/meson.build index 5d233bfb217e..a682c281d8ea 100644 --- a/test cases/frameworks/17 mpi/meson.build +++ b/test cases/frameworks/17 mpi/meson.build @@ -35,7 +35,7 @@ if add_languages('fortran', required : false) if method in ['auto', 'pkg-config'] # https://bugs.debian.org/1078026 fs = import('fs') - if fs.exists('/usr/lib/x86_64-linux-gnu/pkgconfig/ompi-fort.pc') + if fs.is_dir('/ci') and fs.exists('/usr/lib/x86_64-linux-gnu/pkgconfig/ompi-fort.pc') if fs.hash('/usr/lib/x86_64-linux-gnu/pkgconfig/ompi-fort.pc', 'md5') == '0892a93630e3d3359c43c58d5a82efc0' error('MESON_SKIP_TEST: openmpi pkgconfig file is broken on Debian/Ubuntu') endif From 9501228168086939da1710da634830a70818934b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20S=C5=82omi=C5=84ski?= Date: Fri, 20 Sep 2024 19:38:06 +0200 Subject: [PATCH 187/302] nasm: Use different test sources for x86 and x86_64 The x86 test files might not work on x86_64 Linux in certain cases, for example if the kernel is configured without support for x86 executables (which also gets rid of the old system call interface). Bug: https://bugs.gentoo.org/936911 --- .../{hello.asm => hello-x86.asm} | 0 .../nasm/1 configure file/hello-x86_64.asm | 18 +++++++++++++++ test cases/nasm/1 configure file/meson.build | 2 +- .../{hello.asm => hello-x86.asm} | 0 .../nasm/2 asm language/hello-x86_64.asm | 22 +++++++++++++++++++ test cases/nasm/2 asm language/meson.build | 4 ++-- 6 files changed, 43 insertions(+), 3 deletions(-) rename test cases/nasm/1 configure file/{hello.asm => hello-x86.asm} (100%) create mode 100644 test cases/nasm/1 configure file/hello-x86_64.asm rename test cases/nasm/2 asm language/{hello.asm => hello-x86.asm} (100%) create mode 100644 test cases/nasm/2 asm language/hello-x86_64.asm diff --git a/test cases/nasm/1 configure file/hello.asm b/test cases/nasm/1 configure file/hello-x86.asm similarity index 100% rename from test cases/nasm/1 configure file/hello.asm rename to test cases/nasm/1 configure file/hello-x86.asm diff --git a/test cases/nasm/1 configure file/hello-x86_64.asm b/test cases/nasm/1 configure file/hello-x86_64.asm new file mode 100644 index 000000000000..b6cb776babbd --- /dev/null +++ b/test cases/nasm/1 configure file/hello-x86_64.asm @@ -0,0 +1,18 @@ +%include "config.asm" + + section .data +msg: db "Hello World", 10 +len: equ $ - msg + + section .text + global main +main: + mov eax, 1 ; sys_write + mov edi, 1 ; fd = STDOUT_FILENO + mov rsi, msg ; buf = msg + mov rdx, len ; count = len + syscall + + mov eax, 60 ; sys_exit + mov edi, HELLO ; exit code + syscall diff --git a/test cases/nasm/1 configure file/meson.build b/test cases/nasm/1 configure file/meson.build index abe7bb30f98c..46a704ceb633 100644 --- a/test cases/nasm/1 configure file/meson.build +++ b/test cases/nasm/1 configure file/meson.build @@ -50,7 +50,7 @@ config_file = configure_file( cc = meson.get_compiler('c') link_args = cc.get_supported_link_arguments(['-no-pie']) -exe = executable('hello', asm_gen.process('hello.asm'), +exe = executable('hello', asm_gen.process('hello-' + host_machine.cpu_family() + '.asm'), link_args: link_args, ) diff --git a/test cases/nasm/2 asm language/hello.asm b/test cases/nasm/2 asm language/hello-x86.asm similarity index 100% rename from test cases/nasm/2 asm language/hello.asm rename to test cases/nasm/2 asm language/hello-x86.asm diff --git a/test cases/nasm/2 asm language/hello-x86_64.asm b/test cases/nasm/2 asm language/hello-x86_64.asm new file mode 100644 index 000000000000..7e495f92ab5e --- /dev/null +++ b/test cases/nasm/2 asm language/hello-x86_64.asm @@ -0,0 +1,22 @@ +%include "config.asm" + +%ifdef FOO +%define RETVAL HELLO +%endif + + section .data +msg: db "Hello World", 10 +len: equ $ - msg + + section .text + global main +main: + mov eax, 1 ; sys_write + mov edi, 1 ; fd = STDOUT_FILENO + mov rsi, msg ; buf = msg + mov rdx, len ; count = len + syscall + + mov eax, 60 ; sys_exit + mov edi, RETVAL ; exit code + syscall diff --git a/test cases/nasm/2 asm language/meson.build b/test cases/nasm/2 asm language/meson.build index d5a2ba3eaeb2..594d12dc2496 100644 --- a/test cases/nasm/2 asm language/meson.build +++ b/test cases/nasm/2 asm language/meson.build @@ -46,7 +46,7 @@ config_file = configure_file( cc = meson.get_compiler('c') link_args = cc.get_supported_link_arguments(['-no-pie']) -exe = executable('hello', 'hello.asm', +exe = executable('hello', 'hello-' + host_machine.cpu_family() + '.asm', nasm_args: '-DFOO', link_args: link_args, ) @@ -55,7 +55,7 @@ test('hello', exe) #Test whether pthread dependency gets filtered out threads = dependency('threads') -exe2 = executable('hello_w_threads', 'hello.asm', +exe2 = executable('hello_w_threads', 'hello-' + host_machine.cpu_family() + '.asm', config_file, nasm_args: '-DFOO', link_args: link_args, From 933b0129a8b0247216c7ced5e454c24233bfe0e0 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 20 Sep 2024 15:23:51 -0700 Subject: [PATCH 188/302] CI: run lint workflows on changes to the lint config files --- .github/workflows/lint.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 5c6d56de30e9..5588034723b8 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -9,10 +9,16 @@ on: paths: - "**.py" - ".github/workflows/lint.yml" + - ".pylintrc" + - ".flake8" + - ".mypy.ini" pull_request: paths: - "**.py" - ".github/workflows/lint.yml" + - ".pylintrc" + - ".flake8" + - ".mypy.ini" permissions: contents: read From 7659c6c2368fa0a439cab4e18d7d6ce1bc568f97 Mon Sep 17 00:00:00 2001 From: Benoit Pierre Date: Fri, 20 Sep 2024 23:57:48 +0200 Subject: [PATCH 189/302] pylint: disable `too-many-positional-arguments` Added in 3.3.0, split from `too-many-arguments`, which is disabled. --- .pylintrc | 1 + 1 file changed, 1 insertion(+) diff --git a/.pylintrc b/.pylintrc index 64316fe6e70e..4a93d4923a25 100644 --- a/.pylintrc +++ b/.pylintrc @@ -66,6 +66,7 @@ disable= too-many-lines, too-many-locals, too-many-nested-blocks, + too-many-positional-arguments, too-many-public-methods, too-many-return-statements, too-many-statements, From 3f4957c713f70d708f066fff119088040bb1d287 Mon Sep 17 00:00:00 2001 From: Benoit Pierre Date: Fri, 15 Sep 2023 21:17:24 +0200 Subject: [PATCH 190/302] rewriter: don't output target info to stderr Send the info to stdout, where it belongs. --- mesonbuild/mlog.py | 72 +++++++++++++++++++++++---------------- mesonbuild/rewriter.py | 3 +- unittests/rewritetests.py | 8 ++--- 3 files changed, 48 insertions(+), 35 deletions(-) diff --git a/mesonbuild/mlog.py b/mesonbuild/mlog.py index bc8faeba7d06..6a7111a932f9 100644 --- a/mesonbuild/mlog.py +++ b/mesonbuild/mlog.py @@ -49,32 +49,6 @@ def _windows_ansi() -> bool: # original behavior return bool(kernel.SetConsoleMode(stdout, mode.value | 0x4) or os.environ.get('ANSICON')) -def colorize_console() -> bool: - _colorize_console: bool = getattr(sys.stdout, 'colorize_console', None) - if _colorize_console is not None: - return _colorize_console - - try: - if is_windows(): - _colorize_console = os.isatty(sys.stdout.fileno()) and _windows_ansi() - else: - _colorize_console = os.isatty(sys.stdout.fileno()) and os.environ.get('TERM', 'dumb') != 'dumb' - except Exception: - _colorize_console = False - - sys.stdout.colorize_console = _colorize_console # type: ignore[attr-defined] - return _colorize_console - -def setup_console() -> None: - # on Windows, a subprocess might call SetConsoleMode() on the console - # connected to stdout and turn off ANSI escape processing. Call this after - # running a subprocess to ensure we turn it on again. - if is_windows(): - try: - delattr(sys.stdout, 'colorize_console') - except AttributeError: - pass - _in_ci = 'CI' in os.environ _ci_is_github = 'GITHUB_ACTIONS' in os.environ @@ -91,6 +65,7 @@ class _Logger: log_dir: T.Optional[str] = None log_depth: T.List[str] = field(default_factory=list) + log_to_stderr: bool = False log_file: T.Optional[T.TextIO] = None log_timestamp_start: T.Optional[float] = None log_fatal_warnings = False @@ -139,7 +114,7 @@ def shutdown(self) -> T.Optional[str]: return None def start_pager(self) -> None: - if not colorize_console(): + if not self.colorize_console(): return pager_cmd = [] if 'PAGER' in os.environ: @@ -223,12 +198,17 @@ def force_print(self, *args: str, nested: bool, sep: T.Optional[str] = None, raw = '\n'.join(lines) # _Something_ is going to get printed. + if self.log_pager: + output = self.log_pager.stdin + elif self.log_to_stderr: + output = sys.stderr + else: + output = sys.stdout try: - output = self.log_pager.stdin if self.log_pager else None print(raw, end='', file=output) except UnicodeEncodeError: cleaned = raw.encode('ascii', 'replace').decode('ascii') - print(cleaned, end='') + print(cleaned, end='', file=output) def debug(self, *args: TV_Loggable, sep: T.Optional[str] = None, end: T.Optional[str] = None, display_timestamp: bool = True) -> None: @@ -244,7 +224,7 @@ def _log(self, *args: TV_Loggable, is_error: bool = False, if self.log_file is not None: print(*arr, file=self.log_file, sep=sep, end=end) self.log_file.flush() - if colorize_console(): + if self.colorize_console(): arr = process_markup(args, True, display_timestamp) if not self.log_errors_only or is_error: force_print(*arr, nested=nested, sep=sep, end=end) @@ -403,8 +383,38 @@ def nested_warnings(self) -> T.Iterator[None]: def get_warning_count(self) -> int: return self.log_warnings_counter + def redirect(self, to_stderr: bool) -> None: + self.log_to_stderr = to_stderr + + def colorize_console(self) -> bool: + output = sys.stderr if self.log_to_stderr else sys.stdout + _colorize_console: bool = getattr(output, 'colorize_console', None) + if _colorize_console is not None: + return _colorize_console + try: + if is_windows(): + _colorize_console = os.isatty(output.fileno()) and _windows_ansi() + else: + _colorize_console = os.isatty(output.fileno()) and os.environ.get('TERM', 'dumb') != 'dumb' + except Exception: + _colorize_console = False + output.colorize_console = _colorize_console # type: ignore[attr-defined] + return _colorize_console + + def setup_console(self) -> None: + # on Windows, a subprocess might call SetConsoleMode() on the console + # connected to stdout and turn off ANSI escape processing. Call this after + # running a subprocess to ensure we turn it on again. + output = sys.stderr if self.log_to_stderr else sys.stdout + if is_windows(): + try: + delattr(output, 'colorize_console') + except AttributeError: + pass + _logger = _Logger() cmd_ci_include = _logger.cmd_ci_include +colorize_console = _logger.colorize_console debug = _logger.debug deprecation = _logger.deprecation error = _logger.error @@ -421,9 +431,11 @@ def get_warning_count(self) -> int: no_logging = _logger.no_logging notice = _logger.notice process_markup = _logger.process_markup +redirect = _logger.redirect set_quiet = _logger.set_quiet set_timestamp_start = _logger.set_timestamp_start set_verbose = _logger.set_verbose +setup_console = _logger.setup_console shutdown = _logger.shutdown start_pager = _logger.start_pager stop_pager = _logger.stop_pager diff --git a/mesonbuild/rewriter.py b/mesonbuild/rewriter.py index 78517bf05f8b..919bd3847b13 100644 --- a/mesonbuild/rewriter.py +++ b/mesonbuild/rewriter.py @@ -385,7 +385,7 @@ def add_info(self, cmd_type: str, cmd_id: str, data: dict): def print_info(self): if self.info_dump is None: return - sys.stderr.write(json.dumps(self.info_dump, indent=2)) + sys.stdout.write(json.dumps(self.info_dump, indent=2)) def on_error(self): if self.skip_errors: @@ -1044,6 +1044,7 @@ def generate_cmd(options) -> T.List[dict]: } def run(options): + mlog.redirect(True) if not options.verbose: mlog.set_quiet() diff --git a/unittests/rewritetests.py b/unittests/rewritetests.py index a9e72b369180..7fad513f5271 100644 --- a/unittests/rewritetests.py +++ b/unittests/rewritetests.py @@ -34,12 +34,12 @@ def rewrite_raw(self, directory, args): print('STDERR:') print(p.stderr) if p.returncode != 0: - if 'MESON_SKIP_TEST' in p.stdout: + if 'MESON_SKIP_TEST' in p.stderr: raise unittest.SkipTest('Project requested skipping.') - raise subprocess.CalledProcessError(p.returncode, command, output=p.stdout) - if not p.stderr: + raise subprocess.CalledProcessError(p.returncode, command, output=p.stderr) + if not p.stdout: return {} - return json.loads(p.stderr) + return json.loads(p.stdout) def rewrite(self, directory, args): if isinstance(args, str): From c8b463491c3dac4f21120ff9cbc2de491e2b66c9 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 19 Sep 2024 18:54:32 +0200 Subject: [PATCH 191/302] Add get_variable() system dependency --- mesonbuild/dependencies/base.py | 4 ++-- mesonbuild/dependencies/cmake.py | 2 +- mesonbuild/dependencies/configtool.py | 2 +- mesonbuild/dependencies/pkgconfig.py | 2 +- mesonbuild/interpreter/interpreterobjects.py | 2 ++ mesonbuild/interpreter/kwargs.py | 1 + 6 files changed, 8 insertions(+), 5 deletions(-) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 4803e6dce5c9..239098c042cc 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -237,7 +237,7 @@ def _add_sub_dependency(self, deplist: T.Iterable[T.Callable[[], 'Dependency']]) def get_variable(self, *, cmake: T.Optional[str] = None, pkgconfig: T.Optional[str] = None, configtool: T.Optional[str] = None, internal: T.Optional[str] = None, - default_value: T.Optional[str] = None, + system: T.Optional[str] = None, default_value: T.Optional[str] = None, pkgconfig_define: PkgConfigDefineType = None) -> str: if default_value is not None: return default_value @@ -329,7 +329,7 @@ def get_include_dirs(self) -> T.List['IncludeDirs']: def get_variable(self, *, cmake: T.Optional[str] = None, pkgconfig: T.Optional[str] = None, configtool: T.Optional[str] = None, internal: T.Optional[str] = None, - default_value: T.Optional[str] = None, + system: T.Optional[str] = None, default_value: T.Optional[str] = None, pkgconfig_define: PkgConfigDefineType = None) -> str: val = self.variables.get(internal, default_value) if val is not None: diff --git a/mesonbuild/dependencies/cmake.py b/mesonbuild/dependencies/cmake.py index 5493e94ba79d..4a722157ff56 100644 --- a/mesonbuild/dependencies/cmake.py +++ b/mesonbuild/dependencies/cmake.py @@ -617,7 +617,7 @@ def log_details(self) -> str: def get_variable(self, *, cmake: T.Optional[str] = None, pkgconfig: T.Optional[str] = None, configtool: T.Optional[str] = None, internal: T.Optional[str] = None, - default_value: T.Optional[str] = None, + system: T.Optional[str] = None, default_value: T.Optional[str] = None, pkgconfig_define: PkgConfigDefineType = None) -> str: if cmake and self.traceparser is not None: try: diff --git a/mesonbuild/dependencies/configtool.py b/mesonbuild/dependencies/configtool.py index f49c16d4a307..f9ec5217a1e4 100644 --- a/mesonbuild/dependencies/configtool.py +++ b/mesonbuild/dependencies/configtool.py @@ -150,7 +150,7 @@ def log_tried() -> str: def get_variable(self, *, cmake: T.Optional[str] = None, pkgconfig: T.Optional[str] = None, configtool: T.Optional[str] = None, internal: T.Optional[str] = None, - default_value: T.Optional[str] = None, + system: T.Optional[str] = None, default_value: T.Optional[str] = None, pkgconfig_define: PkgConfigDefineType = None) -> str: if configtool: p, out, _ = Popen_safe(self.config + self.get_variable_args(configtool)) diff --git a/mesonbuild/dependencies/pkgconfig.py b/mesonbuild/dependencies/pkgconfig.py index 9d47155a23d4..4fea86c12a33 100644 --- a/mesonbuild/dependencies/pkgconfig.py +++ b/mesonbuild/dependencies/pkgconfig.py @@ -557,7 +557,7 @@ def log_tried() -> str: def get_variable(self, *, cmake: T.Optional[str] = None, pkgconfig: T.Optional[str] = None, configtool: T.Optional[str] = None, internal: T.Optional[str] = None, - default_value: T.Optional[str] = None, + system: T.Optional[str] = None, default_value: T.Optional[str] = None, pkgconfig_define: PkgConfigDefineType = None) -> str: if pkgconfig: try: diff --git a/mesonbuild/interpreter/interpreterobjects.py b/mesonbuild/interpreter/interpreterobjects.py index 1d602828587f..bc0d7e7695ab 100644 --- a/mesonbuild/interpreter/interpreterobjects.py +++ b/mesonbuild/interpreter/interpreterobjects.py @@ -545,6 +545,7 @@ def partial_dependency_method(self, args: T.List[TYPE_nvar], kwargs: 'kwargs.Dep KwargInfo('pkgconfig', (str, NoneType)), KwargInfo('configtool', (str, NoneType)), KwargInfo('internal', (str, NoneType), since='0.54.0'), + KwargInfo('system', (str, NoneType), since='1.6.0'), KwargInfo('default_value', (str, NoneType)), PKGCONFIG_DEFINE_KW, ) @@ -561,6 +562,7 @@ def variable_method(self, args: T.Tuple[T.Optional[str]], kwargs: 'kwargs.Depend pkgconfig=kwargs['pkgconfig'] or default_varname, configtool=kwargs['configtool'] or default_varname, internal=kwargs['internal'] or default_varname, + system=kwargs['system'] or default_varname, default_value=kwargs['default_value'], pkgconfig_define=kwargs['pkgconfig_define'], ) diff --git a/mesonbuild/interpreter/kwargs.py b/mesonbuild/interpreter/kwargs.py index 25c40a0d4438..ae4866a88ad8 100644 --- a/mesonbuild/interpreter/kwargs.py +++ b/mesonbuild/interpreter/kwargs.py @@ -268,6 +268,7 @@ class DependencyGetVariable(TypedDict): pkgconfig: T.Optional[str] configtool: T.Optional[str] internal: T.Optional[str] + system: T.Optional[str] default_value: T.Optional[str] pkgconfig_define: PkgConfigDefineType From cbbe455ba4f7da2d9056023d8e8647da96eeaf09 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 20 Sep 2024 08:48:54 +0200 Subject: [PATCH 192/302] Document get_variable(system) --- docs/markdown/Dependencies.md | 4 ++-- docs/markdown/snippets/system_variable_in_dep.md | 3 +++ docs/yaml/objects/dep.yaml | 7 ++++++- 3 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 docs/markdown/snippets/system_variable_in_dep.md diff --git a/docs/markdown/Dependencies.md b/docs/markdown/Dependencies.md index a457342d1a9c..3c3df1bcc3a8 100644 --- a/docs/markdown/Dependencies.md +++ b/docs/markdown/Dependencies.md @@ -80,8 +80,8 @@ var = foo_dep.get_variable(cmake : 'CMAKE_VAR', pkgconfig : 'pkg-config-var', co ``` It accepts the keywords 'cmake', 'pkgconfig', 'pkgconfig_define', -'configtool', 'internal', and 'default_value'. 'pkgconfig_define' -works just like the 'define_variable' argument to +'configtool', 'internal', 'system', and 'default_value'. +'pkgconfig_define' works just like the 'define_variable' argument to `get_pkgconfig_variable`. When this method is invoked the keyword corresponding to the underlying type of the dependency will be used to look for a variable. If that variable cannot be found or if the caller diff --git a/docs/markdown/snippets/system_variable_in_dep.md b/docs/markdown/snippets/system_variable_in_dep.md new file mode 100644 index 000000000000..0cd936322bd9 --- /dev/null +++ b/docs/markdown/snippets/system_variable_in_dep.md @@ -0,0 +1,3 @@ +## Support for variable in system dependencies + +System Dependency method `get_variable()` now supports `system` variable. diff --git a/docs/yaml/objects/dep.yaml b/docs/yaml/objects/dep.yaml index 28d93d79f7f6..ffd19f7976b2 100644 --- a/docs/yaml/objects/dep.yaml +++ b/docs/yaml/objects/dep.yaml @@ -191,7 +191,7 @@ methods: since: 0.58.0 description: | This argument is used as a default value - for `cmake`, `pkgconfig`, `configtool` and `internal` keyword + for `cmake`, `pkgconfig`, `configtool`, `internal` and `system` keyword arguments. It is useful in the common case where `pkgconfig` and `internal` use the same variable name, in which case it's easier to write `dep.get_variable('foo')` instead of `dep.get_variable(pkgconfig: 'foo', internal: 'foo')`. @@ -214,6 +214,11 @@ methods: since: 0.54.0 description: The internal variable name + system: + type: str + since: 1.6.0 + description: The system variable name + default_value: type: str description: The default value to return when the variable does not exist From 59f6105f7980a7e615df8b2c7700a40d707415a3 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 5 Sep 2024 20:56:01 +0200 Subject: [PATCH 193/302] add diasdk dependency --- mesonbuild/dependencies/__init__.py | 1 + mesonbuild/dependencies/dev.py | 102 ++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) diff --git a/mesonbuild/dependencies/__init__.py b/mesonbuild/dependencies/__init__.py index 89d2285ba3a6..a3eb6623f02c 100644 --- a/mesonbuild/dependencies/__init__.py +++ b/mesonbuild/dependencies/__init__.py @@ -195,6 +195,7 @@ def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T. 'zlib': 'dev', 'jni': 'dev', 'jdk': 'dev', + 'diasdk': 'dev', 'boost': 'boost', 'cuda': 'cuda', diff --git a/mesonbuild/dependencies/dev.py b/mesonbuild/dependencies/dev.py index de85516feb64..94f51ff69b12 100644 --- a/mesonbuild/dependencies/dev.py +++ b/mesonbuild/dependencies/dev.py @@ -28,8 +28,10 @@ if T.TYPE_CHECKING: from ..envconfig import MachineInfo from ..environment import Environment + from ..compilers import Compiler from ..mesonlib import MachineChoice from typing_extensions import TypedDict + from ..interpreter.type_checking import PkgConfigDefineType class JNISystemDependencyKW(TypedDict): modules: T.List[str] @@ -700,6 +702,106 @@ def __init__(self, environment: 'Environment', kwargs: JNISystemDependencyKW): packages['jdk'] = JDKSystemDependency +class DiaSDKSystemDependency(SystemDependency): + + def _try_path(self, diadir: str, cpu: str) -> bool: + if not os.path.isdir(diadir): + return False + + include = os.path.join(diadir, 'include') + if not os.path.isdir(include): + mlog.error('DIA SDK is missing include directory:', include) + return False + + lib = os.path.join(diadir, 'lib', cpu, 'diaguids.lib') + if not os.path.exists(lib): + mlog.error('DIA SDK is missing library:', lib) + return False + + bindir = os.path.join(diadir, 'bin', cpu) + if not os.path.exists(bindir): + mlog.error(f'Directory {bindir} not found') + return False + + found = glob.glob(os.path.join(bindir, 'msdia*.dll')) + if not found: + mlog.error("Can't find msdia*.dll in " + bindir) + return False + if len(found) > 1: + mlog.error('Multiple msdia*.dll files found in ' + bindir) + return False + self.dll = found[0] + + # Parse only major version from DLL name (eg '8' from 'msdia80.dll', '14' from 'msdia140.dll', etc.). + # Minor version is not reflected in the DLL name, instead '0' is always used. + # Aside from major version in DLL name, the SDK version is not visible to user anywhere. + # The only place where the full version is stored, seems to be the Version field in msdia*.dll resources. + dllname = os.path.basename(self.dll) + versionstr = dllname[len('msdia'):-len('.dll')] + if versionstr[-1] == '0': + self.version = versionstr[:-1] + else: + mlog.error(f"Unexpected DIA SDK version string in '{dllname}'") + self.version = 'unknown' + + self.compile_args.append('-I' + include) + self.link_args.append(lib) + self.is_found = True + return True + + # Check if compiler has a built-in macro defined + @staticmethod + def _has_define(compiler: 'Compiler', dname: str, env: 'Environment') -> bool: + defval, _ = compiler.get_define(dname, '', env, [], []) + return defval is not None + + def __init__(self, environment: 'Environment', kwargs: T.Dict[str, T.Any]) -> None: + super().__init__('diasdk', environment, kwargs) + self.is_found = False + + compilers = environment.coredata.compilers.host + if 'cpp' in compilers: + compiler = compilers['cpp'] + elif 'c' in compilers: + compiler = compilers['c'] + else: + raise DependencyException('DIA SDK is only supported in C and C++ projects') + + is_msvc_clang = compiler.id == 'clang' and self._has_define(compiler, '_MSC_VER', environment) + if compiler.id not in {'msvc', 'clang-cl'} and not is_msvc_clang: + raise DependencyException('DIA SDK is only supported with Microsoft Visual Studio compilers') + + cpu_translate = {'arm': 'arm', 'aarch64': 'arm64', 'x86': '.', 'x86_64': 'amd64'} + cpu_family = environment.machines.host.cpu_family + cpu = cpu_translate.get(cpu_family) + if cpu is None: + raise DependencyException(f'DIA SDK is not supported for "{cpu_family}" architecture') + + vsdir = os.environ.get('VSInstallDir') + if vsdir is None: + raise DependencyException("Environment variable VSInstallDir required for DIA SDK is not set") + + diadir = os.path.join(vsdir, 'DIA SDK') + if self._try_path(diadir, cpu): + mlog.debug('DIA SDK was found at default path: ', diadir) + self.is_found = True + return + mlog.debug('DIA SDK was not found at default path: ', diadir) + + return + + def get_variable(self, *, cmake: T.Optional[str] = None, pkgconfig: T.Optional[str] = None, + configtool: T.Optional[str] = None, internal: T.Optional[str] = None, + system: T.Optional[str] = None, default_value: T.Optional[str] = None, + pkgconfig_define: PkgConfigDefineType = None) -> str: + if system == 'dll' and self.is_found: + return self.dll + if default_value is not None: + return default_value + raise DependencyException(f'Could not get system variable and no default was set for {self!r}') + +packages['diasdk'] = DiaSDKSystemDependency + packages['llvm'] = llvm_factory = DependencyFactory( 'LLVM', [DependencyMethods.CMAKE, DependencyMethods.CONFIG_TOOL], From 527752a58874cd82f87f3122efae9300dabe173f Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 5 Sep 2024 22:28:25 +0200 Subject: [PATCH 194/302] add description --- docs/markdown/Dependencies.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/docs/markdown/Dependencies.md b/docs/markdown/Dependencies.md index 3c3df1bcc3a8..93f75d5a916b 100644 --- a/docs/markdown/Dependencies.md +++ b/docs/markdown/Dependencies.md @@ -849,6 +849,34 @@ version. *New in 0.54.0* the `system` method. +## DIA SDK + +*(added 1.6.0)* + +Microsoft's Debug Interface Access SDK (DIA SDK) is available only on Windows, +when using msvc, clang-cl or clang compiler from Microsoft Visual Studio. + +The DIA SDK runtime is not statically linked to target. The default usage +method requires the runtime DLL (msdiaXXX.dll) to be manually registered in the +OS with `regsrv32.exe` command, so it can be loaded using `CoCreateInstance` +Windows function. + +Alternatively, you can use meson to copy the DIA runtime DLL to your build +directory, and load it dynamically using `NoRegCoCreate` function provided by +the DIA SDK. To facilitate this, you can read DLL path from dependency's +variable 'dll' and use fs module to copy it. Example: + +```meson +dia = dependency('diasdk', required: true) +fs = import('fs') +fs.copyfile(dia.get_variable('dll')) + +conf = configuration_data() +conf.set('msdia_dll_name', fs.name(dia_dll_name)) +``` + +Only the major version is available (eg. version is `14` for msdia140.dll). +
1: They may appear to be case-insensitive, if the underlying file system happens to be case-insensitive. From 63cea2ae221a7134a71747a3813135ceb14c0a4b Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 5 Sep 2024 23:39:49 +0200 Subject: [PATCH 195/302] add test cases --- .../windows/23 diasdk/dia_registered.cpp | 30 +++++++++++++++++ test cases/windows/23 diasdk/meson.build | 13 ++++++++ .../windows/24 diasdk copy dll/config.h.in | 3 ++ .../24 diasdk copy dll/dia_from_dll.cpp | 32 +++++++++++++++++++ .../windows/24 diasdk copy dll/meson.build | 21 ++++++++++++ 5 files changed, 99 insertions(+) create mode 100644 test cases/windows/23 diasdk/dia_registered.cpp create mode 100644 test cases/windows/23 diasdk/meson.build create mode 100644 test cases/windows/24 diasdk copy dll/config.h.in create mode 100644 test cases/windows/24 diasdk copy dll/dia_from_dll.cpp create mode 100644 test cases/windows/24 diasdk copy dll/meson.build diff --git a/test cases/windows/23 diasdk/dia_registered.cpp b/test cases/windows/23 diasdk/dia_registered.cpp new file mode 100644 index 000000000000..cec4fb2f678f --- /dev/null +++ b/test cases/windows/23 diasdk/dia_registered.cpp @@ -0,0 +1,30 @@ +// Loads DIA SDK from system registry using CoCreateInstance(). +// The corresponding msdiaXXX.dll must be registered in system registry +// (eg. run `regsvr32.exe msdia140.dll` as administrator) + +#include +#include +#include +#include + +int main() +{ + try { + + HRESULT hr = CoInitialize(NULL); + if (FAILED(hr)) + throw std::runtime_error("Failed to initialize COM library"); + + IDiaDataSource* datasrc; + hr = CoCreateInstance( CLSID_DiaSource, NULL, CLSCTX_INPROC_SERVER, __uuidof(IDiaDataSource), (void **)&datasrc); + if (FAILED(hr)) + throw std::runtime_error("Can't create IDiaDataSource. You must register msdia*.dll with regsvr32.exe."); + + std::cout << "DIA was successfully loaded\n"; + return 0; + + } catch (std::exception& err) { + std::cerr << err.what() << std::endl; + return 1; + } +} diff --git a/test cases/windows/23 diasdk/meson.build b/test cases/windows/23 diasdk/meson.build new file mode 100644 index 000000000000..bb8477822a66 --- /dev/null +++ b/test cases/windows/23 diasdk/meson.build @@ -0,0 +1,13 @@ +project('diatest', 'cpp') + +if host_machine.system() != 'windows' + error('MESON_SKIP_TEST: unsupported platform') +endif +cpp = meson.get_compiler('cpp', native: false) +is_msvc_clang = cpp.get_id() == 'clang' and cpp.get_define('_MSC_VER') != '' +if not ['msvc', 'clang-cl'].contains(cpp.get_id()) and not is_msvc_clang + error('MESON_SKIP_TEST: unsupported compiler') +endif + +dia = dependency('diasdk', required: true) +executable('dia_registered', ['dia_registered.cpp'], dependencies:[dia]) diff --git a/test cases/windows/24 diasdk copy dll/config.h.in b/test cases/windows/24 diasdk copy dll/config.h.in new file mode 100644 index 000000000000..80d59c1a4b09 --- /dev/null +++ b/test cases/windows/24 diasdk copy dll/config.h.in @@ -0,0 +1,3 @@ +#pragma once + +#define MSDIA_DLL_NAME L"@msdia_dll_name@" diff --git a/test cases/windows/24 diasdk copy dll/dia_from_dll.cpp b/test cases/windows/24 diasdk copy dll/dia_from_dll.cpp new file mode 100644 index 000000000000..5474717490d3 --- /dev/null +++ b/test cases/windows/24 diasdk copy dll/dia_from_dll.cpp @@ -0,0 +1,32 @@ +// Loads msdiaXXX.dll from current directory using NoRegCoCreate. +// File name is set in config.h symbol MSDIA_DLL_NAME. + +#include +#include +#include +#include +#include + +#include "config.h" + +int main() +{ + try { + + HRESULT hr = CoInitialize(NULL); + if (FAILED(hr)) + throw std::runtime_error("Failed to initialize COM library"); + + IDiaDataSource* datasrc; + hr = NoRegCoCreate(MSDIA_DLL_NAME, CLSID_DiaSource, __uuidof(IDiaDataSource), (void**)&datasrc); + if (FAILED(hr)) + throw std::runtime_error("Can't open DIA DLL"); + + std::cout << "DIA was successfully loaded\n"; + return 0; + + } catch (std::exception& err) { + std::cerr << err.what() << std::endl; + return 1; + } +} diff --git a/test cases/windows/24 diasdk copy dll/meson.build b/test cases/windows/24 diasdk copy dll/meson.build new file mode 100644 index 000000000000..1a078b0d98de --- /dev/null +++ b/test cases/windows/24 diasdk copy dll/meson.build @@ -0,0 +1,21 @@ +project('diatest', 'cpp') + +if host_machine.system() != 'windows' + error('MESON_SKIP_TEST: unsupported platform') +endif +cpp = meson.get_compiler('cpp', native: false) +is_msvc_clang = cpp.get_id() == 'clang' and cpp.get_define('_MSC_VER') != '' +if not ['msvc', 'clang-cl'].contains(cpp.get_id()) and not is_msvc_clang + error('MESON_SKIP_TEST: unsupported compiler') +endif + +dia = dependency('diasdk', required: true) +dia_dll_name = dia.get_variable('dll') +fs = import('fs') +fs.copyfile( dia_dll_name ) + +conf = configuration_data() +conf.set('msdia_dll_name', fs.name(dia_dll_name)) +configure_file(input: 'config.h.in', output: 'config.h', configuration: conf) + +executable('dia_from_dll', ['dia_from_dll.cpp'], dependencies: [dia]) From dbad301c8b039c4469f8727924baf250421d64ac Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 5 Sep 2024 23:43:30 +0200 Subject: [PATCH 196/302] add doc snippet --- docs/markdown/snippets/dia_sdk.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 docs/markdown/snippets/dia_sdk.md diff --git a/docs/markdown/snippets/dia_sdk.md b/docs/markdown/snippets/dia_sdk.md new file mode 100644 index 000000000000..eb704230da4f --- /dev/null +++ b/docs/markdown/snippets/dia_sdk.md @@ -0,0 +1,3 @@ +## Support for DIA SDK + +Added support for Windows Debug Interface Access SDK (DIA SDK) dependency. It allows reading with MSVC debugging information (.PDB format). This dependency can only be used on Windows, with msvc, clang or clang-cl compiler. From b1abfa89d99146858df5988a39a324c48159cfa0 Mon Sep 17 00:00:00 2001 From: Will Ayd Date: Sat, 21 Sep 2024 22:18:58 -0400 Subject: [PATCH 197/302] Add Accept-Language and Accept-Encoding headers to wrap requests This makes wrap requests look more like browser requests, which is helpful in rare cases to prevent the request from being rejected --- mesonbuild/wrap/wrap.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mesonbuild/wrap/wrap.py b/mesonbuild/wrap/wrap.py index 3fe40ed9f322..197a4478a40e 100644 --- a/mesonbuild/wrap/wrap.py +++ b/mesonbuild/wrap/wrap.py @@ -687,7 +687,11 @@ def get_data(self, urlstring: str) -> T.Tuple[str, str]: elif WHITELIST_SUBDOMAIN in urlstring: raise WrapException(f'{urlstring} may be a WrapDB-impersonating URL') else: - headers = {'User-Agent': f'mesonbuild/{coredata.version}'} + headers = { + 'User-Agent': f'mesonbuild/{coredata.version}', + 'Accept-Language': '*', + 'Accept-Encoding': '*', + } creds = self.get_netrc_credentials(url.netloc) if creds is not None and '@' not in url.netloc: From 5102f436576b873ab5b2042179af9b1b824f0b39 Mon Sep 17 00:00:00 2001 From: Martin Garton Date: Mon, 16 Sep 2024 14:35:25 +0100 Subject: [PATCH 198/302] Add a newline at the end of test files When running in some settings, a C compiler may demand newlines at the end of each file. Instead of modifying everywhere that writes out test files to incorporate newlines in each indivudual string, simply add a newline when writing it out. Only add a newline to the end of the file if there isn't one already there. An examples of when this is a problem is running with `CC=clang` and `CFLAGS="--std=c99 -pedantic-errors"` and meson.build contains (for example) the following: ``` project('myproject', 'c') executable('myexecutable', 'main.c') cc = meson.get_compiler('c') sizeof_int = cc.sizeof('int') ``` sizeof_int will be -1, because the compile failed. The meson logs contain the error `testfile.c:7:10: error: no newline at end of file` --- mesonbuild/compilers/compilers.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index b9605ccaedcb..cb047be0c14c 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -805,6 +805,8 @@ def compile(self, code: 'mesonlib.FileOrString', 'testfile.' + self.default_suffix) with open(srcname, 'w', encoding='utf-8') as ofile: ofile.write(code) + if not code.endswith('\n'): + ofile.write('\n') # ccache would result in a cache miss no_ccache = True code_debug = f'Code:\n{code}' From bc30d5982d4f1e7650340bd189e1bb820ec2d7a8 Mon Sep 17 00:00:00 2001 From: Andrew McNulty Date: Fri, 20 Sep 2024 20:39:03 +0200 Subject: [PATCH 199/302] meson command tests: clean up temporary script upon completion --- run_meson_command_tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run_meson_command_tests.py b/run_meson_command_tests.py index d405a5b8790e..f9faca9af6fe 100755 --- a/run_meson_command_tests.py +++ b/run_meson_command_tests.py @@ -206,13 +206,13 @@ def test_meson_runpython(self): with open(script_file, 'w') as f: f.write('#!/usr/bin/env python3\n\n') f.write(f'{test_command}\n') + self.addCleanup(os.remove, script_file) for cmd in [['-c', test_command, 'fake argument'], [script_file, 'fake argument']]: pyout = self._run(python_command + cmd) mesonout = self._run(python_command + [meson_command, 'runpython'] + cmd, env=env) self.assertEqual(pyout, mesonout) - if __name__ == '__main__': print('Meson build system', meson_version, 'Command Tests') raise SystemExit(unittest.main(buffer=True)) From 191b801f1d8524d20fa134ab23c6c7080f29c126 Mon Sep 17 00:00:00 2001 From: Andrew McNulty Date: Sat, 21 Sep 2024 11:27:05 +0200 Subject: [PATCH 200/302] run_single_test: Ensure symlinks exist and are cleaned up The common test case "268 install functions and follow symlinks" requires that certain symlinks exist in order to function. If one clones a fresh repo and executes run_single_test.py with the aforementioned test as the target it will fail as the required symlinks are not part of the repo. Normally these symlinks are created and cleaned up when the overall testsuite is run but this is not the case for run_single_test.py This commit calls the necessary creation and cleanup functions in the case of run_single_test.py. --- run_single_test.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/run_single_test.py b/run_single_test.py index 0b4750b76d1b..6cc75ac17b4e 100755 --- a/run_single_test.py +++ b/run_single_test.py @@ -16,6 +16,7 @@ from run_tests import handle_meson_skip_test from run_project_tests import TestDef, load_test_json, run_test, BuildStep from run_project_tests import setup_commands, detect_system_compiler, detect_tools +from run_project_tests import setup_symlinks, clear_transitive_files if T.TYPE_CHECKING: from run_project_tests import CompilerArgumentType @@ -44,6 +45,7 @@ def main() -> None: parser.add_argument('--quick', action='store_true', help='Skip some compiler and tool checking') args = T.cast('ArgumentType', parser.parse_args()) + setup_symlinks() setup_commands(args.backend) if not args.quick: detect_system_compiler(args) @@ -95,6 +97,7 @@ def should_fail(path: pathlib.Path) -> str: mlog.log(cmd_res) mlog.log(result.stde) + clear_transitive_files() exit(1 if failed else 0) if __name__ == "__main__": From 726d9c0b61ecdf0fbe1fb4f0d8c883eaac8108d0 Mon Sep 17 00:00:00 2001 From: Andrei Horodniceanu Date: Fri, 13 Sep 2024 10:13:30 +0300 Subject: [PATCH 201/302] .github/workflows/os_comp.yml: set HOME to /root on OpenSUSE The D compiler and associated tools are installed under /root and the setup script run during the actual testing expects that `~` will expand to the same path. Because github overrides HOME the dmd environment setup script will not be run which leads to all D related tests being skipped, even though the whole test suite reports as having finished successfully. Signed-off-by: Andrei Horodniceanu --- .github/workflows/os_comp.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/os_comp.yml b/.github/workflows/os_comp.yml index 05e4f072deb6..0830a05e5836 100644 --- a/.github/workflows/os_comp.yml +++ b/.github/workflows/os_comp.yml @@ -60,7 +60,14 @@ jobs: # All environment variables are stored inside the docker image in /ci/env_vars.sh # They are defined in the `env` section in each image.json. CI_ARGS should be set # via the `args` array ub the image.json - run: bash -c 'source /ci/env_vars.sh; cd $GITHUB_WORKSPACE; ./tools/run_with_cov.py ./run_tests.py $CI_ARGS' + shell: bash + run: | + # dmd is installed under /root on OpenSUSE + [[ ${{ matrix.cfg.id }} == opensuse ]] && export HOME=/root + + source /ci/env_vars.sh + cd $GITHUB_WORKSPACE + ./tools/run_with_cov.py ./run_tests.py $CI_ARGS - name: Aggregate coverage reports run: ./ci/combine_cov.sh From 6e98767c31dcc23229edee4c5609d65eaf3646a8 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Wed, 13 Mar 2024 13:30:34 -0700 Subject: [PATCH 202/302] dependency: define equality and hash operators for Dependency When a dependency is copied and its name is changed, we still need a way to say "this is the same dependency", which we now have. It is important, however, when a partial dependency is created that dependency does *not* match the original dependency, since they are not providing the same data. This was always happening for InternalDependencies as an implementation detail, but not for other kinds. --- mesonbuild/dependencies/base.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 239098c042cc..ed6138a7ee0b 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -1,5 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright 2013-2018 The Meson development team +# Copyright © 2024 Intel Corporation # This file contains the detection logic for external dependencies. # Custom logic for several other packages are in separate files. @@ -10,6 +11,7 @@ import collections import itertools import typing as T +import uuid from enum import Enum from .. import mlog, mesonlib @@ -106,6 +108,9 @@ def _process_include_type_kw(cls, kwargs: T.Dict[str, T.Any]) -> str: return kwargs['include_type'] def __init__(self, type_name: DependencyTypeName, kwargs: T.Dict[str, T.Any]) -> None: + # This allows two Dependencies to be compared even after being copied. + # The purpose is to allow the name to be changed, but still have a proper comparison + self._id = uuid.uuid4().int self.name = f'dep{id(self)}' self.version: T.Optional[str] = None self.language: T.Optional[str] = None # None means C-like @@ -124,6 +129,14 @@ def __init__(self, type_name: DependencyTypeName, kwargs: T.Dict[str, T.Any]) -> self.featurechecks: T.List['FeatureCheckBase'] = [] self.feature_since: T.Optional[T.Tuple[str, str]] = None + def __eq__(self, other: object) -> bool: + if not isinstance(other, Dependency): + return NotImplemented + return self._id == other._id + + def __hash__(self) -> int: + return self._id + def __repr__(self) -> str: return f'<{self.__class__.__name__} {self.name}: {self.is_found}>' @@ -402,6 +415,7 @@ def get_partial_dependency(self, *, compile_args: bool = False, link_args: bool = False, links: bool = False, includes: bool = False, sources: bool = False) -> Dependency: new = copy.copy(self) + new._id = uuid.uuid4().int if not compile_args: new.compile_args = [] if not link_args: @@ -472,7 +486,9 @@ def __init__(self, name: str, environment: 'Environment') -> None: def get_partial_dependency(self, *, compile_args: bool = False, link_args: bool = False, links: bool = False, includes: bool = False, sources: bool = False) -> 'NotFoundDependency': - return copy.copy(self) + new = copy.copy(self) + new._id = uuid.uuid4().int + return new class ExternalLibrary(ExternalDependency): @@ -512,6 +528,7 @@ def get_partial_dependency(self, *, compile_args: bool = False, # External library only has link_args, so ignore the rest of the # interface. new = copy.copy(self) + new._id = uuid.uuid4().int if not link_args: new.link_args = [] return new From b7bf61e33e76705e6dd9a0e59e48ac9f3b97e765 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Wed, 13 Mar 2024 12:48:06 -0700 Subject: [PATCH 203/302] interpreter: when overriding a dependency make its name match Otherwise internal dependencies have auto-generated names that are not human readable. Instead, use the name that the dependency overrides. For example: ```meson meson.override_dependency('zlib', declare_dependency()) dep_zlib = dependency('zlib') assert(dep_zlib.name() == 'zlib') ``` Fixes: #12967 --- mesonbuild/interpreter/mesonmain.py | 13 ++++++++++++- .../declare_dependency/meson.build | 10 +++++++++- .../external_dependency/header_only.c | 8 ++++++++ .../external_dependency/link.c | 12 ++++++++++++ .../external_dependency/meson.build | 17 +++++++++++++++++ .../common/183 partial dependency/meson.build | 5 ++++- .../common/98 subproject subdir/meson.build | 18 +++++++++++++++++- 7 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 test cases/common/183 partial dependency/external_dependency/header_only.c create mode 100644 test cases/common/183 partial dependency/external_dependency/link.c create mode 100644 test cases/common/183 partial dependency/external_dependency/meson.build diff --git a/mesonbuild/interpreter/mesonmain.py b/mesonbuild/interpreter/mesonmain.py index 31ef544cdc6a..a148f9624ae6 100644 --- a/mesonbuild/interpreter/mesonmain.py +++ b/mesonbuild/interpreter/mesonmain.py @@ -1,8 +1,9 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright 2012-2021 The Meson development team -# Copyright © 2021 Intel Corporation +# Copyright © 2021-2024 Intel Corporation from __future__ import annotations +import copy import os import typing as T @@ -348,6 +349,16 @@ def override_dependency_method(self, args: T.Tuple[str, dependencies.Dependency] if not name: raise InterpreterException('First argument must be a string and cannot be empty') + # Make a copy since we're going to mutate. + # + # dep = declare_dependency() + # meson.override_dependency('foo', dep) + # meson.override_dependency('foo-1.0', dep) + # dep = dependency('foo') + # dep.name() # == 'foo-1.0' + dep = copy.copy(dep) + dep.name = name + optkey = OptionKey('default_library', subproject=self.interpreter.subproject) default_library = self.interpreter.coredata.get_option(optkey) assert isinstance(default_library, str), 'for mypy' diff --git a/test cases/common/183 partial dependency/declare_dependency/meson.build b/test cases/common/183 partial dependency/declare_dependency/meson.build index 3783f669467a..8c62d10820cc 100644 --- a/test cases/common/183 partial dependency/declare_dependency/meson.build +++ b/test cases/common/183 partial dependency/declare_dependency/meson.build @@ -1,4 +1,4 @@ -# Copyright © 2018 Intel Corporation +# Copyright © 2018-2024 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -29,4 +29,12 @@ dec_exe = executable( dependencies : sub_dep, ) +# Ensure that two partial dependencies of the same dependency are applied, as +# they may provide different values. +dec2_exe = executable( + 'declare_dep2', + files('main.c', 'other.c'), + dependencies : [sub_dep.partial_dependency(), sub_dep], +) + test('Declare Dependency', dec_exe) diff --git a/test cases/common/183 partial dependency/external_dependency/header_only.c b/test cases/common/183 partial dependency/external_dependency/header_only.c new file mode 100644 index 000000000000..ecdd58becbd7 --- /dev/null +++ b/test cases/common/183 partial dependency/external_dependency/header_only.c @@ -0,0 +1,8 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright © 2024 Intel Corporation + */ + +#include + +int main(void) { return 0; } diff --git a/test cases/common/183 partial dependency/external_dependency/link.c b/test cases/common/183 partial dependency/external_dependency/link.c new file mode 100644 index 000000000000..dae5561e14eb --- /dev/null +++ b/test cases/common/183 partial dependency/external_dependency/link.c @@ -0,0 +1,12 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright © 2024 Intel Corporation + */ + +#include +#include + +int main(void) { + const char * zver = zlibVersion(); + return strcmp(zver, ZLIB_VERSION); +} diff --git a/test cases/common/183 partial dependency/external_dependency/meson.build b/test cases/common/183 partial dependency/external_dependency/meson.build new file mode 100644 index 000000000000..4194bb76e379 --- /dev/null +++ b/test cases/common/183 partial dependency/external_dependency/meson.build @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright © 2024 Intel Corporation + +# TODO: don't use compile whenever we get includes and compile args separated +dep_zlib_sub = dep_zlib.partial_dependency(compile_args : true, includes : true) + +executable( + 'zlib header only test', + 'header_only.c', + dependencies : dep_zlib_sub, +) + +executable( + 'zlib link test', + 'link.c', + dependencies : [dep_zlib_sub, dep_zlib], +) diff --git a/test cases/common/183 partial dependency/meson.build b/test cases/common/183 partial dependency/meson.build index e908487f184a..c492cc3d42f6 100644 --- a/test cases/common/183 partial dependency/meson.build +++ b/test cases/common/183 partial dependency/meson.build @@ -1,4 +1,4 @@ -# Copyright © 2018 Intel Corporation +# Copyright © 2018-2024 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,3 +15,6 @@ project('partial dependency', ['c', 'cpp']) subdir('declare_dependency') + +dep_zlib = dependency('zlib', required : false) +subdir('external_dependency', if_found : dep_zlib) diff --git a/test cases/common/98 subproject subdir/meson.build b/test cases/common/98 subproject subdir/meson.build index ef053d86c41c..d2bafedf5119 100644 --- a/test cases/common/98 subproject subdir/meson.build +++ b/test cases/common/98 subproject subdir/meson.build @@ -1,3 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2016-2023 The Meson Developers +# Copyright © 2024 Intel Corporation + project('proj', 'c') subproject('sub') libSub = dependency('sub', fallback: ['sub', 'libSub']) @@ -6,7 +10,19 @@ exe = executable('prog', 'prog.c', dependencies: libSub) test('subproject subdir', exe) # Verify the subproject has placed dependency override. -dependency('sub-1.0') +d = dependency('sub-1.0') + +# verify that the name is the overridden name +assert(d.name() == 'sub-1.0', 'name was not properly set, should have been "sub-1.0", but was @0@'.format(d.name())) + +# Verify that when a dependency object is used for two overrides, the correct +# name is used +meson.override_dependency('new-dep', d) +d2 = dependency('new-dep') +assert(d2.name() == 'new-dep', 'name was not properly set, should have been "new-dep", but was @0@'.format(d2.name())) + +# And that the old dependency wasn't changed +assert(d.name() == 'sub-1.0', 'original dependency was mutated.') # Verify we can now take 'sub' dependency without fallback, but only version 1.0. dependency('sub') From e2ab61627a2989b9c7e4c8062d681a8084bf5280 Mon Sep 17 00:00:00 2001 From: paugier Date: Wed, 4 Sep 2024 23:15:56 +0200 Subject: [PATCH 204/302] MPI detection: mpicc/mpiicc before pkg-config The standard way to compile MPI applications (recommanded by all MPI implementations) is to use the commands mpicc/mpiicc (and friends). Therefore, it is standard to just set PATH such that mpicc points towards a wrapper of the MPI implementation that one wants to use. In contrast, pkg-config is supported only by OpenMPI. Therefore, Meson has first to take into account the mpicc command to get chance to use mpicc of MPICH or IntelMPI in the case OpenMPI is installed (so that pkg-config would find it). --- mesonbuild/dependencies/mpi.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/mesonbuild/dependencies/mpi.py b/mesonbuild/dependencies/mpi.py index f9c911c29a2a..f97bb3311380 100644 --- a/mesonbuild/dependencies/mpi.py +++ b/mesonbuild/dependencies/mpi.py @@ -37,18 +37,6 @@ def mpi_factory(env: 'Environment', return [] compiler_is_intel = compiler.get_id() in {'intel', 'intel-cl'} - # Only OpenMPI has pkg-config, and it doesn't work with the intel compilers - if DependencyMethods.PKGCONFIG in methods and not compiler_is_intel: - pkg_name = None - if language == 'c': - pkg_name = 'ompi-c' - elif language == 'cpp': - pkg_name = 'ompi-cxx' - elif language == 'fortran': - pkg_name = 'ompi-fort' - candidates.append(functools.partial( - PkgConfigDependency, pkg_name, env, kwargs, language=language)) - if DependencyMethods.CONFIG_TOOL in methods: nwargs = kwargs.copy() @@ -90,6 +78,19 @@ def mpi_factory(env: 'Environment', candidates.append(functools.partial( MSMPIDependency, 'msmpi', env, kwargs, language=language)) + # Only OpenMPI has pkg-config, and it doesn't work with the intel compilers + # for MPI, environment variables and commands like mpicc should have priority + if DependencyMethods.PKGCONFIG in methods and not compiler_is_intel: + pkg_name = None + if language == 'c': + pkg_name = 'ompi-c' + elif language == 'cpp': + pkg_name = 'ompi-cxx' + elif language == 'fortran': + pkg_name = 'ompi-fort' + candidates.append(functools.partial( + PkgConfigDependency, pkg_name, env, kwargs, language=language)) + return candidates packages['mpi'] = mpi_factory From 901f5dfbf8899c80a4880a81cee91796bd697e71 Mon Sep 17 00:00:00 2001 From: paugier Date: Fri, 30 Aug 2024 17:29:10 +0200 Subject: [PATCH 205/302] MPI detection: support more implementations (any compilers) --- mesonbuild/dependencies/configtool.py | 40 ++++---- mesonbuild/dependencies/mpi.py | 131 +++++++++++++------------- 2 files changed, 87 insertions(+), 84 deletions(-) diff --git a/mesonbuild/dependencies/configtool.py b/mesonbuild/dependencies/configtool.py index f9ec5217a1e4..ef106a8b0acd 100644 --- a/mesonbuild/dependencies/configtool.py +++ b/mesonbuild/dependencies/configtool.py @@ -69,6 +69,21 @@ def _sanitize_version(self, version: str) -> str: return m.group(0).rstrip('.') return version + def _check_and_get_version(self, tool: T.List[str], returncode: int) -> T.Tuple[bool, T.Union[str, None]]: + """Check whether a command is valid and get its version""" + p, out = Popen_safe(tool + [self.version_arg])[:2] + valid = True + if p.returncode != returncode: + if self.skip_version: + # maybe the executable is valid even if it doesn't support --version + p = Popen_safe(tool + [self.skip_version])[0] + if p.returncode != returncode: + valid = False + else: + valid = False + version = self._sanitize_version(out.strip()) + return valid, version + def find_config(self, versions: T.List[str], returncode: int = 0) \ -> T.Tuple[T.Optional[T.List[str]], T.Optional[str]]: """Helper method that searches for config tool binaries in PATH and @@ -82,36 +97,29 @@ def find_config(self, versions: T.List[str], returncode: int = 0) \ continue tool = potential_bin.get_command() try: - p, out = Popen_safe(tool + [self.version_arg])[:2] + valid, version = self._check_and_get_version(tool, returncode) except (FileNotFoundError, PermissionError): continue - if p.returncode != returncode: - if self.skip_version: - # maybe the executable is valid even if it doesn't support --version - p = Popen_safe(tool + [self.skip_version])[0] - if p.returncode != returncode: - continue - else: - continue - - out = self._sanitize_version(out.strip()) + if not valid: + continue + # Some tools, like pcap-config don't supply a version, but also # don't fail with --version, in that case just assume that there is # only one version and return it. - if not out: + if not version: return (tool, None) if versions: - is_found = version_compare_many(out, versions)[0] + is_found = version_compare_many(version, versions)[0] # This allows returning a found version without a config tool, # which is useful to inform the user that you found version x, # but y was required. if not is_found: tool = None if best_match[1]: - if version_compare(out, '> {}'.format(best_match[1])): - best_match = (tool, out) + if version_compare(version, '> {}'.format(best_match[1])): + best_match = (tool, version) else: - best_match = (tool, out) + best_match = (tool, version) return best_match diff --git a/mesonbuild/dependencies/mpi.py b/mesonbuild/dependencies/mpi.py index f97bb3311380..14c2560cc898 100644 --- a/mesonbuild/dependencies/mpi.py +++ b/mesonbuild/dependencies/mpi.py @@ -9,6 +9,7 @@ import re from ..environment import detect_cpu_family +from ..mesonlib import Popen_safe from .base import DependencyMethods, detect_compiler, SystemDependency from .configtool import ConfigToolDependency from .detect import packages @@ -40,41 +41,43 @@ def mpi_factory(env: 'Environment', if DependencyMethods.CONFIG_TOOL in methods: nwargs = kwargs.copy() + # We try the environment variables for the tools first, but then + # fall back to the hardcoded names + + if language == 'c': + env_vars = ['MPICC'] + elif language == 'cpp': + env_vars = ['MPICXX'] + elif language == 'fortran': + env_vars = ['MPIFC', 'MPIF90', 'MPIF77'] + + tool_names = [os.environ.get(env_name) for env_name in env_vars] + tool_names = [t for t in tool_names if t] # remove empty environment variables + if compiler_is_intel: if env.machines[for_machine].is_windows(): - nwargs['version_arg'] = '-v' nwargs['returncode_value'] = 3 if language == 'c': - tool_names = [os.environ.get('I_MPI_CC'), 'mpiicc'] + tool_names.append('mpiicc') elif language == 'cpp': - tool_names = [os.environ.get('I_MPI_CXX'), 'mpiicpc'] + tool_names.append('mpiicpc') elif language == 'fortran': - tool_names = [os.environ.get('I_MPI_F90'), 'mpiifort'] + tool_names.append('mpiifort') - cls: T.Type[ConfigToolDependency] = IntelMPIConfigToolDependency - else: # OpenMPI, which doesn't work with intel - # - # We try the environment variables for the tools first, but then - # fall back to the hardcoded names - if language == 'c': - tool_names = [os.environ.get('MPICC'), 'mpicc'] - elif language == 'cpp': - tool_names = [os.environ.get('MPICXX'), 'mpic++', 'mpicxx', 'mpiCC'] - elif language == 'fortran': - tool_names = [os.environ.get(e) for e in ['MPIFC', 'MPIF90', 'MPIF77']] - tool_names.extend(['mpifort', 'mpif90', 'mpif77']) - - cls = OpenMPIConfigToolDependency - - tool_names = [t for t in tool_names if t] # remove empty environment variables - assert tool_names + # even with intel compilers, mpicc has to be considered + if language == 'c': + tool_names.append('mpicc') + elif language == 'cpp': + tool_names.extend(['mpic++', 'mpicxx', 'mpiCC']) + elif language == 'fortran': + tool_names.extend(['mpifort', 'mpif90', 'mpif77']) nwargs['tools'] = tool_names candidates.append(functools.partial( - cls, tool_names[0], env, nwargs, language=language)) + MPIConfigToolDependency, tool_names[0], env, nwargs, language=language)) - if DependencyMethods.SYSTEM in methods: + if DependencyMethods.SYSTEM in methods and env.machines[for_machine].is_windows(): candidates.append(functools.partial( MSMPIDependency, 'msmpi', env, kwargs, language=language)) @@ -96,7 +99,18 @@ def mpi_factory(env: 'Environment', packages['mpi'] = mpi_factory -class _MPIConfigToolDependency(ConfigToolDependency): +class MPIConfigToolDependency(ConfigToolDependency): + """Wrapper around mpicc, Intel's mpiicc and friends.""" + + def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any], + language: T.Optional[str] = None): + super().__init__(name, env, kwargs, language=language) + if not self.is_found: + return + + args = self.get_config_value(['-show'], 'link and compile args') + self.compile_args = self._filter_compile_args(args) + self.link_args = self._filter_link_args(args) def _filter_compile_args(self, args: T.List[str]) -> T.List[str]: """ @@ -147,53 +161,34 @@ def _is_link_arg(self, f: str) -> bool: f == '-pthread' or (f.startswith('-W') and f != '-Wall' and not f.startswith('-Werror'))) - -class IntelMPIConfigToolDependency(_MPIConfigToolDependency): - - """Wrapper around Intel's mpiicc and friends.""" - - version_arg = '-v' # --version is not the same as -v - - def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any], - language: T.Optional[str] = None): - super().__init__(name, env, kwargs, language=language) - if not self.is_found: - return - - args = self.get_config_value(['-show'], 'link and compile args') - self.compile_args = self._filter_compile_args(args) - self.link_args = self._filter_link_args(args) - - def _sanitize_version(self, out: str) -> str: - v = re.search(r'(\d{4}) Update (\d)', out) + def _check_and_get_version(self, tool: T.List[str], returncode: int) -> T.Tuple[bool, T.Union[str, None]]: + p, out = Popen_safe(tool + ['--showme:version'])[:2] + valid = p.returncode == returncode + if valid: + # OpenMPI + v = re.search(r'\d+.\d+.\d+', out) + if v: + version = v.group(0) + else: + version = None + return valid, version + + # --version is not the same as -v + p, out = Popen_safe(tool + ['-v'])[:2] + valid = p.returncode == returncode + out = out.split("\n", maxsplit=1)[0] + + # cases like "mpicc for MPICH version 4.2.2" + v = re.search(r'\d+.\d+.\d+', out) if v: - return '{}.{}'.format(v.group(1), v.group(2)) - return out - + return valid, v.group(0) -class OpenMPIConfigToolDependency(_MPIConfigToolDependency): - - """Wrapper around OpenMPI mpicc and friends.""" - - version_arg = '--showme:version' - - def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any], - language: T.Optional[str] = None): - super().__init__(name, env, kwargs, language=language) - if not self.is_found: - return - - c_args = self.get_config_value(['--showme:compile'], 'compile_args') - self.compile_args = self._filter_compile_args(c_args) - - l_args = self.get_config_value(['--showme:link'], 'link_args') - self.link_args = self._filter_link_args(l_args) - - def _sanitize_version(self, out: str) -> str: - v = re.search(r'\d+.\d+.\d+', out) + # cases like "mpigcc for Intel(R) MPI library 2021.13" + v = re.search(r'\d+.\d+', out) if v: - return v.group(0) - return out + return valid, v.group(0) + + return valid, None class MSMPIDependency(SystemDependency): From 179663523acd3f417f7fdefb83ec31244245d748 Mon Sep 17 00:00:00 2001 From: paugier Date: Mon, 2 Sep 2024 17:46:08 +0200 Subject: [PATCH 206/302] MPI detection: get version from old IntelMPI wrappers --- mesonbuild/dependencies/mpi.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/mesonbuild/dependencies/mpi.py b/mesonbuild/dependencies/mpi.py index 14c2560cc898..246b312330f0 100644 --- a/mesonbuild/dependencies/mpi.py +++ b/mesonbuild/dependencies/mpi.py @@ -176,18 +176,23 @@ def _check_and_get_version(self, tool: T.List[str], returncode: int) -> T.Tuple[ # --version is not the same as -v p, out = Popen_safe(tool + ['-v'])[:2] valid = p.returncode == returncode - out = out.split("\n", maxsplit=1)[0] + first_line = out.split('\n', maxsplit=1)[0] # cases like "mpicc for MPICH version 4.2.2" - v = re.search(r'\d+.\d+.\d+', out) + v = re.search(r'\d+.\d+.\d+', first_line) if v: return valid, v.group(0) # cases like "mpigcc for Intel(R) MPI library 2021.13" - v = re.search(r'\d+.\d+', out) + v = re.search(r'\d+.\d+', first_line) if v: return valid, v.group(0) + # cases like "mpiifort for the Intel(R) MPI Library 2019 Update 9 for Linux*" + v = re.search(r'(\d{4}) Update (\d)', first_line) + if v: + return valid, f'{v.group(1)}.{v.group(2)}' + return valid, None From c572879bc90e098678c4a1a408ba43ea74ed8595 Mon Sep 17 00:00:00 2001 From: paugier Date: Thu, 5 Sep 2024 10:23:51 +0200 Subject: [PATCH 207/302] MPI detection: try --showme:compile/--showme:link and -compile_info/-link_info --- mesonbuild/dependencies/mpi.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/mesonbuild/dependencies/mpi.py b/mesonbuild/dependencies/mpi.py index 246b312330f0..2d9e992f6f5a 100644 --- a/mesonbuild/dependencies/mpi.py +++ b/mesonbuild/dependencies/mpi.py @@ -10,7 +10,7 @@ from ..environment import detect_cpu_family from ..mesonlib import Popen_safe -from .base import DependencyMethods, detect_compiler, SystemDependency +from .base import DependencyException, DependencyMethods, detect_compiler, SystemDependency from .configtool import ConfigToolDependency from .detect import packages from .factory import factory_methods @@ -108,9 +108,21 @@ def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any], if not self.is_found: return - args = self.get_config_value(['-show'], 'link and compile args') - self.compile_args = self._filter_compile_args(args) - self.link_args = self._filter_link_args(args) + # --showme for OpenMPI, -compile_info/-link_info for MPICH and IntelMPI + for comp, link in [('--showme:compile', '--showme:link'), ('-compile_info', '-link_info'), ('-show', None)]: + try: + c_args = self.get_config_value([comp], 'compile_args') + l_args = self.get_config_value([link], 'link_args') if link is not None else c_args + except DependencyException: + continue + else: + break + else: + self.is_found = False + return + + self.compile_args = self._filter_compile_args(c_args) + self.link_args = self._filter_link_args(l_args) def _filter_compile_args(self, args: T.List[str]) -> T.List[str]: """ From 6797f9bc1502609783a8fc465e2960819ab4f38f Mon Sep 17 00:00:00 2001 From: Pierre Lamot Date: Wed, 12 Jun 2024 12:03:24 +0200 Subject: [PATCH 208/302] qt module: allow has_tools to specify which tools to check This allows checking for tools that may not be available in older version of qt or avoiding requesting tools that may not be necessary for a given project Co-authored-by: Nirbheek Chauhan --- docs/markdown/Qt6-module.md | 3 ++ docs/markdown/snippets/qt_has_tools_ignore.md | 12 ++++++ mesonbuild/modules/_qt.py | 27 ++++++++++--- test cases/frameworks/4 qt/meson.build | 38 +++++++++++-------- test cases/frameworks/4 qt/meson_options.txt | 1 + unittests/linuxliketests.py | 14 +++++++ 6 files changed, 74 insertions(+), 21 deletions(-) create mode 100644 docs/markdown/snippets/qt_has_tools_ignore.md diff --git a/docs/markdown/Qt6-module.md b/docs/markdown/Qt6-module.md index 673b4999630d..7b6f94715882 100644 --- a/docs/markdown/Qt6-module.md +++ b/docs/markdown/Qt6-module.md @@ -156,6 +156,9 @@ This method takes the following keyword arguments: `true` or an enabled [`feature`](Build-options.md#features) and some tools are missing Meson will abort. - `method` string: The method to use to detect Qt, see [[dependency]] +- `tools`: string[]: *Since 1.6.0*. List of tools to check. Testable tools + are `moc`, `uic`, `rcc` and `lrelease`. By default `tools` is set to `['moc', + 'uic', 'rcc', 'lrelease']` ## Dependencies diff --git a/docs/markdown/snippets/qt_has_tools_ignore.md b/docs/markdown/snippets/qt_has_tools_ignore.md new file mode 100644 index 000000000000..4def48db2b51 --- /dev/null +++ b/docs/markdown/snippets/qt_has_tools_ignore.md @@ -0,0 +1,12 @@ +## Tools can be selected when calling `has_tools()` on the Qt modules + +When checking for the presence of Qt tools, you can now explictly ask Meson +which tools you need. This is particularly useful when you do not need +`lrelease` because you are not shipping any translations. For example: + +```meson +qt6_mod = import('qt6') +qt6_mod.has_tools(required: true, tools: ['moc', 'uic', 'rcc']) +``` + +valid tools are `moc`, `uic`, `rcc` and `lrelease`. diff --git a/mesonbuild/modules/_qt.py b/mesonbuild/modules/_qt.py index ebb8a3994097..9f10c58266a5 100644 --- a/mesonbuild/modules/_qt.py +++ b/mesonbuild/modules/_qt.py @@ -27,6 +27,7 @@ from ..interpreter import kwargs from ..mesonlib import FileOrString from ..programs import ExternalProgram + from typing_extensions import Literal QtDependencyType = T.Union[QtPkgConfigDependency, QmakeQtDependency] @@ -80,6 +81,7 @@ class PreprocessKwArgs(TypedDict): class HasToolKwArgs(kwargs.ExtractRequired): method: str + tools: T.List[Literal['moc', 'uic', 'rcc', 'lrelease']] class CompileTranslationsKwArgs(TypedDict): @@ -91,10 +93,21 @@ class CompileTranslationsKwArgs(TypedDict): rcc_extra_arguments: T.List[str] ts_files: T.List[T.Union[str, File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList]] +def _list_in_set_validator(choices: T.Set[str]) -> T.Callable[[T.List[str]], T.Optional[str]]: + """Check that the choice given was one of the given set.""" + def inner(checklist: T.List[str]) -> T.Optional[str]: + invalid = set(checklist).difference(choices) + if invalid: + return f"invalid selections {', '.join(sorted(invalid))}, valid elements are {', '.join(sorted(choices))}." + return None + + return inner + class QtBaseModule(ExtensionModule): _tools_detected = False _rcc_supports_depfiles = False _moc_supports_depfiles = False + _set_of_qt_tools = {'moc', 'uic', 'rcc', 'lrelease'} def __init__(self, interpreter: 'Interpreter', qt_version: int = 5): ExtensionModule.__init__(self, interpreter) @@ -102,10 +115,7 @@ def __init__(self, interpreter: 'Interpreter', qt_version: int = 5): # It is important that this list does not change order as the order of # the returned ExternalPrograms will change as well self.tools: T.Dict[str, T.Union[ExternalProgram, build.Executable]] = { - 'moc': NonExistingExternalProgram('moc'), - 'uic': NonExistingExternalProgram('uic'), - 'rcc': NonExistingExternalProgram('rcc'), - 'lrelease': NonExistingExternalProgram('lrelease'), + tool: NonExistingExternalProgram(tool) for tool in self._set_of_qt_tools } self.methods.update({ 'has_tools': self.has_tools, @@ -258,6 +268,10 @@ def _parse_qrc_deps(self, state: 'ModuleState', 'qt.has_tools', KwargInfo('required', (bool, options.UserFeatureOption), default=False), KwargInfo('method', str, default='auto'), + KwargInfo('tools', ContainerTypeInfo(list, str), listify=True, + default=['moc', 'uic', 'rcc', 'lrelease'], + validator=_list_in_set_validator(_set_of_qt_tools), + since='1.6.0'), ) def has_tools(self, state: 'ModuleState', args: T.Tuple, kwargs: 'HasToolKwArgs') -> bool: method = kwargs.get('method', 'auto') @@ -269,8 +283,9 @@ def has_tools(self, state: 'ModuleState', args: T.Tuple, kwargs: 'HasToolKwArgs' mlog.log('qt.has_tools skipped: feature', mlog.bold(feature), 'disabled') return False self._detect_tools(state, method, required=False) - for tool in self.tools.values(): - if not tool.found(): + for tool in kwargs['tools']: + assert tool in self._set_of_qt_tools, f'tools must be in {self._set_of_qt_tools}' + if not self.tools[tool].found(): if required: raise MesonException('Qt tools not found') return False diff --git a/test cases/frameworks/4 qt/meson.build b/test cases/frameworks/4 qt/meson.build index 54cd7cb9bac3..58ec4d16f786 100644 --- a/test cases/frameworks/4 qt/meson.build +++ b/test cases/frameworks/4 qt/meson.build @@ -48,7 +48,13 @@ foreach qt : ['qt4', 'qt5', 'qt6'] qtdep = dependency(qt, modules : qt_modules, main : true, private_headers: true, required : required, method : get_option('method')) if qtdep.found() qtmodule = import(qt) - assert(qtmodule.has_tools(), 'You may be missing a devel package. (qttools5-dev-tools on Debian based systems)') + if get_option('expect_lrelease') + assert(qtmodule.has_tools(), 'You may be missing a devel package. (qttools5-dev-tools on Debian based systems)') + else + assert(not qtmodule.has_tools(), 'Unexpectedly found lrelease') + assert(not qtmodule.has_tools(tools: ['lrelease']), 'Unexpectedly found lrelease') + assert(qtmodule.has_tools(tools: ['moc', 'uic', 'rcc']), 'You may be missing a devel package. (qttools5-dev-tools on Debian based systems)') + endif # Test that fetching a variable works and yields a non-empty value assert(qtdep.get_variable('prefix', configtool: 'QT_INSTALL_PREFIX') != '') @@ -91,23 +97,25 @@ foreach qt : ['qt4', 'qt5', 'qt6'] # qt4-rcc and qt5-rcc take different arguments, for example qt4: ['-compress', '3']; qt5: '--compress=3' qtmodule.preprocess(qt + 'testrccarg', qresources : files(['stuff.qrc', 'stuff2.qrc']), rcc_extra_arguments : '--compress=3', method : get_option('method')) - translations_cpp = qtmodule.compile_translations(qresource: qt+'_lang.qrc') - # unity builds suck and definitely cannot handle two qrc embeds in one compilation unit - unityproof_translations = static_library(qt+'unityproof_translations', translations_cpp, dependencies: qtdep) + if get_option('expect_lrelease') + translations_cpp = qtmodule.compile_translations(qresource: qt+'_lang.qrc') + # unity builds suck and definitely cannot handle two qrc embeds in one compilation unit + unityproof_translations = static_library(qt+'unityproof_translations', translations_cpp, dependencies: qtdep) - extra_cpp_args += '-DQT="@0@"'.format(qt) - qexe = executable(qt + 'app', - sources : ['main.cpp', 'mainWindow.cpp', # Sources that don't need preprocessing. - prep, prep_rcc], - dependencies : qtdep, - link_with: unityproof_translations, - cpp_args: extra_cpp_args, - gui_app : true) + extra_cpp_args += '-DQT="@0@"'.format(qt) + qexe = executable(qt + 'app', + sources : ['main.cpp', 'mainWindow.cpp', # Sources that don't need preprocessing. + prep, prep_rcc], + dependencies : qtdep, + link_with: unityproof_translations, + cpp_args: extra_cpp_args, + gui_app : true) - # We need a console test application because some test environments - # do not have an X server. + # We need a console test application because some test environments + # do not have an X server. - translations = qtmodule.compile_translations(ts_files : qt+'core_fr.ts', build_by_default : true) + translations = qtmodule.compile_translations(ts_files : qt+'core_fr.ts', build_by_default : true) + endif qtcore = dependency(qt, modules : 'Core', method : get_option('method')) diff --git a/test cases/frameworks/4 qt/meson_options.txt b/test cases/frameworks/4 qt/meson_options.txt index 223f4fb0b05f..9a7513434012 100644 --- a/test cases/frameworks/4 qt/meson_options.txt +++ b/test cases/frameworks/4 qt/meson_options.txt @@ -1,2 +1,3 @@ option('method', type : 'string', value : 'auto', description : 'The method to use to find Qt') option('required', type : 'string', value : 'qt5', description : 'The version of Qt which is required to be present') +option('expect_lrelease', type: 'boolean', value: true) diff --git a/unittests/linuxliketests.py b/unittests/linuxliketests.py index f92c992cc613..bf0437bca582 100644 --- a/unittests/linuxliketests.py +++ b/unittests/linuxliketests.py @@ -36,6 +36,7 @@ from mesonbuild.compilers.objc import AppleClangObjCCompiler from mesonbuild.compilers.objcpp import AppleClangObjCPPCompiler from mesonbuild.dependencies.pkgconfig import PkgConfigDependency, PkgConfigCLI, PkgConfigInterface +from mesonbuild.programs import NonExistingExternalProgram import mesonbuild.modules.pkgconfig PKG_CONFIG = os.environ.get('PKG_CONFIG', 'pkg-config') @@ -317,6 +318,19 @@ def test_generate_gir_with_address_sanitizer(self): self.init(testdir, extra_args=['-Db_sanitize=address', '-Db_lundef=false']) self.build() + def test_qt5dependency_no_lrelease(self): + ''' + Test that qt5 detection with qmake works. This can't be an ordinary + test case because it involves setting the environment. + ''' + testdir = os.path.join(self.framework_test_dir, '4 qt') + def _no_lrelease(self, prog, *args, **kwargs): + if 'lrelease' in prog: + return NonExistingExternalProgram(prog) + return self._interpreter.find_program_impl(prog, *args, **kwargs) + with mock.patch.object(mesonbuild.modules.ModuleState, 'find_program', _no_lrelease): + self.init(testdir, inprocess=True, extra_args=['-Dmethod=qmake', '-Dexpect_lrelease=false']) + def test_qt5dependency_qmake_detection(self): ''' Test that qt5 detection with qmake works. This can't be an ordinary From 798bf519035808aa4d86e6b58d7a6b3c5e4b2988 Mon Sep 17 00:00:00 2001 From: Andrei Alexeyev Date: Wed, 27 Sep 2023 11:43:23 +0200 Subject: [PATCH 209/302] linkers: basic support for the 'zig cc' linker --- docs/markdown/Reference-tables.md | 1 + docs/markdown/snippets/zig_ld.md | 18 ++++++++++++++++++ mesonbuild/linkers/detect.py | 3 +++ mesonbuild/linkers/linkers.py | 7 +++++++ 4 files changed, 29 insertions(+) create mode 100644 docs/markdown/snippets/zig_ld.md diff --git a/docs/markdown/Reference-tables.md b/docs/markdown/Reference-tables.md index 7e0d6cffc256..e4e964c2d3d7 100644 --- a/docs/markdown/Reference-tables.md +++ b/docs/markdown/Reference-tables.md @@ -62,6 +62,7 @@ These are return values of the `get_linker_id` method in a compiler object. | ld.mold | The fast MOLD linker | | ld.solaris | Solaris and illumos | | ld.wasm | emscripten's wasm-ld linker | +| ld.zigcc | The Zig linker (C/C++ frontend; GNU-like) | | ld64 | Apple ld64 | | ld64.lld | The LLVM linker, with the ld64 interface | | link | MSVC linker | diff --git a/docs/markdown/snippets/zig_ld.md b/docs/markdown/snippets/zig_ld.md new file mode 100644 index 000000000000..8835c38ca4f7 --- /dev/null +++ b/docs/markdown/snippets/zig_ld.md @@ -0,0 +1,18 @@ +## Zig 0.11 can be used as a C/C++ compiler frontend + +Zig offers +[a C/C++ frontend](https://andrewkelley.me/post/zig-cc-powerful-drop-in-replacement-gcc-clang.html) as a drop-in replacement for Clang. It worked fine with Meson up to Zig 0.10. Since 0.11, Zig's +dynamic linker reports itself as `zig ld`, which wasn't known to Meson. Meson now correctly handles +Zig's linker. + +You can use Zig's frontend via a [machine file](Machine-files.md): + +```ini +[binaries] +c = ['zig', 'cc'] +cpp = ['zig', 'c++'] +ar = ['zig', 'ar'] +ranlib = ['zig', 'ranlib'] +lib = ['zig', 'lib'] +dlltool = ['zig', 'dlltool'] +``` diff --git a/mesonbuild/linkers/detect.py b/mesonbuild/linkers/detect.py index 0dce5ad501b1..e928f3e0d5c8 100644 --- a/mesonbuild/linkers/detect.py +++ b/mesonbuild/linkers/detect.py @@ -236,6 +236,9 @@ def guess_nix_linker(env: 'Environment', compiler: T.List[str], comp_class: T.Ty linker = linkers.AIXDynamicLinker( compiler, for_machine, comp_class.LINKER_PREFIX, override, version=search_version(e)) + elif o.startswith('zig ld'): + linker = linkers.ZigCCDynamicLinker( + compiler, for_machine, comp_class.LINKER_PREFIX, override, version=v) else: __failed_to_detect_linker(compiler, check_args, o, e) return linker diff --git a/mesonbuild/linkers/linkers.py b/mesonbuild/linkers/linkers.py index d011e67b9c54..e401d7c9aa61 100644 --- a/mesonbuild/linkers/linkers.py +++ b/mesonbuild/linkers/linkers.py @@ -938,6 +938,13 @@ def get_win_subsystem_args(self, value: str) -> T.List[str]: raise mesonlib.MesonBugException(f'win_subsystem: {value} not handled in lld linker. This should not be possible.') +class ZigCCDynamicLinker(LLVMDynamicLinker): + id = 'ld.zigcc' + + def get_thinlto_cache_args(self, path: str) -> T.List[str]: + return [] + + class WASMDynamicLinker(GnuLikeDynamicLinkerMixin, PosixDynamicLinkerMixin, DynamicLinker): """Emscripten's wasm-ld.""" From f3daf6265aa412c2d54784100c8618e9008a2f9d Mon Sep 17 00:00:00 2001 From: Tristan Ross Date: Tue, 30 Jul 2024 18:50:19 -0700 Subject: [PATCH 210/302] linkers: Disable -rpath-link with ld.zigcc Zig issue https://github.com/ziglang/zig/issues/18713 --- mesonbuild/linkers/linkers.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mesonbuild/linkers/linkers.py b/mesonbuild/linkers/linkers.py index e401d7c9aa61..dc42b3a2032f 100644 --- a/mesonbuild/linkers/linkers.py +++ b/mesonbuild/linkers/linkers.py @@ -708,7 +708,9 @@ def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str, args.extend(self._apply_prefix('-rpath,' + paths)) # TODO: should this actually be "for solaris/sunos"? - if mesonlib.is_sunos(): + # NOTE: Remove the zigcc check once zig support "-rpath-link" + # See https://github.com/ziglang/zig/issues/18713 + if mesonlib.is_sunos() or self.id == 'ld.zigcc': return (args, rpath_dirs_to_remove) # Rpaths to use while linking must be absolute. These are not From 8eaeff5b1f3057f827dfc95ac3987903c9bcb828 Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Tue, 20 Aug 2024 08:59:37 -0500 Subject: [PATCH 211/302] clang-tidy: Avoid spawning too many threads The clang-tidy-fix target uses run-clang-tidy to do the fixing, however this script itself spawns `os.cpu_count()` threads as part of its internal parallelism. When combined with Meson's parallelism this results in the creation of potentially thousands of unecessary threads. This commit rewrites the clang-tidy-fix to perform the same task run-clang-tidy does but exclusively on Meson's thread pool. "Fix-it" snippets are saved to `meson-private/clang-tidy-fix/` by a parallel clang-tidy phase, afterwards (to avoid races) all collected fixes are applied with a single call to clang-apply-replacements. --- mesonbuild/backend/ninjabackend.py | 5 +-- mesonbuild/environment.py | 26 ++++++++++++++++ mesonbuild/scripts/clangtidy.py | 50 +++++++++++++++++++++++++----- 3 files changed, 72 insertions(+), 9 deletions(-) diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index d8995f031eea..6eb1f1d0191d 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -3666,10 +3666,11 @@ def generate_clangformat(self) -> None: self.generate_clangtool('format', 'check') def generate_clangtidy(self) -> None: - import shutil - if not shutil.which('clang-tidy'): + if not environment.detect_clangtidy(): return self.generate_clangtool('tidy') + if not environment.detect_clangapply(): + return self.generate_clangtool('tidy', 'fix') def generate_tags(self, tool: str, target_name: str) -> None: diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 90c9bb911c5e..71a2f3afcb6a 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -275,6 +275,32 @@ def detect_clangformat() -> T.List[str]: return [path] return [] +def detect_clangtidy() -> T.List[str]: + """ Look for clang-tidy binary on build platform + + Return: a single-element list of the found clang-tidy binary ready to be + passed to Popen() + """ + tools = get_llvm_tool_names('clang-tidy') + for tool in tools: + path = shutil.which(tool) + if path is not None: + return [path] + return [] + +def detect_clangapply() -> T.List[str]: + """ Look for clang-apply-replacements binary on build platform + + Return: a single-element list of the found clang-apply-replacements binary + ready to be passed to Popen() + """ + tools = get_llvm_tool_names('clang-apply-replacements') + for tool in tools: + path = shutil.which(tool) + if path is not None: + return [path] + return [] + def detect_windows_arch(compilers: CompilersDict) -> str: """ Detecting the 'native' architecture of Windows is not a trivial task. We diff --git a/mesonbuild/scripts/clangtidy.py b/mesonbuild/scripts/clangtidy.py index 1e0c4a5a396a..a922f8514062 100644 --- a/mesonbuild/scripts/clangtidy.py +++ b/mesonbuild/scripts/clangtidy.py @@ -6,15 +6,22 @@ import argparse import subprocess from pathlib import Path +import tempfile +import os +import shutil +import sys from .run_tool import run_tool +from ..environment import detect_clangtidy, detect_clangapply import typing as T -def run_clang_tidy(fname: Path, builddir: Path) -> subprocess.CompletedProcess: - return subprocess.run(['clang-tidy', '-quiet', '-p', str(builddir), str(fname)]) - -def run_clang_tidy_fix(fname: Path, builddir: Path) -> subprocess.CompletedProcess: - return subprocess.run(['run-clang-tidy', '-fix', '-format', '-quiet', '-p', str(builddir), str(fname)]) +def run_clang_tidy(fname: Path, tidyexe: list, builddir: Path, fixesdir: T.Optional[Path]) -> subprocess.CompletedProcess: + args = [] + if fixesdir is not None: + handle, name = tempfile.mkstemp(prefix=fname.name + '.', suffix='.yaml', dir=fixesdir) + os.close(handle) + args.extend(['-export-fixes', name]) + return subprocess.run(tidyexe + args + ['-quiet', '-p', str(builddir), str(fname)]) def run(args: T.List[str]) -> int: parser = argparse.ArgumentParser() @@ -26,5 +33,34 @@ def run(args: T.List[str]) -> int: srcdir = Path(options.sourcedir) builddir = Path(options.builddir) - run_func = run_clang_tidy_fix if options.fix else run_clang_tidy - return run_tool('clang-tidy', srcdir, builddir, run_func, builddir) + tidyexe = detect_clangtidy() + if not tidyexe: + print(f'Could not execute clang-tidy "{" ".join(tidyexe)}"') + return 1 + + fixesdir: T.Optional[Path] = None + if options.fix: + applyexe = detect_clangapply() + if not applyexe: + print(f'Could not execute clang-apply-replacements "{" ".join(applyexe)}"') + return 1 + + fixesdir = builddir / 'meson-private' / 'clang-tidy-fix' + if fixesdir.is_dir(): + shutil.rmtree(fixesdir) + elif fixesdir.exists(): + fixesdir.unlink() + fixesdir.mkdir(parents=True) + + tidyret = run_tool('clang-tidy', srcdir, builddir, run_clang_tidy, tidyexe, builddir, fixesdir) + if fixesdir is not None: + print('Applying fix-its...') + applyret = subprocess.run(applyexe + ['-format', '-style=file', '-ignore-insert-conflict', fixesdir]).returncode + + if tidyret != 0: + print('Errors encountered while running clang-tidy', file=sys.stderr) + return tidyret + if fixesdir is not None and applyret != 0: + print('Errors encountered while running clang-apply-replacements', file=sys.stderr) + return applyret + return 0 From 1aac6cc1ec380a14519822d1a2bdf3e5850de68b Mon Sep 17 00:00:00 2001 From: Florent Valette Date: Tue, 30 Jul 2024 11:36:50 +0200 Subject: [PATCH 212/302] compiler,rust: fix sanity check and internal deps for baremetal rust project/target Sanity check for bare metal rust wasn't working for a while and there is a pending PR (#12175). To workaround this problem, we used to let sanity check for build machine and manually defined rustc target. Commit 18f8aeda8b59a132f24fa1af800ff65cac2f61f4 breaks this workaround as, even without an exe_wrapper, native_static_libs are appends as internal deps. This behaviour makes sense for cross compiled rust in a rich environment but not any for no-std rust. As said in comments, one can't tell if the code is no-std or not because this is an annotation from sources. From our point of view, it is pretty clear that building a no-std rust target means that one has to define system='bare metal' and kernel='none' in his cross-file. According to that, sanity_check for rust compiler is modified to handle kernel == 'none' case by building a specific no-std rust snippet, with an extra args if rust_ld is ls.bfd (in order to prevent the linker to link with a potentially non existing startfile for the given target). 'native_static_libs' is also leave empty in that very case. This commit fix the spurious native static libs for no-std case and allow us to remove our dirty workaround which by-passed non working sanity check for bare metal rust. One who wants to use meson for baremetal Rust project only have to define the rust target in their cross file. e.g. rust = ['rustc', '--target', ''] --- mesonbuild/build.py | 5 +++++ mesonbuild/compilers/rust.py | 36 ++++++++++++++++++++++++++++++------ 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 5eff0ed805c5..460ed549be92 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -2133,6 +2133,11 @@ def post_init(self) -> None: if self.rust_crate_type == 'staticlib': # FIXME: In the case of no-std we should not add those libraries, # but we have no way to know currently. + + # XXX: + # In the case of no-std, we are likely in a bare metal case + # and thus, machine_info kernel should be set to 'none'. + # In that case, native_static_libs list is empty. rustc = self.compilers['rust'] d = dependencies.InternalDependency('undefined', [], [], rustc.native_static_libs, diff --git a/mesonbuild/compilers/rust.py b/mesonbuild/compilers/rust.py index d071559da118..f09911db642c 100644 --- a/mesonbuild/compilers/rust.py +++ b/mesonbuild/compilers/rust.py @@ -76,13 +76,33 @@ def needs_static_linker(self) -> bool: def sanity_check(self, work_dir: str, environment: 'Environment') -> None: source_name = os.path.join(work_dir, 'sanity.rs') output_name = os.path.join(work_dir, 'rusttest') - with open(source_name, 'w', encoding='utf-8') as ofile: - ofile.write(textwrap.dedent( - '''fn main() { - } - ''')) + cmdlist = self.exelist.copy() - cmdlist = self.exelist + ['-o', output_name, source_name] + with open(source_name, 'w', encoding='utf-8') as ofile: + # If machine kernel is not `none`, try to compile a dummy program. + # If 'none', this is likely a `no-std`(i.e. bare metal) project. + if self.info.kernel != 'none': + ofile.write(textwrap.dedent( + '''fn main() { + } + ''')) + else: + # If rustc linker is gcc, add `-nostartfiles` + if 'ld.' in self.linker.id: + cmdlist.extend(['-C', 'link-arg=-nostartfiles']) + ofile.write(textwrap.dedent( + '''#![no_std] + #![no_main] + #[no_mangle] + pub fn _start() { + } + #[panic_handler] + fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} + } + ''')) + + cmdlist.extend(['-o', output_name, source_name]) pc, stdo, stde = Popen_safe_logged(cmdlist, cwd=work_dir) if pc.returncode != 0: raise EnvironmentException(f'Rust compiler {self.name_string()} cannot compile programs.') @@ -107,6 +127,10 @@ def _native_static_libs(self, work_dir: str, source_name: str) -> None: raise EnvironmentException('Rust compiler cannot compile staticlib.') match = re.search('native-static-libs: (.*)$', stde, re.MULTILINE) if not match: + if self.info.kernel == 'none': + # no match and kernel == none (i.e. baremetal) is a valid use case. + # return and let native_static_libs list empty + return raise EnvironmentException('Failed to find native-static-libs in Rust compiler output.') # Exclude some well known libraries that we don't need because they # are always part of C/C++ linkers. Rustc probably should not print From c3597520992b0743c7a954416bc414de9cf57ce8 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Mon, 23 Sep 2024 19:27:41 +0100 Subject: [PATCH 213/302] env2mfile: Fix a typo Debian cross architectures are detected via dpkg-architecture, not via dpkg-reconfigure. Signed-off-by: Simon McVittie --- mesonbuild/scripts/env2mfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/scripts/env2mfile.py b/mesonbuild/scripts/env2mfile.py index bc0101e26d5b..c6f22ae7600c 100755 --- a/mesonbuild/scripts/env2mfile.py +++ b/mesonbuild/scripts/env2mfile.py @@ -330,7 +330,7 @@ def detect_cross_system(infos: MachineInfo, options: T.Any) -> None: def detect_cross_env(options: T.Any) -> MachineInfo: if options.debarch: - print('Detecting cross environment via dpkg-reconfigure.') + print('Detecting cross environment via dpkg-architecture.') infos = detect_cross_debianlike(options) else: print('Detecting cross environment via environment variables.') From b7ce7c2d39cb537d9158e24e458ee5ce293a7bd3 Mon Sep 17 00:00:00 2001 From: Alan Coopersmith Date: Tue, 24 Sep 2024 12:42:13 -0700 Subject: [PATCH 214/302] linkers: Fix linker detection with clang on Solaris Fixes: #13711 --- mesonbuild/linkers/detect.py | 45 ++++++++++++++++++---------------- unittests/allplatformstests.py | 2 ++ 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/mesonbuild/linkers/detect.py b/mesonbuild/linkers/detect.py index e928f3e0d5c8..493430a87cee 100644 --- a/mesonbuild/linkers/detect.py +++ b/mesonbuild/linkers/detect.py @@ -186,27 +186,6 @@ def guess_nix_linker(env: 'Environment', compiler: T.List[str], comp_class: T.Ty v = search_version(o) linker = linkers.LLVMDynamicLinker(compiler, for_machine, comp_class.LINKER_PREFIX, override, version=v) - # detect xtools first, bug #10805 - elif 'xtools-' in o.split('\n', maxsplit=1)[0]: - xtools = o.split(' ', maxsplit=1)[0] - v = xtools.split('-', maxsplit=2)[1] - linker = linkers.AppleDynamicLinker(compiler, for_machine, comp_class.LINKER_PREFIX, override, version=v) - # First might be apple clang, second is for real gcc, the third is icc. - # Note that "ld: unknown option: " sometimes instead is "ld: unknown options:". - elif e.endswith('(use -v to see invocation)\n') or 'macosx_version' in e or 'ld: unknown option' in e: - if isinstance(comp_class.LINKER_PREFIX, str): - cmd = compiler + [comp_class.LINKER_PREFIX + '-v'] + extra_args - else: - cmd = compiler + comp_class.LINKER_PREFIX + ['-v'] + extra_args - _, newo, newerr = Popen_safe_logged(cmd, msg='Detecting Apple linker via') - - for line in newerr.split('\n'): - if 'PROJECT:ld' in line or 'PROJECT:dyld' in line: - v = line.split('-')[1] - break - else: - __failed_to_detect_linker(compiler, check_args, o, e) - linker = linkers.AppleDynamicLinker(compiler, for_machine, comp_class.LINKER_PREFIX, override, version=v) elif 'GNU' in o or 'GNU' in e: gnu_cls: T.Type[GnuDynamicLinker] # this is always the only thing on stdout, except for swift @@ -239,6 +218,30 @@ def guess_nix_linker(env: 'Environment', compiler: T.List[str], comp_class: T.Ty elif o.startswith('zig ld'): linker = linkers.ZigCCDynamicLinker( compiler, for_machine, comp_class.LINKER_PREFIX, override, version=v) + # detect xtools first, bug #10805 + elif 'xtools-' in o.split('\n', maxsplit=1)[0]: + xtools = o.split(' ', maxsplit=1)[0] + v = xtools.split('-', maxsplit=2)[1] + linker = linkers.AppleDynamicLinker(compiler, for_machine, comp_class.LINKER_PREFIX, override, version=v) + # detect linker on MacOS - must be after other platforms because the + # "(use -v to see invocation)" will match clang on other platforms, + # but the rest of the checks will fail and call __failed_to_detect_linker. + # First might be apple clang, second is for real gcc, the third is icc. + # Note that "ld: unknown option: " sometimes instead is "ld: unknown options:". + elif e.endswith('(use -v to see invocation)\n') or 'macosx_version' in e or 'ld: unknown option' in e: + if isinstance(comp_class.LINKER_PREFIX, str): + cmd = compiler + [comp_class.LINKER_PREFIX + '-v'] + extra_args + else: + cmd = compiler + comp_class.LINKER_PREFIX + ['-v'] + extra_args + _, newo, newerr = Popen_safe_logged(cmd, msg='Detecting Apple linker via') + + for line in newerr.split('\n'): + if 'PROJECT:ld' in line or 'PROJECT:dyld' in line: + v = line.split('-')[1] + break + else: + __failed_to_detect_linker(compiler, check_args, o, e) + linker = linkers.AppleDynamicLinker(compiler, for_machine, comp_class.LINKER_PREFIX, override, version=v) else: __failed_to_detect_linker(compiler, check_args, o, e) return linker diff --git a/unittests/allplatformstests.py b/unittests/allplatformstests.py index 3be97cb3b613..ca4b194e6180 100644 --- a/unittests/allplatformstests.py +++ b/unittests/allplatformstests.py @@ -1129,6 +1129,8 @@ def test_compiler_detection(self): # ld-like linker of link.exe-like linker (usually the # former for msys2, the latter otherwise) self.assertIsInstance(cc.linker, (linkers.MSVCDynamicLinker, linkers.GnuLikeDynamicLinkerMixin)) + elif is_sunos(): + self.assertIsInstance(cc.linker, (linkers.SolarisDynamicLinker, linkers.GnuLikeDynamicLinkerMixin)) else: self.assertIsInstance(cc.linker, linkers.GnuLikeDynamicLinkerMixin) if isinstance(cc, intel): From 83b2968118ca6dae1444267b2651d2d9a2efd07f Mon Sep 17 00:00:00 2001 From: Elliot Date: Sun, 22 Sep 2024 12:51:31 -0400 Subject: [PATCH 215/302] Don't fail to package when run twice Guards against exit when the default nuget source is already installed, or when wix is installed but not the wix ui toolset. --- packaging/createmsi.py | 44 ++++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/packaging/createmsi.py b/packaging/createmsi.py index 77667fe68a36..bb2fade72e70 100755 --- a/packaging/createmsi.py +++ b/packaging/createmsi.py @@ -20,6 +20,8 @@ # Elementtree does not support CDATA. So hack it. WINVER_CHECK = 'Installed OR (VersionNT64 > 602)>' +NUGET_INDEX = 'https://api.nuget.org/v3/index.json' +WIXEXT_TOOL = 'WixToolset.UI.wixext' def gen_guid(): ''' @@ -302,28 +304,50 @@ def build_package(self): ]) +def is_nuget_source_active(): + ''' + Check if nuget source is active + ''' + result = subprocess.run(['dotnet', 'nuget', 'list', 'source', '--format', 'Short'], stdout=subprocess.PIPE) + return f'E {NUGET_INDEX}' in result.stdout.decode('utf-8') + +def is_wixext_installed(): + ''' + Check if wix extension is installed + ''' + result = subprocess.run(['wix', 'extension', 'list'], stdout=subprocess.PIPE) + return WIXEXT_TOOL in result.stdout.decode('utf-8') + def install_wix(): - subprocess.check_call(['dotnet', - 'nuget', - 'add', - 'source', - 'https://api.nuget.org/v3/index.json']) + # Check if nuget source is active before trying to add it + # dotnet nuget add source returns non-zero if the source already exists + if not is_nuget_source_active(): + subprocess.check_call(['dotnet', + 'nuget', + 'add', + 'source', + NUGET_INDEX]) + subprocess.check_call(['dotnet', 'tool', 'install', '--global', 'wix']) - subprocess.check_call(['wix', - 'extension', - 'add', - 'WixToolset.UI.wixext', - ]) if __name__ == '__main__': if not os.path.exists('meson.py'): sys.exit(print('Run me in the top level source dir.')) if not shutil.which('wix'): install_wix() + + # Install wixext if not installed + if not is_wixext_installed(): + subprocess.check_call(['wix', + 'extension', + 'add', + WIXEXT_TOOL, + ]) + subprocess.check_call(['pip', 'install', '--upgrade', 'pyinstaller']) p = PackageGenerator() From 790c43debe884ddd9fea4f73e6da4b0cc07fe934 Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Sun, 29 Sep 2024 14:20:36 -0400 Subject: [PATCH 216/302] docs: update the Visual Studio guide for the post-0.59 era with automatic vsenv For many years now, meson hasn't required manually entering a Visual Studio command prompt but has autodetected it. This confuses some readers of this outdated documentation into thinking it is much harder than it is. --- docs/markdown/Using-with-Visual-Studio.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/docs/markdown/Using-with-Visual-Studio.md b/docs/markdown/Using-with-Visual-Studio.md index 2680e8baf989..c6a0806a5bd1 100644 --- a/docs/markdown/Using-with-Visual-Studio.md +++ b/docs/markdown/Using-with-Visual-Studio.md @@ -5,9 +5,17 @@ short-description: How to use Meson in Visual Studio # Using with Visual Studio In order to generate Visual Studio projects, Meson needs to know the -settings of your installed version of Visual Studio. The only way to -get this information is to run Meson under the Visual Studio Command -Prompt. +settings of your installed version of Visual Studio. + + +The traditional way to get this information is to run Meson (or any build +system) under the Visual Studio Command Prompt. + +If no Visual Studio Command Prompt was detected, and no mingw compilers are +detected either, meson will attempt to find "a" Visual Studio installation for +you automatically, by asking Microsoft's "vswhere" program. If you want to +ignore mingw compilers, pass the `--vsenv` option on the meson command line. +If you need to guarantee a specific Visual Studio version, set it up manually. You can always find the Visual Studio Command Prompt by searching from the Start Menu. However, the name is different for each Visual Studio From 3f135284c7d830fd5b7c7c8061dca227c87326a4 Mon Sep 17 00:00:00 2001 From: mid-kid Date: Sun, 29 Sep 2024 09:25:59 +0200 Subject: [PATCH 217/302] metrowerks: Fix compute_parameters_with_absolute_paths --- mesonbuild/compilers/mixins/metrowerks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/compilers/mixins/metrowerks.py b/mesonbuild/compilers/mixins/metrowerks.py index 8934e8376f42..561b50ceaefe 100644 --- a/mesonbuild/compilers/mixins/metrowerks.py +++ b/mesonbuild/compilers/mixins/metrowerks.py @@ -275,6 +275,6 @@ def _unix_args_to_native(cls, args: T.List[str], info: MachineInfo) -> T.List[st def compute_parameters_with_absolute_paths(self, parameter_list: T.List[str], build_dir: str) -> T.List[str]: for idx, i in enumerate(parameter_list): if i[:2] == '-I': - parameter_list[idx] = i[:9] + os.path.normpath(os.path.join(build_dir, i[9:])) + parameter_list[idx] = i[:2] + os.path.normpath(os.path.join(build_dir, i[2:])) return parameter_list From aed67bbb685a4d70451e34d993574e31f91386b8 Mon Sep 17 00:00:00 2001 From: mid-kid Date: Sun, 29 Sep 2024 09:37:25 +0200 Subject: [PATCH 218/302] metrowerks: Whine when trying to build a shared library Also cleaned up redundant functions in the subclass. --- mesonbuild/linkers/linkers.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/mesonbuild/linkers/linkers.py b/mesonbuild/linkers/linkers.py index dc42b3a2032f..c4df0fa1d893 100644 --- a/mesonbuild/linkers/linkers.py +++ b/mesonbuild/linkers/linkers.py @@ -1637,9 +1637,6 @@ def get_allow_undefined_args(self) -> T.List[str]: def get_accepts_rsp(self) -> bool: return True - def get_lib_prefix(self) -> str: - return "" - def get_linker_always_args(self) -> T.List[str]: return [] @@ -1652,8 +1649,9 @@ def get_search_args(self, dirname: str) -> T.List[str]: def invoked_by_compiler(self) -> bool: return False - def rsp_file_syntax(self) -> RSPFileSyntax: - return RSPFileSyntax.GCC + def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str, + suffix: str, soversion: str, darwin_versions: T.Tuple[str, str]) -> T.List[str]: + raise MesonException(f'{self.id} does not support shared libraries.') class MetrowerksLinkerARM(MetrowerksLinker): From ddc03e5ab3449efcded44ac35e3d6934bdc85c1e Mon Sep 17 00:00:00 2001 From: mid-kid Date: Sun, 29 Sep 2024 12:51:17 +0200 Subject: [PATCH 219/302] metrowerks: Pass warning flags to all subtools The "on" option is documented as passing the warning flags to all subtools, and implies "most". The default in the majority of projects is -warnings on,nocmdline, which I'd take to be the equivalent of -Wall -Wextra, there isn't really an inbetween. --- mesonbuild/compilers/mixins/metrowerks.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/mesonbuild/compilers/mixins/metrowerks.py b/mesonbuild/compilers/mixins/metrowerks.py index 561b50ceaefe..60982212e241 100644 --- a/mesonbuild/compilers/mixins/metrowerks.py +++ b/mesonbuild/compilers/mixins/metrowerks.py @@ -179,13 +179,12 @@ def __init__(self) -> None: self.base_options = { OptionKey(o) for o in ['b_pch', 'b_ndebug']} - default_warn_args: T.List[str] = [] self.warn_args: T.Dict[str, T.List[str]] = { - '0': ['-w', 'off'], - '1': default_warn_args, - '2': default_warn_args + ['-w', 'most'], - '3': default_warn_args + ['-w', 'all'], - 'everything': default_warn_args + ['-w', 'full']} + '0': ['-warnings', 'off'], + '1': [], + '2': ['-warnings', 'on,nocmdline'], + '3': ['-warnings', 'on,all'], + 'everything': ['-warnings', 'on,full']} def depfile_for_object(self, objfile: str) -> T.Optional[str]: # Earlier versions of these compilers do not support specifying From 5399d3de02cb0f92e334f3f5f61cf0aa8521ac63 Mon Sep 17 00:00:00 2001 From: Raul Tambre Date: Mon, 30 Sep 2024 16:29:40 +0300 Subject: [PATCH 220/302] compilers/detect: remove unsupported -cpp flag for Clang preprocessor detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clang's resource files, e.g. /usr/share/clang/clang++.cfg, can be used to bump the default standard level across the system. However due to llvm/llvm-project#61641 `clang++ -std=c++17 -E -dM -` doesn't work. The workaround is to pass the language explicitly. 4ad792e158b6059eb847dd0562aff9bd7029981f fixed the issue by passing the language explicitly, but started passing the `-cpp` flag, which Clang doesn't support. Basically Clang would always fallback to the second detection attempt as a result. Remove the unsupported flag and the above scenarios works now too. 🙂 See-also: https://github.com/llvm/llvm-project/issues/61641 Fixes: 4ad792e158b6059eb847dd0562aff9bd7029981f --- mesonbuild/compilers/detect.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/mesonbuild/compilers/detect.py b/mesonbuild/compilers/detect.py index 41ecf25288a7..7542fb6283a2 100644 --- a/mesonbuild/compilers/detect.py +++ b/mesonbuild/compilers/detect.py @@ -1436,13 +1436,12 @@ def _try_obtain_compiler_defines(args: T.List[str]) -> str: # based on the driver. lang = clang_lang_map[lang] - # The compiler may not infer the target language based on the driver name - # so first, try with '-cpp -x lang', then fallback without given it's less - # portable. We try with '-cpp' as GCC needs it for Fortran at least, and - # it seems to do no harm. - output = _try_obtain_compiler_defines(['-cpp', '-x', lang] + baseline_test_args) + # The compiler may not infer the target language based on the driver name. + # Try first with '-x lang' to supported systemwide language level overrides, + # then fallback to without since it's a more recent option. + output = _try_obtain_compiler_defines(['-x', lang] + baseline_test_args) except (EnvironmentException, KeyError): - mlog.debug(f'pre-processor extraction using -cpp -x {lang} failed, falling back w/o lang') + mlog.debug(f'pre-processor extraction using -x {lang} failed, falling back w/o lang') output = _try_obtain_compiler_defines(baseline_test_args) defines: T.Dict[str, str] = {} From 9294c81fc134515a7b7d06ed538b66f45993b59d Mon Sep 17 00:00:00 2001 From: Stephan Lachnit Date: Mon, 30 Sep 2024 14:50:25 +0200 Subject: [PATCH 221/302] cmake/traceparser: fix typo --- mesonbuild/cmake/traceparser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/cmake/traceparser.py b/mesonbuild/cmake/traceparser.py index bc18b51a5b4d..38a2d31a595a 100644 --- a/mesonbuild/cmake/traceparser.py +++ b/mesonbuild/cmake/traceparser.py @@ -637,7 +637,7 @@ def _cmake_target_link_options(self, tline: CMakeTraceLine) -> None: def _cmake_target_link_libraries(self, tline: CMakeTraceLine) -> None: # DOC: https://cmake.org/cmake/help/latest/command/target_link_libraries.html - self._parse_common_target_options('target_link_options', 'LINK_LIBRARIES', 'INTERFACE_LINK_LIBRARIES', tline) + self._parse_common_target_options('target_link_libraries', 'LINK_LIBRARIES', 'INTERFACE_LINK_LIBRARIES', tline) def _cmake_message(self, tline: CMakeTraceLine) -> None: # DOC: https://cmake.org/cmake/help/latest/command/message.html From fb4995a2c607b8289ae97a3faa5917f2887da294 Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Thu, 26 Sep 2024 15:00:54 +0530 Subject: [PATCH 222/302] programs: Store the project version when overriding find_program When we're using the output of configure_file() with override_find_program(), we weren't storing the version anywhere, so get_version() was trying to run the script during setup. This is usually fine, except in cases where the configure_file() script actually has to import a library built as part of the project, and fails to run. For built executables, we simply use the project version, and we now do the same here too. --- mesonbuild/interpreter/mesonmain.py | 2 +- mesonbuild/programs.py | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/mesonbuild/interpreter/mesonmain.py b/mesonbuild/interpreter/mesonmain.py index a148f9624ae6..c82f933450c1 100644 --- a/mesonbuild/interpreter/mesonmain.py +++ b/mesonbuild/interpreter/mesonmain.py @@ -334,7 +334,7 @@ def override_find_program_method(self, args: T.Tuple[str, T.Union[mesonlib.File, self.interpreter.environment.build_dir) if not os.path.exists(abspath): raise InterpreterException(f'Tried to override {name} with a file that does not exist.') - exe = OverrideProgram(name, [abspath]) + exe = OverrideProgram(name, self.interpreter.project_version, command=[abspath]) self.interpreter.add_find_program_override(name, exe) @typed_kwargs( diff --git a/mesonbuild/programs.py b/mesonbuild/programs.py index 8f7d1c36c3f3..bbe8ea421cb4 100644 --- a/mesonbuild/programs.py +++ b/mesonbuild/programs.py @@ -340,6 +340,12 @@ class OverrideProgram(ExternalProgram): """A script overriding a program.""" + def __init__(self, name: str, version: str, command: T.Optional[T.List[str]] = None, + silent: bool = False, search_dir: T.Optional[str] = None, + extra_search_dirs: T.Optional[T.List[str]] = None): + self.cached_version = version + super().__init__(name, command=command, silent=silent, + search_dir=search_dir, extra_search_dirs=extra_search_dirs) def find_external_program(env: 'Environment', for_machine: MachineChoice, name: str, display_name: str, default_names: T.List[str], From a31f8d68cb068ad84fab08c901b7f8c707dc420f Mon Sep 17 00:00:00 2001 From: Andrea Pappacoda Date: Sat, 28 Sep 2024 12:00:43 +0200 Subject: [PATCH 223/302] tests: use statx instead of sendmmsg in has_function test Both recvmmsg/sendmmsg and statx require the `_GNU_SOURCE` symbol to be defined to be shown in headers, but statx has the additional property of being defined on all glibc systems[1], unlike recvmmsg which isn't implemented on Hurd[2][3]. With this fix, all tests now pass on Hurd. $ cat meson.build project('test', 'c') cc = meson.get_compiler('c') cc.has_header_symbol('sys/stat.h', 'statx') cc.has_header_symbol('sys/stat.h', 'statx', prefix: '#define _GNU_SOURCE') cc.has_function('statx') $ meson setup build The Meson build system Version: 1.5.1 Source dir: /tmp/tmp.XcWk4fMra4 Build dir: /tmp/tmp.XcWk4fMra4/build Build type: native build Project name: test Project version: undefined C compiler for the host machine: cc (gcc 14.2.0 "cc (Debian 14.2.0-3) 14.2.0") C linker for the host machine: cc ld.bfd 2.43.1 Host machine cpu family: x86_64 Host machine cpu: x86_64 Header "sys/stat.h" has symbol "statx" : NO Header "sys/stat.h" has symbol "statx" : YES Checking for function "statx" : YES Build targets in project: 0 [1]: https://sourceware.org/git/?p=glibc.git;a=blob;f=io/statx_generic.c;h=93faf12297cfcd37ba005a02e991eab351d74174;hb=HEAD [2]: https://www.gnu.org/software/hurd/open_issues/glibc.html#recvmmsg [3]: https://github.com/mesonbuild/meson/pull/4351 --- test cases/common/36 has function/meson.build | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test cases/common/36 has function/meson.build b/test cases/common/36 has function/meson.build index bb3e869760cb..d8b539880d8c 100644 --- a/test cases/common/36 has function/meson.build +++ b/test cases/common/36 has function/meson.build @@ -98,12 +98,11 @@ foreach cc : compilers # For some functions one needs to define _GNU_SOURCE before including the # right headers to get them picked up. Make sure we can detect these functions # as well without any prefix - if cc.has_header_symbol('sys/socket.h', 'recvmmsg', + if cc.has_header_symbol('sys/stat.h', 'statx', prefix : '#define _GNU_SOURCE', args : unit_test_args) - # We assume that if recvmmsg exists sendmmsg does too - assert (cc.has_function('sendmmsg', args : unit_test_args), - 'Failed to detect function "sendmmsg" (should always exist).') + assert (cc.has_function('statx', args : unit_test_args), + 'Failed to detect function "statx" (should always exist).') endif # We should be able to find GCC and Clang __builtin functions From d584c7debb128253c72df892595d9ffe79262f04 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Mon, 30 Sep 2024 09:23:27 -0700 Subject: [PATCH 224/302] tests: set c++ stdandard to c++11 for hd5f This fails on MacOS otherwise --- test cases/frameworks/25 hdf5/meson.build | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test cases/frameworks/25 hdf5/meson.build b/test cases/frameworks/25 hdf5/meson.build index b9f5784b4fd6..38e001202bfc 100644 --- a/test cases/frameworks/25 hdf5/meson.build +++ b/test cases/frameworks/25 hdf5/meson.build @@ -1,4 +1,8 @@ -project('hdf5_framework', 'c') +project( + 'hdf5_framework', + 'c', + default_options : ['cpp_std=c++11'], +) # NOTE: all HDF5 languages must have HDF5 C library working. From 9ce607665a2dfc2239198040494d646fa243747b Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Wed, 18 Sep 2024 18:05:30 +0300 Subject: [PATCH 225/302] Add a simple reproducibility test command. --- docs/markdown/Commands.md | 28 ++++++ docs/markdown/snippets/reprotester.md | 15 ++++ mesonbuild/mesonmain.py | 4 +- mesonbuild/scripts/reprotest.py | 123 ++++++++++++++++++++++++++ 4 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 docs/markdown/snippets/reprotester.md create mode 100755 mesonbuild/scripts/reprotest.py diff --git a/docs/markdown/Commands.md b/docs/markdown/Commands.md index 542f1b269d40..8e34800a44b3 100644 --- a/docs/markdown/Commands.md +++ b/docs/markdown/Commands.md @@ -225,6 +225,34 @@ DESTDIR=/path/to/staging/area meson install -C builddir Since *0.60.0* `DESTDIR` and `--destdir` can be a path relative to build directory. An absolute path will be set into environment when executing scripts. +### reprotest + +*(since 1.6.0)* + +{{ reprotest_usage.inc }} + +Simple reproducible build tester that compiles the project twice and +checks whether the end results are identical. + +This command must be run in the source root of the project you want to +test. + +{{ reprotest_arguments.inc }} + +#### Examples + + meson reprotest + +Builds the current project with its default settings. + + meson reprotest --intermediaries -- --buildtype=debugoptimized + +Builds the target and also checks that all intermediate files like +object files are also identical. All command line arguments after the +`--` are passed directly to the underlying `meson` invocation. Only +use option arguments, i.e. those that start with a dash, Meson sets +directory arguments automatically. + ### rewrite *(since 0.50.0)* diff --git a/docs/markdown/snippets/reprotester.md b/docs/markdown/snippets/reprotester.md new file mode 100644 index 000000000000..dc86acdb988d --- /dev/null +++ b/docs/markdown/snippets/reprotester.md @@ -0,0 +1,15 @@ +## Simple tool to test build reproducibility + +Meson now ships with a command for testing whether your project can be +[built reprodicibly](https://reproducible-builds.org/). It can be used +by running a command like the following in the source root of your +project: + + meson reprotest --intermediaries -- --buildtype=debugoptimized + +All command line options after the `--` are passed to the build +invocations directly. + +This tool is not meant to be exhaustive, but instead easy and +convenient to run. It will detect some but definitely not all +reproducibility issues. diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py index faa0f426d82a..2c1ca97a386f 100644 --- a/mesonbuild/mesonmain.py +++ b/mesonbuild/mesonmain.py @@ -65,7 +65,7 @@ class CommandLineParser: def __init__(self) -> None: # only import these once we do full argparse processing from . import mconf, mdist, minit, minstall, mintro, msetup, mtest, rewriter, msubprojects, munstable_coredata, mcompile, mdevenv, mformat - from .scripts import env2mfile + from .scripts import env2mfile, reprotest from .wrap import wraptool import shutil @@ -103,6 +103,8 @@ def __init__(self) -> None: help_msg='Run commands in developer environment') self.add_command('env2mfile', env2mfile.add_arguments, env2mfile.run, help_msg='Convert current environment to a cross or native file') + self.add_command('reprotest', reprotest.add_arguments, reprotest.run, + help_msg='Test if project builds reproducibly') self.add_command('format', mformat.add_arguments, mformat.run, aliases=['fmt'], help_msg='Format meson source file') # Add new commands above this line to list them in help command diff --git a/mesonbuild/scripts/reprotest.py b/mesonbuild/scripts/reprotest.py new file mode 100755 index 000000000000..fc9315c8f21f --- /dev/null +++ b/mesonbuild/scripts/reprotest.py @@ -0,0 +1,123 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2024 The Meson development team + +from __future__ import annotations + +import sys, os, subprocess, shutil +import pathlib +import typing as T + +if T.TYPE_CHECKING: + import argparse + +from ..mesonlib import get_meson_command + +# Note: when adding arguments, please also add them to the completion +# scripts in $MESONSRC/data/shell-completions/ +def add_arguments(parser: 'argparse.ArgumentParser') -> None: + parser.add_argument('--intermediaries', + default=False, + action='store_true', + help='Check intermediate files.') + parser.add_argument('mesonargs', nargs='*', + help='Arguments to pass to "meson setup".') + +IGNORE_PATTERNS = ('.ninja_log', + '.ninja_deps', + 'meson-private', + 'meson-logs', + 'meson-info', + ) + +INTERMEDIATE_EXTENSIONS = ('.gch', + '.pch', + '.o', + '.obj', + '.class', + ) + +class ReproTester: + def __init__(self, options: T.Any): + self.args = options.mesonargs + self.meson = get_meson_command()[:] + self.builddir = pathlib.Path('buildrepro') + self.storagedir = pathlib.Path('buildrepro.1st') + self.issues: T.List[str] = [] + self.check_intermediaries = options.intermediaries + + def run(self) -> int: + if not os.path.isfile('meson.build'): + sys.exit('This command needs to be run at your project source root.') + self.disable_ccache() + self.cleanup() + self.build() + self.check_output() + self.print_results() + if not self.issues: + self.cleanup() + return len(self.issues) + + def disable_ccache(self) -> None: + os.environ['CCACHE_DISABLE'] = '1' + + def cleanup(self) -> None: + if self.builddir.exists(): + shutil.rmtree(self.builddir) + if self.storagedir.exists(): + shutil.rmtree(self.storagedir) + + def build(self) -> None: + setup_command: T.Sequence[str] = self.meson + ['setup', str(self.builddir)] + self.args + build_command: T.Sequence[str] = self.meson + ['compile', '-C', str(self.builddir)] + subprocess.check_call(setup_command) + subprocess.check_call(build_command) + self.builddir.rename(self.storagedir) + subprocess.check_call(setup_command) + subprocess.check_call(build_command) + + def ignore_file(self, fstr: str) -> bool: + for p in IGNORE_PATTERNS: + if p in fstr: + return True + if not self.check_intermediaries: + if fstr.endswith(INTERMEDIATE_EXTENSIONS): + return True + return False + + def check_contents(self, fromdir: str, todir: str, check_contents: bool) -> None: + import filecmp + frompath = fromdir + '/' + topath = todir + '/' + for fromfile in pathlib.Path(fromdir).glob('**/*'): + if not fromfile.is_file(): + continue + fstr = fromfile.as_posix() + if self.ignore_file(fstr): + continue + assert fstr.startswith(frompath) + tofile = pathlib.Path(fstr.replace(frompath, topath, 1)) + if not tofile.exists(): + self.issues.append(f'Missing file: {tofile}') + elif check_contents: + if not filecmp.cmp(fromfile, tofile, shallow=False): + self.issues.append(f'File contents differ: {fromfile}') + + def print_results(self) -> None: + if self.issues: + print('Build differences detected') + for i in self.issues: + print(i) + else: + print('No differences detected.') + + def check_output(self) -> None: + self.check_contents('buildrepro', 'buildrepro.1st', True) + self.check_contents('buildrepro.1st', 'buildrepro', False) + +def run(options: T.Any) -> None: + rt = ReproTester(options) + try: + sys.exit(rt.run()) + except Exception as e: + print(e) + sys.exit(1) From e2508053a264a521671fa01c234e3db979de2a70 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 27 Aug 2024 13:02:51 -0700 Subject: [PATCH 226/302] interpreterobjects: use typed_pos_args for subproject.get_variable --- mesonbuild/interpreter/interpreterobjects.py | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/mesonbuild/interpreter/interpreterobjects.py b/mesonbuild/interpreter/interpreterobjects.py index bc0d7e7695ab..4ff53d38f4d8 100644 --- a/mesonbuild/interpreter/interpreterobjects.py +++ b/mesonbuild/interpreter/interpreterobjects.py @@ -844,25 +844,19 @@ def found(self) -> bool: return not isinstance(self.held_object, NullSubprojectInterpreter) @noKwargs + @typed_pos_args('subproject.get_variable', str, optargs=[object]) @noArgsFlattening @unholder_return - def get_variable_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> T.Union[TYPE_var, InterpreterObject]: - if len(args) < 1 or len(args) > 2: - raise InterpreterException('Get_variable takes one or two arguments.') + def get_variable_method(self, args: T.Tuple[str, T.Optional[HoldableObject]], kwargs: TYPE_kwargs) -> T.Union[TYPE_var, InterpreterObject]: if isinstance(self.held_object, NullSubprojectInterpreter): # == not self.found() raise InterpreterException(f'Subproject "{self.subdir}" disabled can\'t get_variable on it.') - varname = args[0] - if not isinstance(varname, str): - raise InterpreterException('Get_variable first argument must be a string.') + varname, fallback = args try: return self.held_object.variables[varname] except KeyError: - pass - - if len(args) == 2: - return self.held_object._holderify(args[1]) - - raise InvalidArguments(f'Requested variable "{varname}" not found.') + if fallback is not None: + return self.held_object._holderify(fallback) + raise InvalidArguments(f'Requested variable "{varname}" not found.') class ModuleObjectHolder(ObjectHolder[ModuleObject]): def method_call(self, method_name: str, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> TYPE_var: From 2ce15a690601101826cad501a9b9e24a0c774252 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 27 Aug 2024 13:06:36 -0700 Subject: [PATCH 227/302] modules/cmake: use typed_pos_args for subproject.get_variable --- mesonbuild/interpreter/interpreterobjects.py | 11 +++++++---- mesonbuild/modules/cmake.py | 8 ++++---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/mesonbuild/interpreter/interpreterobjects.py b/mesonbuild/interpreter/interpreterobjects.py index 4ff53d38f4d8..a919102607be 100644 --- a/mesonbuild/interpreter/interpreterobjects.py +++ b/mesonbuild/interpreter/interpreterobjects.py @@ -843,11 +843,8 @@ def found_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool: def found(self) -> bool: return not isinstance(self.held_object, NullSubprojectInterpreter) - @noKwargs - @typed_pos_args('subproject.get_variable', str, optargs=[object]) - @noArgsFlattening @unholder_return - def get_variable_method(self, args: T.Tuple[str, T.Optional[HoldableObject]], kwargs: TYPE_kwargs) -> T.Union[TYPE_var, InterpreterObject]: + def get_variable(self, args: T.Tuple[str, T.Optional[str]], kwargs: TYPE_kwargs) -> T.Union[TYPE_var, InterpreterObject]: if isinstance(self.held_object, NullSubprojectInterpreter): # == not self.found() raise InterpreterException(f'Subproject "{self.subdir}" disabled can\'t get_variable on it.') varname, fallback = args @@ -858,6 +855,12 @@ def get_variable_method(self, args: T.Tuple[str, T.Optional[HoldableObject]], kw return self.held_object._holderify(fallback) raise InvalidArguments(f'Requested variable "{varname}" not found.') + @noKwargs + @typed_pos_args('subproject.get_variable', str, optargs=[object]) + @noArgsFlattening + def get_variable_method(self, args: T.Tuple[str, T.Optional[str]], kwargs: TYPE_kwargs) -> T.Union[TYPE_var, InterpreterObject]: + return self.get_variable(args, kwargs) + class ModuleObjectHolder(ObjectHolder[ModuleObject]): def method_call(self, method_name: str, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> TYPE_var: modobj = self.held_object diff --git a/mesonbuild/modules/cmake.py b/mesonbuild/modules/cmake.py index 4fda7b30d003..78a1a0cf9d32 100644 --- a/mesonbuild/modules/cmake.py +++ b/mesonbuild/modules/cmake.py @@ -39,7 +39,7 @@ from ..cmake import SingleTargetOptions from ..environment import Environment from ..interpreter import Interpreter, kwargs - from ..interpreterbase import TYPE_kwargs, TYPE_var + from ..interpreterbase import TYPE_kwargs, TYPE_var, InterpreterObject class WriteBasicPackageVersionFile(TypedDict): @@ -126,9 +126,9 @@ def _args_to_info(self, args: T.List[str]) -> T.Dict[str, str]: return res @noKwargs - @stringArgs - def get_variable(self, state: ModuleState, args: T.List[str], kwargs: TYPE_kwargs) -> TYPE_var: - return self.subp.get_variable_method(args, kwargs) + @typed_pos_args('cmake.subproject.get_variable', str, optargs=[str]) + def get_variable(self, state: ModuleState, args: T.Tuple[str, T.Optional[str]], kwargs: TYPE_kwargs) -> T.Union[TYPE_var, InterpreterObject]: + return self.subp.get_variable(args, kwargs) @FeatureNewKwargs('dependency', '0.56.0', ['include_type']) @permittedKwargs({'include_type'}) From 626f4fd244f29c86469b5675ff7d48e32bf5d82d Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 27 Aug 2024 13:09:54 -0700 Subject: [PATCH 228/302] modules/cmake: use typed_pos_args for subproject.dependency --- mesonbuild/modules/cmake.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mesonbuild/modules/cmake.py b/mesonbuild/modules/cmake.py index 78a1a0cf9d32..b73c90462e31 100644 --- a/mesonbuild/modules/cmake.py +++ b/mesonbuild/modules/cmake.py @@ -132,9 +132,9 @@ def get_variable(self, state: ModuleState, args: T.Tuple[str, T.Optional[str]], @FeatureNewKwargs('dependency', '0.56.0', ['include_type']) @permittedKwargs({'include_type'}) - @stringArgs - def dependency(self, state: ModuleState, args: T.List[str], kwargs: T.Dict[str, str]) -> dependencies.Dependency: - info = self._args_to_info(args) + @typed_pos_args('cmake.subproject.dependency', str) + def dependency(self, state: ModuleState, args: T.Tuple[str], kwargs: T.Dict[str, str]) -> dependencies.Dependency: + info = self._args_to_info(list(args)) if info['func'] == 'executable': raise InvalidArguments(f'{args[0]} is an executable and does not support the dependency() method. Use target() instead.') if info['dep'] is None: From 60e2da24c03039b007d9319a43e7f7ff1895e44c Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 27 Aug 2024 13:11:32 -0700 Subject: [PATCH 229/302] modules/cmake: use typed_pos_args for remaining subproject methods Since these are all more-or-less the same --- mesonbuild/modules/cmake.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/mesonbuild/modules/cmake.py b/mesonbuild/modules/cmake.py index b73c90462e31..d437d7d7b094 100644 --- a/mesonbuild/modules/cmake.py +++ b/mesonbuild/modules/cmake.py @@ -18,7 +18,6 @@ FeatureNew, FeatureNewKwargs, - stringArgs, permittedKwargs, noPosargs, noKwargs, @@ -148,21 +147,21 @@ def dependency(self, state: ModuleState, args: T.Tuple[str], kwargs: T.Dict[str, return orig @noKwargs - @stringArgs - def include_directories(self, state: ModuleState, args: T.List[str], kwargs: TYPE_kwargs) -> build.IncludeDirs: - info = self._args_to_info(args) + @typed_pos_args('cmake.subproject.include_directories', str) + def include_directories(self, state: ModuleState, args: T.Tuple[str], kwargs: TYPE_kwargs) -> build.IncludeDirs: + info = self._args_to_info(list(args)) return self.get_variable(state, [info['inc']], kwargs) @noKwargs - @stringArgs - def target(self, state: ModuleState, args: T.List[str], kwargs: TYPE_kwargs) -> build.Target: - info = self._args_to_info(args) + @typed_pos_args('cmake.subproject.target', str) + def target(self, state: ModuleState, args: T.Tuple[str], kwargs: TYPE_kwargs) -> build.Target: + info = self._args_to_info(list(args)) return self.get_variable(state, [info['tgt']], kwargs) @noKwargs - @stringArgs - def target_type(self, state: ModuleState, args: T.List[str], kwargs: TYPE_kwargs) -> str: - info = self._args_to_info(args) + @typed_pos_args('cmake.subproject.target_type', str) + def target_type(self, state: ModuleState, args: T.Tuple[str], kwargs: TYPE_kwargs) -> str: + info = self._args_to_info(list(args)) return info['func'] @noPosargs From f9c2a68372fe03824297307a1d549d9fe3c71101 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 27 Aug 2024 13:14:22 -0700 Subject: [PATCH 230/302] interpreterbase/decorators: delete now unused stringArgs --- mesonbuild/interpreterbase/__init__.py | 2 -- mesonbuild/interpreterbase/decorators.py | 13 ------------- 2 files changed, 15 deletions(-) diff --git a/mesonbuild/interpreterbase/__init__.py b/mesonbuild/interpreterbase/__init__.py index 934375a0ee93..aa38e949063b 100644 --- a/mesonbuild/interpreterbase/__init__.py +++ b/mesonbuild/interpreterbase/__init__.py @@ -28,7 +28,6 @@ 'noPosargs', 'noKwargs', - 'stringArgs', 'noArgsFlattening', 'noSecondLevelHolderResolving', 'unholder_return', @@ -87,7 +86,6 @@ from .decorators import ( noPosargs, noKwargs, - stringArgs, noArgsFlattening, noSecondLevelHolderResolving, unholder_return, diff --git a/mesonbuild/interpreterbase/decorators.py b/mesonbuild/interpreterbase/decorators.py index fe6f6a53bd1b..06cac526db22 100644 --- a/mesonbuild/interpreterbase/decorators.py +++ b/mesonbuild/interpreterbase/decorators.py @@ -62,19 +62,6 @@ def wrapped(*wrapped_args: T.Any, **wrapped_kwargs: T.Any) -> T.Any: return f(*wrapped_args, **wrapped_kwargs) return T.cast('TV_func', wrapped) -def stringArgs(f: TV_func) -> TV_func: - @wraps(f) - def wrapped(*wrapped_args: T.Any, **wrapped_kwargs: T.Any) -> T.Any: - args = get_callee_args(wrapped_args)[1] - if not isinstance(args, list): - mlog.debug('Not a list:', str(args)) - raise InvalidArguments('Argument not a list.') - if not all(isinstance(s, str) for s in args): - mlog.debug('Element not a string:', str(args)) - raise InvalidArguments('Arguments must be strings.') - return f(*wrapped_args, **wrapped_kwargs) - return T.cast('TV_func', wrapped) - def noArgsFlattening(f: TV_func) -> TV_func: setattr(f, 'no-args-flattening', True) # noqa: B010 return f From c79453ed73569796130eb62fbfa913d89e9bfb54 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 27 Aug 2024 13:19:21 -0700 Subject: [PATCH 231/302] modules/cmake: simplify _args_to_info We don't need to pass a list, and we don't need to check length or type --- mesonbuild/modules/cmake.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/mesonbuild/modules/cmake.py b/mesonbuild/modules/cmake.py index d437d7d7b094..8eefe11cc284 100644 --- a/mesonbuild/modules/cmake.py +++ b/mesonbuild/modules/cmake.py @@ -109,11 +109,7 @@ def __init__(self, subp: SubprojectHolder): 'found': self.found_method, }) - def _args_to_info(self, args: T.List[str]) -> T.Dict[str, str]: - if len(args) != 1: - raise InterpreterException('Exactly one argument is required.') - - tgt = args[0] + def _args_to_info(self, tgt: str) -> T.Dict[str, str]: res = self.cm_interpreter.target_info(tgt) if res is None: raise InterpreterException(f'The CMake target {tgt} does not exist\n' + @@ -133,7 +129,7 @@ def get_variable(self, state: ModuleState, args: T.Tuple[str, T.Optional[str]], @permittedKwargs({'include_type'}) @typed_pos_args('cmake.subproject.dependency', str) def dependency(self, state: ModuleState, args: T.Tuple[str], kwargs: T.Dict[str, str]) -> dependencies.Dependency: - info = self._args_to_info(list(args)) + info = self._args_to_info(args[0]) if info['func'] == 'executable': raise InvalidArguments(f'{args[0]} is an executable and does not support the dependency() method. Use target() instead.') if info['dep'] is None: @@ -149,19 +145,19 @@ def dependency(self, state: ModuleState, args: T.Tuple[str], kwargs: T.Dict[str, @noKwargs @typed_pos_args('cmake.subproject.include_directories', str) def include_directories(self, state: ModuleState, args: T.Tuple[str], kwargs: TYPE_kwargs) -> build.IncludeDirs: - info = self._args_to_info(list(args)) + info = self._args_to_info(args[0]) return self.get_variable(state, [info['inc']], kwargs) @noKwargs @typed_pos_args('cmake.subproject.target', str) def target(self, state: ModuleState, args: T.Tuple[str], kwargs: TYPE_kwargs) -> build.Target: - info = self._args_to_info(list(args)) + info = self._args_to_info(args[0]) return self.get_variable(state, [info['tgt']], kwargs) @noKwargs @typed_pos_args('cmake.subproject.target_type', str) def target_type(self, state: ModuleState, args: T.Tuple[str], kwargs: TYPE_kwargs) -> str: - info = self._args_to_info(list(args)) + info = self._args_to_info(args[0]) return info['func'] @noPosargs From 351ae5d3a61f20ecbd6e487662ae53808da8fcbd Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 27 Aug 2024 13:33:12 -0700 Subject: [PATCH 232/302] modules/cmake: use typed_kwargs for subproject.dependency --- mesonbuild/modules/cmake.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/mesonbuild/modules/cmake.py b/mesonbuild/modules/cmake.py index 8eefe11cc284..10a4ef29bd12 100644 --- a/mesonbuild/modules/cmake.py +++ b/mesonbuild/modules/cmake.py @@ -16,7 +16,6 @@ from ..interpreter.type_checking import REQUIRED_KW, INSTALL_DIR_KW, NoneType, in_set_validator from ..interpreterbase import ( FeatureNew, - FeatureNewKwargs, permittedKwargs, noPosargs, @@ -89,7 +88,6 @@ class Subproject(kwargs.ExtractRequired): message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !") endif() endmacro() - #################################################################################### ''' @@ -125,9 +123,17 @@ def _args_to_info(self, tgt: str) -> T.Dict[str, str]: def get_variable(self, state: ModuleState, args: T.Tuple[str, T.Optional[str]], kwargs: TYPE_kwargs) -> T.Union[TYPE_var, InterpreterObject]: return self.subp.get_variable(args, kwargs) - @FeatureNewKwargs('dependency', '0.56.0', ['include_type']) - @permittedKwargs({'include_type'}) @typed_pos_args('cmake.subproject.dependency', str) + @typed_kwargs( + 'cmake.subproject.dependency', + KwargInfo( + 'include_type', + str, + default='preserve', + since='0.56.0', + validator=in_set_validator({'preserve', 'system', 'non-system'}) + ), + ) def dependency(self, state: ModuleState, args: T.Tuple[str], kwargs: T.Dict[str, str]) -> dependencies.Dependency: info = self._args_to_info(args[0]) if info['func'] == 'executable': @@ -136,9 +142,8 @@ def dependency(self, state: ModuleState, args: T.Tuple[str], kwargs: T.Dict[str, raise InvalidArguments(f'{args[0]} does not support the dependency() method. Use target() instead.') orig = self.get_variable(state, [info['dep']], {}) assert isinstance(orig, dependencies.Dependency) - actual = orig.include_type - if 'include_type' in kwargs and kwargs['include_type'] != actual: - mlog.debug('Current include type is {}. Converting to requested {}'.format(actual, kwargs['include_type'])) + if kwargs['include_type'] != 'preserve' and kwargs['include_type'] != orig.include_type: + mlog.debug('Current include type is {}. Converting to requested {}'.format(orig.include_type, kwargs['include_type'])) return orig.generate_system_dependency(kwargs['include_type']) return orig From 3d27f1c60ad5ff10a04a6d73646a075707121a97 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 27 Aug 2024 13:49:50 -0700 Subject: [PATCH 233/302] modules/cmake: use typed_kwargs instead of permittedKwargs --- mesonbuild/modules/cmake.py | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/mesonbuild/modules/cmake.py b/mesonbuild/modules/cmake.py index 10a4ef29bd12..2168aaa516c0 100644 --- a/mesonbuild/modules/cmake.py +++ b/mesonbuild/modules/cmake.py @@ -17,7 +17,6 @@ from ..interpreterbase import ( FeatureNew, - permittedKwargs, noPosargs, noKwargs, @@ -34,7 +33,7 @@ from typing_extensions import TypedDict from . import ModuleState - from ..cmake import SingleTargetOptions + from ..cmake.common import SingleTargetOptions from ..environment import Environment from ..interpreter import Interpreter, kwargs from ..interpreterbase import TYPE_kwargs, TYPE_var, InterpreterObject @@ -59,6 +58,12 @@ class Subproject(kwargs.ExtractRequired): options: T.Optional[CMakeSubprojectOptions] cmake_options: T.List[str] + class TargetKW(TypedDict): + + target: T.Optional[str] + + +_TARGET_KW = KwargInfo('target', (str, NoneType)) COMPATIBILITIES = ['AnyNewerVersion', 'SameMajorVersion', 'SameMinorVersion', 'ExactVersion'] @@ -194,8 +199,8 @@ def __init__(self) -> None: } ) - def _get_opts(self, kwargs: dict) -> SingleTargetOptions: - if 'target' in kwargs: + def _get_opts(self, kwargs: TargetKW) -> SingleTargetOptions: + if kwargs['target'] is not None: return self.target_options[kwargs['target']] return self.target_options.global_options @@ -205,23 +210,23 @@ def add_cmake_defines(self, state: ModuleState, args: T.Tuple[T.List[T.Dict[str, self.cmake_options += cmake_defines_to_args(args[0]) @typed_pos_args('subproject_options.set_override_option', str, str) - @permittedKwargs({'target'}) - def set_override_option(self, state: ModuleState, args: T.Tuple[str, str], kwargs: TYPE_kwargs) -> None: + @typed_kwargs('subproject_options.set_override_option', _TARGET_KW) + def set_override_option(self, state: ModuleState, args: T.Tuple[str, str], kwargs: TargetKW) -> None: self._get_opts(kwargs).set_opt(args[0], args[1]) @typed_pos_args('subproject_options.set_install', bool) - @permittedKwargs({'target'}) - def set_install(self, state: ModuleState, args: T.Tuple[bool], kwargs: TYPE_kwargs) -> None: + @typed_kwargs('subproject_options.set_install', _TARGET_KW) + def set_install(self, state: ModuleState, args: T.Tuple[bool], kwargs: TargetKW) -> None: self._get_opts(kwargs).set_install(args[0]) @typed_pos_args('subproject_options.append_compile_args', str, varargs=str, min_varargs=1) - @permittedKwargs({'target'}) - def append_compile_args(self, state: ModuleState, args: T.Tuple[str, T.List[str]], kwargs: TYPE_kwargs) -> None: + @typed_kwargs('subproject_options.append_compile_args', _TARGET_KW) + def append_compile_args(self, state: ModuleState, args: T.Tuple[str, T.List[str]], kwargs: TargetKW) -> None: self._get_opts(kwargs).append_args(args[0], args[1]) @typed_pos_args('subproject_options.append_link_args', varargs=str, min_varargs=1) - @permittedKwargs({'target'}) - def append_link_args(self, state: ModuleState, args: T.Tuple[T.List[str]], kwargs: TYPE_kwargs) -> None: + @typed_kwargs('subproject_options.append_link_args', _TARGET_KW) + def append_link_args(self, state: ModuleState, args: T.Tuple[T.List[str]], kwargs: TargetKW) -> None: self._get_opts(kwargs).append_link_args(args[0]) @noPosargs From efa85c5b645624e17ac733e209bda4d118ad8cfb Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 1 Oct 2024 09:58:16 -0700 Subject: [PATCH 234/302] minstall: fix bug link --- mesonbuild/minstall.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/minstall.py b/mesonbuild/minstall.py index e5901c45ae85..9921295fda8e 100644 --- a/mesonbuild/minstall.py +++ b/mesonbuild/minstall.py @@ -152,7 +152,7 @@ def set_chown(path: str, user: T.Union[str, int, None] = None, if sys.version_info >= (3, 13): # pylint: disable=unexpected-keyword-arg - # cannot handle sys.version_info, https://github.com/pylint-dev/pylint/issues/9138 + # cannot handle sys.version_info, https://github.com/pylint-dev/pylint/issues/9622 shutil.chown(path, user, group, dir_fd=dir_fd, follow_symlinks=follow_symlinks) else: real_os_chown = os.chown From d528b83ff2660518009495e02eea1d2917112082 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 1 Oct 2024 09:26:41 -0700 Subject: [PATCH 235/302] compilers: annotate lang_suffixes --- mesonbuild/compilers/compilers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index cb047be0c14c..35a0b2be768a 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -51,7 +51,7 @@ # Mapping of language to suffixes of files that should always be in that language # This means we can't include .h headers here since they could be C, C++, ObjC, etc. # First suffix is the language's default. -lang_suffixes = { +lang_suffixes: T.Mapping[str, T.Tuple[str, ...]] = { 'c': ('c',), 'cpp': ('cpp', 'cppm', 'cc', 'cxx', 'c++', 'hh', 'hpp', 'ipp', 'hxx', 'ino', 'ixx', 'C', 'H'), 'cuda': ('cu',), From cd75bbee9bd887a162f1da9eea2fe24c0b07c312 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 1 Oct 2024 09:28:24 -0700 Subject: [PATCH 236/302] compilers: remove hasattr for `file_suffixes` This is used in exactly two cases, and it's just not worth it. Those two cases can override the default set of extensions, and in the process allow a nice bit of code cleanup, especially toward type checking. --- mesonbuild/compilers/compilers.py | 3 +-- mesonbuild/compilers/fortran.py | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 35a0b2be768a..dbe80273924d 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -452,8 +452,7 @@ def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, self.exelist = ccache + exelist self.exelist_no_ccache = exelist # In case it's been overridden by a child class already - if not hasattr(self, 'file_suffixes'): - self.file_suffixes = lang_suffixes[self.language] + self.file_suffixes = lang_suffixes[self.language] if not hasattr(self, 'can_compile_suffixes'): self.can_compile_suffixes: T.Set[str] = set(self.file_suffixes) self.default_suffix = self.file_suffixes[0] diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py index a99a95ce37ba..5012fba074a0 100644 --- a/mesonbuild/compilers/fortran.py +++ b/mesonbuild/compilers/fortran.py @@ -262,7 +262,6 @@ def openmp_flags(self, env: Environment) -> T.List[str]: class IntelFortranCompiler(IntelGnuLikeCompiler, FortranCompiler): - file_suffixes = ('f90', 'f', 'for', 'ftn', 'fpp', ) id = 'intel' def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, @@ -275,6 +274,7 @@ def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoic # FIXME: Add support for OS X and Windows in detect_fortran_compiler so # we are sent the type of compiler IntelGnuLikeCompiler.__init__(self) + self.file_suffixes = ('f90', 'f', 'for', 'ftn', 'fpp', ) default_warn_args = ['-warn', 'general', '-warn', 'truncated_source'] self.warn_args = {'0': [], '1': default_warn_args, @@ -318,7 +318,6 @@ class IntelLLVMFortranCompiler(IntelFortranCompiler): class IntelClFortranCompiler(IntelVisualStudioLikeCompiler, FortranCompiler): - file_suffixes = ('f90', 'f', 'for', 'ftn', 'fpp', ) always_args = ['/nologo'] def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, @@ -329,6 +328,7 @@ def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoic is_cross, info, linker=linker, full_version=full_version) IntelVisualStudioLikeCompiler.__init__(self, target) + self.file_suffixes = ('f90', 'f', 'for', 'ftn', 'fpp', ) default_warn_args = ['/warn:general', '/warn:truncated_source'] self.warn_args = {'0': [], From 3728b228a6ce112d0f55220b1c8770a4eb1aab8c Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 1 Oct 2024 09:31:22 -0700 Subject: [PATCH 237/302] compilers: remove hasattr from `can_compile_suffixes` This is never set outside the `Compiler.__init__`, only added to. As such there's no reason to have this `hasattr` check. It's wasting time *and* confusing our static checkers. --- mesonbuild/compilers/compilers.py | 4 +--- mesonbuild/compilers/mixins/ccrx.py | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index dbe80273924d..3ec50c9583c1 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -451,10 +451,8 @@ def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, full_version: T.Optional[str] = None, is_cross: bool = False): self.exelist = ccache + exelist self.exelist_no_ccache = exelist - # In case it's been overridden by a child class already self.file_suffixes = lang_suffixes[self.language] - if not hasattr(self, 'can_compile_suffixes'): - self.can_compile_suffixes: T.Set[str] = set(self.file_suffixes) + self.can_compile_suffixes = set(self.file_suffixes) self.default_suffix = self.file_suffixes[0] self.version = version self.full_version = full_version diff --git a/mesonbuild/compilers/mixins/ccrx.py b/mesonbuild/compilers/mixins/ccrx.py index 63270726bc4c..d1badaa1c7eb 100644 --- a/mesonbuild/compilers/mixins/ccrx.py +++ b/mesonbuild/compilers/mixins/ccrx.py @@ -40,7 +40,6 @@ class CcrxCompiler(Compiler): if T.TYPE_CHECKING: is_cross = True - can_compile_suffixes: T.Set[str] = set() id = 'ccrx' From 940c45f8324fec675b4e10591f5379aa571ab073 Mon Sep 17 00:00:00 2001 From: mid-kid Date: Sun, 29 Sep 2024 10:55:34 +0200 Subject: [PATCH 238/302] Add additional C++ filename extensions These are all supported by GCC: https://gcc.gnu.org/onlinedocs/gcc-14.2.0/gcc/Overall-Options.html --- mesonbuild/compilers/compilers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 3ec50c9583c1..603a3eb484de 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -53,7 +53,7 @@ # First suffix is the language's default. lang_suffixes: T.Mapping[str, T.Tuple[str, ...]] = { 'c': ('c',), - 'cpp': ('cpp', 'cppm', 'cc', 'cxx', 'c++', 'hh', 'hpp', 'ipp', 'hxx', 'ino', 'ixx', 'C', 'H'), + 'cpp': ('cpp', 'cppm', 'cc', 'cp', 'cxx', 'c++', 'hh', 'hp', 'hpp', 'ipp', 'hxx', 'h++', 'ino', 'ixx', 'CPP', 'C', 'HPP', 'H'), 'cuda': ('cu',), # f90, f95, f03, f08 are for free-form fortran ('f90' recommended) # f, for, ftn, fpp are for fixed-form fortran ('f' or 'for' recommended) From 21b105473079fe3722c1268b507dd91dde95abba Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Tue, 1 Oct 2024 18:57:26 -0400 Subject: [PATCH 239/302] mark the PyPI metadata as supporting python 3.13 meson runs okay on 3.13, since release 1.5.0 / https://github.com/mesonbuild/meson/pull/13205 --- setup.cfg | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.cfg b/setup.cfg index 2f2962eedcba..51b8aeeba3bd 100644 --- a/setup.cfg +++ b/setup.cfg @@ -31,6 +31,7 @@ classifiers = Programming Language :: Python :: 3.10 Programming Language :: Python :: 3.11 Programming Language :: Python :: 3.12 + Programming Language :: Python :: 3.13 Topic :: Software Development :: Build Tools long_description = Meson is a cross-platform build system designed to be both as fast and as user friendly as possible. It supports many languages and compilers, including GCC, Clang, PGI, Intel, and Visual Studio. Its build definitions are written in a simple non-Turing complete DSL. From 54cb8cec8c27fd2cf3faf70cff2e517a3de37790 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Mon, 30 Sep 2024 11:14:30 -0700 Subject: [PATCH 240/302] backend/ninja: allow cleandead with dyndeps and ninja >= 1.12 I fixed the upstream issue here, so if we have >= 1.12 we don't need to worry about the dyndeps issue. See: https://github.com/ninja-build/ninja/pull/2406/ --- mesonbuild/backend/ninjabackend.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 6eb1f1d0191d..675248962594 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -692,7 +692,9 @@ def generate(self, capture: bool = False, vslite_ctx: T.Optional[T.Dict] = None) mlog.cmd_ci_include(outfilename) # For CI debugging # Refresh Ninja's caches. https://github.com/ninja-build/ninja/pull/1685 # Cannot use when running with dyndeps: https://github.com/ninja-build/ninja/issues/1952 - if mesonlib.version_compare(self.ninja_version, '>=1.10.0') and os.path.exists(os.path.join(self.environment.build_dir, '.ninja_log')) and not self._uses_dyndeps: + if ((mesonlib.version_compare(self.ninja_version, '>= 1.12.0') or + (mesonlib.version_compare(self.ninja_version, '>=1.10.0') and not self._uses_dyndeps)) + and os.path.exists(os.path.join(self.environment.build_dir, '.ninja_log'))): subprocess.call(self.ninja_command + ['-t', 'restat'], cwd=self.environment.build_dir) subprocess.call(self.ninja_command + ['-t', 'cleandead'], cwd=self.environment.build_dir) self.generate_compdb() From 3b248c2ab73cd6780552815b8e3e547587f8dcd7 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 2 Oct 2024 15:22:46 +0100 Subject: [PATCH 241/302] docs: Use examples for build_machine.cpu() that genuinely exist Previously, the documentation said that the CPU name might be amd64, but in fact x86_64 (AMD64) machines are detected as x86_64 in both cpu() and cpu_family() during native builds. Reference: https://buildd.debian.org/status/fetch.php?pkg=libglvnd&arch=amd64&ver=1.7.0-1%2Bb1&stamp=1714222481&raw=0 Instead, mention the only common case for more-specific CPU names other than 32-bit x86, namely 32-bit ARM. On Debian's autobuilders (which are running 32-bit user-space on a 64-bit-capable CPU), native builds genuinely do present as `armv8l`: https://buildd.debian.org/status/fetch.php?pkg=libglvnd&arch=armhf&ver=1.7.0-1%2Bb1&stamp=1714223924&raw=0 On other machines, they might be some older CPU functionality level. At the time of writing, cpu() *can* return amd64 when using `meson env2mfile` on Debian systems, but I think that's a bug in env2mfile (#13742). Signed-off-by: Simon McVittie --- docs/yaml/builtins/build_machine.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/yaml/builtins/build_machine.yaml b/docs/yaml/builtins/build_machine.yaml index 7b7fcd208ec5..83e0aaf3e6e5 100644 --- a/docs/yaml/builtins/build_machine.yaml +++ b/docs/yaml/builtins/build_machine.yaml @@ -22,7 +22,7 @@ methods: - name: cpu returns: str - description: Returns a more specific CPU name, such as `i686`, `amd64`, etc. + description: Returns a more specific CPU name, such as `i686`, `armv8l`, etc. - name: system returns: str From 3ee9e358b4be10d982a59fabf6e247cd16ac94f5 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 1 Oct 2024 14:13:49 -0700 Subject: [PATCH 242/302] Document the .kernel() and .subsystem() methods Which were added in Meson 1.2, but don't have entires in the reference manual. --- docs/yaml/builtins/build_machine.yaml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/docs/yaml/builtins/build_machine.yaml b/docs/yaml/builtins/build_machine.yaml index 83e0aaf3e6e5..b79525fd5053 100644 --- a/docs/yaml/builtins/build_machine.yaml +++ b/docs/yaml/builtins/build_machine.yaml @@ -35,3 +35,24 @@ methods: - name: endian returns: str description: returns `'big'` on big-endian systems and `'little'` on little-endian systems. + +- name: kernel + returns: str + since: 1.2.0 + description: | + Returns the name of the Operating System Kernel, such as `linux`, `xnu`, and + `nt`. [See here for more complete + list](Reference-tables.md#kernel-names-since-120) These are more specific + than `system`. If this cannot be detected (for the build machine), or is not + set in the cross file (for the host machine when cross compiling), calling + this method is fatal. + +- name: subsystem + returns: str + since: 1.2.0 + description: | + Returns the variant of the operating system, such as `ios` and `tvos`. [See + here for more complete list](Reference-tables.md#kernel-names-since-120) + These are more specific than `system`. If this cannot be detected (for the + build machine), or is not set in the cross file (for the host machine when + cross compiling), calling this method is fatal. From ed1d626c356e5d194b94943cd56bb99f14d38db0 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 2 Oct 2024 12:36:57 +0100 Subject: [PATCH 243/302] env2mfile: Convert MachineInfo into a dataclass This will make it easier to unit-test functions that work with a MachineInfo, by constructing the expected object in a single call. Signed-off-by: Simon McVittie --- mesonbuild/scripts/env2mfile.py | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/mesonbuild/scripts/env2mfile.py b/mesonbuild/scripts/env2mfile.py index c6f22ae7600c..ff3fedafba95 100755 --- a/mesonbuild/scripts/env2mfile.py +++ b/mesonbuild/scripts/env2mfile.py @@ -3,6 +3,7 @@ from __future__ import annotations +from dataclasses import dataclass, field import sys, os, subprocess, shutil import shlex import typing as T @@ -47,21 +48,21 @@ def add_arguments(parser: 'argparse.ArgumentParser') -> None: parser.add_argument('--endian', default='little', choices=['big', 'little'], help='Define endianness for cross compilation.') +@dataclass class MachineInfo: - def __init__(self) -> None: - self.compilers: T.Dict[str, T.List[str]] = {} - self.binaries: T.Dict[str, T.List[str]] = {} - self.properties: T.Dict[str, T.Union[str, T.List[str]]] = {} - self.compile_args: T.Dict[str, T.List[str]] = {} - self.link_args: T.Dict[str, T.List[str]] = {} - self.cmake: T.Dict[str, T.Union[str, T.List[str]]] = {} - - self.system: T.Optional[str] = None - self.subsystem: T.Optional[str] = None - self.kernel: T.Optional[str] = None - self.cpu: T.Optional[str] = None - self.cpu_family: T.Optional[str] = None - self.endian: T.Optional[str] = None + compilers: T.Dict[str, T.List[str]] = field(default_factory=dict) + binaries: T.Dict[str, T.List[str]] = field(default_factory=dict) + properties: T.Dict[str, T.Union[str, T.List[str]]] = field(default_factory=dict) + compile_args: T.Dict[str, T.List[str]] = field(default_factory=dict) + link_args: T.Dict[str, T.List[str]] = field(default_factory=dict) + cmake: T.Dict[str, T.Union[str, T.List[str]]] = field(default_factory=dict) + + system: T.Optional[str] = None + subsystem: T.Optional[str] = None + kernel: T.Optional[str] = None + cpu: T.Optional[str] = None + cpu_family: T.Optional[str] = None + endian: T.Optional[str] = None #parser = argparse.ArgumentParser(description='''Generate cross compilation definition file for the Meson build system. # From 6224a7f48e16852dd49fc85b02a5c508500d6db0 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 2 Oct 2024 12:38:01 +0100 Subject: [PATCH 244/302] env2mfile: Split detect_cross_debianlike() Separating the part that runs dpkg-architecture from the part that interprets its results will make it easier to unit-test the latter. Signed-off-by: Simon McVittie --- mesonbuild/scripts/env2mfile.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mesonbuild/scripts/env2mfile.py b/mesonbuild/scripts/env2mfile.py index ff3fedafba95..debf2745eb60 100755 --- a/mesonbuild/scripts/env2mfile.py +++ b/mesonbuild/scripts/env2mfile.py @@ -171,6 +171,9 @@ def detect_cross_debianlike(options: T.Any) -> MachineInfo: cmd = ['dpkg-architecture', '-a' + options.debarch] output = subprocess.check_output(cmd, universal_newlines=True, stderr=subprocess.DEVNULL) + return dpkg_architecture_to_machine_info(output, options) + +def dpkg_architecture_to_machine_info(output: str, options: T.Any) -> MachineInfo: data = {} for line in output.split('\n'): line = line.strip() From 1c11a04f94ae18fbe494cce84038763f11b65583 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 2 Oct 2024 12:43:17 +0100 Subject: [PATCH 245/302] unittests: Test env2mfile's dpkg_architecture_to_machine_info This test parses several possible outputs of dpkg-architecture and asserts that they produce the expected MachineInfo. To avoid depending on suitable cross-tools being installed, use unittest.mock to override locate_path with a version that pretends that all of the tools we're interested in are in /usr/bin. Similarly, use mock environment variables to exercise what happens when we have those set. The test data used here exercises most variations: * big- and little-endianness * GNU CPU (x86_64) differing from dpkg CPU (amd64) * Linux, kFreeBSD and Hurd * special-cased architectures: x86, arm, mips64el, ppc64el expected_compilers() intentionally doesn't assume that every compiler is gcc (even though they all are, right now), because #13721 proposes adding valac which does not take a gcc suffix. Signed-off-by: Simon McVittie --- unittests/internaltests.py | 391 +++++++++++++++++++++++++++++++++++++ 1 file changed, 391 insertions(+) diff --git a/unittests/internaltests.py b/unittests/internaltests.py index 310b4f680bad..13d3446bfe1a 100644 --- a/unittests/internaltests.py +++ b/unittests/internaltests.py @@ -4,6 +4,7 @@ from configparser import ConfigParser from pathlib import Path from unittest import mock +import argparse import contextlib import io import json @@ -13,6 +14,7 @@ import stat import subprocess import tempfile +import textwrap import typing as T import unittest @@ -23,6 +25,7 @@ import mesonbuild.envconfig import mesonbuild.environment import mesonbuild.modules.gnome +import mesonbuild.scripts.env2mfile from mesonbuild import coredata from mesonbuild.compilers.c import ClangCCompiler, GnuCCompiler from mesonbuild.compilers.cpp import VisualStudioCPPCompiler @@ -1715,3 +1718,391 @@ def test_option_key_from_string(self) -> None: for raw, expected in cases: with self.subTest(raw): self.assertEqual(OptionKey.from_string(raw), expected) + + def test_env2mfile_deb(self) -> None: + MachineInfo = mesonbuild.scripts.env2mfile.MachineInfo + to_machine_info = mesonbuild.scripts.env2mfile.dpkg_architecture_to_machine_info + + # For testing purposes, behave as though all cross-programs + # exist in /usr/bin + def locate_path(program: str) -> T.List[str]: + if os.path.isabs(program): + return [program] + return ['/usr/bin/' + program] + + def expected_compilers( + gnu_tuple: str, + gcc_suffix: str = '', + ) -> T.Dict[str, T.List[str]]: + return { + 'c': [f'/usr/bin/{gnu_tuple}-gcc{gcc_suffix}'], + 'cpp': [f'/usr/bin/{gnu_tuple}-g++{gcc_suffix}'], + 'objc': [f'/usr/bin/{gnu_tuple}-gobjc{gcc_suffix}'], + 'objcpp': [f'/usr/bin/{gnu_tuple}-gobjc++{gcc_suffix}'], + } + + def expected_binaries(gnu_tuple: str) -> T.Dict[str, T.List[str]]: + return { + 'ar': [f'/usr/bin/{gnu_tuple}-ar'], + 'strip': [f'/usr/bin/{gnu_tuple}-strip'], + 'objcopy': [f'/usr/bin/{gnu_tuple}-objcopy'], + 'ld': [f'/usr/bin/{gnu_tuple}-ld'], + 'cmake': ['/usr/bin/cmake'], + 'pkg-config': [f'/usr/bin/{gnu_tuple}-pkg-config'], + 'cups-config': ['/usr/bin/cups-config'], + } + + for title, dpkg_arch, gccsuffix, env, expected in [ + ( + # s390x is an example of the common case where the + # Meson CPU name, the GNU CPU name, the dpkg architecture + # name and uname -m all agree. + # (alpha, m68k, ppc64, riscv64, sh4, sparc64 are similar) + 's390x-linux-gnu', + # Output of `dpkg-architecture -a...`, filtered to + # only the DEB_HOST_ parts because that's all we use + textwrap.dedent( + ''' + DEB_HOST_ARCH=s390x + DEB_HOST_ARCH_ABI=base + DEB_HOST_ARCH_BITS=64 + DEB_HOST_ARCH_CPU=s390x + DEB_HOST_ARCH_ENDIAN=big + DEB_HOST_ARCH_LIBC=gnu + DEB_HOST_ARCH_OS=linux + DEB_HOST_GNU_CPU=s390x + DEB_HOST_GNU_SYSTEM=linux-gnu + DEB_HOST_GNU_TYPE=s390x-linux-gnu + DEB_HOST_MULTIARCH=s390x-linux-gnu + ''' + ), + '', + {'PATH': '/usr/bin'}, + MachineInfo( + compilers=expected_compilers('s390x-linux-gnu'), + binaries=expected_binaries('s390x-linux-gnu'), + properties={}, + compile_args={}, + link_args={}, + cmake={ + 'CMAKE_C_COMPILER': ['/usr/bin/s390x-linux-gnu-gcc'], + 'CMAKE_CXX_COMPILER': ['/usr/bin/s390x-linux-gnu-g++'], + 'CMAKE_SYSTEM_NAME': 'Linux', + 'CMAKE_SYSTEM_PROCESSOR': 's390x', + }, + system='linux', + subsystem='linux', + kernel='linux', + cpu='s390x', + cpu_family='s390x', + endian='big', + ), + ), + # Debian amd64 vs. GNU, Meson, etc. x86_64. + # arm64/aarch64, hppa/parisc, i386/i686/x86, loong64/loongarch64, + # powerpc/ppc are similar. + ( + 'x86_64-linux-gnu', + textwrap.dedent( + ''' + DEB_HOST_ARCH=amd64 + DEB_HOST_ARCH_ABI=base + DEB_HOST_ARCH_BITS=64 + DEB_HOST_ARCH_CPU=amd64 + DEB_HOST_ARCH_ENDIAN=little + DEB_HOST_ARCH_LIBC=gnu + DEB_HOST_ARCH_OS=linux + DEB_HOST_GNU_CPU=x86_64 + DEB_HOST_GNU_SYSTEM=linux-gnu + DEB_HOST_GNU_TYPE=x86_64-linux-gnu + DEB_HOST_MULTIARCH=x86_64-linux-gnu + ''' + ), + '', + {'PATH': '/usr/bin'}, + MachineInfo( + compilers=expected_compilers('x86_64-linux-gnu'), + binaries=expected_binaries('x86_64-linux-gnu'), + properties={}, + compile_args={}, + link_args={}, + cmake={ + 'CMAKE_C_COMPILER': ['/usr/bin/x86_64-linux-gnu-gcc'], + 'CMAKE_CXX_COMPILER': ['/usr/bin/x86_64-linux-gnu-g++'], + 'CMAKE_SYSTEM_NAME': 'Linux', + 'CMAKE_SYSTEM_PROCESSOR': 'x86_64', + }, + system='linux', + subsystem='linux', + kernel='linux', + # TODO: In native builds we get x86_64, but in + # cross-builds it's amd64 + cpu='TODO', + cpu_family='x86_64', + endian='little', + ), + ), + ( + 'arm-linux-gnueabihf with non-default gcc and environment', + textwrap.dedent( + ''' + DEB_HOST_ARCH=armhf + DEB_HOST_ARCH_ABI=eabihf + DEB_HOST_ARCH_BITS=32 + DEB_HOST_ARCH_CPU=arm + DEB_HOST_ARCH_ENDIAN=little + DEB_HOST_ARCH_LIBC=gnu + DEB_HOST_ARCH_OS=linux + DEB_HOST_GNU_CPU=arm + DEB_HOST_GNU_SYSTEM=linux-gnueabihf + DEB_HOST_GNU_TYPE=arm-linux-gnueabihf + DEB_HOST_MULTIARCH=arm-linux-gnueabihf + ''' + ), + '-12', + { + 'PATH': '/usr/bin', + 'CPPFLAGS': '-DNDEBUG', + 'CFLAGS': '-std=c99', + 'CXXFLAGS': '-std=c++11', + 'OBJCFLAGS': '-fobjc-exceptions', + 'OBJCXXFLAGS': '-fobjc-nilcheck', + 'LDFLAGS': '-Wl,-O1', + }, + MachineInfo( + compilers=expected_compilers('arm-linux-gnueabihf', '-12'), + binaries=expected_binaries('arm-linux-gnueabihf'), + properties={}, + compile_args={ + 'c': ['-DNDEBUG', '-std=c99'], + 'cpp': ['-DNDEBUG', '-std=c++11'], + 'objc': ['-DNDEBUG', '-fobjc-exceptions'], + 'objcpp': ['-DNDEBUG', '-fobjc-nilcheck'], + }, + link_args={ + 'c': ['-std=c99', '-Wl,-O1'], + 'cpp': ['-std=c++11', '-Wl,-O1'], + 'objc': ['-fobjc-exceptions', '-Wl,-O1'], + 'objcpp': ['-fobjc-nilcheck', '-Wl,-O1'], + }, + cmake={ + 'CMAKE_C_COMPILER': ['/usr/bin/arm-linux-gnueabihf-gcc-12'], + 'CMAKE_CXX_COMPILER': ['/usr/bin/arm-linux-gnueabihf-g++-12'], + 'CMAKE_SYSTEM_NAME': 'Linux', + 'CMAKE_SYSTEM_PROCESSOR': 'armv7l', + }, + system='linux', + subsystem='linux', + kernel='linux', + # In a native build this would often be armv8l + # (the version of the running CPU) but the architecture + # baseline in Debian is officially ARMv7 + cpu='arm7hlf', + cpu_family='arm', + endian='little', + ), + ), + ( + 'special cases for i386 (i686, x86) and Hurd', + textwrap.dedent( + ''' + DEB_HOST_ARCH=hurd-i386 + DEB_HOST_ARCH_ABI=base + DEB_HOST_ARCH_BITS=32 + DEB_HOST_ARCH_CPU=i386 + DEB_HOST_ARCH_ENDIAN=little + DEB_HOST_ARCH_LIBC=gnu + DEB_HOST_ARCH_OS=hurd + DEB_HOST_GNU_CPU=i686 + DEB_HOST_GNU_SYSTEM=gnu + DEB_HOST_GNU_TYPE=i686-gnu + DEB_HOST_MULTIARCH=i386-gnu + ''' + ), + '', + {'PATH': '/usr/bin'}, + MachineInfo( + compilers=expected_compilers('i686-gnu'), + binaries=expected_binaries('i686-gnu'), + properties={}, + compile_args={}, + link_args={}, + cmake={ + 'CMAKE_C_COMPILER': ['/usr/bin/i686-gnu-gcc'], + 'CMAKE_CXX_COMPILER': ['/usr/bin/i686-gnu-g++'], + 'CMAKE_SYSTEM_NAME': 'GNU', + 'CMAKE_SYSTEM_PROCESSOR': 'i686', + }, + # TODO: Currently hurd, but should be gnu as per + # https://mesonbuild.com/Reference-tables.html + system='TODO', + subsystem='TODO', + # TODO: Currently linux, but should be gnu/hurd/mach? + # https://github.com/mesonbuild/meson/issues/13740 + kernel='TODO', + # TODO: Currently hurd-i386, but should be i686 + cpu='TODO', + cpu_family='x86', + endian='little', + ), + ), + ( + 'special cases for amd64 (x86_64) and kFreeBSD', + textwrap.dedent( + ''' + DEB_HOST_ARCH=kfreebsd-amd64 + DEB_HOST_ARCH_ABI=base + DEB_HOST_ARCH_BITS=64 + DEB_HOST_ARCH_CPU=x86_amd64 + DEB_HOST_ARCH_ENDIAN=little + DEB_HOST_ARCH_LIBC=gnu + DEB_HOST_ARCH_OS=kfreebsd + DEB_HOST_GNU_CPU=x86_64 + DEB_HOST_GNU_SYSTEM=kfreebsd-gnu + DEB_HOST_GNU_TYPE=x86_64-kfreebsd-gnu + DEB_HOST_MULTIARCH=x86_64-kfreebsd-gnu + ''' + ), + '', + {'PATH': '/usr/bin'}, + MachineInfo( + compilers=expected_compilers('x86_64-kfreebsd-gnu'), + binaries=expected_binaries('x86_64-kfreebsd-gnu'), + properties={}, + compile_args={}, + link_args={}, + cmake={ + 'CMAKE_C_COMPILER': ['/usr/bin/x86_64-kfreebsd-gnu-gcc'], + 'CMAKE_CXX_COMPILER': ['/usr/bin/x86_64-kfreebsd-gnu-g++'], + 'CMAKE_SYSTEM_NAME': 'kFreeBSD', + 'CMAKE_SYSTEM_PROCESSOR': 'x86_64', + }, + system='kfreebsd', + subsystem='kfreebsd', + # TODO: Currently linux but should be freebsd + kernel='TODO', + # TODO: Currently kfreebsd-amd64 but should be x86_64 + cpu='TODO', + cpu_family='x86_64', + endian='little', + ), + ), + ( + 'special case for mips64el', + textwrap.dedent( + ''' + DEB_HOST_ARCH=mips64el + DEB_HOST_ARCH_ABI=abi64 + DEB_HOST_ARCH_BITS=64 + DEB_HOST_ARCH_CPU=mips64el + DEB_HOST_ARCH_ENDIAN=little + DEB_HOST_ARCH_LIBC=gnu + DEB_HOST_ARCH_OS=linux + DEB_HOST_GNU_CPU=mips64el + DEB_HOST_GNU_SYSTEM=linux-gnuabi64 + DEB_HOST_GNU_TYPE=mips64el-linux-gnuabi64 + DEB_HOST_MULTIARCH=mips64el-linux-gnuabi64 + ''' + ), + '', + {'PATH': '/usr/bin'}, + MachineInfo( + compilers=expected_compilers('mips64el-linux-gnuabi64'), + binaries=expected_binaries('mips64el-linux-gnuabi64'), + properties={}, + compile_args={}, + link_args={}, + cmake={ + 'CMAKE_C_COMPILER': ['/usr/bin/mips64el-linux-gnuabi64-gcc'], + 'CMAKE_CXX_COMPILER': ['/usr/bin/mips64el-linux-gnuabi64-g++'], + 'CMAKE_SYSTEM_NAME': 'Linux', + 'CMAKE_SYSTEM_PROCESSOR': 'mips64', + }, + system='linux', + subsystem='linux', + kernel='linux', + cpu='mips64', + cpu_family='mips64', + endian='little', + ), + ), + ( + 'special case for ppc64el', + textwrap.dedent( + ''' + DEB_HOST_ARCH=ppc64el + DEB_HOST_ARCH_ABI=base + DEB_HOST_ARCH_BITS=64 + DEB_HOST_ARCH_CPU=ppc64el + DEB_HOST_ARCH_ENDIAN=little + DEB_HOST_ARCH_LIBC=gnu + DEB_HOST_ARCH_OS=linux + DEB_HOST_GNU_CPU=powerpc64le + DEB_HOST_GNU_SYSTEM=linux-gnu + DEB_HOST_GNU_TYPE=powerpc64le-linux-gnu + DEB_HOST_MULTIARCH=powerpc64le-linux-gnu + ''' + ), + '', + {'PATH': '/usr/bin'}, + MachineInfo( + compilers=expected_compilers('powerpc64le-linux-gnu'), + binaries=expected_binaries('powerpc64le-linux-gnu'), + properties={}, + compile_args={}, + link_args={}, + cmake={ + 'CMAKE_C_COMPILER': ['/usr/bin/powerpc64le-linux-gnu-gcc'], + 'CMAKE_CXX_COMPILER': ['/usr/bin/powerpc64le-linux-gnu-g++'], + 'CMAKE_SYSTEM_NAME': 'Linux', + 'CMAKE_SYSTEM_PROCESSOR': 'ppc64le', + }, + system='linux', + subsystem='linux', + kernel='linux', + # TODO: Currently ppc64el, but native builds have ppc64le, + # and maybe it should be ppc64 in both cases? + # https://github.com/mesonbuild/meson/issues/13741 + cpu='TODO', + cpu_family='ppc64', + endian='little', + ), + ), + ]: + with self.subTest(title), \ + unittest.mock.patch.dict('os.environ', env, clear=True), \ + unittest.mock.patch('mesonbuild.scripts.env2mfile.locate_path') as mock_locate_path: + mock_locate_path.side_effect = locate_path + options = argparse.Namespace() + options.gccsuffix = gccsuffix + actual = to_machine_info(dpkg_arch, options) + + if expected.system == 'TODO': + print(f'TODO: {title}: system() -> {actual.system}') + else: + self.assertEqual(actual.system, expected.system) + + if expected.subsystem == 'TODO': + print(f'TODO: {title}: subsystem() -> {actual.subsystem}') + else: + self.assertEqual(actual.subsystem, expected.subsystem) + + if expected.kernel == 'TODO': + print(f'TODO: {title}: kernel() -> {actual.kernel}') + else: + self.assertEqual(actual.kernel, expected.kernel) + + if expected.cpu == 'TODO': + print(f'TODO: {title}: cpu() -> {actual.cpu}') + else: + self.assertEqual(actual.cpu, expected.cpu) + + self.assertEqual(actual.cpu_family, expected.cpu_family) + self.assertEqual(actual.endian, expected.endian) + + self.assertEqual(actual.compilers, expected.compilers) + self.assertEqual(actual.binaries, expected.binaries) + self.assertEqual(actual.properties, expected.properties) + self.assertEqual(actual.compile_args, expected.compile_args) + self.assertEqual(actual.link_args, expected.link_args) + self.assertEqual(actual.cmake, expected.cmake) From b4a7251eb8cb73eb2038ffe80a0b3d4211733fe8 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 2 Oct 2024 18:52:17 +0100 Subject: [PATCH 246/302] env2mfile: Add a function for mostly-identity mappings with special cases This makes the frequent pattern of things like "CPU families are the same as GNU CPUs, with a few known exceptions" less verbose. Signed-off-by: Simon McVittie --- mesonbuild/scripts/env2mfile.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/mesonbuild/scripts/env2mfile.py b/mesonbuild/scripts/env2mfile.py index debf2745eb60..68496b9f2a53 100755 --- a/mesonbuild/scripts/env2mfile.py +++ b/mesonbuild/scripts/env2mfile.py @@ -142,6 +142,13 @@ def get_args_from_envvars(infos: MachineInfo) -> None: 'powerpc64le': 'ppc64', } +def replace_special_cases(special_cases: T.Mapping[str, str], name: str) -> str: + ''' + If name is a key in special_cases, replace it with the value, or otherwise + pass it through unchanged. + ''' + return special_cases.get(name, name) + def deb_detect_cmake(infos: MachineInfo, data: T.Dict[str, str]) -> None: system_name_map = {'linux': 'Linux', 'kfreebsd': 'kFreeBSD', 'hurd': 'GNU'} system_processor_map = {'arm': 'armv7l', 'mips64el': 'mips64', 'powerpc64le': 'ppc64le'} @@ -152,8 +159,7 @@ def deb_detect_cmake(infos: MachineInfo, data: T.Dict[str, str]) -> None: except KeyError: pass infos.cmake["CMAKE_SYSTEM_NAME"] = system_name_map[data['DEB_HOST_ARCH_OS']] - infos.cmake["CMAKE_SYSTEM_PROCESSOR"] = system_processor_map.get(data['DEB_HOST_GNU_CPU'], - data['DEB_HOST_GNU_CPU']) + infos.cmake["CMAKE_SYSTEM_PROCESSOR"] = replace_special_cases(system_processor_map, data['DEB_HOST_GNU_CPU']) def deb_compiler_lookup(infos: MachineInfo, compilerstems: T.List[T.Tuple[str, str]], host_arch: str, gccsuffix: str) -> None: for langname, stem in compilerstems: @@ -185,10 +191,8 @@ def dpkg_architecture_to_machine_info(output: str, options: T.Any) -> MachineInf host_os = data['DEB_HOST_ARCH_OS'] host_subsystem = host_os host_kernel = 'linux' - host_cpu_family = deb_cpu_family_map.get(data['DEB_HOST_GNU_CPU'], - data['DEB_HOST_GNU_CPU']) - host_cpu = deb_cpu_map.get(data['DEB_HOST_ARCH'], - data['DEB_HOST_ARCH']) + host_cpu_family = replace_special_cases(deb_cpu_family_map, data['DEB_HOST_GNU_CPU']) + host_cpu = replace_special_cases(deb_cpu_map, data['DEB_HOST_ARCH']) host_endian = data['DEB_HOST_ARCH_ENDIAN'] compilerstems = [('c', 'gcc'), From 1909a8180b60cf9b8cc3663dff9fb486b13ab3b4 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 2 Oct 2024 18:54:02 +0100 Subject: [PATCH 247/302] env2mfile: Map Debian GNU/Hurd to system() -> gnu As per , and matching what happens when running Meson for a native build on Debian GNU/Hurd. Signed-off-by: Simon McVittie --- mesonbuild/scripts/env2mfile.py | 7 ++++++- unittests/internaltests.py | 6 ++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/mesonbuild/scripts/env2mfile.py b/mesonbuild/scripts/env2mfile.py index 68496b9f2a53..57a679c59bbc 100755 --- a/mesonbuild/scripts/env2mfile.py +++ b/mesonbuild/scripts/env2mfile.py @@ -142,6 +142,11 @@ def get_args_from_envvars(infos: MachineInfo) -> None: 'powerpc64le': 'ppc64', } +# map from DEB_HOST_ARCH_OS to Meson machine.system() +deb_os_map = { + 'hurd': 'gnu', +} + def replace_special_cases(special_cases: T.Mapping[str, str], name: str) -> str: ''' If name is a key in special_cases, replace it with the value, or otherwise @@ -188,7 +193,7 @@ def dpkg_architecture_to_machine_info(output: str, options: T.Any) -> MachineInf k, v = line.split('=', 1) data[k] = v host_arch = data['DEB_HOST_GNU_TYPE'] - host_os = data['DEB_HOST_ARCH_OS'] + host_os = replace_special_cases(deb_os_map, data['DEB_HOST_ARCH_OS']) host_subsystem = host_os host_kernel = 'linux' host_cpu_family = replace_special_cases(deb_cpu_family_map, data['DEB_HOST_GNU_CPU']) diff --git a/unittests/internaltests.py b/unittests/internaltests.py index 13d3446bfe1a..36b124db821b 100644 --- a/unittests/internaltests.py +++ b/unittests/internaltests.py @@ -1933,10 +1933,8 @@ def expected_binaries(gnu_tuple: str) -> T.Dict[str, T.List[str]]: 'CMAKE_SYSTEM_NAME': 'GNU', 'CMAKE_SYSTEM_PROCESSOR': 'i686', }, - # TODO: Currently hurd, but should be gnu as per - # https://mesonbuild.com/Reference-tables.html - system='TODO', - subsystem='TODO', + system='gnu', + subsystem='gnu', # TODO: Currently linux, but should be gnu/hurd/mach? # https://github.com/mesonbuild/meson/issues/13740 kernel='TODO', From 114a3e29144c99c6ff36c656ab3d72fd5aa36f6e Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 2 Oct 2024 18:55:23 +0100 Subject: [PATCH 248/302] env2mfile: Don't hard-code Debian as always being Linux All official Debian release architectures use the Linux kernel, but unofficial ports like hurd-i386 and kfreebsd-amd64 use the Hurd and FreeBSD kernel, respectively. Map Linux to 'linux' and kFreeBSD ports to 'freebsd' as per the reference tables in Meson's documentation. For now, use the Debian system name such as 'hurd' for anything else (see #13740 for the question of whether Hurd should identify its kernel differently). Signed-off-by: Simon McVittie --- mesonbuild/scripts/env2mfile.py | 7 ++++++- unittests/internaltests.py | 7 ++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/mesonbuild/scripts/env2mfile.py b/mesonbuild/scripts/env2mfile.py index 57a679c59bbc..a59c1c40cba6 100755 --- a/mesonbuild/scripts/env2mfile.py +++ b/mesonbuild/scripts/env2mfile.py @@ -147,6 +147,11 @@ def get_args_from_envvars(infos: MachineInfo) -> None: 'hurd': 'gnu', } +# map from DEB_HOST_ARCH_OS to Meson machine.kernel() +deb_kernel_map = { + 'kfreebsd': 'freebsd', +} + def replace_special_cases(special_cases: T.Mapping[str, str], name: str) -> str: ''' If name is a key in special_cases, replace it with the value, or otherwise @@ -195,7 +200,7 @@ def dpkg_architecture_to_machine_info(output: str, options: T.Any) -> MachineInf host_arch = data['DEB_HOST_GNU_TYPE'] host_os = replace_special_cases(deb_os_map, data['DEB_HOST_ARCH_OS']) host_subsystem = host_os - host_kernel = 'linux' + host_kernel = replace_special_cases(deb_kernel_map, data['DEB_HOST_ARCH_OS']) host_cpu_family = replace_special_cases(deb_cpu_family_map, data['DEB_HOST_GNU_CPU']) host_cpu = replace_special_cases(deb_cpu_map, data['DEB_HOST_ARCH']) host_endian = data['DEB_HOST_ARCH_ENDIAN'] diff --git a/unittests/internaltests.py b/unittests/internaltests.py index 36b124db821b..fbcfc1cf546b 100644 --- a/unittests/internaltests.py +++ b/unittests/internaltests.py @@ -1935,7 +1935,9 @@ def expected_binaries(gnu_tuple: str) -> T.Dict[str, T.List[str]]: }, system='gnu', subsystem='gnu', - # TODO: Currently linux, but should be gnu/hurd/mach? + # TODO: Currently hurd; should match whatever happens + # during native builds, but at the moment native builds + # fail when kernel() is called. # https://github.com/mesonbuild/meson/issues/13740 kernel='TODO', # TODO: Currently hurd-i386, but should be i686 @@ -1977,8 +1979,7 @@ def expected_binaries(gnu_tuple: str) -> T.Dict[str, T.List[str]]: }, system='kfreebsd', subsystem='kfreebsd', - # TODO: Currently linux but should be freebsd - kernel='TODO', + kernel='freebsd', # TODO: Currently kfreebsd-amd64 but should be x86_64 cpu='TODO', cpu_family='x86_64', From 9d0de83368c89ff7fc54ec95d5f15ec29e8e0f0e Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 2 Oct 2024 18:57:21 +0100 Subject: [PATCH 249/302] env2mfile: Base cpu on DEB_HOST_GNU_CPU unless DEB_HOST_ARCH is special `DEB_HOST_ARCH` encodes both the CPU family and the OS, so using it to get the CPU type gives the wrong answer for non-Linux ports. However, `DEB_HOST_GNU_CPU` gives less detailed information about the CPU: it's `arm` for all 32-bit ARM CPUs, and doesn't distinguish between the differing baselines of `armel` (ARMv5 softfloat) and `armhf` (ARMv7 hardfloat). When cross-compiling for x86_64 Linux, this changes the `cpu()` from `amd64` to `x86_64`, which is consistent with the answer we get during native builds on that architecture. When cross-compiling for `ppc64el`, this changes the `cpu()` from `ppc64el` to `ppc64`, which is a reasonable change but is still not consistent with what we see during native builds (which is `ppc64le`): see #13741 for that. Resolves: https://github.com/mesonbuild/meson/issues/13742 Signed-off-by: Simon McVittie --- mesonbuild/scripts/env2mfile.py | 11 +++++++++-- unittests/internaltests.py | 13 ++++--------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/mesonbuild/scripts/env2mfile.py b/mesonbuild/scripts/env2mfile.py index a59c1c40cba6..207d75749c95 100755 --- a/mesonbuild/scripts/env2mfile.py +++ b/mesonbuild/scripts/env2mfile.py @@ -130,14 +130,20 @@ def get_args_from_envvars(infos: MachineInfo) -> None: if objcpp_link_args: infos.link_args['objcpp'] = objcpp_link_args +# map from DEB_HOST_GNU_CPU to Meson machine.cpu_family() deb_cpu_family_map = { 'mips64el': 'mips64', 'i686': 'x86', 'powerpc64le': 'ppc64', } -deb_cpu_map = { +# map from DEB_HOST_ARCH to Meson machine.cpu() +deb_arch_cpu_map = { 'armhf': 'arm7hlf', +} + +# map from DEB_HOST_GNU_CPU to Meson machine.cpu() +deb_cpu_map = { 'mips64el': 'mips64', 'powerpc64le': 'ppc64', } @@ -202,7 +208,8 @@ def dpkg_architecture_to_machine_info(output: str, options: T.Any) -> MachineInf host_subsystem = host_os host_kernel = replace_special_cases(deb_kernel_map, data['DEB_HOST_ARCH_OS']) host_cpu_family = replace_special_cases(deb_cpu_family_map, data['DEB_HOST_GNU_CPU']) - host_cpu = replace_special_cases(deb_cpu_map, data['DEB_HOST_ARCH']) + host_cpu = deb_arch_cpu_map.get(data['DEB_HOST_ARCH'], + replace_special_cases(deb_cpu_map, data['DEB_HOST_GNU_CPU'])) host_endian = data['DEB_HOST_ARCH_ENDIAN'] compilerstems = [('c', 'gcc'), diff --git a/unittests/internaltests.py b/unittests/internaltests.py index fbcfc1cf546b..23d08e6e2992 100644 --- a/unittests/internaltests.py +++ b/unittests/internaltests.py @@ -1835,9 +1835,7 @@ def expected_binaries(gnu_tuple: str) -> T.Dict[str, T.List[str]]: system='linux', subsystem='linux', kernel='linux', - # TODO: In native builds we get x86_64, but in - # cross-builds it's amd64 - cpu='TODO', + cpu='x86_64', cpu_family='x86_64', endian='little', ), @@ -1940,8 +1938,7 @@ def expected_binaries(gnu_tuple: str) -> T.Dict[str, T.List[str]]: # fail when kernel() is called. # https://github.com/mesonbuild/meson/issues/13740 kernel='TODO', - # TODO: Currently hurd-i386, but should be i686 - cpu='TODO', + cpu='i686', cpu_family='x86', endian='little', ), @@ -1980,8 +1977,7 @@ def expected_binaries(gnu_tuple: str) -> T.Dict[str, T.List[str]]: system='kfreebsd', subsystem='kfreebsd', kernel='freebsd', - # TODO: Currently kfreebsd-amd64 but should be x86_64 - cpu='TODO', + cpu='x86_64', cpu_family='x86_64', endian='little', ), @@ -2059,8 +2055,7 @@ def expected_binaries(gnu_tuple: str) -> T.Dict[str, T.List[str]]: system='linux', subsystem='linux', kernel='linux', - # TODO: Currently ppc64el, but native builds have ppc64le, - # and maybe it should be ppc64 in both cases? + # TODO: Currently ppc64, but native builds have ppc64le # https://github.com/mesonbuild/meson/issues/13741 cpu='TODO', cpu_family='ppc64', From 3c2d04d702a765a9510ede80f517f5274dde5933 Mon Sep 17 00:00:00 2001 From: Andrei Horodniceanu Date: Mon, 23 Sep 2024 21:22:29 +0300 Subject: [PATCH 250/302] ci/ciimage: Lower nofile ulimit on containers that test D The D stdlib function std.process.spawnProcessPosix suffers from a bug that causes any program that calls it to OOM if the nofile ulimit is large. This doesn't affect CI currently but trying to run or build the containers locally will most likely crash when calling dub as docker defaults to something like 1073741816 for both the hard limit and soft limit. Lowering the soft limit is enough to make dub behave. Signed-off-by: Andrei Horodniceanu --- ci/ciimage/opensuse/install.sh | 3 +++ ci/ciimage/ubuntu-rolling/install.sh | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/ci/ciimage/opensuse/install.sh b/ci/ciimage/opensuse/install.sh index 7de18ecb646b..fdfedcb1bf2e 100755 --- a/ci/ciimage/opensuse/install.sh +++ b/ci/ciimage/opensuse/install.sh @@ -35,6 +35,9 @@ echo 'export PKG_CONFIG_PATH="/usr/lib64/mpi/gcc/openmpi3/lib64/pkgconfig:$PKG_C curl -fsS https://dlang.org/install.sh | bash -s dmd | tee dmd_out.txt cat dmd_out.txt | grep source | sed 's/^[^`]*`//g' | sed 's/`.*//g' >> /ci/env_vars.sh chmod +x /ci/env_vars.sh +# Lower ulimit before running dub, otherwise there's a very high chance it will OOM. +# See: https://github.com/dlang/phobos/pull/9048 and https://github.com/dlang/phobos/pull/8990 +echo 'ulimit -n -S 10000' >> /ci/env_vars.sh source /ci/env_vars.sh diff --git a/ci/ciimage/ubuntu-rolling/install.sh b/ci/ciimage/ubuntu-rolling/install.sh index 1706d837dc00..2066944e4cf5 100755 --- a/ci/ciimage/ubuntu-rolling/install.sh +++ b/ci/ciimage/ubuntu-rolling/install.sh @@ -44,6 +44,10 @@ eatmydata apt-get -y install --no-install-recommends wine-stable # Wine is spec install_python_packages hotdoc +# Lower ulimit before running dub, otherwise there's a very high chance it will OOM. +# See: https://github.com/dlang/phobos/pull/9048 and https://github.com/dlang/phobos/pull/8990 +echo 'ulimit -n -S 10000' >> /ci/env_vars.sh +ulimit -n -S 10000 # dub stuff dub_fetch urld dub build --deep urld --arch=x86_64 --compiler=gdc --build=debug From 0f914b75fe39d924ff93d9651eba79c32c597365 Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Thu, 26 Sep 2024 14:50:52 +0530 Subject: [PATCH 251/302] programs: Allow excluding certain paths when searching in PATH --- mesonbuild/dependencies/configtool.py | 10 +++-- mesonbuild/dependencies/ui.py | 2 +- mesonbuild/interpreter/interpreter.py | 18 ++++---- mesonbuild/programs.py | 62 ++++++++++++++++----------- unittests/failuretests.py | 4 +- 5 files changed, 54 insertions(+), 42 deletions(-) diff --git a/mesonbuild/dependencies/configtool.py b/mesonbuild/dependencies/configtool.py index ef106a8b0acd..476f7ad420aa 100644 --- a/mesonbuild/dependencies/configtool.py +++ b/mesonbuild/dependencies/configtool.py @@ -37,7 +37,7 @@ class ConfigToolDependency(ExternalDependency): allow_default_for_cross = False __strip_version = re.compile(r'^[0-9][0-9.]+') - def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any], language: T.Optional[str] = None): + def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any], language: T.Optional[str] = None, exclude_paths: T.Optional[T.List[str]] = None): super().__init__(DependencyTypeName('config-tool'), environment, kwargs, language=language) self.name = name # You may want to overwrite the class version in some cases @@ -52,7 +52,7 @@ def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T. req_version = mesonlib.stringlistify(req_version_raw) else: req_version = [] - tool, version = self.find_config(req_version, kwargs.get('returncode_value', 0)) + tool, version = self.find_config(req_version, kwargs.get('returncode_value', 0), exclude_paths=exclude_paths) self.config = tool self.is_found = self.report_config(version, req_version) if not self.is_found: @@ -84,15 +84,17 @@ def _check_and_get_version(self, tool: T.List[str], returncode: int) -> T.Tuple[ version = self._sanitize_version(out.strip()) return valid, version - def find_config(self, versions: T.List[str], returncode: int = 0) \ + def find_config(self, versions: T.List[str], returncode: int = 0, exclude_paths: T.Optional[T.List[str]] = None) \ -> T.Tuple[T.Optional[T.List[str]], T.Optional[str]]: """Helper method that searches for config tool binaries in PATH and returns the one that best matches the given version requirements. """ + exclude_paths = [] if exclude_paths is None else exclude_paths best_match: T.Tuple[T.Optional[T.List[str]], T.Optional[str]] = (None, None) for potential_bin in find_external_program( self.env, self.for_machine, self.tool_name, - self.tool_name, self.tools, allow_default_for_cross=self.allow_default_for_cross): + self.tool_name, self.tools, exclude_paths=exclude_paths, + allow_default_for_cross=self.allow_default_for_cross): if not potential_bin.found(): continue tool = potential_bin.get_command() diff --git a/mesonbuild/dependencies/ui.py b/mesonbuild/dependencies/ui.py index cc17377a649b..d88af7945c7c 100644 --- a/mesonbuild/dependencies/ui.py +++ b/mesonbuild/dependencies/ui.py @@ -68,7 +68,7 @@ def __init__(self, environment: 'Environment', kwargs: T.Dict[str, T.Any]) -> No ['--gui-libs' if 'gui' in self.modules else '--base-libs'], 'link_args')) - def find_config(self, versions: T.Optional[T.List[str]] = None, returncode: int = 0) -> T.Tuple[T.Optional[T.List[str]], T.Optional[str]]: + def find_config(self, versions: T.Optional[T.List[str]] = None, returncode: int = 0, exclude_paths: T.Optional[T.List[str]] = None) -> T.Tuple[T.Optional[T.List[str]], T.Optional[str]]: tool = [self.tools[0]] try: p, out = Popen_safe(tool + ['--help'])[:2] diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index eceb40a6bcbe..aa839da361f4 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -816,7 +816,7 @@ def run_command_impl(self, cmd = cmd.absolute_path(srcdir, builddir) # Prefer scripts in the current source directory search_dir = os.path.join(srcdir, self.subdir) - prog = ExternalProgram(cmd, silent=True, search_dir=search_dir) + prog = ExternalProgram(cmd, silent=True, search_dirs=[search_dir]) if not prog.found(): raise InterpreterException(f'Program or command {cmd!r} not found or not executable') cmd = prog @@ -1586,7 +1586,7 @@ def program_from_file_for(self, for_machine: MachineChoice, prognames: T.List[me return prog return None - def program_from_system(self, args: T.List[mesonlib.FileOrString], search_dirs: T.List[str], + def program_from_system(self, args: T.List[mesonlib.FileOrString], search_dirs: T.Optional[T.List[str]], extra_info: T.List[mlog.TV_Loggable]) -> T.Optional[ExternalProgram]: # Search for scripts relative to current subdir. # Do not cache found programs because find_program('foobar') @@ -1601,15 +1601,15 @@ def program_from_system(self, args: T.List[mesonlib.FileOrString], search_dirs: search_dir = os.path.join(self.environment.get_source_dir(), exename.subdir) exename = exename.fname - extra_search_dirs = [] + search_dirs = [search_dir] elif isinstance(exename, str): - search_dir = source_dir - extra_search_dirs = search_dirs + if search_dirs: + search_dirs = [source_dir] + search_dirs + else: + search_dirs = [source_dir] else: raise InvalidArguments(f'find_program only accepts strings and files, not {exename!r}') - extprog = ExternalProgram(exename, search_dir=search_dir, - extra_search_dirs=extra_search_dirs, - silent=True) + extprog = ExternalProgram(exename, search_dirs=search_dirs, silent=True) if extprog.found(): extra_info.append(f"({' '.join(extprog.get_command())})") return extprog @@ -1681,7 +1681,7 @@ def find_program_impl(self, args: T.List[mesonlib.FileOrString], def program_lookup(self, args: T.List[mesonlib.FileOrString], for_machine: MachineChoice, default_options: T.Optional[T.Dict[OptionKey, T.Union[str, int, bool, T.List[str]]]], required: bool, - search_dirs: T.List[str], + search_dirs: T.Optional[T.List[str]], wanted: T.Union[str, T.List[str]], version_arg: T.Optional[str], version_func: T.Optional[ProgramVersionFunc], diff --git a/mesonbuild/programs.py b/mesonbuild/programs.py index bbe8ea421cb4..9ad38e126b60 100644 --- a/mesonbuild/programs.py +++ b/mesonbuild/programs.py @@ -25,14 +25,20 @@ class ExternalProgram(mesonlib.HoldableObject): - """A program that is found on the system.""" + """A program that is found on the system. + :param name: The name of the program + :param command: Optionally, an argument list constituting the command. Used when + you already know the command and do not want to search. + :param silent: Whether to print messages when initializing + :param search_dirs: A list of directories to search in first, followed by PATH + :param exclude_paths: A list of directories to exclude when searching in PATH""" windows_exts = ('exe', 'msc', 'com', 'bat', 'cmd') for_machine = MachineChoice.BUILD def __init__(self, name: str, command: T.Optional[T.List[str]] = None, - silent: bool = False, search_dir: T.Optional[str] = None, - extra_search_dirs: T.Optional[T.List[str]] = None): + silent: bool = False, search_dirs: T.Optional[T.List[T.Optional[str]]] = None, + exclude_paths: T.Optional[T.List[str]] = None): self.name = name self.path: T.Optional[str] = None self.cached_version: T.Optional[str] = None @@ -51,13 +57,10 @@ def __init__(self, name: str, command: T.Optional[T.List[str]] = None, else: self.command = [cmd] + args else: - all_search_dirs = [search_dir] - if extra_search_dirs: - all_search_dirs += extra_search_dirs - for d in all_search_dirs: - self.command = self._search(name, d) - if self.found(): - break + if search_dirs is None: + # For compat with old behaviour + search_dirs = [None] + self.command = self._search(name, search_dirs, exclude_paths) if self.found(): # Set path to be the last item that is actually a file (in order to @@ -242,7 +245,7 @@ def _search_dir(self, name: str, search_dir: T.Optional[str]) -> T.Optional[list return [trial_ext] return None - def _search_windows_special_cases(self, name: str, command: str) -> T.List[T.Optional[str]]: + def _search_windows_special_cases(self, name: str, command: T.Optional[str], exclude_paths: T.Optional[T.List[str]]) -> T.List[T.Optional[str]]: ''' Lots of weird Windows quirks: 1. PATH search for @name returns files with extensions from PATHEXT, @@ -278,31 +281,37 @@ def _search_windows_special_cases(self, name: str, command: str) -> T.List[T.Opt # On Windows, interpreted scripts must have an extension otherwise they # cannot be found by a standard PATH search. So we do a custom search # where we manually search for a script with a shebang in PATH. - search_dirs = self._windows_sanitize_path(os.environ.get('PATH', '')).split(';') + search_dirs = OrderedSet(self._windows_sanitize_path(os.environ.get('PATH', '')).split(';')) + if exclude_paths: + search_dirs.difference_update(exclude_paths) for search_dir in search_dirs: commands = self._search_dir(name, search_dir) if commands: return commands return [None] - def _search(self, name: str, search_dir: T.Optional[str]) -> T.List[T.Optional[str]]: + def _search(self, name: str, search_dirs: T.List[T.Optional[str]], exclude_paths: T.Optional[T.List[str]]) -> T.List[T.Optional[str]]: ''' - Search in the specified dir for the specified executable by name + Search in the specified dirs for the specified executable by name and if not found search in PATH ''' - commands = self._search_dir(name, search_dir) - if commands: - return commands + for search_dir in search_dirs: + commands = self._search_dir(name, search_dir) + if commands: + return commands # If there is a directory component, do not look in PATH if os.path.dirname(name) and not os.path.isabs(name): return [None] # Do a standard search in PATH - path = os.environ.get('PATH', None) + path = os.environ.get('PATH', os.defpath) if mesonlib.is_windows() and path: path = self._windows_sanitize_path(path) + if exclude_paths: + paths = OrderedSet(path.split(os.pathsep)).difference(exclude_paths) + path = os.pathsep.join(paths) command = shutil.which(name, path=path) if mesonlib.is_windows(): - return self._search_windows_special_cases(name, command) + return self._search_windows_special_cases(name, command, exclude_paths) # On UNIX-like platforms, shutil.which() is enough to find # all executables whether in PATH or with an absolute path return [command] @@ -341,15 +350,16 @@ class OverrideProgram(ExternalProgram): """A script overriding a program.""" def __init__(self, name: str, version: str, command: T.Optional[T.List[str]] = None, - silent: bool = False, search_dir: T.Optional[str] = None, - extra_search_dirs: T.Optional[T.List[str]] = None): + silent: bool = False, search_dirs: T.Optional[T.List[T.Optional[str]]] = None, + exclude_paths: T.Optional[T.List[str]] = None): self.cached_version = version super().__init__(name, command=command, silent=silent, - search_dir=search_dir, extra_search_dirs=extra_search_dirs) + search_dirs=search_dirs, exclude_paths=exclude_paths) def find_external_program(env: 'Environment', for_machine: MachineChoice, name: str, display_name: str, default_names: T.List[str], - allow_default_for_cross: bool = True) -> T.Generator['ExternalProgram', None, None]: + allow_default_for_cross: bool = True, + exclude_paths: T.Optional[T.List[str]] = None) -> T.Generator['ExternalProgram', None, None]: """Find an external program, checking the cross file plus any default options.""" potential_names = OrderedSet(default_names) potential_names.add(name) @@ -367,8 +377,8 @@ def find_external_program(env: 'Environment', for_machine: MachineChoice, name: # Fallback on hard-coded defaults, if a default binary is allowed for use # with cross targets, or if this is not a cross target if allow_default_for_cross or not (for_machine is MachineChoice.HOST and env.is_cross_build(for_machine)): - for potential_path in default_names: - mlog.debug(f'Trying a default {display_name} fallback at', potential_path) - yield ExternalProgram(potential_path, silent=True) + for potential_name in default_names: + mlog.debug(f'Trying a default {display_name} fallback at', potential_name) + yield ExternalProgram(potential_name, silent=True, exclude_paths=exclude_paths) else: mlog.debug('Default target is not allowed for cross use') diff --git a/unittests/failuretests.py b/unittests/failuretests.py index baa59204766f..8a802120b6f3 100644 --- a/unittests/failuretests.py +++ b/unittests/failuretests.py @@ -34,10 +34,10 @@ def no_pkgconfig(): old_which = shutil.which old_search = ExternalProgram._search - def new_search(self, name, search_dir): + def new_search(self, name, search_dirs, exclude_paths): if name == 'pkg-config': return [None] - return old_search(self, name, search_dir) + return old_search(self, name, search_dirs, exclude_paths) def new_which(cmd, *kwargs): if cmd == 'pkg-config': From d48602a5f3dade3c1800b3e3d11ad09a45a761a2 Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Thu, 26 Sep 2024 14:56:34 +0530 Subject: [PATCH 252/302] curses: Ignore /usr/bin/ncurses5.4-config on macOS macOS mistakenly ships /usr/bin/ncurses5.4-config and a man page for it, but none of the headers or libraries are available in the location advertised by it. Ignore /usr/bin because it can only contain this broken configtool script. Homebrew is /usr/local or /opt/homebrew. Xcode's command-line tools SDK does include curses, but the configtool in there is wrong too, and anyway we can't just randomly pick it up since the user must explicitly select that as a target by using a native file. The MacOSX SDK itself does not include curses. We also can't ignore ncurses5.4-config entirely because it might be available in a different prefix. --- mesonbuild/dependencies/misc.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py index b5c40984a8e7..4815e1c18cd9 100644 --- a/mesonbuild/dependencies/misc.py +++ b/mesonbuild/dependencies/misc.py @@ -312,7 +312,14 @@ class CursesConfigToolDependency(ConfigToolDependency): tools = ['ncursesw6-config', 'ncursesw5-config', 'ncurses6-config', 'ncurses5-config', 'ncurses5.4-config'] def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any], language: T.Optional[str] = None): - super().__init__(name, env, kwargs, language) + exclude_paths = None + # macOS mistakenly ships /usr/bin/ncurses5.4-config and a man page for + # it, but none of the headers or libraries. Ignore /usr/bin because it + # can only contain this broken configtool script. + # Homebrew is /usr/local or /opt/homebrew. + if env.machines.build and env.machines.build.system == 'darwin': + exclude_paths = ['/usr/bin'] + super().__init__(name, env, kwargs, language, exclude_paths=exclude_paths) if not self.is_found: return self.compile_args = self.get_config_value(['--cflags'], 'compile_args') From 4c3bb4f67b49359a1f3f1441ad4a736f78266f5f Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Fri, 4 Oct 2024 00:38:15 -0400 Subject: [PATCH 253/302] Fix C++ standard support for Emscripten The first versions of Emscripten that correspond with the Clang version Meson uses to determine flag support don't actually support the expected flags. So I went through and picked the first version that actually worked with the expected flags. Fixes #13628 --- mesonbuild/compilers/cpp.py | 9 +++++++++ test cases/wasm/1 basic/meson.build | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py index f9ebf08da8e8..86bb113be492 100644 --- a/mesonbuild/compilers/cpp.py +++ b/mesonbuild/compilers/cpp.py @@ -350,6 +350,15 @@ class EmscriptenCPPCompiler(EmscriptenMixin, ClangCPPCompiler): id = 'emscripten' + # Emscripten uses different version numbers than Clang; `emcc -v` will show + # the Clang version number used as well (but `emcc --version` does not). + # See https://github.com/pyodide/pyodide/discussions/4762 for more on + # emcc <--> clang versions. Note, although earlier versions claim to be the + # Clang versions 12.0.0 and 17.0.0 required for these C++ standards, they + # only accept the flags in the later versions below. + _CPP23_VERSION = '>=2.0.10' + _CPP26_VERSION = '>=3.1.39' + def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', linker: T.Optional['DynamicLinker'] = None, diff --git a/test cases/wasm/1 basic/meson.build b/test cases/wasm/1 basic/meson.build index d27599271b1c..bbf37b636091 100644 --- a/test cases/wasm/1 basic/meson.build +++ b/test cases/wasm/1 basic/meson.build @@ -1,7 +1,7 @@ project('emcctest', 'c', 'cpp', default_options: [ 'c_std=c17', - 'cpp_std=c++17', + 'cpp_std=c++26', ] ) From eda59e141d30204908ef1f56b2637164310c9ccc Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Sun, 10 Mar 2024 23:26:02 -0400 Subject: [PATCH 254/302] Turn off CMake compile launcher when using zig This setting is for things like `ccache`, but if Meson treats zig that way, then it will expand the second argument to become: ``` /usr/bin/zig /usr/lib64/ccache/cc ``` in CMake and `/usr/lib64/ccache/cc` is _not_ an argument to `zig`. If you run ``` $ CC='zig cc' CXX='zig c++' ./meson.py setup 'test cases/cmake/1 basic' build ``` then CMake will fail to compile a "simple test program" and setup fails. --- mesonbuild/cmake/toolchain.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mesonbuild/cmake/toolchain.py b/mesonbuild/cmake/toolchain.py index 89d5d84449e0..7d73a7cea014 100644 --- a/mesonbuild/cmake/toolchain.py +++ b/mesonbuild/cmake/toolchain.py @@ -198,6 +198,8 @@ def is_cmdline_option(compiler: 'Compiler', arg: str) -> bool: if compiler.get_argument_syntax() == 'msvc': return arg.startswith('/') else: + if compiler.exelist[0] == 'zig' and arg in {'ar', 'cc', 'c++', 'dlltool', 'lib', 'ranlib', 'objcopy', 'rc'}: + return True return arg.startswith('-') def update_cmake_compiler_state(self) -> None: From 9575ed30abba70508749d69a9f601e2c6ed657c2 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 4 Oct 2024 10:48:59 -0700 Subject: [PATCH 255/302] docs: Mention that rust edition/standard 2018 or later should be used As the 2018 standard changes the way rust handles externs, and is the first edition that allows `--extern crate=path` to completely replace (in all but a few corner cases) the use of `extern crate` in the rust files. --- docs/markdown/Rust.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/markdown/Rust.md b/docs/markdown/Rust.md index 74f68442c638..d30fe68373cc 100644 --- a/docs/markdown/Rust.md +++ b/docs/markdown/Rust.md @@ -10,7 +10,9 @@ short-description: Working with Rust in Meson Meson can't track dependency information for crates linked by rustc as a result of `extern crate` statements in Rust source code. If your crate dependencies are properly expressed in Meson, there should be no -need for `extern crate` statements in your Rust code. +need for `extern crate` statements in your Rust code, as long as you use the +Rust 2018 edition or later. This means adding `rust_std=2018` (or later) to the +`project(default_options)` argument. An example of the problems with `extern crate` is that if you delete a crate from a Meson build file, other crates that depend on that crate From 7cb36747f8764d27279db17d4aff62b89581fa16 Mon Sep 17 00:00:00 2001 From: andy5995 Date: Fri, 4 Oct 2024 02:11:44 -0500 Subject: [PATCH 256/302] docs: Add windres to cross-compiling example --- docs/markdown/Cross-compilation.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/markdown/Cross-compilation.md b/docs/markdown/Cross-compilation.md index ccbcfd363ef5..0cfef71b9cd0 100644 --- a/docs/markdown/Cross-compilation.md +++ b/docs/markdown/Cross-compilation.md @@ -14,6 +14,7 @@ targeting 64-bit Windows could be: c = 'x86_64-w64-mingw32-gcc' cpp = 'x86_64-w64-mingw32-g++' ar = 'x86_64-w64-mingw32-ar' +windres = 'x86_64-w64-mingw32-windres' strip = 'x86_64-w64-mingw32-strip' exe_wrapper = 'wine64' From 373586fab53908a2315b1f0347c8b87968e3ccb8 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sun, 6 Oct 2024 22:58:30 +0300 Subject: [PATCH 257/302] Reorder test dirs for rc1. --- .../generate.py | 0 .../meson.build | 0 .../common/{274 environment => 275 environment}/meson.build | 0 test cases/common/{274 environment => 275 environment}/testenv.py | 0 .../invalid.c | 0 .../meson.build | 0 .../meson_options.txt | 0 .../valid.c | 0 .../include/meson.build | 0 .../meson.build | 0 .../meson.build | 0 .../common/{278 pkgconfig-gen => 279 pkgconfig-gen}/meson.build | 0 .../common/{278 pkgconfig-gen => 279 pkgconfig-gen}/simple.c | 0 .../common/{278 pkgconfig-gen => 279 pkgconfig-gen}/simple.h | 0 .../{278 pkgconfig-gen => 279 pkgconfig-gen}/simple2/exports.def | 0 .../{278 pkgconfig-gen => 279 pkgconfig-gen}/simple2/meson.build | 0 .../{278 pkgconfig-gen => 279 pkgconfig-gen}/simple2/simple2.c | 0 .../{278 pkgconfig-gen => 279 pkgconfig-gen}/simple2/simple2.h | 0 .../common/{278 pkgconfig-gen => 279 pkgconfig-gen}/test.json | 0 19 files changed, 0 insertions(+), 0 deletions(-) rename test cases/common/{273 customtarget exe for test => 274 customtarget exe for test}/generate.py (100%) rename test cases/common/{273 customtarget exe for test => 274 customtarget exe for test}/meson.build (100%) rename test cases/common/{274 environment => 275 environment}/meson.build (100%) rename test cases/common/{274 environment => 275 environment}/testenv.py (100%) rename test cases/common/{275 required keyword in compiles functions => 276 required keyword in compiles functions}/invalid.c (100%) rename test cases/common/{275 required keyword in compiles functions => 276 required keyword in compiles functions}/meson.build (100%) rename test cases/common/{275 required keyword in compiles functions => 276 required keyword in compiles functions}/meson_options.txt (100%) rename test cases/common/{275 required keyword in compiles functions => 276 required keyword in compiles functions}/valid.c (100%) rename test cases/common/{276 generator custom_tgt subdir => 277 generator custom_tgt subdir}/include/meson.build (100%) rename test cases/common/{276 generator custom_tgt subdir => 277 generator custom_tgt subdir}/meson.build (100%) rename test cases/common/{277 custom target private dir => 278 custom target private dir}/meson.build (100%) rename test cases/common/{278 pkgconfig-gen => 279 pkgconfig-gen}/meson.build (100%) rename test cases/common/{278 pkgconfig-gen => 279 pkgconfig-gen}/simple.c (100%) rename test cases/common/{278 pkgconfig-gen => 279 pkgconfig-gen}/simple.h (100%) rename test cases/common/{278 pkgconfig-gen => 279 pkgconfig-gen}/simple2/exports.def (100%) rename test cases/common/{278 pkgconfig-gen => 279 pkgconfig-gen}/simple2/meson.build (100%) rename test cases/common/{278 pkgconfig-gen => 279 pkgconfig-gen}/simple2/simple2.c (100%) rename test cases/common/{278 pkgconfig-gen => 279 pkgconfig-gen}/simple2/simple2.h (100%) rename test cases/common/{278 pkgconfig-gen => 279 pkgconfig-gen}/test.json (100%) diff --git a/test cases/common/273 customtarget exe for test/generate.py b/test cases/common/274 customtarget exe for test/generate.py similarity index 100% rename from test cases/common/273 customtarget exe for test/generate.py rename to test cases/common/274 customtarget exe for test/generate.py diff --git a/test cases/common/273 customtarget exe for test/meson.build b/test cases/common/274 customtarget exe for test/meson.build similarity index 100% rename from test cases/common/273 customtarget exe for test/meson.build rename to test cases/common/274 customtarget exe for test/meson.build diff --git a/test cases/common/274 environment/meson.build b/test cases/common/275 environment/meson.build similarity index 100% rename from test cases/common/274 environment/meson.build rename to test cases/common/275 environment/meson.build diff --git a/test cases/common/274 environment/testenv.py b/test cases/common/275 environment/testenv.py similarity index 100% rename from test cases/common/274 environment/testenv.py rename to test cases/common/275 environment/testenv.py diff --git a/test cases/common/275 required keyword in compiles functions/invalid.c b/test cases/common/276 required keyword in compiles functions/invalid.c similarity index 100% rename from test cases/common/275 required keyword in compiles functions/invalid.c rename to test cases/common/276 required keyword in compiles functions/invalid.c diff --git a/test cases/common/275 required keyword in compiles functions/meson.build b/test cases/common/276 required keyword in compiles functions/meson.build similarity index 100% rename from test cases/common/275 required keyword in compiles functions/meson.build rename to test cases/common/276 required keyword in compiles functions/meson.build diff --git a/test cases/common/275 required keyword in compiles functions/meson_options.txt b/test cases/common/276 required keyword in compiles functions/meson_options.txt similarity index 100% rename from test cases/common/275 required keyword in compiles functions/meson_options.txt rename to test cases/common/276 required keyword in compiles functions/meson_options.txt diff --git a/test cases/common/275 required keyword in compiles functions/valid.c b/test cases/common/276 required keyword in compiles functions/valid.c similarity index 100% rename from test cases/common/275 required keyword in compiles functions/valid.c rename to test cases/common/276 required keyword in compiles functions/valid.c diff --git a/test cases/common/276 generator custom_tgt subdir/include/meson.build b/test cases/common/277 generator custom_tgt subdir/include/meson.build similarity index 100% rename from test cases/common/276 generator custom_tgt subdir/include/meson.build rename to test cases/common/277 generator custom_tgt subdir/include/meson.build diff --git a/test cases/common/276 generator custom_tgt subdir/meson.build b/test cases/common/277 generator custom_tgt subdir/meson.build similarity index 100% rename from test cases/common/276 generator custom_tgt subdir/meson.build rename to test cases/common/277 generator custom_tgt subdir/meson.build diff --git a/test cases/common/277 custom target private dir/meson.build b/test cases/common/278 custom target private dir/meson.build similarity index 100% rename from test cases/common/277 custom target private dir/meson.build rename to test cases/common/278 custom target private dir/meson.build diff --git a/test cases/common/278 pkgconfig-gen/meson.build b/test cases/common/279 pkgconfig-gen/meson.build similarity index 100% rename from test cases/common/278 pkgconfig-gen/meson.build rename to test cases/common/279 pkgconfig-gen/meson.build diff --git a/test cases/common/278 pkgconfig-gen/simple.c b/test cases/common/279 pkgconfig-gen/simple.c similarity index 100% rename from test cases/common/278 pkgconfig-gen/simple.c rename to test cases/common/279 pkgconfig-gen/simple.c diff --git a/test cases/common/278 pkgconfig-gen/simple.h b/test cases/common/279 pkgconfig-gen/simple.h similarity index 100% rename from test cases/common/278 pkgconfig-gen/simple.h rename to test cases/common/279 pkgconfig-gen/simple.h diff --git a/test cases/common/278 pkgconfig-gen/simple2/exports.def b/test cases/common/279 pkgconfig-gen/simple2/exports.def similarity index 100% rename from test cases/common/278 pkgconfig-gen/simple2/exports.def rename to test cases/common/279 pkgconfig-gen/simple2/exports.def diff --git a/test cases/common/278 pkgconfig-gen/simple2/meson.build b/test cases/common/279 pkgconfig-gen/simple2/meson.build similarity index 100% rename from test cases/common/278 pkgconfig-gen/simple2/meson.build rename to test cases/common/279 pkgconfig-gen/simple2/meson.build diff --git a/test cases/common/278 pkgconfig-gen/simple2/simple2.c b/test cases/common/279 pkgconfig-gen/simple2/simple2.c similarity index 100% rename from test cases/common/278 pkgconfig-gen/simple2/simple2.c rename to test cases/common/279 pkgconfig-gen/simple2/simple2.c diff --git a/test cases/common/278 pkgconfig-gen/simple2/simple2.h b/test cases/common/279 pkgconfig-gen/simple2/simple2.h similarity index 100% rename from test cases/common/278 pkgconfig-gen/simple2/simple2.h rename to test cases/common/279 pkgconfig-gen/simple2/simple2.h diff --git a/test cases/common/278 pkgconfig-gen/test.json b/test cases/common/279 pkgconfig-gen/test.json similarity index 100% rename from test cases/common/278 pkgconfig-gen/test.json rename to test cases/common/279 pkgconfig-gen/test.json From 739683943aa8caca37343b105a0f363abf772fa9 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sun, 6 Oct 2024 23:14:54 +0300 Subject: [PATCH 258/302] Update version number for rc1. --- man/meson.1 | 2 +- mesonbuild/coredata.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/man/meson.1 b/man/meson.1 index b6ceb2a27fbe..41917a97db30 100644 --- a/man/meson.1 +++ b/man/meson.1 @@ -1,4 +1,4 @@ -.TH MESON "1" "July 2024" "meson 1.5.0" "User Commands" +.TH MESON "1" "October 2024" "meson 1.6.0" "User Commands" .SH NAME meson - a high productivity build system .SH DESCRIPTION diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 276c3a67807b..250e6a1f16f6 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -74,7 +74,7 @@ class SharedCMDOptions(Protocol): # # Pip requires that RCs are named like this: '0.1.0.rc1' # But the corresponding Git tag needs to be '0.1.0rc1' -version = '1.5.99' +version = '1.6.0.rc1' # The next stable version when we are in dev. This is used to allow projects to # require meson version >=1.2.0 when using 1.1.99. FeatureNew won't warn when From 2291b3f27f932a7c09bd5ce28be0d5dbe4f3612f Mon Sep 17 00:00:00 2001 From: scivision Date: Sun, 6 Oct 2024 00:47:26 -0400 Subject: [PATCH 259/302] test: avoid need for explict CMake minimum This mitigates maintenance burden as CMake minimum version isn't relevant for these tests. CMake >= 3.31 warns if CMake minimum version is less than 3.10. ref: https://gitlab.kitware.com/cmake/cmake/-/merge_requests/9875 --- test cases/cmake/1 basic/subprojects/cmMod/CMakeLists.txt | 4 ++-- .../cmake/10 header only/subprojects/cmMod/CMakeLists.txt | 2 +- .../11 cmake_module_path/subprojects/cmMod/CMakeLists.txt | 2 +- .../12 generator expressions/subprojects/cmMod/CMakeLists.txt | 2 +- .../cmake/13 system includes/subprojects/cmMod/CMakeLists.txt | 2 +- test cases/cmake/16 threads/subprojects/cmMod/CMakeLists.txt | 2 +- .../17 include path order/subprojects/cmMod/CMakeLists.txt | 2 +- .../18 skip include files/subprojects/cmMod/CMakeLists.txt | 2 +- test cases/cmake/2 advanced/subprojects/cmMod/CMakeLists.txt | 2 +- .../cmake/21 shared module/subprojects/cmMod/CMakeLists.txt | 2 +- .../cmake/23 cmake toolchain/subprojects/cmMod/CMakeLists.txt | 2 +- .../subprojects/cmModFortran/CMakeLists.txt | 2 +- .../24 mixing languages/subprojects/cmTest/CMakeLists.txt | 2 +- .../cmake/25 assembler/subprojects/cmTest/CMakeLists.txt | 2 +- .../27 dependency fallback/subprojects/cmMod/CMakeLists.txt | 4 ++-- .../subprojects/cmake_subp/CMakeLists.txt | 2 +- .../subprojects/force_cmake/CMakeLists.txt | 2 +- .../cmake/3 advanced no dep/subprojects/cmMod/CMakeLists.txt | 2 +- .../cmake/8 custom command/subprojects/cmMod/CMakeLists.txt | 2 +- .../subprojects/cmMod/CMakeLists.txt | 2 +- .../subprojects/cmlib/CMakeLists.txt | 2 +- .../subprojects/cmlib/CMakeLists.txt | 2 +- test cases/unit/1 soname/CMakeLists.txt | 2 +- 23 files changed, 25 insertions(+), 25 deletions(-) diff --git a/test cases/cmake/1 basic/subprojects/cmMod/CMakeLists.txt b/test cases/cmake/1 basic/subprojects/cmMod/CMakeLists.txt index 2197667a3412..5a2589a973ce 100644 --- a/test cases/cmake/1 basic/subprojects/cmMod/CMakeLists.txt +++ b/test cases/cmake/1 basic/subprojects/cmMod/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION ${CMAKE_VERSION}) project(cmMod) set (CMAKE_CXX_STANDARD 14) @@ -12,7 +12,7 @@ target_compile_definitions(cmModLib++ PRIVATE MESON_MAGIC_FLAG=21) target_compile_definitions(cmModLib++ INTERFACE MESON_MAGIC_FLAG=42) # Test PCH support -if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.16.0") +if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.16.0") target_precompile_headers(cmModLib++ PRIVATE "cpp_pch.hpp") endif() diff --git a/test cases/cmake/10 header only/subprojects/cmMod/CMakeLists.txt b/test cases/cmake/10 header only/subprojects/cmMod/CMakeLists.txt index e01b6e260517..ba6f70111328 100644 --- a/test cases/cmake/10 header only/subprojects/cmMod/CMakeLists.txt +++ b/test cases/cmake/10 header only/subprojects/cmMod/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION ${CMAKE_VERSION}) project(cmMod) set (CMAKE_CXX_STANDARD 14) diff --git a/test cases/cmake/11 cmake_module_path/subprojects/cmMod/CMakeLists.txt b/test cases/cmake/11 cmake_module_path/subprojects/cmMod/CMakeLists.txt index 88ba9bc57ad0..b77d7a3afae2 100644 --- a/test cases/cmake/11 cmake_module_path/subprojects/cmMod/CMakeLists.txt +++ b/test cases/cmake/11 cmake_module_path/subprojects/cmMod/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION ${CMAKE_VERSION}) project(cmMod) diff --git a/test cases/cmake/12 generator expressions/subprojects/cmMod/CMakeLists.txt b/test cases/cmake/12 generator expressions/subprojects/cmMod/CMakeLists.txt index 27b37218a356..c7cd2ffc06b1 100644 --- a/test cases/cmake/12 generator expressions/subprojects/cmMod/CMakeLists.txt +++ b/test cases/cmake/12 generator expressions/subprojects/cmMod/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION ${CMAKE_VERSION}) project(cmMod) set (CMAKE_CXX_STANDARD 14) diff --git a/test cases/cmake/13 system includes/subprojects/cmMod/CMakeLists.txt b/test cases/cmake/13 system includes/subprojects/cmMod/CMakeLists.txt index a6b0ba40c7d0..2557a2ae9a9e 100644 --- a/test cases/cmake/13 system includes/subprojects/cmMod/CMakeLists.txt +++ b/test cases/cmake/13 system includes/subprojects/cmMod/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION ${CMAKE_VERSION}) project(cmMod) set (CMAKE_CXX_STANDARD 14) diff --git a/test cases/cmake/16 threads/subprojects/cmMod/CMakeLists.txt b/test cases/cmake/16 threads/subprojects/cmMod/CMakeLists.txt index 4d61b0c37ad7..04e7bdda14d4 100644 --- a/test cases/cmake/16 threads/subprojects/cmMod/CMakeLists.txt +++ b/test cases/cmake/16 threads/subprojects/cmMod/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION ${CMAKE_VERSION}) project(cmMod C CXX) set (CMAKE_CXX_STANDARD 14) diff --git a/test cases/cmake/17 include path order/subprojects/cmMod/CMakeLists.txt b/test cases/cmake/17 include path order/subprojects/cmMod/CMakeLists.txt index 9a252df18918..800ada9fd466 100644 --- a/test cases/cmake/17 include path order/subprojects/cmMod/CMakeLists.txt +++ b/test cases/cmake/17 include path order/subprojects/cmMod/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION ${CMAKE_VERSION}) project(cmMod) set (CMAKE_CXX_STANDARD 14) diff --git a/test cases/cmake/18 skip include files/subprojects/cmMod/CMakeLists.txt b/test cases/cmake/18 skip include files/subprojects/cmMod/CMakeLists.txt index 4db01b32da6a..50f87524638c 100644 --- a/test cases/cmake/18 skip include files/subprojects/cmMod/CMakeLists.txt +++ b/test cases/cmake/18 skip include files/subprojects/cmMod/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION ${CMAKE_VERSION}) project(cmMod) set (CMAKE_CXX_STANDARD 14) diff --git a/test cases/cmake/2 advanced/subprojects/cmMod/CMakeLists.txt b/test cases/cmake/2 advanced/subprojects/cmMod/CMakeLists.txt index 7af9e6b97119..7dd11e74942f 100644 --- a/test cases/cmake/2 advanced/subprojects/cmMod/CMakeLists.txt +++ b/test cases/cmake/2 advanced/subprojects/cmMod/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION ${CMAKE_VERSION}) project(cmMod) set(CMAKE_CXX_STANDARD 14) diff --git a/test cases/cmake/21 shared module/subprojects/cmMod/CMakeLists.txt b/test cases/cmake/21 shared module/subprojects/cmMod/CMakeLists.txt index d2fcfe3ffde3..4770bc7b3d91 100644 --- a/test cases/cmake/21 shared module/subprojects/cmMod/CMakeLists.txt +++ b/test cases/cmake/21 shared module/subprojects/cmMod/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION ${CMAKE_VERSION}) project(cmModule) diff --git a/test cases/cmake/23 cmake toolchain/subprojects/cmMod/CMakeLists.txt b/test cases/cmake/23 cmake toolchain/subprojects/cmMod/CMakeLists.txt index a00affaebe26..9fc121b8b888 100644 --- a/test cases/cmake/23 cmake toolchain/subprojects/cmMod/CMakeLists.txt +++ b/test cases/cmake/23 cmake toolchain/subprojects/cmMod/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION ${CMAKE_VERSION}) project(cmMod NONE) diff --git a/test cases/cmake/23 cmake toolchain/subprojects/cmModFortran/CMakeLists.txt b/test cases/cmake/23 cmake toolchain/subprojects/cmModFortran/CMakeLists.txt index ecf1737fc223..cf84e13efe88 100644 --- a/test cases/cmake/23 cmake toolchain/subprojects/cmModFortran/CMakeLists.txt +++ b/test cases/cmake/23 cmake toolchain/subprojects/cmModFortran/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.10) project(cmMod NONE) diff --git a/test cases/cmake/24 mixing languages/subprojects/cmTest/CMakeLists.txt b/test cases/cmake/24 mixing languages/subprojects/cmTest/CMakeLists.txt index a1886115bf5f..a25882bb340c 100644 --- a/test cases/cmake/24 mixing languages/subprojects/cmTest/CMakeLists.txt +++ b/test cases/cmake/24 mixing languages/subprojects/cmTest/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION ${CMAKE_VERSION}) project(cmTest LANGUAGES C OBJC) diff --git a/test cases/cmake/25 assembler/subprojects/cmTest/CMakeLists.txt b/test cases/cmake/25 assembler/subprojects/cmTest/CMakeLists.txt index bb8834dc22bc..f8f014747a10 100644 --- a/test cases/cmake/25 assembler/subprojects/cmTest/CMakeLists.txt +++ b/test cases/cmake/25 assembler/subprojects/cmTest/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION ${CMAKE_VERSION}) project(cmTest) diff --git a/test cases/cmake/27 dependency fallback/subprojects/cmMod/CMakeLists.txt b/test cases/cmake/27 dependency fallback/subprojects/cmMod/CMakeLists.txt index f920576e27ea..2f4e31c9fbb2 100644 --- a/test cases/cmake/27 dependency fallback/subprojects/cmMod/CMakeLists.txt +++ b/test cases/cmake/27 dependency fallback/subprojects/cmMod/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION ${CMAKE_VERSION}) project(cmMod VERSION 1.2.3) set(CMAKE_CXX_STANDARD 14) @@ -12,7 +12,7 @@ target_compile_definitions(cmModLib++ PRIVATE MESON_MAGIC_FLAG=21) target_compile_definitions(cmModLib++ INTERFACE MESON_MAGIC_FLAG=42) # Test PCH support -if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.16.0") +if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.16.0") target_precompile_headers(cmModLib++ PRIVATE "cpp_pch.hpp") endif() diff --git a/test cases/cmake/27 dependency fallback/subprojects/cmake_subp/CMakeLists.txt b/test cases/cmake/27 dependency fallback/subprojects/cmake_subp/CMakeLists.txt index 6443fcadd69a..51451a222bd9 100644 --- a/test cases/cmake/27 dependency fallback/subprojects/cmake_subp/CMakeLists.txt +++ b/test cases/cmake/27 dependency fallback/subprojects/cmake_subp/CMakeLists.txt @@ -1,2 +1,2 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION ${CMAKE_VERSION}) project(cmModDummy) diff --git a/test cases/cmake/27 dependency fallback/subprojects/force_cmake/CMakeLists.txt b/test cases/cmake/27 dependency fallback/subprojects/force_cmake/CMakeLists.txt index 497beb95ee18..442fc4eb6c40 100644 --- a/test cases/cmake/27 dependency fallback/subprojects/force_cmake/CMakeLists.txt +++ b/test cases/cmake/27 dependency fallback/subprojects/force_cmake/CMakeLists.txt @@ -1,2 +1,2 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION ${CMAKE_VERSION}) project(cmModBoth) diff --git a/test cases/cmake/3 advanced no dep/subprojects/cmMod/CMakeLists.txt b/test cases/cmake/3 advanced no dep/subprojects/cmMod/CMakeLists.txt index d738d45c9767..d31a6a294de7 100644 --- a/test cases/cmake/3 advanced no dep/subprojects/cmMod/CMakeLists.txt +++ b/test cases/cmake/3 advanced no dep/subprojects/cmMod/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION ${CMAKE_VERSION}) project(cmMod) set(CMAKE_CXX_STANDARD 14) diff --git a/test cases/cmake/8 custom command/subprojects/cmMod/CMakeLists.txt b/test cases/cmake/8 custom command/subprojects/cmMod/CMakeLists.txt index a5da5e7d21ef..65c725b25ff8 100644 --- a/test cases/cmake/8 custom command/subprojects/cmMod/CMakeLists.txt +++ b/test cases/cmake/8 custom command/subprojects/cmMod/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION ${CMAKE_VERSION}) project(cmMod) set (CMAKE_CXX_STANDARD 14) diff --git a/test cases/failing build/3 cmake subproject isolation/subprojects/cmMod/CMakeLists.txt b/test cases/failing build/3 cmake subproject isolation/subprojects/cmMod/CMakeLists.txt index 852dd09a8dab..a4564d3f1b25 100644 --- a/test cases/failing build/3 cmake subproject isolation/subprojects/cmMod/CMakeLists.txt +++ b/test cases/failing build/3 cmake subproject isolation/subprojects/cmMod/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION ${CMAKE_VERSION}) project(cmMod) set (CMAKE_CXX_STANDARD 14) diff --git a/test cases/failing/109 cmake executable dependency/subprojects/cmlib/CMakeLists.txt b/test cases/failing/109 cmake executable dependency/subprojects/cmlib/CMakeLists.txt index 006787986f0f..e927eae8f944 100644 --- a/test cases/failing/109 cmake executable dependency/subprojects/cmlib/CMakeLists.txt +++ b/test cases/failing/109 cmake executable dependency/subprojects/cmlib/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION ${CMAKE_VERSION}) project(cmlib) diff --git a/test cases/failing/119 cmake subproject error/subprojects/cmlib/CMakeLists.txt b/test cases/failing/119 cmake subproject error/subprojects/cmlib/CMakeLists.txt index edbe39535c1f..a845525b8df0 100644 --- a/test cases/failing/119 cmake subproject error/subprojects/cmlib/CMakeLists.txt +++ b/test cases/failing/119 cmake subproject error/subprojects/cmlib/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION ${CMAKE_VERSION}) project(cmlib) diff --git a/test cases/unit/1 soname/CMakeLists.txt b/test cases/unit/1 soname/CMakeLists.txt index c4f2e3eb93d8..47571b1c1e7b 100644 --- a/test cases/unit/1 soname/CMakeLists.txt +++ b/test cases/unit/1 soname/CMakeLists.txt @@ -7,7 +7,7 @@ # soname to 1.2.3 but Autotools sets it to 1. project(vertest C) -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION ${CMAKE_VERSION}) add_library(nover SHARED versioned.c) From 4d1623078fa4c217c8c4e779839121988e0b7be4 Mon Sep 17 00:00:00 2001 From: scivision Date: Sun, 6 Oct 2024 00:50:09 -0400 Subject: [PATCH 260/302] toolchain.py minimum CMake 3.10 to avoid deprecation warning ref: https://gitlab.kitware.com/cmake/cmake/-/merge_requests/9875 --- mesonbuild/cmake/toolchain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/cmake/toolchain.py b/mesonbuild/cmake/toolchain.py index 7d73a7cea014..43f262605922 100644 --- a/mesonbuild/cmake/toolchain.py +++ b/mesonbuild/cmake/toolchain.py @@ -212,7 +212,7 @@ def update_cmake_compiler_state(self) -> None: languages = list(self.compilers.keys()) lang_ids = [language_map.get(x, x.upper()) for x in languages] cmake_content = dedent(f''' - cmake_minimum_required(VERSION 3.7) + cmake_minimum_required(VERSION 3.10) project(CompInfo {' '.join(lang_ids)}) ''') From adeb844b40ea338fefdbae0270f8152a2afe9c44 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Fri, 11 Oct 2024 17:15:43 +0300 Subject: [PATCH 261/302] Recreate Boost symlink at runtime to survive sdist. Closes: #13763. --- run_format_tests.py | 5 +++- run_project_tests.py | 24 ++++++++++++++----- .../35 boost symlinks/boost/include/boost | 1 - .../frameworks/35 boost symlinks/meson.build | 6 +++++ .../frameworks/35 boost symlinks/test.json | 3 +++ 5 files changed, 31 insertions(+), 8 deletions(-) delete mode 120000 test cases/frameworks/35 boost symlinks/boost/include/boost create mode 100644 test cases/frameworks/35 boost symlinks/test.json diff --git a/run_format_tests.py b/run_format_tests.py index 719b76b5ac21..30c975882d9b 100755 --- a/run_format_tests.py +++ b/run_format_tests.py @@ -65,9 +65,12 @@ def check_format() -> None: check_file(root / file) def check_symlinks(): + # Test data must NOT contain symlinks. setup.py + # butchers them. If you need symlinks, they need + # to be created on the fly. for f in Path('test cases').glob('**/*'): if f.is_symlink(): - if 'boost symlinks' in str(f): + if 'boost symlinks/boost/lib' in str(f): continue raise SystemExit(f'Test data dir contains symlink: {f}.') diff --git a/run_project_tests.py b/run_project_tests.py index 831b947ccca4..a8d9a5b370fd 100755 --- a/run_project_tests.py +++ b/run_project_tests.py @@ -1563,12 +1563,17 @@ def get_version(t: ToolInfo) -> str: print('{0:<{2}}: {1}'.format(tool.tool, get_version(tool), max_width)) print() -tmpdir = list(Path('.').glob('test cases/**/*install functions and follow symlinks')) -assert len(tmpdir) == 1 -symlink_test_dir = tmpdir[0] -symlink_file1 = symlink_test_dir / 'foo/link1' -symlink_file2 = symlink_test_dir / 'foo/link2.h' -del tmpdir +tmpdir1 = list(Path('.').glob('test cases/**/*install functions and follow symlinks')) +tmpdir2 = list(Path('.').glob('test cases/frameworks/*boost symlinks')) +assert len(tmpdir1) == 1 +assert len(tmpdir2) == 1 +symlink_test_dir1 = tmpdir1[0] +symlink_test_dir2 = tmpdir2[0] / 'boost/include' +symlink_file1 = symlink_test_dir1 / 'foo/link1' +symlink_file2 = symlink_test_dir1 / 'foo/link2.h' +symlink_file3 = symlink_test_dir2 / 'boost' +del tmpdir1 +del tmpdir2 def clear_transitive_files() -> None: a = Path('test cases/common') @@ -1585,11 +1590,18 @@ def clear_transitive_files() -> None: symlink_file2.unlink() except FileNotFoundError: pass + try: + symlink_file3.unlink() + symlink_test_dir2.rmdir() + except FileNotFoundError: + pass def setup_symlinks() -> None: try: symlink_file1.symlink_to('file1') symlink_file2.symlink_to('file1') + symlink_test_dir2.mkdir(parents=True, exist_ok=True) + symlink_file3.symlink_to('../Cellar/boost/0.3.0/include/boost') except OSError: print('symlinks are not supported on this system') diff --git a/test cases/frameworks/35 boost symlinks/boost/include/boost b/test cases/frameworks/35 boost symlinks/boost/include/boost deleted file mode 120000 index 8acd7e291d4c..000000000000 --- a/test cases/frameworks/35 boost symlinks/boost/include/boost +++ /dev/null @@ -1 +0,0 @@ -../Cellar/boost/0.3.0/include/boost \ No newline at end of file diff --git a/test cases/frameworks/35 boost symlinks/meson.build b/test cases/frameworks/35 boost symlinks/meson.build index b49a143ef40d..b3767f1bdebe 100644 --- a/test cases/frameworks/35 boost symlinks/meson.build +++ b/test cases/frameworks/35 boost symlinks/meson.build @@ -1,5 +1,11 @@ project('boosttestsymlinks', 'cpp') +bm = build_machine.system() + +if bm == 'windows' or bm == 'cygwin' + error('MESON_SKIP_TEST: Windows and symlinks do not mix.') +endif + dep = dependency('boost', modules : ['regex', 'python'], required: false) assert(dep.found(), 'expected to find a fake version of boost') diff --git a/test cases/frameworks/35 boost symlinks/test.json b/test cases/frameworks/35 boost symlinks/test.json new file mode 100644 index 000000000000..23af7d93189d --- /dev/null +++ b/test cases/frameworks/35 boost symlinks/test.json @@ -0,0 +1,3 @@ +{ + "expect_skip_on_jobname": ["azure", "cygwin", "msys2"] +} From 84070410f3fca7781fd1234315e06aae9966bd87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Est=C3=A8ve?= Date: Mon, 7 Oct 2024 10:35:21 +0200 Subject: [PATCH 262/302] Fix minimal version for Emscripten C23 support --- mesonbuild/compilers/c.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index 819ef8bb8628..aa85f1191aa7 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -213,7 +213,7 @@ class EmscriptenCCompiler(EmscriptenMixin, ClangCCompiler): _C17_VERSION = '>=1.38.35' _C18_VERSION = '>=1.38.35' _C2X_VERSION = '>=1.38.35' # 1.38.35 used Clang 9.0.0 - _C23_VERSION = '>=3.0.0' # 3.0.0 used Clang 18.0.0 + _C23_VERSION = '>=3.1.45' # 3.1.45 used Clang 18.0.0 def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', From d3542ff690d0be723cfd3ebfaaac99290517837f Mon Sep 17 00:00:00 2001 From: Kevin Meagher <11620178+kjmeagher@users.noreply.github.com> Date: Thu, 30 May 2024 23:14:29 -0500 Subject: [PATCH 263/302] Add options for standard parameter for nvc and nvc++ fixes #13271 --- docs/markdown/snippets/nvc_now_support_setting_std.md | 6 ++++++ mesonbuild/compilers/c.py | 8 ++++++++ mesonbuild/compilers/cpp.py | 11 +++++++++++ 3 files changed, 25 insertions(+) create mode 100644 docs/markdown/snippets/nvc_now_support_setting_std.md diff --git a/docs/markdown/snippets/nvc_now_support_setting_std.md b/docs/markdown/snippets/nvc_now_support_setting_std.md new file mode 100644 index 000000000000..5e537ae9fb6b --- /dev/null +++ b/docs/markdown/snippets/nvc_now_support_setting_std.md @@ -0,0 +1,6 @@ +## nvc and nvc++ now support setting std + +The following standards are available for nvc: c89, c90, c99, c11, +c17, c18, gnu90, gnu89, gnu99, gnu11, gnu17, gnu18. For nvc++: +c++98, c++03, c++11, c++14, c++17, c++20, c++23, gnu++98, gnu++03, +gnu++11, gnu++14, gnu++17, gnu++20 diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index aa85f1191aa7..f67281f04a51 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -361,6 +361,14 @@ def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_ info, linker=linker, full_version=full_version) PGICompiler.__init__(self) + def get_options(self) -> 'MutableKeyedOptionDictType': + opts = CCompiler.get_options(self) + cppstd_choices = ['c89', 'c90', 'c99', 'c11', 'c17', 'c18'] + std_opt = opts[self.form_compileropt_key('std')] + assert isinstance(std_opt, options.UserStdOption), 'for mypy' + std_opt.set_versions(cppstd_choices, gnu=True) + return opts + class ElbrusCCompiler(ElbrusCompiler, CCompiler): def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py index 86bb113be492..930e7b7e5bb9 100644 --- a/mesonbuild/compilers/cpp.py +++ b/mesonbuild/compilers/cpp.py @@ -566,6 +566,17 @@ def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_ info, linker=linker, full_version=full_version) PGICompiler.__init__(self) + def get_options(self) -> 'MutableKeyedOptionDictType': + opts = CPPCompiler.get_options(self) + cppstd_choices = [ + 'c++98', 'c++03', 'c++11', 'c++14', 'c++17', 'c++20', 'c++23', + 'gnu++98', 'gnu++03', 'gnu++11', 'gnu++14', 'gnu++17', 'gnu++20' + ] + std_opt = opts[self.form_compileropt_key('std')] + assert isinstance(std_opt, options.UserStdOption), 'for mypy' + std_opt.set_versions(cppstd_choices) + return opts + class ElbrusCPPCompiler(ElbrusCompiler, CPPCompiler): def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, From 842504d6143d0820c5467db93fa1f004fd241157 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Tue, 10 Oct 2023 11:00:53 -0400 Subject: [PATCH 264/302] mlog: Log once should not take location into account --- mesonbuild/mlog.py | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/mesonbuild/mlog.py b/mesonbuild/mlog.py index 6a7111a932f9..b43ac8a692e3 100644 --- a/mesonbuild/mlog.py +++ b/mesonbuild/mlog.py @@ -243,34 +243,27 @@ def log(self, *args: TV_Loggable, is_error: bool = False, sep: T.Optional[str] = None, end: T.Optional[str] = None, display_timestamp: bool = True) -> None: - if once: - self._log_once(*args, is_error=is_error, nested=nested, sep=sep, end=end, display_timestamp=display_timestamp) - else: + if self._should_log(*args, once=once): self._log(*args, is_error=is_error, nested=nested, sep=sep, end=end, display_timestamp=display_timestamp) def log_timestamp(self, *args: TV_Loggable) -> None: if self.log_timestamp_start: self.log(*args) - def _log_once(self, *args: TV_Loggable, is_error: bool = False, - nested: bool = True, sep: T.Optional[str] = None, - end: T.Optional[str] = None, display_timestamp: bool = True) -> None: - """Log variant that only prints a given message one time per meson invocation. - - This considers ansi decorated values by the values they wrap without - regard for the AnsiDecorator itself. - """ + def _should_log(self, *args: TV_Loggable, once: bool) -> bool: def to_str(x: TV_Loggable) -> str: if isinstance(x, str): return x if isinstance(x, AnsiDecorator): return x.text return str(x) + if not once: + return True t = tuple(to_str(a) for a in args) if t in self.logged_once: - return + return False self.logged_once.add(t) - self._log(*args, is_error=is_error, nested=nested, sep=sep, end=end, display_timestamp=display_timestamp) + return True def _log_error(self, severity: _Severity, *rargs: TV_Loggable, once: bool = False, fatal: bool = True, @@ -293,6 +286,9 @@ def _log_error(self, severity: _Severity, *rargs: TV_Loggable, # rargs is a tuple, not a list args = label + list(rargs) + if not self._should_log(*args, once=once): + return + if location is not None: location_file = relpath(location.filename, os.getcwd()) location_str = get_error_location_string(location_file, location.lineno) @@ -301,7 +297,7 @@ def _log_error(self, severity: _Severity, *rargs: TV_Loggable, location_list = T.cast('TV_LoggableList', [location_str]) args = location_list + args - log(*args, once=once, nested=nested, sep=sep, end=end, is_error=is_error) + self._log(*args, nested=nested, sep=sep, end=end, is_error=is_error) self.log_warnings_counter += 1 From 304207b9d26fc8c2450e15af7260e850cbe97189 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Tue, 10 Oct 2023 11:07:22 -0400 Subject: [PATCH 265/302] cargo: Document that cargo subprojects is an experimental feature --- docs/markdown/Wrap-dependency-system-manual.md | 6 ++++++ docs/markdown/snippets/cargo_exp.md | 8 ++++++++ mesonbuild/interpreter/interpreter.py | 2 ++ 3 files changed, 16 insertions(+) create mode 100644 docs/markdown/snippets/cargo_exp.md diff --git a/docs/markdown/Wrap-dependency-system-manual.md b/docs/markdown/Wrap-dependency-system-manual.md index 9bb7a842648c..d84e4aa186d2 100644 --- a/docs/markdown/Wrap-dependency-system-manual.md +++ b/docs/markdown/Wrap-dependency-system-manual.md @@ -297,6 +297,9 @@ fallback to use the subproject, assuming it uses ### CMake wraps +**Note**: This is experimental and has no backwards or forwards compatibility guarantees. +See [Meson's rules on mixing build systems](Mixing-build-systems.md). + Since the CMake module does not know the public name of the provided dependencies, a CMake `.wrap` file cannot use the `dependency_names = foo` syntax. Instead, the `dep_name = _dep` syntax should be used, where @@ -316,6 +319,9 @@ foo-bar-1.0 = foo_bar_dep ``` ### Cargo wraps +**Note**: This is experimental and has no backwards or forwards compatibility guarantees. +See [Meson's rules on mixing build systems](Mixing-build-systems.md). + Cargo subprojects automatically override the `--rs` dependency name: - `package_name` is defined in `[package] name = ...` section of the `Cargo.toml`. diff --git a/docs/markdown/snippets/cargo_exp.md b/docs/markdown/snippets/cargo_exp.md new file mode 100644 index 000000000000..34d379a70c4b --- /dev/null +++ b/docs/markdown/snippets/cargo_exp.md @@ -0,0 +1,8 @@ +## Cargo subprojects is experimental + +Cargo subprojects was intended to be experimental with no stability guarantees. +That notice was unfortunately missing from documentation. Meson will now start +warning about usage of experimental features and future releases might do breaking +changes. + +This is aligned with our general policy regarding [mixing build systems](Mixing-build-systems.md). diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index aa839da361f4..ecc5bfc2d7b4 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -1043,6 +1043,8 @@ def _do_subproject_cargo(self, subp_name: str, subdir: str, kwargs: kwtypes.DoSubproject) -> SubprojectHolder: from .. import cargo FeatureNew.single_use('Cargo subproject', '1.3.0', self.subproject, location=self.current_node) + mlog.warning('Cargo subproject is an experimental feature and has no backwards compatibility guarantees.', + once=True, location=self.current_node) with mlog.nested(subp_name): ast, options = cargo.interpret(subp_name, subdir, self.environment) self.coredata.update_project_options(options, subp_name) From e1c09ee25f8e4efb064acd3f87c539d7319a90ee Mon Sep 17 00:00:00 2001 From: Pierre Lamot Date: Wed, 7 Aug 2024 16:32:20 +0200 Subject: [PATCH 266/302] backend/ninja: fix bad @OUTPUTn@ replacements `outfilelist` is the output list of the target, while `outfiles` is the output list of the individual commands Bug: mesonbuild/meson/pull/13304#issuecomment-2226398671 --- mesonbuild/backend/ninjabackend.py | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 675248962594..ee86c27e0b61 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -2605,17 +2605,18 @@ def generate_genlist_for_target(self, genlist: build.GeneratedList, target: buil subdir = genlist.subdir exe = generator.get_exe() infilelist = genlist.get_inputs() - outfilelist = genlist.get_outputs() extra_dependencies = self.get_target_depend_files(genlist) - for i, curfile in enumerate(infilelist): - if len(generator.outputs) == 1: - sole_output = os.path.join(self.get_target_private_dir(target), outfilelist[i]) - else: - sole_output = f'{curfile}' + for curfile in infilelist: infilename = curfile.rel_to_builddir(self.build_to_src, self.get_target_private_dir(target)) base_args = generator.get_arglist(infilename) outfiles = genlist.get_outputs_for(curfile) - outfiles = [os.path.join(self.get_target_private_dir(target), of) for of in outfiles] + outfilespriv = [os.path.join(self.get_target_private_dir(target), of) for of in outfiles] + + if len(generator.outputs) == 1: + sole_output = outfilespriv[0] + else: + sole_output = f'{curfile}' + if generator.depfile is None: rulename = 'CUSTOM_COMMAND' args = base_args @@ -2626,19 +2627,16 @@ def generate_genlist_for_target(self, genlist: build.GeneratedList, target: buil args = [x.replace('@DEPFILE@', depfile) for x in base_args] args = [x.replace("@INPUT@", infilename).replace('@OUTPUT@', sole_output) for x in args] - args = self.replace_outputs(args, self.get_target_private_dir(target), outfilelist) - # We have consumed output files, so drop them from the list of remaining outputs. - if len(generator.outputs) > 1: - outfilelist = outfilelist[len(generator.outputs):] + args = self.replace_outputs(args, self.get_target_private_dir(target), outfiles) args = self.replace_paths(target, args, override_subdir=subdir) cmdlist, reason = self.as_meson_exe_cmdline(exe, self.replace_extra_args(args, genlist), - capture=outfiles[0] if generator.capture else None, + capture=outfilespriv[0] if generator.capture else None, env=genlist.env) abs_pdir = os.path.join(self.environment.get_build_dir(), self.get_target_dir(target)) os.makedirs(abs_pdir, exist_ok=True) - elem = NinjaBuildElement(self.all_outputs, outfiles, rulename, infilename) + elem = NinjaBuildElement(self.all_outputs, outfilespriv, rulename, infilename) elem.add_dep([self.get_target_filename(x) for x in generator.depends]) if generator.depfile is not None: elem.add_item('DEPFILE', depfile) From 83d9b21401ec338efeff231316c06aa78e862843 Mon Sep 17 00:00:00 2001 From: Pierre Lamot Date: Thu, 8 Aug 2024 11:06:09 +0200 Subject: [PATCH 267/302] test cases: add test for @OUTPUT0@ substitution rules when a generator used a single @OUTPUT0@ and was processing multiple targets, the variable was replaced with a wrong value --- test cases/common/52 object generator/dir/meson.build | 6 ++++++ test cases/common/52 object generator/dir/source5.c | 3 +++ test cases/common/52 object generator/dir/source6.c | 3 +++ test cases/common/52 object generator/meson.build | 4 +++- test cases/common/52 object generator/prog.c | 5 ++++- 5 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 test cases/common/52 object generator/dir/meson.build create mode 100644 test cases/common/52 object generator/dir/source5.c create mode 100644 test cases/common/52 object generator/dir/source6.c diff --git a/test cases/common/52 object generator/dir/meson.build b/test cases/common/52 object generator/dir/meson.build new file mode 100644 index 000000000000..e661d8665499 --- /dev/null +++ b/test cases/common/52 object generator/dir/meson.build @@ -0,0 +1,6 @@ +#check with a single @OUTPUT0@ in a subdirectory and multiple inputs +gen4 = generator(python, + output : ['@BASENAME@.o'], + arguments : [comp, cc, '@INPUT@', '@OUTPUT0@']) + +generated4 = gen4.process(files('source5.c', 'source6.c')) diff --git a/test cases/common/52 object generator/dir/source5.c b/test cases/common/52 object generator/dir/source5.c new file mode 100644 index 000000000000..c512fc310279 --- /dev/null +++ b/test cases/common/52 object generator/dir/source5.c @@ -0,0 +1,3 @@ +int func5_in_obj(void) { + return 0; +} diff --git a/test cases/common/52 object generator/dir/source6.c b/test cases/common/52 object generator/dir/source6.c new file mode 100644 index 000000000000..adcf2cd454fd --- /dev/null +++ b/test cases/common/52 object generator/dir/source6.c @@ -0,0 +1,3 @@ +int func6_in_obj(void) { + return 0; +} diff --git a/test cases/common/52 object generator/meson.build b/test cases/common/52 object generator/meson.build index 49590d6d60f9..656a9088586f 100644 --- a/test cases/common/52 object generator/meson.build +++ b/test cases/common/52 object generator/meson.build @@ -37,6 +37,8 @@ gen3 = generator(python, generated3 = gen3.process(['source4.c']) -e = executable('prog', 'prog.c', generated, generated2, generated3) +subdir('dir') + +e = executable('prog', 'prog.c', generated, generated2, generated3, generated4) test('objgen', e) \ No newline at end of file diff --git a/test cases/common/52 object generator/prog.c b/test cases/common/52 object generator/prog.c index 80056dc031a9..ce54b073939a 100644 --- a/test cases/common/52 object generator/prog.c +++ b/test cases/common/52 object generator/prog.c @@ -2,7 +2,10 @@ int func1_in_obj(void); int func2_in_obj(void); int func3_in_obj(void); int func4_in_obj(void); +int func5_in_obj(void); +int func6_in_obj(void); + int main(void) { - return func1_in_obj() + func2_in_obj() + func3_in_obj() + func4_in_obj(); + return func1_in_obj() + func2_in_obj() + func3_in_obj() + func4_in_obj() + func5_in_obj() + func6_in_obj(); } From ec7a81ad8620ef0f94be7f84eb946bc90ad1446c Mon Sep 17 00:00:00 2001 From: Daniele Nicolodi Date: Sat, 12 Oct 2024 13:00:03 +0200 Subject: [PATCH 268/302] mintro: Add license and license_files to project introspection data --- mesonbuild/ast/introspection.py | 20 ++++++++++++++++++-- mesonbuild/mintro.py | 6 ++++-- unittests/allplatformstests.py | 11 ++++++++++- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/mesonbuild/ast/introspection.py b/mesonbuild/ast/introspection.py index 89df1d25a86a..b2eb1f8cd633 100644 --- a/mesonbuild/ast/introspection.py +++ b/mesonbuild/ast/introspection.py @@ -93,14 +93,30 @@ def func_project(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[st if len(args) < 1: raise InvalidArguments('Not enough arguments to project(). Needs at least the project name.') + def _str_list(node: T.Any) -> T.Optional[T.List[str]]: + if isinstance(node, ArrayNode): + r = [] + for v in node.args.arguments: + if not isinstance(v, StringNode): + return None + r.append(v.value) + return r + if isinstance(node, StringNode): + return [node.value] + return None + proj_name = args[0] proj_vers = kwargs.get('version', 'undefined') - proj_langs = self.flatten_args(args[1:]) if isinstance(proj_vers, ElementaryNode): proj_vers = proj_vers.value if not isinstance(proj_vers, str): proj_vers = 'undefined' - self.project_data = {'descriptive_name': proj_name, 'version': proj_vers} + proj_langs = self.flatten_args(args[1:]) + # Match the value returned by ``meson.project_license()`` when + # no ``license`` argument is specified in the ``project()`` call. + proj_license = _str_list(kwargs.get('license', None)) or ['unknown'] + proj_license_files = _str_list(kwargs.get('license_files', None)) or [] + self.project_data = {'descriptive_name': proj_name, 'version': proj_vers, 'license': proj_license, 'license_files': proj_license_files} optfile = os.path.join(self.source_root, self.subdir, 'meson.options') if not os.path.exists(optfile): diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py index 07ad533d3f05..810a2b674b40 100644 --- a/mesonbuild/mintro.py +++ b/mesonbuild/mintro.py @@ -470,10 +470,12 @@ def list_machines(builddata: build.Build) -> T.Dict[str, T.Dict[str, T.Union[str machines[m]['object_suffix'] = machine.get_object_suffix() return machines -def list_projinfo(builddata: build.Build) -> T.Dict[str, T.Union[str, T.List[T.Dict[str, str]]]]: - result: T.Dict[str, T.Union[str, T.List[T.Dict[str, str]]]] = { +def list_projinfo(builddata: build.Build) -> T.Dict[str, T.Union[str, T.List[str], T.List[T.Dict[str, str]]]]: + result: T.Dict[str, T.Union[str, T.List[str], T.List[T.Dict[str, str]]]] = { 'version': builddata.project_version, 'descriptive_name': builddata.project_name, + 'license': builddata.dep_manifest[builddata.project_name].license, + 'license_files': [f[1].fname for f in builddata.dep_manifest[builddata.project_name].license_files], 'subproject_dir': builddata.subproject_dir, } subprojects = [] diff --git a/unittests/allplatformstests.py b/unittests/allplatformstests.py index ca4b194e6180..afea39742bcb 100644 --- a/unittests/allplatformstests.py +++ b/unittests/allplatformstests.py @@ -3021,6 +3021,8 @@ def test_introspect_projectinfo_subprojects(self): expected = { 'descriptive_name': 'proj', 'version': 'undefined', + 'license': ['unknown'], + 'license_files': [], 'subproject_dir': 'subprojects', 'subprojects': [ { @@ -3415,7 +3417,14 @@ def assertKeyTypes(key_type_list, obj, strict: bool = True): self.assertListEqual(dependencies_to_find, []) # Check projectinfo - self.assertDictEqual(res['projectinfo'], {'version': '1.2.3', 'descriptive_name': 'introspection', 'subproject_dir': 'subprojects', 'subprojects': []}) + self.assertDictEqual(res['projectinfo'], { + 'version': '1.2.3', + 'license': ['unknown'], + 'license_files': [], + 'descriptive_name': 'introspection', + 'subproject_dir': 'subprojects', + 'subprojects': [] + }) # Check targets targets_to_find = { From 9fd9cc957f979c4fd9fbc18886122d62f5e1a129 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sun, 13 Oct 2024 18:40:31 +0300 Subject: [PATCH 269/302] Bump version number for rc2. --- mesonbuild/coredata.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 250e6a1f16f6..ced1eecdac63 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -74,7 +74,7 @@ class SharedCMDOptions(Protocol): # # Pip requires that RCs are named like this: '0.1.0.rc1' # But the corresponding Git tag needs to be '0.1.0rc1' -version = '1.6.0.rc1' +version = '1.6.0.rc2' # The next stable version when we are in dev. This is used to allow projects to # require meson version >=1.2.0 when using 1.1.99. FeatureNew won't warn when From 4fce94a878f2d7cc10486d5b673bf2f4ce3ce634 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sun, 13 Oct 2024 22:47:33 +0300 Subject: [PATCH 270/302] Do not run symlink setup on Windows. --- run_project_tests.py | 45 +++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/run_project_tests.py b/run_project_tests.py index a8d9a5b370fd..49a96083176f 100755 --- a/run_project_tests.py +++ b/run_project_tests.py @@ -1563,17 +1563,23 @@ def get_version(t: ToolInfo) -> str: print('{0:<{2}}: {1}'.format(tool.tool, get_version(tool), max_width)) print() -tmpdir1 = list(Path('.').glob('test cases/**/*install functions and follow symlinks')) -tmpdir2 = list(Path('.').glob('test cases/frameworks/*boost symlinks')) -assert len(tmpdir1) == 1 -assert len(tmpdir2) == 1 -symlink_test_dir1 = tmpdir1[0] -symlink_test_dir2 = tmpdir2[0] / 'boost/include' -symlink_file1 = symlink_test_dir1 / 'foo/link1' -symlink_file2 = symlink_test_dir1 / 'foo/link2.h' -symlink_file3 = symlink_test_dir2 / 'boost' -del tmpdir1 -del tmpdir2 +symlink_test_dir1 = None +symlink_test_dir2 = None +symlink_file1 = None +symlink_file2 = None +symlink_file3 = None + +def scan_test_data_symlinks() -> None: + global symlink_test_dir1, symlink_test_dir2, symlink_file1, symlink_file2, symlink_file3 + tmpdir1 = list(Path('.').glob('test cases/**/*install functions and follow symlinks')) + tmpdir2 = list(Path('.').glob('test cases/frameworks/*boost symlinks')) + assert len(tmpdir1) == 1 + assert len(tmpdir2) == 1 + symlink_test_dir1 = tmpdir1[0] + symlink_test_dir2 = tmpdir2[0] / 'boost/include' + symlink_file1 = symlink_test_dir1 / 'foo/link1' + symlink_file2 = symlink_test_dir1 / 'foo/link2.h' + symlink_file3 = symlink_test_dir2 / 'boost' def clear_transitive_files() -> None: a = Path('test cases/common') @@ -1583,16 +1589,19 @@ def clear_transitive_files() -> None: else: mesonlib.windows_proof_rm(str(d)) try: - symlink_file1.unlink() + if symlink_file1 is not None: + symlink_file1.unlink() except FileNotFoundError: pass try: - symlink_file2.unlink() + if symlink_file2 is not None: + symlink_file2.unlink() except FileNotFoundError: pass try: - symlink_file3.unlink() - symlink_test_dir2.rmdir() + if symlink_file3 is not None: + symlink_file3.unlink() + symlink_test_dir2.rmdir() except FileNotFoundError: pass @@ -1610,7 +1619,6 @@ def setup_symlinks() -> None: raise SystemExit('Running under CI but $MESON_CI_JOBNAME is not set (set to "thirdparty" if you are running outside of the github org)') setup_vsenv() - try: # This fails in some CI environments for unknown reasons. num_workers = multiprocessing.cpu_count() @@ -1649,8 +1657,11 @@ def setup_symlinks() -> None: if options.native_file: options.extra_args += ['--native-file', options.native_file] + if not mesonlib.is_windows(): + scan_test_data_symlinks() clear_transitive_files() - setup_symlinks() + if not mesonlib.is_windows(): + setup_symlinks() mesonlib.set_meson_command(get_meson_script()) print('Meson build system', meson_version, 'Project Tests') From 5f0bd8ff1e7fc43199d4b371fc4625f80baba810 Mon Sep 17 00:00:00 2001 From: Aditya Vidyadhar Kamath Date: Tue, 15 Oct 2024 10:15:00 -0500 Subject: [PATCH 271/302] Update release notes for 1.6.0. Closes: #13773. --- .../markdown/snippets/add_support_for_ibm_clang_for_AIX.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 docs/markdown/snippets/add_support_for_ibm_clang_for_AIX.md diff --git a/docs/markdown/snippets/add_support_for_ibm_clang_for_AIX.md b/docs/markdown/snippets/add_support_for_ibm_clang_for_AIX.md new file mode 100644 index 000000000000..526bbb3cc41d --- /dev/null +++ b/docs/markdown/snippets/add_support_for_ibm_clang_for_AIX.md @@ -0,0 +1,7 @@ +## Support for OpenXL compiler in AIX. + +The OpenXL compiler is now supported from Meson 1.6.0 onwards. +So currently, in AIX Operating system we support GCC and openXL compilers for Meson build system. + +Both the compilers will archive shared libraries and generate a shared object +for a shared module while using Meson in AIX. From 5cc511b1e6ff031f9257e11584c79e50370d9a4c Mon Sep 17 00:00:00 2001 From: Andoni Morales Alastruey Date: Thu, 26 Sep 2024 12:55:20 +0200 Subject: [PATCH 272/302] pkgconfig: add support to override pkg-config --- mesonbuild/dependencies/pkgconfig.py | 38 ++++++++++++++----- mesonbuild/interpreter/interpreter.py | 3 ++ run_project_tests.py | 5 +++ .../common/279 pkgconfig override/meson.build | 8 ++++ .../subprojects/pkg-config.wrap | 5 +++ .../subprojects/pkg-config/bin/pkg-config.py | 13 +++++++ .../subprojects/pkg-config/meson.build | 4 ++ 7 files changed, 66 insertions(+), 10 deletions(-) create mode 100644 test cases/common/279 pkgconfig override/meson.build create mode 100644 test cases/common/279 pkgconfig override/subprojects/pkg-config.wrap create mode 100755 test cases/common/279 pkgconfig override/subprojects/pkg-config/bin/pkg-config.py create mode 100644 test cases/common/279 pkgconfig override/subprojects/pkg-config/meson.build diff --git a/mesonbuild/dependencies/pkgconfig.py b/mesonbuild/dependencies/pkgconfig.py index 4fea86c12a33..bc24f760fd0d 100644 --- a/mesonbuild/dependencies/pkgconfig.py +++ b/mesonbuild/dependencies/pkgconfig.py @@ -6,7 +6,8 @@ from pathlib import Path from .base import ExternalDependency, DependencyException, sort_libpaths, DependencyTypeName -from ..mesonlib import EnvironmentVariables, OrderedSet, PerMachine, Popen_safe, Popen_safe_logged, MachineChoice, join_args +from ..mesonlib import (EnvironmentVariables, OrderedSet, PerMachine, Popen_safe, Popen_safe_logged, MachineChoice, + join_args, MesonException) from ..options import OptionKey from ..programs import find_external_program, ExternalProgram from .. import mlog @@ -30,6 +31,14 @@ class PkgConfigInterface: class_impl: PerMachine[T.Union[Literal[False], T.Optional[PkgConfigInterface]]] = PerMachine(False, False) class_cli_impl: PerMachine[T.Union[Literal[False], T.Optional[PkgConfigCLI]]] = PerMachine(False, False) + pkg_bin_per_machine: PerMachine[T.Optional[ExternalProgram]] = PerMachine(None, None) + + @staticmethod + def set_program_override(pkg_bin: ExternalProgram, for_machine: MachineChoice) -> None: + if PkgConfigInterface.class_impl[for_machine]: + raise MesonException(f'Tried to override pkg-config for machine {for_machine} but it was already initialized.\n' + 'pkg-config must be overridden before it\'s used.') + PkgConfigInterface.pkg_bin_per_machine[for_machine] = pkg_bin @staticmethod def instance(env: Environment, for_machine: MachineChoice, silent: bool) -> T.Optional[PkgConfigInterface]: @@ -37,7 +46,7 @@ def instance(env: Environment, for_machine: MachineChoice, silent: bool) -> T.Op for_machine = for_machine if env.is_cross_build() else MachineChoice.HOST impl = PkgConfigInterface.class_impl[for_machine] if impl is False: - impl = PkgConfigCLI(env, for_machine, silent) + impl = PkgConfigCLI(env, for_machine, silent, PkgConfigInterface.pkg_bin_per_machine[for_machine]) if not impl.found(): impl = None if not impl and not silent: @@ -57,7 +66,7 @@ def _cli(env: Environment, for_machine: MachineChoice, silent: bool = False) -> if impl and not isinstance(impl, PkgConfigCLI): impl = PkgConfigInterface.class_cli_impl[for_machine] if impl is False: - impl = PkgConfigCLI(env, for_machine, silent) + impl = PkgConfigCLI(env, for_machine, silent, PkgConfigInterface.pkg_bin_per_machine[for_machine]) if not impl.found(): impl = None PkgConfigInterface.class_cli_impl[for_machine] = impl @@ -113,9 +122,10 @@ def list_all(self) -> ImmutableListProtocol[str]: class PkgConfigCLI(PkgConfigInterface): '''pkg-config CLI implementation''' - def __init__(self, env: Environment, for_machine: MachineChoice, silent: bool) -> None: + def __init__(self, env: Environment, for_machine: MachineChoice, silent: bool, + pkgbin: T.Optional[ExternalProgram] = None) -> None: super().__init__(env, for_machine) - self._detect_pkgbin() + self._detect_pkgbin(pkgbin) if self.pkgbin and not silent: mlog.log('Found pkg-config:', mlog.green('YES'), mlog.bold(f'({self.pkgbin.get_path()})'), mlog.blue(self.pkgbin_version)) @@ -200,14 +210,21 @@ def _split_args(cmd: str) -> T.List[str]: # output using shlex.split rather than mesonlib.split_args return shlex.split(cmd) - def _detect_pkgbin(self) -> None: - for potential_pkgbin in find_external_program( - self.env, self.for_machine, 'pkg-config', 'Pkg-config', - self.env.default_pkgconfig, allow_default_for_cross=False): + def _detect_pkgbin(self, pkgbin: T.Optional[ExternalProgram] = None) -> None: + def validate(potential_pkgbin: ExternalProgram) -> bool: version_if_ok = self._check_pkgconfig(potential_pkgbin) if version_if_ok: self.pkgbin = potential_pkgbin self.pkgbin_version = version_if_ok + return True + return False + + if pkgbin and validate(pkgbin): + return + + for potential_pkgbin in find_external_program(self.env, self.for_machine, "pkg-config", "Pkg-config", + self.env.default_pkgconfig, allow_default_for_cross=False): + if validate(potential_pkgbin): return self.pkgbin = None @@ -274,7 +291,8 @@ def _call_pkgbin(self, args: T.List[str], env: T.Optional[EnvironOrDict] = None) class PkgConfigDependency(ExternalDependency): - def __init__(self, name: str, environment: Environment, kwargs: T.Dict[str, T.Any], language: T.Optional[str] = None) -> None: + def __init__(self, name: str, environment: Environment, kwargs: T.Dict[str, T.Any], + language: T.Optional[str] = None) -> None: super().__init__(DependencyTypeName('pkgconfig'), environment, kwargs, language=language) self.name = name self.is_libtool = False diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index ecc5bfc2d7b4..8a2e0e954af3 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -1640,6 +1640,9 @@ def add_find_program_override(self, name: str, exe: T.Union[build.Executable, Ex if name in self.build.find_overrides: raise InterpreterException(f'Tried to override executable "{name}" which has already been overridden.') self.build.find_overrides[name] = exe + if name == 'pkg-config' and isinstance(exe, ExternalProgram): + from ..dependencies.pkgconfig import PkgConfigInterface + PkgConfigInterface.set_program_override(exe, MachineChoice.HOST) def notfound_program(self, args: T.List[mesonlib.FileOrString]) -> ExternalProgram: return NonExistingExternalProgram(' '.join( diff --git a/run_project_tests.py b/run_project_tests.py index 49a96083176f..ab34c27f21d2 100755 --- a/run_project_tests.py +++ b/run_project_tests.py @@ -551,9 +551,14 @@ def validate_output(test: TestDef, stdo: str, stde: str) -> str: def clear_internal_caches() -> None: import mesonbuild.interpreterbase from mesonbuild.dependencies.cmake import CMakeDependency + from mesonbuild.dependencies.pkgconfig import PkgConfigInterface from mesonbuild.mesonlib import PerMachine mesonbuild.interpreterbase.FeatureNew.feature_registry = {} CMakeDependency.class_cmakeinfo = PerMachine(None, None) + PkgConfigInterface.class_impl = PerMachine(False, False) + PkgConfigInterface.class_cli_impl = PerMachine(False, False) + PkgConfigInterface.pkg_bin_per_machine = PerMachine(None, None) + def run_test_inprocess(testdir: str) -> T.Tuple[int, str, str, str]: old_stdout = sys.stdout diff --git a/test cases/common/279 pkgconfig override/meson.build b/test cases/common/279 pkgconfig override/meson.build new file mode 100644 index 000000000000..90298288bda1 --- /dev/null +++ b/test cases/common/279 pkgconfig override/meson.build @@ -0,0 +1,8 @@ +project('override pkg-config', 'c') + +subproject('pkg-config') + +pkgconfig = find_program('pkg-config') + +# This dependency can only be found if pkg-config is overridden with our custom pkg-config.py +gobj = dependency('test-package-0.0', version : '= 0.0.0') diff --git a/test cases/common/279 pkgconfig override/subprojects/pkg-config.wrap b/test cases/common/279 pkgconfig override/subprojects/pkg-config.wrap new file mode 100644 index 000000000000..ef7a52ed2037 --- /dev/null +++ b/test cases/common/279 pkgconfig override/subprojects/pkg-config.wrap @@ -0,0 +1,5 @@ +[wrap-file] +directory = pkg-config + +[provide] +program_names = pkg-config diff --git a/test cases/common/279 pkgconfig override/subprojects/pkg-config/bin/pkg-config.py b/test cases/common/279 pkgconfig override/subprojects/pkg-config/bin/pkg-config.py new file mode 100755 index 000000000000..7dc28c849415 --- /dev/null +++ b/test cases/common/279 pkgconfig override/subprojects/pkg-config/bin/pkg-config.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python3 + +import sys + +if len(sys.argv) > 1: + if sys.argv[1] == "--modversion": + if sys.argv[2] == "test-package-0.0": + print("0.0.0") + else: + exit(-1) + elif sys.argv[1] == "--version": + print("0.0.0") + exit(0) diff --git a/test cases/common/279 pkgconfig override/subprojects/pkg-config/meson.build b/test cases/common/279 pkgconfig override/subprojects/pkg-config/meson.build new file mode 100644 index 000000000000..af526f9345a9 --- /dev/null +++ b/test cases/common/279 pkgconfig override/subprojects/pkg-config/meson.build @@ -0,0 +1,4 @@ +project('pkg-config') + +pkgconfig = find_program(meson.project_source_root() / 'bin' / 'pkg-config.py') +meson.override_find_program('pkg-config', pkgconfig) From fbeedf4b141ac84d236649aa1e5d4f6bf773ce92 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sun, 20 Oct 2024 19:29:42 +0300 Subject: [PATCH 273/302] Condense test directories. --- .../meson.build | 0 .../simple.c | 0 .../simple.h | 0 .../simple2/exports.def | 0 .../simple2/meson.build | 0 .../simple2/simple2.c | 0 .../simple2/simple2.h | 0 .../test.json | 0 .../foo.py | 0 .../meson.build | 0 .../subdir/meson.build | 0 .../lib2.rs | 0 .../main.rs | 0 .../meson.build | 0 .../meson.build | 0 .../unit/{104 strip => 103 strip}/lib.c | 0 .../unit/{104 strip => 103 strip}/meson.build | 0 .../meson.build | 0 .../meson.build | 0 .../foo.c | 0 .../foo.dat | 0 .../foo.h | 0 .../foo/foofile | 0 .../meson.build | 0 .../subprojects/bar/bar.c | 0 .../subprojects/bar/bar.dat | 0 .../subprojects/bar/bar.h | 0 .../subprojects/bar/bar/barfile | 0 .../subprojects/bar/meson.build | 0 .../meson.build | 0 .../meson_options.txt | 0 .../subprojects/sub/foo.c | 0 .../subprojects/sub/meson.build | 0 .../.clang-format | 0 .../.clang-format-ignore | 0 .../.clang-format-include | 0 .../meson.build | 0 .../not-included/badformat.cpp | 0 .../src/badformat.c | 0 .../src/badformat.cpp | 0 .../easytogrepfor/genh.py | 0 .../easytogrepfor/meson.build | 0 .../{95 custominc => 94 custominc}/helper.c | 0 .../meson.build | 0 .../{95 custominc => 94 custominc}/prog.c | 0 .../{95 custominc => 94 custominc}/prog2.c | 0 .../meson.build | 0 .../subprojects/something/meson.build | 0 .../meson.build | 0 .../test.c | 0 .../.gitignore | 0 .../libtestprovider/meson.build | 0 .../libtestprovider/provider.c | 0 .../proguser/meson.build | 0 .../proguser/receiver.c | 0 .../bar-custom.txt | 0 .../bar-devel.h | 0 .../bar-notag.txt | 0 .../custom_files/data.txt | 0 .../excludes/excluded.txt | 0 .../excludes/excluded/placeholder.txt | 0 .../excludes/installed.txt | 0 .../foo.in | 0 .../foo1-devel.h | 0 .../lib.c | 0 .../main.c | 0 .../meson.build | 0 .../script.py | 0 .../subdir/bar2-devel.h | 0 .../subdir/foo2.in | 0 .../subdir/foo3-devel.h | 0 .../subdir/lib.c | 0 .../subdir/main.c | 0 .../subdir/meson.build | 0 .../subdir/script.py | 0 .../subprojects/subproject/aaa.txt | 0 .../subprojects/subproject/bbb.txt | 0 .../subprojects/subproject/meson.build | 0 .../file.txt.in | 0 .../meson.build | 0 .../subdir/meson.build | 0 unittests/allplatformstests.py | 22 +++++++++---------- unittests/linuxliketests.py | 6 ++--- unittests/platformagnostictests.py | 6 ++--- 84 files changed, 17 insertions(+), 17 deletions(-) rename test cases/common/{279 pkgconfig-gen => 280 pkgconfig-gen}/meson.build (100%) rename test cases/common/{279 pkgconfig-gen => 280 pkgconfig-gen}/simple.c (100%) rename test cases/common/{279 pkgconfig-gen => 280 pkgconfig-gen}/simple.h (100%) rename test cases/common/{279 pkgconfig-gen => 280 pkgconfig-gen}/simple2/exports.def (100%) rename test cases/common/{279 pkgconfig-gen => 280 pkgconfig-gen}/simple2/meson.build (100%) rename test cases/common/{279 pkgconfig-gen => 280 pkgconfig-gen}/simple2/simple2.c (100%) rename test cases/common/{279 pkgconfig-gen => 280 pkgconfig-gen}/simple2/simple2.h (100%) rename test cases/common/{279 pkgconfig-gen => 280 pkgconfig-gen}/test.json (100%) rename test cases/unit/{101 relative find program => 100 relative find program}/foo.py (100%) rename test cases/unit/{101 relative find program => 100 relative find program}/meson.build (100%) rename test cases/unit/{101 relative find program => 100 relative find program}/subdir/meson.build (100%) rename test cases/unit/{102 rlib linkage => 101 rlib linkage}/lib2.rs (100%) rename test cases/unit/{102 rlib linkage => 101 rlib linkage}/main.rs (100%) rename test cases/unit/{102 rlib linkage => 101 rlib linkage}/meson.build (100%) rename test cases/unit/{103 python without pkgconfig => 102 python without pkgconfig}/meson.build (100%) rename test cases/unit/{104 strip => 103 strip}/lib.c (100%) rename test cases/unit/{104 strip => 103 strip}/meson.build (100%) rename test cases/unit/{105 debug function => 104 debug function}/meson.build (100%) rename test cases/unit/{106 pkgconfig relocatable with absolute path => 105 pkgconfig relocatable with absolute path}/meson.build (100%) rename test cases/unit/{92 install skip subprojects => 91 install skip subprojects}/foo.c (100%) rename test cases/unit/{92 install skip subprojects => 91 install skip subprojects}/foo.dat (100%) rename test cases/unit/{92 install skip subprojects => 91 install skip subprojects}/foo.h (100%) rename test cases/unit/{92 install skip subprojects => 91 install skip subprojects}/foo/foofile (100%) rename test cases/unit/{92 install skip subprojects => 91 install skip subprojects}/meson.build (100%) rename test cases/unit/{92 install skip subprojects => 91 install skip subprojects}/subprojects/bar/bar.c (100%) rename test cases/unit/{92 install skip subprojects => 91 install skip subprojects}/subprojects/bar/bar.dat (100%) rename test cases/unit/{92 install skip subprojects => 91 install skip subprojects}/subprojects/bar/bar.h (100%) rename test cases/unit/{92 install skip subprojects => 91 install skip subprojects}/subprojects/bar/bar/barfile (100%) rename test cases/unit/{92 install skip subprojects => 91 install skip subprojects}/subprojects/bar/meson.build (100%) rename test cases/unit/{93 new subproject in configured project => 92 new subproject in configured project}/meson.build (100%) rename test cases/unit/{93 new subproject in configured project => 92 new subproject in configured project}/meson_options.txt (100%) rename test cases/unit/{93 new subproject in configured project => 92 new subproject in configured project}/subprojects/sub/foo.c (100%) rename test cases/unit/{93 new subproject in configured project => 92 new subproject in configured project}/subprojects/sub/meson.build (100%) rename test cases/unit/{94 clangformat => 93 clangformat}/.clang-format (100%) rename test cases/unit/{94 clangformat => 93 clangformat}/.clang-format-ignore (100%) rename test cases/unit/{94 clangformat => 93 clangformat}/.clang-format-include (100%) rename test cases/unit/{94 clangformat => 93 clangformat}/meson.build (100%) rename test cases/unit/{94 clangformat => 93 clangformat}/not-included/badformat.cpp (100%) rename test cases/unit/{94 clangformat => 93 clangformat}/src/badformat.c (100%) rename test cases/unit/{94 clangformat => 93 clangformat}/src/badformat.cpp (100%) rename test cases/unit/{95 custominc => 94 custominc}/easytogrepfor/genh.py (100%) rename test cases/unit/{95 custominc => 94 custominc}/easytogrepfor/meson.build (100%) rename test cases/unit/{95 custominc => 94 custominc}/helper.c (100%) rename test cases/unit/{95 custominc => 94 custominc}/meson.build (100%) rename test cases/unit/{95 custominc => 94 custominc}/prog.c (100%) rename test cases/unit/{95 custominc => 94 custominc}/prog2.c (100%) rename test cases/unit/{96 implicit force fallback => 95 implicit force fallback}/meson.build (100%) rename test cases/unit/{96 implicit force fallback => 95 implicit force fallback}/subprojects/something/meson.build (100%) rename test cases/unit/{97 compiler.links file arg => 96 compiler.links file arg}/meson.build (100%) rename test cases/unit/{97 compiler.links file arg => 96 compiler.links file arg}/test.c (100%) rename test cases/unit/{98 link full name => 97 link full name}/.gitignore (100%) rename test cases/unit/{98 link full name => 97 link full name}/libtestprovider/meson.build (100%) rename test cases/unit/{98 link full name => 97 link full name}/libtestprovider/provider.c (100%) rename test cases/unit/{98 link full name => 97 link full name}/proguser/meson.build (100%) rename test cases/unit/{98 link full name => 97 link full name}/proguser/receiver.c (100%) rename test cases/unit/{99 install all targets => 98 install all targets}/bar-custom.txt (100%) rename test cases/unit/{99 install all targets => 98 install all targets}/bar-devel.h (100%) rename test cases/unit/{99 install all targets => 98 install all targets}/bar-notag.txt (100%) rename test cases/unit/{99 install all targets => 98 install all targets}/custom_files/data.txt (100%) rename test cases/unit/{99 install all targets => 98 install all targets}/excludes/excluded.txt (100%) rename test cases/unit/{99 install all targets => 98 install all targets}/excludes/excluded/placeholder.txt (100%) rename test cases/unit/{99 install all targets => 98 install all targets}/excludes/installed.txt (100%) rename test cases/unit/{99 install all targets => 98 install all targets}/foo.in (100%) rename test cases/unit/{99 install all targets => 98 install all targets}/foo1-devel.h (100%) rename test cases/unit/{99 install all targets => 98 install all targets}/lib.c (100%) rename test cases/unit/{99 install all targets => 98 install all targets}/main.c (100%) rename test cases/unit/{99 install all targets => 98 install all targets}/meson.build (100%) rename test cases/unit/{99 install all targets => 98 install all targets}/script.py (100%) rename test cases/unit/{99 install all targets => 98 install all targets}/subdir/bar2-devel.h (100%) rename test cases/unit/{99 install all targets => 98 install all targets}/subdir/foo2.in (100%) rename test cases/unit/{99 install all targets => 98 install all targets}/subdir/foo3-devel.h (100%) rename test cases/unit/{99 install all targets => 98 install all targets}/subdir/lib.c (100%) rename test cases/unit/{99 install all targets => 98 install all targets}/subdir/main.c (100%) rename test cases/unit/{99 install all targets => 98 install all targets}/subdir/meson.build (100%) rename test cases/unit/{99 install all targets => 98 install all targets}/subdir/script.py (100%) rename test cases/unit/{99 install all targets => 98 install all targets}/subprojects/subproject/aaa.txt (100%) rename test cases/unit/{99 install all targets => 98 install all targets}/subprojects/subproject/bbb.txt (100%) rename test cases/unit/{99 install all targets => 98 install all targets}/subprojects/subproject/meson.build (100%) rename test cases/unit/{100 custom target name => 99 custom target name}/file.txt.in (100%) rename test cases/unit/{100 custom target name => 99 custom target name}/meson.build (100%) rename test cases/unit/{100 custom target name => 99 custom target name}/subdir/meson.build (100%) diff --git a/test cases/common/279 pkgconfig-gen/meson.build b/test cases/common/280 pkgconfig-gen/meson.build similarity index 100% rename from test cases/common/279 pkgconfig-gen/meson.build rename to test cases/common/280 pkgconfig-gen/meson.build diff --git a/test cases/common/279 pkgconfig-gen/simple.c b/test cases/common/280 pkgconfig-gen/simple.c similarity index 100% rename from test cases/common/279 pkgconfig-gen/simple.c rename to test cases/common/280 pkgconfig-gen/simple.c diff --git a/test cases/common/279 pkgconfig-gen/simple.h b/test cases/common/280 pkgconfig-gen/simple.h similarity index 100% rename from test cases/common/279 pkgconfig-gen/simple.h rename to test cases/common/280 pkgconfig-gen/simple.h diff --git a/test cases/common/279 pkgconfig-gen/simple2/exports.def b/test cases/common/280 pkgconfig-gen/simple2/exports.def similarity index 100% rename from test cases/common/279 pkgconfig-gen/simple2/exports.def rename to test cases/common/280 pkgconfig-gen/simple2/exports.def diff --git a/test cases/common/279 pkgconfig-gen/simple2/meson.build b/test cases/common/280 pkgconfig-gen/simple2/meson.build similarity index 100% rename from test cases/common/279 pkgconfig-gen/simple2/meson.build rename to test cases/common/280 pkgconfig-gen/simple2/meson.build diff --git a/test cases/common/279 pkgconfig-gen/simple2/simple2.c b/test cases/common/280 pkgconfig-gen/simple2/simple2.c similarity index 100% rename from test cases/common/279 pkgconfig-gen/simple2/simple2.c rename to test cases/common/280 pkgconfig-gen/simple2/simple2.c diff --git a/test cases/common/279 pkgconfig-gen/simple2/simple2.h b/test cases/common/280 pkgconfig-gen/simple2/simple2.h similarity index 100% rename from test cases/common/279 pkgconfig-gen/simple2/simple2.h rename to test cases/common/280 pkgconfig-gen/simple2/simple2.h diff --git a/test cases/common/279 pkgconfig-gen/test.json b/test cases/common/280 pkgconfig-gen/test.json similarity index 100% rename from test cases/common/279 pkgconfig-gen/test.json rename to test cases/common/280 pkgconfig-gen/test.json diff --git a/test cases/unit/101 relative find program/foo.py b/test cases/unit/100 relative find program/foo.py similarity index 100% rename from test cases/unit/101 relative find program/foo.py rename to test cases/unit/100 relative find program/foo.py diff --git a/test cases/unit/101 relative find program/meson.build b/test cases/unit/100 relative find program/meson.build similarity index 100% rename from test cases/unit/101 relative find program/meson.build rename to test cases/unit/100 relative find program/meson.build diff --git a/test cases/unit/101 relative find program/subdir/meson.build b/test cases/unit/100 relative find program/subdir/meson.build similarity index 100% rename from test cases/unit/101 relative find program/subdir/meson.build rename to test cases/unit/100 relative find program/subdir/meson.build diff --git a/test cases/unit/102 rlib linkage/lib2.rs b/test cases/unit/101 rlib linkage/lib2.rs similarity index 100% rename from test cases/unit/102 rlib linkage/lib2.rs rename to test cases/unit/101 rlib linkage/lib2.rs diff --git a/test cases/unit/102 rlib linkage/main.rs b/test cases/unit/101 rlib linkage/main.rs similarity index 100% rename from test cases/unit/102 rlib linkage/main.rs rename to test cases/unit/101 rlib linkage/main.rs diff --git a/test cases/unit/102 rlib linkage/meson.build b/test cases/unit/101 rlib linkage/meson.build similarity index 100% rename from test cases/unit/102 rlib linkage/meson.build rename to test cases/unit/101 rlib linkage/meson.build diff --git a/test cases/unit/103 python without pkgconfig/meson.build b/test cases/unit/102 python without pkgconfig/meson.build similarity index 100% rename from test cases/unit/103 python without pkgconfig/meson.build rename to test cases/unit/102 python without pkgconfig/meson.build diff --git a/test cases/unit/104 strip/lib.c b/test cases/unit/103 strip/lib.c similarity index 100% rename from test cases/unit/104 strip/lib.c rename to test cases/unit/103 strip/lib.c diff --git a/test cases/unit/104 strip/meson.build b/test cases/unit/103 strip/meson.build similarity index 100% rename from test cases/unit/104 strip/meson.build rename to test cases/unit/103 strip/meson.build diff --git a/test cases/unit/105 debug function/meson.build b/test cases/unit/104 debug function/meson.build similarity index 100% rename from test cases/unit/105 debug function/meson.build rename to test cases/unit/104 debug function/meson.build diff --git a/test cases/unit/106 pkgconfig relocatable with absolute path/meson.build b/test cases/unit/105 pkgconfig relocatable with absolute path/meson.build similarity index 100% rename from test cases/unit/106 pkgconfig relocatable with absolute path/meson.build rename to test cases/unit/105 pkgconfig relocatable with absolute path/meson.build diff --git a/test cases/unit/92 install skip subprojects/foo.c b/test cases/unit/91 install skip subprojects/foo.c similarity index 100% rename from test cases/unit/92 install skip subprojects/foo.c rename to test cases/unit/91 install skip subprojects/foo.c diff --git a/test cases/unit/92 install skip subprojects/foo.dat b/test cases/unit/91 install skip subprojects/foo.dat similarity index 100% rename from test cases/unit/92 install skip subprojects/foo.dat rename to test cases/unit/91 install skip subprojects/foo.dat diff --git a/test cases/unit/92 install skip subprojects/foo.h b/test cases/unit/91 install skip subprojects/foo.h similarity index 100% rename from test cases/unit/92 install skip subprojects/foo.h rename to test cases/unit/91 install skip subprojects/foo.h diff --git a/test cases/unit/92 install skip subprojects/foo/foofile b/test cases/unit/91 install skip subprojects/foo/foofile similarity index 100% rename from test cases/unit/92 install skip subprojects/foo/foofile rename to test cases/unit/91 install skip subprojects/foo/foofile diff --git a/test cases/unit/92 install skip subprojects/meson.build b/test cases/unit/91 install skip subprojects/meson.build similarity index 100% rename from test cases/unit/92 install skip subprojects/meson.build rename to test cases/unit/91 install skip subprojects/meson.build diff --git a/test cases/unit/92 install skip subprojects/subprojects/bar/bar.c b/test cases/unit/91 install skip subprojects/subprojects/bar/bar.c similarity index 100% rename from test cases/unit/92 install skip subprojects/subprojects/bar/bar.c rename to test cases/unit/91 install skip subprojects/subprojects/bar/bar.c diff --git a/test cases/unit/92 install skip subprojects/subprojects/bar/bar.dat b/test cases/unit/91 install skip subprojects/subprojects/bar/bar.dat similarity index 100% rename from test cases/unit/92 install skip subprojects/subprojects/bar/bar.dat rename to test cases/unit/91 install skip subprojects/subprojects/bar/bar.dat diff --git a/test cases/unit/92 install skip subprojects/subprojects/bar/bar.h b/test cases/unit/91 install skip subprojects/subprojects/bar/bar.h similarity index 100% rename from test cases/unit/92 install skip subprojects/subprojects/bar/bar.h rename to test cases/unit/91 install skip subprojects/subprojects/bar/bar.h diff --git a/test cases/unit/92 install skip subprojects/subprojects/bar/bar/barfile b/test cases/unit/91 install skip subprojects/subprojects/bar/bar/barfile similarity index 100% rename from test cases/unit/92 install skip subprojects/subprojects/bar/bar/barfile rename to test cases/unit/91 install skip subprojects/subprojects/bar/bar/barfile diff --git a/test cases/unit/92 install skip subprojects/subprojects/bar/meson.build b/test cases/unit/91 install skip subprojects/subprojects/bar/meson.build similarity index 100% rename from test cases/unit/92 install skip subprojects/subprojects/bar/meson.build rename to test cases/unit/91 install skip subprojects/subprojects/bar/meson.build diff --git a/test cases/unit/93 new subproject in configured project/meson.build b/test cases/unit/92 new subproject in configured project/meson.build similarity index 100% rename from test cases/unit/93 new subproject in configured project/meson.build rename to test cases/unit/92 new subproject in configured project/meson.build diff --git a/test cases/unit/93 new subproject in configured project/meson_options.txt b/test cases/unit/92 new subproject in configured project/meson_options.txt similarity index 100% rename from test cases/unit/93 new subproject in configured project/meson_options.txt rename to test cases/unit/92 new subproject in configured project/meson_options.txt diff --git a/test cases/unit/93 new subproject in configured project/subprojects/sub/foo.c b/test cases/unit/92 new subproject in configured project/subprojects/sub/foo.c similarity index 100% rename from test cases/unit/93 new subproject in configured project/subprojects/sub/foo.c rename to test cases/unit/92 new subproject in configured project/subprojects/sub/foo.c diff --git a/test cases/unit/93 new subproject in configured project/subprojects/sub/meson.build b/test cases/unit/92 new subproject in configured project/subprojects/sub/meson.build similarity index 100% rename from test cases/unit/93 new subproject in configured project/subprojects/sub/meson.build rename to test cases/unit/92 new subproject in configured project/subprojects/sub/meson.build diff --git a/test cases/unit/94 clangformat/.clang-format b/test cases/unit/93 clangformat/.clang-format similarity index 100% rename from test cases/unit/94 clangformat/.clang-format rename to test cases/unit/93 clangformat/.clang-format diff --git a/test cases/unit/94 clangformat/.clang-format-ignore b/test cases/unit/93 clangformat/.clang-format-ignore similarity index 100% rename from test cases/unit/94 clangformat/.clang-format-ignore rename to test cases/unit/93 clangformat/.clang-format-ignore diff --git a/test cases/unit/94 clangformat/.clang-format-include b/test cases/unit/93 clangformat/.clang-format-include similarity index 100% rename from test cases/unit/94 clangformat/.clang-format-include rename to test cases/unit/93 clangformat/.clang-format-include diff --git a/test cases/unit/94 clangformat/meson.build b/test cases/unit/93 clangformat/meson.build similarity index 100% rename from test cases/unit/94 clangformat/meson.build rename to test cases/unit/93 clangformat/meson.build diff --git a/test cases/unit/94 clangformat/not-included/badformat.cpp b/test cases/unit/93 clangformat/not-included/badformat.cpp similarity index 100% rename from test cases/unit/94 clangformat/not-included/badformat.cpp rename to test cases/unit/93 clangformat/not-included/badformat.cpp diff --git a/test cases/unit/94 clangformat/src/badformat.c b/test cases/unit/93 clangformat/src/badformat.c similarity index 100% rename from test cases/unit/94 clangformat/src/badformat.c rename to test cases/unit/93 clangformat/src/badformat.c diff --git a/test cases/unit/94 clangformat/src/badformat.cpp b/test cases/unit/93 clangformat/src/badformat.cpp similarity index 100% rename from test cases/unit/94 clangformat/src/badformat.cpp rename to test cases/unit/93 clangformat/src/badformat.cpp diff --git a/test cases/unit/95 custominc/easytogrepfor/genh.py b/test cases/unit/94 custominc/easytogrepfor/genh.py similarity index 100% rename from test cases/unit/95 custominc/easytogrepfor/genh.py rename to test cases/unit/94 custominc/easytogrepfor/genh.py diff --git a/test cases/unit/95 custominc/easytogrepfor/meson.build b/test cases/unit/94 custominc/easytogrepfor/meson.build similarity index 100% rename from test cases/unit/95 custominc/easytogrepfor/meson.build rename to test cases/unit/94 custominc/easytogrepfor/meson.build diff --git a/test cases/unit/95 custominc/helper.c b/test cases/unit/94 custominc/helper.c similarity index 100% rename from test cases/unit/95 custominc/helper.c rename to test cases/unit/94 custominc/helper.c diff --git a/test cases/unit/95 custominc/meson.build b/test cases/unit/94 custominc/meson.build similarity index 100% rename from test cases/unit/95 custominc/meson.build rename to test cases/unit/94 custominc/meson.build diff --git a/test cases/unit/95 custominc/prog.c b/test cases/unit/94 custominc/prog.c similarity index 100% rename from test cases/unit/95 custominc/prog.c rename to test cases/unit/94 custominc/prog.c diff --git a/test cases/unit/95 custominc/prog2.c b/test cases/unit/94 custominc/prog2.c similarity index 100% rename from test cases/unit/95 custominc/prog2.c rename to test cases/unit/94 custominc/prog2.c diff --git a/test cases/unit/96 implicit force fallback/meson.build b/test cases/unit/95 implicit force fallback/meson.build similarity index 100% rename from test cases/unit/96 implicit force fallback/meson.build rename to test cases/unit/95 implicit force fallback/meson.build diff --git a/test cases/unit/96 implicit force fallback/subprojects/something/meson.build b/test cases/unit/95 implicit force fallback/subprojects/something/meson.build similarity index 100% rename from test cases/unit/96 implicit force fallback/subprojects/something/meson.build rename to test cases/unit/95 implicit force fallback/subprojects/something/meson.build diff --git a/test cases/unit/97 compiler.links file arg/meson.build b/test cases/unit/96 compiler.links file arg/meson.build similarity index 100% rename from test cases/unit/97 compiler.links file arg/meson.build rename to test cases/unit/96 compiler.links file arg/meson.build diff --git a/test cases/unit/97 compiler.links file arg/test.c b/test cases/unit/96 compiler.links file arg/test.c similarity index 100% rename from test cases/unit/97 compiler.links file arg/test.c rename to test cases/unit/96 compiler.links file arg/test.c diff --git a/test cases/unit/98 link full name/.gitignore b/test cases/unit/97 link full name/.gitignore similarity index 100% rename from test cases/unit/98 link full name/.gitignore rename to test cases/unit/97 link full name/.gitignore diff --git a/test cases/unit/98 link full name/libtestprovider/meson.build b/test cases/unit/97 link full name/libtestprovider/meson.build similarity index 100% rename from test cases/unit/98 link full name/libtestprovider/meson.build rename to test cases/unit/97 link full name/libtestprovider/meson.build diff --git a/test cases/unit/98 link full name/libtestprovider/provider.c b/test cases/unit/97 link full name/libtestprovider/provider.c similarity index 100% rename from test cases/unit/98 link full name/libtestprovider/provider.c rename to test cases/unit/97 link full name/libtestprovider/provider.c diff --git a/test cases/unit/98 link full name/proguser/meson.build b/test cases/unit/97 link full name/proguser/meson.build similarity index 100% rename from test cases/unit/98 link full name/proguser/meson.build rename to test cases/unit/97 link full name/proguser/meson.build diff --git a/test cases/unit/98 link full name/proguser/receiver.c b/test cases/unit/97 link full name/proguser/receiver.c similarity index 100% rename from test cases/unit/98 link full name/proguser/receiver.c rename to test cases/unit/97 link full name/proguser/receiver.c diff --git a/test cases/unit/99 install all targets/bar-custom.txt b/test cases/unit/98 install all targets/bar-custom.txt similarity index 100% rename from test cases/unit/99 install all targets/bar-custom.txt rename to test cases/unit/98 install all targets/bar-custom.txt diff --git a/test cases/unit/99 install all targets/bar-devel.h b/test cases/unit/98 install all targets/bar-devel.h similarity index 100% rename from test cases/unit/99 install all targets/bar-devel.h rename to test cases/unit/98 install all targets/bar-devel.h diff --git a/test cases/unit/99 install all targets/bar-notag.txt b/test cases/unit/98 install all targets/bar-notag.txt similarity index 100% rename from test cases/unit/99 install all targets/bar-notag.txt rename to test cases/unit/98 install all targets/bar-notag.txt diff --git a/test cases/unit/99 install all targets/custom_files/data.txt b/test cases/unit/98 install all targets/custom_files/data.txt similarity index 100% rename from test cases/unit/99 install all targets/custom_files/data.txt rename to test cases/unit/98 install all targets/custom_files/data.txt diff --git a/test cases/unit/99 install all targets/excludes/excluded.txt b/test cases/unit/98 install all targets/excludes/excluded.txt similarity index 100% rename from test cases/unit/99 install all targets/excludes/excluded.txt rename to test cases/unit/98 install all targets/excludes/excluded.txt diff --git a/test cases/unit/99 install all targets/excludes/excluded/placeholder.txt b/test cases/unit/98 install all targets/excludes/excluded/placeholder.txt similarity index 100% rename from test cases/unit/99 install all targets/excludes/excluded/placeholder.txt rename to test cases/unit/98 install all targets/excludes/excluded/placeholder.txt diff --git a/test cases/unit/99 install all targets/excludes/installed.txt b/test cases/unit/98 install all targets/excludes/installed.txt similarity index 100% rename from test cases/unit/99 install all targets/excludes/installed.txt rename to test cases/unit/98 install all targets/excludes/installed.txt diff --git a/test cases/unit/99 install all targets/foo.in b/test cases/unit/98 install all targets/foo.in similarity index 100% rename from test cases/unit/99 install all targets/foo.in rename to test cases/unit/98 install all targets/foo.in diff --git a/test cases/unit/99 install all targets/foo1-devel.h b/test cases/unit/98 install all targets/foo1-devel.h similarity index 100% rename from test cases/unit/99 install all targets/foo1-devel.h rename to test cases/unit/98 install all targets/foo1-devel.h diff --git a/test cases/unit/99 install all targets/lib.c b/test cases/unit/98 install all targets/lib.c similarity index 100% rename from test cases/unit/99 install all targets/lib.c rename to test cases/unit/98 install all targets/lib.c diff --git a/test cases/unit/99 install all targets/main.c b/test cases/unit/98 install all targets/main.c similarity index 100% rename from test cases/unit/99 install all targets/main.c rename to test cases/unit/98 install all targets/main.c diff --git a/test cases/unit/99 install all targets/meson.build b/test cases/unit/98 install all targets/meson.build similarity index 100% rename from test cases/unit/99 install all targets/meson.build rename to test cases/unit/98 install all targets/meson.build diff --git a/test cases/unit/99 install all targets/script.py b/test cases/unit/98 install all targets/script.py similarity index 100% rename from test cases/unit/99 install all targets/script.py rename to test cases/unit/98 install all targets/script.py diff --git a/test cases/unit/99 install all targets/subdir/bar2-devel.h b/test cases/unit/98 install all targets/subdir/bar2-devel.h similarity index 100% rename from test cases/unit/99 install all targets/subdir/bar2-devel.h rename to test cases/unit/98 install all targets/subdir/bar2-devel.h diff --git a/test cases/unit/99 install all targets/subdir/foo2.in b/test cases/unit/98 install all targets/subdir/foo2.in similarity index 100% rename from test cases/unit/99 install all targets/subdir/foo2.in rename to test cases/unit/98 install all targets/subdir/foo2.in diff --git a/test cases/unit/99 install all targets/subdir/foo3-devel.h b/test cases/unit/98 install all targets/subdir/foo3-devel.h similarity index 100% rename from test cases/unit/99 install all targets/subdir/foo3-devel.h rename to test cases/unit/98 install all targets/subdir/foo3-devel.h diff --git a/test cases/unit/99 install all targets/subdir/lib.c b/test cases/unit/98 install all targets/subdir/lib.c similarity index 100% rename from test cases/unit/99 install all targets/subdir/lib.c rename to test cases/unit/98 install all targets/subdir/lib.c diff --git a/test cases/unit/99 install all targets/subdir/main.c b/test cases/unit/98 install all targets/subdir/main.c similarity index 100% rename from test cases/unit/99 install all targets/subdir/main.c rename to test cases/unit/98 install all targets/subdir/main.c diff --git a/test cases/unit/99 install all targets/subdir/meson.build b/test cases/unit/98 install all targets/subdir/meson.build similarity index 100% rename from test cases/unit/99 install all targets/subdir/meson.build rename to test cases/unit/98 install all targets/subdir/meson.build diff --git a/test cases/unit/99 install all targets/subdir/script.py b/test cases/unit/98 install all targets/subdir/script.py similarity index 100% rename from test cases/unit/99 install all targets/subdir/script.py rename to test cases/unit/98 install all targets/subdir/script.py diff --git a/test cases/unit/99 install all targets/subprojects/subproject/aaa.txt b/test cases/unit/98 install all targets/subprojects/subproject/aaa.txt similarity index 100% rename from test cases/unit/99 install all targets/subprojects/subproject/aaa.txt rename to test cases/unit/98 install all targets/subprojects/subproject/aaa.txt diff --git a/test cases/unit/99 install all targets/subprojects/subproject/bbb.txt b/test cases/unit/98 install all targets/subprojects/subproject/bbb.txt similarity index 100% rename from test cases/unit/99 install all targets/subprojects/subproject/bbb.txt rename to test cases/unit/98 install all targets/subprojects/subproject/bbb.txt diff --git a/test cases/unit/99 install all targets/subprojects/subproject/meson.build b/test cases/unit/98 install all targets/subprojects/subproject/meson.build similarity index 100% rename from test cases/unit/99 install all targets/subprojects/subproject/meson.build rename to test cases/unit/98 install all targets/subprojects/subproject/meson.build diff --git a/test cases/unit/100 custom target name/file.txt.in b/test cases/unit/99 custom target name/file.txt.in similarity index 100% rename from test cases/unit/100 custom target name/file.txt.in rename to test cases/unit/99 custom target name/file.txt.in diff --git a/test cases/unit/100 custom target name/meson.build b/test cases/unit/99 custom target name/meson.build similarity index 100% rename from test cases/unit/100 custom target name/meson.build rename to test cases/unit/99 custom target name/meson.build diff --git a/test cases/unit/100 custom target name/subdir/meson.build b/test cases/unit/99 custom target name/subdir/meson.build similarity index 100% rename from test cases/unit/100 custom target name/subdir/meson.build rename to test cases/unit/99 custom target name/subdir/meson.build diff --git a/unittests/allplatformstests.py b/unittests/allplatformstests.py index afea39742bcb..cadbc40e9680 100644 --- a/unittests/allplatformstests.py +++ b/unittests/allplatformstests.py @@ -627,7 +627,7 @@ def test_forcefallback(self): self.run_tests() def test_implicit_forcefallback(self): - testdir = os.path.join(self.unit_test_dir, '96 implicit force fallback') + testdir = os.path.join(self.unit_test_dir, '95 implicit force fallback') with self.assertRaises(subprocess.CalledProcessError): self.init(testdir) self.init(testdir, extra_args=['--wrap-mode=forcefallback']) @@ -2061,7 +2061,7 @@ def check_pcfile(name, *, relocatable, levels=2): check_pcfile('libvartest2.pc', relocatable=False) self.wipe() - testdir_abs = os.path.join(self.unit_test_dir, '106 pkgconfig relocatable with absolute path') + testdir_abs = os.path.join(self.unit_test_dir, '105 pkgconfig relocatable with absolute path') self.init(testdir_abs) check_pcfile('libsimple.pc', relocatable=True, levels=3) @@ -2472,7 +2472,7 @@ def test_check_module_linking(self): self.assertIn(msg, out) def test_mixed_language_linker_check(self): - testdir = os.path.join(self.unit_test_dir, '97 compiler.links file arg') + testdir = os.path.join(self.unit_test_dir, '96 compiler.links file arg') self.init(testdir) cmds = self.get_meson_log_compiler_checks() self.assertEqual(len(cmds), 5) @@ -4297,7 +4297,7 @@ def test_build_b_options(self) -> None: self.init(srcdir, extra_args=['-Dbuild.b_lto=true']) def test_install_skip_subprojects(self): - testdir = os.path.join(self.unit_test_dir, '92 install skip subprojects') + testdir = os.path.join(self.unit_test_dir, '91 install skip subprojects') self.init(testdir) self.build() @@ -4344,7 +4344,7 @@ def check_installed_files(extra_args, expected): check_installed_files(['--skip-subprojects', 'another'], all_expected) def test_adding_subproject_to_configure_project(self) -> None: - srcdir = os.path.join(self.unit_test_dir, '93 new subproject in configured project') + srcdir = os.path.join(self.unit_test_dir, '92 new subproject in configured project') self.init(srcdir) self.build() self.setconf('-Duse-sub=true') @@ -4394,7 +4394,7 @@ def test_clang_format_check(self): if not shutil.which('clang-format'): raise SkipTest('clang-format not found') - testdir = os.path.join(self.unit_test_dir, '94 clangformat') + testdir = os.path.join(self.unit_test_dir, '93 clangformat') newdir = os.path.join(self.builddir, 'testdir') shutil.copytree(testdir, newdir) self.new_builddir() @@ -4419,7 +4419,7 @@ def test_clang_format_check(self): self.build('clang-format-check') def test_custom_target_implicit_include(self): - testdir = os.path.join(self.unit_test_dir, '95 custominc') + testdir = os.path.join(self.unit_test_dir, '94 custominc') self.init(testdir) self.build() compdb = self.get_compdb() @@ -4459,7 +4459,7 @@ def test_env_flags_to_linker(self) -> None: self.assertEqual(sorted(link_args), sorted(['-flto'])) def test_install_tag(self) -> None: - testdir = os.path.join(self.unit_test_dir, '99 install all targets') + testdir = os.path.join(self.unit_test_dir, '98 install all targets') self.init(testdir) self.build() @@ -4630,7 +4630,7 @@ def test_install_script_dry_run(self): def test_introspect_install_plan(self): - testdir = os.path.join(self.unit_test_dir, '99 install all targets') + testdir = os.path.join(self.unit_test_dir, '98 install all targets') introfile = os.path.join(self.builddir, 'meson-info', 'intro-install_plan.json') self.init(testdir) self.assertPathExists(introfile) @@ -4902,7 +4902,7 @@ def test_rust_rlib_linkage(self) -> None: }} ''') - testdir = os.path.join(self.unit_test_dir, '102 rlib linkage') + testdir = os.path.join(self.unit_test_dir, '101 rlib linkage') gen_file = os.path.join(testdir, 'lib.rs') with open(gen_file, 'w', encoding='utf-8') as f: f.write(template.format(0)) @@ -4950,7 +4950,7 @@ def test_bindgen_drops_invalid(self) -> None: return def test_custom_target_name(self): - testdir = os.path.join(self.unit_test_dir, '100 custom target name') + testdir = os.path.join(self.unit_test_dir, '99 custom target name') self.init(testdir) out = self.build() if self.backend is Backend.ninja: diff --git a/unittests/linuxliketests.py b/unittests/linuxliketests.py index bf0437bca582..3ac98076095c 100644 --- a/unittests/linuxliketests.py +++ b/unittests/linuxliketests.py @@ -1333,7 +1333,7 @@ def test_link_arg_fullname(self): see: https://github.com/mesonbuild/meson/issues/9000 https://stackoverflow.com/questions/48532868/gcc-library-option-with-a-colon-llibevent-a ''' - testdir = os.path.join(self.unit_test_dir, '98 link full name','libtestprovider') + testdir = os.path.join(self.unit_test_dir, '97 link full name','libtestprovider') oldprefix = self.prefix # install into installdir without using DESTDIR installdir = self.installdir @@ -1346,7 +1346,7 @@ def test_link_arg_fullname(self): self.new_builddir() env = {'LIBRARY_PATH': os.path.join(installdir, self.libdir), 'PKG_CONFIG_PATH': _prepend_pkg_config_path(os.path.join(installdir, self.libdir, 'pkgconfig'))} - testdir = os.path.join(self.unit_test_dir, '98 link full name','proguser') + testdir = os.path.join(self.unit_test_dir, '97 link full name','proguser') self.init(testdir,override_envvars=env) # test for link with full path @@ -1752,7 +1752,7 @@ def test_cmake_multilib(self): @skipUnless(is_linux() or is_osx(), 'Test only applicable to Linux and macOS') def test_install_strip(self): - testdir = os.path.join(self.unit_test_dir, '104 strip') + testdir = os.path.join(self.unit_test_dir, '103 strip') self.init(testdir) self.build() diff --git a/unittests/platformagnostictests.py b/unittests/platformagnostictests.py index 3ee0b458c9dd..2fb75f284993 100644 --- a/unittests/platformagnostictests.py +++ b/unittests/platformagnostictests.py @@ -32,7 +32,7 @@ def test_relative_find_program(self): Tests that find_program() with a relative path does not find the program in current workdir. ''' - testdir = os.path.join(self.unit_test_dir, '101 relative find program') + testdir = os.path.join(self.unit_test_dir, '100 relative find program') self.init(testdir, workdir=testdir) def test_invalid_option_names(self): @@ -91,11 +91,11 @@ def write_file(code: str): interp.process, fname) def test_python_dependency_without_pkgconfig(self): - testdir = os.path.join(self.unit_test_dir, '103 python without pkgconfig') + testdir = os.path.join(self.unit_test_dir, '102 python without pkgconfig') self.init(testdir, override_envvars={'PKG_CONFIG': 'notfound'}) def test_debug_function_outputs_to_meson_log(self): - testdir = os.path.join(self.unit_test_dir, '105 debug function') + testdir = os.path.join(self.unit_test_dir, '104 debug function') log_msg = 'This is an example debug output, should only end up in debug log' output = self.init(testdir) From 4c6c89ca7afa6244ba888ce08936acb470e126aa Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sun, 20 Oct 2024 19:33:06 +0300 Subject: [PATCH 274/302] Update docs and version number for release. --- docs/markdown/Release-notes-for-1.6.0.md | 175 ++++++++++++++++++ .../add_support_for_ibm_clang_for_AIX.md | 7 - .../alias_target_of_both_libraries.md | 5 - .../snippets/always_report_deprecations.md | 29 --- docs/markdown/snippets/cargo_exp.md | 8 - .../cmake_only_public_link_flags_in_dep.md | 8 - .../snippets/default_both_libraries.md | 11 -- .../snippets/dep_as_shared_as_static.md | 8 - docs/markdown/snippets/dia_sdk.md | 3 - docs/markdown/snippets/llvm_flang.md | 9 - .../snippets/nvc_now_support_setting_std.md | 6 - docs/markdown/snippets/qt_has_tools_ignore.md | 12 -- docs/markdown/snippets/reprotester.md | 15 -- .../snippets/system_variable_in_dep.md | 3 - .../test_args_accepts_external_program.md | 10 - docs/markdown/snippets/zig_ld.md | 18 -- docs/sitemap.txt | 1 + mesonbuild/coredata.py | 2 +- 18 files changed, 177 insertions(+), 153 deletions(-) create mode 100644 docs/markdown/Release-notes-for-1.6.0.md delete mode 100644 docs/markdown/snippets/add_support_for_ibm_clang_for_AIX.md delete mode 100644 docs/markdown/snippets/alias_target_of_both_libraries.md delete mode 100644 docs/markdown/snippets/always_report_deprecations.md delete mode 100644 docs/markdown/snippets/cargo_exp.md delete mode 100644 docs/markdown/snippets/cmake_only_public_link_flags_in_dep.md delete mode 100644 docs/markdown/snippets/default_both_libraries.md delete mode 100644 docs/markdown/snippets/dep_as_shared_as_static.md delete mode 100644 docs/markdown/snippets/dia_sdk.md delete mode 100644 docs/markdown/snippets/llvm_flang.md delete mode 100644 docs/markdown/snippets/nvc_now_support_setting_std.md delete mode 100644 docs/markdown/snippets/qt_has_tools_ignore.md delete mode 100644 docs/markdown/snippets/reprotester.md delete mode 100644 docs/markdown/snippets/system_variable_in_dep.md delete mode 100644 docs/markdown/snippets/test_args_accepts_external_program.md delete mode 100644 docs/markdown/snippets/zig_ld.md diff --git a/docs/markdown/Release-notes-for-1.6.0.md b/docs/markdown/Release-notes-for-1.6.0.md new file mode 100644 index 000000000000..9e5cea6d17d5 --- /dev/null +++ b/docs/markdown/Release-notes-for-1.6.0.md @@ -0,0 +1,175 @@ +--- +title: Release 1.6.0 +short-description: Release notes for 1.6.0 +... + +# New features + +Meson 1.6.0 was released on 20 October 2024 +## Support for OpenXL compiler in AIX. + +The OpenXL compiler is now supported from Meson 1.6.0 onwards. +So currently, in AIX Operating system we support GCC and openXL compilers for Meson build system. + +Both the compilers will archive shared libraries and generate a shared object +for a shared module while using Meson in AIX. + +## `alias_target` of `both_libraries` + +Previously, when passing a [[@both_libs]] object to [[alias_target]], the alias +would only point to the shared library. It now points to both the static and the +shared library. + +## Default to printing deprecations when no minimum version is specified. + +For a long time, the [[project]] function has supported specifying the minimum +`meson_version:` needed by a project. When this is used, deprecated features +from before that version produce warnings, as do features which aren't +available in all supported versions. + +When no minimum version was specified, meson didn't warn you even about +deprecated functionality that might go away in an upcoming semver major release +of meson. + +Now, meson will treat an unspecified minimum version following semver: + +- For new features introduced in the current meson semver major cycle + (currently: all features added since 1.0) a warning is printed. Features that + have been available since the initial 1.0 release are assumed to be widely + available. + +- For features that have been deprecated by any version of meson, a warning is + printed. Since no minimum version was specified, it is assumed that the + project wishes to follow the latest and greatest functionality. + +These warnings will overlap for functionality that was both deprecated and +replaced with an alternative in the current release cycle. The combination +means that projects without a minimum version specified are assumed to want +broad compatibility with the current release cycle (1.x). + +Projects that specify a minimum `meson_version:` will continue to only receive +actionable warnings based on their current minimum version. + +## Cargo subprojects is experimental + +Cargo subprojects was intended to be experimental with no stability guarantees. +That notice was unfortunately missing from documentation. Meson will now start +warning about usage of experimental features and future releases might do breaking +changes. + +This is aligned with our general policy regarding [mixing build systems](Mixing-build-systems.md). + +## Dependencies from CMake subprojects now use only PUBLIC link flags + +Any [[@dep]] obtained from a CMake subproject (or `.wrap` with `method = cmake`) +now only includes link flags marked in CMake as `PUBLIC` or `INTERFACE`. +Flags marked as `PRIVATE` are now only applied when building the subproject +library and not when using it as a dependency. This better matches how CMake +handles link flags and fixes link errors when using some CMake projects as +subprojects. + +## New built-in option for default both_libraries + +`both_libraries` targets used to be considered as a shared library by default. +There is now the `default_both_libraries` option to change this default. + +When `default_both_libraries` is 'auto', [[both_libraries]] with dependencies +that are [[@both_libs]] themselves will link with the same kind of library. +For example, if `libA` is a [[@both_libs]] and `libB` is a [[@both_libs]] +linked with `libA` (or with an internal dependency on `libA`), +the static lib of `libB` will link with the static lib of `libA`, and the +shared lib of `libA` will link with the shared lib of `libB`. + +## New `as_static` and `as_shared` methods on internal dependencies + +[[@dep]] object returned by [[declare_dependency]] now has `.as_static()` and +`.as_shared()` methods, to convert to a dependency that prefers the `static` +or the `shared` version of the linked [[@both_libs]] target. + +When the same dependency is used without those methods, the +`default_both_libraries` option determines which version is used. + +## Support for DIA SDK + +Added support for Windows Debug Interface Access SDK (DIA SDK) dependency. It allows reading with MSVC debugging information (.PDB format). This dependency can only be used on Windows, with msvc, clang or clang-cl compiler. + +## Support for LLVM-based flang compiler + +Added basic handling for the [flang](https://flang.llvm.org/docs/) compiler +that's now part of LLVM. It is the successor of another compiler named +[flang](https://github.com/flang-compiler/flang) by largely the same +group of developers, who now refer to the latter as "classic flang". + +Meson already supports classic flang, and the LLVM-based flang now +uses the compiler-id `'llvm-flang'`. + +## nvc and nvc++ now support setting std + +The following standards are available for nvc: c89, c90, c99, c11, +c17, c18, gnu90, gnu89, gnu99, gnu11, gnu17, gnu18. For nvc++: +c++98, c++03, c++11, c++14, c++17, c++20, c++23, gnu++98, gnu++03, +gnu++11, gnu++14, gnu++17, gnu++20 + +## Tools can be selected when calling `has_tools()` on the Qt modules + +When checking for the presence of Qt tools, you can now explictly ask Meson +which tools you need. This is particularly useful when you do not need +`lrelease` because you are not shipping any translations. For example: + +```meson +qt6_mod = import('qt6') +qt6_mod.has_tools(required: true, tools: ['moc', 'uic', 'rcc']) +``` + +valid tools are `moc`, `uic`, `rcc` and `lrelease`. + +## Simple tool to test build reproducibility + +Meson now ships with a command for testing whether your project can be +[built reprodicibly](https://reproducible-builds.org/). It can be used +by running a command like the following in the source root of your +project: + + meson reprotest --intermediaries -- --buildtype=debugoptimized + +All command line options after the `--` are passed to the build +invocations directly. + +This tool is not meant to be exhaustive, but instead easy and +convenient to run. It will detect some but definitely not all +reproducibility issues. + +## Support for variable in system dependencies + +System Dependency method `get_variable()` now supports `system` variable. + +## test() and benchmark() functions accept new types + +`test` and `benchmark` now accept ExternalPrograms (as returned by +`find_program`) in the `args` list. This can be useful where the test +executable is a wrapper which invokes another program given as an +argument. + +```meson +test('some_test', find_program('sudo'), args : [ find_program('sh'), 'script.sh' ]) +``` + +## Zig 0.11 can be used as a C/C++ compiler frontend + +Zig offers +[a C/C++ frontend](https://andrewkelley.me/post/zig-cc-powerful-drop-in-replacement-gcc-clang.html) as a drop-in replacement for Clang. It worked fine with Meson up to Zig 0.10. Since 0.11, Zig's +dynamic linker reports itself as `zig ld`, which wasn't known to Meson. Meson now correctly handles +Zig's linker. + +You can use Zig's frontend via a [machine file](Machine-files.md): + +```ini +[binaries] +c = ['zig', 'cc'] +cpp = ['zig', 'c++'] +ar = ['zig', 'ar'] +ranlib = ['zig', 'ranlib'] +lib = ['zig', 'lib'] +dlltool = ['zig', 'dlltool'] +``` + diff --git a/docs/markdown/snippets/add_support_for_ibm_clang_for_AIX.md b/docs/markdown/snippets/add_support_for_ibm_clang_for_AIX.md deleted file mode 100644 index 526bbb3cc41d..000000000000 --- a/docs/markdown/snippets/add_support_for_ibm_clang_for_AIX.md +++ /dev/null @@ -1,7 +0,0 @@ -## Support for OpenXL compiler in AIX. - -The OpenXL compiler is now supported from Meson 1.6.0 onwards. -So currently, in AIX Operating system we support GCC and openXL compilers for Meson build system. - -Both the compilers will archive shared libraries and generate a shared object -for a shared module while using Meson in AIX. diff --git a/docs/markdown/snippets/alias_target_of_both_libraries.md b/docs/markdown/snippets/alias_target_of_both_libraries.md deleted file mode 100644 index ab77a6556576..000000000000 --- a/docs/markdown/snippets/alias_target_of_both_libraries.md +++ /dev/null @@ -1,5 +0,0 @@ -## `alias_target` of `both_libraries` - -Previously, when passing a [[@both_libs]] object to [[alias_target]], the alias -would only point to the shared library. It now points to both the static and the -shared library. diff --git a/docs/markdown/snippets/always_report_deprecations.md b/docs/markdown/snippets/always_report_deprecations.md deleted file mode 100644 index fbf4cdf4701e..000000000000 --- a/docs/markdown/snippets/always_report_deprecations.md +++ /dev/null @@ -1,29 +0,0 @@ -## Default to printing deprecations when no minimum version is specified. - -For a long time, the [[project]] function has supported specifying the minimum -`meson_version:` needed by a project. When this is used, deprecated features -from before that version produce warnings, as do features which aren't -available in all supported versions. - -When no minimum version was specified, meson didn't warn you even about -deprecated functionality that might go away in an upcoming semver major release -of meson. - -Now, meson will treat an unspecified minimum version following semver: - -- For new features introduced in the current meson semver major cycle - (currently: all features added since 1.0) a warning is printed. Features that - have been available since the initial 1.0 release are assumed to be widely - available. - -- For features that have been deprecated by any version of meson, a warning is - printed. Since no minimum version was specified, it is assumed that the - project wishes to follow the latest and greatest functionality. - -These warnings will overlap for functionality that was both deprecated and -replaced with an alternative in the current release cycle. The combination -means that projects without a minimum version specified are assumed to want -broad compatibility with the current release cycle (1.x). - -Projects that specify a minimum `meson_version:` will continue to only receive -actionable warnings based on their current minimum version. diff --git a/docs/markdown/snippets/cargo_exp.md b/docs/markdown/snippets/cargo_exp.md deleted file mode 100644 index 34d379a70c4b..000000000000 --- a/docs/markdown/snippets/cargo_exp.md +++ /dev/null @@ -1,8 +0,0 @@ -## Cargo subprojects is experimental - -Cargo subprojects was intended to be experimental with no stability guarantees. -That notice was unfortunately missing from documentation. Meson will now start -warning about usage of experimental features and future releases might do breaking -changes. - -This is aligned with our general policy regarding [mixing build systems](Mixing-build-systems.md). diff --git a/docs/markdown/snippets/cmake_only_public_link_flags_in_dep.md b/docs/markdown/snippets/cmake_only_public_link_flags_in_dep.md deleted file mode 100644 index 83ccfd439166..000000000000 --- a/docs/markdown/snippets/cmake_only_public_link_flags_in_dep.md +++ /dev/null @@ -1,8 +0,0 @@ -## Dependencies from CMake subprojects now use only PUBLIC link flags - -Any [[@dep]] obtained from a CMake subproject (or `.wrap` with `method = cmake`) -now only includes link flags marked in CMake as `PUBLIC` or `INTERFACE`. -Flags marked as `PRIVATE` are now only applied when building the subproject -library and not when using it as a dependency. This better matches how CMake -handles link flags and fixes link errors when using some CMake projects as -subprojects. diff --git a/docs/markdown/snippets/default_both_libraries.md b/docs/markdown/snippets/default_both_libraries.md deleted file mode 100644 index dc9cb6bca3a8..000000000000 --- a/docs/markdown/snippets/default_both_libraries.md +++ /dev/null @@ -1,11 +0,0 @@ -## New built-in option for default both_libraries - -`both_libraries` targets used to be considered as a shared library by default. -There is now the `default_both_libraries` option to change this default. - -When `default_both_libraries` is 'auto', [[both_libraries]] with dependencies -that are [[@both_libs]] themselves will link with the same kind of library. -For example, if `libA` is a [[@both_libs]] and `libB` is a [[@both_libs]] -linked with `libA` (or with an internal dependency on `libA`), -the static lib of `libB` will link with the static lib of `libA`, and the -shared lib of `libA` will link with the shared lib of `libB`. diff --git a/docs/markdown/snippets/dep_as_shared_as_static.md b/docs/markdown/snippets/dep_as_shared_as_static.md deleted file mode 100644 index a84e9eeaa182..000000000000 --- a/docs/markdown/snippets/dep_as_shared_as_static.md +++ /dev/null @@ -1,8 +0,0 @@ -## New `as_static` and `as_shared` methods on internal dependencies - -[[@dep]] object returned by [[declare_dependency]] now has `.as_static()` and -`.as_shared()` methods, to convert to a dependency that prefers the `static` -or the `shared` version of the linked [[@both_libs]] target. - -When the same dependency is used without those methods, the -`default_both_libraries` option determines which version is used. diff --git a/docs/markdown/snippets/dia_sdk.md b/docs/markdown/snippets/dia_sdk.md deleted file mode 100644 index eb704230da4f..000000000000 --- a/docs/markdown/snippets/dia_sdk.md +++ /dev/null @@ -1,3 +0,0 @@ -## Support for DIA SDK - -Added support for Windows Debug Interface Access SDK (DIA SDK) dependency. It allows reading with MSVC debugging information (.PDB format). This dependency can only be used on Windows, with msvc, clang or clang-cl compiler. diff --git a/docs/markdown/snippets/llvm_flang.md b/docs/markdown/snippets/llvm_flang.md deleted file mode 100644 index 4575fe054ca9..000000000000 --- a/docs/markdown/snippets/llvm_flang.md +++ /dev/null @@ -1,9 +0,0 @@ -## Support for LLVM-based flang compiler - -Added basic handling for the [flang](https://flang.llvm.org/docs/) compiler -that's now part of LLVM. It is the successor of another compiler named -[flang](https://github.com/flang-compiler/flang) by largely the same -group of developers, who now refer to the latter as "classic flang". - -Meson already supports classic flang, and the LLVM-based flang now -uses the compiler-id `'llvm-flang'`. diff --git a/docs/markdown/snippets/nvc_now_support_setting_std.md b/docs/markdown/snippets/nvc_now_support_setting_std.md deleted file mode 100644 index 5e537ae9fb6b..000000000000 --- a/docs/markdown/snippets/nvc_now_support_setting_std.md +++ /dev/null @@ -1,6 +0,0 @@ -## nvc and nvc++ now support setting std - -The following standards are available for nvc: c89, c90, c99, c11, -c17, c18, gnu90, gnu89, gnu99, gnu11, gnu17, gnu18. For nvc++: -c++98, c++03, c++11, c++14, c++17, c++20, c++23, gnu++98, gnu++03, -gnu++11, gnu++14, gnu++17, gnu++20 diff --git a/docs/markdown/snippets/qt_has_tools_ignore.md b/docs/markdown/snippets/qt_has_tools_ignore.md deleted file mode 100644 index 4def48db2b51..000000000000 --- a/docs/markdown/snippets/qt_has_tools_ignore.md +++ /dev/null @@ -1,12 +0,0 @@ -## Tools can be selected when calling `has_tools()` on the Qt modules - -When checking for the presence of Qt tools, you can now explictly ask Meson -which tools you need. This is particularly useful when you do not need -`lrelease` because you are not shipping any translations. For example: - -```meson -qt6_mod = import('qt6') -qt6_mod.has_tools(required: true, tools: ['moc', 'uic', 'rcc']) -``` - -valid tools are `moc`, `uic`, `rcc` and `lrelease`. diff --git a/docs/markdown/snippets/reprotester.md b/docs/markdown/snippets/reprotester.md deleted file mode 100644 index dc86acdb988d..000000000000 --- a/docs/markdown/snippets/reprotester.md +++ /dev/null @@ -1,15 +0,0 @@ -## Simple tool to test build reproducibility - -Meson now ships with a command for testing whether your project can be -[built reprodicibly](https://reproducible-builds.org/). It can be used -by running a command like the following in the source root of your -project: - - meson reprotest --intermediaries -- --buildtype=debugoptimized - -All command line options after the `--` are passed to the build -invocations directly. - -This tool is not meant to be exhaustive, but instead easy and -convenient to run. It will detect some but definitely not all -reproducibility issues. diff --git a/docs/markdown/snippets/system_variable_in_dep.md b/docs/markdown/snippets/system_variable_in_dep.md deleted file mode 100644 index 0cd936322bd9..000000000000 --- a/docs/markdown/snippets/system_variable_in_dep.md +++ /dev/null @@ -1,3 +0,0 @@ -## Support for variable in system dependencies - -System Dependency method `get_variable()` now supports `system` variable. diff --git a/docs/markdown/snippets/test_args_accepts_external_program.md b/docs/markdown/snippets/test_args_accepts_external_program.md deleted file mode 100644 index d730ad5f3be5..000000000000 --- a/docs/markdown/snippets/test_args_accepts_external_program.md +++ /dev/null @@ -1,10 +0,0 @@ -## test() and benchmark() functions accept new types - -`test` and `benchmark` now accept ExternalPrograms (as returned by -`find_program`) in the `args` list. This can be useful where the test -executable is a wrapper which invokes another program given as an -argument. - -```meson -test('some_test', find_program('sudo'), args : [ find_program('sh'), 'script.sh' ]) -``` diff --git a/docs/markdown/snippets/zig_ld.md b/docs/markdown/snippets/zig_ld.md deleted file mode 100644 index 8835c38ca4f7..000000000000 --- a/docs/markdown/snippets/zig_ld.md +++ /dev/null @@ -1,18 +0,0 @@ -## Zig 0.11 can be used as a C/C++ compiler frontend - -Zig offers -[a C/C++ frontend](https://andrewkelley.me/post/zig-cc-powerful-drop-in-replacement-gcc-clang.html) as a drop-in replacement for Clang. It worked fine with Meson up to Zig 0.10. Since 0.11, Zig's -dynamic linker reports itself as `zig ld`, which wasn't known to Meson. Meson now correctly handles -Zig's linker. - -You can use Zig's frontend via a [machine file](Machine-files.md): - -```ini -[binaries] -c = ['zig', 'cc'] -cpp = ['zig', 'c++'] -ar = ['zig', 'ar'] -ranlib = ['zig', 'ranlib'] -lib = ['zig', 'lib'] -dlltool = ['zig', 'dlltool'] -``` diff --git a/docs/sitemap.txt b/docs/sitemap.txt index 79fdeeffe70f..8d7d157e1506 100644 --- a/docs/sitemap.txt +++ b/docs/sitemap.txt @@ -88,6 +88,7 @@ index.md Wrap-best-practices-and-tips.md Shipping-prebuilt-binaries-as-wraps.md Release-notes.md + Release-notes-for-1.6.0.md Release-notes-for-1.5.0.md Release-notes-for-1.4.0.md Release-notes-for-1.3.0.md diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index ced1eecdac63..963aedb402d4 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -74,7 +74,7 @@ class SharedCMDOptions(Protocol): # # Pip requires that RCs are named like this: '0.1.0.rc1' # But the corresponding Git tag needs to be '0.1.0rc1' -version = '1.6.0.rc2' +version = '1.6.0' # The next stable version when we are in dev. This is used to allow projects to # require meson version >=1.2.0 when using 1.1.99. FeatureNew won't warn when From c893fc84f12e3ad67033c2fa70bc04e206d2ab85 Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Mon, 14 Oct 2024 00:58:18 +0200 Subject: [PATCH 275/302] Add GNU/Hurd kernel results uname -s does return gnu there. Resolves: https://github.com/mesonbuild/meson/issues/13740 Signed-off-by: Samuel Thibault (cherry picked from commit 165c62208475085fdafddca29eee201bc98c3ab8) --- docs/markdown/Reference-tables.md | 1 + mesonbuild/environment.py | 1 + mesonbuild/scripts/env2mfile.py | 1 + unittests/internaltests.py | 6 +----- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/markdown/Reference-tables.md b/docs/markdown/Reference-tables.md index e4e964c2d3d7..a5d0d5cdcc18 100644 --- a/docs/markdown/Reference-tables.md +++ b/docs/markdown/Reference-tables.md @@ -182,6 +182,7 @@ Native names as returned by the `.kernel()` method. | freebsd | | | openbsd | | | netbsd | | +| gnu | GNU Hurd | | nt | | | xnu | Kernel of various Apple OSes | | illumos | Kernel derived from OpenSolaris by community efforts | diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 71a2f3afcb6a..2621b9ca2db1 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -476,6 +476,7 @@ def detect_cpu(compilers: CompilersDict) -> str: 'darwin': 'xnu', 'dragonfly': 'dragonfly', 'haiku': 'haiku', + 'gnu': 'gnu', } def detect_kernel(system: str) -> T.Optional[str]: diff --git a/mesonbuild/scripts/env2mfile.py b/mesonbuild/scripts/env2mfile.py index 207d75749c95..b2c9a45b2f80 100755 --- a/mesonbuild/scripts/env2mfile.py +++ b/mesonbuild/scripts/env2mfile.py @@ -156,6 +156,7 @@ def get_args_from_envvars(infos: MachineInfo) -> None: # map from DEB_HOST_ARCH_OS to Meson machine.kernel() deb_kernel_map = { 'kfreebsd': 'freebsd', + 'hurd': 'gnu', } def replace_special_cases(special_cases: T.Mapping[str, str], name: str) -> str: diff --git a/unittests/internaltests.py b/unittests/internaltests.py index 23d08e6e2992..3f50ac6e009b 100644 --- a/unittests/internaltests.py +++ b/unittests/internaltests.py @@ -1933,11 +1933,7 @@ def expected_binaries(gnu_tuple: str) -> T.Dict[str, T.List[str]]: }, system='gnu', subsystem='gnu', - # TODO: Currently hurd; should match whatever happens - # during native builds, but at the moment native builds - # fail when kernel() is called. - # https://github.com/mesonbuild/meson/issues/13740 - kernel='TODO', + kernel='gnu', cpu='i686', cpu_family='x86', endian='little', From 788773b51d064134aff994516d27826a3d2919f1 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Mon, 23 Sep 2024 19:33:30 +0100 Subject: [PATCH 276/302] env2mfile: Generalize detection of pkg-config to have a list of tools Cross-tools on Debian generally follow the naming convention set by Autotools AC_CHECK_TOOL, where the name is prefixed with the GNU architecture tuple for the host architecture. env2mfile was already using this for pkg-config, but there are many other tools that can be detected in the same way. Signed-off-by: Simon McVittie (cherry picked from commit 7300e4ed88286ed4fd1f3bf9f2b6b29a1f8768c0) --- mesonbuild/scripts/env2mfile.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/mesonbuild/scripts/env2mfile.py b/mesonbuild/scripts/env2mfile.py index b2c9a45b2f80..16ab1b980c4f 100755 --- a/mesonbuild/scripts/env2mfile.py +++ b/mesonbuild/scripts/env2mfile.py @@ -230,10 +230,13 @@ def dpkg_architecture_to_machine_info(output: str, options: T.Any) -> MachineInf deb_detect_cmake(infos, data) except ValueError: pass - try: - infos.binaries['pkg-config'] = locate_path("%s-pkg-config" % host_arch) - except ValueError: - pass # pkg-config is optional + for tool in [ + 'pkg-config', + ]: + try: + infos.binaries[tool] = locate_path("%s-%s" % (host_arch, tool)) + except ValueError: + pass # optional try: infos.binaries['cups-config'] = locate_path("cups-config") except ValueError: From 2918899e74f7f93b094af7d15dc6062e1de8b2d4 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 2 Oct 2024 19:23:42 +0100 Subject: [PATCH 277/302] env2mfile: Use Debian cross-prefixed GObject-Introspection tools In Debian testing/unstable, there are wrappers available for various GObject-Introspection tools during cross-builds, using qemu internally. Signed-off-by: Simon McVittie (cherry picked from commit 851d866349b41533d57ef8a3c3e49f01f95680e3) --- mesonbuild/scripts/env2mfile.py | 6 ++++++ unittests/internaltests.py | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/mesonbuild/scripts/env2mfile.py b/mesonbuild/scripts/env2mfile.py index 16ab1b980c4f..2a366fd19950 100755 --- a/mesonbuild/scripts/env2mfile.py +++ b/mesonbuild/scripts/env2mfile.py @@ -231,6 +231,12 @@ def dpkg_architecture_to_machine_info(output: str, options: T.Any) -> MachineInf except ValueError: pass for tool in [ + 'g-ir-annotation-tool', + 'g-ir-compiler', + 'g-ir-doc-tool', + 'g-ir-generate', + 'g-ir-inspect', + 'g-ir-scanner', 'pkg-config', ]: try: diff --git a/unittests/internaltests.py b/unittests/internaltests.py index 3f50ac6e009b..0cf70600189f 100644 --- a/unittests/internaltests.py +++ b/unittests/internaltests.py @@ -1750,6 +1750,12 @@ def expected_binaries(gnu_tuple: str) -> T.Dict[str, T.List[str]]: 'cmake': ['/usr/bin/cmake'], 'pkg-config': [f'/usr/bin/{gnu_tuple}-pkg-config'], 'cups-config': ['/usr/bin/cups-config'], + 'g-ir-annotation-tool': [f'/usr/bin/{gnu_tuple}-g-ir-annotation-tool'], + 'g-ir-compiler': [f'/usr/bin/{gnu_tuple}-g-ir-compiler'], + 'g-ir-doc-tool': [f'/usr/bin/{gnu_tuple}-g-ir-doc-tool'], + 'g-ir-generate': [f'/usr/bin/{gnu_tuple}-g-ir-generate'], + 'g-ir-inspect': [f'/usr/bin/{gnu_tuple}-g-ir-inspect'], + 'g-ir-scanner': [f'/usr/bin/{gnu_tuple}-g-ir-scanner'], } for title, dpkg_arch, gccsuffix, env, expected in [ From 18443151d96caeae85f54ddb414e3af64dd62b8a Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 2 Oct 2024 19:25:12 +0100 Subject: [PATCH 278/302] env2mfile: Automatically set exe_wrapper on Debian if possible Recent versions of the architecture-properties package provide a cross-exe-wrapper package containing ${DEB_HOST_GNU_TYPE}-cross-exe-wrapper, which is currently a wrapper around qemu-user but could use different emulators on each architecture if it becomes necessary in the future. Signed-off-by: Simon McVittie (cherry picked from commit 86f9fe4c9a825feb93ca4b2ecf701d0877120d06) --- mesonbuild/scripts/env2mfile.py | 7 +++++++ unittests/internaltests.py | 1 + 2 files changed, 8 insertions(+) diff --git a/mesonbuild/scripts/env2mfile.py b/mesonbuild/scripts/env2mfile.py index 2a366fd19950..7896954fada9 100755 --- a/mesonbuild/scripts/env2mfile.py +++ b/mesonbuild/scripts/env2mfile.py @@ -243,6 +243,13 @@ def dpkg_architecture_to_machine_info(output: str, options: T.Any) -> MachineInf infos.binaries[tool] = locate_path("%s-%s" % (host_arch, tool)) except ValueError: pass # optional + for tool, exe in [ + ('exe_wrapper', 'cross-exe-wrapper'), + ]: + try: + infos.binaries[tool] = locate_path("%s-%s" % (host_arch, exe)) + except ValueError: + pass try: infos.binaries['cups-config'] = locate_path("cups-config") except ValueError: diff --git a/unittests/internaltests.py b/unittests/internaltests.py index 0cf70600189f..0116f7fde1fe 100644 --- a/unittests/internaltests.py +++ b/unittests/internaltests.py @@ -1750,6 +1750,7 @@ def expected_binaries(gnu_tuple: str) -> T.Dict[str, T.List[str]]: 'cmake': ['/usr/bin/cmake'], 'pkg-config': [f'/usr/bin/{gnu_tuple}-pkg-config'], 'cups-config': ['/usr/bin/cups-config'], + 'exe_wrapper': [f'/usr/bin/{gnu_tuple}-cross-exe-wrapper'], 'g-ir-annotation-tool': [f'/usr/bin/{gnu_tuple}-g-ir-annotation-tool'], 'g-ir-compiler': [f'/usr/bin/{gnu_tuple}-g-ir-compiler'], 'g-ir-doc-tool': [f'/usr/bin/{gnu_tuple}-g-ir-doc-tool'], From 591a88b37ba1ca71cecaa9f5b78fd88fd8775bef Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 2 Oct 2024 19:27:00 +0100 Subject: [PATCH 279/302] env2mfile: Use a cross valac on Debian if possible This is functionally equivalent to the logic used to locate the cross exe_wrapper, but puts it below the "Compilers" heading rather than "Other binaries". Signed-off-by: Simon McVittie (cherry picked from commit f0a86b2b8c05c091e3fc03c2982affbd3ec7f59e) --- mesonbuild/scripts/env2mfile.py | 7 +++++++ unittests/internaltests.py | 1 + 2 files changed, 8 insertions(+) diff --git a/mesonbuild/scripts/env2mfile.py b/mesonbuild/scripts/env2mfile.py index 7896954fada9..05bd1544e7c0 100755 --- a/mesonbuild/scripts/env2mfile.py +++ b/mesonbuild/scripts/env2mfile.py @@ -250,6 +250,13 @@ def dpkg_architecture_to_machine_info(output: str, options: T.Any) -> MachineInf infos.binaries[tool] = locate_path("%s-%s" % (host_arch, exe)) except ValueError: pass + for tool, exe in [ + ('vala', 'valac'), + ]: + try: + infos.compilers[tool] = locate_path("%s-%s" % (host_arch, exe)) + except ValueError: + pass try: infos.binaries['cups-config'] = locate_path("cups-config") except ValueError: diff --git a/unittests/internaltests.py b/unittests/internaltests.py index 0116f7fde1fe..69f52a413627 100644 --- a/unittests/internaltests.py +++ b/unittests/internaltests.py @@ -1739,6 +1739,7 @@ def expected_compilers( 'cpp': [f'/usr/bin/{gnu_tuple}-g++{gcc_suffix}'], 'objc': [f'/usr/bin/{gnu_tuple}-gobjc{gcc_suffix}'], 'objcpp': [f'/usr/bin/{gnu_tuple}-gobjc++{gcc_suffix}'], + 'vala': [f'/usr/bin/{gnu_tuple}-valac'], } def expected_binaries(gnu_tuple: str) -> T.Dict[str, T.List[str]]: From 9ce23e8a199288a9b5edff91e134fe1188eb2af2 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Sat, 26 Oct 2024 20:05:35 -0700 Subject: [PATCH 280/302] modules/rust: Add support for autolib field in the Cargo.toml This adds support for parsing the new `autolib` member (https://github.com/rust-lang/cargo/pull/14591). This is a quick and easy fix, suitable for backport. A larger more involved fix will be to stop splatting out the cargo dictionaries, and instead pass the fields we know about 1 by 1, and warning the user if we come across unknown fields. Fixes: #13826 (cherry picked from commit b131b2dc76ff0b14d755b1a3bbf7ce9565f49b0d) --- mesonbuild/cargo/interpreter.py | 1 + mesonbuild/cargo/manifest.py | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/mesonbuild/cargo/interpreter.py b/mesonbuild/cargo/interpreter.py index 5f89c05ec88b..a95ee5be39be 100644 --- a/mesonbuild/cargo/interpreter.py +++ b/mesonbuild/cargo/interpreter.py @@ -147,6 +147,7 @@ class Package: publish: bool = True metadata: T.Dict[str, T.Dict[str, str]] = dataclasses.field(default_factory=dict) default_run: T.Optional[str] = None + autolib: bool = True autobins: bool = True autoexamples: bool = True autotests: bool = True diff --git a/mesonbuild/cargo/manifest.py b/mesonbuild/cargo/manifest.py index 50c048991333..95b0d4bb8cb2 100644 --- a/mesonbuild/cargo/manifest.py +++ b/mesonbuild/cargo/manifest.py @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# Copyright © 2022-2023 Intel Corporation +# Copyright © 2022-2024 Intel Corporation """Type definitions for cargo manifest files.""" @@ -33,6 +33,7 @@ 'publish': bool, 'metadata': T.Dict[str, T.Dict[str, str]], 'default-run': str, + 'autolib': bool, 'autobins': bool, 'autoexamples': bool, 'autotests': bool, @@ -65,6 +66,7 @@ class FixedPackage(TypedDict, total=False): publish: bool metadata: T.Dict[str, T.Dict[str, str]] default_run: str + autolib: bool autobins: bool autoexamples: bool autotests: bool From 68b11bb01ae57e2db471f649cf519bb66688942f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Andr=C3=A9s=20Margffoy=20Tuay?= Date: Thu, 31 Oct 2024 17:37:52 -0500 Subject: [PATCH 281/302] Enable GCC to find free-threaded python DLL library (cherry picked from commit 4ac3e7d356cfc1a6a290cd6961f01c11510c0618) --- mesonbuild/dependencies/python.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mesonbuild/dependencies/python.py b/mesonbuild/dependencies/python.py index fff4aaa9e849..326e605d8543 100644 --- a/mesonbuild/dependencies/python.py +++ b/mesonbuild/dependencies/python.py @@ -229,7 +229,10 @@ def get_windows_link_args(self, limited_api: bool) -> T.Optional[T.List[str]]: elif imp_lower == 'pypy': libpath = Path(f'libpypy{verdot}-c.dll') else: - libpath = Path(f'python{vernum}.dll') + if self.is_freethreaded: + libpath = Path(f'python{vernum}t.dll') + else: + libpath = Path(f'python{vernum}.dll') else: if self.is_freethreaded: libpath = Path('libs') / f'python{vernum}t.lib' From 60c3c145951a07b48406de641ddbd31b9f093dcd Mon Sep 17 00:00:00 2001 From: Nick <0xb000@gmail.com> Date: Mon, 4 Nov 2024 17:58:54 +0200 Subject: [PATCH 282/302] Xcode backend: only use found appleframeworksn Add a check before using an `appleframeworks` to make sure it was found. This fixes an exception in meson while encountering an optional dep for the target. (cherry picked from commit 273894d9897dc60e524506e5dbefc550184aa2cf) --- mesonbuild/backend/xcodebackend.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mesonbuild/backend/xcodebackend.py b/mesonbuild/backend/xcodebackend.py index fc490c1b5d35..31fd272b3f0b 100644 --- a/mesonbuild/backend/xcodebackend.py +++ b/mesonbuild/backend/xcodebackend.py @@ -526,7 +526,7 @@ def generate_native_frameworks_map(self) -> None: self.native_frameworks_fileref = {} for t in self.build_targets.values(): for dep in t.get_external_deps(): - if dep.name == 'appleframeworks': + if dep.name == 'appleframeworks' and dep.found(): for f in dep.frameworks: self.native_frameworks[f] = self.gen_id() self.native_frameworks_fileref[f] = self.gen_id() @@ -691,7 +691,7 @@ def generate_pbx_aggregate_target(self, objects_dict: PbxDict) -> None: def generate_pbx_build_file(self, objects_dict: PbxDict) -> None: for tname, t in self.build_targets.items(): for dep in t.get_external_deps(): - if dep.name == 'appleframeworks': + if dep.name == 'appleframeworks' and dep.found(): for f in dep.frameworks: fw_dict = PbxDict() fwkey = self.native_frameworks[f] @@ -848,7 +848,7 @@ def generate_pbx_container_item_proxy(self, objects_dict: PbxDict) -> None: def generate_pbx_file_reference(self, objects_dict: PbxDict) -> None: for tname, t in self.build_targets.items(): for dep in t.get_external_deps(): - if dep.name == 'appleframeworks': + if dep.name == 'appleframeworks' and dep.found(): for f in dep.frameworks: fw_dict = PbxDict() framework_fileref = self.native_frameworks_fileref[f] @@ -1023,7 +1023,7 @@ def generate_pbx_frameworks_buildphase(self, objects_dict: PbxDict) -> None: file_list = PbxArray() bt_dict.add_item('files', file_list) for dep in t.get_external_deps(): - if dep.name == 'appleframeworks': + if dep.name == 'appleframeworks' and dep.found(): for f in dep.frameworks: file_list.add_item(self.native_frameworks[f], f'{f}.framework in Frameworks') bt_dict.add_item('runOnlyForDeploymentPostprocessing', 0) @@ -1071,7 +1071,7 @@ def generate_pbx_group(self, objects_dict: PbxDict) -> None: for t in self.build_targets.values(): for dep in t.get_external_deps(): - if dep.name == 'appleframeworks': + if dep.name == 'appleframeworks' and dep.found(): for f in dep.frameworks: frameworks_children.add_item(self.native_frameworks_fileref[f], f) From ab1e2d9f4fc1cf928ba4eb21b92def92a4b1d24c Mon Sep 17 00:00:00 2001 From: Andrew McNulty Date: Sat, 12 Oct 2024 11:15:45 +0100 Subject: [PATCH 283/302] coverage.py: Guard use of `--html-nested` behind version check. `--html-nested` was added to gcovr in version 6.0 so passing it to versions before this will result in gcovr complaining that it doesn't recognise the argument. Added a version check to ensure that we pass a recognised argument for versions before 6.0 Fixes #13781 (cherry picked from commit 4c7226e3632704e38606839cc962b27d44cd32e3) --- mesonbuild/scripts/coverage.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mesonbuild/scripts/coverage.py b/mesonbuild/scripts/coverage.py index f01946944afe..a4dfebfb9d9b 100644 --- a/mesonbuild/scripts/coverage.py +++ b/mesonbuild/scripts/coverage.py @@ -159,9 +159,14 @@ def coverage(outputs: T.List[str], source_root: str, subproject_root: str, build htmloutdir = os.path.join(log_dir, 'coveragereport') if not os.path.isdir(htmloutdir): os.mkdir(htmloutdir) + # Use `--html-details` if gcovr version < 6.0, otherwise + # use `--html-nested`. + html_arg = '--html-details' + if mesonlib.version_compare(gcovr_version, '>=6.0'): + html_arg = '--html-nested' subprocess.check_call(gcovr_base_cmd + gcovr_config + ['--html', - '--html-nested', + html_arg, '--print-summary', '-o', os.path.join(htmloutdir, 'index.html'), ] + gcov_exe_args) From 91941be11483c0b4fd496bea24a05040a430c16d Mon Sep 17 00:00:00 2001 From: prajwal-ibm Date: Thu, 7 Nov 2024 04:06:40 -0600 Subject: [PATCH 284/302] Fix building on AIX when no project languages are used Closes #13878 (cherry picked from commit 8400083418445bfe2d36e57e0988d3f2d208cad4) --- mesonbuild/backend/ninjabackend.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index ee86c27e0b61..00061d019a8d 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -2369,7 +2369,7 @@ def generate_dynamic_link_rules(self) -> None: options = self._rsp_options(compiler) self.add_rule(NinjaRule(rule, command, args, description, **options, extra=pool)) - if self.environment.machines[for_machine].is_aix(): + if self.environment.machines[for_machine].is_aix() and complist: rule = 'AIX_LINKER{}'.format(self.get_rule_suffix(for_machine)) description = 'Archiving AIX shared library' cmdlist = compiler.get_command_to_archive_shlib() From 8780511369a6a10d04599ac2290829d978cf21bb Mon Sep 17 00:00:00 2001 From: Nick <0xb000@gmail.com> Date: Mon, 4 Nov 2024 20:43:33 +0200 Subject: [PATCH 285/302] De-duplicate BuildTarget.sources If the same source is provided by multiple dependencies it was added multiple times, as `added_sources` was only guarding against duplicates within the same source list. This was not a problem with ninja, but it triggers multiple sanity checks within xcode backend while attempting to create multiple ids for the same file. Rename `added_sources` to `seen_sources` as per reviewers request (cherry picked from commit 7b10f48d1cfbdf4c5d0f061d9da32e057ffdc460) --- mesonbuild/build.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 460ed549be92..31113feb1398 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -758,6 +758,8 @@ def __init__( self.pch: T.Dict[str, T.List[str]] = {} self.extra_args: T.DefaultDict[str, T.List[str]] = kwargs.get('language_args', defaultdict(list)) self.sources: T.List[File] = [] + # If the same source is defined multiple times, use it only once. + self.seen_sources: T.Set[File] = set() self.generated: T.List['GeneratedTypes'] = [] self.extra_files: T.List[File] = [] self.d_features: DFeatures = { @@ -880,12 +882,11 @@ def process_sourcelist(self, sources: T.List['SourceOutputs']) -> None: (static as they are only regenerated if meson itself is regenerated) 3. Sources files generated by another target or a Generator (generated) """ - added_sources: T.Set[File] = set() # If the same source is defined multiple times, use it only once. for s in sources: if isinstance(s, File): - if s not in added_sources: + if s not in self.seen_sources: self.sources.append(s) - added_sources.add(s) + self.seen_sources.add(s) elif isinstance(s, (CustomTarget, CustomTargetIndex, GeneratedList)): self.generated.append(s) From 152bddc98b8cbc89bcabb00d55afdadde6a0d22a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 20 Nov 2024 16:19:49 +0100 Subject: [PATCH 286/302] rust: fix computation of library directory Using a rustup-based toolchain fails the "rust/2 sharedlib" test for me: ./prog: error while loading shared libraries: libstd-211931512faabf29.so: cannot open shared object file: No such file or directory This happens because recent rustup places the standard library under SYSROOT/lib/rustlib/TARGET/lib. Retrieve the right directory using "--print target-libdir". This also provides a more accurate version for rustc installed in /usr. Before: $ echo $(/usr/bin/rustc --print sysroot)/lib /usr/lib After: $ /usr/bin/rustc --print target-libdir /usr/lib/rustlib/x86_64-unknown-linux-gnu/lib While at it, cache the value to avoid repeated process invocation. Signed-off-by: Paolo Bonzini (cherry picked from commit 9f3f88feed74518f406839f4935b79a45d364540) --- mesonbuild/backend/ninjabackend.py | 2 +- mesonbuild/compilers/rust.py | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 00061d019a8d..b78ad076d24b 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -2124,7 +2124,7 @@ def _link_library(libname: str, static: bool, bundle: bool = False): # ... but then add rustc's sysroot to account for rustup # installations for rpath_arg in rpath_args: - args += ['-C', 'link-arg=' + rpath_arg + ':' + os.path.join(rustc.get_sysroot(), 'lib')] + args += ['-C', 'link-arg=' + rpath_arg + ':' + rustc.get_target_libdir()] proc_macro_dylib_path = None if getattr(target, 'rust_crate_type', '') == 'proc-macro': diff --git a/mesonbuild/compilers/rust.py b/mesonbuild/compilers/rust.py index f09911db642c..02ac593842ad 100644 --- a/mesonbuild/compilers/rust.py +++ b/mesonbuild/compilers/rust.py @@ -142,11 +142,18 @@ def _native_static_libs(self, work_dir: str, source_name: str) -> None: def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: return ['--dep-info', outfile] + @functools.lru_cache(maxsize=None) def get_sysroot(self) -> str: cmd = self.get_exelist(ccache=False) + ['--print', 'sysroot'] p, stdo, stde = Popen_safe_logged(cmd) return stdo.split('\n', maxsplit=1)[0] + @functools.lru_cache(maxsize=None) + def get_target_libdir(self) -> str: + cmd = self.get_exelist(ccache=False) + ['--print', 'target-libdir'] + p, stdo, stde = Popen_safe_logged(cmd) + return stdo.split('\n', maxsplit=1)[0] + @functools.lru_cache(maxsize=None) def get_crt_static(self) -> bool: cmd = self.get_exelist(ccache=False) + ['--print', 'cfg'] From 78844d6f0e4cf5741b36f06c5b5a482ae7336231 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 20 Nov 2024 08:00:20 +0000 Subject: [PATCH 287/302] environment: Never require an exe_wrapper for native builds It is possible to run a container or chroot with one ABI on a CPU and kernel that would normally have a different ABI, most commonly by running a 32-bit container on a 64-bit CPU and kernel. When we do a native build in such an environment, the build and host architectures are both equal to the architecture of the container, and it is safe to assume that we can run executables from that architecture, because if we could not, we wouldn't be running Python successfully. Until now, we have been handling this by adding explicit special cases in `machine_info_can_run()` for each known-good combination of the detected CPU and the host architecture: every x86_64 can run x86 binaries, and every mips64 is assumed to be able to run 32-bit mips binaries. However, the equivalent would not be true on ARM systems: *most* aarch64 CPUs can run arm binaries, but not all (according to Wikipedia, ARM Cortex-A34 is an example of a purely 64-bit CPU that cannot execute 32-bit instructions). Instead, assume that if we are doing a native build (not a cross build), by definition we can run build-architecture executables, and since the host architecture is equal to the build architecture during a native build, this implies that we can run host-architecture executables too. This makes the behaviour of `need_exe_wrapper()` consistent with `meson.can_run_host_binaries()`, which in turn avoids `Compiler.run()` failing with error message "Can not run test applications in this cross environment" during native builds even though `meson.can_run_host_binaries()` has previously succeeded. Resolves: https://github.com/mesonbuild/meson/issues/13841 Signed-off-by: Simon McVittie (cherry picked from commit fd309fff248bb697498befa89c3b81049b8b2c0c) --- mesonbuild/environment.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 2621b9ca2db1..e3fa14fabbe5 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -988,6 +988,8 @@ def need_exe_wrapper(self, for_machine: MachineChoice = MachineChoice.HOST): value = self.properties[for_machine].get('needs_exe_wrapper', None) if value is not None: return value + if not self.is_cross_build(): + return False return not machine_info_can_run(self.machines[for_machine]) def get_exe_wrapper(self) -> T.Optional[ExternalProgram]: From 8f1c7e6b9717b2e27ada52dfcb1b098a80fbe0d5 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Fri, 29 Nov 2024 22:51:43 +0200 Subject: [PATCH 288/302] env2mfile: add flag to use _FOR_BUILD envvars. (cherry picked from commit 0efc33940417ed3ca80addf702fb7549eef99b69) --- mesonbuild/scripts/env2mfile.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/mesonbuild/scripts/env2mfile.py b/mesonbuild/scripts/env2mfile.py index 05bd1544e7c0..16051a871941 100755 --- a/mesonbuild/scripts/env2mfile.py +++ b/mesonbuild/scripts/env2mfile.py @@ -16,12 +16,6 @@ if T.TYPE_CHECKING: import argparse -def has_for_build() -> bool: - for cenv in envconfig.ENV_VAR_COMPILER_MAP.values(): - if os.environ.get(cenv + '_FOR_BUILD'): - return True - return False - # Note: when adding arguments, please also add them to the completion # scripts in $MESONSRC/data/shell-completions/ def add_arguments(parser: 'argparse.ArgumentParser') -> None: @@ -35,6 +29,8 @@ def add_arguments(parser: 'argparse.ArgumentParser') -> None: help='Generate a cross compilation file.') parser.add_argument('--native', default=False, action='store_true', help='Generate a native compilation file.') + parser.add_argument('--use-for-build', default=False, action='store_true', + help='Use _FOR_BUILD envvars.') parser.add_argument('--system', default=None, help='Define system for cross compilation.') parser.add_argument('--subsystem', default=None, @@ -421,12 +417,10 @@ def detect_missing_native_binaries(infos: MachineInfo) -> None: infos.binaries[toolname] = [exe] def detect_native_env(options: T.Any) -> MachineInfo: - use_for_build = has_for_build() - if use_for_build: - mlog.log('Using FOR_BUILD envvars for detection') + if options.use_for_build: + mlog.log('Using _FOR_BUILD envvars for detection (native file for use during cross compilation)') esuffix = '_FOR_BUILD' else: - mlog.log('Using regular envvars for detection.') esuffix = '' infos = detect_compilers_from_envvars(esuffix) detect_missing_native_compilers(infos) @@ -443,6 +437,8 @@ def run(options: T.Any) -> None: mlog.notice('This functionality is experimental and subject to change.') detect_cross = options.cross if detect_cross: + if options.use_for_build: + sys.exit('--use-for-build only makes sense for --native, not --cross') infos = detect_cross_env(options) write_system_info = True else: From 688e69cdd2a0fe057de2db5411e36b9133f053d8 Mon Sep 17 00:00:00 2001 From: Charles Brunet Date: Tue, 29 Oct 2024 16:51:36 -0400 Subject: [PATCH 289/302] fix generate_gir with BothLibraries dependency Co-authored-by: Xavier Claessens (cherry picked from commit d8ea5c4d8875bf198f088c603868edf66a3c7c65) --- mesonbuild/build.py | 52 ++++++++++++------- mesonbuild/interpreter/interpreter.py | 22 ++++---- mesonbuild/interpreter/interpreterobjects.py | 10 ++-- .../frameworks/38 gir both_libraries/bar.c | 7 +++ .../frameworks/38 gir both_libraries/bar.h | 1 + .../frameworks/38 gir both_libraries/foo.c | 6 +++ .../frameworks/38 gir both_libraries/foo.h | 1 + .../38 gir both_libraries/meson.build | 42 +++++++++++++++ .../38 gir both_libraries/test.json | 3 ++ 9 files changed, 111 insertions(+), 33 deletions(-) create mode 100644 test cases/frameworks/38 gir both_libraries/bar.c create mode 100644 test cases/frameworks/38 gir both_libraries/bar.h create mode 100644 test cases/frameworks/38 gir both_libraries/foo.c create mode 100644 test cases/frameworks/38 gir both_libraries/foo.h create mode 100644 test cases/frameworks/38 gir both_libraries/meson.build create mode 100644 test cases/frameworks/38 gir both_libraries/test.json diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 31113feb1398..cf71dc2a6622 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -770,6 +770,7 @@ def __init__( } self.pic = False self.pie = False + self.both_lib: T.Optional[T.Union[StaticLibrary, SharedLibrary]] = None # Track build_rpath entries so we can remove them at install time self.rpath_dirs_to_remove: T.Set[bytes] = set() self.process_sourcelist(sources) @@ -1736,16 +1737,20 @@ def process_vs_module_defs_kw(self, kwargs: T.Dict[str, T.Any]) -> None: def extract_targets_as_list(self, kwargs: T.Dict[str, T.Union[LibTypes, T.Sequence[LibTypes]]], key: T.Literal['link_with', 'link_whole']) -> T.List[LibTypes]: bl_type = self.environment.coredata.get_option(OptionKey('default_both_libraries')) if bl_type == 'auto': - bl_type = 'static' if isinstance(self, StaticLibrary) else 'shared' - - def _resolve_both_libs(lib: LibTypes) -> LibTypes: - if isinstance(lib, BothLibraries): - return lib.get(bl_type) - return lib + if isinstance(self, StaticLibrary): + bl_type = 'static' + elif isinstance(self, SharedLibrary): + bl_type = 'shared' self_libs: T.List[LibTypes] = self.link_targets if key == 'link_with' else self.link_whole_targets - lib_list = listify(kwargs.get(key, [])) + self_libs - return [_resolve_both_libs(t) for t in lib_list] + + lib_list = [] + for lib in listify(kwargs.get(key, [])) + self_libs: + if isinstance(lib, (Target, BothLibraries)): + lib_list.append(lib.get(bl_type)) + else: + lib_list.append(lib) + return lib_list def get(self, lib_type: T.Literal['static', 'shared', 'auto']) -> LibTypes: """Base case used by BothLibraries""" @@ -2200,6 +2205,14 @@ def is_linkable_target(self): def is_internal(self) -> bool: return not self.install + def set_shared(self, shared_library: SharedLibrary) -> None: + self.both_lib = shared_library + + def get(self, lib_type: T.Literal['static', 'shared', 'auto']) -> LibTypes: + if lib_type == 'shared': + return self.both_lib or self + return self + class SharedLibrary(BuildTarget): known_kwargs = known_shlib_kwargs @@ -2466,6 +2479,14 @@ def type_suffix(self): def is_linkable_target(self): return True + def set_static(self, static_library: StaticLibrary) -> None: + self.both_lib = static_library + + def get(self, lib_type: T.Literal['static', 'shared']) -> LibTypes: + if lib_type == 'static': + return self.both_lib or self + return self + # A shared library that is meant to be used with dlopen rather than linking # into something else. class SharedModule(SharedLibrary): @@ -2502,7 +2523,7 @@ def get_default_install_dir(self) -> T.Union[T.Tuple[str, str], T.Tuple[None, No return self.environment.get_shared_module_dir(), '{moduledir_shared}' class BothLibraries(SecondLevelHolder): - def __init__(self, shared: SharedLibrary, static: StaticLibrary, preferred_library: Literal['shared', 'static', 'auto']) -> None: + def __init__(self, shared: SharedLibrary, static: StaticLibrary, preferred_library: Literal['shared', 'static']) -> None: self._preferred_library = preferred_library self.shared = shared self.static = static @@ -2910,23 +2931,14 @@ class AliasTarget(RunTarget): typename = 'alias' - def __init__(self, name: str, dependencies: T.Sequence[T.Union[Target, BothLibraries]], + def __init__(self, name: str, dependencies: T.Sequence[Target], subdir: str, subproject: str, environment: environment.Environment): - super().__init__(name, [], list(self._deps_generator(dependencies)), subdir, subproject, environment) + super().__init__(name, [], dependencies, subdir, subproject, environment) def __repr__(self): repr_str = "<{0} {1}>" return repr_str.format(self.__class__.__name__, self.get_id()) - @staticmethod - def _deps_generator(dependencies: T.Sequence[T.Union[Target, BothLibraries]]) -> T.Iterator[Target]: - for dep in dependencies: - if isinstance(dep, BothLibraries): - yield dep.shared - yield dep.static - else: - yield dep - class Jar(BuildTarget): known_kwargs = known_jar_kwargs diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index 8a2e0e954af3..ac4a55e8b848 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -31,7 +31,7 @@ from ..interpreterbase import Disabler, disablerIfNotFound from ..interpreterbase import FeatureNew, FeatureDeprecated, FeatureBroken, FeatureNewKwargs from ..interpreterbase import ObjectHolder, ContextManagerObject -from ..interpreterbase import stringifyUserArguments, resolve_second_level_holders +from ..interpreterbase import stringifyUserArguments from ..modules import ExtensionModule, ModuleObject, MutableModuleObject, NewExtensionModule, NotFoundExtensionModule from ..optinterpreter import optname_regex @@ -690,7 +690,6 @@ def func_files(self, node: mparser.FunctionNode, args: T.Tuple[T.List[str]], kwa KwargInfo('version', (str, NoneType)), KwargInfo('objects', ContainerTypeInfo(list, build.ExtractedObjects), listify=True, default=[], since='1.1.0'), ) - @noSecondLevelHolderResolving def func_declare_dependency(self, node: mparser.BaseNode, args: T.List[TYPE_var], kwargs: kwtypes.FuncDeclareDependency) -> dependencies.Dependency: deps = kwargs['dependencies'] @@ -1917,15 +1916,12 @@ def func_jar(self, node: mparser.BaseNode, @permittedKwargs(known_build_target_kwargs) @typed_pos_args('build_target', str, varargs=SOURCES_VARARGS) @typed_kwargs('build_target', *BUILD_TARGET_KWS, allow_unknown=True) - @noSecondLevelHolderResolving def func_build_target(self, node: mparser.BaseNode, args: T.Tuple[str, SourcesVarargsType], kwargs: kwtypes.BuildTarget ) -> T.Union[build.Executable, build.StaticLibrary, build.SharedLibrary, build.SharedModule, build.BothLibraries, build.Jar]: target_type = kwargs['target_type'] - if target_type not in {'both_libraries', 'library'}: - args, kwargs = resolve_second_level_holders(args, kwargs) if target_type == 'executable': return self.build_target(node, args, kwargs, build.Executable) @@ -2172,13 +2168,19 @@ def func_run_target(self, node: mparser.FunctionNode, args: T.Tuple[str], @FeatureNew('alias_target', '0.52.0') @typed_pos_args('alias_target', str, varargs=(build.Target, build.BothLibraries), min_varargs=1) @noKwargs - @noSecondLevelHolderResolving def func_alias_target(self, node: mparser.BaseNode, args: T.Tuple[str, T.List[T.Union[build.Target, build.BothLibraries]]], kwargs: TYPE_kwargs) -> build.AliasTarget: name, deps = args if any(isinstance(d, build.RunTarget) for d in deps): FeatureNew.single_use('alias_target that depends on run_targets', '0.60.0', self.subproject) - tg = build.AliasTarget(name, deps, self.subdir, self.subproject, self.environment) + real_deps: T.List[build.Target] = [] + for d in deps: + if isinstance(d, build.BothLibraries): + real_deps.append(d.shared) + real_deps.append(d.static) + else: + real_deps.append(d) + tg = build.AliasTarget(name, real_deps, self.subdir, self.subproject, self.environment) self.add_target(name, tg) return tg @@ -3284,16 +3286,18 @@ def build_both_libraries(self, node: mparser.BaseNode, args: T.Tuple[str, Source # Keep only compilers used for linking static_lib.compilers = {k: v for k, v in static_lib.compilers.items() if k in compilers.clink_langs} + # Cross reference them to implement as_shared() and as_static() methods. + shared_lib.set_static(static_lib) + static_lib.set_shared(shared_lib) + return build.BothLibraries(shared_lib, static_lib, preferred_library) def build_library(self, node: mparser.BaseNode, args: T.Tuple[str, SourcesVarargsType], kwargs: kwtypes.Library): default_library = self.coredata.get_option(OptionKey('default_library', subproject=self.subproject)) assert isinstance(default_library, str), 'for mypy' if default_library == 'shared': - args, kwargs = resolve_second_level_holders(args, kwargs) return self.build_target(node, args, T.cast('kwtypes.StaticLibrary', kwargs), build.SharedLibrary) elif default_library == 'static': - args, kwargs = resolve_second_level_holders(args, kwargs) return self.build_target(node, args, T.cast('kwtypes.SharedLibrary', kwargs), build.StaticLibrary) elif default_library == 'both': return self.build_both_libraries(node, args, kwargs) diff --git a/mesonbuild/interpreter/interpreterobjects.py b/mesonbuild/interpreter/interpreterobjects.py index a919102607be..f4a2b4107ed3 100644 --- a/mesonbuild/interpreter/interpreterobjects.py +++ b/mesonbuild/interpreter/interpreterobjects.py @@ -1001,8 +1001,6 @@ class SharedLibraryHolder(BuildTargetHolder[build.SharedLibrary]): class BothLibrariesHolder(BuildTargetHolder[build.BothLibraries]): def __init__(self, libs: build.BothLibraries, interp: 'Interpreter'): - # FIXME: This build target always represents the shared library, but - # that should be configurable. super().__init__(libs, interp) self.methods.update({'get_shared_lib': self.get_shared_lib_method, 'get_static_lib': self.get_static_lib_method, @@ -1017,12 +1015,16 @@ def __repr__(self) -> str: @noPosargs @noKwargs def get_shared_lib_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> build.SharedLibrary: - return self.held_object.shared + lib = copy.copy(self.held_object.shared) + lib.both_lib = None + return lib @noPosargs @noKwargs def get_static_lib_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> build.StaticLibrary: - return self.held_object.static + lib = copy.copy(self.held_object.static) + lib.both_lib = None + return lib class SharedModuleHolder(BuildTargetHolder[build.SharedModule]): pass diff --git a/test cases/frameworks/38 gir both_libraries/bar.c b/test cases/frameworks/38 gir both_libraries/bar.c new file mode 100644 index 000000000000..4cb41f798294 --- /dev/null +++ b/test cases/frameworks/38 gir both_libraries/bar.c @@ -0,0 +1,7 @@ +#include "bar.h" +#include "foo.h" + +int bar_func(void) +{ + return foo_func() + 42; +} diff --git a/test cases/frameworks/38 gir both_libraries/bar.h b/test cases/frameworks/38 gir both_libraries/bar.h new file mode 100644 index 000000000000..d22827b837f7 --- /dev/null +++ b/test cases/frameworks/38 gir both_libraries/bar.h @@ -0,0 +1 @@ +int bar_func(void); diff --git a/test cases/frameworks/38 gir both_libraries/foo.c b/test cases/frameworks/38 gir both_libraries/foo.c new file mode 100644 index 000000000000..b88aa91dabb4 --- /dev/null +++ b/test cases/frameworks/38 gir both_libraries/foo.c @@ -0,0 +1,6 @@ +#include "foo.h" + +int foo_func(void) +{ + return 42; +} diff --git a/test cases/frameworks/38 gir both_libraries/foo.h b/test cases/frameworks/38 gir both_libraries/foo.h new file mode 100644 index 000000000000..2a0867249307 --- /dev/null +++ b/test cases/frameworks/38 gir both_libraries/foo.h @@ -0,0 +1 @@ +int foo_func(void); diff --git a/test cases/frameworks/38 gir both_libraries/meson.build b/test cases/frameworks/38 gir both_libraries/meson.build new file mode 100644 index 000000000000..cb9cdd31f3ed --- /dev/null +++ b/test cases/frameworks/38 gir both_libraries/meson.build @@ -0,0 +1,42 @@ +project('gir both libraries', 'c') + +gir = dependency('gobject-introspection-1.0', required: false) +if not gir.found() + error('MESON_SKIP_TEST gobject-introspection not found.') +endif + +if host_machine.system() == 'cygwin' + # FIXME: g-ir-scanner seems broken on cygwin: + # ERROR: can't resolve libraries to shared libraries: foo++ + error('MESON_SKIP_TEST g-ir-scanner is broken on cygwin.') +endif + +gnome = import('gnome') + +# Regression test simulating how GStreamer generate its GIRs. +# Generated gobject-introspection binaries for every GStreamer libraries must +# first call gst_init() defined in the main libgstreamer, which means they need +# to link on that lib. +# A regression caused by https://github.com/mesonbuild/meson/pull/12632 made +# Meson not link the binary generated for bar with libfoo in the case it uses +# both_libraries(). + +libfoo = both_libraries('foo', 'foo.c') +foo_gir = gnome.generate_gir(libfoo, + namespace: 'foo', + nsversion: '1.0', + sources: ['foo.c', 'foo.h'], +) +foo_dep = declare_dependency( + link_with: libfoo, + sources: foo_gir, +) + +libbar = both_libraries('bar', 'bar.c', dependencies: foo_dep) +gnome.generate_gir(libbar, + namespace: 'bar', + nsversion: '1.0', + sources: ['bar.c', 'bar.h'], + extra_args: '--add-init-section=extern void foo_func(void);foo_func();', + dependencies: foo_dep, +) diff --git a/test cases/frameworks/38 gir both_libraries/test.json b/test cases/frameworks/38 gir both_libraries/test.json new file mode 100644 index 000000000000..82ac42a293b3 --- /dev/null +++ b/test cases/frameworks/38 gir both_libraries/test.json @@ -0,0 +1,3 @@ +{ + "expect_skip_on_jobname": ["azure", "macos", "msys2", "cygwin"] +} \ No newline at end of file From 860752e7f129287c75a4e321e39a2a8e74eeaa1b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 20 Nov 2024 19:02:06 +0100 Subject: [PATCH 290/302] libgcrypt-config is no more on ubuntu-rolling (cherry picked from commit f9f69d835e01cc6467455b3ad166a7a367920304) --- test cases/frameworks/24 libgcrypt/test.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test cases/frameworks/24 libgcrypt/test.json b/test cases/frameworks/24 libgcrypt/test.json index 9c282daa86e7..4860d9e00e65 100644 --- a/test cases/frameworks/24 libgcrypt/test.json +++ b/test cases/frameworks/24 libgcrypt/test.json @@ -1,3 +1,3 @@ { - "expect_skip_on_jobname": ["arch", "azure", "cygwin", "msys2"] + "expect_skip_on_jobname": ["arch", "azure", "cygwin", "msys2", "ubuntu-rolling"] } From 65780d5449db60ce9acc24865fc1ccad4161e176 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Mon, 28 Oct 2024 14:23:24 -0700 Subject: [PATCH 291/302] run_single_test.py: Fix for symlink changes (cherry picked from commit a2b0e665bb8dbd1353311faf8af5b55113d21d96) --- run_single_test.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/run_single_test.py b/run_single_test.py index 6cc75ac17b4e..b7c294269013 100755 --- a/run_single_test.py +++ b/run_single_test.py @@ -13,10 +13,11 @@ import typing as T from mesonbuild import mlog +from mesonbuild.mesonlib import is_windows from run_tests import handle_meson_skip_test from run_project_tests import TestDef, load_test_json, run_test, BuildStep from run_project_tests import setup_commands, detect_system_compiler, detect_tools -from run_project_tests import setup_symlinks, clear_transitive_files +from run_project_tests import scan_test_data_symlinks, setup_symlinks, clear_transitive_files if T.TYPE_CHECKING: from run_project_tests import CompilerArgumentType @@ -45,6 +46,8 @@ def main() -> None: parser.add_argument('--quick', action='store_true', help='Skip some compiler and tool checking') args = T.cast('ArgumentType', parser.parse_args()) + if not is_windows(): + scan_test_data_symlinks() setup_symlinks() setup_commands(args.backend) if not args.quick: From 2f484f5b23933e7541b8a0f60e64fcba839c3795 Mon Sep 17 00:00:00 2001 From: x1z53 Date: Wed, 23 Oct 2024 00:26:49 +0300 Subject: [PATCH 292/302] msetup: Correction of the message text (cherry picked from commit 59a608878c83d82f6943def8d9be15fa49d128a7) --- mesonbuild/msetup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/msetup.py b/mesonbuild/msetup.py index 81f4af1c444f..e634c05ab5aa 100644 --- a/mesonbuild/msetup.py +++ b/mesonbuild/msetup.py @@ -165,7 +165,7 @@ def validate_dirs(self) -> T.Tuple[str, str]: if not self.options.reconfigure and not self.options.wipe: print('Directory already configured.\n\n' 'Just run your build command (e.g. ninja) and Meson will regenerate as necessary.\n' - 'Run "meson setup --reconfigure to force Meson to regenerate.\n\n' + 'Run "meson setup --reconfigure" to force Meson to regenerate.\n\n' 'If build failures persist, run "meson setup --wipe" to rebuild from scratch\n' 'using the same options as passed when configuring the build.') if self.options.cmd_line_options: From f9485fba66626a1a080dd354487feae2c6b9f355 Mon Sep 17 00:00:00 2001 From: Frank Richter Date: Mon, 4 Nov 2024 12:23:05 +0100 Subject: [PATCH 293/302] CMakeToolchain: Log output on compiler state failure (cherry picked from commit 040c8d04cc66af891e251939bd44bcc0da11a543) --- mesonbuild/cmake/toolchain.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mesonbuild/cmake/toolchain.py b/mesonbuild/cmake/toolchain.py index 43f262605922..9eb961c52bc7 100644 --- a/mesonbuild/cmake/toolchain.py +++ b/mesonbuild/cmake/toolchain.py @@ -232,10 +232,15 @@ def update_cmake_compiler_state(self) -> None: cmake_args += trace.trace_args() cmake_args += cmake_get_generator_args(self.env) cmake_args += [f'-DCMAKE_TOOLCHAIN_FILE={temp_toolchain_file.as_posix()}', '.'] - rc, _, raw_trace = self.cmakebin.call(cmake_args, build_dir=build_dir, disable_cache=True) + rc, raw_stdout, raw_trace = self.cmakebin.call(cmake_args, build_dir=build_dir, disable_cache=True) if rc != 0: mlog.warning('CMake Toolchain: Failed to determine CMake compilers state') + mlog.debug(f' -- return code: {rc}') + for line in raw_stdout.split('\n'): + mlog.debug(f' -- stdout: {line.rstrip()}') + for line in raw_trace.split('\n'): + mlog.debug(f' -- stderr: {line.rstrip()}') return # Parse output From e57145a65fafb0855be27cfc906ef5b602899cf9 Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Fri, 8 Nov 2024 16:18:57 -0500 Subject: [PATCH 294/302] mdevenv: exec directly into the program to run We don't need an extra process in the process tree (specifically the `meson devenv` process itself). Aside for the redundancy, it's actively problematic if you abort a program in the devenv by using CTRL+C, as meson itself will then emit a traceback (KeyboardInterrupt) which is quite ugly. (cherry picked from commit 1985ad19cb69f6db1d7e2e0c89fa6796782bfd43) --- mesonbuild/mdevenv.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/mesonbuild/mdevenv.py b/mesonbuild/mdevenv.py index 064cf5ed6f89..8c6ce2031d45 100644 --- a/mesonbuild/mdevenv.py +++ b/mesonbuild/mdevenv.py @@ -9,7 +9,7 @@ from pathlib import Path from . import build, minstall -from .mesonlib import (EnvironmentVariables, MesonException, is_windows, setup_vsenv, +from .mesonlib import (EnvironmentVariables, MesonException, join_args, is_windows, setup_vsenv, get_wine_shortpath, MachineChoice, relpath) from .options import OptionKey from . import mlog @@ -226,10 +226,9 @@ def run(options: argparse.Namespace) -> int: args[0] = abs_path or args[0] try: - return subprocess.call(args, close_fds=False, - env=devenv, - cwd=workdir) - except subprocess.CalledProcessError as e: - return e.returncode + os.chdir(workdir) + os.execvpe(args[0], args, env=devenv) except FileNotFoundError: raise MesonException(f'Command not found: {args[0]}') + except OSError as e: + raise MesonException(f'Command `{join_args(args)}` failed to execute: {e}') From 19a68dcae0e33189fb743fefa3493e68669821a5 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Mon, 18 Nov 2024 09:18:40 -0800 Subject: [PATCH 295/302] tests: HDF5 no longer skips on MacOS The `-show` switch was added into the cmake-generated scripts in HDFGroup/hdf5@6fa09bd and backported to 1.14.5. (cherry picked from commit 33376efc4c1daf53c5509ea5fa7611b18d10416a) --- test cases/frameworks/25 hdf5/test.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test cases/frameworks/25 hdf5/test.json b/test cases/frameworks/25 hdf5/test.json index 590d4bc20283..2448f57425d7 100644 --- a/test cases/frameworks/25 hdf5/test.json +++ b/test cases/frameworks/25 hdf5/test.json @@ -3,7 +3,7 @@ "options": { "method": [ { "val": "pkg-config", "expect_skip_on_jobname": ["linux-gentoo-gcc"] }, - { "val": "config-tool", "expect_skip_on_jobname": ["macos"] } + { "val": "config-tool" } ] } }, From a686faa9490e5841ccfc5379dd810a6411c1e063 Mon Sep 17 00:00:00 2001 From: Luca Bacci Date: Wed, 20 Nov 2024 10:00:51 +0100 Subject: [PATCH 296/302] run_single_test.py: skip setup_symlinks() call on Windows (cherry picked from commit 69af44d50ef6fdceefff08446d915cc6b1fe2d50) --- run_single_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run_single_test.py b/run_single_test.py index b7c294269013..23b175641b50 100755 --- a/run_single_test.py +++ b/run_single_test.py @@ -48,7 +48,7 @@ def main() -> None: if not is_windows(): scan_test_data_symlinks() - setup_symlinks() + setup_symlinks() setup_commands(args.backend) if not args.quick: detect_system_compiler(args) From 228e54797db8d016225179adab070eab153c002b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 9 Dec 2024 15:28:45 +0100 Subject: [PATCH 297/302] modernize Rust template Signed-off-by: Paolo Bonzini (cherry picked from commit 8578a995ae45ff737e25b8ff9d8ab0abe8d3b64c) --- mesonbuild/templates/rusttemplates.py | 27 +++++++++++++++------------ mesonbuild/templates/sampleimpl.py | 12 +++++++----- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/mesonbuild/templates/rusttemplates.py b/mesonbuild/templates/rusttemplates.py index 5bb7e4c19006..1dbf5b614115 100644 --- a/mesonbuild/templates/rusttemplates.py +++ b/mesonbuild/templates/rusttemplates.py @@ -20,25 +20,28 @@ pub fn {function_name}() -> i32 {{ return internal_function(); }} -''' -lib_rust_test_template = '''extern crate {crate_file}; +#[cfg(test)] +mod tests {{ + use super::*; -fn main() {{ - println!("printing: {{}}", {crate_file}::{function_name}()); + #[test] + fn test_function() {{ + assert_eq!({function_name}(), 0); + }} }} ''' lib_rust_meson_template = '''project('{project_name}', 'rust', - version : '{version}', - default_options : ['warning_level=3']) + version : '{version}', meson_version: '>=1.3.0', + default_options : ['rust_std=2021', 'warning_level=3']) + +rust = import('rust') shlib = static_library('{lib_name}', '{source_file}', install : true) -test_exe = executable('{test_exe_name}', '{test_source_file}', - link_with : shlib) -test('{test_name}', test_exe) +rust.test('{test_name}', shlib) # Make this library usable as a Meson subproject. {ltoken}_dep = declare_dependency( @@ -54,8 +57,8 @@ ''' hello_rust_meson_template = '''project('{project_name}', 'rust', - version : '{version}', - default_options : ['warning_level=3']) + version : '{version}', meson_version: '>=1.3.0', + default_options : ['rust_std=2021', 'warning_level=3']) exe = executable('{exe_name}', '{source_name}', install : true) @@ -70,7 +73,7 @@ class RustProject(FileImpl): exe_template = hello_rust_template exe_meson_template = hello_rust_meson_template lib_template = lib_rust_template - lib_test_template = lib_rust_test_template + lib_test_template = None lib_meson_template = lib_rust_meson_template def lib_kwargs(self) -> T.Dict[str, str]: diff --git a/mesonbuild/templates/sampleimpl.py b/mesonbuild/templates/sampleimpl.py index 570a370b8e3f..c222a1bf9aa7 100644 --- a/mesonbuild/templates/sampleimpl.py +++ b/mesonbuild/templates/sampleimpl.py @@ -41,7 +41,7 @@ def lib_template(self) -> str: pass @abc.abstractproperty - def lib_test_template(self) -> str: + def lib_test_template(self) -> T.Optional[str]: pass @abc.abstractproperty @@ -85,8 +85,9 @@ def create_library(self) -> None: } with open(lib_name, 'w', encoding='utf-8') as f: f.write(self.lib_template.format(**kwargs)) - with open(test_name, 'w', encoding='utf-8') as f: - f.write(self.lib_test_template.format(**kwargs)) + if self.lib_test_template: + with open(test_name, 'w', encoding='utf-8') as f: + f.write(self.lib_test_template.format(**kwargs)) with open('meson.build', 'w', encoding='utf-8') as f: f.write(self.lib_meson_template.format(**kwargs)) @@ -132,8 +133,9 @@ def create_library(self) -> None: kwargs = self.lib_kwargs() with open(lib_name, 'w', encoding='utf-8') as f: f.write(self.lib_template.format(**kwargs)) - with open(test_name, 'w', encoding='utf-8') as f: - f.write(self.lib_test_template.format(**kwargs)) + if self.lib_test_template: + with open(test_name, 'w', encoding='utf-8') as f: + f.write(self.lib_test_template.format(**kwargs)) with open('meson.build', 'w', encoding='utf-8') as f: f.write(self.lib_meson_template.format(**kwargs)) From 2954329691adeb99252a887ad75dfeea58fbc845 Mon Sep 17 00:00:00 2001 From: Sam James Date: Tue, 10 Dec 2024 03:57:40 +0000 Subject: [PATCH 298/302] ci: fix Ubuntu Bionic job Do the same as https://github.com/pytorch/test-infra/pull/5959 and download an old nodejs to keep Ubuntu Bionic working. Bug: https://github.com/actions/checkout/issues/1809 Bug: https://github.com/actions/runner/issues/3373 (cherry picked from commit 54cab0910e26e82f5d4cd7c087781ed7826d649a) --- .github/workflows/os_comp.yml | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/.github/workflows/os_comp.yml b/.github/workflows/os_comp.yml index 0830a05e5836..0912a750a76b 100644 --- a/.github/workflows/os_comp.yml +++ b/.github/workflows/os_comp.yml @@ -26,12 +26,6 @@ on: - ".github/workflows/os_comp.yml" - "run*tests.py" -# make GHA actions use node16 which still works with bionic -# See https://github.blog/changelog/2024-03-07-github-actions-all-actions-will-run-on-node20-instead-of-node16-by-default/ -# Unclear how long this will work though -env: - ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true - permissions: contents: read @@ -49,13 +43,24 @@ jobs: - { name: Gentoo, id: gentoo } - { name: OpenSUSE, id: opensuse } - { name: Ubuntu Bionic, id: bionic } - container: mesonbuild/${{ matrix.cfg.id }}:latest + container: + image: mesonbuild/${{ matrix.cfg.id }}:latest + volumes: + - ${{ matrix.cfg.id == 'bionic' && '/node20217:/node20217:rw,rshared' || ' ' }} + - ${{ matrix.cfg.id == 'bionic' && '/node20217:/__e/node20:ro,rshared' || ' ' }} env: MESON_CI_JOBNAME: linux-${{ matrix.cfg.id }}-gcc steps: - # Need v3 because of bionic - - uses: actions/checkout@v3 + - name: install nodejs20glibc2.17 + if: ${{ matrix.cfg.id == 'bionic' }} + run: | + apt install curl -y + curl -LO https://unofficial-builds.nodejs.org/download/release/v20.9.0/node-v20.9.0-linux-x64-glibc-217.tar.xz + tar -xf node-v20.9.0-linux-x64-glibc-217.tar.xz --strip-components 1 -C /node20217 + ldd /__e/node20/bin/node + - uses: actions/checkout@v4 + - name: Run tests # All environment variables are stored inside the docker image in /ci/env_vars.sh # They are defined in the `env` section in each image.json. CI_ARGS should be set From df403263952f89b2178ae07a4461fd6c60762531 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Mon, 16 Dec 2024 13:29:15 +0200 Subject: [PATCH 299/302] Handle top level options set in subprojects. Closes #13847. (cherry picked from commit 16cf71f0512ec26633b6d21e9c5b28613c36596b) --- mesonbuild/coredata.py | 17 ++++++++++++++--- test cases/unit/123 pkgsubproj/meson.build | 3 +++ .../123 pkgsubproj/subprojects/sub/meson.build | 1 + unittests/linuxliketests.py | 4 ++++ 4 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 test cases/unit/123 pkgsubproj/meson.build create mode 100644 test cases/unit/123 pkgsubproj/subprojects/sub/meson.build diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 963aedb402d4..e748a54270b6 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -658,9 +658,20 @@ def set_options(self, opts_to_set: T.Dict[OptionKey, T.Any], subproject: str = ' elif k.machine != MachineChoice.BUILD and not self.optstore.is_compiler_option(k): unknown_options.append(k) if unknown_options: - unknown_options_str = ', '.join(sorted(str(s) for s in unknown_options)) - sub = f'In subproject {subproject}: ' if subproject else '' - raise MesonException(f'{sub}Unknown options: "{unknown_options_str}"') + if subproject: + # The subproject may have top-level options that should be used + # when it is not a subproject. Ignore those for now. With option + # refactor they will get per-subproject values. + really_unknown = [] + for uo in unknown_options: + topkey = uo.evolve(subproject='') + if topkey not in self.optstore: + really_unknown.append(uo) + unknown_options = really_unknown + if unknown_options: + unknown_options_str = ', '.join(sorted(str(s) for s in unknown_options)) + sub = f'In subproject {subproject}: ' if subproject else '' + raise MesonException(f'{sub}Unknown options: "{unknown_options_str}"') if not self.is_cross_build(): dirty |= self.copy_build_options_from_regular_ones() diff --git a/test cases/unit/123 pkgsubproj/meson.build b/test cases/unit/123 pkgsubproj/meson.build new file mode 100644 index 000000000000..b4cf89fa0b6d --- /dev/null +++ b/test cases/unit/123 pkgsubproj/meson.build @@ -0,0 +1,3 @@ +project('pkg_opt_test') + +subproject('sub') diff --git a/test cases/unit/123 pkgsubproj/subprojects/sub/meson.build b/test cases/unit/123 pkgsubproj/subprojects/sub/meson.build new file mode 100644 index 000000000000..99622b681cdd --- /dev/null +++ b/test cases/unit/123 pkgsubproj/subprojects/sub/meson.build @@ -0,0 +1 @@ +project('subproject', default_options: 'pkgconfig.relocatable=true') diff --git a/unittests/linuxliketests.py b/unittests/linuxliketests.py index 3ac98076095c..55e83750af34 100644 --- a/unittests/linuxliketests.py +++ b/unittests/linuxliketests.py @@ -1827,3 +1827,7 @@ def test_complex_link_cases(self): self.assertIn('build t9-e1: c_LINKER t9-e1.p/main.c.o | libt9-s1.a libt9-s2.a libt9-s3.a\n', content) self.assertIn('build t12-e1: c_LINKER t12-e1.p/main.c.o | libt12-s1.a libt12-s2.a libt12-s3.a\n', content) self.assertIn('build t13-e1: c_LINKER t13-e1.p/main.c.o | libt12-s1.a libt13-s3.a\n', content) + + def test_top_options_in_sp(self): + testdir = os.path.join(self.unit_test_dir, '123 pkgsubproj') + self.init(testdir) From 2d4f4f4105b3841a4f50e1f712af6fc42400537d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Manuel=20J=C3=A1quez=20Leal?= Date: Mon, 16 Dec 2024 17:58:20 +0100 Subject: [PATCH 300/302] dependencies: support old vulkan SDK version In old versions of Vulkan SDK, VK_SDK_PATH environment variable was used instead of VULKAN_SDK. This patch check both environment variables is fallback mode. (cherry picked from commit bcb605201aba66343a9ff16d716454295a7a41c0) --- mesonbuild/dependencies/ui.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/dependencies/ui.py b/mesonbuild/dependencies/ui.py index d88af7945c7c..7adac5e75723 100644 --- a/mesonbuild/dependencies/ui.py +++ b/mesonbuild/dependencies/ui.py @@ -189,7 +189,7 @@ def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T. super().__init__(name, environment, kwargs, language=language) try: - self.vulkan_sdk = os.environ['VULKAN_SDK'] + self.vulkan_sdk = os.environ.get('VULKAN_SDK', os.environ['VK_SDK_PATH']) if not os.path.isabs(self.vulkan_sdk): raise DependencyException('VULKAN_SDK must be an absolute path.') except KeyError: From 98a2951c9bea3094a1b541530b68286fc0119173 Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Sun, 15 Dec 2024 17:43:34 -0500 Subject: [PATCH 301/302] Bump versions to 1.6.1 for release --- man/meson.1 | 2 +- mesonbuild/coredata.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/man/meson.1 b/man/meson.1 index 41917a97db30..38aff57d23db 100644 --- a/man/meson.1 +++ b/man/meson.1 @@ -1,4 +1,4 @@ -.TH MESON "1" "October 2024" "meson 1.6.0" "User Commands" +.TH MESON "1" "December 2024" "meson 1.6.1" "User Commands" .SH NAME meson - a high productivity build system .SH DESCRIPTION diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index e748a54270b6..84c352199bfd 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -74,7 +74,7 @@ class SharedCMDOptions(Protocol): # # Pip requires that RCs are named like this: '0.1.0.rc1' # But the corresponding Git tag needs to be '0.1.0rc1' -version = '1.6.0' +version = '1.6.1' # The next stable version when we are in dev. This is used to allow projects to # require meson version >=1.2.0 when using 1.1.99. FeatureNew won't warn when From 6139cf316386cc51b33124229d407f7e97b0d6c5 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Tue, 29 Apr 2025 08:24:46 +0200 Subject: [PATCH 302/302] Resolve an issue with OptionKey having been moved --- mesonbuild/dependencies/blas_lapack.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mesonbuild/dependencies/blas_lapack.py b/mesonbuild/dependencies/blas_lapack.py index 3bd4ae8425bd..28e673223e18 100644 --- a/mesonbuild/dependencies/blas_lapack.py +++ b/mesonbuild/dependencies/blas_lapack.py @@ -23,7 +23,8 @@ from .. import mlog from .. import mesonlib -from ..mesonlib import MachineChoice, OptionKey +from ..mesonlib import MachineChoice +from ..options import OptionKey from .base import DependencyMethods, SystemDependency from .cmake import CMakeDependency