|
|
|
@ -112,7 +112,7 @@ rsp_threshold = get_rsp_threshold() |
|
|
|
|
# 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_UNQUOTED', 'DESC', 'pool', 'description', 'targetdep'} |
|
|
|
|
raw_names = {'DEPFILE_UNQUOTED', 'DESC', 'pool', 'description', 'targetdep', 'dyndep'} |
|
|
|
|
|
|
|
|
|
NINJA_QUOTE_BUILD_PAT = re.compile(r"[$ :\n]") |
|
|
|
|
NINJA_QUOTE_VAR_PAT = re.compile(r"[$ \n]") |
|
|
|
@ -134,6 +134,11 @@ Please report this error with a test case to the Meson bug tracker.'''.format(te |
|
|
|
|
raise MesonException(errmsg) |
|
|
|
|
return quote_re.sub(r'$\g<0>', text) |
|
|
|
|
|
|
|
|
|
class TargetDependencyScannerInfo: |
|
|
|
|
def __init__(self, private_dir: str, source2object: T.Dict[str, str]): |
|
|
|
|
self.private_dir = private_dir |
|
|
|
|
self.source2object = source2object |
|
|
|
|
|
|
|
|
|
@unique |
|
|
|
|
class Quoting(Enum): |
|
|
|
|
both = 0 |
|
|
|
@ -683,10 +688,17 @@ int dummy; |
|
|
|
|
return False |
|
|
|
|
|
|
|
|
|
def generate_target(self, target): |
|
|
|
|
try: |
|
|
|
|
if isinstance(target, build.BuildTarget): |
|
|
|
|
os.makedirs(self.get_target_private_dir_abs(target)) |
|
|
|
|
except FileExistsError: |
|
|
|
|
pass |
|
|
|
|
if isinstance(target, build.CustomTarget): |
|
|
|
|
self.generate_custom_target(target) |
|
|
|
|
if isinstance(target, build.RunTarget): |
|
|
|
|
self.generate_run_target(target) |
|
|
|
|
compiled_sources = [] |
|
|
|
|
source2object = {} |
|
|
|
|
name = target.get_id() |
|
|
|
|
if name in self.processed_targets: |
|
|
|
|
return |
|
|
|
@ -784,10 +796,12 @@ 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, src) |
|
|
|
|
o, s = self.generate_llvm_ir_compile(target, src) |
|
|
|
|
else: |
|
|
|
|
o = self.generate_single_compile(target, src, True, |
|
|
|
|
o, s = self.generate_single_compile(target, src, True, |
|
|
|
|
order_deps=header_deps) |
|
|
|
|
compiled_sources.append(s) |
|
|
|
|
source2object[s] = o |
|
|
|
|
obj_list.append(o) |
|
|
|
|
|
|
|
|
|
use_pch = self.environment.coredata.base_options.get('b_pch', False) |
|
|
|
@ -822,32 +836,84 @@ 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, src, 'vala', [], header_deps)) |
|
|
|
|
o, s = self.generate_single_compile(target, src, 'vala', [], header_deps) |
|
|
|
|
obj_list.append(o) |
|
|
|
|
|
|
|
|
|
# Generate compile targets for all the pre-existing sources for this target |
|
|
|
|
for src in target_sources.values(): |
|
|
|
|
if not self.environment.is_header(src): |
|
|
|
|
if self.environment.is_llvm_ir(src): |
|
|
|
|
obj_list.append(self.generate_llvm_ir_compile(target, src)) |
|
|
|
|
o, s = self.generate_llvm_ir_compile(target, src) |
|
|
|
|
obj_list.append(o) |
|
|
|
|
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, src, False, [], header_deps)) |
|
|
|
|
o, s = self.generate_single_compile(target, src, False, [], header_deps) |
|
|
|
|
obj_list.append(o) |
|
|
|
|
compiled_sources.append(s) |
|
|
|
|
source2object[s] = o |
|
|
|
|
|
|
|
|
|
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, src, True, unity_deps + header_deps)) |
|
|
|
|
o, s = self.generate_single_compile(target, src, True, unity_deps + header_deps) |
|
|
|
|
obj_list.append(o) |
|
|
|
|
compiled_sources.append(s) |
|
|
|
|
source2object[s] = o |
|
|
|
|
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) |
|
|
|
|
else: |
|
|
|
|
final_obj_list = obj_list |
|
|
|
|
elem = self.generate_link(target, outname, final_obj_list, linker, pch_objects, stdlib_args=stdlib_args) |
|
|
|
|
self.generate_dependency_scan_target(target, compiled_sources, source2object) |
|
|
|
|
self.generate_shlib_aliases(target, self.get_target_dir(target)) |
|
|
|
|
self.add_build(elem) |
|
|
|
|
|
|
|
|
|
def should_scan_target(self, target): |
|
|
|
|
if 'cpp' not in target.compilers: |
|
|
|
|
return False |
|
|
|
|
# Currently only the preview version of Visual Studio is supported. |
|
|
|
|
cpp = target.compilers['cpp'] |
|
|
|
|
if cpp.get_id() != 'msvc': |
|
|
|
|
return False |
|
|
|
|
if not mesonlib.current_vs_supports_modules(): |
|
|
|
|
return False |
|
|
|
|
if mesonlib.version_compare(cpp.version, '<19.28.28617'): |
|
|
|
|
return False |
|
|
|
|
if mesonlib.version_compare(self.ninja_version, '<1.10.0'): |
|
|
|
|
return False |
|
|
|
|
return True |
|
|
|
|
|
|
|
|
|
def generate_dependency_scan_target(self, target, compiled_sources, source2object): |
|
|
|
|
if not self.should_scan_target(target): |
|
|
|
|
return |
|
|
|
|
depscan_file = self.get_dep_scan_file_for(target) |
|
|
|
|
pickle_base = target.name + '.dat' |
|
|
|
|
pickle_file = os.path.join(self.get_target_private_dir(target), pickle_base).replace('\\', '/') |
|
|
|
|
pickle_abs = os.path.join(self.get_target_private_dir_abs(target), pickle_base).replace('\\', '/') |
|
|
|
|
rule_name = 'cppscan' |
|
|
|
|
scan_sources = self.select_sources_to_scan(compiled_sources) |
|
|
|
|
elem = NinjaBuildElement(self.all_outputs, depscan_file, rule_name, scan_sources) |
|
|
|
|
elem.add_item('picklefile', pickle_file) |
|
|
|
|
scaninfo = TargetDependencyScannerInfo(self.get_target_private_dir(target), source2object) |
|
|
|
|
with open(pickle_abs, 'wb') as p: |
|
|
|
|
pickle.dump(scaninfo, p) |
|
|
|
|
self.add_build(elem) |
|
|
|
|
|
|
|
|
|
def select_sources_to_scan(self, compiled_sources): |
|
|
|
|
# in practice pick up C++ and Fortran files. If some other language |
|
|
|
|
# requires scanning (possibly Java to deal with inner class files) |
|
|
|
|
# then add them here. |
|
|
|
|
selected_sources = [] |
|
|
|
|
for source in compiled_sources: |
|
|
|
|
ext = os.path.splitext(source)[1][1:] |
|
|
|
|
if ext in compilers.lang_suffixes['cpp']: |
|
|
|
|
selected_sources.append(source) |
|
|
|
|
return selected_sources |
|
|
|
|
|
|
|
|
|
def process_target_dependencies(self, target): |
|
|
|
|
for t in target.get_dependencies(): |
|
|
|
|
if t.get_id() not in self.processed_targets: |
|
|
|
@ -1074,6 +1140,8 @@ int dummy; |
|
|
|
|
self.rules = [] |
|
|
|
|
self.ruledict = {} |
|
|
|
|
|
|
|
|
|
self.add_rule_comment(NinjaComment('Rules for module scanning.')) |
|
|
|
|
self.generate_scanner_rules() |
|
|
|
|
self.add_rule_comment(NinjaComment('Rules for compiling.')) |
|
|
|
|
self.generate_compile_rules() |
|
|
|
|
self.add_rule_comment(NinjaComment('Rules for linking.')) |
|
|
|
@ -1107,6 +1175,8 @@ int dummy; |
|
|
|
|
self.build_elements.append(comment) |
|
|
|
|
|
|
|
|
|
def add_rule(self, rule): |
|
|
|
|
if rule.name in self.ruledict: |
|
|
|
|
raise MesonException('Tried to add rule {} twice.'.format(rule.name)) |
|
|
|
|
self.rules.append(rule) |
|
|
|
|
self.ruledict[rule.name] = rule |
|
|
|
|
|
|
|
|
@ -1957,6 +2027,26 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) |
|
|
|
|
self.add_rule(NinjaRule(rule, command, [], description, deps=deps, |
|
|
|
|
depfile=depfile)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def generate_scanner_rules(self): |
|
|
|
|
scanner_languages = {'cpp'} # Fixme, add Fortran. |
|
|
|
|
for for_machine in MachineChoice: |
|
|
|
|
clist = self.environment.coredata.compilers[for_machine] |
|
|
|
|
for langname, compiler in clist.items(): |
|
|
|
|
if langname not in scanner_languages: |
|
|
|
|
continue |
|
|
|
|
rulename = '{}scan'.format(langname) |
|
|
|
|
if rulename in self.ruledict: |
|
|
|
|
# Scanning command is the same for native and cross compilation. |
|
|
|
|
continue |
|
|
|
|
command = self.environment.get_build_command() + \ |
|
|
|
|
['--internal', 'depscan'] |
|
|
|
|
args = ['$picklefile', '$out', '$in'] |
|
|
|
|
description = 'Module scanner for {}.'.format(langname) |
|
|
|
|
rule = NinjaRule(rulename, command, args, description) |
|
|
|
|
self.add_rule(rule) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def generate_compile_rules(self): |
|
|
|
|
for for_machine in MachineChoice: |
|
|
|
|
clist = self.environment.coredata.compilers[for_machine] |
|
|
|
@ -2217,7 +2307,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) |
|
|
|
|
element = NinjaBuildElement(self.all_outputs, rel_obj, compiler_name, rel_src) |
|
|
|
|
element.add_item('ARGS', commands) |
|
|
|
|
self.add_build(element) |
|
|
|
|
return rel_obj |
|
|
|
|
return (rel_obj, rel_src) |
|
|
|
|
|
|
|
|
|
def get_source_dir_include_args(self, target, compiler): |
|
|
|
|
curdir = target.get_subdir() |
|
|
|
@ -2439,8 +2529,22 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) |
|
|
|
|
element.add_orderdep(i) |
|
|
|
|
element.add_item('DEPFILE', dep_file) |
|
|
|
|
element.add_item('ARGS', commands) |
|
|
|
|
|
|
|
|
|
self.add_dependency_scanner_entries_to_element(target, compiler, element) |
|
|
|
|
self.add_build(element) |
|
|
|
|
return rel_obj |
|
|
|
|
assert(isinstance(rel_obj, str)) |
|
|
|
|
assert(isinstance(rel_src, str)) |
|
|
|
|
return (rel_obj, rel_src.replace('\\', '/')) |
|
|
|
|
|
|
|
|
|
def add_dependency_scanner_entries_to_element(self, target, compiler, element): |
|
|
|
|
if not self.should_scan_target(target): |
|
|
|
|
return |
|
|
|
|
dep_scan_file = self.get_dep_scan_file_for(target) |
|
|
|
|
element.add_item('dyndep', dep_scan_file) |
|
|
|
|
element.add_orderdep(dep_scan_file) |
|
|
|
|
|
|
|
|
|
def get_dep_scan_file_for(self, target): |
|
|
|
|
return os.path.join(self.get_target_private_dir(target), 'depscan.dd') |
|
|
|
|
|
|
|
|
|
def add_header_deps(self, target, ninja_element, header_deps): |
|
|
|
|
for d in header_deps: |
|
|
|
|