aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild
diff options
context:
space:
mode:
authorJussi Pakkanen <jpakkane@gmail.com>2023-06-27 23:57:13 +0300
committerGitHub <noreply@github.com>2023-06-27 23:57:13 +0300
commita4fb8dcc4111575c670c384e52bf1abb119879b9 (patch)
treebdf995d017f7452d7b96f17829d022a208243aba /mesonbuild
parent8946bc05f7f9cdd16dce3613c481a66f7835fc7f (diff)
parent6bfb47a455af60dc975e21dd82943d5baa2bea83 (diff)
downloadmeson-a4fb8dcc4111575c670c384e52bf1abb119879b9.zip
meson-a4fb8dcc4111575c670c384e52bf1abb119879b9.tar.gz
meson-a4fb8dcc4111575c670c384e52bf1abb119879b9.tar.bz2
Merge pull request #11902 from dcbaker/submit/rust-module-enhancements
Rust module enhancements for mesa
Diffstat (limited to 'mesonbuild')
-rw-r--r--mesonbuild/backend/ninjabackend.py60
-rw-r--r--mesonbuild/build.py31
-rw-r--r--mesonbuild/envconfig.py6
-rw-r--r--mesonbuild/modules/rust.py29
4 files changed, 108 insertions, 18 deletions
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index 29cc8c6..ba614fd 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -1948,6 +1948,49 @@ class NinjaBackend(backends.Backend):
args += output
linkdirs = mesonlib.OrderedSet()
external_deps = target.external_deps.copy()
+
+ # Have we already injected msvc-crt args?
+ #
+ # If we don't have A C, C++, or Fortran compiler that is
+ # VisualStudioLike treat this as if we've already injected them
+ #
+ # We handle this here rather than in the rust compiler because in
+ # general we don't want to link rust targets to a non-default crt.
+ # However, because of the way that MSCRTs work you can only link to one
+ # per target, so if A links to the debug one, and B links to the normal
+ # one you can't link A and B. Rust is hardcoded to the default one,
+ # so if we compile C/C++ code and link against a non-default MSCRT then
+ # linking will fail. We can work around this by injecting MSCRT link
+ # arguments early in the rustc command line
+ # https://github.com/rust-lang/rust/issues/39016
+ crt_args_injected = not any(x is not None and x.get_argument_syntax() == 'msvc' for x in
+ (self.environment.coredata.compilers[target.for_machine].get(l)
+ for l in ['c', 'cpp', 'fortran']))
+
+ crt_link_args: T.List[str] = []
+ try:
+ buildtype = self.environment.coredata.options[OptionKey('buildtype')].value
+ crt = self.environment.coredata.options[OptionKey('b_vscrt')].value
+ is_debug = buildtype == 'debug'
+
+ if crt == 'from_buildtype':
+ crt = 'mdd' if is_debug else 'md'
+ elif crt == 'static_from_buildtype':
+ crt = 'mtd' if is_debug else 'mt'
+
+ if crt == 'mdd':
+ crt_link_args = ['-l', 'static=msvcrtd']
+ elif crt == 'md':
+ # this is the default, no need to inject anything
+ crt_args_injected = True
+ elif crt == 'mtd':
+ crt_link_args = ['-l', 'static=libcmtd']
+ elif crt == 'mt':
+ crt_link_args = ['-l', 'static=libcmt']
+
+ except KeyError:
+ crt_args_injected = True
+
# TODO: we likely need to use verbatim to handle name_prefix and name_suffix
for d in target.link_targets:
linkdirs.add(d.subdir)
@@ -1961,7 +2004,13 @@ class NinjaBackend(backends.Backend):
d_name = self._get_rust_dependency_name(target, d)
args += ['--extern', '{}={}'.format(d_name, os.path.join(d.subdir, d.filename))]
project_deps.append(RustDep(d_name, self.rust_crates[d.name].order))
- elif isinstance(d, build.StaticLibrary):
+ continue
+
+ if not crt_args_injected and not {'c', 'cpp', 'fortran'}.isdisjoint(d.compilers):
+ args += crt_link_args
+ crt_args_injected = True
+
+ if isinstance(d, build.StaticLibrary):
# Rustc doesn't follow Meson's convention that static libraries
# are called .a, and import libraries are .lib, so we have to
# manually handle that.
@@ -2001,6 +2050,10 @@ class NinjaBackend(backends.Backend):
args += ['--extern', '{}={}'.format(d_name, os.path.join(d.subdir, d.filename))]
project_deps.append(RustDep(d_name, self.rust_crates[d.name].order))
else:
+ if not crt_args_injected and not {'c', 'cpp', 'fortran'}.isdisjoint(d.compilers):
+ crt_args_injected = True
+ crt_args_injected = True
+
if rustc.linker.id in {'link', 'lld-link'}:
if verbatim:
# If we can use the verbatim modifier, then everything is great
@@ -2045,6 +2098,11 @@ class NinjaBackend(backends.Backend):
if d == '':
d = '.'
args += ['-L', d]
+
+ # Because of the way rustc links, this must come after any potential
+ # library need to link with their stdlibs (C++ and Fortran, for example)
+ args.extend(target.get_used_stdlib_args('rust'))
+
target_deps = target.get_dependencies()
has_shared_deps = any(isinstance(dep, build.SharedLibrary) for dep in target_deps)
has_rust_shared_deps = any(dep.uses_rust()
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index b952598..1ecab0d 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -698,6 +698,15 @@ class BuildTarget(Target):
install_dir: T.List[T.Union[str, Literal[False]]]
+ # This set contains all the languages a linker can link natively
+ # without extra flags. For instance, nvcc (cuda) can link C++
+ # without injecting -lc++/-lstdc++, see
+ # https://github.com/mesonbuild/meson/issues/10570
+ _MASK_LANGS: T.FrozenSet[T.Tuple[str, str]] = frozenset([
+ # (language, linker)
+ ('cpp', 'cuda'),
+ ])
+
def __init__(
self,
name: str,
@@ -1579,14 +1588,6 @@ You probably should put it in link_with instead.''')
# Languages used by dependencies
dep_langs = self.get_langs_used_by_deps()
- # This set contains all the languages a linker can link natively
- # without extra flags. For instance, nvcc (cuda) can link C++
- # without injecting -lc++/-lstdc++, see
- # https://github.com/mesonbuild/meson/issues/10570
- MASK_LANGS = frozenset([
- # (language, linker)
- ('cpp', 'cuda'),
- ])
# Pick a compiler based on the language priority-order
for l in clink_langs:
if l in self.compilers or l in dep_langs:
@@ -1597,10 +1598,7 @@ You probably should put it in link_with instead.''')
f'Could not get a dynamic linker for build target {self.name!r}. '
f'Requires a linker for language "{l}", but that is not '
'a project language.')
- stdlib_args: T.List[str] = []
- for dl in itertools.chain(self.compilers, dep_langs):
- if dl != linker.language and (dl, linker.language) not in MASK_LANGS:
- stdlib_args += all_compilers[dl].language_stdlib_only_link_flags(self.environment)
+ stdlib_args: T.List[str] = self.get_used_stdlib_args(linker.language)
# Type of var 'linker' is Compiler.
# Pretty hard to fix because the return value is passed everywhere
return linker, stdlib_args
@@ -1616,6 +1614,15 @@ You probably should put it in link_with instead.''')
raise AssertionError(f'Could not get a dynamic linker for build target {self.name!r}')
+ def get_used_stdlib_args(self, link_language: str) -> T.List[str]:
+ all_compilers = self.environment.coredata.compilers[self.for_machine]
+ all_langs = set(all_compilers).union(self.get_langs_used_by_deps())
+ stdlib_args: T.List[str] = []
+ for dl in all_langs:
+ if dl != link_language and (dl, link_language) not in self._MASK_LANGS:
+ stdlib_args.extend(all_compilers[dl].language_stdlib_only_link_flags(self.environment))
+ return stdlib_args
+
def uses_rust(self) -> bool:
return 'rust' in self.compilers
diff --git a/mesonbuild/envconfig.py b/mesonbuild/envconfig.py
index 24c1855..7e0c567 100644
--- a/mesonbuild/envconfig.py
+++ b/mesonbuild/envconfig.py
@@ -237,6 +237,12 @@ class Properties:
value = T.cast('T.Optional[str]', self.properties.get('java_home'))
return Path(value) if value else None
+ def get_bindgen_clang_args(self) -> T.List[str]:
+ value = mesonlib.listify(self.properties.get('bindgen_clang_arguments', []))
+ if not all(isinstance(v, str) for v in value):
+ raise EnvironmentException('bindgen_clang_arguments must be a string or an array of strings')
+ return T.cast('T.List[str]', value)
+
def __eq__(self, other: object) -> bool:
if isinstance(other, type(self)):
return self.properties == other.properties
diff --git a/mesonbuild/modules/rust.py b/mesonbuild/modules/rust.py
index bf1fd1d..92b0470 100644
--- a/mesonbuild/modules/rust.py
+++ b/mesonbuild/modules/rust.py
@@ -1,4 +1,4 @@
-# Copyright © 2020-2022 Intel Corporation
+# Copyright © 2020-2023 Intel Corporation
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -18,15 +18,16 @@ import typing as T
from . import ExtensionModule, ModuleReturnValue, ModuleInfo
from .. import mlog
-from ..build import BothLibraries, BuildTarget, CustomTargetIndex, Executable, ExtractedObjects, GeneratedList, IncludeDirs, CustomTarget, StructuredSources
+from ..build import BothLibraries, BuildTarget, CustomTargetIndex, Executable, ExtractedObjects, GeneratedList, IncludeDirs, CustomTarget, InvalidArguments, Jar, StructuredSources
from ..compilers.compilers import are_asserts_disabled
from ..dependencies import Dependency, ExternalLibrary
-from ..interpreter.type_checking import DEPENDENCIES_KW, TEST_KWS, OUTPUT_KW, INCLUDE_DIRECTORIES
+from ..interpreter.type_checking import DEPENDENCIES_KW, LINK_WITH_KW, TEST_KWS, OUTPUT_KW, INCLUDE_DIRECTORIES
from ..interpreterbase import ContainerTypeInfo, InterpreterException, KwargInfo, typed_kwargs, typed_pos_args, noPosargs
from ..mesonlib import File
if T.TYPE_CHECKING:
from . import ModuleState
+ from ..build import LibTypes
from ..interpreter import Interpreter
from ..interpreter import kwargs as _kwargs
from ..interpreter.interpreter import SourceInputs, SourceOutputs
@@ -38,6 +39,8 @@ if T.TYPE_CHECKING:
dependencies: T.List[T.Union[Dependency, ExternalLibrary]]
is_parallel: bool
+ link_with: T.List[LibTypes]
+ rust_args: T.List[str]
class FuncBindgen(TypedDict):
@@ -68,6 +71,14 @@ class RustModule(ExtensionModule):
'rust.test',
*TEST_KWS,
DEPENDENCIES_KW,
+ LINK_WITH_KW.evolve(since='1.2.0'),
+ KwargInfo(
+ 'rust_args',
+ ContainerTypeInfo(list, str),
+ listify=True,
+ default=[],
+ since='1.2.0',
+ ),
KwargInfo('is_parallel', bool, default=False),
)
def test(self, state: ModuleState, args: T.Tuple[str, BuildTarget], kwargs: FuncTest) -> ModuleReturnValue:
@@ -112,6 +123,9 @@ class RustModule(ExtensionModule):
rust.test('rust_lib_test', rust_lib)
```
"""
+ if any(isinstance(t, Jar) for t in kwargs.get('link_with', [])):
+ raise InvalidArguments('Rust tests cannot link with Jar targets')
+
name = args[0]
base_target: BuildTarget = args[1]
if not base_target.uses_rust():
@@ -142,9 +156,11 @@ class RustModule(ExtensionModule):
new_target_kwargs = base_target.kwargs.copy()
# Don't mutate the shallow copied list, instead replace it with a new
# one
- new_target_kwargs['rust_args'] = new_target_kwargs.get('rust_args', []) + ['--test']
+ new_target_kwargs['rust_args'] = \
+ new_target_kwargs.get('rust_args', []) + kwargs['rust_args'] + ['--test']
new_target_kwargs['install'] = False
new_target_kwargs['dependencies'] = new_target_kwargs.get('dependencies', []) + kwargs['dependencies']
+ new_target_kwargs['link_with'] = new_target_kwargs.get('link_with', []) + kwargs['link_with']
sources = T.cast('T.List[SourceOutputs]', base_target.sources.copy())
sources.extend(base_target.generated)
@@ -194,7 +210,10 @@ class RustModule(ExtensionModule):
else:
depends.append(d)
- clang_args: T.List[str] = []
+ # Copy to avoid subsequent calls mutating the original
+ # TODO: if we want this to be per-machine we'll need a native kwarg
+ clang_args = state.environment.properties.host.get_bindgen_clang_args().copy()
+
for i in state.process_include_dirs(kwargs['include_directories']):
# bindgen always uses clang, so it's safe to hardcode -I here
clang_args.extend([f'-I{x}' for x in i.to_string_list(