ios: Fix Xcode project buildgen.

Change-Id: Ib9701a2c7c7ebc55ba69e1e6fa9cde59d3e4c557
Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2378400
Commit-Queue: Justin Cohen <justincohen@chromium.org>
Reviewed-by: Mark Mentovai <mark@chromium.org>
This commit is contained in:
Justin Cohen 2020-08-27 10:14:38 -04:00 committed by Commit Bot
parent 59e8120e7a
commit 71695216f9

View File

@ -29,6 +29,7 @@ import filecmp
import json
import hashlib
import os
import re
import shutil
import subprocess
import sys
@ -45,11 +46,10 @@ class XcodeProject(object):
while True:
self.counter += 1
str_id = "%s %s %d" % (parent_name, obj['isa'], self.counter)
new_id = hashlib.sha1(
str_id.encode("utf-8")).hexdigest()[:24].upper()
new_id = hashlib.sha1(str_id.encode("utf-8")).hexdigest()[:24].upper()
# Make sure ID is unique. It's possible there could be an id
# conflict since this is run after GN runs.
# Make sure ID is unique. It's possible there could be an id conflict
# since this is run after GN runs.
if new_id not in self.objects:
self.objects[new_id] = obj
return new_id
@ -77,7 +77,8 @@ def CopyTreeIfChanged(source, target):
if not os.path.isdir(target):
os.makedirs(target)
for name in os.listdir(source):
CopyTreeIfChanged(os.path.join(source, name),
CopyTreeIfChanged(
os.path.join(source, name),
os.path.join(target, name))
@ -85,8 +86,7 @@ def LoadXcodeProjectAsJSON(project_dir):
"""Return Xcode project at |path| as a JSON string."""
return check_output([
'plutil', '-convert', 'json', '-o', '-',
os.path.join(project_dir, 'project.pbxproj')
])
os.path.join(project_dir, 'project.pbxproj')])
def WriteXcodeProject(output_path, json_string):
@ -95,7 +95,8 @@ def WriteXcodeProject(output_path, json_string):
temp_file.write(json_string.encode("utf-8"))
temp_file.flush()
subprocess.check_call(['plutil', '-convert', 'xml1', temp_file.name])
CopyFileIfChanged(temp_file.name,
CopyFileIfChanged(
temp_file.name,
os.path.join(output_path, 'project.pbxproj'))
@ -118,17 +119,23 @@ def UpdateXcodeProject(project_dir, configurations, root_dir):
# Teach build shell script to look for the configuration and platform.
if isa == 'PBXShellScriptBuildPhase':
shell_path = value['shellPath']
if shell_path.endswith('/sh'):
value['shellScript'] = value['shellScript'].replace(
'ninja -C .',
'ninja -C "../${CONFIGURATION}${EFFECTIVE_PLATFORM_NAME}"')
elif re.search('[ /]python[23]?$', shell_path):
value['shellScript'] = value['shellScript'].replace(
'ninja_params = [ \'-C\', \'.\' ]',
'ninja_params = [ \'-C\', \'../\' + os.environ[\'CONFIGURATION\']'
' + os.environ[\'EFFECTIVE_PLATFORM_NAME\'] ]')
# Add new configuration, using the first one as default.
if isa == 'XCConfigurationList':
value['defaultConfigurationName'] = configurations[0]
objects_to_remove.extend(value['buildConfigurations'])
build_config_template = project.objects[value['buildConfigurations']
[0]]
build_config_template = project.objects[value['buildConfigurations'][0]]
build_config_template['buildSettings']['CONFIGURATION_BUILD_DIR'] = \
'$(PROJECT_DIR)/../$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)'
@ -175,6 +182,7 @@ def GetOrCreateRootGroup(project, root_object, group_name):
class ObjectKey(object):
"""Wrapper around PBXFileReference and PBXGroup for sorting.
A PBXGroup represents a "directory" containing a list of files in an
@ -259,17 +267,15 @@ def GetFolderForPath(project, group_object, path):
new_root = objects[child]
break
if not new_root:
# If the folder isn't found we could just cram it into the leaf
# existing folder, but that leads to folders with tons of README.md
# inside.
# If the folder isn't found we could just cram it into the leaf existing
# folder, but that leads to folders with tons of README.md inside.
new_root = CreateGroup(project, group_object, folder)
group_object = new_root
return group_object
def ConvertGnXcodeProject(root_dir, input_dir, output_dir, configurations):
'''Tweak the Xcode project generated by gn to support multiple
configurations.
'''Tweak the Xcode project generated by gn to support multiple configurations.
The Xcode projects generated by "gn gen --ide" only supports a single
platform and configuration (as the platform and configuration are set
@ -289,15 +295,15 @@ def ConvertGnXcodeProject(root_dir, input_dir, output_dir, configurations):
# project name "all.xcodeproj").
for project_name in ('all.xcodeproj', 'products.xcodeproj'):
if os.path.exists(os.path.join(input_dir, project_name)):
UpdateXcodeProject(os.path.join(input_dir, project_name),
UpdateXcodeProject(
os.path.join(input_dir, project_name),
configurations, root_dir)
CopyTreeIfChanged(os.path.join(input_dir, project_name),
os.path.join(output_dir, project_name))
else:
shutil.rmtree(os.path.join(output_dir, project_name),
ignore_errors=True)
shutil.rmtree(os.path.join(output_dir, project_name), ignore_errors=True)
# Copy all.xcworkspace if it exists (will be removed in a future gn version).
workspace_name = 'all.xcworkspace'
@ -305,25 +311,23 @@ def ConvertGnXcodeProject(root_dir, input_dir, output_dir, configurations):
CopyTreeIfChanged(os.path.join(input_dir, workspace_name),
os.path.join(output_dir, workspace_name))
else:
shutil.rmtree(os.path.join(output_dir, workspace_name),
ignore_errors=True)
shutil.rmtree(os.path.join(output_dir, workspace_name), ignore_errors=True)
def Main(args):
parser = argparse.ArgumentParser(
description='Convert GN Xcode projects for iOS.')
parser.add_argument(
'input', help='directory containing [product|all] Xcode projects.')
'input',
help='directory containing [product|all] Xcode projects.')
parser.add_argument(
'output', help='directory where to generate the iOS configuration.')
parser.add_argument('--add-config',
dest='configurations',
default=[],
action='append',
'output',
help='directory where to generate the iOS configuration.')
parser.add_argument(
'--add-config', dest='configurations', default=[], action='append',
help='configuration to add to the Xcode project')
parser.add_argument('--root',
type=os.path.abspath,
required=True,
parser.add_argument(
'--root', type=os.path.abspath, required=True,
help='root directory of the project')
args = parser.parse_args(args)
@ -348,13 +352,10 @@ def Main(args):
return 1
if not args.configurations:
sys.stderr.write(
'At least one configuration required, see --add-config.\n')
sys.stderr.write('At least one configuration required, see --add-config.\n')
return 1
ConvertGnXcodeProject(args.root, args.input, args.output,
args.configurations)
ConvertGnXcodeProject(args.root, args.input, args.output, args.configurations)
if __name__ == '__main__':
sys.exit(Main(sys.argv[1:]))