aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Googler <noreply@google.com>2015-06-16 21:10:26 +0000
committerGravatar John Field <jfield@google.com>2015-06-17 15:22:50 +0000
commitaa7cb9a253b2a66a54bf8c65af9a8e7748bf23b9 (patch)
tree9d35c67aa48b79ab4f6398dcadf874dc04e074ba
parente4682895367ad1cc5033d1ef37093a2d6439043b (diff)
Add ability to compile objc_binary targets with Swift sources.
* Swift sources whitelisted * Swift compilation and module merging actions * Swift stdlib copying into IPA action * Special case for signing embedded swift stdlib dylibs during bundle signing * Works with mixed ObjC/Swift sources * Doesn't support working with dependencies from Swift code. * Requires Xcode 6.3.1 for swift compiler and tooling. -- MOS_MIGRATED_REVID=96141887
-rwxr-xr-xcompile.sh2
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/Bundling.java8
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/CompilationArtifacts.java15
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java154
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/IntermediateArtifacts.java30
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/IosSdkCommands.java22
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCommon.java8
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProvider.java8
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/ObjcRuleClasses.java9
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/ReleaseBundlingSupport.java61
-rw-r--r--src/tools/xcode-common/BUILD1
-rw-r--r--src/tools/xcode-common/java/com/google/devtools/build/xcode/swiftstdlibtoolzip/BUILD17
-rw-r--r--src/tools/xcode-common/java/com/google/devtools/build/xcode/swiftstdlibtoolzip/README4
-rw-r--r--src/tools/xcode-common/java/com/google/devtools/build/xcode/swiftstdlibtoolzip/SwiftStdlibToolZip.java59
-rw-r--r--tools/objc/BUILD6
15 files changed, 386 insertions, 18 deletions
diff --git a/compile.sh b/compile.sh
index aaa4ba6e10..047d0e2b67 100755
--- a/compile.sh
+++ b/compile.sh
@@ -111,6 +111,8 @@ if [ $DO_TOOLS_COMPILATION ]; then
tools/objc/precomp_actoolzip_deploy.jar
bazel_bootstrap //src/tools/xcode-common/java/com/google/devtools/build/xcode/ibtoolzip:ibtoolzip_deploy.jar \
tools/objc/precomp_ibtoolzip_deploy.jar
+ bazel_bootstrap //src/tools/xcode-common/java/com/google/devtools/build/xcode/swiftstdlibtoolzip:swiftstdlibtoolzip_deploy.jar \
+ tools/objc/precomp_swiftstdlibtoolzip_deploy.jar
bazel_bootstrap //src/objc_tools/momczip:momczip_deploy.jar \
tools/objc/precomp_momczip_deploy.jar
bazel_bootstrap //src/objc_tools/bundlemerge:bundlemerge_deploy.jar \
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/Bundling.java b/src/main/java/com/google/devtools/build/lib/rules/objc/Bundling.java
index d3545fa7dd..b336096838 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/Bundling.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/Bundling.java
@@ -16,6 +16,7 @@ package com.google.devtools.build.lib.rules.objc;
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.ASSET_CATALOG;
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.BUNDLE_FILE;
+import static com.google.devtools.build.lib.rules.objc.ObjcProvider.Flag.USES_SWIFT;
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.IMPORTED_LIBRARY;
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.LIBRARY;
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.MERGE_ZIP;
@@ -166,6 +167,11 @@ final class Bundling {
for (Artifact storyboard : objcProvider.get(STORYBOARD)) {
mergeZipBuilder.add(intermediateArtifacts.compiledStoryboardZip(storyboard));
}
+
+ if (objcProvider.is(USES_SWIFT)) {
+ mergeZipBuilder.add(intermediateArtifacts.swiftFrameworksFileZip());
+ }
+
return mergeZipBuilder.build();
}
@@ -434,7 +440,7 @@ final class Bundling {
public NestedSet<Artifact> getBundleContentArtifacts() {
return bundleContentArtifacts;
}
-
+
/**
* Returns primary bundle ID to use, can be null.
*/
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationArtifacts.java b/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationArtifacts.java
index 5aac139e57..7d1377b5a5 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationArtifacts.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationArtifacts.java
@@ -16,6 +16,7 @@ package com.google.devtools.build.lib.rules.objc;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.actions.Artifact;
@@ -68,6 +69,7 @@ final class CompilationArtifacts {
private final Iterable<Artifact> nonArcSrcs;
private final Optional<Artifact> archive;
private final Optional<Artifact> pchFile;
+ private final boolean hasSwiftSources;
private CompilationArtifacts(
Iterable<Artifact> srcs,
@@ -78,6 +80,12 @@ final class CompilationArtifacts {
this.nonArcSrcs = Preconditions.checkNotNull(nonArcSrcs);
this.archive = Preconditions.checkNotNull(archive);
this.pchFile = Preconditions.checkNotNull(pchFile);
+ this.hasSwiftSources = Iterables.any(this.srcs, new Predicate<Artifact>() {
+ @Override
+ public boolean apply(Artifact artifact) {
+ return ObjcRuleClasses.SWIFT_SOURCES.matches(artifact.getExecPath());
+ }
+ });
}
public Iterable<Artifact> getSrcs() {
@@ -95,4 +103,11 @@ final class CompilationArtifacts {
public Optional<Artifact> getPchFile() {
return pchFile;
}
+
+ /**
+ * Returns true if any of this target's srcs are Swift source files.
+ */
+ public boolean hasSwiftSources() {
+ return hasSwiftSources;
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java
index bfd4b1819c..d6a5e8eab5 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java
@@ -20,6 +20,7 @@ import static com.google.devtools.build.lib.rules.objc.ObjcProvider.FORCE_LOAD_L
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.FRAMEWORK_DIR;
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.FRAMEWORK_FILE;
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.Flag.USES_CPP;
+import static com.google.devtools.build.lib.rules.objc.ObjcProvider.Flag.USES_SWIFT;
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.HEADER;
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.IMPORTED_LIBRARY;
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.INCLUDE;
@@ -32,12 +33,14 @@ import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.CLANG_PLU
import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.DSYMUTIL;
import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.NON_ARC_SRCS_TYPE;
import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.SRCS_TYPE;
+import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.SWIFT;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.actions.Action;
import com.google.devtools.build.lib.actions.Artifact;
@@ -146,17 +149,24 @@ final class CompilationSupport {
for (Artifact sourceFile : compilationArtifacts.getSrcs()) {
Artifact objFile = intermediateArtifacts.objFile(sourceFile);
objFiles.add(objFile);
- registerCompileAction(sourceFile, objFile, compilationArtifacts.getPchFile(),
- objcProvider, intermediateArtifacts, ImmutableList.of("-fobjc-arc"),
- isCodeCoverageEnabled);
+ if (ObjcRuleClasses.SWIFT_SOURCES.matches(sourceFile.getFilename())) {
+ registerSwiftCompileAction(sourceFile, objFile, intermediateArtifacts);
+ } else {
+ registerCompileAction(sourceFile, objFile, objcProvider, intermediateArtifacts,
+ compilationArtifacts, ImmutableList.of("-fobjc-arc"), isCodeCoverageEnabled);
+ }
}
for (Artifact nonArcSourceFile : compilationArtifacts.getNonArcSrcs()) {
Artifact objFile = intermediateArtifacts.objFile(nonArcSourceFile);
objFiles.add(objFile);
- registerCompileAction(nonArcSourceFile, objFile, compilationArtifacts.getPchFile(),
- objcProvider, intermediateArtifacts, ImmutableList.of("-fno-objc-arc"),
- isCodeCoverageEnabled);
+ registerCompileAction(nonArcSourceFile, objFile, objcProvider, intermediateArtifacts,
+ compilationArtifacts, ImmutableList.of("-fno-objc-arc"), isCodeCoverageEnabled);
+ }
+
+ if (compilationArtifacts.hasSwiftSources()) {
+ registerSwiftModuleMergeAction(intermediateArtifacts, compilationArtifacts);
}
+
for (Artifact archive : compilationArtifacts.getArchive().asSet()) {
registerArchiveActions(intermediateArtifacts, objFiles, archive);
}
@@ -165,14 +175,15 @@ final class CompilationSupport {
private void registerCompileAction(
Artifact sourceFile,
Artifact objFile,
- Optional<Artifact> pchFile,
ObjcProvider objcProvider,
IntermediateArtifacts intermediateArtifacts,
+ CompilationArtifacts compilationArtifacts,
Iterable<String> otherFlags,
boolean isCodeCoverageEnabled) {
ObjcConfiguration objcConfiguration = ObjcRuleClasses.objcConfiguration(ruleContext);
ImmutableList.Builder<String> coverageFlags = new ImmutableList.Builder<>();
ImmutableList.Builder<Artifact> gcnoFiles = new ImmutableList.Builder<>();
+ ImmutableList.Builder<Artifact> additionalInputs = new ImmutableList.Builder<>();
if (isCodeCoverageEnabled) {
coverageFlags.addAll(CLANG_COVERAGE_FLAGS);
gcnoFiles.add(intermediateArtifacts.gcnoFile(sourceFile));
@@ -181,6 +192,14 @@ final class CompilationSupport {
if (ObjcRuleClasses.CPP_SOURCES.matches(sourceFile.getExecPath())) {
commandLine.add("-stdlib=libc++");
}
+
+ if (compilationArtifacts.hasSwiftSources()) {
+ // Add the directory that contains merged TargetName-Swift.h header to search path, in case
+ // any of ObjC files use it.
+ commandLine.add("-I");
+ commandLine.addPath(intermediateArtifacts.swiftHeader().getExecPath().getParentDirectory());
+ additionalInputs.add(intermediateArtifacts.swiftHeader());
+ }
commandLine
.add(IosSdkCommands.compileFlagsForClang(objcConfiguration))
.add(IosSdkCommands.commonLinkAndCompileFlagsForClang(
@@ -188,7 +207,7 @@ final class CompilationSupport {
.add(objcConfiguration.getCoptsForCompilationMode())
.addBeforeEachPath(
"-iquote", ObjcCommon.userHeaderSearchPaths(ruleContext.getConfiguration()))
- .addBeforeEachExecPath("-include", pchFile.asSet())
+ .addBeforeEachExecPath("-include", compilationArtifacts.getPchFile().asSet())
.addBeforeEachPath("-I", objcProvider.get(INCLUDE))
.add(otherFlags)
.addFormatEach("-D%s", objcProvider.get(DEFINE))
@@ -204,11 +223,114 @@ final class CompilationSupport {
.setExecutable(CLANG)
.setCommandLine(commandLine.build())
.addInput(sourceFile)
+ .addInputs(additionalInputs.build())
.addOutput(objFile)
.addOutputs(gcnoFiles.build())
.addTransitiveInputs(objcProvider.get(HEADER))
.addTransitiveInputs(objcProvider.get(FRAMEWORK_FILE))
- .addInputs(pchFile.asSet())
+ .addInputs(compilationArtifacts.getPchFile().asSet())
+ .build(ruleContext));
+ }
+
+ /**
+ * Compiles a single swift file.
+ *
+ * @param sourceFile the artifact to compile
+ * @param objFile the resulting object artifact
+ */
+ private void registerSwiftCompileAction(
+ Artifact sourceFile,
+ Artifact objFile,
+ IntermediateArtifacts intermediateArtifacts) {
+ ObjcConfiguration objcConfiguration = ObjcRuleClasses.objcConfiguration(ruleContext);
+
+ // Compiling a single swift file requires knowledge of all of the other
+ // swift files in the same module. The primary file ({@code sourceFile}) is
+ // compiled to an object file, while the remaining files are used to resolve
+ // symbols (they behave like c/c++ headers in this context).
+ ImmutableSet.Builder<Artifact> otherSwiftSourcesBuilder = ImmutableSet.builder();
+ for (Artifact otherSourceFile : compilationArtifacts(ruleContext).getSrcs()) {
+ if (ObjcRuleClasses.SWIFT_SOURCES.matches(otherSourceFile.getFilename())
+ && otherSourceFile != sourceFile) {
+ otherSwiftSourcesBuilder.add(otherSourceFile);
+ }
+ }
+ ImmutableSet<Artifact> otherSwiftSources = otherSwiftSourcesBuilder.build();
+
+ CustomCommandLine.Builder commandLine = new CustomCommandLine.Builder()
+ .add("-frontend")
+ .add("-emit-object")
+ .add("-target").add(IosSdkCommands.swiftTarget(objcConfiguration))
+ .add("-sdk").add(IosSdkCommands.sdkDir(objcConfiguration))
+ .add("-enable-objc-interop");
+
+ if (objcConfiguration.generateDebugSymbols()) {
+ commandLine.add("-g");
+ }
+
+ commandLine
+ .add("-Onone")
+ .add("-module-name").add(getModuleName())
+ .add("-parse-as-library")
+ .addExecPath("-primary-file", sourceFile)
+ .addExecPaths(otherSwiftSources)
+ .addExecPath("-o", objFile)
+ .addExecPath("-emit-module-path", intermediateArtifacts.swiftModuleFile(sourceFile));
+
+ // Add all ObjC headers to the compiler, in case Swift code is calling into Objc
+ // TODO(bazel-team): This can be augmented by an explicit bridging header field in the rule.
+ commandLine.addBeforeEachExecPath("-import-objc-header", attributes.hdrs());
+
+ ruleContext.registerAction(ObjcRuleClasses.spawnOnDarwinActionBuilder()
+ .setMnemonic("SwiftCompile")
+ .setExecutable(SWIFT)
+ .setCommandLine(commandLine.build())
+ .addInput(sourceFile)
+ .addInputs(otherSwiftSources)
+ .addInputs(attributes.hdrs())
+ .addOutput(objFile)
+ .addOutput(intermediateArtifacts.swiftModuleFile(sourceFile))
+ .build(ruleContext));
+ }
+
+ /**
+ * Merges multiple .partial_swiftmodule files together. Also produces a swift header that can be
+ * used by Objective-C code.
+ */
+ private void registerSwiftModuleMergeAction(
+ IntermediateArtifacts intermediateArtifacts,
+ CompilationArtifacts compilationArtifacts) {
+ ObjcConfiguration objcConfiguration = ObjcRuleClasses.objcConfiguration(ruleContext);
+
+ ImmutableList.Builder<Artifact> moduleFiles = new ImmutableList.Builder<>();
+ for (Artifact src : compilationArtifacts.getSrcs()) {
+ if (ObjcRuleClasses.SWIFT_SOURCES.matches(src.getFilename())) {
+ moduleFiles.add(intermediateArtifacts.swiftModuleFile(src));
+ }
+ }
+
+ CustomCommandLine.Builder commandLine = new CustomCommandLine.Builder();
+ commandLine.add("-frontend");
+ commandLine.add("-emit-module");
+ commandLine.add("-sdk").add(IosSdkCommands.sdkDir(objcConfiguration));
+ commandLine.add("-target").add(IosSdkCommands.swiftTarget(objcConfiguration));
+ if (objcConfiguration.generateDebugSymbols()) {
+ commandLine.add("-g");
+ }
+
+ commandLine.add("-module-name").add(getModuleName());
+ commandLine.add("-parse-as-library");
+ commandLine.addExecPaths(moduleFiles.build());
+ commandLine.addExecPath("-o", intermediateArtifacts.swiftModule());
+ commandLine.addExecPath("-emit-objc-header-path", intermediateArtifacts.swiftHeader());
+
+ ruleContext.registerAction(ObjcRuleClasses.spawnOnDarwinActionBuilder()
+ .setMnemonic("SwiftModuleMerge")
+ .setExecutable(SWIFT)
+ .setCommandLine(commandLine.build())
+ .addInputs(moduleFiles.build())
+ .addOutput(intermediateArtifacts.swiftModule())
+ .addOutput(intermediateArtifacts.swiftHeader())
.build(ruleContext));
}
@@ -345,6 +467,13 @@ final class CompilationSupport {
commandLine.add(LINKER_COVERAGE_FLAGS);
}
+ if (objcProvider.is(USES_SWIFT)) {
+ commandLine
+ .add("-L").add(IosSdkCommands.swiftLibDir(objcConfiguration))
+ .add("-Xlinker").add("-rpath")
+ .add("-Xlinker").add("@executable_path/Frameworks");
+ }
+
// Call to dsymutil for debug symbol generation must happen in the link action.
// All debug symbol information is encoded in object files inside archive files. To generate
// the debug symbol bundle, dsymutil will look inside the linked binary for the encoded
@@ -565,4 +694,11 @@ final class CompilationSupport {
// TODO(bazel-team): Throw instead of returning null?
return str.endsWith(suffix) ? str.substring(0, str.length() - suffix.length()) : null;
}
+
+ /**
+ * Returns the name of Swift module for this target.
+ */
+ private String getModuleName() {
+ return ruleContext.getLabel().getName();
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/IntermediateArtifacts.java b/src/main/java/com/google/devtools/build/lib/rules/objc/IntermediateArtifacts.java
index 9e1372e8d4..4af59d6ad5 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/IntermediateArtifacts.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/IntermediateArtifacts.java
@@ -183,6 +183,28 @@ final class IntermediateArtifacts {
}
/**
+ * The swift module produced by compiling the {@code source} artifact.
+ */
+ public Artifact swiftModuleFile(Artifact source) {
+ return analysisEnvironment.getDerivedArtifact(inUniqueObjsDir(source, ".partial_swiftmodule"),
+ binDirectory);
+ }
+
+ /**
+ * Integrated swift module for this target.
+ */
+ public Artifact swiftModule() {
+ return appendExtension(".swiftmodule");
+ }
+
+ /**
+ * Integrated swift header for this target.
+ */
+ public Artifact swiftHeader() {
+ return appendExtension("-Swift.h");
+ }
+
+ /**
* The artifact for the .gcno file that should be generated when compiling the {@code source}
* artifact.
*/
@@ -236,6 +258,14 @@ final class IntermediateArtifacts {
}
/**
+ * Returns the artifact which is the output of running swift-stdlib-tool and copying resulting
+ * dylibs.
+ */
+ public Artifact swiftFrameworksFileZip() {
+ return appendExtension(".swiftstdlib.zip");
+ }
+
+ /**
* Debug symbol plist generated for a linked binary.
*/
public Artifact dsymPlist() {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/IosSdkCommands.java b/src/main/java/com/google/devtools/build/lib/rules/objc/IosSdkCommands.java
index 32c24c1395..b788f7c0e0 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/IosSdkCommands.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/IosSdkCommands.java
@@ -84,6 +84,28 @@ public class IosSdkCommands {
return platformDir(configuration) + "/Developer/Library/Frameworks";
}
+ /**
+ * Returns swift libraries path.
+ */
+ public static String swiftLibDir(ObjcConfiguration configuration) {
+ return DEVELOPER_DIR + "/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/"
+ + swiftPlatform(configuration);
+ }
+
+ /**
+ * Returns a platform name string suitable for use in Swift tools.
+ */
+ public static String swiftPlatform(ObjcConfiguration configuration) {
+ return getPlatformPlistName(configuration).toLowerCase();
+ }
+
+ /**
+ * Returns the target string for swift compiler. For example, "x86_64-apple-ios8.2"
+ */
+ public static String swiftTarget(ObjcConfiguration configuration) {
+ return configuration.getIosCpu() + "-apple-" + "ios" + configuration.getIosSdkVersion();
+ }
+
private static Iterable<PathFragment> uniqueParentDirectories(Iterable<PathFragment> paths) {
ImmutableSet.Builder<PathFragment> parents = new ImmutableSet.Builder<>();
for (PathFragment path : paths) {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCommon.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCommon.java
index e311bc3473..3b317ab8dd 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCommon.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCommon.java
@@ -26,6 +26,7 @@ import static com.google.devtools.build.lib.rules.objc.ObjcProvider.FORCE_LOAD_L
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.FRAMEWORK_DIR;
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.FRAMEWORK_FILE;
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.Flag.USES_CPP;
+import static com.google.devtools.build.lib.rules.objc.ObjcProvider.Flag.USES_SWIFT;
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.GCNO;
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.GENERAL_RESOURCE_FILE;
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.HEADER;
@@ -455,13 +456,20 @@ public final class ObjcCommon {
}
boolean usesCpp = false;
+ boolean usesSwift = false;
for (Artifact sourceFile :
Iterables.concat(artifacts.getSrcs(), artifacts.getNonArcSrcs())) {
usesCpp = usesCpp || ObjcRuleClasses.CPP_SOURCES.matches(sourceFile.getExecPath());
+ usesSwift = usesSwift || ObjcRuleClasses.SWIFT_SOURCES.matches(sourceFile.getExecPath());
}
+
if (usesCpp) {
objcProvider.add(FLAG, USES_CPP);
}
+
+ if (usesSwift) {
+ objcProvider.add(FLAG, USES_SWIFT);
+ }
}
if (alwayslink) {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProvider.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProvider.java
index e2fc6e9363..92fce30111 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProvider.java
@@ -199,7 +199,13 @@ public final class ObjcProvider implements TransitiveInfoProvider {
* Indicates that C++ (or Objective-C++) is used in any source file. This affects how the linker
* is invoked.
*/
- USES_CPP;
+ USES_CPP,
+
+ /**
+ * Indicates that Swift source files are present. This affects bundling, compiling and linking
+ * actions.
+ */
+ USES_SWIFT
}
private final ImmutableMap<Key<?>, NestedSet<?>> items;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcRuleClasses.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcRuleClasses.java
index dec8cc582c..bd2ecc6566 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcRuleClasses.java
@@ -61,10 +61,13 @@ public class ObjcRuleClasses {
IosSdkCommands.DEVELOPER_DIR + "/Toolchains/XcodeDefault.xctoolchain/usr/bin";
static final PathFragment CLANG = new PathFragment(BIN_DIR + "/clang");
static final PathFragment CLANG_PLUSPLUS = new PathFragment(BIN_DIR + "/clang++");
+ static final PathFragment SWIFT = new PathFragment(BIN_DIR + "/swift");
static final PathFragment LIBTOOL = new PathFragment(BIN_DIR + "/libtool");
static final PathFragment DSYMUTIL = new PathFragment(BIN_DIR + "/dsymutil");
static final PathFragment LIPO = new PathFragment(BIN_DIR + "/lipo");
static final PathFragment IBTOOL = new PathFragment(IosSdkCommands.IBTOOL_PATH);
+ static final PathFragment SWIFT_STDLIB_TOOL = new PathFragment(BIN_DIR + "/swift-stdlib-tool");
+
private static final PathFragment JAVA = new PathFragment("/usr/bin/java");
private ObjcRuleClasses() {
@@ -312,9 +315,11 @@ public class ObjcRuleClasses {
*/
static final FileType CPP_SOURCES = FileType.of(".cc", ".cpp", ".mm", ".cxx", ".C");
+ static final FileType SWIFT_SOURCES = FileType.of(".swift");
+
private static final FileType NON_CPP_SOURCES = FileType.of(".m", ".c");
- static final FileTypeSet SRCS_TYPE = FileTypeSet.of(NON_CPP_SOURCES, CPP_SOURCES);
+ static final FileTypeSet SRCS_TYPE = FileTypeSet.of(NON_CPP_SOURCES, CPP_SOURCES, SWIFT_SOURCES);
static final FileTypeSet NON_ARC_SRCS_TYPE = FileTypeSet.of(FileType.of(".m", ".mm"));
@@ -452,6 +457,8 @@ public class ObjcRuleClasses {
.value(env.getLabel("//tools/objc:actoolzip_deploy.jar")))
.add(attr("$ibtoolzip_deploy", LABEL).cfg(HOST)
.value(env.getLabel("//tools/objc:ibtoolzip_deploy.jar")))
+ .add(attr("$swiftstdlibtoolzip_deploy", LABEL).cfg(HOST)
+ .value(env.getLabel("//tools/objc:swiftstdlibtoolzip_deploy.jar")))
.build();
}
@Override
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ReleaseBundlingSupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ReleaseBundlingSupport.java
index f403daa7db..e10dee00f6 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ReleaseBundlingSupport.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ReleaseBundlingSupport.java
@@ -16,6 +16,7 @@ package com.google.devtools.build.lib.rules.objc;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.devtools.build.lib.packages.ImplicitOutputsFunction.fromTemplates;
+import static com.google.devtools.build.lib.rules.objc.ObjcProvider.Flag.USES_SWIFT;
import static com.google.devtools.build.lib.rules.objc.TargetDeviceFamily.UI_DEVICE_FAMILY_VALUES;
import com.google.common.annotations.VisibleForTesting;
@@ -203,6 +204,7 @@ public final class ReleaseBundlingSupport {
registerCombineArchitecturesAction();
registerTransformAndCopyBreakpadFilesAction();
+ registerSwiftStdlibActionsIfNecessary();
ObjcConfiguration objcConfiguration = ObjcRuleClasses.objcConfiguration(ruleContext);
Artifact ipaOutput = ruleContext.getImplicitOutputArtifact(IPA);
@@ -505,23 +507,38 @@ public final class ReleaseBundlingSupport {
private ReleaseBundlingSupport registerSignBundleAction(
Artifact entitlements, Artifact ipaOutput, Artifact ipaUnsigned) {
// TODO(bazel-team): Support variable substitution
+
+ ImmutableList.Builder<String> dirsToSign = new ImmutableList.Builder<>();
+
+ // Explicitly sign Swift frameworks. Unfortunately --deep option on codesign doesn't do this
+ // automatically.
+ // The order here is important. The innermost code must singed first.
+ if (objcProvider.is(USES_SWIFT)) {
+ dirsToSign.add(bundling.getBundleDir() + "/Frameworks/*");
+ }
+ dirsToSign.add(bundling.getBundleDir());
+
+ StringBuilder codesignCommandLineBuilder = new StringBuilder();
+ for (String dir : dirsToSign.build()) {
+ codesignCommandLineBuilder
+ .append(codesignCommand(attributes.provisioningProfile(), entitlements, "${t}/" + dir))
+ .append(" && ");
+ }
+
ruleContext.registerAction(ObjcRuleClasses.spawnOnDarwinActionBuilder()
.setMnemonic("IosSignBundle")
.setProgressMessage("Signing iOS bundle: " + ruleContext.getLabel())
.setExecutable(new PathFragment("/bin/bash"))
.addArgument("-c")
- // TODO(bazel-team): Support --resource-rules for resources
+ // TODO(bazel-team): Support nested code signing.
.addArgument("set -e && "
+ "t=$(mktemp -d -t signing_intermediate) && "
// Get an absolute path since we need to cd into the temp directory for zip.
+ "signed_ipa=${PWD}/" + ipaOutput.getExecPathString() + " && "
+ "unzip -qq " + ipaUnsigned.getExecPathString() + " -d ${t} && "
- + codesignCommand(
- attributes.provisioningProfile(),
- entitlements,
- "${t}/" + bundling.getBundleDir())
+ + codesignCommandLineBuilder.toString()
// Using zip since we need to preserve permissions
- + " && cd \"${t}\" && /usr/bin/zip -q -r \"${signed_ipa}\" .")
+ + "cd \"${t}\" && /usr/bin/zip -q -r \"${signed_ipa}\" .")
.addInput(ipaUnsigned)
.addInput(attributes.provisioningProfile())
.addInput(entitlements)
@@ -668,6 +685,31 @@ public final class ReleaseBundlingSupport {
.build(ruleContext));
}
+ /**
+ * Registers an action to copy Swift standard library dylibs into app bundle.
+ */
+ private void registerSwiftStdlibActionsIfNecessary() {
+ if (!objcProvider.is(USES_SWIFT)) {
+ return;
+ }
+
+ ObjcConfiguration objcConfiguration = ObjcRuleClasses.objcConfiguration(ruleContext);
+
+ CustomCommandLine.Builder commandLine = CustomCommandLine.builder()
+ .addPath(intermediateArtifacts.swiftFrameworksFileZip().getExecPath())
+ .add("Frameworks")
+ .addPath(ObjcRuleClasses.SWIFT_STDLIB_TOOL)
+ .add("--platform").add(IosSdkCommands.swiftPlatform(objcConfiguration))
+ .addExecPath("--scan-executable", intermediateArtifacts.singleArchitectureBinary());
+
+ ruleContext.registerAction(
+ ObjcRuleClasses.spawnJavaOnDarwinActionBuilder(attributes.swiftStdlibToolDeployJar())
+ .setMnemonic("SwiftStdlibCopy")
+ .setCommandLine(commandLine.build())
+ .addOutput(intermediateArtifacts.swiftFrameworksFileZip())
+ .addInput(intermediateArtifacts.singleArchitectureBinary())
+ .build(ruleContext));
+ }
private String extractPlistCommand(Artifact provisioningProfile) {
return "security cms -D -i " + ShellUtils.shellEscape(provisioningProfile.getExecPathString());
@@ -757,6 +799,13 @@ public final class ReleaseBundlingSupport {
ruleContext.getPrerequisiteArtifact("$runner_script_template", Mode.HOST));
}
+ /**
+ * Returns the location of the swiftstdlibtoolzip deploy jar.
+ */
+ Artifact swiftStdlibToolDeployJar() {
+ return ruleContext.getPrerequisiteArtifact("$swiftstdlibtoolzip_deploy", Mode.HOST);
+ }
+
String bundleId() {
return checkNotNull(stringAttribute("bundle_id"));
}
diff --git a/src/tools/xcode-common/BUILD b/src/tools/xcode-common/BUILD
index b34518bb66..187e8c1dfe 100644
--- a/src/tools/xcode-common/BUILD
+++ b/src/tools/xcode-common/BUILD
@@ -6,6 +6,7 @@ filegroup(
"//src/tools/xcode-common/java/com/google/devtools/build/xcode/actoolzip:srcs",
"//src/tools/xcode-common/java/com/google/devtools/build/xcode/common:srcs",
"//src/tools/xcode-common/java/com/google/devtools/build/xcode/ibtoolzip:srcs",
+ "//src/tools/xcode-common/java/com/google/devtools/build/xcode/swiftstdlibtoolzip:srcs",
"//src/tools/xcode-common/java/com/google/devtools/build/xcode/util:srcs",
"//src/tools/xcode-common/java/com/google/devtools/build/xcode/zip:srcs",
"//src/tools/xcode-common/java/com/google/devtools/build/xcode/zippingoutput:srcs",
diff --git a/src/tools/xcode-common/java/com/google/devtools/build/xcode/swiftstdlibtoolzip/BUILD b/src/tools/xcode-common/java/com/google/devtools/build/xcode/swiftstdlibtoolzip/BUILD
new file mode 100644
index 0000000000..b42968804a
--- /dev/null
+++ b/src/tools/xcode-common/java/com/google/devtools/build/xcode/swiftstdlibtoolzip/BUILD
@@ -0,0 +1,17 @@
+package(default_visibility = ["//src:__subpackages__"])
+
+filegroup(
+ name = "srcs",
+ srcs = glob(["**"]),
+)
+
+java_binary(
+ name = "swiftstdlibtoolzip",
+ srcs = ["SwiftStdlibToolZip.java"],
+ main_class = "com.google.devtools.build.xcode.swiftstdlibtoolzip.SwiftStdlibToolZip",
+ visibility = ["//visibility:public"],
+ deps = [
+ "//src/tools/xcode-common/java/com/google/devtools/build/xcode/zippingoutput",
+ "//third_party:guava",
+ ],
+)
diff --git a/src/tools/xcode-common/java/com/google/devtools/build/xcode/swiftstdlibtoolzip/README b/src/tools/xcode-common/java/com/google/devtools/build/xcode/swiftstdlibtoolzip/README
new file mode 100644
index 0000000000..0c8b3f082d
--- /dev/null
+++ b/src/tools/xcode-common/java/com/google/devtools/build/xcode/swiftstdlibtoolzip/README
@@ -0,0 +1,4 @@
+swiftstdlibtoolzip runs swift-stdlib-tool, which scans executables and copies required Swift
+framework dylibs to the specified path, then zips up the output for further bundle merging.
+
+swift-stdlib-tool only runs on Darwin, so swiftstdlibtoolzip only runs on Darwin.
diff --git a/src/tools/xcode-common/java/com/google/devtools/build/xcode/swiftstdlibtoolzip/SwiftStdlibToolZip.java b/src/tools/xcode-common/java/com/google/devtools/build/xcode/swiftstdlibtoolzip/SwiftStdlibToolZip.java
new file mode 100644
index 0000000000..2043a08fd3
--- /dev/null
+++ b/src/tools/xcode-common/java/com/google/devtools/build/xcode/swiftstdlibtoolzip/SwiftStdlibToolZip.java
@@ -0,0 +1,59 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.xcode.swiftstdlibtoolzip;
+
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.xcode.zippingoutput.Arguments;
+import com.google.devtools.build.xcode.zippingoutput.Wrapper;
+import com.google.devtools.build.xcode.zippingoutput.Wrappers;
+
+import java.io.IOException;
+
+/**
+ * A tool which wraps swift-stdlib-tool by running and zipping its output. See {@link Wrapper} for
+ * more information.
+ */
+public class SwiftStdlibToolZip implements Wrapper {
+
+ @Override
+ public String name() {
+ return "SwiftStdlibToolZip";
+ }
+
+ @Override
+ public String subtoolName() {
+ return "swift-stdlib-tool";
+ }
+
+ @Override
+ public Iterable<String> subCommand(Arguments arguments, String outputDirectory) {
+ return new ImmutableList.Builder<String>()
+ .add(arguments.subtoolCmd())
+ .addAll(arguments.subtoolExtraArgs())
+ .add("--copy")
+ .add("--verbose")
+ .add("--destination").add(outputDirectory)
+ .build();
+ }
+
+ @Override
+ public boolean outputDirectoryMustExist() {
+ return true;
+ }
+
+ public static void main(String[] args) throws IOException, InterruptedException {
+ Wrappers.executePipingOutput(args, new SwiftStdlibToolZip());
+ }
+}
diff --git a/tools/objc/BUILD b/tools/objc/BUILD
index 9ab7180907..8b27ebe1d1 100644
--- a/tools/objc/BUILD
+++ b/tools/objc/BUILD
@@ -39,6 +39,12 @@ java_binary(
main_class = "com.google.devtools.build.xcode.xcodegen.XcodeGen",
)
+java_binary(
+ name = "swiftstdlibtoolzip",
+ srcs = [":precomp_xcodegen_deploy.jar"],
+ main_class = "com.google.devtools.build.xcode.swiftstdlibtoolzip.SwiftStdlibToolZip",
+)
+
filegroup(
name = "srcs",
srcs = glob(["**"]),