diff --git a/Sources/SWBCore/Settings/BuiltinMacros.swift b/Sources/SWBCore/Settings/BuiltinMacros.swift index deae0f54..ff16e32b 100644 --- a/Sources/SWBCore/Settings/BuiltinMacros.swift +++ b/Sources/SWBCore/Settings/BuiltinMacros.swift @@ -806,6 +806,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") @@ -1875,6 +1876,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, diff --git a/Sources/SWBCore/SpecImplementations/Tools/LinkerTools.swift b/Sources/SWBCore/SpecImplementations/Tools/LinkerTools.swift index 8dd603b1..44c1681d 100644 --- a/Sources/SWBCore/SpecImplementations/Tools/LinkerTools.swift +++ b/Sources/SWBCore/SpecImplementations/Tools/LinkerTools.swift @@ -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 } @@ -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 { @@ -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") @@ -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 diff --git a/Tests/SWBBuildSystemTests/PreviewsBuildOperationTests.swift b/Tests/SWBBuildSystemTests/PreviewsBuildOperationTests.swift index 3f70f261..f6627365 100644 --- a/Tests/SWBBuildSystemTests/PreviewsBuildOperationTests.swift +++ b/Tests/SWBBuildSystemTests/PreviewsBuildOperationTests.swift @@ -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"]) } } @@ -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"]) } } } diff --git a/Tests/SWBTaskConstructionTests/PreviewsTaskConstructionTests.swift b/Tests/SWBTaskConstructionTests/PreviewsTaskConstructionTests.swift index 4e7e6eee..2092b03f 100644 --- a/Tests/SWBTaskConstructionTests/PreviewsTaskConstructionTests.swift +++ b/Tests/SWBTaskConstructionTests/PreviewsTaskConstructionTests.swift @@ -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") @@ -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") @@ -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", @@ -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() @@ -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") diff --git a/Tests/SwiftBuildTests/GeneratePreviewInfoTests.swift b/Tests/SwiftBuildTests/GeneratePreviewInfoTests.swift index 90cc62d1..ab4b2b97 100644 --- a/Tests/SwiftBuildTests/GeneratePreviewInfoTests.swift +++ b/Tests/SwiftBuildTests/GeneratePreviewInfoTests.swift @@ -228,11 +228,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",