Merge pull request #8787 from mesonbuild/xcodeprojecttree

Rework Xcode project navigation tree
pull/8794/head
Jussi Pakkanen 4 years ago committed by GitHub
commit 45acef1241
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 166
      mesonbuild/backend/xcodebackend.py

@ -58,6 +58,12 @@ OPT2XCODEOPT = {'0': '0',
BOOL2XCODEBOOL = {True: 'YES', False: 'NO'}
LINKABLE_EXTENSIONS = {'.o', '.a', '.obj', '.so', '.dylib'}
class FileTreeEntry:
def __init__(self):
self.subdirs = {}
self.targets = []
class PbxItem:
def __init__(self, value, comment = ''):
self.value = value
@ -267,6 +273,7 @@ class XCodeBackend(backends.Backend):
self.generate_pbxdep_map()
self.generate_containerproxy_map()
self.generate_target_file_maps()
self.generate_build_file_maps()
self.proj_dir = os.path.join(self.environment.get_build_dir(), self.build.project_name + '.xcodeproj')
os.makedirs(self.proj_dir, exist_ok=True)
self.proj_file = os.path.join(self.proj_dir, 'project.pbxproj')
@ -321,7 +328,6 @@ class XCodeBackend(backends.Backend):
xcodetype = XCODETYPEMAP.get(fname.split('.')[-1].lower())
if not xcodetype:
xcodetype = 'sourcecode.unknown'
mlog.warning(f'Unknown file type "{fname}" fallbacking to "{xcodetype}". Xcode project might be malformed.')
return xcodetype
def generate_filemap(self):
@ -509,6 +515,12 @@ class XCodeBackend(backends.Backend):
else:
raise RuntimeError('Unknown input type ' + str(o))
def generate_build_file_maps(self):
for buildfile in self.interpreter.get_build_def_files():
assert(isinstance(buildfile, str))
self.buildfile_ids[buildfile] = self.gen_id()
self.fileref_ids[buildfile] = self.gen_id()
def generate_source_phase_map(self):
self.source_phase = {}
for t in self.build_targets:
@ -825,6 +837,18 @@ class XCodeBackend(backends.Backend):
custom_dict.add_item('sourceTree', 'SOURCE_ROOT')
objects_dict.add_item(self.custom_target_output_fileref[o], custom_dict)
for buildfile in self.interpreter.get_build_def_files():
basename = os.path.split(buildfile)[1]
buildfile_dict = PbxDict()
typestr = self.get_xcodetype(buildfile)
buildfile_dict.add_item('isa', 'PBXFileReference')
buildfile_dict.add_item('explicitFileType', '"' + typestr + '"')
buildfile_dict.add_item('name', f'"{basename}"')
buildfile_dict.add_item('path', f'"{buildfile}"')
buildfile_dict.add_item('refType', 0)
buildfile_dict.add_item('sourceTree', 'SOURCE_ROOT')
objects_dict.add_item(self.fileref_ids[buildfile], buildfile_dict)
def generate_pbx_frameworks_buildphase(self, objects_dict):
for t in self.build_targets.values():
bt_dict = PbxDict()
@ -848,33 +872,22 @@ class XCodeBackend(backends.Backend):
for t in self.custom_targets:
groupmap[t] = self.gen_id()
target_src_map[t] = self.gen_id()
sources_id = self.gen_id()
projecttree_id = self.gen_id()
resources_id = self.gen_id()
products_id = self.gen_id()
frameworks_id = self.gen_id()
frameworks_id = self.gen_id()
main_dict = PbxDict()
objects_dict.add_item(self.maingroup_id, main_dict)
main_dict.add_item('isa', 'PBXGroup')
main_children = PbxArray()
main_dict.add_item('children', main_children)
main_children.add_item(sources_id, 'Sources')
main_children.add_item(projecttree_id, 'Project tree')
main_children.add_item(resources_id, 'Resources')
main_children.add_item(products_id, 'Products')
main_children.add_item(frameworks_id, 'Frameworks')
main_dict.add_item('sourceTree', '"<group>"')
# Sources
source_dict = PbxDict()
objects_dict.add_item(sources_id, source_dict, 'Sources')
source_dict.add_item('isa', 'PBXGroup')
source_children = PbxArray()
source_dict.add_item('children', source_children)
for t in self.build_targets:
source_children.add_item(groupmap[t], t)
for t in self.custom_targets:
source_children.add_item(groupmap[t], t)
source_dict.add_item('name', 'Sources')
source_dict.add_item('sourceTree', '"<group>"')
self.add_projecttree(objects_dict, projecttree_id)
resource_dict = PbxDict()
objects_dict.add_item(resources_id, resource_dict, 'Resources')
@ -900,44 +913,6 @@ class XCodeBackend(backends.Backend):
frameworks_dict.add_item('name', 'Frameworks')
frameworks_dict.add_item('sourceTree', '"<group>"')
# Targets
for tname, t in self.build_targets.items():
target_dict = PbxDict()
objects_dict.add_item(groupmap[tname], target_dict, tname)
target_dict.add_item('isa', 'PBXGroup')
target_children = PbxArray()
target_dict.add_item('children', target_children)
target_children.add_item(target_src_map[tname], 'Source files')
if t.subproject:
target_dict.add_item('name', f'"{t.subproject}{t}"')
else:
target_dict.add_item('name', f'"{t}"')
target_dict.add_item('sourceTree', '"<group>"')
source_files_dict = PbxDict()
objects_dict.add_item(target_src_map[tname], source_files_dict, 'Source files')
source_files_dict.add_item('isa', 'PBXGroup')
source_file_children = PbxArray()
source_files_dict.add_item('children', source_file_children)
for s in t.sources:
if isinstance(s, mesonlib.File):
s = os.path.join(s.subdir, s.fname)
elif isinstance(s, str):
s = os.path.joni(t.subdir, s)
else:
continue
source_file_children.add_item(self.fileref_ids[(tname, s)], s)
for o in t.objects:
if isinstance(o, build.ExtractedObjects):
# Do not show built object files in the project tree.
continue
if isinstance(o, mesonlib.File):
o = os.path.join(o.subdir, o.fname)
else:
o = os.path.join(t.subdir, o)
source_file_children.add_item(self.fileref_ids[(tname, o)], o)
source_files_dict.add_item('name', '"Source files"')
source_files_dict.add_item('sourceTree', '"<group>"')
for tname, t in self.custom_targets.items():
target_dict = PbxDict()
objects_dict.add_item(groupmap[tname], target_dict, tname)
@ -977,6 +952,89 @@ class XCodeBackend(backends.Backend):
product_dict.add_item('name', 'Products')
product_dict.add_item('sourceTree', '"<group>"')
def write_group_target_entry(self, objects_dict, t):
tid = t.get_id()
group_id = self.gen_id()
target_dict = PbxDict()
objects_dict.add_item(group_id, target_dict, tid)
target_dict.add_item('isa', 'PBXGroup')
target_children = PbxArray()
target_dict.add_item('children', target_children)
target_dict.add_item('name', f'"{t} · target"')
target_dict.add_item('sourceTree', '"<group>"')
source_files_dict = PbxDict()
for s in t.sources:
if isinstance(s, mesonlib.File):
s = os.path.join(s.subdir, s.fname)
elif isinstance(s, str):
s = os.path.joni(t.subdir, s)
else:
continue
target_children.add_item(self.fileref_ids[(tid, s)], s)
for o in t.objects:
if isinstance(o, build.ExtractedObjects):
# Do not show built object files in the project tree.
continue
if isinstance(o, mesonlib.File):
o = os.path.join(o.subdir, o.fname)
else:
o = os.path.join(t.subdir, o)
target_children.add_item(self.fileref_ids[(tid, o)], o)
source_files_dict.add_item('name', '"Source files"')
source_files_dict.add_item('sourceTree', '"<group>"')
return group_id
def add_projecttree(self, objects_dict, projecttree_id):
root_dict = PbxDict()
objects_dict.add_item(projecttree_id, root_dict, "Root of project tree")
root_dict.add_item('isa', 'PBXGroup')
target_children = PbxArray()
root_dict.add_item('children', target_children)
root_dict.add_item('name', '"Project root"')
root_dict.add_item('sourceTree', '"<group>"')
project_tree = self.generate_project_tree()
self.write_tree(objects_dict, project_tree, target_children, '')
def write_tree(self, objects_dict, tree_node, children_array, current_subdir):
subdir_dict = PbxDict()
subdir_children = PbxArray()
for subdir_name, subdir_node in tree_node.subdirs.items():
subdir_id = self.gen_id()
objects_dict.add_item(subdir_id, subdir_dict)
children_array.add_item(subdir_id)
subdir_dict.add_item('isa', 'PBXGroup')
subdir_dict.add_item('children', subdir_children)
subdir_dict.add_item('name', f'"{subdir_name}"')
subdir_dict.add_item('sourceTree', '"<group>"')
self.write_tree(objects_dict, subdir_node, subdir_children, os.path.join(current_subdir, subdir_name))
for target in tree_node.targets:
group_id = self.write_group_target_entry(objects_dict, target)
children_array.add_item(group_id)
potentials = [os.path.join(current_subdir, 'meson.build'),
os.path.join(current_subdir, 'meson_options.txt')]
for bf in potentials:
i = self.fileref_ids.get(bf, None)
if i:
children_array.add_item(i)
def generate_project_tree(self):
tree_info = FileTreeEntry()
for tname, t in self.build_targets.items():
self.add_target_to_tree(tree_info, t)
return tree_info
def add_target_to_tree(self, tree_root, t):
current_node = tree_root
path_segments = t.subdir.split('/')
for s in path_segments:
if not s:
continue
if s not in current_node.subdirs:
current_node.subdirs[s] = FileTreeEntry()
current_node = current_node.subdirs[s]
current_node.targets.append(t)
def generate_pbx_native_target(self, objects_dict):
for tname, idval in self.native_targets.items():

Loading…
Cancel
Save