diff --git a/tools/shuriken.py b/tools/shuriken.py index 955c672..e5a1943 100755 --- a/tools/shuriken.py +++ b/tools/shuriken.py @@ -497,7 +497,7 @@ class ShurikenCli: CompileTargetCpp = namedtuple('CompileTargetCpp', ['src', 'obj']) CompileTargetCppm = namedtuple('CompileTargetCppm', ['src', 'obj', 'pcm']) -CompileTargetStdModule = namedtuple('CompileTargetStdModule', ['src', 'pcm']) +CompileTargetStdModule = namedtuple('CompileTargetStdModule', ['original_src', 'generated_src', 'pcm']) class NinjaFileGenerator: @@ -552,7 +552,8 @@ class NinjaFileGenerator: std_module_sources = std_module_source_finder.find_module_sources(['std']) for module_name, module_src_path in std_module_sources.items(): self.compile_targets_std_module.append(CompileTargetStdModule( - src=str(module_src_path), + original_src=str(module_src_path), + generated_src=f"$builddir/generated/stdlib/{module_name}.cppm", pcm=f"$builddir/pcm/{module_name}.pcm", )) @@ -589,6 +590,10 @@ linker_args = {target_config.merged_linker_args} # -- RULES +# Rule to copy an arbitrary file (or multiple) from in to out +rule copy + command = cp $in $out + # Rule to compile a .cpp file to a .o file rule cpp command = {target_config.cpp_compiler} $cpp_flags -c $in -o $out @@ -607,7 +612,7 @@ rule link # Rule to generate a compilation database (JSON file) from the build targets defined in a Ninja file rule generate_compdb - command = ninja -f $in -t compdb cpp cppm > $out + command = ninja -f $in -t compdb cpp cppm std_module > $out # Rule to generate a Ninja dyndep file for C++ module dependencies based on a compilation database rule generate_dyndeps @@ -617,7 +622,7 @@ rule generate_dyndeps # -- STATIC BUILD TARGETS # Generate compilation database from default target Ninja file -build $compdb_file: generate_compdb {self.config.get_ninja_file_path(config.default_target)} +build $compdb_file: generate_compdb {self.config.get_ninja_file_path(config.default_target)} | generate_source_files # Shortcut alias to generate compilation database build compdb: phony $compdb_file @@ -632,11 +637,18 @@ build $dyndep_file: generate_dyndeps $compdb_file build $builddir/{target_config.output_file}: link {' '.join(self.link_target_obj_files)} default $builddir/{target_config.output_file} +# Phony target that depends on all generated source files +build generate_source_files: phony {self.list_generated_source_files()} + {self.render_compile_targets()} # End of build.{target}.ninja """.strip() + def list_generated_source_files(self) -> str: + generated_files = [target.generated_src for target in self.compile_targets_std_module] + return ' '.join(generated_files) + def render_compile_targets(self) -> str: rendered_targets = list(map(self.render_compile_target_std_module, self.compile_targets_std_module)) rendered_targets += list(map(self.render_compile_target_cpp, self.compile_targets_cpp)) @@ -661,7 +673,9 @@ build {target.obj} | {target.pcm}: cppm {target.src} || $dyndep_file @staticmethod def render_compile_target_std_module(target: CompileTargetStdModule) -> str: return f""" -build {target.pcm}: std_module {target.src} || $dyndep_file +build {target.generated_src}: copy {target.original_src} + +build {target.pcm}: std_module {target.generated_src} || $dyndep_file dyndep = $dyndep_file """.strip() @@ -683,10 +697,6 @@ class BuildDependencyParser: # Map of module names to PCM file paths module_map: dict[str, Path] = {} - # Add standard library modules to module map (if "import std" support is enabled) - if self.config.enable_import_std: - module_map['std'] = Path(target_build_dir, 'pcm', 'std.pcm') - # Validate module name and path convention, construct map of module names to PCM file paths for rule in parsed_p1689['rules']: provides = rule.get('provides', []) @@ -697,20 +707,16 @@ class BuildDependencyParser: module_name: str = provides[0]['logical-name'] assert module_name not in module_map, f'Module "{module_name}" is provided more than once: {rule}' - expected_source_path = str(Path(source_dir, module_name.replace('.', '/') + '.cppm')) - assert provides[0]['source-path'] == expected_source_path, \ - f"Module name does not match source path: {rule}" + if module_name != 'std': + expected_source_path = str(Path(source_dir, module_name.replace('.', '/') + '.cppm')) + assert provides[0]['source-path'] == expected_source_path, \ + f"Module name does not match source path: {rule}" module_map[module_name] = Path(target_build_dir, 'pcm', module_name + '.pcm') # Collect all module dependencies to generate dyndeps build_dependencies: dict[Path, list[Path]] = {} - # If "import std" support is enabled, we need to add std to the build dependencies, even though it doesn't have - # any dependencies itself. This is needed, otherwise the module won't be built automatically. - if self.config.enable_import_std: - build_dependencies[target_build_dir / 'pcm/std.pcm'] = [] - # Parse rules and get module dependencies for rule in parsed_p1689['rules']: # Compilation database contains "build/{default_target}" paths, we need to map them to "build/{target}"