Skip to content

[6.2] Cherry pick Static Library Binary targets #8705

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ Package.resolved
.vscode
Utilities/InstalledSwiftPMConfiguration/config.json
.devcontainer
Fixtures/BinaryLibraries/Static/Package1/Simple.artifactbundle/build
26 changes: 26 additions & 0 deletions Fixtures/BinaryLibraries/Static/Package1/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// swift-tools-version: 6.0

import PackageDescription

let package = Package(
name: "Package1",
targets: [
.executableTarget(
name: "Example",
dependencies: [
"Simple",
"Wrapper"
]
),
.target(
name: "Wrapper",
dependencies: [
"Simple"
]
),
.binaryTarget(
name: "Simple",
path: "Simple.artifactbundle"
),
]
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
SRC_FILES := $(wildcard *.c)

# Define architectures and platforms
ARCHS := x86_64 arm64
PLATFORMS := macos linux

# Define output directories
BUILD_DIR := build
DIST_DIR := dist

# Platform-specific settings
MACOS_SDK := $(shell xcrun --sdk macosx --show-sdk-path 2>/dev/null || echo "")
MACOS_MIN_VERSION := 10.15

# Compiler flags
COMMON_FLAGS := -O2

# Platform and architecture specific flags
MACOS_X86_64_FLAGS := -target x86_64-apple-macos$(MACOS_MIN_VERSION) -isysroot $(MACOS_SDK)
MACOS_ARM64_FLAGS := -target arm64-apple-macos$(MACOS_MIN_VERSION) -isysroot $(MACOS_SDK)
LINUX_X86_64_FLAGS := -target x86_64-unknown-linux-gnu
LINUX_ARM64_FLAGS := -target aarch64-unknown-linux-gnu

.PHONY: all clean macos linux universal

all: macos linux

# Create necessary directories
$(BUILD_DIR):
mkdir -p $(BUILD_DIR)/macos/x86_64
mkdir -p $(BUILD_DIR)/macos/arm64
mkdir -p $(BUILD_DIR)/linux/x86_64
mkdir -p $(BUILD_DIR)/linux/arm64

$(DIST_DIR):
mkdir -p $(DIST_DIR)/macos
mkdir -p $(DIST_DIR)/linux

# macOS x86_64 build
$(BUILD_DIR)/macos/x86_64/%.o: %.c | $(BUILD_DIR)
clang $(COMMON_FLAGS) $(MACOS_X86_64_FLAGS) -c -o $@ $<

# macOS arm64 build
$(BUILD_DIR)/macos/arm64/%.o: %.c | $(BUILD_DIR)
clang $(COMMON_FLAGS) $(MACOS_ARM64_FLAGS) -c -o $@ $<

# Linux x86_64 build
$(BUILD_DIR)/linux/x86_64/%.o: %.c | $(BUILD_DIR)
clang $(COMMON_FLAGS) $(LINUX_X86_64_FLAGS) -c -o $@ $<

# Linux arm64 build
$(BUILD_DIR)/linux/arm64/%.o: %.c | $(BUILD_DIR)
clang $(COMMON_FLAGS) $(LINUX_ARM64_FLAGS) -c -o $@ $<

# Define object files for each platform and architecture
MACOS_X86_64_OBJ_FILES := $(patsubst %.c,$(BUILD_DIR)/macos/x86_64/%.o,$(SRC_FILES))
MACOS_ARM64_OBJ_FILES := $(patsubst %.c,$(BUILD_DIR)/macos/arm64/%.o,$(SRC_FILES))
LINUX_X86_64_OBJ_FILES := $(patsubst %.c,$(BUILD_DIR)/linux/x86_64/%.o,$(SRC_FILES))
LINUX_ARM64_OBJ_FILES := $(patsubst %.c,$(BUILD_DIR)/linux/arm64/%.o,$(SRC_FILES))

# Create individual architecture libraries
$(DIST_DIR)/macos/libSimple_x86_64.a: $(MACOS_X86_64_OBJ_FILES) | $(DIST_DIR)
llvm-ar rc $@ $^

$(DIST_DIR)/macos/libSimple_arm64.a: $(MACOS_ARM64_OBJ_FILES) | $(DIST_DIR)
llvm-ar rc $@ $^

$(DIST_DIR)/linux/libSimple_x86_64.a: $(LINUX_X86_64_OBJ_FILES) | $(DIST_DIR)
llvm-ar rc $@ $^

$(DIST_DIR)/linux/libSimple_arm64.a: $(LINUX_ARM64_OBJ_FILES) | $(DIST_DIR)
llvm-ar rc $@ $^

# Create universal binary for macOS
$(DIST_DIR)/macos/libSimple.a: $(DIST_DIR)/macos/libSimple_x86_64.a $(DIST_DIR)/macos/libSimple_arm64.a
lipo -create -output $@ $^

# For Linux, we'll provide separate libraries since lipo is macOS-specific
linux: $(DIST_DIR)/linux/libSimple_x86_64.a $(DIST_DIR)/linux/libSimple_arm64.a
@echo "Linux libraries built in $(DIST_DIR)/linux/"
@echo "Note: For Linux, use the architecture-specific libraries as needed."

macos: $(DIST_DIR)/macos/libSimple.a
@echo "macOS universal library built at $(DIST_DIR)/macos/libSimple.a"

clean:
rm -rf $(BUILD_DIR) $(DIST_DIR)
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
int foo(void);
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module Simple {
header "simple.h"
export *
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"schemaVersion": "1.0",
"artifacts": {
"simple": {
"type": "staticLibrary",
"version": "1.0.0",
"variants": [
{
"path": "dist/macOS/libSimple.a",
"supportedTriples": ["arm64-apple-macosx", "x86_64-apple-macosx"],
"staticLibraryMetadata": {
"headerPaths": ["include"],
"moduleMapPath": "include/simple.modulemap"
}
},
{
"path": "dist/linux/libSimple_arm64.a",
"supportedTriples": ["aarch64-unknown-linux-gnu"],
"staticLibraryMetadata": {
"headerPaths": ["include"],
"moduleMapPath": "include/simple.modulemap"
}
},
{
"path": "dist/linux/libSimple_x86_64.a",
"supportedTriples": ["x86_64-unknown-linux-gnu"],
"staticLibraryMetadata": {
"headerPaths": ["include"],
"moduleMapPath": "include/simple.modulemap"
}
}
]
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
int foo(void) { return 42; }
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import Simple
import Wrapper

@main
struct Example {
static func main() {
print(foo())
print(bar())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
int bar(void);
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#include "simple.h"

int bar(void) { return foo(); }
19 changes: 17 additions & 2 deletions Sources/Build/BuildPlan/BuildPlan+Clang.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,22 @@ extension BuildPlan {
clangTarget.additionalFlags += ["-fmodule-map-file=\(target.moduleMapPath.pathString)"]
clangTarget.additionalFlags += try pkgConfig(for: target).cFlags
case let target as BinaryModule:
if case .xcframework = target.kind {
switch target.kind {
case .unknown:
break
case .artifactsArchive:
let libraries = try self.parseLibraryArtifactsArchive(for: target, triple: clangTarget.buildParameters.triple)
for library in libraries {
library.headersPaths.forEach {
clangTarget.additionalFlags += ["-I", $0.pathString]
}
if let moduleMapPath = library.moduleMapPath {
clangTarget.additionalFlags += ["-fmodule-map-file=\(moduleMapPath)"]
}

clangTarget.libraryBinaryPaths.insert(library.libraryPath)
}
case .xcframework:
let libraries = try self.parseXCFramework(for: target, triple: clangTarget.buildParameters.triple)
for library in libraries {
library.headersPaths.forEach {
Expand All @@ -57,9 +72,9 @@ extension BuildPlan {
clangTarget.libraryBinaryPaths.insert(library.libraryPath)
}
}

default: continue
}
}
}

}
29 changes: 23 additions & 6 deletions Sources/Build/BuildPlan/BuildPlan+Product.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import class PackageModel.SwiftModule
import class PackageModel.SystemLibraryModule
import struct SPMBuildCore.BuildParameters
import struct SPMBuildCore.ExecutableInfo
import struct SPMBuildCore.LibraryInfo
import func TSCBasic.topologicalSort

extension BuildPlan {
Expand All @@ -50,7 +51,7 @@ extension BuildPlan {
} else if binaryPath.basename.starts(with: "lib") {
buildProduct.additionalFlags += ["-l\(binaryPath.basenameWithoutExt.dropFirst(3))"]
} else {
self.observabilityScope.emit(error: "unexpected binary framework")
self.observabilityScope.emit(error: "unexpected binary name at \(binaryPath). Static libraries should be prefixed with lib")
}
}

Expand Down Expand Up @@ -297,10 +298,20 @@ extension BuildPlan {
libraryBinaryPaths.insert(library.libraryPath)
}
case .artifactsArchive:
let tools = try self.parseArtifactsArchive(
let tools = try self.parseExecutableArtifactsArchive(
for: binaryTarget, triple: productDescription.buildParameters.triple
)
tools.forEach { availableTools[$0.name] = $0.executablePath }
for tool in tools {
availableTools[tool.name] = tool.executablePath
}

let libraries = try self.parseLibraryArtifactsArchive(
for: binaryTarget,
triple: productDescription.buildParameters.triple
)
for library in libraries {
libraryBinaryPaths.insert(library.libraryPath)
}
case .unknown:
throw InternalError("unknown binary target '\(module.name)' type")
}
Expand Down Expand Up @@ -330,10 +341,16 @@ extension BuildPlan {
}

/// Extracts the artifacts from an artifactsArchive
private func parseArtifactsArchive(for binaryTarget: BinaryModule, triple: Triple) throws -> [ExecutableInfo] {
try self.externalExecutablesCache.memoize(key: binaryTarget) {
let execInfos = try binaryTarget.parseArtifactArchives(for: triple, fileSystem: self.fileSystem)
private func parseExecutableArtifactsArchive(for module: BinaryModule, triple: Triple) throws -> [ExecutableInfo] {
try self.externalExecutablesCache.memoize(key: module) {
let execInfos = try module.parseExecutableArtifactArchives(for: triple, fileSystem: self.fileSystem)
return execInfos.filter { !$0.supportedTriples.isEmpty }
}
}

func parseLibraryArtifactsArchive(for module: BinaryModule, triple: Triple) throws -> [LibraryInfo] {
try self.externalLibrariesCache.memoize(key: module) {
try module.parseLibraryArtifactArchives(for: triple, fileSystem: self.fileSystem)
}
}
}
19 changes: 18 additions & 1 deletion Sources/Build/BuildPlan/BuildPlan+Swift.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,24 @@ extension BuildPlan {
swiftTarget.additionalFlags += ["-Xcc", "-fmodule-map-file=\(target.moduleMapPath.pathString)"]
swiftTarget.additionalFlags += try pkgConfig(for: target).cFlags
case let target as BinaryModule:
if case .xcframework = target.kind {
switch target.kind {
case .unknown:
break
case .artifactsArchive:
let libraries = try self.parseLibraryArtifactsArchive(for: target, triple: swiftTarget.buildParameters.triple)
for library in libraries {
library.headersPaths.forEach {
swiftTarget.additionalFlags += ["-I", $0.pathString, "-Xcc", "-I", "-Xcc", $0.pathString]
}
if let moduleMapPath = library.moduleMapPath {
// We need to pass the module map if there is one. If there is none Swift cannot import it but
// this might still be valid
swiftTarget.additionalFlags += ["-Xcc", "-fmodule-map-file=\(moduleMapPath)"]
}

swiftTarget.libraryBinaryPaths.insert(library.libraryPath)
}
case .xcframework:
let libraries = try self.parseXCFramework(for: target, triple: swiftTarget.buildParameters.triple)
for library in libraries {
library.headersPaths.forEach {
Expand Down
2 changes: 1 addition & 1 deletion Sources/Build/BuildPlan/BuildPlan.swift
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ public class BuildPlan: SPMBuildCore.BuildPlan {
private var pkgConfigCache = [SystemLibraryModule: (cFlags: [String], libs: [String])]()

/// Cache for library information.
private var externalLibrariesCache = [BinaryModule: [LibraryInfo]]()
var externalLibrariesCache = [BinaryModule: [LibraryInfo]]()

/// Cache for tools information.
var externalExecutablesCache = [BinaryModule: [ExecutableInfo]]()
Expand Down
4 changes: 2 additions & 2 deletions Sources/PackageLoading/ManifestLoader+Validation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ import TSCUtility

public struct ManifestValidator {
static var supportedLocalBinaryDependencyExtensions: [String] {
["zip"] + BinaryModule.Kind.allCases.filter{ $0 != .unknown }.map { $0.fileExtension }
Set(["zip"] + BinaryModule.Kind.allCases.filter { !$0.isUnknown }.map { $0.fileExtension }).sorted()
}
static var supportedRemoteBinaryDependencyExtensions: [String] {
["zip", "artifactbundleindex"]
["artifactbundleindex", "zip"]
}

private let manifest: Manifest
Expand Down
Loading