diff --git a/Fixtures/Miscellaneous/LTO/SwiftAndCTargets/.gitignore b/Fixtures/Miscellaneous/LTO/SwiftAndCTargets/.gitignore new file mode 100644 index 00000000000..0023a534063 --- /dev/null +++ b/Fixtures/Miscellaneous/LTO/SwiftAndCTargets/.gitignore @@ -0,0 +1,8 @@ +.DS_Store +/.build +/Packages +xcuserdata/ +DerivedData/ +.swiftpm/configuration/registries.json +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +.netrc diff --git a/Fixtures/Miscellaneous/LTO/SwiftAndCTargets/Package.swift b/Fixtures/Miscellaneous/LTO/SwiftAndCTargets/Package.swift new file mode 100644 index 00000000000..fb06627fc9e --- /dev/null +++ b/Fixtures/Miscellaneous/LTO/SwiftAndCTargets/Package.swift @@ -0,0 +1,12 @@ +// swift-tools-version: 5.9 + +import PackageDescription + +let package = Package( + name: "SwiftAndCTargets", + targets: [ + .target(name: "cLib"), + .executableTarget(name: "exe", dependencies: ["cLib", "swiftLib"]), + .target(name: "swiftLib"), + ] +) diff --git a/Fixtures/Miscellaneous/LTO/SwiftAndCTargets/Sources/cLib/cLib.c b/Fixtures/Miscellaneous/LTO/SwiftAndCTargets/Sources/cLib/cLib.c new file mode 100644 index 00000000000..b52375f8c67 --- /dev/null +++ b/Fixtures/Miscellaneous/LTO/SwiftAndCTargets/Sources/cLib/cLib.c @@ -0,0 +1,7 @@ +#include + +#include "include/cLib.h" + +void cPrint(int value) { + printf("c value: %i\n", value); +} diff --git a/Fixtures/Miscellaneous/LTO/SwiftAndCTargets/Sources/cLib/include/cLib.h b/Fixtures/Miscellaneous/LTO/SwiftAndCTargets/Sources/cLib/include/cLib.h new file mode 100644 index 00000000000..26f79cc4baa --- /dev/null +++ b/Fixtures/Miscellaneous/LTO/SwiftAndCTargets/Sources/cLib/include/cLib.h @@ -0,0 +1,3 @@ +#pragma once + +extern void cPrint(int); diff --git a/Fixtures/Miscellaneous/LTO/SwiftAndCTargets/Sources/exe/main.swift b/Fixtures/Miscellaneous/LTO/SwiftAndCTargets/Sources/exe/main.swift new file mode 100644 index 00000000000..48ced4c693e --- /dev/null +++ b/Fixtures/Miscellaneous/LTO/SwiftAndCTargets/Sources/exe/main.swift @@ -0,0 +1,5 @@ +import swiftLib +import cLib + +cPrint(1) +swiftPrint(value: 2) diff --git a/Fixtures/Miscellaneous/LTO/SwiftAndCTargets/Sources/swiftLib/swiftLib.swift b/Fixtures/Miscellaneous/LTO/SwiftAndCTargets/Sources/swiftLib/swiftLib.swift new file mode 100644 index 00000000000..f986bfaa7f9 --- /dev/null +++ b/Fixtures/Miscellaneous/LTO/SwiftAndCTargets/Sources/swiftLib/swiftLib.swift @@ -0,0 +1,3 @@ +public func swiftPrint(value: Int) { + print("swift value: \(value)") +} diff --git a/Sources/Build/BuildDescription/ProductBuildDescription.swift b/Sources/Build/BuildDescription/ProductBuildDescription.swift index bd63fa749c4..4a64ee91fa0 100644 --- a/Sources/Build/BuildDescription/ProductBuildDescription.swift +++ b/Sources/Build/BuildDescription/ProductBuildDescription.swift @@ -325,6 +325,16 @@ public final class ProductBuildDescription: SPMBuildCore.ProductBuildDescription // User arguments (from -Xlinker) should follow generated arguments to allow user overrides args += self.buildParameters.flags.linkerFlags.asSwiftcLinkerFlags() + // Enable the correct lto mode if requested. + switch self.buildParameters.linkingParameters.linkTimeOptimizationMode { + case nil: + break + case .full: + args += ["-lto=llvm-full"] + case .thin: + args += ["-lto=llvm-thin"] + } + // Pass default library paths from the toolchain. for librarySearchPath in self.buildParameters.toolchain.librarySearchPaths { args += ["-L", librarySearchPath.pathString] diff --git a/Tests/FunctionalTests/MiscellaneousTests.swift b/Tests/FunctionalTests/MiscellaneousTests.swift index 51b87f3d733..c4fe10d65ca 100644 --- a/Tests/FunctionalTests/MiscellaneousTests.swift +++ b/Tests/FunctionalTests/MiscellaneousTests.swift @@ -337,6 +337,27 @@ class MiscellaneousTestCase: XCTestCase { } } + func testLTO() throws { + #if os(macOS) + // FIXME: this test requires swift-driver to be installed + // Currently swift-ci does not build/install swift-driver before running + // swift-package-manager tests which results in this test failing. + // See the following additional discussion: + // - https://github.com/apple/swift/pull/69696 + // - https://github.com/apple/swift/pull/61766 + // - https://github.com/apple/swift-package-manager/pull/5842#issuecomment-1301632685 + try fixture(name: "Miscellaneous/LTO/SwiftAndCTargets") { fixturePath in + let output = try executeSwiftBuild( + fixturePath, + extraArgs: ["--experimental-lto-mode=full", "--verbose"]) + // FIXME: On macOS dsymutil cannot find temporary .o files? (#6890) + // Ensure warnings like the following are not present in build output + // warning: (arm64) /var/folders/ym/6l_0x8vj0b70sz_4h9d70p440000gn/T/main-e120de.o unable to open object file: No such file or directory + // XCTAssertNoMatch(output.stdout, .contains("unable to open object file")) + } + #endif + } + func testUnicode() throws { #if !os(Linux) && !os(Android) // TODO: - Linux has trouble with this and needs investigation. try fixture(name: "Miscellaneous/Unicode") { fixturePath in