diff options
author | Jussi Pakkanen <jpakkane@gmail.com> | 2021-04-17 22:27:04 +0300 |
---|---|---|
committer | Jussi Pakkanen <jpakkane@gmail.com> | 2021-04-18 19:19:29 +0300 |
commit | 68dda2a2419f6741c6585dad29bdce7f41464ec0 (patch) | |
tree | 18065effa0fc35ae4bc0774c90709da83d16c8ed | |
parent | e422e9c634997313350a5dc3136980cac2567043 (diff) | |
download | meson-68dda2a2419f6741c6585dad29bdce7f41464ec0.zip meson-68dda2a2419f6741c6585dad29bdce7f41464ec0.tar.gz meson-68dda2a2419f6741c6585dad29bdce7f41464ec0.tar.bz2 |
Xcode: fix generators that take custom targets as inputs.
-rw-r--r-- | mesonbuild/backend/xcodebackend.py | 201 | ||||
-rw-r--r-- | mesonbuild/build.py | 10 |
2 files changed, 128 insertions, 83 deletions
diff --git a/mesonbuild/backend/xcodebackend.py b/mesonbuild/backend/xcodebackend.py index 9635e82..54fc229 100644 --- a/mesonbuild/backend/xcodebackend.py +++ b/mesonbuild/backend/xcodebackend.py @@ -396,25 +396,36 @@ class XCodeBackend(backends.Backend): for genlist in t.generated: if not isinstance(genlist, build.GeneratedList): continue - k = (tname, generator_id) - assert(k not in self.shell_targets) - self.shell_targets[k] = self.gen_id() - ofile_abs = [] - for i in genlist.get_inputs(): - for o_base in genlist.get_outputs_for(i): - o = os.path.join(self.get_target_private_dir(t), o_base) - ofile_abs.append(os.path.join(self.environment.get_build_dir(), o)) - assert(k not in self.generator_outputs) - self.generator_outputs[k] = ofile_abs - buildfile_ids = [] - fileref_ids = [] - for i in range(len(ofile_abs)): - buildfile_ids.append(self.gen_id()) - fileref_ids.append(self.gen_id()) - self.generator_buildfile_ids[k] = buildfile_ids - self.generator_fileref_ids[k] = fileref_ids + self.gen_single_target_map(genlist, tname, t, generator_id) generator_id += 1 # FIXME add outputs. + for tname, t in self.custom_targets.items(): + generator_id = 0 + for genlist in t.sources: + if not isinstance(genlist, build.GeneratedList): + continue + self.gen_single_target_map(genlist, tname, t, generator_id) + generator_id += 1 + + def gen_single_target_map(self, genlist, tname, t, generator_id): + k = (tname, generator_id) + assert(k not in self.shell_targets) + self.shell_targets[k] = self.gen_id() + ofile_abs = [] + for i in genlist.get_inputs(): + for o_base in genlist.get_outputs_for(i): + o = os.path.join(self.get_target_private_dir(t), o_base) + ofile_abs.append(os.path.join(self.environment.get_build_dir(), o)) + assert(k not in self.generator_outputs) + self.generator_outputs[k] = ofile_abs + buildfile_ids = [] + fileref_ids = [] + for i in range(len(ofile_abs)): + buildfile_ids.append(self.gen_id()) + fileref_ids.append(self.gen_id()) + self.generator_buildfile_ids[k] = buildfile_ids + self.generator_fileref_ids[k] = fileref_ids + def generate_native_frameworks_map(self): self.native_frameworks = {} @@ -494,7 +505,18 @@ class XCodeBackend(backends.Backend): for tname, t in self.build.get_custom_targets().items(): ct_id = self.gen_id() self.custom_aggregate_targets[tname] = ct_id - aggregated_targets.append((ct_id, tname, self.buildconflistmap[tname], [self.shell_targets[tname]], [])) + build_phases = [] + dependencies = [] + generator_id = 0 + for s in t.sources: + if not isinstance(s, build.GeneratedList): + continue + build_phases.append(self.shell_targets[(tname, generator_id)]) + for d in s.depends: + dependencies.append(self.pbx_custom_dep_map[d.get_id()]) + generator_id += 1 + build_phases.append(self.shell_targets[tname]) + aggregated_targets.append((ct_id, tname, self.buildconflistmap[tname], build_phases, dependencies)) # Sort objects by ID before writing sorted_aggregated_targets = sorted(aggregated_targets, key=operator.itemgetter(0)) @@ -573,17 +595,7 @@ class XCodeBackend(backends.Backend): for g in t.generated: if not isinstance(g, build.GeneratedList): continue - file_ids = self.generator_buildfile_ids[(tname, generator_id)] - ref_ids = self.generator_fileref_ids[tname, generator_id] - assert(len(ref_ids) == len(file_ids)) - for i in range(len(file_ids)): - file_o = file_ids[i] - ref_id = ref_ids[i] - odict = PbxDict() - objects_dict.add_item(file_o, odict) - odict.add_item('isa', 'PBXBuildFile') - odict.add_item('fileRef', ref_id) - + self.create_generator_shellphase(objects_dict, tname, generator_id) generator_id += 1 # Custom targets are shell build phases in Xcode terminology. @@ -596,6 +608,24 @@ class XCodeBackend(backends.Backend): objects_dict.add_item(self.custom_target_output_buildfile[o], custom_dict, f'/* {o} */') custom_dict.add_item('isa', 'PBXBuildFile') custom_dict.add_item('fileRef', self.custom_target_output_fileref[o]) + generator_id = 0 + for g in t.sources: + if not isinstance(g, build.GeneratedList): + continue + self.create_generator_shellphase(objects_dict, tname, generator_id) + generator_id += 1 + + def create_generator_shellphase(self, objects_dict, tname, generator_id): + file_ids = self.generator_buildfile_ids[(tname, generator_id)] + ref_ids = self.generator_fileref_ids[(tname, generator_id)] + assert(len(ref_ids) == len(file_ids)) + for i in range(len(file_ids)): + file_o = file_ids[i] + ref_id = ref_ids[i] + odict = PbxDict() + objects_dict.add_item(file_o, odict) + odict.add_item('isa', 'PBXBuildFile') + odict.add_item('fileRef', ref_id) def generate_pbx_build_style(self, objects_dict): # FIXME: Xcode 9 and later does not uses PBXBuildStyle and it gets removed. Maybe we can remove this part. @@ -1033,59 +1063,68 @@ class XCodeBackend(backends.Backend): generator_id = 0 for genlist in t.generated: if isinstance(genlist, build.GeneratedList): - generator = genlist.get_generator() - exe = generator.get_exe() - exe_arr = self.build_target_to_cmd_array(exe) - workdir = self.environment.get_build_dir() - gen_dict = PbxDict() - objects_dict.add_item(self.shell_targets[(tname, generator_id)], gen_dict, '"Generator {}/{}"'.format(generator_id, tname)) - infilelist = genlist.get_inputs() - outfilelist = genlist.get_outputs() - gen_dict.add_item('isa', 'PBXShellScriptBuildPhase') - gen_dict.add_item('buildActionMask', 2147483647) - gen_dict.add_item('files', PbxArray()) - gen_dict.add_item('inputPaths', PbxArray()) - gen_dict.add_item('name', '"Generator {}/{}"'.format(generator_id, tname)) - commands = [["cd", workdir]] # Array of arrays, each one a single command, will get concatenated below. - k = (tname, generator_id) - ofile_abs = self.generator_outputs[k] - outarray = PbxArray() - gen_dict.add_item('outputPaths', outarray) - for of in ofile_abs: - outarray.add_item(of) - for i in infilelist: - # This might be needed to be added to inputPaths. It's not done yet as it is - # unclear whether it is necessary, what actually happens when it is defined - # and currently the build works without it. - #infile_abs = i.absolute_path(self.environment.get_source_dir(), self.environment.get_build_dir()) - infilename = i.rel_to_builddir(self.build_to_src) - base_args = generator.get_arglist(infilename) - for o_base in genlist.get_outputs_for(i): - o = os.path.join(self.get_target_private_dir(t), o_base) - args = [x.replace("@INPUT@", infilename).replace('@OUTPUT@', o).replace('@BUILD_DIR@', self.get_target_private_dir(t)) for x in base_args] - args = self.replace_outputs(args, self.get_target_private_dir(t), outfilelist) - args = self.replace_extra_args(args, genlist) - if generator.capture: - # When capturing, stdout is the output. Forward it with the shell. - full_command = ['('] + exe_arr + args + ['>', o, ')'] - else: - full_command = exe_arr + args - commands.append(full_command) - gen_dict.add_item('runOnlyForDeploymentPostprocessing', 0) - gen_dict.add_item('shellPath', '/bin/sh') - quoted_cmds = [] - for cmnd in commands: - q = [] - for c in cmnd: - if ' ' in c: - q.append(f'\\"{c}\\"') - else: - q.append(c) - quoted_cmds.append(' '.join(q)) - cmdstr = '"' + ' && '.join(quoted_cmds) + '"' - gen_dict.add_item('shellScript', cmdstr) - gen_dict.add_item('showEnvVarsInLog', 0) + self.generate_single_generator_phase(tname, t, genlist, generator_id, objects_dict) generator_id += 1 + for tname, t in self.custom_targets.items(): + generator_id = 0 + for genlist in t.sources: + if isinstance(genlist, build.GeneratedList): + self.generate_single_generator_phase(tname, t, genlist, generator_id, objects_dict) + generator_id += 1 + + def generate_single_generator_phase(self, tname, t, genlist, generator_id, objects_dict): + generator = genlist.get_generator() + exe = generator.get_exe() + exe_arr = self.build_target_to_cmd_array(exe) + workdir = self.environment.get_build_dir() + gen_dict = PbxDict() + objects_dict.add_item(self.shell_targets[(tname, generator_id)], gen_dict, '"Generator {}/{}"'.format(generator_id, tname)) + infilelist = genlist.get_inputs() + outfilelist = genlist.get_outputs() + gen_dict.add_item('isa', 'PBXShellScriptBuildPhase') + gen_dict.add_item('buildActionMask', 2147483647) + gen_dict.add_item('files', PbxArray()) + gen_dict.add_item('inputPaths', PbxArray()) + gen_dict.add_item('name', '"Generator {}/{}"'.format(generator_id, tname)) + commands = [["cd", workdir]] # Array of arrays, each one a single command, will get concatenated below. + k = (tname, generator_id) + ofile_abs = self.generator_outputs[k] + outarray = PbxArray() + gen_dict.add_item('outputPaths', outarray) + for of in ofile_abs: + outarray.add_item(of) + for i in infilelist: + # This might be needed to be added to inputPaths. It's not done yet as it is + # unclear whether it is necessary, what actually happens when it is defined + # and currently the build works without it. + #infile_abs = i.absolute_path(self.environment.get_source_dir(), self.environment.get_build_dir()) + infilename = i.rel_to_builddir(self.build_to_src) + base_args = generator.get_arglist(infilename) + for o_base in genlist.get_outputs_for(i): + o = os.path.join(self.get_target_private_dir(t), o_base) + args = [x.replace("@INPUT@", infilename).replace('@OUTPUT@', o).replace('@BUILD_DIR@', self.get_target_private_dir(t)) for x in base_args] + args = self.replace_outputs(args, self.get_target_private_dir(t), outfilelist) + args = self.replace_extra_args(args, genlist) + if generator.capture: + # When capturing, stdout is the output. Forward it with the shell. + full_command = ['('] + exe_arr + args + ['>', o, ')'] + else: + full_command = exe_arr + args + commands.append(full_command) + gen_dict.add_item('runOnlyForDeploymentPostprocessing', 0) + gen_dict.add_item('shellPath', '/bin/sh') + quoted_cmds = [] + for cmnd in commands: + q = [] + for c in cmnd: + if ' ' in c: + q.append(f'\\"{c}\\"') + else: + q.append(c) + quoted_cmds.append(' '.join(q)) + cmdstr = '"' + ' && '.join(quoted_cmds) + '"' + gen_dict.add_item('shellScript', cmdstr) + gen_dict.add_item('showEnvVarsInLog', 0) def generate_pbx_sources_build_phase(self, objects_dict): diff --git a/mesonbuild/build.py b/mesonbuild/build.py index ab2866e..69e853f 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -1580,10 +1580,15 @@ class Generator: def process_files(self, name, files, state, preserve_path_from=None, extra_args=None): new = False output = GeneratedList(self, state.subdir, preserve_path_from, extra_args=extra_args if extra_args is not None else []) + #XXX for e in unholder(files): fs = [e] + if isinstance(e, CustomTarget): + output.depends.add(e) + if isinstance(e, CustomTargetIndex): + output.depends.add(e.target) if isinstance(e, (CustomTarget, CustomTargetIndex, GeneratedList)): - self.depends.append(e) + self.depends.append(e) # BUG: this should go in the GeneratedList object, not this object. fs = [] for f in e.get_outputs(): fs.append(File.from_built_file(state.subdir, f)) @@ -1610,6 +1615,7 @@ class GeneratedList: def __init__(self, generator, subdir, preserve_path_from=None, extra_args=None): self.generator = unholder(generator) self.name = self.generator.exe + self.depends = set() # Things this target depends on (because e.g. a custom target was used as input) self.subdir = subdir self.infilelist = [] self.outfilelist = [] @@ -2545,7 +2551,7 @@ class Jar(BuildTarget): class CustomTargetIndex: """A special opaque object returned by indexing a CustomTarget. This object - exists in meson, but acts as a proxy in the backends, making targets depend + exists in Meson, but acts as a proxy in the backends, making targets depend on the CustomTarget it's derived from, but only adding one source file to the sources. """ |