Xcode: can generate object files with generators.

pull/8633/head
Jussi Pakkanen 4 years ago
parent 9dfd53dc40
commit 50cf8bcaba
  1. 85
      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,62 @@ 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)
commands = [["cd", workdir]] # Array of arrays, each one a single command, will get concatenated below.
ofile_abs = []
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)
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 +1079,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 = {}

Loading…
Cancel
Save