Skip to content

Commit 7b2534f

Browse files
committed
Force linker to lld on amazon linux 2.
There is a bug in the gold linker on amazon linux 2 See: https://sourceware.org/bugzilla/show_bug.cgi?id=23016 It is triggered when linking relocatable objects built with LLVM based compilers. * Add gear to detect the os distribution and version * For amazon linux 2 force ALTERNATE_LINKER to lld
1 parent 469349f commit 7b2534f

File tree

2 files changed

+159
-2
lines changed

2 files changed

+159
-2
lines changed

Sources/SWBGenericUnixPlatform/Plugin.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,10 @@ struct GenericUnixSDKRegistryExtension: SDKRegistryExtension {
126126
defaultProperties = [:]
127127
}
128128

129-
if operatingSystem == .freebsd || operatingSystem != context.hostOperatingSystem {
130-
// FreeBSD is always LLVM-based, and if we're cross-compiling, use lld
129+
if operatingSystem == .freebsd || (operatingSystem == .linux && operatingSystem.distribution?.kind == .amazon && operatingSystem.distribution?.version == "2") || operatingSystem != context.hostOperatingSystem {
130+
// FreeBSD is always LLVM-based, use lld
131+
// Amazon Linux 2 has a gold linker bug see: https://sourceware.org/bugzilla/show_bug.cgi?id=23016, use lld
132+
// or if we're cross-compiling, use lld
131133
defaultProperties["ALTERNATE_LINKER"] = "lld"
132134
}
133135

Sources/SWBUtil/ProcessInfo.swift

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,56 @@ extension ProcessInfo {
123123
return .unknown
124124
#endif
125125
}
126+
127+
128+
}
129+
130+
public struct LinuxDistribution: Hashable, Sendable {
131+
public enum Kind: String, CaseIterable, Hashable, Sendable {
132+
case unknown
133+
case ubuntu
134+
case debian
135+
case amazon = "amzn"
136+
case centos
137+
case rhel
138+
case fedora
139+
case suse
140+
case alpine
141+
case arch
142+
143+
/// The display name for the distribution kind
144+
public var displayName: String {
145+
switch self {
146+
case .unknown: return "Unknown Linux"
147+
case .ubuntu: return "Ubuntu"
148+
case .debian: return "Debian"
149+
case .amazon: return "Amazon Linux"
150+
case .centos: return "CentOS"
151+
case .rhel: return "Red Hat Enterprise Linux"
152+
case .fedora: return "Fedora"
153+
case .suse: return "SUSE"
154+
case .alpine: return "Alpine Linux"
155+
case .arch: return "Arch Linux"
156+
}
157+
}
158+
}
159+
160+
public let kind: Kind
161+
public let version: String?
162+
163+
public init(kind: Kind, version: String? = nil) {
164+
self.kind = kind
165+
self.version = version
166+
}
167+
168+
/// The display name for the distribution including version if available
169+
public var displayName: String {
170+
if let version = version {
171+
return "\(kind.displayName) \(version)"
172+
} else {
173+
return kind.displayName
174+
}
175+
}
126176
}
127177

128178
public enum OperatingSystem: Hashable, Sendable {
@@ -157,6 +207,16 @@ public enum OperatingSystem: Hashable, Sendable {
157207
}
158208
}
159209

210+
/// The distribution if this is a Linux operating system
211+
public var distribution: LinuxDistribution? {
212+
switch self {
213+
case .linux:
214+
return detectHostLinuxDistribution()
215+
default:
216+
return nil
217+
}
218+
}
219+
160220
public var imageFormat: ImageFormat {
161221
switch self {
162222
case .macOS, .iOS, .tvOS, .watchOS, .visionOS:
@@ -167,6 +227,101 @@ public enum OperatingSystem: Hashable, Sendable {
167227
return .elf
168228
}
169229
}
230+
231+
/// Detects the Linux distribution by examining system files
232+
/// Start with the "generic" /etc/os-release then fallback
233+
/// to various distribution named files.
234+
private func detectHostLinuxDistribution() -> LinuxDistribution? {
235+
#if os(Linux)
236+
// Try /etc/os-release first (standard)
237+
if let osRelease = try? String(contentsOfFile: "/etc/os-release") {
238+
if let distribution = parseOSRelease(osRelease) {
239+
return distribution
240+
}
241+
}
242+
// Fallback to distribution-specific files
243+
let distributionFiles: [(String, LinuxDistribution.Kind)] = [
244+
("/etc/ubuntu-release", .ubuntu),
245+
("/etc/debian_version", .debian),
246+
("/etc/amazon-release", .amazon),
247+
("/etc/centos-release", .centos),
248+
("/etc/redhat-release", .rhel),
249+
("/etc/fedora-release", .fedora),
250+
("/etc/SuSE-release", .suse),
251+
("/etc/alpine-release", .alpine),
252+
("/etc/arch-release", .arch),
253+
]
254+
for (file, kind) in distributionFiles {
255+
if FileManager.default.fileExists(atPath: file) {
256+
return LinuxDistribution(kind: kind)
257+
}
258+
}
259+
#endif
260+
return nil
261+
}
262+
263+
/// Parses /etc/os-release content to determine distribution and version
264+
/// Fallback to just getting the distribution from specific files.
265+
private func parseOSRelease(_ content: String) -> LinuxDistribution? {
266+
let lines = content.components(separatedBy: .newlines)
267+
var id: String?
268+
var idLike: String?
269+
var versionId: String?
270+
271+
// Parse out ID, ID_LIKE and VERSION_ID
272+
for line in lines {
273+
let trimmed = line.trimmingCharacters(in: .whitespaces)
274+
if trimmed.hasPrefix("ID=") {
275+
id = String(trimmed.dropFirst(3)).trimmingCharacters(in: CharacterSet(charactersIn: "\""))
276+
} else if trimmed.hasPrefix("ID_LIKE=") {
277+
idLike = String(trimmed.dropFirst(8)).trimmingCharacters(in: CharacterSet(charactersIn: "\""))
278+
} else if trimmed.hasPrefix("VERSION_ID=") {
279+
versionId = String(trimmed.dropFirst(11)).trimmingCharacters(in: CharacterSet(charactersIn: "\""))
280+
}
281+
}
282+
283+
// Check ID first
284+
if let id = id {
285+
let kind: LinuxDistribution.Kind?
286+
switch id.lowercased() {
287+
case "ubuntu": kind = .ubuntu
288+
case "debian": kind = .debian
289+
case "amzn": kind = .amazon
290+
case "centos": kind = .centos
291+
case "rhel": kind = .rhel
292+
case "fedora": kind = .fedora
293+
case "suse", "opensuse", "opensuse-leap", "opensuse-tumbleweed": kind = .suse
294+
case "alpine": kind = .alpine
295+
case "arch": kind = .arch
296+
default: kind = nil
297+
}
298+
299+
if let kind = kind {
300+
return LinuxDistribution(kind: kind, version: versionId)
301+
}
302+
}
303+
304+
// Check ID_LIKE as fallback
305+
if let idLike = idLike {
306+
let likes = idLike.components(separatedBy: .whitespaces)
307+
for like in likes {
308+
let kind: LinuxDistribution.Kind?
309+
switch like.lowercased() {
310+
case "ubuntu": kind = .ubuntu
311+
case "debian": kind = .debian
312+
case "rhel", "fedora": kind = .rhel
313+
case "suse": kind = .suse
314+
case "arch": kind = .arch
315+
default: kind = nil
316+
}
317+
318+
if let kind = kind {
319+
return LinuxDistribution(kind: kind, version: versionId)
320+
}
321+
}
322+
}
323+
return nil
324+
}
170325
}
171326

172327
public enum ImageFormat {

0 commit comments

Comments
 (0)