Skip to content

Commit 927bf18

Browse files
committed
[Xcodeproj] Create symlink'ed dylibs for C frameworks
This patch adds library search path to generated Xcode projects to a directory with symlinks to C framework binaries so that client provided modulemap can work with Xcode as well as SwiftPM. - https://bugs.swift.org/browse/SR-2465 - <rdar://problem/28038845> SR-2465: Xcode project cannot use C language target with custom module map
1 parent 4c397e6 commit 927bf18

File tree

2 files changed

+33
-1
lines changed

2 files changed

+33
-1
lines changed

Sources/Xcodeproj/Module+PBXProj.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ extension Module {
5252
var releaseConfigurationReference: String { return "_ReleaseConf_\(c99name)" }
5353
var compilePhaseReference: String { return "CompilePhase_\(c99name)" }
5454
var linkPhaseReference: String { return "___LinkPhase_\(c99name)" }
55+
var shellScriptPhaseReference: String { return "_ScriptPhase_\(c99name)" }
5556
}
5657

5758
func fileRef(forLinkPhaseChild module: Module, from: Module) -> String {
@@ -218,6 +219,12 @@ extension Module {
218219
var buildSettings = [String: Any]()
219220
let plistPath = xcodeProjectPath.appending(component: infoPlistFileName)
220221

222+
// Add default library search path to the directory where symlinks to framework
223+
// binaries will be put with name `lib<library-name>.dylib` so that autolinking
224+
// can proceed without providing another modulemap for Xcode projects.
225+
// See: https://bugs.swift.org/browse/SR-2465
226+
buildSettings["LIBRARY_SEARCH_PATHS"] = ["$(PROJECT_TEMP_DIR)/SymlinkLibs/"]
227+
221228
if isTest {
222229
buildSettings["EMBEDDED_CONTENT_CONTAINS_SWIFT"] = "YES"
223230

Sources/Xcodeproj/pbxproj().swift

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,14 @@ public func pbxproj(srcroot: AbsolutePath, projectRoot: AbsolutePath, xcodeprojP
179179
print(" \(module.targetReference) = {")
180180
print(" isa = PBXNativeTarget;")
181181
print(" buildConfigurationList = \(module.configurationListReference);")
182-
print(" buildPhases = (\(module.compilePhaseReference), \(module.linkPhaseReference));")
182+
183+
print(" buildPhases = (")
184+
// Add a shell script phase for clang module libraries for SR-2465.
185+
if module.isClangModuleLibrary {
186+
print("\(module.shellScriptPhaseReference), ")
187+
}
188+
print("\(module.compilePhaseReference), \(module.linkPhaseReference));")
189+
183190
print(" buildRules = ();")
184191
print(" dependencies = (\(module.nativeTargetDependencies));")
185192
print(" name = '\(module.name)';")
@@ -196,6 +203,16 @@ public func pbxproj(srcroot: AbsolutePath, projectRoot: AbsolutePath, xcodeprojP
196203
print(" sourceTree = BUILT_PRODUCTS_DIR;")
197204
print(" };")
198205

206+
// shell script build phase.
207+
if module.isClangModuleLibrary {
208+
print(" \(module.shellScriptPhaseReference) = {")
209+
print(" isa = PBXShellScriptBuildPhase;")
210+
print(" shellPath = /bin/sh;")
211+
print(" shellScript = \"mkdir -p \\\"$PROJECT_TEMP_DIR/SymlinkLibs\\\"\nln -sf \\\"$BUILT_PRODUCTS_DIR/$EXECUTABLE_PATH\\\" \\\"$PROJECT_TEMP_DIR/SymlinkLibs/lib$EXECUTABLE_NAME.dylib\\\"\";")
212+
print(" runOnlyForDeploymentPostprocessing = 0;")
213+
print(" };")
214+
}
215+
199216
// sources build phase
200217
print(" \(module.compilePhaseReference) = {")
201218
print(" isa = PBXSourcesBuildPhase;")
@@ -474,6 +491,14 @@ private extension SupportedLanguageExtension {
474491
}
475492

476493
private extension Module {
494+
495+
var isClangModuleLibrary: Bool {
496+
if case let clangModule as ClangModule = self, clangModule.type == .library {
497+
return true
498+
}
499+
return false
500+
}
501+
477502
func fileType(forSource source: RelativePath) -> String {
478503
switch self {
479504
case is SwiftModule:

0 commit comments

Comments
 (0)