Skip to content

Commit fa97456

Browse files
committed
add linkage tests
1 parent fbb9bd8 commit fa97456

5 files changed

Lines changed: 89 additions & 169 deletions

File tree

Tests/LinkageTest/Package.swift

Lines changed: 14 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -3,164 +3,32 @@
33
import Foundation
44
import PackageDescription
55

6-
// Note: the JAVA_HOME environment variable must be set to point to where
7-
// Java is installed, e.g.,
8-
// Library/Java/JavaVirtualMachines/openjdk-21.jdk/Contents/Home.
9-
func findJavaHome() -> String {
10-
if let home = ProcessInfo.processInfo.environment["JAVA_HOME"] {
11-
return home
12-
}
13-
14-
// This is a workaround for envs (some IDEs) which have trouble with
15-
// picking up env variables during the build process
16-
let path = "\(FileManager.default.homeDirectoryForCurrentUser.path()).java_home"
17-
if let home = try? String(contentsOfFile: path, encoding: .utf8) {
18-
if let lastChar = home.last, lastChar.isNewline {
19-
return String(home.dropLast())
20-
}
21-
22-
return home
23-
}
24-
25-
if let home = getJavaHomeFromLibexecJavaHome(),
26-
!home.isEmpty
27-
{
28-
return home
29-
}
30-
31-
if let home = getJavaHomeFromSDKMAN() {
32-
return home
33-
}
34-
35-
if let home = getJavaHomeFromPath() {
36-
return home
37-
}
38-
39-
if ProcessInfo.processInfo.environment["SPI_PROCESSING"] == "1"
40-
&& ProcessInfo.processInfo.environment["SPI_BUILD"] == nil
41-
{
42-
return ""
43-
}
44-
fatalError("Please set the JAVA_HOME environment variable to point to where Java is installed.")
45-
}
46-
47-
/// On MacOS we can use the java_home tool as a fallback if we can't find JAVA_HOME environment variable.
48-
func getJavaHomeFromLibexecJavaHome() -> String? {
49-
let task = Process()
50-
task.executableURL = URL(fileURLWithPath: "/usr/libexec/java_home")
51-
52-
guard FileManager.default.fileExists(atPath: task.executableURL!.path) else {
53-
return nil
54-
}
55-
56-
let pipe = Pipe()
57-
task.standardOutput = pipe
58-
task.standardError = pipe
59-
60-
do {
61-
try task.run()
62-
task.waitUntilExit()
63-
64-
let data = pipe.fileHandleForReading.readDataToEndOfFile()
65-
let output = String(data: data, encoding: .utf8)?.trimmingCharacters(in: .whitespacesAndNewlines)
66-
67-
if task.terminationStatus == 0 {
68-
return output
69-
} else {
70-
return nil
71-
}
72-
} catch {
73-
return nil
74-
}
75-
}
76-
77-
func getJavaHomeFromSDKMAN() -> String? {
78-
let home = FileManager.default.homeDirectoryForCurrentUser
79-
.appendingPathComponent(".sdkman/candidates/java/current")
80-
81-
let javaBin = home.appendingPathComponent("bin/java").path
82-
if FileManager.default.isExecutableFile(atPath: javaBin) {
83-
return home.path
84-
}
85-
return nil
86-
}
87-
88-
func getJavaHomeFromPath() -> String? {
89-
let task = Process()
90-
task.executableURL = URL(fileURLWithPath: "/usr/bin/which")
91-
task.arguments = ["java"]
92-
93-
let pipe = Pipe()
94-
task.standardOutput = pipe
95-
96-
do {
97-
try task.run()
98-
task.waitUntilExit()
99-
guard task.terminationStatus == 0 else { return nil }
100-
101-
let data = pipe.fileHandleForReading.readDataToEndOfFile()
102-
guard
103-
let javaPath = String(data: data, encoding: .utf8)?
104-
.trimmingCharacters(in: .whitespacesAndNewlines),
105-
!javaPath.isEmpty
106-
else { return nil }
107-
108-
let resolved = URL(fileURLWithPath: javaPath).resolvingSymlinksInPath()
109-
return
110-
resolved
111-
.deletingLastPathComponent()
112-
.deletingLastPathComponent()
113-
.path
114-
} catch {
115-
return nil
116-
}
117-
}
118-
119-
let javaHome = findJavaHome()
120-
121-
let javaIncludePath = "\(javaHome)/include"
122-
#if os(Linux)
123-
let javaPlatformIncludePath = "\(javaIncludePath)/linux"
124-
#elseif os(macOS)
125-
let javaPlatformIncludePath = "\(javaIncludePath)/darwin"
126-
#elseif os(Windows)
127-
let javaPlatformIncludePath = "\(javaIncludePath)/win32"
128-
#endif
129-
1306
let package = Package(
1317
name: "linkage-test",
8+
platforms: [
9+
.macOS(.v15)
10+
],
13211
dependencies: [
13312
.package(name: "swift-java", path: "../..")
13413
],
13514
targets: [
13615
.executableTarget(
13716
name: "LinkageTest",
17+
dependencies: [
18+
.product(name: "SwiftJava", package: "swift-java")
19+
]
20+
),
21+
.executableTarget(
22+
name: "JExtractLinkageTest",
13823
dependencies: [
13924
.product(name: "SwiftJava", package: "swift-java")
14025
],
141-
swiftSettings: [
142-
.unsafeFlags(["-I\(javaIncludePath)", "-I\(javaPlatformIncludePath)"])
26+
exclude: [
27+
"swift-java.config"
14328
],
144-
linkerSettings: [
145-
.unsafeFlags(
146-
[
147-
"-L\(javaHome)/lib/server",
148-
"-Xlinker", "-rpath",
149-
"-Xlinker", "\(javaHome)/lib/server",
150-
],
151-
.when(platforms: [.linux, .macOS])
152-
),
153-
.unsafeFlags(
154-
[
155-
"-L\(javaHome)/lib"
156-
],
157-
.when(platforms: [.windows])
158-
),
159-
.linkedLibrary(
160-
"jvm",
161-
.when(platforms: [.linux, .macOS, .windows])
162-
),
29+
plugins: [
30+
.plugin(name: "JExtractSwiftPlugin", package: "swift-java")
16331
]
164-
)
32+
),
16533
]
16634
)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2024-2026 Apple Inc. and the Swift.org project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of Swift.org project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
public final class JExtractLinkageTest {
16+
public init() {}
17+
18+
public func hello() -> String {
19+
"Hello from JExtractLinkageTest"
20+
}
21+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2024-2025 Apple Inc. and the Swift.org project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of Swift.org project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import SwiftJava
16+
17+
let _ = try? JavaVirtualMachine.shared()
18+
let _ = SwiftPlatform.debugOrRelease
19+
print("Linkage test passed: SwiftJava imported successfully.")
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"javaPackage": "com.example.swift",
3+
"mode": "jni",
4+
"enableJavaCallbacks": true
5+
}

scripts/run-linkage-test.sh

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -24,30 +24,37 @@ echo "Detected JAVA_HOME=${JAVA_HOME}"
2424

2525
echo "Running on Linux - proceeding with linkage test..."
2626

27-
# Build the linkage test package
27+
# Build all targets in the linkage test package in one go
2828
echo "Building linkage test package..."
29-
swift build --package-path Tests/LinkageTest
29+
swift build --package-path Tests/LinkageTest --disable-sandbox
3030

31-
# Construct build path
3231
build_path=$(swift build --package-path Tests/LinkageTest --show-bin-path)
33-
binary_path="$build_path/LinkageTest"
3432

35-
# Verify the binary exists
36-
if [[ ! -f "$binary_path" ]]; then
37-
echo "Error: Built binary not found at $binary_path" >&2
38-
exit 1
39-
fi
40-
41-
echo "Checking linkage for binary: $binary_path"
42-
43-
# Run ldd and check if libFoundation.so is linked
44-
ldd_output=$(ldd "$binary_path")
45-
echo "LDD output:"
46-
echo "$ldd_output"
47-
48-
if echo "$ldd_output" | grep -q "libFoundation.so"; then
49-
echo "Error: Binary is linked against libFoundation.so - this indicates incorrect linkage. Ensure the full Foundation is not linked on Linux when FoundationEssentials is available." >&2
50-
exit 1
51-
else
52-
echo "Success: Binary is not linked against libFoundation.so - linkage test passed."
53-
fi
33+
check_linkage() {
34+
local name="$1"
35+
local binary="$build_path/$name"
36+
37+
if [[ ! -f "$binary" ]]; then
38+
echo "Error: Built binary not found at $binary" >&2
39+
exit 1
40+
fi
41+
42+
echo "Checking linkage for binary: $binary"
43+
local ldd_output
44+
ldd_output=$(ldd "$binary")
45+
echo "LDD output:"
46+
echo "$ldd_output"
47+
48+
if echo "$ldd_output" | grep -q "libFoundation.so"; then
49+
echo "Error: $name is linked against libFoundation.so - this indicates incorrect linkage. Ensure the full Foundation is not linked on Linux when FoundationEssentials is available." >&2
50+
exit 1
51+
else
52+
echo "Success: $name is not linked against libFoundation.so - linkage test passed."
53+
fi
54+
}
55+
56+
check_linkage "LinkageTest"
57+
58+
echo ""
59+
echo "Running JExtract linkage test (JExtractSwiftPlugin with enableJavaCallbacks)..."
60+
check_linkage "JExtractLinkageTest"

0 commit comments

Comments
 (0)