Skip to content

Ignore -no_exported_symbols when the debug dylib is used (rdar://152244838) #554

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Sources/SWBCore/Settings/BuiltinMacros.swift
Original file line number Diff line number Diff line change
Expand Up @@ -805,6 +805,7 @@ public final class BuiltinMacros {
public static let LD_DEPENDENCY_INFO_FILE = BuiltinMacros.declarePathMacro("LD_DEPENDENCY_INFO_FILE")
public static let LD_DYLIB_INSTALL_NAME = BuiltinMacros.declareStringMacro("LD_DYLIB_INSTALL_NAME")
public static let LD_ENTRY_POINT = BuiltinMacros.declareStringMacro("LD_ENTRY_POINT")
public static let LD_EXPORT_SYMBOLS = BuiltinMacros.declareBooleanMacro("LD_EXPORT_SYMBOLS")
public static let LD_EXPORT_GLOBAL_SYMBOLS = BuiltinMacros.declareBooleanMacro("LD_EXPORT_GLOBAL_SYMBOLS")
public static let LD_LTO_OBJECT_FILE = BuiltinMacros.declarePathMacro("LD_LTO_OBJECT_FILE")
public static let LD_NO_PIE = BuiltinMacros.declareBooleanMacro("LD_NO_PIE")
Expand Down Expand Up @@ -1871,6 +1872,7 @@ public final class BuiltinMacros {
LD_ENTRY_POINT,
LD_ENTITLEMENTS_SECTION,
LD_ENTITLEMENTS_SECTION_DER,
LD_EXPORT_SYMBOLS,
LD_EXPORT_GLOBAL_SYMBOLS,
LD_LTO_OBJECT_FILE,
LD_NO_PIE,
Expand Down
30 changes: 29 additions & 1 deletion Sources/SWBCore/SpecImplementations/Tools/LinkerTools.swift
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,8 @@ public final class LdLinkerSpec : GenericLinkerSpec, SpecIdentifierType, @unchec
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.")))
case "-client_name":
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.")))
case "-no_exported_symbols":
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.")))
default:
break
}
Expand Down Expand Up @@ -504,6 +506,15 @@ public final class LdLinkerSpec : GenericLinkerSpec, SpecIdentifierType, @unchec
return nil
}
return cbc.scope.namespace.parseLiteralString(name)
case BuiltinMacros.DEAD_CODE_STRIPPING where isPreviewDylib:
// We need to keep otherwise unused stub executor library symbols present so
// PreviewsInjection can call them when doing the XOJIT handshake.
return cbc.scope.namespace.parseLiteralString("NO")
case BuiltinMacros.LD_EXPORT_SYMBOLS where isPreviewDylib,
BuiltinMacros.LD_EXPORT_GLOBAL_SYMBOLS where isPreviewDylib:
// We need to keep otherwise unused stub executor library symbols present so
// PreviewsInjection can call them when doing the XOJIT handshake.
return cbc.scope.namespace.parseLiteralString("YES")
case BuiltinMacros.OTHER_LDFLAGS where isPreviewDylib:
let ldFlagsToEvaluate: [String]
if dyldEnvDiagnosticBehavior == .warning {
Expand Down Expand Up @@ -774,7 +785,7 @@ public final class LdLinkerSpec : GenericLinkerSpec, SpecIdentifierType, @unchec
switch macro {
case BuiltinMacros.LD_ENTRY_POINT where cbc.scope.previewStyle == .xojit:
return cbc.scope.namespace.parseLiteralString("___debug_blank_executor_main")
case BuiltinMacros.LD_EXPORT_GLOBAL_SYMBOLS:
case BuiltinMacros.LD_EXPORT_SYMBOLS, BuiltinMacros.LD_EXPORT_GLOBAL_SYMBOLS:
// We need to keep otherwise unused stub executor library symbols present so
// PreviewsInjection can call them when doing the XOJIT handshake.
return cbc.scope.namespace.parseLiteralString("YES")
Expand Down Expand Up @@ -1821,6 +1832,23 @@ fileprivate func filterLinkerFlagsWhenUnderPreviewsDylib(_ flags: [String]) -> [
}
continue
}
else if flag == "-Wl,-no_exported_symbols" {
continue
}
else if flag == "-no_exported_symbols" && newFlags.last == "-Xlinker" {
// Filter out `-no_exported_symbols` when using the previews dylib, since this
// strips important symbols that are needed for the stub executor trampoline..
// Transition from `OTHER_LD_FLAGS` to the dedicated `LD_EXPORT_SYMBOLS` (by
// defining both at once) in order to remain compatible with Xcode versions both
// before and after this change.
newFlags.removeLast()
while let next = it.next() {
if next != "-Xlinker" {
break
}
}
continue
}
newFlags.append(flag)
}
return newFlags
Expand Down
4 changes: 2 additions & 2 deletions Tests/SWBBuildSystemTests/PreviewsBuildOperationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ fileprivate struct PreviewsBuildOperationTests: CoreBasedTests {
linkerCommandLine.remove(at: idx)
}
}
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"])
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"])
}
}

Expand Down Expand Up @@ -615,7 +615,7 @@ fileprivate struct PreviewsBuildOperationTests: CoreBasedTests {
linkerCommandLine.remove(at: idx)
}
}
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"])
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"])
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -932,7 +932,7 @@ fileprivate struct PreviewsTaskConstructionTests: CoreBasedTests {

/// 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.
@Test(.requireSDKs(.iOS))
func xOJITEmbeddedInfoPlist() async throws {
func XOJITEmbeddedInfoPlist() async throws {
try await withTemporaryDirectory { tmpDirPath in
let srcRoot = tmpDirPath.join("srcroot")

Expand Down Expand Up @@ -1019,9 +1019,9 @@ fileprivate struct PreviewsTaskConstructionTests: CoreBasedTests {
}
}

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

Expand All @@ -1037,7 +1037,11 @@ fileprivate struct PreviewsTaskConstructionTests: CoreBasedTests {
buildConfigurations: [
TestBuildConfiguration("Debug", buildSettings: [
"LD_ENVIRONMENT": "DYLD_X_PATH=/foo",
"OTHER_LDFLAGS": "-Wl,-dyld_env,NOT=allowed_here -Xlinker -dyld_env -Xlinker NOR=this",
"OTHER_LDFLAGS": """
-Wl,-dyld_env,NOT=allowed_here -Xlinker -dyld_env -Xlinker NOR=this \
-Wl,-no_exported_symbols -Xlinker -no_exported_symbols
""",
"LD_EXPORT_SYMBOLS": "NO",
"GENERATE_INFOPLIST_FILE": "YES",
"PRODUCT_NAME": "$(TARGET_NAME)",
"PRODUCT_BUNDLE_IDENTIFIER": "com.test.ProjectName",
Expand Down Expand Up @@ -1100,20 +1104,26 @@ fileprivate struct PreviewsTaskConstructionTests: CoreBasedTests {
// from OTHER_LDFLAGS, which is overridden to a custom set of flags _without_ $(inherited), so the stub executor doesn't get them
task.checkCommandLineDoesNotContain("-Wl,-dyld_env,NOT=allowed_here")
task.checkCommandLineDoesNotContain("NOR=this")
task.checkCommandLineDoesNotContain("-Wl,-no_exported_symbols")
task.checkCommandLineDoesNotContain("-no_exported_symbols")
}

results.checkTask(.matchRule(["Ld", "\(srcRoot.str)/build/Debug-iphonesimulator/Tool.debug.dylib", "normal"])) { task in
// 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
// 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
task.checkCommandLineDoesNotContain("-dyld_env")
task.checkCommandLineDoesNotContain("DYLD_X_PATH=/foo")

// from OTHER_LDFLAGS, which is passed through unchanged to the previews dylib
// from OTHER_LDFLAGS, which is passed through unchanged to the debug dylib
task.checkCommandLineDoesNotContain("-Wl,-dyld_env,NOT=allowed_here")
task.checkCommandLineDoesNotContain("NOR=this")
task.checkCommandLineDoesNotContain("-Wl,-no_exported_symbols")
task.checkCommandLineDoesNotContain("-no_exported_symbols")
}

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')"))
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')"))
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')"))
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')"))

results.checkNoTask()
results.checkNoDiagnostics()
Expand All @@ -1123,7 +1133,7 @@ fileprivate struct PreviewsTaskConstructionTests: CoreBasedTests {
}

@Test(.requireSDKs(.iOS))
func xOJITPropagatingRpaths() async throws {
func XOJITPropagatingRpaths() async throws {
try await withTemporaryDirectory { tmpDirPath in
let srcRoot = tmpDirPath.join("srcroot")

Expand Down
2 changes: 1 addition & 1 deletion Tests/SwiftBuildTests/GeneratePreviewInfoTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -229,11 +229,11 @@ fileprivate struct GeneratePreviewInfoTests: CoreBasedTests {
"\(tmpDir.str)/Test/build/Test.build/Debug-iphoneos/App.build/Objects-normal/\(activeRunDestination.targetArchitecture)/App.LinkFileList",
"-install_name",
"@rpath/App.debug.dylib",
"-dead_strip",
"-Xlinker",
"-object_path_lto",
"-Xlinker",
"\(tmpDir.str)/Test/build/Test.build/Debug-iphoneos/App.build/Objects-normal/\(activeRunDestination.targetArchitecture)/App_lto.o",
"-rdynamic",
"-Xlinker",
"-dependency_info",
"-Xlinker",
Expand Down
Loading