Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(166)

Unified Diff: pylib/gyp/generator/ninja.py

Issue 1160773005: Support for Swift language and Clang modules for ninja generator. Base URL: https://chromium.googlesource.com/external/gyp@master
Patch Set: Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | pylib/gyp/mac_tool.py » ('j') | pylib/gyp/xcode_emulation.py » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pylib/gyp/generator/ninja.py
diff --git a/pylib/gyp/generator/ninja.py b/pylib/gyp/generator/ninja.py
index 6823f4ffbdaf25ad8676650f65e55cd3e58b2a30..602f9fdb36d5a1406303974736d0376b4b21acd5 100644
--- a/pylib/gyp/generator/ninja.py
+++ b/pylib/gyp/generator/ninja.py
@@ -140,6 +140,10 @@ class Target(object):
# On Windows, incremental linking requires linking against all the .objs
# that compose a .lib (rather than the .lib itself). That list is stored
# here.
+
+ # Path to the file representing completion of building module, if any.
+ self.module_stamp = None
+
self.component_objs = None
# Windows only. The import .lib is the output of a build step, but
# because dependents only link against the lib (not both the lib and the
@@ -376,6 +380,9 @@ class NinjaWriter(object):
# should be used for linking.
self.uses_cpp = False
+ # Track if there are any swift sources
+ self.uses_swift = False
+
self.is_mac_bundle = gyp.xcode_emulation.IsMacBundle(self.flavor, spec)
self.xcode_settings = self.msvs_settings = None
if self.flavor == 'mac':
@@ -408,6 +415,7 @@ class NinjaWriter(object):
# any of its compile steps.
actions_depends = []
compile_depends = []
+ module_depends = []
# TODO(evan): it is rather confusing which things are lists and which
# are strings. Fix these.
if 'dependencies' in spec:
@@ -416,8 +424,14 @@ class NinjaWriter(object):
target = self.target_outputs[dep]
actions_depends.append(target.PreActionInput(self.flavor))
compile_depends.append(target.PreCompileInput())
+ module_depends.append(target.module_stamp)
actions_depends = filter(None, actions_depends)
compile_depends = filter(None, compile_depends)
+ module_depends = filter(None, module_depends)
+ if (self.flavor == 'mac' and
+ self.xcode_settings.AreModulesEnabled(config_name)):
+ compile_depends += module_depends
+
actions_depends = self.WriteCollapsedDependencies('actions_depends',
actions_depends)
compile_depends = self.WriteCollapsedDependencies('compile_depends',
@@ -439,6 +453,14 @@ class NinjaWriter(object):
# because no compile ever depends on them.
compile_depends_stamp = (self.target.actions_stamp or compile_depends)
+ if self.flavor == 'mac':
+ # Module should be written before compilaton, because Swift compiler
+ # use it
+ module_stamp = self.WriteModule(self.ninja, compile_depends_stamp,
+ config_name, spec)
+ if module_stamp:
+ compile_depends_stamp = module_stamp
+
# Write out the compilation steps, if any.
link_deps = []
sources = extra_sources + spec.get('sources', [])
@@ -855,6 +877,236 @@ class NinjaWriter(object):
('binary', isBinary)])
bundle_depends.append(out)
+ def _AddSwiftModuleExt(self, module):
+ return module + '.swiftmodule'
+
+ def _GetSwiftModulePath(self, config_name, spec, arch=None):
+ module_path = self._AddSwiftModuleExt(
+ self.xcode_settings.GetProductModuleName(config_name))
+ if self._IsFramework(spec):
+ module_path = os.path.join(
+ self.xcode_settings.GetBundleModulesFolderPath(), module_path)
+ if arch:
+ # Fixing path for armv7, since Xcode expects it to have 'arm' name instead
+ if arch == 'armv7':
+ arch = 'arm'
+ module_path = os.path.join(module_path, self._AddSwiftModuleExt(arch))
+ return module_path
+
+ def WriteFrameworkHeaders(self, ninja_file, headers, headers_dir):
+ outputs = []
+ for header in headers:
+ out_path = os.path.join(headers_dir, os.path.basename(header))
+ outputs.append(out_path)
+ self.ninja.build(out_path, 'mac_tool', header,
+ variables=[('mactool_cmd', 'copy-bundle-resource'), \
+ ('binary', False)])
+ return outputs
+
+ def _GetModuleMapFilePath(self):
+ return os.path.join(self.xcode_settings.GetBundleModulesFolderPath(),
+ 'module.modulemap')
+
+ def _IsFramework(self, spec):
+ is_framework = (spec['type'] == 'shared_library') and self.is_mac_bundle
+ return is_framework
+
+ def WriteModule(self, ninja_file, predepends, config_name, spec):
+ """Write build rules to build Clang module."""
+ if not self.xcode_settings.IsModuleDefined(config_name):
+ return None
+ if not self._IsFramework(spec):
+ # There are no any actions by Xcode for non-framework targets
+ return None
+
+ assert(self.xcode_settings.AreModulesEnabled(config_name))
+
+ ninja_file.newline()
+
+ module_inputs = []
+ # Copying headers to framework
+ public_headers = map(self.GypPathToNinja,
+ list(spec.get('mac_framework_headers', [])))
+ module_inputs += self.WriteFrameworkHeaders(
+ ninja_file, public_headers,
+ self.xcode_settings.GetBundlePublicHeadersFolderPath())
+
+ private_headers = map(self.GypPathToNinja,
+ list(spec.get('mac_framework_private_headers', [])))
+ module_inputs += self.WriteFrameworkHeaders(
+ ninja_file, private_headers,
+ self.xcode_settings.GetBundlePrivateHeadersFolderPath())
+
+ module_name = self.xcode_settings.GetProductModuleName(config_name)
+ umbrella_header = None
+ for header in public_headers:
+ filename, _ = os.path.splitext(os.path.basename(header))
+ if filename == module_name:
+ umbrella_header = header
+ break
+
+ assert(umbrella_header)
+
+ # Building module map file in the /Modules folder
+ module_map_path = self._GetModuleMapFilePath()
+ variables = {
+ 'module_name': module_name,
+ 'umbrella_header': os.path.basename(umbrella_header),
+ 'map_file': module_map_path }
+ module_map_stamp = self.GypPathToUniqueOutput('modulemap.stamp')
+ self.ninja.build(module_map_stamp, 'modulemap', [umbrella_header],
+ variables=variables)
+ module_inputs.append(module_map_stamp)
+
+ # Resulting module stamp
+ module_stamp = self.GypPathToUniqueOutput('module.stamp')
+ self.ninja.build(module_stamp, 'stamp', module_inputs,
+ order_only=predepends)
+ self.target.module_stamp = module_stamp
+ ninja_file.newline()
+ return module_stamp
+
+ def WriteSwiftSourcesForArch(self, ninja_file, config_name, sources,
+ predepends, spec, arch=None):
+ assert(self.flavor == 'mac')
+
+ # Collecting all Swift sources
+ swift_sources = []
+ for source in sources:
+ filename, ext = os.path.splitext(source)
+ ext = ext[1:]
+ if ext == 'swift':
+ swift_sources.append(self.GypPathToNinja(source))
+ if not swift_sources:
+ return ([], None)
+
+ self.uses_swift = True
+
+ if not arch:
+ arch = self.archs[0]
+
+ # Writing compile flags
+ swift_compile_flags = self.xcode_settings.GetSwiftCompileFlags(
+ config_name, self.GypPathToNinja, arch)
+ self.WriteVariableList(ninja_file, 'swift_compile_flags',
+ map(self.ExpandSpecial, swift_compile_flags))
+ ninja_file.newline()
+
+ # Writing per-file rules
+ link_deps = []
+ partial_modules = []
+ for source in swift_sources:
+ filename, ext = os.path.splitext(os.path.basename(source))
+ obj_path = self.GypPathToUniqueOutput(filename + self.obj_ext)
+ obj_path = AddArch(obj_path, arch)
+ src_module_path = self.GypPathToUniqueOutput(
+ self._AddSwiftModuleExt(filename))
+ src_module_path = AddArch(src_module_path, arch)
+
+ compile_input = [source]
+ for another_source in swift_sources:
+ if source != another_source:
+ compile_input.append(another_source)
+
+ variables = {'out_obj': obj_path, 'out_module': src_module_path}
+ ninja_file.build([obj_path, src_module_path], 'swift', compile_input,
+ variables=variables,
+ order_only=predepends)
+
+ link_deps.append(obj_path)
+ partial_modules.append(src_module_path)
+
+ ninja_file.newline()
+
+ # Writing Swift merge flags
+ swift_merge_flags = self.xcode_settings.GetSwiftMergeFlags(
+ config_name, self.GypPathToNinja, arch)
+ self.WriteVariableList(ninja_file, 'swift_merge_flags',
+ map(self.ExpandSpecial, swift_merge_flags))
+ ninja_file.newline()
+
+
+ # Writing header for first arch without arch extension,
+ # for it to be used by Objc sources
+ header_arch = None if arch == self.archs[0] else arch
+ header_path = self.xcode_settings.GetSwiftHeaderPath(
+ config_name, self.GypPathToNinja, header_arch)
+ module_path = self._GetSwiftModulePath(config_name, spec, arch)
+ variables = {'out_module': module_path, 'out_header': header_path}
+ ninja_file.build([module_path, header_path], 'swiftmerge',
+ partial_modules, variables=variables)
+ ninja_file.newline()
+
+ return (link_deps, module_path)
+
+ def WriteSwiftModule(self, ninja_file, config_name, spec):
+ """Write build rules to build Swift module data"""
+ if not self.uses_swift:
+ return
+
+ assert(self.xcode_settings.AreModulesEnabled(config_name))
+
+ ninja_file.newline()
+
+ module_inputs = []
+ map_depends = []
+ for arch in self.archs:
+ swift_module_path = self._GetSwiftModulePath(config_name, spec, arch)
+ module_inputs.append(swift_module_path)
+ map_depends.append(swift_module_path)
+
+ if self._IsFramework(spec):
+ assert(self.xcode_settings.IsModuleDefined(config_name))
+
+ # Copying Swift header to framework
+ swift_header = self.xcode_settings.GetSwiftHeaderPath(
+ config_name, self.GypPathToNinja)
+ module_inputs += self.WriteFrameworkHeaders(
+ ninja_file, [swift_header],
+ self.xcode_settings.GetBundlePublicHeadersFolderPath())
+
+ # Appending Swift info to the module map file in the /Modules folder
+ module_name = self.xcode_settings.GetProductModuleName(config_name)
+ module_map_path = self._GetModuleMapFilePath()
+ variables = {
+ 'module_name': module_name,
+ 'swift_header': os.path.basename(swift_header),
+ 'map_file': module_map_path }
+ module_map_stamp = self.GypPathToUniqueOutput('swiftmodulemap.stamp')
+ self.ninja.build(module_map_stamp, 'swiftmodulemap', [swift_header],
+ order_only=map_depends, variables=variables)
+ module_inputs.append(module_map_stamp)
+
+ # Resulting Swift actions stamp
+ module_stamp = self.GypPathToUniqueOutput('swift_module.stamp')
+ self.ninja.build(module_stamp, 'stamp', module_inputs)
+ self.target.module_stamp = module_stamp
+ ninja_file.newline()
+
+ def AppendSwiftLinkerOptions(self, ldflags, implicit_deps, config_name, spec,
+ arch):
+ if not self.uses_swift:
+ return
+ if arch is None:
+ arch = self.archs[0]
+ module_path = self._GetSwiftModulePath(config_name, spec, arch)
+ ldflags += self.xcode_settings.GetSwiftLdflags(config_name, module_path)
+ implicit_deps.add(module_path)
+
+ def CopySwiftLibsToBundle(self, spec):
+ is_final = spec['type'] in ('executable', 'loadable_module')
+ if not gyp.xcode_emulation.IsSwiftSupported() or not is_final:
+ return None
+
+ # Copying all needed Swift dylibs right into the bundle
+ app_frameworks_path = (
+ self.xcode_settings.GetBundleFrameworksFolderPath())
+ swift_libs_path = self.xcode_settings.GetSwiftLibsPath(self.config_name)
+ variables = {'swift_libs_path': swift_libs_path}
+ self.ninja.build(app_frameworks_path, 'copyswiftlibs', self.target.binary,
+ variables=variables)
+ return app_frameworks_path
+
def WriteSources(self, ninja_file, config_name, config, sources, predepends,
precompiled_header, spec):
"""Write build rules to compile all of |sources|."""
@@ -976,6 +1228,13 @@ class NinjaWriter(object):
map(self.ExpandSpecial, arflags))
ninja_file.newline()
outputs = []
+
+ if self.flavor == 'mac':
+ swift_outputs, swift_module = self.WriteSwiftSourcesForArch(
+ ninja_file, config_name, sources, predepends, spec, arch)
+ outputs += swift_outputs
+ predepends = swift_module or predepends
+
has_rc_source = False
for source in sources:
filename, ext = os.path.splitext(source)
@@ -1139,6 +1398,8 @@ class NinjaWriter(object):
self.ExpandSpecial(generator_default_variables['PRODUCT_DIR']),
self.GypPathToNinja, arch)
ldflags = env_ldflags + ldflags
+ self.AppendSwiftLinkerOptions(
+ ldflags, implicit_deps, config_name, spec, arch)
elif self.flavor == 'win':
manifest_base_name = self.GypPathToUniqueOutput(
self.ComputeOutputFileName(spec))
@@ -1248,6 +1509,7 @@ class NinjaWriter(object):
return linked_binary
def WriteTarget(self, spec, config_name, config, link_deps, compile_deps):
+ self.WriteSwiftModule(self.ninja, config_name, spec)
extra_link_deps = any(self.target_outputs.get(dep).Linkable()
for dep in spec.get('dependencies', [])
if dep in self.target_outputs)
@@ -1300,6 +1562,14 @@ class NinjaWriter(object):
def WriteMacBundle(self, spec, mac_bundle_depends, is_empty):
assert self.is_mac_bundle
+
+ swift_frameworks = self.CopySwiftLibsToBundle(spec)
+ if swift_frameworks:
+ mac_bundle_depends.append(swift_frameworks)
+
+ if self.target.module_stamp:
+ mac_bundle_depends.append(self.target.module_stamp)
+
package_framework = spec['type'] in ('shared_library', 'loadable_module')
output = self.ComputeMacBundleOutput()
if is_empty:
@@ -1922,6 +2192,10 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
master_ninja.variable(
'readelf', GetEnvironFallback(['READELF_target', 'READELF'], readelf))
+ if flavor == 'mac' and gyp.xcode_emulation.IsSwiftSupported():
+ master_ninja.variable(
+ 'swift', subprocess.check_output(['xcrun', '-f', 'swift']))
+
if generator_supports_multiple_toolsets:
if not cc_host:
cc_host = cc
@@ -2106,6 +2380,32 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
depfile='$out.d',
deps=deps)
master_ninja.rule(
+ 'swift',
+ description='SWIFT $out_obj',
+ command=('$swift -frontend -c -primary-file $in $swift_compile_flags '
+ '-emit-module-path $out_module '
+ '-o $out_obj'))
+ master_ninja.rule(
+ 'swiftmerge',
+ description='SWIFT MERGE $out_module',
+ command=('$swift -frontend -emit-module $in $swift_merge_flags '
+ '-emit-objc-header-path $out_header '
+ '-o $out_module'))
+ master_ninja.rule(
+ 'copyswiftlibs',
+ description='COPY SWIFT LIBS $out',
+ command=('./gyp-mac-tool copy-swift-libs $swift_libs_path $out $in'))
+ master_ninja.rule(
+ 'modulemap',
+ description='MODULE MAP $map_file',
+ command=('./gyp-mac-tool build-module-map-file '
+ '$module_name $umbrella_header $map_file $out'))
+ master_ninja.rule(
+ 'swiftmodulemap',
+ description='SWIFT MODULE MAP $map_file',
+ command=('./gyp-mac-tool append-swift-to-module-map-file '
+ '$module_name $swift_header $map_file $out'))
+ master_ninja.rule(
'alink',
description='LIBTOOL-STATIC $out, POSTBUILDS',
command='rm -f $out && '
« no previous file with comments | « no previous file | pylib/gyp/mac_tool.py » ('j') | pylib/gyp/xcode_emulation.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698