diff options
author | Jussi Pakkanen <jpakkane@gmail.com> | 2019-04-28 21:51:06 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-04-28 21:51:06 +0300 |
commit | 03d34a79f8632bd8d84d06e1f76b2fdba00a9be0 (patch) | |
tree | 00576213c4e0e9e8dad62ba31ae9a9072a32f0d2 /mesonbuild/backend | |
parent | 65091b7677973b783cdb2ebb5b9be9b0b97db975 (diff) | |
parent | 0debaab8d1547570e321ea11ea4fc8307ae55874 (diff) | |
download | meson-03d34a79f8632bd8d84d06e1f76b2fdba00a9be0.zip meson-03d34a79f8632bd8d84d06e1f76b2fdba00a9be0.tar.gz meson-03d34a79f8632bd8d84d06e1f76b2fdba00a9be0.tar.bz2 |
Merge pull request #5309 from jon-turney/ninja-backend-refactoring
Ninja backend refactoring
Diffstat (limited to 'mesonbuild/backend')
-rw-r--r-- | mesonbuild/backend/ninjabackend.py | 763 |
1 files changed, 380 insertions, 383 deletions
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 8edaeec..9a6fdad 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -40,12 +40,12 @@ FORTRAN_SUBMOD_PAT = r"\s*submodule\s*\((\w+:?\w+)\)\s*(\w+)\s*$" if mesonlib.is_windows(): quote_func = lambda s: '"{}"'.format(s) - execute_wrapper = 'cmd /c' - rmfile_prefix = 'del /f /s /q {} &&' + execute_wrapper = ['cmd', '/c'] + rmfile_prefix = ['del', '/f', '/s', '/q', '{}', '&&'] else: quote_func = shlex.quote - execute_wrapper = '' - rmfile_prefix = 'rm -f {} &&' + execute_wrapper = [] + rmfile_prefix = ['rm', '-f', '{}', '&&'] def ninja_quote(text, is_build_line=False): if is_build_line: @@ -63,6 +63,52 @@ Please report this error with a test case to the Meson bug tracker.''' % text raise MesonException(errmsg) return text +class NinjaComment: + def __init__(self, comment): + self.comment = comment + + def write(self, outfile): + for l in self.comment.split('\n'): + outfile.write('# ') + outfile.write(l) + outfile.write('\n') + outfile.write('\n') + +class NinjaRule: + def __init__(self, rule, command, args, description, + rspable = False, deps = None, depfile = None, extra = None): + self.name = rule + self.command = command # includes args which never go into a rspfile + self.args = args # args which will go into a rspfile, if used + self.description = description + self.deps = deps # depstyle 'gcc' or 'msvc' + self.depfile = depfile + self.extra = extra + self.rspable = rspable # if a rspfile can be used + self.refcount = 0 + + def write(self, outfile): + if not self.refcount: + return + + outfile.write('rule %s\n' % self.name) + if self.rspable: + outfile.write(' command = %s @$out.rsp\n' % ' '.join(self.command)) + outfile.write(' rspfile = $out.rsp\n') + outfile.write(' rspfile_content = %s\n' % ' '.join(self.args)) + else: + outfile.write(' command = %s\n' % ' '.join(self.command + self.args)) + if self.deps: + outfile.write(' deps = %s\n' % self.deps) + if self.depfile: + outfile.write(' depfile = %s\n' % self.depfile) + outfile.write(' description = %s\n' % self.description) + if self.extra: + for l in self.extra.split('\n'): + outfile.write(' ') + outfile.write(l) + outfile.write('\n') + outfile.write('\n') class NinjaBuildElement: def __init__(self, all_outputs, outfilenames, rule, infilenames): @@ -116,7 +162,10 @@ class NinjaBuildElement: line = line.replace('\\', '/') outfile.write(line) - # All the entries that should remain unquoted + # ninja variables whose value should remain unquoted. The value of these + # ninja variables (or variables we use them in) is interpreted directly + # by ninja (e.g. the value of the depfile variable is a pathname that + # ninja will read from, etc.), so it must not be shell quoted. raw_names = {'DEPFILE', 'DESC', 'pool', 'description'} for e in self.elems: @@ -154,7 +203,7 @@ class NinjaBackend(backends.Backend): self.all_outputs = {} self.introspection_data = {} - def create_target_alias(self, to_target, outfile): + def create_target_alias(self, to_target): # We need to use aliases for targets that might be used as directory # names to workaround a Ninja bug that breaks `ninja -t clean`. # This is used for 'reserved' targets such as 'test', 'install', @@ -165,7 +214,7 @@ class NinjaBackend(backends.Backend): raise AssertionError(m.format(to_target)) from_target = to_target[len('meson-'):] elem = NinjaBuildElement(self.all_outputs, from_target, 'phony', to_target) - elem.write(outfile) + self.add_build(elem) def detect_vs_dep_prefix(self, tempfilename): '''VS writes its dependency in a locale dependent format. @@ -220,24 +269,40 @@ int dummy; outfile.write('# It is autogenerated by the Meson build system.\n') outfile.write('# Do not edit by hand.\n\n') outfile.write('ninja_required_version = 1.5.1\n\n') + + num_pools = self.environment.coredata.backend_options['backend_max_links'].value + if num_pools > 0: + outfile.write('''pool link_pool + depth = %d + +''' % num_pools) + with self.detect_vs_dep_prefix(tempfilename) as outfile: - self.generate_rules(outfile) - self.generate_phony(outfile) - outfile.write('# Build rules for targets\n\n') + self.generate_rules() + + self.build_elements = [] + self.generate_phony() + self.add_build_comment(NinjaComment('Build rules for targets')) for t in self.build.get_targets().values(): - self.generate_target(t, outfile) - outfile.write('# Test rules\n\n') - self.generate_tests(outfile) - outfile.write('# Install rules\n\n') - self.generate_install(outfile) - self.generate_dist(outfile) + self.generate_target(t) + self.add_build_comment(NinjaComment('Test rules')) + self.generate_tests() + self.add_build_comment(NinjaComment('Install rules')) + self.generate_install() + self.generate_dist() if 'b_coverage' in self.environment.coredata.base_options and \ self.environment.coredata.base_options['b_coverage'].value: - outfile.write('# Coverage rules\n\n') - self.generate_coverage_rules(outfile) - outfile.write('# Suffix\n\n') - self.generate_utils(outfile) - self.generate_ending(outfile) + self.add_build_comment(NinjaComment('Coverage rules')) + self.generate_coverage_rules() + self.add_build_comment(NinjaComment('Suffix')) + self.generate_utils() + self.generate_ending() + + self.write_rules(outfile) + self.write_builds(outfile) + + default = 'default all\n\n' + outfile.write(default) # Only overwrite the old build file after the new one has been # fully created. os.replace(tempfilename, outfilename) @@ -377,11 +442,11 @@ int dummy; return True return False - def generate_target(self, target, outfile): + def generate_target(self, target): if isinstance(target, build.CustomTarget): - self.generate_custom_target(target, outfile) + self.generate_custom_target(target) if isinstance(target, build.RunTarget): - self.generate_run_target(target, outfile) + self.generate_run_target(target) name = target.get_id() if name in self.processed_targets: return @@ -389,20 +454,20 @@ int dummy; # Initialize an empty introspection source list self.introspection_data[name] = {} # Generate rules for all dependency targets - self.process_target_dependencies(target, outfile) + self.process_target_dependencies(target) # If target uses a language that cannot link to C objects, # just generate for that language and return. if isinstance(target, build.Jar): - self.generate_jar_target(target, outfile) + self.generate_jar_target(target) return if self.is_rust_target(target): - self.generate_rust_target(target, outfile) + self.generate_rust_target(target) return if 'cs' in target.compilers: - self.generate_cs_target(target, outfile) + self.generate_cs_target(target) return if 'swift' in target.compilers: - self.generate_swift_target(target, outfile) + self.generate_swift_target(target) return # Now we handle the following languages: @@ -420,14 +485,14 @@ int dummy; # Sources consumed by valac are filtered out. These only contain # C/C++ sources, objects, generated libs, and unknown sources now. target_sources, generated_sources, \ - vala_generated_sources = self.generate_vala_compile(target, outfile) + vala_generated_sources = self.generate_vala_compile(target) else: target_sources = self.get_target_sources(target) generated_sources = self.get_target_generated_sources(target) vala_generated_sources = [] self.scan_fortran_module_outputs(target) # Generate rules for GeneratedLists - self.generate_generator_list_rules(target, outfile) + self.generate_generator_list_rules(target) # Generate rules for building the remaining source files in this target outname = self.get_target_filename(target) @@ -479,15 +544,15 @@ int dummy; # because we need `header_deps` to be fully generated in the above loop. for src in generated_source_files: if self.environment.is_llvm_ir(src): - o = self.generate_llvm_ir_compile(target, outfile, src) + o = self.generate_llvm_ir_compile(target, src) else: - o = self.generate_single_compile(target, outfile, src, True, + o = self.generate_single_compile(target, src, True, header_deps=header_deps) obj_list.append(o) use_pch = self.environment.coredata.base_options.get('b_pch', False) if use_pch and target.has_pch(): - pch_objects = self.generate_pch(target, outfile, header_deps=header_deps) + pch_objects = self.generate_pch(target, header_deps=header_deps) else: pch_objects = [] @@ -517,39 +582,39 @@ int dummy; # Passing 'vala' here signifies that we want the compile # arguments to be specialized for C code generated by # valac. For instance, no warnings should be emitted. - obj_list.append(self.generate_single_compile(target, outfile, src, 'vala', [], header_deps)) + obj_list.append(self.generate_single_compile(target, src, 'vala', [], header_deps)) # Generate compile targets for all the pre-existing sources for this target for f, src in target_sources.items(): if not self.environment.is_header(src): if self.environment.is_llvm_ir(src): - obj_list.append(self.generate_llvm_ir_compile(target, outfile, src)) + obj_list.append(self.generate_llvm_ir_compile(target, src)) elif is_unity and self.get_target_source_can_unity(target, src): abs_src = os.path.join(self.environment.get_build_dir(), src.rel_to_builddir(self.build_to_src)) unity_src.append(abs_src) else: - obj_list.append(self.generate_single_compile(target, outfile, src, False, [], header_deps)) + obj_list.append(self.generate_single_compile(target, src, False, [], header_deps)) obj_list += self.flatten_object_list(target) if is_unity: for src in self.generate_unity_files(target, unity_src): - obj_list.append(self.generate_single_compile(target, outfile, src, True, unity_deps + header_deps)) + obj_list.append(self.generate_single_compile(target, src, True, unity_deps + header_deps)) linker, stdlib_args = self.determine_linker_and_stdlib_args(target) - elem = self.generate_link(target, outfile, outname, obj_list, linker, pch_objects, stdlib_args=stdlib_args) + elem = self.generate_link(target, outname, obj_list, linker, pch_objects, stdlib_args=stdlib_args) self.generate_shlib_aliases(target, self.get_target_dir(target)) - elem.write(outfile) + self.add_build(elem) - def process_target_dependencies(self, target, outfile): + def process_target_dependencies(self, target): for t in target.get_dependencies(): if t.get_id() not in self.processed_targets: - self.generate_target(t, outfile) + self.generate_target(t) - def custom_target_generator_inputs(self, target, outfile): + def custom_target_generator_inputs(self, target): for s in target.sources: if hasattr(s, 'held_object'): s = s.held_object if isinstance(s, build.GeneratedList): - self.generate_genlist_for_target(s, target, outfile) + self.generate_genlist_for_target(s, target) def unwrap_dep_list(self, target): deps = [] @@ -562,8 +627,8 @@ int dummy; deps.append(os.path.join(self.get_target_dir(i), output)) return deps - def generate_custom_target(self, target, outfile): - self.custom_target_generator_inputs(target, outfile) + def generate_custom_target(self, target): + self.custom_target_generator_inputs(target) (srcs, ofilenames, cmd) = self.eval_custom_target_command(target) deps = self.unwrap_dep_list(target) deps += self.get_custom_target_depend_files(target) @@ -624,10 +689,10 @@ int dummy; cmd = self.replace_paths(target, cmd) elem.add_item('COMMAND', cmd) elem.add_item('description', desc.format(target.name, cmd_type)) - elem.write(outfile) + self.add_build(elem) self.processed_targets[target.get_id()] = True - def generate_run_target(self, target, outfile): + def generate_run_target(self, target): cmd = self.environment.get_build_command() + ['--internal', 'commandrunner'] deps = self.unwrap_dep_list(target) arg_strings = [] @@ -686,9 +751,9 @@ int dummy; elem.add_item('COMMAND', cmd) elem.add_item('description', 'Running external command %s.' % target.name) elem.add_item('pool', 'console') - elem.write(outfile) + self.add_build(elem) # Alias that runs the target defined above with the name the user specified - self.create_target_alias(target_name, outfile) + self.create_target_alias(target_name) self.processed_targets[target.get_id()] = True def generate_coverage_command(self, elem, outputs): @@ -701,49 +766,49 @@ int dummy; self.environment.get_build_dir(), self.environment.get_log_dir()]) - def generate_coverage_rules(self, outfile): + def generate_coverage_rules(self): e = NinjaBuildElement(self.all_outputs, 'meson-coverage', 'CUSTOM_COMMAND', 'PHONY') self.generate_coverage_command(e, []) e.add_item('description', 'Generates coverage reports.') - e.write(outfile) + self.add_build(e) # Alias that runs the target defined above - self.create_target_alias('meson-coverage', outfile) - self.generate_coverage_legacy_rules(outfile) + self.create_target_alias('meson-coverage') + self.generate_coverage_legacy_rules() - def generate_coverage_legacy_rules(self, outfile): + def generate_coverage_legacy_rules(self): e = NinjaBuildElement(self.all_outputs, 'meson-coverage-xml', 'CUSTOM_COMMAND', 'PHONY') self.generate_coverage_command(e, ['--xml']) e.add_item('description', 'Generates XML coverage report.') - e.write(outfile) + self.add_build(e) # Alias that runs the target defined above - self.create_target_alias('meson-coverage-xml', outfile) + self.create_target_alias('meson-coverage-xml') e = NinjaBuildElement(self.all_outputs, 'meson-coverage-text', 'CUSTOM_COMMAND', 'PHONY') self.generate_coverage_command(e, ['--text']) e.add_item('description', 'Generates text coverage report.') - e.write(outfile) + self.add_build(e) # Alias that runs the target defined above - self.create_target_alias('meson-coverage-text', outfile) + self.create_target_alias('meson-coverage-text') e = NinjaBuildElement(self.all_outputs, 'meson-coverage-html', 'CUSTOM_COMMAND', 'PHONY') self.generate_coverage_command(e, ['--html']) e.add_item('description', 'Generates HTML coverage report.') - e.write(outfile) + self.add_build(e) # Alias that runs the target defined above - self.create_target_alias('meson-coverage-html', outfile) + self.create_target_alias('meson-coverage-html') - def generate_install(self, outfile): + def generate_install(self): self.create_install_data_files() elem = NinjaBuildElement(self.all_outputs, 'meson-install', 'CUSTOM_COMMAND', 'PHONY') elem.add_dep('all') elem.add_item('DESC', 'Installing files.') elem.add_item('COMMAND', self.environment.get_build_command() + ['install', '--no-rebuild']) elem.add_item('pool', 'console') - elem.write(outfile) + self.add_build(elem) # Alias that runs the target defined above - self.create_target_alias('meson-install', outfile) + self.create_target_alias('meson-install') - def generate_tests(self, outfile): + def generate_tests(self): self.serialize_tests() cmd = self.environment.get_build_command(True) + ['test', '--no-rebuild'] if not self.environment.coredata.get_builtin_option('stdsplit'): @@ -754,9 +819,9 @@ int dummy; elem.add_item('COMMAND', cmd) elem.add_item('DESC', 'Running all tests.') elem.add_item('pool', 'console') - elem.write(outfile) + self.add_build(elem) # Alias that runs the above-defined meson-test target - self.create_target_alias('meson-test', outfile) + self.create_target_alias('meson-test') # And then benchmarks. cmd = self.environment.get_build_command(True) + [ @@ -766,54 +831,71 @@ int dummy; elem.add_item('COMMAND', cmd) elem.add_item('DESC', 'Running benchmark suite.') elem.add_item('pool', 'console') - elem.write(outfile) + self.add_build(elem) # Alias that runs the above-defined meson-benchmark target - self.create_target_alias('meson-benchmark', outfile) + self.create_target_alias('meson-benchmark') - def generate_rules(self, outfile): - outfile.write('# Rules for compiling.\n\n') - self.generate_compile_rules(outfile) - outfile.write('# Rules for linking.\n\n') - num_pools = self.environment.coredata.backend_options['backend_max_links'].value - if num_pools > 0: - outfile.write('''pool link_pool - depth = %d + def generate_rules(self): + self.rules = [] + self.ruledict = {} -''' % num_pools) + self.add_rule_comment(NinjaComment('Rules for compiling.')) + self.generate_compile_rules() + self.add_rule_comment(NinjaComment('Rules for linking.')) if self.environment.is_cross_build(): - self.generate_static_link_rules(True, outfile) - self.generate_static_link_rules(False, outfile) - self.generate_dynamic_link_rules(outfile) - outfile.write('# Other rules\n\n') - outfile.write('rule CUSTOM_COMMAND\n') - outfile.write(' command = $COMMAND\n') - outfile.write(' description = $DESC\n') - outfile.write(' restat = 1\n\n') + self.generate_static_link_rules(True) + self.generate_static_link_rules(False) + self.generate_dynamic_link_rules() + self.add_rule_comment(NinjaComment('Other rules')) # Ninja errors out if you have deps = gcc but no depfile, so we must # have two rules for custom commands. - outfile.write('rule CUSTOM_COMMAND_DEP\n') - outfile.write(' command = $COMMAND\n') - outfile.write(' description = $DESC\n') - outfile.write(' deps = gcc\n') - outfile.write(' depfile = $DEPFILE\n') - outfile.write(' restat = 1\n\n') - outfile.write('rule REGENERATE_BUILD\n') + self.add_rule(NinjaRule('CUSTOM_COMMAND', ['$COMMAND'], [], '$DESC', + extra='restat = 1')) + self.add_rule(NinjaRule('CUSTOM_COMMAND_DEP', ['$COMMAND'], [], '$DESC', + deps='gcc', depfile='$DEPFILE', + extra='restat = 1')) + c = [ninja_quote(quote_func(x)) for x in self.environment.get_build_command()] + \ ['--internal', 'regenerate', ninja_quote(quote_func(self.environment.get_source_dir())), ninja_quote(quote_func(self.environment.get_build_dir()))] - outfile.write(" command = " + ' '.join(c) + ' --backend ninja\n') - outfile.write(' description = Regenerating build files.\n') - outfile.write(' generator = 1\n\n') - outfile.write('\n') + self.add_rule(NinjaRule('REGENERATE_BUILD', + c + ['--backend', 'ninja'], [], + 'Regenerating build files.', + extra='generator = 1')) - def generate_phony(self, outfile): - outfile.write('# Phony build target, always out of date\n') - outfile.write('build PHONY: phony\n') - outfile.write('\n') + def add_rule_comment(self, comment): + self.rules.append(comment) + + def add_build_comment(self, comment): + self.build_elements.append(comment) + + def add_rule(self, rule): + self.rules.append(rule) + self.ruledict[rule.name] = rule + + def add_build(self, build): + self.build_elements.append(build) + + # increment rule refcount + if build.rule != 'phony': + self.ruledict[build.rule].refcount += 1 + + def write_rules(self, outfile): + for r in self.rules: + r.write(outfile) + + def write_builds(self, outfile): + for b in self.build_elements: + b.write(outfile) + + def generate_phony(self): + self.add_build_comment(NinjaComment('Phony build target, always out of date')) + elem = NinjaBuildElement(self.all_outputs, 'PHONY', 'phony', '') + self.add_build(elem) - def generate_jar_target(self, target, outfile): + def generate_jar_target(self, target): fname = target.get_filename() outname_rel = os.path.join(self.get_target_dir(target), fname) src_list = target.get_sources() @@ -838,7 +920,7 @@ int dummy; compile_args = self.determine_single_java_compile_args(target, compiler) for src in src_list + gen_src_list: - plain_class_path = self.generate_single_java_compile(src, target, compiler, compile_args, outfile) + plain_class_path = self.generate_single_java_compile(src, target, compiler, compile_args) class_list.append(plain_class_path) class_dep_list = [os.path.join(self.get_target_private_dir(target), i) for i in class_list] manifest_path = os.path.join(self.get_target_private_dir(target), 'META-INF', 'MANIFEST.MF') @@ -863,11 +945,11 @@ int dummy; elem = NinjaBuildElement(self.all_outputs, outname_rel, jar_rule, []) elem.add_dep(class_dep_list) elem.add_item('ARGS', commands) - elem.write(outfile) + self.add_build(elem) # Create introspection information self.create_target_source_introspection(target, compiler, compile_args, src_list, gen_src_list) - def generate_cs_resource_tasks(self, target, outfile): + def generate_cs_resource_tasks(self, target): args = [] deps = [] for r in target.resources: @@ -880,7 +962,7 @@ int dummy; elem = NinjaBuildElement(self.all_outputs, ofilename, "CUSTOM_COMMAND", rel_sourcefile) elem.add_item('COMMAND', ['resgen', rel_sourcefile, ofilename]) elem.add_item('DESC', 'Compiling resource %s.' % rel_sourcefile) - elem.write(outfile) + self.add_build(elem) deps.append(ofilename) a = '-resource:' + ofilename else: @@ -888,7 +970,7 @@ int dummy; args.append(a) return args, deps - def generate_cs_target(self, target, outfile): + def generate_cs_target(self, target): buildtype = self.get_option_for_target('buildtype', target) fname = target.get_filename() outname_rel = os.path.join(self.get_target_dir(target), fname) @@ -906,7 +988,7 @@ int dummy; commands.append('-target:library') else: raise MesonException('Unknown C# target type.') - (resource_args, resource_deps) = self.generate_cs_resource_tasks(target, outfile) + (resource_args, resource_deps) = self.generate_cs_resource_tasks(target) commands += resource_args deps += resource_deps commands += compiler.get_output_args(outname_rel) @@ -934,9 +1016,9 @@ int dummy; elem = NinjaBuildElement(self.all_outputs, outputs, 'cs_COMPILER', rel_srcs + generated_rel_srcs) elem.add_dep(deps) elem.add_item('ARGS', commands) - elem.write(outfile) + self.add_build(elem) - self.generate_generator_list_rules(target, outfile) + self.generate_generator_list_rules(target) self.create_target_source_introspection(target, compiler, commands, rel_srcs, generated_rel_srcs) def determine_single_java_compile_args(self, target, compiler): @@ -956,7 +1038,7 @@ int dummy; args += ['-sourcepath', sourcepath] return args - def generate_single_java_compile(self, src, target, compiler, args, outfile): + def generate_single_java_compile(self, src, target, compiler, args): deps = [os.path.join(self.get_target_dir(l), l.get_filename()) for l in target.link_targets] generated_sources = self.get_target_generated_sources(target) for rel_src, gensrc in generated_sources.items(): @@ -968,17 +1050,14 @@ int dummy; element = NinjaBuildElement(self.all_outputs, rel_obj, compiler.get_language() + '_COMPILER', rel_src) element.add_dep(deps) element.add_item('ARGS', args) - element.write(outfile) + self.add_build(element) return plain_class_path - def generate_java_link(self, outfile): - rule = 'rule java_LINKER\n' - command = ' command = jar $ARGS\n' - description = ' description = Creating JAR $out.\n' - outfile.write(rule) - outfile.write(command) - outfile.write(description) - outfile.write('\n') + def generate_java_link(self): + rule = 'java_LINKER' + command = ['jar', '$ARGS'] + description = 'Creating JAR $out.' + self.add_rule(NinjaRule(rule, command, [], description)) def determine_dep_vapis(self, target): """ @@ -1054,7 +1133,7 @@ int dummy; srctype[f] = gensrc return vala, vapi, (others, othersgen) - def generate_vala_compile(self, target, outfile): + def generate_vala_compile(self, target): """Vala is compiled into C. Set up all necessary build steps here.""" (vala_src, vapi_src, other_src) = self.split_vala_sources(target) extra_dep_files = [] @@ -1169,11 +1248,11 @@ int dummy; all_files + dependency_vapis) element.add_item('ARGS', args) element.add_dep(extra_dep_files) - element.write(outfile) + self.add_build(element) self.create_target_source_introspection(target, valac, args, all_files, []) return other_src[0], other_src[1], vala_c_src - def generate_rust_target(self, target, outfile): + def generate_rust_target(self, target): rustc = target.compilers['rust'] # Rust compiler takes only the main file as input and # figures out what other files are needed via import @@ -1261,9 +1340,9 @@ int dummy; element.add_item('ARGS', args) element.add_item('targetdep', depfile) element.add_item('cratetype', cratetype) - element.write(outfile) + self.add_build(element) if isinstance(target, build.SharedLibrary): - self.generate_shsym(outfile, target) + self.generate_shsym(target) self.create_target_source_introspection(target, rustc, args, [main_rust_file], []) def swift_module_file_name(self, target): @@ -1309,7 +1388,7 @@ int dummy; others.append(i) return srcs, others - def generate_swift_target(self, target, outfile): + def generate_swift_target(self, target): module_name = self.target_swift_modulename(target) swiftc = target.compilers['swift'] abssrc = [] @@ -1383,35 +1462,35 @@ int dummy; elem.add_dep(abs_headers) elem.add_item('ARGS', compile_args + header_imports + abs_generated + module_includes) elem.add_item('RUNDIR', rundir) - elem.write(outfile) + self.add_build(elem) elem = NinjaBuildElement(self.all_outputs, out_module_name, 'swift_COMPILER', abssrc) elem.add_dep(in_module_files + rel_generated) elem.add_item('ARGS', compile_args + abs_generated + module_includes + swiftc.get_mod_gen_args()) elem.add_item('RUNDIR', rundir) - elem.write(outfile) + self.add_build(elem) if isinstance(target, build.StaticLibrary): - elem = self.generate_link(target, outfile, self.get_target_filename(target), + elem = self.generate_link(target, self.get_target_filename(target), rel_objects, self.build.static_linker) - elem.write(outfile) + self.add_build(elem) elif isinstance(target, build.Executable): elem = NinjaBuildElement(self.all_outputs, self.get_target_filename(target), 'swift_COMPILER', []) elem.add_dep(rel_objects) elem.add_dep(link_deps) elem.add_item('ARGS', link_args + swiftc.get_std_exe_link_args() + objects + abs_link_deps) elem.add_item('RUNDIR', rundir) - elem.write(outfile) + self.add_build(elem) else: raise MesonException('Swift supports only executable and static library targets.') # Introspection information self.create_target_source_introspection(target, swiftc, compile_args + header_imports + module_includes, relsrc, rel_generated) - def generate_static_link_rules(self, is_cross, outfile): + def generate_static_link_rules(self, is_cross): num_pools = self.environment.coredata.backend_options['backend_max_links'].value if 'java' in self.build.compilers: if not is_cross: - self.generate_java_link(outfile) + self.generate_java_link() if is_cross: if self.environment.is_cross_build(): static_linker = self.build.static_cross_linker @@ -1423,15 +1502,9 @@ int dummy; crstr = '' if static_linker is None: return - rule = 'rule STATIC%s_LINKER\n' % crstr - if static_linker.can_linker_accept_rsp(): - command_template = ''' command = {executable} $LINK_ARGS {output_args} @$out.rsp - rspfile = $out.rsp - rspfile_content = $in -''' - else: - command_template = ' command = {executable} $LINK_ARGS {output_args} $in\n' + rule = 'STATIC%s_LINKER' % crstr cmdlist = [] + args = ['$in'] # FIXME: Must normalize file names with pathlib.Path before writing # them out to fix this properly on Windows. See: # https://github.com/mesonbuild/meson/issues/1517 @@ -1440,19 +1513,20 @@ int dummy; # `ar` has no options to overwrite archives. It always appends, # which is never what we want. Delete an existing library first if # it exists. https://github.com/mesonbuild/meson/issues/1355 - cmdlist = [execute_wrapper, rmfile_prefix.format('$out')] + cmdlist = execute_wrapper + [c.format('$out') for c in rmfile_prefix] cmdlist += static_linker.get_exelist() - command = command_template.format( - executable=' '.join(cmdlist), - output_args=' '.join(static_linker.get_output_args('$out'))) - description = ' description = Linking static target $out.\n\n' - outfile.write(rule) - outfile.write(command) + cmdlist += ['$LINK_ARGS'] + cmdlist += static_linker.get_output_args('$out') + description = 'Linking static target $out.' if num_pools > 0: - outfile.write(' pool = link_pool\n') - outfile.write(description) + pool = 'pool = link_pool' + else: + pool = None + self.add_rule(NinjaRule(rule, cmdlist, args, description, + rspable=static_linker.can_linker_accept_rsp(), + extra=pool)) - def generate_dynamic_link_rules(self, outfile): + def generate_dynamic_link_rules(self): num_pools = self.environment.coredata.backend_options['backend_max_links'].value ctypes = [(self.build.compilers, False)] if self.environment.is_cross_build(): @@ -1469,180 +1543,126 @@ int dummy; crstr = '' if is_cross: crstr = '_CROSS' - rule = 'rule %s%s_LINKER\n' % (langname, crstr) - if compiler.can_linker_accept_rsp(): - command_template = ''' command = {executable} @$out.rsp - rspfile = $out.rsp - rspfile_content = $ARGS {output_args} $in $LINK_ARGS $aliasing -''' - else: - command_template = ' command = {executable} $ARGS {output_args} $in $LINK_ARGS $aliasing\n' - command = command_template.format( - executable=' '.join(compiler.get_linker_exelist()), - output_args=' '.join(compiler.get_linker_output_args('$out')) - ) - description = ' description = Linking target $out.\n' - outfile.write(rule) - outfile.write(command) + rule = '%s%s_LINKER' % (langname, crstr) + command = compiler.get_linker_exelist() + args = ['$ARGS'] + compiler.get_linker_output_args('$out') + ['$in', '$LINK_ARGS'] + description = 'Linking target $out.' if num_pools > 0: - outfile.write(' pool = link_pool\n') - outfile.write(description) - outfile.write('\n') - outfile.write('\n') + pool = 'pool = link_pool' + else: + pool = None + self.add_rule(NinjaRule(rule, command, args, description, + rspable=compiler.can_linker_accept_rsp(), + extra=pool)) + args = [ninja_quote(quote_func(x)) for x in self.environment.get_build_command()] + \ ['--internal', 'symbolextractor', '$in', '$out'] - symrule = 'rule SHSYM\n' - symcmd = ' command = ' + ' '.join(args) + ' $CROSS\n' - synstat = ' restat = 1\n' - syndesc = ' description = Generating symbol file $out.\n' - outfile.write(symrule) - outfile.write(symcmd) - outfile.write(synstat) - outfile.write(syndesc) - outfile.write('\n') - - def generate_java_compile_rule(self, compiler, outfile): - rule = 'rule %s_COMPILER\n' % compiler.get_language() - invoc = ' '.join([ninja_quote(i) for i in compiler.get_exelist()]) - command = ' command = %s $ARGS $in\n' % invoc - description = ' description = Compiling Java object $in.\n' - outfile.write(rule) - outfile.write(command) - outfile.write(description) - outfile.write('\n') - - def generate_cs_compile_rule(self, compiler, outfile): - rule = 'rule %s_COMPILER\n' % compiler.get_language() - invoc = ' '.join([ninja_quote(i) for i in compiler.get_exelist()]) - - if mesonlib.is_windows(): - command = ''' command = {executable} @$out.rsp - rspfile = $out.rsp - rspfile_content = $ARGS $in -'''.format(executable=invoc) - else: - command = ' command = %s $ARGS $in\n' % invoc - - description = ' description = Compiling C Sharp target $out.\n' - outfile.write(rule) - outfile.write(command) - outfile.write(description) - outfile.write('\n') - - def generate_vala_compile_rules(self, compiler, outfile): - rule = 'rule %s_COMPILER\n' % compiler.get_language() - invoc = ' '.join([ninja_quote(i) for i in compiler.get_exelist()]) - command = ' command = %s $ARGS $in\n' % invoc - description = ' description = Compiling Vala source $in.\n' - restat = ' restat = 1\n' # ValaC does this always to take advantage of it. - outfile.write(rule) - outfile.write(command) - outfile.write(description) - outfile.write(restat) - outfile.write('\n') - - def generate_rust_compile_rules(self, compiler, outfile, is_cross): + symrule = 'SHSYM' + symcmd = args + ['$CROSS'] + syndesc = 'Generating symbol file $out.' + synstat = 'restat = 1' + self.add_rule(NinjaRule(symrule, symcmd, [], syndesc, extra=synstat)) + + def generate_java_compile_rule(self, compiler): + rule = '%s_COMPILER' % compiler.get_language() + invoc = [ninja_quote(i) for i in compiler.get_exelist()] + command = invoc + ['$ARGS', '$in'] + description = 'Compiling Java object $in.' + self.add_rule(NinjaRule(rule, command, [], description)) + + def generate_cs_compile_rule(self, compiler): + rule = '%s_COMPILER' % compiler.get_language() + invoc = [ninja_quote(i) for i in compiler.get_exelist()] + command = invoc + args = ['$ARGS', '$in'] + description = 'Compiling C Sharp target $out.' + self.add_rule(NinjaRule(rule, command, args, description, + rspable=mesonlib.is_windows())) + + def generate_vala_compile_rules(self, compiler): + rule = '%s_COMPILER' % compiler.get_language() + invoc = [ninja_quote(i) for i in compiler.get_exelist()] + command = invoc + ['$ARGS', '$in'] + description = 'Compiling Vala source $in.' + self.add_rule(NinjaRule(rule, command, [], description, extra='restat = 1')) + + def generate_rust_compile_rules(self, compiler, is_cross): crstr = '' if is_cross: crstr = '_CROSS' - rule = 'rule %s%s_COMPILER\n' % (compiler.get_language(), crstr) - invoc = ' '.join([ninja_quote(i) for i in compiler.get_exelist()]) - command = ' command = %s $ARGS $in\n' % invoc - description = ' description = Compiling Rust source $in.\n' - depfile = ' depfile = $targetdep\n' - - depstyle = ' deps = gcc\n' - outfile.write(rule) - outfile.write(command) - outfile.write(description) - outfile.write(depfile) - outfile.write(depstyle) - outfile.write('\n') - - def generate_swift_compile_rules(self, compiler, outfile): - rule = 'rule %s_COMPILER\n' % compiler.get_language() + rule = '%s%s_COMPILER' % (compiler.get_language(), crstr) + invoc = [ninja_quote(i) for i in compiler.get_exelist()] + command = invoc + ['$ARGS', '$in'] + description = 'Compiling Rust source $in.' + depfile = '$targetdep' + depstyle = 'gcc' + self.add_rule(NinjaRule(rule, command, [], description, deps=depstyle, + depfile=depfile)) + + def generate_swift_compile_rules(self, compiler): + rule = '%s_COMPILER' % compiler.get_language() full_exe = [ninja_quote(x) for x in self.environment.get_build_command()] + [ '--internal', 'dirchanger', '$RUNDIR', ] - invoc = (' '.join(full_exe) + ' ' + - ' '.join(ninja_quote(i) for i in compiler.get_exelist())) - command = ' command = %s $ARGS $in\n' % invoc - description = ' description = Compiling Swift source $in.\n' - outfile.write(rule) - outfile.write(command) - outfile.write(description) - outfile.write('\n') + invoc = full_exe + [ninja_quote(i) for i in compiler.get_exelist()] + command = invoc + ['$ARGS', '$in'] + description = 'Compiling Swift source $in.' + self.add_rule(NinjaRule(rule, command, [], description)) - def generate_fortran_dep_hack(self, outfile, crstr): + def generate_fortran_dep_hack(self, crstr): + rule = 'FORTRAN_DEP_HACK%s' % (crstr) if mesonlib.is_windows(): - cmd = 'cmd /C ""' + cmd = ['cmd', '/C'] else: - cmd = 'true' - template = '''# Workaround for these issues: -# https://groups.google.com/forum/#!topic/ninja-build/j-2RfBIOd_8 -# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485 -rule FORTRAN_DEP_HACK%s - command = %s - description = Dep hack - restat = 1 - -''' - outfile.write(template % (crstr, cmd)) - - def generate_llvm_ir_compile_rule(self, compiler, is_cross, outfile): + cmd = ['true'] + self.add_rule_comment(NinjaComment('''Workaround for these issues: +https://groups.google.com/forum/#!topic/ninja-build/j-2RfBIOd_8 +https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) + self.add_rule(NinjaRule(rule, cmd, [], 'Dep hack', extra='restat = 1')) + + def generate_llvm_ir_compile_rule(self, compiler, is_cross): if getattr(self, 'created_llvm_ir_rule', False): return - rule = 'rule llvm_ir{}_COMPILER\n'.format('_CROSS' if is_cross else '') - if compiler.can_linker_accept_rsp(): - command_template = ' command = {executable} @$out.rsp\n' \ - ' rspfile = $out.rsp\n' \ - ' rspfile_content = $ARGS {output_args} {compile_only_args} $in\n' - else: - command_template = ' command = {executable} $ARGS {output_args} {compile_only_args} $in\n' - command = command_template.format( - executable=' '.join([ninja_quote(i) for i in compiler.get_exelist()]), - output_args=' '.join(compiler.get_output_args('$out')), - compile_only_args=' '.join(compiler.get_compile_only_args()) - ) - description = ' description = Compiling LLVM IR object $in.\n' - outfile.write(rule) - outfile.write(command) - outfile.write(description) - outfile.write('\n') + rule = 'llvm_ir{}_COMPILER'.format('_CROSS' if is_cross else '') + command = [ninja_quote(i) for i in compiler.get_exelist()] + args = ['$ARGS'] + compiler.get_output_args('$out') + compiler.get_compile_only_args() + ['$in'] + description = 'Compiling LLVM IR object $in.' + self.add_rule(NinjaRule(rule, command, args, description, + rspable=compiler.can_linker_accept_rsp())) self.created_llvm_ir_rule = True - def generate_compile_rule_for(self, langname, compiler, is_cross, outfile): + def generate_compile_rule_for(self, langname, compiler, is_cross): if langname == 'java': if not is_cross: - self.generate_java_compile_rule(compiler, outfile) + self.generate_java_compile_rule(compiler) return if langname == 'cs': if not is_cross: - self.generate_cs_compile_rule(compiler, outfile) + self.generate_cs_compile_rule(compiler) return if langname == 'vala': if not is_cross: - self.generate_vala_compile_rules(compiler, outfile) + self.generate_vala_compile_rules(compiler) return if langname == 'rust': - self.generate_rust_compile_rules(compiler, outfile, is_cross) + self.generate_rust_compile_rules(compiler, is_cross) return if langname == 'swift': if not is_cross: - self.generate_swift_compile_rules(compiler, outfile) + self.generate_swift_compile_rules(compiler) return if is_cross: crstr = '_CROSS' else: crstr = '' if langname == 'fortran': - self.generate_fortran_dep_hack(outfile, crstr) - rule = 'rule %s%s_COMPILER\n' % (langname, crstr) + self.generate_fortran_dep_hack(crstr) + rule = '%s%s_COMPILER' % (langname, crstr) depargs = compiler.get_dependency_gen_args('$out', '$DEPFILE') quoted_depargs = [] for d in depargs: @@ -1650,39 +1670,27 @@ rule FORTRAN_DEP_HACK%s d = quote_func(d) quoted_depargs.append(d) - if compiler.can_linker_accept_rsp(): - command_template = ''' command = {executable} @$out.rsp - rspfile = $out.rsp - rspfile_content = $ARGS {dep_args} {output_args} {compile_only_args} $in -''' - else: - command_template = ' command = {executable} $ARGS {dep_args} {output_args} {compile_only_args} $in\n' - command = command_template.format( - executable=' '.join([ninja_quote(i) for i in compiler.get_exelist()]), - dep_args=' '.join(quoted_depargs), - output_args=' '.join(compiler.get_output_args('$out')), - compile_only_args=' '.join(compiler.get_compile_only_args()) - ) - description = ' description = Compiling %s object $out.\n' % compiler.get_display_language() + command = [ninja_quote(i) for i in compiler.get_exelist()] + args = ['$ARGS'] + quoted_depargs + compiler.get_output_args('$out') + compiler.get_compile_only_args() + ['$in'] + description = 'Compiling %s object $out.' % compiler.get_display_language() if isinstance(compiler, VisualStudioCCompiler): - deps = ' deps = msvc\n' + deps = 'msvc' + depfile = None else: - deps = ' deps = gcc\n' - deps += ' depfile = $DEPFILE\n' - outfile.write(rule) - outfile.write(command) - outfile.write(deps) - outfile.write(description) - outfile.write('\n') + deps = 'gcc' + depfile = '$DEPFILE' + self.add_rule(NinjaRule(rule, command, args, description, + rspable=compiler.can_linker_accept_rsp(), + deps=deps, depfile=depfile)) - def generate_pch_rule_for(self, langname, compiler, is_cross, outfile): + def generate_pch_rule_for(self, langname, compiler, is_cross): if langname != 'c' and langname != 'cpp': return if is_cross: crstr = '_CROSS' else: crstr = '' - rule = 'rule %s%s_PCH\n' % (langname, crstr) + rule = '%s%s_PCH' % (langname, crstr) depargs = compiler.get_dependency_gen_args('$out', '$DEPFILE') quoted_depargs = [] @@ -1691,50 +1699,42 @@ rule FORTRAN_DEP_HACK%s d = quote_func(d) quoted_depargs.append(d) if isinstance(compiler, VisualStudioCCompiler): - output = '' + output = [] else: - output = ' '.join(compiler.get_output_args('$out')) - command = " command = {executable} $ARGS {dep_args} {output_args} {compile_only_args} $in\n".format( - executable=' '.join(compiler.get_exelist()), - dep_args=' '.join(quoted_depargs), - output_args=output, - compile_only_args=' '.join(compiler.get_compile_only_args()) - ) - description = ' description = Precompiling header %s.\n' % '$in' + output = compiler.get_output_args('$out') + command = compiler.get_exelist() + ['$ARGS'] + quoted_depargs + output + compiler.get_compile_only_args() + ['$in'] + description = 'Precompiling header $in.' if isinstance(compiler, VisualStudioCCompiler): - deps = ' deps = msvc\n' + deps = 'msvc' + depfile = None else: - deps = ' deps = gcc\n' - deps += ' depfile = $DEPFILE\n' - outfile.write(rule) - outfile.write(command) - outfile.write(deps) - outfile.write(description) - outfile.write('\n') + deps = 'gcc' + depfile = '$DEPFILE' + self.add_rule(NinjaRule(rule, command, [], description, deps=deps, + depfile=depfile)) - def generate_compile_rules(self, outfile): + def generate_compile_rules(self): for langname, compiler in self.build.compilers.items(): if compiler.get_id() == 'clang': - self.generate_llvm_ir_compile_rule(compiler, False, outfile) - self.generate_compile_rule_for(langname, compiler, False, outfile) - self.generate_pch_rule_for(langname, compiler, False, outfile) + self.generate_llvm_ir_compile_rule(compiler, False) + self.generate_compile_rule_for(langname, compiler, False) + self.generate_pch_rule_for(langname, compiler, False) if self.environment.is_cross_build(): cclist = self.build.cross_compilers for langname, compiler in cclist.items(): if compiler.get_id() == 'clang': - self.generate_llvm_ir_compile_rule(compiler, True, outfile) - self.generate_compile_rule_for(langname, compiler, True, outfile) - self.generate_pch_rule_for(langname, compiler, True, outfile) - outfile.write('\n') + self.generate_llvm_ir_compile_rule(compiler, True) + self.generate_compile_rule_for(langname, compiler, True) + self.generate_pch_rule_for(langname, compiler, True) - def generate_generator_list_rules(self, target, outfile): + def generate_generator_list_rules(self, target): # CustomTargets have already written their rules and # CustomTargetIndexes don't actually get generated, so write rules for # GeneratedLists here for genlist in target.get_generated_sources(): if isinstance(genlist, (build.CustomTarget, build.CustomTargetIndex)): continue - self.generate_genlist_for_target(genlist, target, outfile) + self.generate_genlist_for_target(genlist, target) def replace_paths(self, target, args, override_subdir=None): if override_subdir: @@ -1750,7 +1750,7 @@ rule FORTRAN_DEP_HACK%s args = [x.replace('\\', '/') for x in args] return args - def generate_genlist_for_target(self, genlist, target, outfile): + def generate_genlist_for_target(self, genlist, target): generator = genlist.get_generator() subdir = genlist.subdir exe = generator.get_exe() @@ -1811,7 +1811,7 @@ rule FORTRAN_DEP_HACK%s if isinstance(exe, build.BuildTarget): elem.add_dep(self.get_target_filename(exe)) elem.add_item('COMMAND', cmd) - elem.write(outfile) + self.add_build(elem) def scan_fortran_module_outputs(self, target): """ @@ -1945,7 +1945,7 @@ rule FORTRAN_DEP_HACK%s def get_link_debugfile_args(self, linker, target, outname): return linker.get_link_debugfile_args(outname) - def generate_llvm_ir_compile(self, target, outfile, src): + def generate_llvm_ir_compile(self, target, src): compiler = get_compiler_for_source(target.compilers.values(), src) commands = CompilerArgs(compiler) # Compiler args for compiling this target @@ -1977,7 +1977,7 @@ rule FORTRAN_DEP_HACK%s # current compiler. commands = commands.to_native() element.add_item('ARGS', commands) - element.write(outfile) + self.add_build(element) return rel_obj def get_source_dir_include_args(self, target, compiler): @@ -2098,7 +2098,7 @@ rule FORTRAN_DEP_HACK%s commands += compiler.get_include_args(self.get_target_private_dir(target), False) return commands - def generate_single_compile(self, target, outfile, src, is_generated=False, header_deps=None, order_deps=None): + def generate_single_compile(self, target, src, is_generated=False, header_deps=None, order_deps=None): """ Compiles C/C++, ObjC/ObjC++, Fortran, and D sources """ @@ -2175,7 +2175,7 @@ rule FORTRAN_DEP_HACK%s if srcfile == src: depelem = NinjaBuildElement(self.all_outputs, modfile, 'FORTRAN_DEP_HACK' + crstr, rel_obj) - depelem.write(outfile) + self.add_build(depelem) commands += compiler.get_module_outdir_args(self.get_target_private_dir(target)) element = NinjaBuildElement(self.all_outputs, rel_obj, compiler_name, rel_src) @@ -2196,7 +2196,7 @@ rule FORTRAN_DEP_HACK%s element.add_orderdep(i) element.add_item('DEPFILE', dep_file) element.add_item('ARGS', commands) - element.write(outfile) + self.add_build(element) return rel_obj def add_header_deps(self, target, ninja_element, header_deps): @@ -2259,7 +2259,7 @@ rule FORTRAN_DEP_HACK%s dep = dst + '.' + compiler.get_depfile_suffix() return commands, dep, dst, [] # Gcc does not create an object file during pch generation. - def generate_pch(self, target, outfile, header_deps=None): + def generate_pch(self, target, header_deps=None): header_deps = header_deps if header_deps is not None else [] cstr = '' pch_objects = [] @@ -2293,10 +2293,10 @@ rule FORTRAN_DEP_HACK%s self.add_header_deps(target, elem, header_deps) elem.add_item('ARGS', commands) elem.add_item('DEPFILE', dep) - elem.write(outfile) + self.add_build(elem) return pch_objects - def generate_shsym(self, outfile, target): + def generate_shsym(self, target): target_name = target.get_filename() target_file = self.get_target_filename(target) targetdir = self.get_target_private_dir(target) @@ -2304,7 +2304,7 @@ rule FORTRAN_DEP_HACK%s elem = NinjaBuildElement(self.all_outputs, symname, 'SHSYM', target_file) if self.environment.is_cross_build(): elem.add_item('CROSS', '--cross-host=' + self.environment.machines.host.system) - elem.write(outfile) + self.add_build(elem) def get_cross_stdlib_link_args(self, target, linker): if isinstance(target, build.StaticLibrary) or not target.is_cross: @@ -2439,7 +2439,7 @@ rule FORTRAN_DEP_HACK%s return guessed_dependencies + absolute_libs - def generate_link(self, target, outfile, outname, obj_list, linker, extra_args=None, stdlib_args=None): + def generate_link(self, target, outname, obj_list, linker, extra_args=None, stdlib_args=None): extra_args = extra_args if extra_args is not None else [] stdlib_args = stdlib_args if stdlib_args is not None else [] if isinstance(target, build.StaticLibrary): @@ -2447,7 +2447,7 @@ rule FORTRAN_DEP_HACK%s else: linker_base = linker.get_language() # Fixme. if isinstance(target, build.SharedLibrary): - self.generate_shsym(outfile, target) + self.generate_shsym(target) crstr = '' if target.is_cross: crstr = '_CROSS' @@ -2600,38 +2600,38 @@ rule FORTRAN_DEP_HACK%s except OSError: mlog.debug("Library versioning disabled because we do not have symlink creation privileges.") - def generate_custom_target_clean(self, outfile, trees): + def generate_custom_target_clean(self, trees): e = NinjaBuildElement(self.all_outputs, 'meson-clean-ctlist', 'CUSTOM_COMMAND', 'PHONY') d = CleanTrees(self.environment.get_build_dir(), trees) d_file = os.path.join(self.environment.get_scratch_dir(), 'cleantrees.dat') e.add_item('COMMAND', self.environment.get_build_command() + ['--internal', 'cleantrees', d_file]) e.add_item('description', 'Cleaning custom target directories.') - e.write(outfile) + self.add_build(e) # Alias that runs the target defined above - self.create_target_alias('meson-clean-ctlist', outfile) + self.create_target_alias('meson-clean-ctlist') # Write out the data file passed to the script with open(d_file, 'wb') as ofile: pickle.dump(d, ofile) return 'clean-ctlist' - def generate_gcov_clean(self, outfile): + def generate_gcov_clean(self): gcno_elem = NinjaBuildElement(self.all_outputs, 'meson-clean-gcno', 'CUSTOM_COMMAND', 'PHONY') script_root = self.environment.get_script_dir() clean_script = os.path.join(script_root, 'delwithsuffix.py') gcno_elem.add_item('COMMAND', mesonlib.python_command + [clean_script, '.', 'gcno']) gcno_elem.add_item('description', 'Deleting gcno files.') - gcno_elem.write(outfile) + self.add_build(gcno_elem) # Alias that runs the target defined above - self.create_target_alias('meson-clean-gcno', outfile) + self.create_target_alias('meson-clean-gcno') gcda_elem = NinjaBuildElement(self.all_outputs, 'meson-clean-gcda', 'CUSTOM_COMMAND', 'PHONY') script_root = self.environment.get_script_dir() clean_script = os.path.join(script_root, 'delwithsuffix.py') gcda_elem.add_item('COMMAND', mesonlib.python_command + [clean_script, '.', 'gcda']) gcda_elem.add_item('description', 'Deleting gcda files.') - gcda_elem.write(outfile) + self.add_build(gcda_elem) # Alias that runs the target defined above - self.create_target_alias('meson-clean-gcda', outfile) + self.create_target_alias('meson-clean-gcda') def get_user_option_args(self): cmds = [] @@ -2642,7 +2642,7 @@ rule FORTRAN_DEP_HACK%s # affect behavior in any other way. return sorted(cmds) - def generate_dist(self, outfile): + def generate_dist(self): elem = NinjaBuildElement(self.all_outputs, 'meson-dist', 'CUSTOM_COMMAND', 'PHONY') elem.add_item('DESC', 'Creating source packages') elem.add_item('COMMAND', self.environment.get_build_command() + [ @@ -2651,22 +2651,22 @@ rule FORTRAN_DEP_HACK%s self.environment.build_dir, ] + self.environment.get_build_command()) elem.add_item('pool', 'console') - elem.write(outfile) + self.add_build(elem) # Alias that runs the target defined above - self.create_target_alias('meson-dist', outfile) + self.create_target_alias('meson-dist') - def generate_scanbuild(self, outfile): + def generate_scanbuild(self): cmd = self.environment.get_build_command() + \ ['--internal', 'scanbuild', self.environment.source_dir, self.environment.build_dir] + \ self.environment.get_build_command() + self.get_user_option_args() elem = NinjaBuildElement(self.all_outputs, 'meson-scan-build', 'CUSTOM_COMMAND', 'PHONY') elem.add_item('COMMAND', cmd) elem.add_item('pool', 'console') - elem.write(outfile) + self.add_build(elem) # Alias that runs the target defined above - self.create_target_alias('meson-scan-build', outfile) + self.create_target_alias('meson-scan-build') - def generate_clangformat(self, outfile): + def generate_clangformat(self): import shutil target_name = 'clang-format' if shutil.which('clang-format') is None: @@ -2681,22 +2681,22 @@ rule FORTRAN_DEP_HACK%s elem = NinjaBuildElement(self.all_outputs, 'meson-' + target_name, 'CUSTOM_COMMAND', 'PHONY') elem.add_item('COMMAND', cmd) elem.add_item('pool', 'console') - elem.write(outfile) - self.create_target_alias('meson-' + target_name, outfile) + self.add_build(elem) + self.create_target_alias('meson-' + target_name) # For things like scan-build and other helper tools we might have. - def generate_utils(self, outfile): - self.generate_scanbuild(outfile) - self.generate_clangformat(outfile) + def generate_utils(self): + self.generate_scanbuild() + self.generate_clangformat() cmd = self.environment.get_build_command() + ['--internal', 'uninstall'] elem = NinjaBuildElement(self.all_outputs, 'meson-uninstall', 'CUSTOM_COMMAND', 'PHONY') elem.add_item('COMMAND', cmd) elem.add_item('pool', 'console') - elem.write(outfile) + self.add_build(elem) # Alias that runs the target defined above - self.create_target_alias('meson-uninstall', outfile) + self.create_target_alias('meson-uninstall') - def generate_ending(self, outfile): + def generate_ending(self): targetlist = [] for t in self.get_build_by_default_targets().values(): # Add the first output of each target to the 'all' target so that @@ -2704,16 +2704,13 @@ rule FORTRAN_DEP_HACK%s targetlist.append(os.path.join(self.get_target_dir(t), t.get_outputs()[0])) elem = NinjaBuildElement(self.all_outputs, 'all', 'phony', targetlist) - elem.write(outfile) - - default = 'default all\n\n' - outfile.write(default) + self.add_build(elem) elem = NinjaBuildElement(self.all_outputs, 'meson-clean', 'CUSTOM_COMMAND', 'PHONY') elem.add_item('COMMAND', [self.ninja_command, '-t', 'clean']) elem.add_item('description', 'Cleaning.') # Alias that runs the above-defined meson-clean target - self.create_target_alias('meson-clean', outfile) + self.create_target_alias('meson-clean') # If we have custom targets in this project, add all their outputs to # the list that is passed to the `cleantrees.py` script. The script @@ -2728,26 +2725,26 @@ rule FORTRAN_DEP_HACK%s for o in t.get_outputs(): ctlist.append(os.path.join(self.get_target_dir(t), o)) if ctlist: - elem.add_dep(self.generate_custom_target_clean(outfile, ctlist)) + elem.add_dep(self.generate_custom_target_clean(ctlist)) if 'b_coverage' in self.environment.coredata.base_options and \ self.environment.coredata.base_options['b_coverage'].value: - self.generate_gcov_clean(outfile) + self.generate_gcov_clean() elem.add_dep('clean-gcda') elem.add_dep('clean-gcno') - elem.write(outfile) + self.add_build(elem) deps = self.get_regen_filelist() elem = NinjaBuildElement(self.all_outputs, 'build.ninja', 'REGENERATE_BUILD', deps) elem.add_item('pool', 'console') - elem.write(outfile) + self.add_build(elem) elem = NinjaBuildElement(self.all_outputs, 'reconfigure', 'REGENERATE_BUILD', 'PHONY') elem.add_item('pool', 'console') - elem.write(outfile) + self.add_build(elem) elem = NinjaBuildElement(self.all_outputs, deps, 'phony', '') - elem.write(outfile) + self.add_build(elem) def get_introspection_data(self, target_id, target): if target_id not in self.introspection_data or len(self.introspection_data[target_id]) == 0: |