From 60cf80c844d26121c86c1d9da0062f7e2495bd6a Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sun, 11 Apr 2021 16:12:56 +0300 Subject: Xcode: can generate object files with generators. --- mesonbuild/backend/xcodebackend.py | 84 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/mesonbuild/backend/xcodebackend.py b/mesonbuild/backend/xcodebackend.py index 2bd6acf..d94ffde 100644 --- a/mesonbuild/backend/xcodebackend.py +++ b/mesonbuild/backend/xcodebackend.py @@ -189,6 +189,7 @@ class XCodeBackend(backends.Backend): self.test_command_id = self.gen_id() self.test_buildconf_id = self.gen_id() self.top_level_dict = PbxDict() + self.generator_outputs = {} # In Xcode files are not accessed via their file names, but rather every one of them # gets an unique id. More precisely they get one unique id per target they are used # in. If you generate only one id per file and use them, compilation will work but the @@ -252,6 +253,7 @@ class XCodeBackend(backends.Backend): self.generate_native_target_map() self.generate_native_frameworks_map() self.generate_custom_target_map() + self.generate_generator_target_map() self.generate_source_phase_map() self.generate_target_dependency_map() self.generate_pbxdep_map() @@ -378,6 +380,17 @@ class XCodeBackend(backends.Backend): self.custom_target_output_buildfile[o] = self.gen_id() self.custom_target_output_fileref[o] = self.gen_id() + def generate_generator_target_map(self): + # Generator objects do not have natural unique ids + # so use a counter. + for tname, t in self.build_targets.items(): + generator_id = 0 + for s in t.generated: + if isinstance(s, build.GeneratedList): + self.shell_targets[(tname, generator_id)] = self.gen_id() + generator_id += 1 + # FIXME add outputs. + def generate_native_frameworks_map(self): self.native_frameworks = {} self.native_frameworks_fileref = {} @@ -745,9 +758,13 @@ class XCodeBackend(backends.Backend): ntarget_dict.add_item('buildConfigurationList', self.buildconflistmap[tname], f'Build configuration list for PBXNativeTarget "{tname}"') buildphases_array = PbxArray() ntarget_dict.add_item('buildPhases', buildphases_array) + generator_id = 0 for g in t.generated: if isinstance(g, build.CustomTarget): buildphases_array.add_item(self.shell_targets[g.get_id()], f'/* {g.name} */') + elif isinstance(g, build.GeneratedList): + buildphases_array.add_item(self.shell_targets[(tname, generator_id)], 'Generator {}/{}'.format(generator_id, tname)) + generator_id += 1 for bpname, bpval in t.buildphasemap.items(): buildphases_array.add_item(bpval, f'{bpname} yyy') ntarget_dict.add_item('buildRules', PbxArray()) @@ -819,6 +836,10 @@ class XCodeBackend(backends.Backend): cmdstr = ' '.join(["'%s'" % i for i in cmd]) shell_dict.add_item('shellScript', f'"{cmdstr}"') shell_dict.add_item('showEnvVarsInLog', 0) + self.generate_custom_target_shell_build_phases(objects_dict) + self.generate_generator_target_shell_build_phases(objects_dict) + + def generate_custom_target_shell_build_phases(self, objects_dict): # Custom targets are shell build phases in Xcode terminology. for tname, t in self.custom_targets.items(): if not isinstance(t, build.CustomTarget): @@ -842,6 +863,61 @@ class XCodeBackend(backends.Backend): custom_dict.add_item('shellScript', f'"cd {workdir}; {cmdstr}"') custom_dict.add_item('showEnvVarsInLog', 0) + def generate_generator_target_shell_build_phases(self, objects_dict): + for tname, t in self.build_targets.items(): + 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) + self.shell_targets[(tname, id)] = self.gen_id() + 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()) + outarray = PbxArray() + gen_dict.add_item('name', '"Generator {}/{}"'.format(generator_id, tname)) + gen_dict.add_item('outputPaths', outarray) + ofilenames = [] + infiles_abs = [] + commands = [["cd", workdir]] # Array of arrays, each one a single command, will get concatenated below. + ofile_abs = [] + for i in infilelist: + infiles_abs = i.absolute_path(self.environment.get_source_dir(), self.environment.get_build_dir()) # FIXME, make it handle other input types. + 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) + ofile_abs.append(os.path.join(self.environment.get_build_dir(), o)) + args = [x.replace("@INPUT@", infilename).replace('@OUTPUT@', o) for x in base_args] + args = self.replace_outputs(args, self.get_target_private_dir(t), outfilelist) + commands.append(exe_arr + args) + for of in ofile_abs: + outarray.add_item(of) + self.generator_outputs[(tname, generator_id)] = ofile_abs + 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) + generator_id += 1 + + def generate_pbx_sources_build_phase(self, objects_dict): for name in self.source_phase.keys(): phase_dict = PbxDict() @@ -1002,6 +1078,14 @@ class XCodeBackend(backends.Backend): if objname_abs not in added_objs: added_objs.add(objname_abs) ldargs += [r'\"' + objname_abs + r'\"'] + generator_id = 0 + for o in target.generated: + if isinstance(o, build.GeneratedList): + outputs = self.generator_outputs[target_name, generator_id] + generator_id += 1 + for o_abs in outputs: + if o_abs.endswith('.o') or o_abs.endswith('.obj'): + ldargs += [r'\"' + o_abs + r'\"'] ldstr = ' '.join(ldargs) valid = self.buildconfmap[target_name][buildtype] langargs = {} -- cgit v1.1