Skip to content

Commit e4ae7e3

Browse files
committed
Change how libraries are specified to the linker
- remove the platform specifics from computeLibraryArgs, we now just use LIBRARY_PREFIX and remove any suffix for searchPathFlagsForLD, and moved this into the LinkerSpec.LibrarySpecifier extension, this allows for proper searching of libraries, and linking of dynamic libraries on Windows.
1 parent 469349f commit e4ae7e3

File tree

8 files changed

+55
-84
lines changed

8 files changed

+55
-84
lines changed

Sources/SWBCore/Settings/BuiltinMacros.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,7 @@ public final class BuiltinMacros {
685685
public static let EXECUTABLE_DEBUG_DYLIB_MAPPED_PLATFORM = BuiltinMacros.declareStringMacro("EXECUTABLE_DEBUG_DYLIB_MAPPED_PLATFORM")
686686
public static let EXECUTABLE_BLANK_INJECTION_DYLIB_PATH = BuiltinMacros.declareStringMacro("EXECUTABLE_BLANK_INJECTION_DYLIB_PATH")
687687

688+
public static let EXECUTABLE_PREFIX = BuiltinMacros.declareStringMacro("EXECUTABLE_PREFIX")
688689
public static let EXECUTABLE_SUFFIX = BuiltinMacros.declareStringMacro("EXECUTABLE_SUFFIX")
689690
public static let EXECUTABLE_VARIANT_SUFFIX = BuiltinMacros.declareStringMacro("EXECUTABLE_VARIANT_SUFFIX")
690691
public static let EXPORTED_SYMBOLS_FILE = BuiltinMacros.declarePathMacro("EXPORTED_SYMBOLS_FILE")
@@ -1764,6 +1765,7 @@ public final class BuiltinMacros {
17641765
EXECUTABLE_DEBUG_DYLIB_MAPPED_INSTALL_NAME,
17651766
EXECUTABLE_DEBUG_DYLIB_MAPPED_PLATFORM,
17661767
EXECUTABLE_BLANK_INJECTION_DYLIB_PATH,
1768+
EXECUTABLE_PREFIX,
17671769
EXECUTABLE_SUFFIX,
17681770
EXECUTABLE_VARIANT_SUFFIX,
17691771
EXCLUDED_ARCHS,

Sources/SWBCore/SpecImplementations/LinkerSpec.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,9 @@ open class LinkerSpec : CommandLineToolSpec, @unchecked Sendable {
8989
/// The path to the privacy file, if one exists.
9090
public let privacyFile: Path?
9191

92-
public init(kind: Kind, path: Path, mode: Mode, useSearchPaths: Bool, swiftModulePaths: [String: Path], swiftModuleAdditionalLinkerArgResponseFilePaths: [String: Path], explicitDependencies: [Path] = [], topLevelItemPath: Path? = nil, dsymPath: Path? = nil, xcframeworkSourcePath: Path? = nil, privacyFile: Path? = nil) {
92+
public let libPrefix: String
93+
94+
public init(kind: Kind, path: Path, mode: Mode, useSearchPaths: Bool, swiftModulePaths: [String: Path], swiftModuleAdditionalLinkerArgResponseFilePaths: [String: Path], refSettings: Settings? = nil, explicitDependencies: [Path] = [], topLevelItemPath: Path? = nil, dsymPath: Path? = nil, xcframeworkSourcePath: Path? = nil, privacyFile: Path? = nil) {
9395
self.kind = kind
9496
self.path = path
9597
self.mode = mode
@@ -101,6 +103,7 @@ open class LinkerSpec : CommandLineToolSpec, @unchecked Sendable {
101103
self.dsymPath = dsymPath
102104
self.xcframeworkSourcePath = xcframeworkSourcePath
103105
self.privacyFile = privacyFile
106+
self.libPrefix = refSettings?.globalScope.evaluate(BuiltinMacros.EXECUTABLE_PREFIX) ?? ""
104107
}
105108
}
106109

Sources/SWBCore/SpecImplementations/Tools/LinkerTools.swift

Lines changed: 27 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1289,41 +1289,12 @@ public final class LdLinkerSpec : GenericLinkerSpec, SpecIdentifierType, @unchec
12891289
private static func computeLibraryArgs(_ libraries: [LibrarySpecifier], scope: MacroEvaluationScope) -> (args: [String], inputs: [Path]) {
12901290
// Construct the library arguments.
12911291
return libraries.compactMap { specifier -> (args: [String], inputs: [Path]) in
1292-
let basename = specifier.path.basename
1293-
1294-
// FIXME: This isn't a good system, we need to redesign how we talk to the linker w.r.t. search paths and our notion of paths.
12951292
switch specifier.kind {
1296-
case .static:
1297-
if specifier.useSearchPaths, basename.hasPrefix("lib"), basename.hasSuffix(".a") {
1298-
return (specifier.searchPathFlagsForLd(basename.withoutPrefix("lib").withoutSuffix(".a")), [])
1299-
}
1300-
return (specifier.absolutePathFlagsForLd(), [specifier.path])
1301-
case .dynamic:
1302-
let suffix = ".\(scope.evaluate(BuiltinMacros.DYNAMIC_LIBRARY_EXTENSION))"
1303-
if specifier.useSearchPaths, basename.hasPrefix("lib"), basename.hasSuffix(suffix) {
1304-
return (specifier.searchPathFlagsForLd(basename.withoutPrefix("lib").withoutSuffix(suffix)), [])
1305-
}
1306-
return (specifier.absolutePathFlagsForLd(), [specifier.path])
1307-
case .textBased:
1308-
if specifier.useSearchPaths, basename.hasPrefix("lib"), basename.hasSuffix(".tbd") {
1309-
// .merge and .reexport are not supported for text-based libraries.
1310-
return (specifier.searchPathFlagsForLd(basename.withoutPrefix("lib").withoutSuffix(".tbd")), [])
1311-
}
1312-
return (specifier.absolutePathFlagsForLd(), [specifier.path])
1313-
case .framework:
1314-
let frameworkName = Path(basename).withoutSuffix
1293+
case .static, .dynamic, .textBased, .framework:
13151294
if specifier.useSearchPaths {
1316-
return (specifier.searchPathFlagsForLd(frameworkName), [])
1317-
}
1318-
let absPathArgs = specifier.absolutePathFlagsForLd()
1319-
let returnPath: Path
1320-
if let pathArg = absPathArgs.last, Path(pathArg).basename == frameworkName {
1321-
returnPath = Path(pathArg)
1295+
return (specifier.searchPathFlagsForLd(), [])
13221296
}
1323-
else {
1324-
returnPath = specifier.path
1325-
}
1326-
return (absPathArgs, [returnPath])
1297+
return (specifier.absolutePathFlagsForLd(), [specifier.path])
13271298
case .object:
13281299
// Object files are added to linker inputs in the sources task producer.
13291300
return ([], [])
@@ -1559,35 +1530,39 @@ public final class LdLinkerSpec : GenericLinkerSpec, SpecIdentifierType, @unchec
15591530

15601531
/// Extensions to `LinkerSpec.LibrarySpecifier` specific to the dynamic linker.
15611532
fileprivate extension LinkerSpec.LibrarySpecifier {
1562-
func searchPathFlagsForLd(_ name: String) -> [String] {
1533+
func searchPathFlagsForLd() -> [String] {
1534+
let strippedName = Path(path.basename).withoutSuffix.withoutPrefix(libPrefix)
15631535
switch (kind, mode) {
1564-
case (.dynamic, .normal):
1565-
return ["-l" + name]
1536+
case (.static, .weak):
1537+
return ["-weak-l", strippedName]
1538+
case (.static, _),
1539+
(.dynamic, .normal):
1540+
return ["-l", strippedName]
15661541
case (.dynamic, .reexport):
1567-
return ["-Xlinker", "-reexport-l" + name]
1542+
return ["-Xlinker", "-reexport-l", strippedName]
15681543
case (.dynamic, .merge):
1569-
return ["-Xlinker", "-merge-l" + name]
1544+
return ["-Xlinker", "-merge-l", strippedName]
15701545
case (.dynamic, .reexport_merge):
1571-
return ["-Xlinker", "-no_merge-l" + name]
1546+
return ["-Xlinker", "-no_merge-l", strippedName]
15721547
case (.dynamic, .weak):
1573-
return ["-weak-l" + name]
1574-
case (.static, .weak),
1575-
(.textBased, .weak):
1576-
return ["-weak-l" + name]
1577-
case (.static, _),
1578-
(.textBased, _):
1548+
return ["-weak-l", strippedName]
1549+
case (.textBased, .weak):
1550+
// Until the tbd product type have a build setting for there prefix we just hard code this here for now
1551+
return ["-weak-l", Path(path.basename).withoutSuffix.withoutPrefix("lib")]
1552+
case (.textBased, _):
15791553
// Other modes are not supported for these kinds.
1580-
return ["-l" + name]
1554+
// Until the tbd product type have a build setting for there prefix we just hard code this here for now
1555+
return ["-l" + Path(path.basename).withoutSuffix.withoutPrefix("lib")]
15811556
case (.framework, .normal):
1582-
return ["-framework", name]
1557+
return ["-framework", strippedName]
15831558
case (.framework, .reexport):
1584-
return ["-Xlinker", "-reexport_framework", "-Xlinker", name]
1559+
return ["-Xlinker", "-reexport_framework", "-Xlinker", strippedName]
15851560
case (.framework, .merge):
1586-
return ["-Xlinker", "-merge_framework", "-Xlinker", name]
1561+
return ["-Xlinker", "-merge_framework", "-Xlinker", strippedName]
15871562
case (.framework, .reexport_merge):
1588-
return ["-Xlinker", "-no_merge_framework", "-Xlinker", name]
1563+
return ["-Xlinker", "-no_merge_framework", "-Xlinker", strippedName]
15891564
case (.framework, .weak):
1590-
return ["-weak_framework", name]
1565+
return ["-weak_framework", strippedName]
15911566
case (.object, _):
15921567
// Object files are added to linker inputs in the sources task producer.
15931568
return []
@@ -1724,9 +1699,9 @@ public final class LibtoolLinkerSpec : GenericLinkerSpec, SpecIdentifierType, @u
17241699
delegate.warning("Product \(cbc.output.basename) cannot weak-link \(specifier.kind) \(basename)")
17251700
}
17261701

1727-
if specifier.useSearchPaths, basename.hasPrefix("lib"), basename.hasSuffix(".a") {
1702+
if specifier.useSearchPaths {
17281703
// Locate using search paths: Add a -l option and *don't* add the path to the library as an input to the task.
1729-
return ["-l" + basename.withoutPrefix("lib").withoutSuffix(".a")]
1704+
return specifier.searchPathFlagsForLd()
17301705
}
17311706
else {
17321707
// Locate using an absolute path: Add the path as an option and as an input to the task.

Sources/SWBTaskConstruction/TaskProducers/BuildPhaseTaskProducers/SourcesTaskProducer.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,7 @@ package final class SourcesTaskProducer: FilesBasedBuildPhaseTaskProducerBase, F
506506
useSearchPaths: useSearchPaths,
507507
swiftModulePaths: swiftModulePaths,
508508
swiftModuleAdditionalLinkerArgResponseFilePaths: swiftModuleAdditionalLinkerArgResponseFilePaths,
509+
refSettings: settingsForRef,
509510
privacyFile: privacyFile
510511
)
511512
} else if fileType.conformsTo(context.lookupFileType(identifier: "compiled.mach-o.dylib")!) {
@@ -516,6 +517,7 @@ package final class SourcesTaskProducer: FilesBasedBuildPhaseTaskProducerBase, F
516517
useSearchPaths: useSearchPaths,
517518
swiftModulePaths: [:],
518519
swiftModuleAdditionalLinkerArgResponseFilePaths: [:],
520+
refSettings: settingsForRef,
519521
privacyFile: privacyFile
520522
)
521523
} else if fileType.conformsTo(context.lookupFileType(identifier: "sourcecode.text-based-dylib-definition")!) {
@@ -526,6 +528,7 @@ package final class SourcesTaskProducer: FilesBasedBuildPhaseTaskProducerBase, F
526528
useSearchPaths: useSearchPaths,
527529
swiftModulePaths: [:],
528530
swiftModuleAdditionalLinkerArgResponseFilePaths: [:],
531+
refSettings: settingsForRef,
529532
privacyFile: privacyFile
530533
)
531534
} else if fileType.conformsTo(context.lookupFileType(identifier: "wrapper.framework")!) {
@@ -571,6 +574,7 @@ package final class SourcesTaskProducer: FilesBasedBuildPhaseTaskProducerBase, F
571574
useSearchPaths: useSearchPaths,
572575
swiftModulePaths: [:],
573576
swiftModuleAdditionalLinkerArgResponseFilePaths: [:],
577+
refSettings: settingsForRef,
574578
topLevelItemPath: topLevelItemPath,
575579
dsymPath: dsymPath,
576580
privacyFile: privacyFile
@@ -580,7 +584,7 @@ package final class SourcesTaskProducer: FilesBasedBuildPhaseTaskProducerBase, F
580584
kind: .object,
581585
path: absolutePath,
582586
mode: buildFile.shouldLinkWeakly ? .weak : .normal,
583-
useSearchPaths: useSearchPaths,
587+
useSearchPaths: false,
584588
swiftModulePaths: swiftModulePaths,
585589
swiftModuleAdditionalLinkerArgResponseFilePaths: swiftModuleAdditionalLinkerArgResponseFilePaths,
586590
privacyFile: privacyFile

Sources/SWBTestSupport/TestWorkspaces.swift

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,23 +1028,15 @@ package final class TestStandardTarget: TestInternalTarget, Sendable {
10281028
return "\(name).app"
10291029
case .commandLineTool,
10301030
.hostBuildTool,
1031-
.swiftpmTestRunner:
1032-
return "\(name)"
1031+
.swiftpmTestRunner,
1032+
.staticLibrary,
1033+
.objectFile,
1034+
.objectLibrary,
1035+
.dynamicLibrary:
1036+
return "$(EXECUTABLE_NAME)"
10331037
case .framework,
10341038
.staticFramework:
10351039
return "\(name).framework"
1036-
case .staticLibrary:
1037-
return "lib\(name).a"
1038-
case .objectFile:
1039-
return "\(name).o"
1040-
case .objectLibrary:
1041-
return "\(name).objlib"
1042-
case .dynamicLibrary:
1043-
// FIXME: This should be based on the target platform, not the host. See also: <rdar://problem/29410050> Swift Build doesn't support product references with non-constant basenames
1044-
guard let suffix = try? ProcessInfo.processInfo.hostOperatingSystem().imageFormat.dynamicLibraryExtension else {
1045-
return ""
1046-
}
1047-
return "lib\(name).\(suffix)"
10481040
case .bundle:
10491041
return "\(name).bundle"
10501042
case .xpcService:

Sources/SWBWindowsPlatform/Plugin.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ struct WindowsSDKRegistryExtension: SDKRegistryExtension {
170170
"GENERATE_INTERMEDIATE_TEXT_BASED_STUBS": "NO",
171171

172172
"LIBRARY_SEARCH_PATHS": "$(inherited) $(SDKROOT)/usr/lib/swift/windows/$(CURRENT_ARCH)",
173-
"TEST_LIBRARY_SEARCH_PATHS": .plString("\(testingLibraryPath.strWithPosixSlashes)/Testing-$(SWIFT_TESTING_VERSION)/usr/lib/swift/windows/$(CURRENT_ARCH) \(testingLibraryPath.strWithPosixSlashes)/XCTest-$(XCTEST_VERSION)/usr/lib/swift/windows/$(CURRENT_ARCH)"),
173+
"TEST_LIBRARY_SEARCH_PATHS": .plString("\(testingLibraryPath.strWithPosixSlashes)/Testing-$(SWIFT_TESTING_VERSION)/usr/lib/swift/windows/ \(testingLibraryPath.strWithPosixSlashes)/Testing-$(SWIFT_TESTING_VERSION)/usr/lib/swift/windows/$(CURRENT_ARCH) \(testingLibraryPath.strWithPosixSlashes)/XCTest-$(XCTEST_VERSION)/usr/lib/swift/windows/$(CURRENT_ARCH) \(testingLibraryPath.strWithPosixSlashes)/XCTest-$(XCTEST_VERSION)/usr/lib/swift/windows"),
174174
"OTHER_SWIFT_FLAGS": "$(inherited) -libc $(DEFAULT_USE_RUNTIME)",
175175

176176
"DEFAULT_USE_RUNTIME": "MD",

Tests/SWBBuildSystemTests/BuildOperationTests.swift

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,7 @@ fileprivate struct BuildOperationTests: CoreBasedTests {
546546
}
547547
}
548548

549-
@Test(.requireSDKs(.host), .skipHostOS(.macOS), .skipHostOS(.windows, "cannot find testing library"))
549+
@Test(.requireSDKs(.host), .skipHostOS(.macOS))
550550
func unitTestWithGeneratedEntryPoint() async throws {
551551
try await withTemporaryDirectory(removeTreeOnDeinit: false) { (tmpDir: Path) in
552552
let testProject = try await TestProject(
@@ -582,7 +582,7 @@ fileprivate struct BuildOperationTests: CoreBasedTests {
582582
buildPhases: [
583583
TestSourcesBuildPhase(),
584584
TestFrameworksBuildPhase([
585-
"MyTests.so"
585+
TestBuildFile(.target("MyTests"))
586586
])
587587
],
588588
dependencies: ["MyTests"]
@@ -593,7 +593,7 @@ fileprivate struct BuildOperationTests: CoreBasedTests {
593593
buildConfigurations: [
594594
TestBuildConfiguration("Debug", buildSettings: [
595595
"LD_RUNPATH_SEARCH_PATHS": "$(RPATH_ORIGIN)",
596-
"LD_DYLIB_INSTALL_NAME": "MyTests.so"
596+
"LD_DYLIB_INSTALL_NAME": "$(EXECUTABLE_NAME)"
597597
])
598598
],
599599
buildPhases: [
@@ -604,19 +604,15 @@ fileprivate struct BuildOperationTests: CoreBasedTests {
604604
], dependencies: [
605605
"library"
606606
],
607-
productReferenceName: "MyTests.so"
607+
productReferenceName: "$(EXECUTABLE_NAME)"
608608
),
609609
TestStandardTarget(
610610
"library",
611611
type: .dynamicLibrary,
612612
buildConfigurations: [
613613
TestBuildConfiguration("Debug", buildSettings: [
614614
"LD_RUNPATH_SEARCH_PATHS": "$(RPATH_ORIGIN)",
615-
"LD_DYLIB_INSTALL_NAME": "liblibrary.so",
616-
617-
// FIXME: Find a way to make these default
618-
"EXECUTABLE_PREFIX": "lib",
619-
"EXECUTABLE_PREFIX[sdk=windows*]": "",
615+
"LD_DYLIB_INSTALL_NAME": "$(EXECUTABLE_NAME)",
620616
])
621617
],
622618
buildPhases: [
@@ -670,7 +666,7 @@ fileprivate struct BuildOperationTests: CoreBasedTests {
670666
}
671667
}
672668

673-
@Test(.requireSDKs(.host), .skipHostOS(.macOS), .skipHostOS(.windows, "cannot find testing library"))
669+
@Test(.requireSDKs(.host), .skipHostOS(.macOS))
674670
func unitTestWithGeneratedEntryPoint_testabilityDisabled() async throws {
675671
try await withTemporaryDirectory(removeTreeOnDeinit: false) { (tmpDir: Path) in
676672
let testProject = try await TestProject(
@@ -708,7 +704,7 @@ fileprivate struct BuildOperationTests: CoreBasedTests {
708704
buildPhases: [
709705
TestSourcesBuildPhase(),
710706
TestFrameworksBuildPhase([
711-
"MyTests.so"
707+
TestBuildFile(.target("MyTests"))
712708
])
713709
],
714710
dependencies: ["MyTests"]
@@ -719,7 +715,7 @@ fileprivate struct BuildOperationTests: CoreBasedTests {
719715
buildConfigurations: [
720716
TestBuildConfiguration("Debug", buildSettings: [
721717
"LD_RUNPATH_SEARCH_PATHS": "$(RPATH_ORIGIN)",
722-
"LD_DYLIB_INSTALL_NAME": "MyTests.so"
718+
"LD_DYLIB_INSTALL_NAME": "$(EXECUTABLE_NAME)"
723719
])
724720
],
725721
buildPhases: [
@@ -730,15 +726,15 @@ fileprivate struct BuildOperationTests: CoreBasedTests {
730726
], dependencies: [
731727
"library"
732728
],
733-
productReferenceName: "MyTests.so"
729+
productReferenceName: "$(EXECUTABLE_NAME)"
734730
),
735731
TestStandardTarget(
736732
"library",
737733
type: .dynamicLibrary,
738734
buildConfigurations: [
739735
TestBuildConfiguration("Debug", buildSettings: [
740736
"LD_RUNPATH_SEARCH_PATHS": "$(RPATH_ORIGIN)",
741-
"LD_DYLIB_INSTALL_NAME": "liblibrary.so",
737+
"LD_DYLIB_INSTALL_NAME": "$(EXECUTABLE_NAME)",
742738

743739
// FIXME: Find a way to make these default
744740
"EXECUTABLE_PREFIX": "lib",

Tests/SWBTaskConstructionTests/UnitTestTaskConstructionTests.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,6 @@ fileprivate struct UnitTestTaskConstructionTests: CoreBasedTests {
355355
])
356356
],
357357
dependencies: [],
358-
productReferenceName: "$(EXCTABLE_NAME)"
359358
),
360359
])
361360
let core = try await getCore()

0 commit comments

Comments
 (0)