diff options
-rw-r--r-- | mesonbuild/backend/backends.py | 2 | ||||
-rw-r--r-- | mesonbuild/backend/ninjabackend.py | 3 | ||||
-rw-r--r-- | mesonbuild/build.py | 43 | ||||
-rw-r--r-- | mesonbuild/interpreter/compiler.py | 38 |
4 files changed, 83 insertions, 3 deletions
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index 8943464..9776642 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -792,6 +792,8 @@ class Backend: def object_filename_from_source(self, target: build.BuildTarget, source: 'FileOrString') -> str: assert isinstance(source, mesonlib.File) + if isinstance(target, build.CompileTarget): + return target.sources_map[source] build_dir = self.environment.get_build_dir() rel_src = source.rel_to_builddir(self.build_to_src) diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 8dd21f5..7d90ac1 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -986,6 +986,9 @@ class NinjaBackend(backends.Backend): obj_list.append(o) compiled_sources.append(s) source2object[s] = o + if isinstance(target, build.CompileTarget): + # Skip the link stage for this special type of target + return linker, stdlib_args = self.determine_linker_and_stdlib_args(target) if isinstance(target, build.StaticLibrary) and target.prelink: final_obj_list = self.generate_prelink(target, obj_list) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index bf87071..14cc235 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -2581,6 +2581,44 @@ class CustomTarget(Target, CommandBase): def __len__(self) -> int: return len(self.outputs) +class CompileTarget(BuildTarget): + ''' + Target that only compile sources without linking them together. + It can be used as preprocessor, or transpiler. + ''' + + typename = 'compile' + + def __init__(self, + name: str, + subdir: str, + subproject: str, + environment: environment.Environment, + sources: T.List[File], + output_templ: str, + compiler: Compiler, + kwargs): + compilers = {compiler.get_language(): compiler} + super().__init__(name, subdir, subproject, compiler.for_machine, + sources, None, [], environment, compilers, kwargs) + self.filename = name + self.compiler = compiler + self.output_templ = output_templ + self.outputs = [] + for f in sources: + plainname = os.path.basename(f.fname) + basename = os.path.splitext(plainname)[0] + self.outputs.append(output_templ.replace('@BASENAME@', basename).replace('@PLAINNAME@', plainname)) + self.sources_map = dict(zip(sources, self.outputs)) + + def type_suffix(self) -> str: + return "@compile" + + @property + def is_unity(self) -> bool: + return False + + class RunTarget(Target, CommandBase): typename = 'run' @@ -2705,7 +2743,7 @@ class CustomTargetIndex(HoldableObject): typename: T.ClassVar[str] = 'custom' - target: CustomTarget + target: T.Union[CustomTarget, CompileTarget] output: str def __post_init__(self) -> None: @@ -2716,8 +2754,7 @@ class CustomTargetIndex(HoldableObject): return f'{self.target.name}[{self.output}]' def __repr__(self): - return '<CustomTargetIndex: {!r}[{}]>'.format( - self.target, self.target.get_outputs().index(self.output)) + return '<CustomTargetIndex: {!r}[{}]>'.format(self.target, self.output) def get_outputs(self) -> T.List[str]: return [self.output] diff --git a/mesonbuild/interpreter/compiler.py b/mesonbuild/interpreter/compiler.py index b46e502..7397321 100644 --- a/mesonbuild/interpreter/compiler.py +++ b/mesonbuild/interpreter/compiler.py @@ -4,6 +4,7 @@ import enum import functools +import os import typing as T from .. import build @@ -79,6 +80,11 @@ if T.TYPE_CHECKING: header_prefix: str header_required: T.Union[bool, coredata.UserFeatureOption] + class PreprocessKW(TypedDict): + output: str + compile_args: T.List[str] + include_directories: T.List[build.IncludeDirs] + class _TestMode(enum.Enum): @@ -184,6 +190,7 @@ class CompilerHolder(ObjectHolder['Compiler']): 'first_supported_link_argument': self.first_supported_link_argument_method, 'symbols_have_underscore_prefix': self.symbols_have_underscore_prefix_method, 'get_argument_syntax': self.get_argument_syntax_method, + 'preprocess': self.preprocess_method, }) @property @@ -734,3 +741,34 @@ class CompilerHolder(ObjectHolder['Compiler']): @noKwargs def get_argument_syntax_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str: return self.compiler.get_argument_syntax() + + @FeatureNew('compiler.preprocess', '0.64.0') + @typed_pos_args('compiler.preprocess', varargs=(mesonlib.File, str), min_varargs=1) + @typed_kwargs( + 'compiler.preprocess', + KwargInfo('output', str, default='@PLAINNAME@.i'), + KwargInfo('compile_args', ContainerTypeInfo(list, str), listify=True, default=[]), + _INCLUDE_DIRS_KW, + ) + def preprocess_method(self, args: T.Tuple[T.List['mesonlib.FileOrString']], kwargs: 'PreprocessKW') -> T.List[build.CustomTargetIndex]: + compiler = self.compiler.get_preprocessor() + sources = self.interpreter.source_strings_to_files(args[0]) + tg_kwargs = { + f'{self.compiler.language}_args': kwargs['compile_args'], + 'build_by_default': False, + 'include_directories': kwargs['include_directories'], + } + tg = build.CompileTarget( + 'preprocessor', + self.interpreter.subdir, + self.subproject, + self.environment, + sources, + kwargs['output'], + compiler, + tg_kwargs) + self.interpreter.add_target(tg.name, tg) + # Expose this target as list of its outputs, so user can pass them to + # other targets, list outputs, etc. + private_dir = os.path.relpath(self.interpreter.backend.get_target_private_dir(tg), self.interpreter.subdir) + return [build.CustomTargetIndex(tg, os.path.join(private_dir, o)) for o in tg.outputs] |