Skip to content

Commit b133772

Browse files
authored
Ignore -no_exported_symbols when the debug dylib is used (rdar://152244838) (#554)
The stub executor needs to trampoline to the entry point in the debug dylib. But linking with `-no_exported_symbols` strips it and launching the app fails to find the symbol. Handles both the `LD_EXPORT_SYMBOLS` build setting and manual flags added to `OTHER_LDFLAGS`.
1 parent b78e04a commit b133772

File tree

5 files changed

+51
-11
lines changed

5 files changed

+51
-11
lines changed

Sources/SWBCore/Settings/BuiltinMacros.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,7 @@ public final class BuiltinMacros {
805805
public static let LD_DEPENDENCY_INFO_FILE = BuiltinMacros.declarePathMacro("LD_DEPENDENCY_INFO_FILE")
806806
public static let LD_DYLIB_INSTALL_NAME = BuiltinMacros.declareStringMacro("LD_DYLIB_INSTALL_NAME")
807807
public static let LD_ENTRY_POINT = BuiltinMacros.declareStringMacro("LD_ENTRY_POINT")
808+
public static let LD_EXPORT_SYMBOLS = BuiltinMacros.declareBooleanMacro("LD_EXPORT_SYMBOLS")
808809
public static let LD_EXPORT_GLOBAL_SYMBOLS = BuiltinMacros.declareBooleanMacro("LD_EXPORT_GLOBAL_SYMBOLS")
809810
public static let LD_LTO_OBJECT_FILE = BuiltinMacros.declarePathMacro("LD_LTO_OBJECT_FILE")
810811
public static let LD_NO_PIE = BuiltinMacros.declareBooleanMacro("LD_NO_PIE")
@@ -1871,6 +1872,7 @@ public final class BuiltinMacros {
18711872
LD_ENTRY_POINT,
18721873
LD_ENTITLEMENTS_SECTION,
18731874
LD_ENTITLEMENTS_SECTION_DER,
1875+
LD_EXPORT_SYMBOLS,
18741876
LD_EXPORT_GLOBAL_SYMBOLS,
18751877
LD_LTO_OBJECT_FILE,
18761878
LD_NO_PIE,

Sources/SWBCore/SpecImplementations/Tools/LinkerTools.swift

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,8 @@ public final class LdLinkerSpec : GenericLinkerSpec, SpecIdentifierType, @unchec
314314
delegate.emit(Diagnostic(behavior: dyldEnvDiagnosticBehavior, location: .buildSetting(BuiltinMacros.OTHER_LDFLAGS), data: DiagnosticData("The \(BuiltinMacros.OTHER_LDFLAGS.name) build setting is not allowed to contain \(arg), use the dedicated LD_ENVIRONMENT build setting instead.")))
315315
case "-client_name":
316316
delegate.emit(Diagnostic(behavior: dyldEnvDiagnosticBehavior, location: .buildSetting(BuiltinMacros.OTHER_LDFLAGS), data: DiagnosticData("The \(BuiltinMacros.OTHER_LDFLAGS.name) build setting is not allowed to contain \(arg), use the dedicated LD_CLIENT_NAME build setting instead.")))
317+
case "-no_exported_symbols":
318+
delegate.emit(Diagnostic(behavior: dyldEnvDiagnosticBehavior, location: .buildSetting(BuiltinMacros.OTHER_LDFLAGS), data: DiagnosticData("The \(BuiltinMacros.OTHER_LDFLAGS.name) build setting is not allowed to contain \(arg), use the dedicated LD_EXPORT_SYMBOLS build setting instead.")))
317319
default:
318320
break
319321
}
@@ -504,6 +506,15 @@ public final class LdLinkerSpec : GenericLinkerSpec, SpecIdentifierType, @unchec
504506
return nil
505507
}
506508
return cbc.scope.namespace.parseLiteralString(name)
509+
case BuiltinMacros.DEAD_CODE_STRIPPING where isPreviewDylib:
510+
// We need to keep otherwise unused stub executor library symbols present so
511+
// PreviewsInjection can call them when doing the XOJIT handshake.
512+
return cbc.scope.namespace.parseLiteralString("NO")
513+
case BuiltinMacros.LD_EXPORT_SYMBOLS where isPreviewDylib,
514+
BuiltinMacros.LD_EXPORT_GLOBAL_SYMBOLS where isPreviewDylib:
515+
// We need to keep otherwise unused stub executor library symbols present so
516+
// PreviewsInjection can call them when doing the XOJIT handshake.
517+
return cbc.scope.namespace.parseLiteralString("YES")
507518
case BuiltinMacros.OTHER_LDFLAGS where isPreviewDylib:
508519
let ldFlagsToEvaluate: [String]
509520
if dyldEnvDiagnosticBehavior == .warning {
@@ -774,7 +785,7 @@ public final class LdLinkerSpec : GenericLinkerSpec, SpecIdentifierType, @unchec
774785
switch macro {
775786
case BuiltinMacros.LD_ENTRY_POINT where cbc.scope.previewStyle == .xojit:
776787
return cbc.scope.namespace.parseLiteralString("___debug_blank_executor_main")
777-
case BuiltinMacros.LD_EXPORT_GLOBAL_SYMBOLS:
788+
case BuiltinMacros.LD_EXPORT_SYMBOLS, BuiltinMacros.LD_EXPORT_GLOBAL_SYMBOLS:
778789
// We need to keep otherwise unused stub executor library symbols present so
779790
// PreviewsInjection can call them when doing the XOJIT handshake.
780791
return cbc.scope.namespace.parseLiteralString("YES")
@@ -1821,6 +1832,23 @@ fileprivate func filterLinkerFlagsWhenUnderPreviewsDylib(_ flags: [String]) -> [
18211832
}
18221833
continue
18231834
}
1835+
else if flag == "-Wl,-no_exported_symbols" {
1836+
continue
1837+
}
1838+
else if flag == "-no_exported_symbols" && newFlags.last == "-Xlinker" {
1839+
// Filter out `-no_exported_symbols` when using the previews dylib, since this
1840+
// strips important symbols that are needed for the stub executor trampoline..
1841+
// Transition from `OTHER_LD_FLAGS` to the dedicated `LD_EXPORT_SYMBOLS` (by
1842+
// defining both at once) in order to remain compatible with Xcode versions both
1843+
// before and after this change.
1844+
newFlags.removeLast()
1845+
while let next = it.next() {
1846+
if next != "-Xlinker" {
1847+
break
1848+
}
1849+
}
1850+
continue
1851+
}
18241852
newFlags.append(flag)
18251853
}
18261854
return newFlags

Tests/SWBBuildSystemTests/PreviewsBuildOperationTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ fileprivate struct PreviewsBuildOperationTests: CoreBasedTests {
308308
linkerCommandLine.remove(at: idx)
309309
}
310310
}
311-
XCTAssertEqualSequences(linkerCommandLine, ["\(core.developerPath.path.str)/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang", "-Xlinker", "-reproducible", "-target", "\(results.runDestinationTargetArchitecture)-apple-ios\(core.loadSDK(.iOSSimulator).defaultDeploymentTarget)-simulator", "-dynamiclib", "-isysroot", core.loadSDK(.iOSSimulator).path.str, "-Os", "-Xlinker", "-warn_unused_dylibs", "-L\(srcRoot.str)/build/EagerLinkingTBDs/Debug-iphonesimulator", "-L\(srcRoot.str)/build/Debug-iphonesimulator", "-F\(srcRoot.str)/build/EagerLinkingTBDs/Debug-iphonesimulator", "-F\(srcRoot.str)/build/Debug-iphonesimulator", "-filelist", "\(srcRoot.str)/build/ProjectName.build/Debug-iphonesimulator/AppTarget.build/Objects-normal/\(results.runDestinationTargetArchitecture)/AppTarget.LinkFileList", "-install_name", "@rpath/AppTarget.debug.dylib", "-dead_strip", "-Xlinker", "-object_path_lto", "-Xlinker", "\(srcRoot.str)/build/ProjectName.build/Debug-iphonesimulator/AppTarget.build/Objects-normal/\(results.runDestinationTargetArchitecture)/AppTarget_lto.o", "-Xlinker", "-objc_abi_version", "-Xlinker", "2", "-Xlinker", "-dependency_info", "-Xlinker", "\(srcRoot.str)/build/ProjectName.build/Debug-iphonesimulator/AppTarget.build/Objects-normal/\(results.runDestinationTargetArchitecture)/AppTarget_dependency_info.dat", "-L\(core.developerPath.path.str)/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphonesimulator", "-L/usr/lib/swift", "-Xlinker", "-add_ast_path", "-Xlinker", "\(srcRoot.str)/build/ProjectName.build/Debug-iphonesimulator/AppTarget.build/Objects-normal/\(results.runDestinationTargetArchitecture)/AppTarget.swiftmodule", "-Xlinker", "-alias", "-Xlinker", "_main", "-Xlinker", "___debug_main_executable_dylib_entry_point", "-Xlinker", "-no_adhoc_codesign", "-o", "\(srcRoot.str)/build/Debug-iphonesimulator/AppTarget.app/AppTarget.debug.dylib"])
311+
XCTAssertEqualSequences(linkerCommandLine, ["\(core.developerPath.path.str)/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang", "-Xlinker", "-reproducible", "-target", "\(results.runDestinationTargetArchitecture)-apple-ios\(core.loadSDK(.iOSSimulator).defaultDeploymentTarget)-simulator", "-dynamiclib", "-isysroot", core.loadSDK(.iOSSimulator).path.str, "-Os", "-Xlinker", "-warn_unused_dylibs", "-L\(srcRoot.str)/build/EagerLinkingTBDs/Debug-iphonesimulator", "-L\(srcRoot.str)/build/Debug-iphonesimulator", "-F\(srcRoot.str)/build/EagerLinkingTBDs/Debug-iphonesimulator", "-F\(srcRoot.str)/build/Debug-iphonesimulator", "-filelist", "\(srcRoot.str)/build/ProjectName.build/Debug-iphonesimulator/AppTarget.build/Objects-normal/\(results.runDestinationTargetArchitecture)/AppTarget.LinkFileList", "-install_name", "@rpath/AppTarget.debug.dylib", "-Xlinker", "-object_path_lto", "-Xlinker", "\(srcRoot.str)/build/ProjectName.build/Debug-iphonesimulator/AppTarget.build/Objects-normal/\(results.runDestinationTargetArchitecture)/AppTarget_lto.o", "-rdynamic", "-Xlinker", "-objc_abi_version", "-Xlinker", "2", "-Xlinker", "-dependency_info", "-Xlinker", "\(srcRoot.str)/build/ProjectName.build/Debug-iphonesimulator/AppTarget.build/Objects-normal/\(results.runDestinationTargetArchitecture)/AppTarget_dependency_info.dat", "-L\(core.developerPath.path.str)/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphonesimulator", "-L/usr/lib/swift", "-Xlinker", "-add_ast_path", "-Xlinker", "\(srcRoot.str)/build/ProjectName.build/Debug-iphonesimulator/AppTarget.build/Objects-normal/\(results.runDestinationTargetArchitecture)/AppTarget.swiftmodule", "-Xlinker", "-alias", "-Xlinker", "_main", "-Xlinker", "___debug_main_executable_dylib_entry_point", "-Xlinker", "-no_adhoc_codesign", "-o", "\(srcRoot.str)/build/Debug-iphonesimulator/AppTarget.app/AppTarget.debug.dylib"])
312312
}
313313
}
314314

@@ -615,7 +615,7 @@ fileprivate struct PreviewsBuildOperationTests: CoreBasedTests {
615615
linkerCommandLine.remove(at: idx)
616616
}
617617
}
618-
XCTAssertEqualSequences(linkerCommandLine, ["\(core.developerPath.path.str)/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang", "-Xlinker", "-reproducible", "-target", "\(results.runDestinationTargetArchitecture)-apple-ios\(core.loadSDK(.iOSSimulator).defaultDeploymentTarget)-simulator", "-dynamiclib", "-isysroot", core.loadSDK(.iOSSimulator).path.str, "-Os", "-L\(srcRoot.str)/build/EagerLinkingTBDs/Debug-iphonesimulator", "-L\(srcRoot.str)/build/Debug-iphonesimulator", "-F\(srcRoot.str)/build/EagerLinkingTBDs/Debug-iphonesimulator", "-F\(srcRoot.str)/build/Debug-iphonesimulator", "-filelist", "\(srcRoot.str)/build/ProjectName.build/Debug-iphonesimulator/AppTarget.build/Objects-normal/\(results.runDestinationTargetArchitecture)/AppTarget.LinkFileList", "-install_name", "@rpath/AppTarget.debug.dylib", "-dead_strip", "-Xlinker", "-object_path_lto", "-Xlinker", "\(srcRoot.str)/build/ProjectName.build/Debug-iphonesimulator/AppTarget.build/Objects-normal/\(results.runDestinationTargetArchitecture)/AppTarget_lto.o", "-Xlinker", "-objc_abi_version", "-Xlinker", "2", "-Xlinker", "-dependency_info", "-Xlinker", "\(srcRoot.str)/build/ProjectName.build/Debug-iphonesimulator/AppTarget.build/Objects-normal/\(results.runDestinationTargetArchitecture)/AppTarget_dependency_info.dat", "-fobjc-link-runtime", "-L\(core.developerPath.path.str)/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphonesimulator", "-L/usr/lib/swift", "-Xlinker", "-add_ast_path", "-Xlinker", "\(srcRoot.str)/build/ProjectName.build/Debug-iphonesimulator/AppTarget.build/Objects-normal/\(results.runDestinationTargetArchitecture)/AppTarget.swiftmodule", "-Xlinker", "-alias", "-Xlinker", "_main", "-Xlinker", "___debug_main_executable_dylib_entry_point", "-Xlinker", "-no_adhoc_codesign", "-o", "\(srcRoot.str)/build/Debug-iphonesimulator/AppTarget.app/AppTarget.debug.dylib"])
618+
XCTAssertEqualSequences(linkerCommandLine, ["\(core.developerPath.path.str)/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang", "-Xlinker", "-reproducible", "-target", "\(results.runDestinationTargetArchitecture)-apple-ios\(core.loadSDK(.iOSSimulator).defaultDeploymentTarget)-simulator", "-dynamiclib", "-isysroot", core.loadSDK(.iOSSimulator).path.str, "-Os", "-L\(srcRoot.str)/build/EagerLinkingTBDs/Debug-iphonesimulator", "-L\(srcRoot.str)/build/Debug-iphonesimulator", "-F\(srcRoot.str)/build/EagerLinkingTBDs/Debug-iphonesimulator", "-F\(srcRoot.str)/build/Debug-iphonesimulator", "-filelist", "\(srcRoot.str)/build/ProjectName.build/Debug-iphonesimulator/AppTarget.build/Objects-normal/\(results.runDestinationTargetArchitecture)/AppTarget.LinkFileList", "-install_name", "@rpath/AppTarget.debug.dylib", "-Xlinker", "-object_path_lto", "-Xlinker", "\(srcRoot.str)/build/ProjectName.build/Debug-iphonesimulator/AppTarget.build/Objects-normal/\(results.runDestinationTargetArchitecture)/AppTarget_lto.o", "-rdynamic", "-Xlinker", "-objc_abi_version", "-Xlinker", "2", "-Xlinker", "-dependency_info", "-Xlinker", "\(srcRoot.str)/build/ProjectName.build/Debug-iphonesimulator/AppTarget.build/Objects-normal/\(results.runDestinationTargetArchitecture)/AppTarget_dependency_info.dat", "-fobjc-link-runtime", "-L\(core.developerPath.path.str)/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphonesimulator", "-L/usr/lib/swift", "-Xlinker", "-add_ast_path", "-Xlinker", "\(srcRoot.str)/build/ProjectName.build/Debug-iphonesimulator/AppTarget.build/Objects-normal/\(results.runDestinationTargetArchitecture)/AppTarget.swiftmodule", "-Xlinker", "-alias", "-Xlinker", "_main", "-Xlinker", "___debug_main_executable_dylib_entry_point", "-Xlinker", "-no_adhoc_codesign", "-o", "\(srcRoot.str)/build/Debug-iphonesimulator/AppTarget.app/AppTarget.debug.dylib"])
619619
}
620620
}
621621
}

Tests/SWBTaskConstructionTests/PreviewsTaskConstructionTests.swift

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -932,7 +932,7 @@ fileprivate struct PreviewsTaskConstructionTests: CoreBasedTests {
932932

933933
/// Test that the `__info_plist` section ends up in the stub executor instead of the preview dylib when `CREATE_INFOPLIST_SECTION_IN_BINARY` is enabled.
934934
@Test(.requireSDKs(.iOS))
935-
func xOJITEmbeddedInfoPlist() async throws {
935+
func XOJITEmbeddedInfoPlist() async throws {
936936
try await withTemporaryDirectory { tmpDirPath in
937937
let srcRoot = tmpDirPath.join("srcroot")
938938

@@ -1019,9 +1019,9 @@ fileprivate struct PreviewsTaskConstructionTests: CoreBasedTests {
10191019
}
10201020
}
10211021

1022-
/// Test that any `-dyld_env` arguments end up in the stub executor instead of the preview dylib when is enabled.
1022+
/// Test that any `OTHER_LDFLAGS` arguments end up in the stub executor instead of the debug dylib when is enabled.
10231023
@Test(.requireSDKs(.iOS))
1024-
func xOJITDyldEnv() async throws {
1024+
func XOJITOtherLDFlags() async throws {
10251025
try await withTemporaryDirectory { tmpDirPath in
10261026
let srcRoot = tmpDirPath.join("srcroot")
10271027

@@ -1037,7 +1037,11 @@ fileprivate struct PreviewsTaskConstructionTests: CoreBasedTests {
10371037
buildConfigurations: [
10381038
TestBuildConfiguration("Debug", buildSettings: [
10391039
"LD_ENVIRONMENT": "DYLD_X_PATH=/foo",
1040-
"OTHER_LDFLAGS": "-Wl,-dyld_env,NOT=allowed_here -Xlinker -dyld_env -Xlinker NOR=this",
1040+
"OTHER_LDFLAGS": """
1041+
-Wl,-dyld_env,NOT=allowed_here -Xlinker -dyld_env -Xlinker NOR=this \
1042+
-Wl,-no_exported_symbols -Xlinker -no_exported_symbols
1043+
""",
1044+
"LD_EXPORT_SYMBOLS": "NO",
10411045
"GENERATE_INFOPLIST_FILE": "YES",
10421046
"PRODUCT_NAME": "$(TARGET_NAME)",
10431047
"PRODUCT_BUNDLE_IDENTIFIER": "com.test.ProjectName",
@@ -1100,20 +1104,26 @@ fileprivate struct PreviewsTaskConstructionTests: CoreBasedTests {
11001104
// from OTHER_LDFLAGS, which is overridden to a custom set of flags _without_ $(inherited), so the stub executor doesn't get them
11011105
task.checkCommandLineDoesNotContain("-Wl,-dyld_env,NOT=allowed_here")
11021106
task.checkCommandLineDoesNotContain("NOR=this")
1107+
task.checkCommandLineDoesNotContain("-Wl,-no_exported_symbols")
1108+
task.checkCommandLineDoesNotContain("-no_exported_symbols")
11031109
}
11041110

11051111
results.checkTask(.matchRule(["Ld", "\(srcRoot.str)/build/Debug-iphonesimulator/Tool.debug.dylib", "normal"])) { task in
1106-
// from LD_ENVIRONMENT, which is conditional on MACH_O_TYPE=mh_execute, so the previews dylib (which overrides MACH_O_TYPE=mh_dylib) doesn't get it
1112+
// from LD_ENVIRONMENT, which is conditional on MACH_O_TYPE=mh_execute, so the debug dylib (which overrides MACH_O_TYPE=mh_dylib) doesn't get it
11071113
task.checkCommandLineDoesNotContain("-dyld_env")
11081114
task.checkCommandLineDoesNotContain("DYLD_X_PATH=/foo")
11091115

1110-
// from OTHER_LDFLAGS, which is passed through unchanged to the previews dylib
1116+
// from OTHER_LDFLAGS, which is passed through unchanged to the debug dylib
11111117
task.checkCommandLineDoesNotContain("-Wl,-dyld_env,NOT=allowed_here")
11121118
task.checkCommandLineDoesNotContain("NOR=this")
1119+
task.checkCommandLineDoesNotContain("-Wl,-no_exported_symbols")
1120+
task.checkCommandLineDoesNotContain("-no_exported_symbols")
11131121
}
11141122

11151123
results.checkWarning(.equal("The OTHER_LDFLAGS build setting is not allowed to contain -dyld_env, use the dedicated LD_ENVIRONMENT build setting instead. (in target 'Tool' from project 'ProjectName')"))
11161124
results.checkWarning(.equal("The OTHER_LDFLAGS build setting is not allowed to contain -dyld_env, use the dedicated LD_ENVIRONMENT build setting instead. (in target 'Tool' from project 'ProjectName')"))
1125+
results.checkWarning(.equal("The OTHER_LDFLAGS build setting is not allowed to contain -no_exported_symbols, use the dedicated LD_EXPORT_SYMBOLS build setting instead. (in target 'Tool' from project 'ProjectName')"))
1126+
results.checkWarning(.equal("The OTHER_LDFLAGS build setting is not allowed to contain -no_exported_symbols, use the dedicated LD_EXPORT_SYMBOLS build setting instead. (in target 'Tool' from project 'ProjectName')"))
11171127

11181128
results.checkNoTask()
11191129
results.checkNoDiagnostics()
@@ -1123,7 +1133,7 @@ fileprivate struct PreviewsTaskConstructionTests: CoreBasedTests {
11231133
}
11241134

11251135
@Test(.requireSDKs(.iOS))
1126-
func xOJITPropagatingRpaths() async throws {
1136+
func XOJITPropagatingRpaths() async throws {
11271137
try await withTemporaryDirectory { tmpDirPath in
11281138
let srcRoot = tmpDirPath.join("srcroot")
11291139

Tests/SwiftBuildTests/GeneratePreviewInfoTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,11 +229,11 @@ fileprivate struct GeneratePreviewInfoTests: CoreBasedTests {
229229
"\(tmpDir.str)/Test/build/Test.build/Debug-iphoneos/App.build/Objects-normal/\(activeRunDestination.targetArchitecture)/App.LinkFileList",
230230
"-install_name",
231231
"@rpath/App.debug.dylib",
232-
"-dead_strip",
233232
"-Xlinker",
234233
"-object_path_lto",
235234
"-Xlinker",
236235
"\(tmpDir.str)/Test/build/Test.build/Debug-iphoneos/App.build/Objects-normal/\(activeRunDestination.targetArchitecture)/App_lto.o",
236+
"-rdynamic",
237237
"-Xlinker",
238238
"-dependency_info",
239239
"-Xlinker",

0 commit comments

Comments
 (0)