Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
/.cproject
/.idea
/.vscode

./pyrightconfig.json
__pycache__
/.coverage/
/.coveragerc
Expand Down
1 change: 1 addition & 0 deletions ci/ciimage/ubuntu-rolling/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ pkgs=(
itstool
openjdk-11-jre
jq
npm
)

sed -i '/^Types: deb/s/deb/deb deb-src/' /etc/apt/sources.list.d/ubuntu.sources
Expand Down
184 changes: 157 additions & 27 deletions mesonbuild/backend/ninjabackend.py

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions mesonbuild/compilers/cpp.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@ def get_options(self) -> 'MutableKeyedOptionDictType':
})
return opts

def get_cpp20_module_bmi_extension(self) -> str:
raise MesonException("Your compiler does not support 'import std' feature or it has not been implemented")

class _StdCPPLibMixin(CompilerMixinBase):

Expand Down Expand Up @@ -259,6 +261,13 @@ def get_options(self) -> 'MutableKeyedOptionDictType':
self.make_option_name(key),
'Standard Win libraries to link against',
gnu_winlibs)

if version_compare(self.version, '>=17'):
key = self.form_compileropt_key('importstd')
opts[key] = options.UserComboOption(self.make_option_name(key),
'Use #import std.',
'false',
choices=['false', 'true'])
return opts

def get_option_compile_args(self, target: 'BuildTarget', subproject: T.Optional[str] = None) -> T.List[str]:
Expand Down Expand Up @@ -332,6 +341,8 @@ def get_cpp_modules_args(self) -> T.List[str]:
# Although -fmodules-ts is removed in LLVM 17, we keep this in for compatibility with old compilers.
return ['-fmodules', '-fmodules-ts']

def get_cpp20_module_bmi_extension(self) -> str:
return '.pcm'

class ArmLtdClangCPPCompiler(ClangCPPCompiler):

Expand Down
144 changes: 144 additions & 0 deletions mesonbuild/scripts/depscanaccumulate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
from __future__ import annotations

from collections import defaultdict
from dataclasses import dataclass
import json
import os
import subprocess as sp
import sys
import typing as T
import shutil
from ..mesonlib import MesonException

if sys.version_info >= (3, 10):
ModuleName: T.TypeAlias = str
ObjectFile: T.TypeAlias = str
else:
ModuleName = str
ObjectFile = str

@dataclass(frozen=True)
class ModuleProviderInfo:
logical_name: ModuleName
source_path: str
is_interface: bool = False

class CppDependenciesScanner:
pass

def normalize_filename(fname: str) -> str:
return fname.replace(':', '-')

class DynDepRule:
def __init__(self, out: str, imp_outs: T.Optional[T.List[str]], imp_ins: T.List[str]) -> None:
self.output = [f'build {out}']
if imp_outs:
imp_out_str = " ".join([normalize_filename(o) for o in imp_outs])
self.output.append(f" | {imp_out_str}")
self.output.append(": dyndep")
if imp_ins:
imp_ins_str = " ".join([normalize_filename(inf) for inf in imp_ins])
self.output.append(" | " + imp_ins_str)
self.output_str = "".join(self.output) + "\n"

def __str__(self) -> str:
return self.output_str

class ClangDependencyScanner(CppDependenciesScanner):
def __init__(self, compilation_db_file: str, json_output_file: str, dd_output_file: str = 'deps.dd', cpp_compiler: str = 'clang++') -> None:
self.compilation_db_file = compilation_db_file
self.json_output_file = json_output_file
self.dd_output_file = dd_output_file
which_result = shutil.which(cpp_compiler)
assert which_result is not None, f'Could not find {cpp_compiler} in PATH'
self.scan_deps = shutil.which('clang-scan-deps')
if not self.scan_deps:
for ver in range(25, 14, -1):
found = shutil.which(f'clang-scan-deps-{ver}')
if found:
self.scan_deps = found
break
if not self.scan_deps:
raise MesonException('Could not find clang-scan-deps')

def scan(self) -> int:
try:
with open(self.compilation_db_file, 'r', encoding='utf-8') as f:
compile_commands = json.load(f)

cpp_extensions = {'.cpp', '.cc', '.cxx', '.c++', '.cppm', '.C'}
cpp_commands = [cmd for cmd in compile_commands
if os.path.splitext(cmd['file'])[1] in cpp_extensions]

for cmd in cpp_commands:
args = cmd['command'].split()
filtered_args = []
skip_next = False
for arg in args:
if skip_next:
skip_next = False
continue
if arg.startswith('-fprebuilt-module-path') or arg.startswith('-include-pch'):
continue
if arg == '-include-pch':
skip_next = True
continue
filtered_args.append(arg)
cmd['command'] = ' '.join(filtered_args)
filtered_db = self.compilation_db_file + '.filtered.json'
with open(filtered_db, 'w', encoding='utf-8') as f:
json.dump(cpp_commands, f)

r = sp.run(
[
str(self.scan_deps),
"-format=p1689",
"-compilation-database",
filtered_db,
],
capture_output=True,
)

if r.returncode != 0:
print(r.stderr)
raise sp.SubprocessError("Failed to run command")
with open(self.json_output_file, 'w', encoding='utf-8') as f:
f.write(r.stdout.decode('utf-8'))
dependencies_info = json.loads(r.stdout)
all_deps_per_objfile = self.generate_dependencies(dependencies_info["rules"])
self.generate_dd_file(all_deps_per_objfile)
return 0
except sp.SubprocessError:
return 1

def generate_dd_file(self, deps_per_object_file: T.Dict[str, T.Tuple[T.Set[str], T.Set[ModuleProviderInfo]]]) -> None:
with open(self.dd_output_file, "w", encoding='utf-8') as f:
f.write('ninja_dyndep_version = 1\n')
for obj, reqprov in deps_per_object_file.items():
requires, provides = reqprov
dd = DynDepRule(obj, None, [r + '.pcm' for r in requires])
f.write(str(dd))

def generate_dependencies(self, rules: T.List[T.Any]) -> T.Dict[str, T.Tuple[T.Set[str], T.Set[ModuleProviderInfo]]]:
all_entries: T.Dict[str, T.Tuple[T.Set[str], T.Set[ModuleProviderInfo]]] = defaultdict(lambda: (set(), set()))
for r in rules:
obj_processed = r["primary-output"]
all_entries[obj_processed] = (set(), set())
for req in r.get("requires", []):
all_entries[obj_processed][0].add(req["logical-name"])
for prov in r.get("provides", []):
all_entries[obj_processed][1].add(ModuleProviderInfo(
logical_name=prov["logical-name"],
source_path=prov["source-path"],
is_interface=prov.get('is-interface', False)))
return all_entries

def run(args: T.List[str]) -> int:
assert len(args) >= 3, 'Expected <compilation_db> <json_output> <dd_output> [cpp_compiler] arguments'
comp_db_path, json_output_path, dd_output = args[:3]
cpp = args[3] if len(args) > 3 else 'clang++'
scanner = ClangDependencyScanner(comp_db_path, json_output_path, dd_output, cpp)
return scanner.scan()

if __name__ == '__main__':
run(sys.argv[1:])
2 changes: 2 additions & 0 deletions test cases/common/283 wrap override/subprojects/subsub.wrap
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[wrap-redirect]
filename = sub/subprojects/subsub.wrap
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0fd8007dd44a1a5eb5c01af4c138f0993c6cb44da194b36db04484212eff591b
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
project('subsubsub')

meson.override_dependency('subsubsub', declare_dependency())
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[wrap-redirect]
filename = sub_implicit/subprojects/subsub/subprojects/subsubsub.wrap
11 changes: 10 additions & 1 deletion unittests/allplatformstests.py
Original file line number Diff line number Diff line change
Expand Up @@ -1291,7 +1291,8 @@ def test_always_prefer_c_compiler_for_asm(self):
for cmd in self.get_compdb():
# Get compiler
split = split_args(cmd['command'])
if split[0] in ('ccache', 'sccache'):
# Use basename to handle absolute paths like /usr/bin/ccache
if os.path.basename(split[0]) in ('ccache', 'sccache'):
compiler = split[1]
else:
compiler = split[0]
Expand Down Expand Up @@ -3104,6 +3105,14 @@ def test_pkg_config_libdir(self):
@skipIf(is_osx(), 'Not implemented for Darwin yet')
@skipIf(is_windows(), 'POSIX only')
def test_python_build_config_extensions(self):
prefix = sysconfig.get_config_var("prefix")
if prefix != "/usr" and prefix != "/usr/local":
raise unittest.SkipTest(
f'Skipping test because python ({sys.executable}) is a non-system installation'
)
if shutil.which('lld'):
raise unittest.SkipTest(f'Skipping test because python is built with lld')
# I will look into this in detail later
testdir = os.path.join(self.unit_test_dir,
'126 python extension')

Expand Down
3 changes: 3 additions & 0 deletions unittests/machinefiletests.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,9 @@ def test_config_tool_dep(self):
# Do the skip at this level to avoid screwing up the cache
if mesonbuild.envconfig.detect_msys2_arch():
raise SkipTest('Skipped due to problems with LLVM on MSYS2')
llvm_config = shutil.which('llvm-config')
if not llvm_config or not llvm_config.startswith(('/usr', '/bin', '/local')):
raise SkipTest('llvm-config is not a system installation')
self._simple_test('config_dep', 'llvm-config')

def test_python3_module(self):
Expand Down
Loading