From 3ae115b57ad7f8eca09c03f5bd6bf65604dcaf59 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 19 Jan 2021 10:12:38 -0800 Subject: Replace NinjaBackend is_rust_target with build.uses_rust we have two functions to do the exact same thing, and they're basically implemented the same way. Instead, let's just use the BuildTarget one, as it's more generally available. --- mesonbuild/backend/ninjabackend.py | 9 +-------- mesonbuild/build.py | 6 +++--- mesonbuild/modules/unstable_rust.py | 2 +- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index d66708c..d3350bb 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -691,13 +691,6 @@ int dummy; src_block['sources'] += sources src_block['generated_sources'] += generated_sources - def is_rust_target(self, target): - if len(target.sources) > 0: - first_file = target.sources[0] - if first_file.fname.endswith('.rs'): - return True - return False - def generate_target(self, target): try: if isinstance(target, build.BuildTarget): @@ -723,7 +716,7 @@ int dummy; if isinstance(target, build.Jar): self.generate_jar_target(target) return - if self.is_rust_target(target): + if target.uses_rust(): self.generate_rust_target(target) return if 'cs' in target.compilers: diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 017b0f0..fa7c140 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -1412,7 +1412,7 @@ You probably should put it in link_with instead.''') m = 'Could not get a dynamic linker for build target {!r}' raise AssertionError(m.format(self.name)) - def get_using_rustc(self) -> bool: + def uses_rust(self) -> bool: """Is this target a rust target.""" return self.sources and self.sources[0].fname.endswith('.rs') @@ -1687,7 +1687,7 @@ class Executable(BuildTarget): self.import_filename = self.gcc_import_filename if m.is_windows() and ('cs' in self.compilers or - self.get_using_rustc() or + self.uses_rust() or self.get_using_msvc()): self.debug_filename = self.name + '.pdb' @@ -1877,7 +1877,7 @@ class SharedLibrary(BuildTarget): suffix = 'dll' self.vs_import_filename = '{0}{1}.lib'.format(self.prefix if self.prefix is not None else '', self.name) self.gcc_import_filename = '{0}{1}.dll.a'.format(self.prefix if self.prefix is not None else 'lib', self.name) - if self.get_using_rustc(): + if self.uses_rust(): # Shared library is of the form foo.dll prefix = '' # Import library is called foo.dll.lib diff --git a/mesonbuild/modules/unstable_rust.py b/mesonbuild/modules/unstable_rust.py index 02369b6..d215376 100644 --- a/mesonbuild/modules/unstable_rust.py +++ b/mesonbuild/modules/unstable_rust.py @@ -85,7 +85,7 @@ class RustModule(ExtensionModule): base_target: BuildTarget = unholder(args[1]) if not isinstance(base_target, BuildTarget): raise InterpreterException('Second positional argument to rustmod.test() must be a library or executable') - if not base_target.get_using_rustc(): + if not base_target.uses_rust(): raise InterpreterException('Second positional argument to rustmod.test() must be a rust based target') extra_args = stringlistify(kwargs.get('args', [])) -- cgit v1.1 From bff0b415250b4f4f7cd750b60e6c01daaa61af15 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 5 Jan 2021 15:55:02 -0800 Subject: rust: Accept generated sources for main.rs There are still caveats here. Rust/cargo handles generated sources by writing out all targets of a single repo into a single output directory, setting a path to that via a build-time environment variable, and then include those files via a set of functions and macros. Meson's build layout is naturally different, and ninja makes working with environment variables at compile time difficult. Fixes #8157 --- mesonbuild/backend/ninjabackend.py | 13 ++++++++++++- mesonbuild/build.py | 23 ++++++++++++++++------- test cases/rust/11 generated main/gen.py | 16 ++++++++++++++++ test cases/rust/11 generated main/meson.build | 16 ++++++++++++++++ 4 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 test cases/rust/11 generated main/gen.py create mode 100644 test cases/rust/11 generated main/meson.build diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index d3350bb..9f2e649 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -45,7 +45,7 @@ from ..mesonlib import ( ) from ..mesonlib import get_compiler_for_source, has_path_sep, OptionKey from .backends import CleanTrees -from ..build import InvalidArguments +from ..build import GeneratedList, InvalidArguments from ..interpreter import Interpreter if T.TYPE_CHECKING: @@ -1581,12 +1581,23 @@ int dummy; args = rustc.compiler_args() # Compiler args for compiling this target args += compilers.get_base_compile_args(base_proxy, rustc) + self.generate_generator_list_rules(target) main_rust_file = None for i in target.get_sources(): if not rustc.can_compile(i): raise InvalidArguments('Rust target {} contains a non-rust source file.'.format(target.get_basename())) if main_rust_file is None: main_rust_file = i.rel_to_builddir(self.build_to_src) + for g in target.get_generated_sources(): + for i in g.get_outputs(): + if not rustc.can_compile(i): + raise InvalidArguments('Rust target {} contains a non-rust source file.'.format(target.get_basename())) + if isinstance(g, GeneratedList): + fname = os.path.join(self.get_target_private_dir(target), i) + else: + fname = i + if main_rust_file is None: + main_rust_file = fname if main_rust_file is None: raise RuntimeError('A Rust target has no Rust sources. This is weird. Also a bug. Please report') target_name = os.path.join(target.subdir, target.get_filename()) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index fa7c140..13783d1 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -569,7 +569,7 @@ class BuildTarget(Target): unity_opt = environment.coredata.get_option(OptionKey('unity')) self.is_unity = unity_opt == 'on' or (unity_opt == 'subprojects' and subproject != '') self.environment = environment - self.sources = [] + self.sources: T.List[File] = [] self.compilers = OrderedDict() # type: OrderedDict[str, Compiler] self.objects = [] self.external_deps = [] @@ -588,7 +588,7 @@ class BuildTarget(Target): self.need_install = False self.pch = {} self.extra_args: T.Dict[str, T.List['FileOrString']] = {} - self.generated = [] + self.generated: T.Sequence[T.Union[GeneratedList, CustomTarget, CustomTargetIndex]] = [] self.d_features = {} self.pic = False self.pie = False @@ -1414,7 +1414,14 @@ You probably should put it in link_with instead.''') def uses_rust(self) -> bool: """Is this target a rust target.""" - return self.sources and self.sources[0].fname.endswith('.rs') + if self.sources: + first_file = self.sources[0] + if first_file.fname.endswith('.rs'): + return True + elif self.generated: + if self.generated[0].get_outputs()[0].endswith('.rs'): + return True + return False def get_using_msvc(self): ''' @@ -1434,11 +1441,13 @@ You probably should put it in link_with instead.''') 2. If the target contains only objects, process_compilers guesses and picks the first compiler that smells right. ''' - compiler, _ = self.get_clink_dynamic_linker_and_stdlibs() + # Rustc can use msvc style linkers + if self.uses_rust(): + compiler = self.environment.coredata.compilers[self.for_machine]['rust'] + else: + compiler, _ = self.get_clink_dynamic_linker_and_stdlibs() # Mixing many languages with MSVC is not supported yet so ignore stdlibs. - if compiler and compiler.get_linker_id() in {'link', 'lld-link', 'xilink', 'optlink'}: - return True - return False + return compiler and compiler.get_linker_id() in {'link', 'lld-link', 'xilink', 'optlink'} def check_module_linking(self): ''' diff --git a/test cases/rust/11 generated main/gen.py b/test cases/rust/11 generated main/gen.py new file mode 100644 index 0000000..ebbc2a7 --- /dev/null +++ b/test cases/rust/11 generated main/gen.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 + +import argparse + + +def main() -> None: + parser = argparse.ArgumentParser() + parser.add_argument('out') + args = parser.parse_args() + + with open(args.out, 'w') as f: + f.write('fn main() { println!("I prefer tarnish, actually.") }') + + +if __name__ == "__main__": + main() diff --git a/test cases/rust/11 generated main/meson.build b/test cases/rust/11 generated main/meson.build new file mode 100644 index 0000000..4749816 --- /dev/null +++ b/test cases/rust/11 generated main/meson.build @@ -0,0 +1,16 @@ +project('generated rust main', 'rust') + +gen = find_program('gen.py') + +c = custom_target( + 'custom_target', + command : [gen, '@OUTPUT@'], + output : ['main.rs'], +) + +executable('custom_target_main', c) +executable('custom_target_index_main', c[0]) + +gen = generator(gen, arguments : ['@OUTPUT@'], output : '@BASENAME@.rs') +# Doesn't actually use gen.py as input, just a limitation of generators +executable('generator_main', gen.process(['gen.py'])) -- cgit v1.1 From caa6d5e16b6b12f64269246e83d29e2189bb5e92 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Wed, 6 Jan 2021 11:56:52 -0800 Subject: backend/ninja: Add order dependencies for generated sources in rust --- mesonbuild/backend/ninjabackend.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 9f2e649..c1c4c93 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -1582,6 +1582,9 @@ int dummy; # Compiler args for compiling this target args += compilers.get_base_compile_args(base_proxy, rustc) self.generate_generator_list_rules(target) + + orderdeps = [os.path.join(t.subdir, t.get_filename()) for t in target.link_targets] + main_rust_file = None for i in target.get_sources(): if not rustc.can_compile(i): @@ -1598,6 +1601,7 @@ int dummy; fname = i if main_rust_file is None: main_rust_file = fname + orderdeps.append(fname) if main_rust_file is None: raise RuntimeError('A Rust target has no Rust sources. This is weird. Also a bug. Please report') target_name = os.path.join(target.subdir, target.get_filename()) @@ -1635,7 +1639,6 @@ int dummy; args += target.get_extra_args('rust') args += rustc.get_output_args(os.path.join(target.subdir, target.get_filename())) args += self.environment.coredata.get_external_args(target.for_machine, rustc.language) - orderdeps = [os.path.join(t.subdir, t.get_filename()) for t in target.link_targets] linkdirs = OrderedDict() for d in target.link_targets: linkdirs[d.subdir] = True @@ -1682,7 +1685,7 @@ int dummy; args += ['-C', 'link-arg=' + rpath_arg + ':' + os.path.join(rustc.get_sysroot(), 'lib')] compiler_name = self.get_compiler_rule_name('rust', target.for_machine) element = NinjaBuildElement(self.all_outputs, target_name, compiler_name, main_rust_file) - if len(orderdeps) > 0: + if orderdeps: element.add_orderdep(orderdeps) element.add_item('ARGS', args) element.add_item('targetdep', depfile) -- cgit v1.1