From 05c8627a6ff61b911629f09e8320dcd1f5bef071 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Wed, 13 Oct 2021 14:03:16 +0900 Subject: [PATCH 1/4] Don't rename main symbol for WASI For a long-term solution, this renaming feature should be supported on wasm-ld because it's not a limitation of WebAssembly. --- Sources/Build/BuildPlan.swift | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Sources/Build/BuildPlan.swift b/Sources/Build/BuildPlan.swift index 1f86b657170..de02b5c802c 100644 --- a/Sources/Build/BuildPlan.swift +++ b/Sources/Build/BuildPlan.swift @@ -115,14 +115,21 @@ extension BuildParameters { /// Computes the linker flags to use in order to rename a module-named main function to 'main' for the target platform, or nil if the linker doesn't support it for the platform. fileprivate func linkerFlagsForRenamingMainFunction(of target: ResolvedTarget) -> [String]? { - var args: [String] = [] + var args: [String]? if self.triple.isDarwin() { args = ["-alias", "_\(target.c99name)_main", "_main"] } else if self.triple.isLinux() { args = ["--defsym", "main=\(target.c99name)_main"] } - return args.flatMap { ["-Xlinker", $0] } + else if self.triple.isWASI() { + // wasm-ld doesn't support renaming symbols yet + args = nil + } + else { + args = [] + } + return args?.flatMap { ["-Xlinker", $0] } } /// Returns the scoped view of build settings for a given target. From 38e75643c71b1a73a2080de9133e164579ada5a3 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Thu, 14 Oct 2021 08:26:48 +0900 Subject: [PATCH 2/4] Simplify linkerFlagsForRenamingMainFunction to simply return nil for other than linux and darwin platforms --- Sources/Build/BuildPlan.swift | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/Sources/Build/BuildPlan.swift b/Sources/Build/BuildPlan.swift index de02b5c802c..0cfe6bc8229 100644 --- a/Sources/Build/BuildPlan.swift +++ b/Sources/Build/BuildPlan.swift @@ -115,21 +115,17 @@ extension BuildParameters { /// Computes the linker flags to use in order to rename a module-named main function to 'main' for the target platform, or nil if the linker doesn't support it for the platform. fileprivate func linkerFlagsForRenamingMainFunction(of target: ResolvedTarget) -> [String]? { - var args: [String]? + let args: [String] if self.triple.isDarwin() { args = ["-alias", "_\(target.c99name)_main", "_main"] } else if self.triple.isLinux() { args = ["--defsym", "main=\(target.c99name)_main"] } - else if self.triple.isWASI() { - // wasm-ld doesn't support renaming symbols yet - args = nil - } else { - args = [] + return nil } - return args?.flatMap { ["-Xlinker", $0] } + return args.flatMap { ["-Xlinker", $0] } } /// Returns the scoped view of build settings for a given target. From 14bb1e7f428d39cb6407d5f7881fab2a41c05056 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 15 Oct 2021 01:27:44 +0900 Subject: [PATCH 3/4] Add unit tests for main renaming for each platforms The call of checkSupportedFrontendFlags is moved from BuildPlan to test it in file system independently. The check needs to access temp file, but the in-memory fs doesn't allow that. --- Sources/Build/BuildPlan.swift | 10 ++--- Sources/Commands/SwiftTool.swift | 3 ++ Sources/SPMBuildCore/BuildParameters.swift | 5 +++ Tests/BuildTests/BuildPlanTests.swift | 47 ++++++++++++++++++++++ 4 files changed, 60 insertions(+), 5 deletions(-) diff --git a/Sources/Build/BuildPlan.swift b/Sources/Build/BuildPlan.swift index 0cfe6bc8229..4698efa3f1e 100644 --- a/Sources/Build/BuildPlan.swift +++ b/Sources/Build/BuildPlan.swift @@ -748,10 +748,9 @@ public final class SwiftTargetBuildDescription { // we can rename the symbol unconditionally. // No `-` for these flags because the set of Strings in driver.supportedFrontendFlags do // not have a leading `-` - if SwiftTargetBuildDescription.checkSupportedFrontendFlags(flags: ["entry-point-function-name"], fileSystem: self.fileSystem) { - if buildParameters.linkerFlagsForRenamingMainFunction(of: target) != nil { - args += ["-Xfrontend", "-entry-point-function-name", "-Xfrontend", "\(target.c99name)_main"] - } + if buildParameters.shouldRenameEntrypointFunctionName, + buildParameters.linkerFlagsForRenamingMainFunction(of: target) != nil { + args += ["-Xfrontend", "-entry-point-function-name", "-Xfrontend", "\(target.c99name)_main"] } } @@ -1231,7 +1230,8 @@ public final class ProductBuildDescription { // we will instead have generated a source file containing the redirect. // Support for linking tests againsts executables is conditional on the tools // version of the package that defines the executable product. - if product.executableModule.underlyingTarget is SwiftTarget, toolsVersion >= .v5_5 { + if product.executableModule.underlyingTarget is SwiftTarget, toolsVersion >= .v5_5, + buildParameters.shouldRenameEntrypointFunctionName { if let flags = buildParameters.linkerFlagsForRenamingMainFunction(of: product.executableModule) { args += flags } diff --git a/Sources/Commands/SwiftTool.swift b/Sources/Commands/SwiftTool.swift index 761dcf3118c..df776386b50 100644 --- a/Sources/Commands/SwiftTool.swift +++ b/Sources/Commands/SwiftTool.swift @@ -869,6 +869,9 @@ public class SwiftTool { xcbuildFlags: options.xcbuildFlags, jobs: options.jobs ?? UInt32(ProcessInfo.processInfo.activeProcessorCount), shouldLinkStaticSwiftStdlib: options.shouldLinkStaticSwiftStdlib, + shouldRenameEntrypointFunctionName: SwiftTargetBuildDescription.checkSupportedFrontendFlags( + flags: ["entry-point-function-name"], fileSystem: localFileSystem + ), sanitizers: options.enabledSanitizers, enableCodeCoverage: options.shouldEnableCodeCoverage, indexStoreMode: options.indexStoreMode.indexStoreMode, diff --git a/Sources/SPMBuildCore/BuildParameters.swift b/Sources/SPMBuildCore/BuildParameters.swift index bc899508fda..f432518593e 100644 --- a/Sources/SPMBuildCore/BuildParameters.swift +++ b/Sources/SPMBuildCore/BuildParameters.swift @@ -133,6 +133,9 @@ public struct BuildParameters: Encodable { /// Whether to create dylibs for dynamic library products. public var shouldCreateDylibForDynamicProducts: Bool + /// Whether to enable the entry-point-function-name feature. + public var shouldRenameEntrypointFunctionName: Bool + /// The current build environment. public var buildEnvironment: BuildEnvironment { BuildEnvironment(platform: currentPlatform, configuration: configuration) @@ -182,6 +185,7 @@ public struct BuildParameters: Encodable { jobs: UInt32 = UInt32(ProcessInfo.processInfo.activeProcessorCount), shouldLinkStaticSwiftStdlib: Bool = false, shouldEnableManifestCaching: Bool = false, + shouldRenameEntrypointFunctionName: Bool = false, shouldCreateDylibForDynamicProducts: Bool = true, sanitizers: EnabledSanitizers = EnabledSanitizers(), enableCodeCoverage: Bool = false, @@ -211,6 +215,7 @@ public struct BuildParameters: Encodable { self.shouldLinkStaticSwiftStdlib = shouldLinkStaticSwiftStdlib self.shouldEnableManifestCaching = shouldEnableManifestCaching self.shouldCreateDylibForDynamicProducts = shouldCreateDylibForDynamicProducts + self.shouldRenameEntrypointFunctionName = shouldRenameEntrypointFunctionName self.sanitizers = sanitizers self.enableCodeCoverage = enableCodeCoverage self.indexStoreMode = indexStoreMode diff --git a/Tests/BuildTests/BuildPlanTests.swift b/Tests/BuildTests/BuildPlanTests.swift index 1b6f613064d..15f7e48d3bc 100644 --- a/Tests/BuildTests/BuildPlanTests.swift +++ b/Tests/BuildTests/BuildPlanTests.swift @@ -63,6 +63,7 @@ final class BuildPlanTests: XCTestCase { toolchain: SPMBuildCore.Toolchain = MockToolchain(), flags: BuildFlags = BuildFlags(), shouldLinkStaticSwiftStdlib: Bool = false, + shouldRenameEntrypointFunctionName: Bool = false, destinationTriple: TSCUtility.Triple = hostTriple, indexStoreMode: BuildParameters.IndexStoreMode = .off, useExplicitModuleBuild: Bool = false @@ -76,6 +77,7 @@ final class BuildPlanTests: XCTestCase { flags: flags, jobs: 3, shouldLinkStaticSwiftStdlib: shouldLinkStaticSwiftStdlib, + shouldRenameEntrypointFunctionName: shouldRenameEntrypointFunctionName, indexStoreMode: indexStoreMode, useExplicitModuleBuild: useExplicitModuleBuild ) @@ -1826,6 +1828,51 @@ final class BuildPlanTests: XCTestCase { XCTAssertEqual(testPathExtension, "wasm") } + func testEntrypointRenaming() throws { + let fs = InMemoryFileSystem(emptyFiles: + "/Pkg/Sources/exe/main.swift" + ) + + let observability = ObservabilitySystem.makeForTesting() + let graph = try loadPackageGraph( + fs: fs, + manifests: [ + Manifest.createRootManifest( + name: "Pkg", + path: .init("/Pkg"), + toolsVersion: .v5_5, + targets: [ + TargetDescription(name: "exe", type: .executable), + ]), + ], + observabilityScope: observability.topScope + ) + + func createResult(for triple: TSCUtility.Triple) throws -> BuildPlanResult { + BuildPlanResult(plan: try BuildPlan( + buildParameters: mockBuildParameters(shouldRenameEntrypointFunctionName: true, destinationTriple: triple), + graph: graph, + fileSystem: fs, + observabilityScope: observability.topScope + )) + } + let supportingTriples: [TSCUtility.Triple] = [.x86_64Linux, .macOS] + for triple in supportingTriples { + let result = try createResult(for: triple) + let exe = try result.target(for: "exe").swiftTarget().compileArguments() + XCTAssertMatch(exe, ["-Xfrontend", "-entry-point-function-name", "-Xfrontend", "exe_main"]) + let linkExe = try result.buildProduct(for: "exe").linkArguments() + XCTAssertMatch(linkExe, [.contains("exe_main")]) + } + + let unsupportingTriples: [TSCUtility.Triple] = [.wasi, .windows] + for triple in unsupportingTriples { + let result = try createResult(for: triple) + let exe = try result.target(for: "exe").swiftTarget().compileArguments() + XCTAssertNoMatch(exe, ["-entry-point-function-name"]) + } + } + func testIndexStore() throws { let fs = InMemoryFileSystem(emptyFiles: "/Pkg/Sources/exe/main.swift", From ee17d1dc39fa5cbeefc37b5f9fc9a86b89ec2ac6 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sat, 16 Oct 2021 14:17:20 +0900 Subject: [PATCH 4/4] Rename {should,can}RenameEntrypointFunctionName --- Sources/Build/BuildPlan.swift | 4 ++-- Sources/Commands/SwiftTool.swift | 2 +- Sources/SPMBuildCore/BuildParameters.swift | 6 +++--- Tests/BuildTests/BuildPlanTests.swift | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Sources/Build/BuildPlan.swift b/Sources/Build/BuildPlan.swift index 4698efa3f1e..95d964674c7 100644 --- a/Sources/Build/BuildPlan.swift +++ b/Sources/Build/BuildPlan.swift @@ -748,7 +748,7 @@ public final class SwiftTargetBuildDescription { // we can rename the symbol unconditionally. // No `-` for these flags because the set of Strings in driver.supportedFrontendFlags do // not have a leading `-` - if buildParameters.shouldRenameEntrypointFunctionName, + if buildParameters.canRenameEntrypointFunctionName, buildParameters.linkerFlagsForRenamingMainFunction(of: target) != nil { args += ["-Xfrontend", "-entry-point-function-name", "-Xfrontend", "\(target.c99name)_main"] } @@ -1231,7 +1231,7 @@ public final class ProductBuildDescription { // Support for linking tests againsts executables is conditional on the tools // version of the package that defines the executable product. if product.executableModule.underlyingTarget is SwiftTarget, toolsVersion >= .v5_5, - buildParameters.shouldRenameEntrypointFunctionName { + buildParameters.canRenameEntrypointFunctionName { if let flags = buildParameters.linkerFlagsForRenamingMainFunction(of: product.executableModule) { args += flags } diff --git a/Sources/Commands/SwiftTool.swift b/Sources/Commands/SwiftTool.swift index df776386b50..bc39a212c0d 100644 --- a/Sources/Commands/SwiftTool.swift +++ b/Sources/Commands/SwiftTool.swift @@ -869,7 +869,7 @@ public class SwiftTool { xcbuildFlags: options.xcbuildFlags, jobs: options.jobs ?? UInt32(ProcessInfo.processInfo.activeProcessorCount), shouldLinkStaticSwiftStdlib: options.shouldLinkStaticSwiftStdlib, - shouldRenameEntrypointFunctionName: SwiftTargetBuildDescription.checkSupportedFrontendFlags( + canRenameEntrypointFunctionName: SwiftTargetBuildDescription.checkSupportedFrontendFlags( flags: ["entry-point-function-name"], fileSystem: localFileSystem ), sanitizers: options.enabledSanitizers, diff --git a/Sources/SPMBuildCore/BuildParameters.swift b/Sources/SPMBuildCore/BuildParameters.swift index f432518593e..6df687ac5e4 100644 --- a/Sources/SPMBuildCore/BuildParameters.swift +++ b/Sources/SPMBuildCore/BuildParameters.swift @@ -134,7 +134,7 @@ public struct BuildParameters: Encodable { public var shouldCreateDylibForDynamicProducts: Bool /// Whether to enable the entry-point-function-name feature. - public var shouldRenameEntrypointFunctionName: Bool + public var canRenameEntrypointFunctionName: Bool /// The current build environment. public var buildEnvironment: BuildEnvironment { @@ -185,7 +185,7 @@ public struct BuildParameters: Encodable { jobs: UInt32 = UInt32(ProcessInfo.processInfo.activeProcessorCount), shouldLinkStaticSwiftStdlib: Bool = false, shouldEnableManifestCaching: Bool = false, - shouldRenameEntrypointFunctionName: Bool = false, + canRenameEntrypointFunctionName: Bool = false, shouldCreateDylibForDynamicProducts: Bool = true, sanitizers: EnabledSanitizers = EnabledSanitizers(), enableCodeCoverage: Bool = false, @@ -215,7 +215,7 @@ public struct BuildParameters: Encodable { self.shouldLinkStaticSwiftStdlib = shouldLinkStaticSwiftStdlib self.shouldEnableManifestCaching = shouldEnableManifestCaching self.shouldCreateDylibForDynamicProducts = shouldCreateDylibForDynamicProducts - self.shouldRenameEntrypointFunctionName = shouldRenameEntrypointFunctionName + self.canRenameEntrypointFunctionName = canRenameEntrypointFunctionName self.sanitizers = sanitizers self.enableCodeCoverage = enableCodeCoverage self.indexStoreMode = indexStoreMode diff --git a/Tests/BuildTests/BuildPlanTests.swift b/Tests/BuildTests/BuildPlanTests.swift index 15f7e48d3bc..eb5c5b17cce 100644 --- a/Tests/BuildTests/BuildPlanTests.swift +++ b/Tests/BuildTests/BuildPlanTests.swift @@ -63,7 +63,7 @@ final class BuildPlanTests: XCTestCase { toolchain: SPMBuildCore.Toolchain = MockToolchain(), flags: BuildFlags = BuildFlags(), shouldLinkStaticSwiftStdlib: Bool = false, - shouldRenameEntrypointFunctionName: Bool = false, + canRenameEntrypointFunctionName: Bool = false, destinationTriple: TSCUtility.Triple = hostTriple, indexStoreMode: BuildParameters.IndexStoreMode = .off, useExplicitModuleBuild: Bool = false @@ -77,7 +77,7 @@ final class BuildPlanTests: XCTestCase { flags: flags, jobs: 3, shouldLinkStaticSwiftStdlib: shouldLinkStaticSwiftStdlib, - shouldRenameEntrypointFunctionName: shouldRenameEntrypointFunctionName, + canRenameEntrypointFunctionName: canRenameEntrypointFunctionName, indexStoreMode: indexStoreMode, useExplicitModuleBuild: useExplicitModuleBuild ) @@ -1850,7 +1850,7 @@ final class BuildPlanTests: XCTestCase { func createResult(for triple: TSCUtility.Triple) throws -> BuildPlanResult { BuildPlanResult(plan: try BuildPlan( - buildParameters: mockBuildParameters(shouldRenameEntrypointFunctionName: true, destinationTriple: triple), + buildParameters: mockBuildParameters(canRenameEntrypointFunctionName: true, destinationTriple: triple), graph: graph, fileSystem: fs, observabilityScope: observability.topScope