diff options
author | Xavier Claessens <xavier.claessens@collabora.com> | 2022-10-13 14:01:50 -0400 |
---|---|---|
committer | Xavier Claessens <xavier.claessens@collabora.com> | 2022-10-23 12:21:46 +0200 |
commit | 65590e6e4b59e08d0c1a16067524479ed822ad27 (patch) | |
tree | 24ef5a84dd057754db7b0b969e5e4aa78fbc3e77 | |
parent | 5e0f22896f7e007d790c9b606e7b7a940470eff0 (diff) | |
download | meson-65590e6e4b59e08d0c1a16067524479ed822ad27.zip meson-65590e6e4b59e08d0c1a16067524479ed822ad27.tar.gz meson-65590e6e4b59e08d0c1a16067524479ed822ad27.tar.bz2 |
Add cc.preprocess() method for c-like compilers
This introduce a new type of BuildTarget: CompileTarget. From ninja
backend POV it is the same thing as any other build target, except that
it skips the final link step. It could be used in the future for
transpilers too.
-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] |