Skip to content

Separate SwiftKit into SwiftKitCore and SwiftKitFFM #300

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 9 commits into from
Jul 8, 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 .github/actions/prepare_env/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ runs:
java-version: |
24
21
19
cache: 'gradle'
- name: Set JAVA_HOME_{N}
shell: bash
Expand Down
24 changes: 16 additions & 8 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,14 @@ jobs:
- uses: actions/checkout@v4
- name: Prepare CI Environment
uses: ./.github/actions/prepare_env
- name: Gradle :SwiftKit:build
run: ./gradlew build -x test
- name: Gradle :SwiftKit:check
run: ./gradlew :SwiftKit:check --info
- name: Gradle :SwiftKitCore:build
run: ./gradlew :SwiftKitCore:build -x test
- name: Gradle :SwiftKitCore:check
run: ./gradlew :SwiftKitCore:check --info
- name: Gradle :SwiftKitFFM:build
run: ./gradlew :SwiftKitFFM:build -x test
- name: Gradle :SwiftKitFFM:check
run: ./gradlew :SwiftKitFFM:check --info
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah that's nice actually to keep them separate rather than one big :check


test-java-macos:
name: Test (Java) (${{ matrix.os_version }} swift:${{ matrix.swift_version }} jdk:${{matrix.jdk_vendor}})
Expand All @@ -51,10 +55,14 @@ jobs:
- uses: actions/checkout@v4
- name: Prepare CI Environment
uses: ./.github/actions/prepare_env
- name: Gradle :SwiftKit:build
run: ./gradlew build -x test
- name: Gradle :SwiftKit:check
run: ./gradlew :SwiftKit:check --debug
- name: Gradle :SwiftKitCore:build
run: ./gradlew :SwiftKitCore:build -x test
- name: Gradle :SwiftKitCore:check
run: ./gradlew :SwiftKitCore:check --debug
- name: Gradle :SwiftKitFFM:build
run: ./gradlew :SwiftKitFFM:build -x test
- name: Gradle :SwiftKitFFM:check
run: ./gradlew :SwiftKitFFM:check --debug

benchmark-java:
name: Benchmark (JMH) (${{ matrix.os_version }} swift:${{ matrix.swift_version }} jdk:${{matrix.jdk_vendor}})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,6 @@ repositories {
mavenCentral()
}

testing {
suites {
val test by getting(JvmTestSuite::class) {
useJUnitJupiter("5.10.3")
}
}
}

/// Enable access to preview APIs, e.g. java.lang.foreign.* (Panama)
tasks.withType(JavaCompile::class).forEach {
it.options.compilerArgs.add("--enable-preview")
it.options.compilerArgs.add("-Xlint:preview")
}


fun getSwiftRuntimeLibraryPaths(): List<String> {
val process = ProcessBuilder("swiftc", "-print-target-info")
.redirectError(ProcessBuilder.Redirect.INHERIT)
Expand Down
2 changes: 1 addition & 1 deletion Samples/JExtractJNISampleApp/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ tasks.clean {
}

dependencies {
implementation(project(':SwiftKit'))
implementation(project(':SwiftKitCore'))

testImplementation(platform("org.junit:junit-bom:5.10.0"))
testImplementation("org.junit.jupiter:junit-jupiter")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@

// Import javakit/swiftkit support libraries

import org.swift.swiftkit.SwiftKit;
import org.swift.swiftkit.core.SwiftLibraries;

public class HelloJava2SwiftJNI {

public static void main(String[] args) {
System.out.print("Property: java.library.path = " + SwiftKit.getJavaLibraryPath());
System.out.print("Property: java.library.path = " + SwiftLibraries.getJavaLibraryPath());

examples();
}
Expand All @@ -35,10 +35,8 @@ static void examples() {
MySwiftLibrary.globalTakeIntInt(1337, 42);

long cnt = MySwiftLibrary.globalWriteString("String from Java");
SwiftKit.trace("count = " + cnt);

long i = MySwiftLibrary.globalMakeInt();
SwiftKit.trace("globalMakeInt() = " + i);

MySwiftClass.method();

Expand Down
3 changes: 2 additions & 1 deletion Samples/SwiftAndJavaJarSampleLib/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ java {
}

dependencies {
implementation(project(':SwiftKit'))
implementation(project(':SwiftKitCore'))
implementation(project(':SwiftKitFFM'))

testImplementation(platform("org.junit:junit-bom:5.10.0"))
testImplementation("org.junit.jupiter:junit-jupiter")
Expand Down
5 changes: 3 additions & 2 deletions Samples/SwiftAndJavaJarSampleLib/ci-validate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@ fi

# check if we can compile a plain Example file that uses the generated Java bindings that should be in the generated jar
# The classpath MUST end with a * if it contains jar files, and must not if it directly contains class files.
SWIFTKIT_CLASSPATH="$(pwd)/../../SwiftKit/build/libs/*"
SWIFTKIT_CORE_CLASSPATH="$(pwd)/../../SwiftKitCore/build/libs/*"
SWIFTKIT_FFM_CLASSPATH="$(pwd)/../../SwiftKitFFM/build/libs/*"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, sorry you had to go through figuring that out, but now you know hah :)

MYLIB_CLASSPATH="$(pwd)/build/libs/*"
CLASSPATH="$(pwd)/:${SWIFTKIT_CLASSPATH}:${MYLIB_CLASSPATH}"
CLASSPATH="$(pwd)/:${SWIFTKIT_FFM_CLASSPATH}:${SWIFTKIT_CORE_CLASSPATH}:${MYLIB_CLASSPATH}"
echo "CLASSPATH = ${CLASSPATH}"

$JAVAC -cp "${CLASSPATH}" Example.java
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//

package org.swift.swiftkit;
package org.swift.swiftkit.ffm;

import java.util.concurrent.TimeUnit;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,18 @@

// Import swift-extract generated sources

import com.example.swift.MySwiftLibrary;
import com.example.swift.MySwiftClass;

// Import javakit/swiftkit support libraries
import org.swift.swiftkit.SwiftArena;
import org.swift.swiftkit.SwiftKit;
import org.swift.swiftkit.SwiftValueWitnessTable;

import java.util.Arrays;
import org.swift.swiftkit.core.SwiftLibraries;
import org.swift.swiftkit.ffm.AllocatingSwiftArena;
import org.swift.swiftkit.ffm.SwiftRuntime;

public class HelloJava2Swift {

public static void main(String[] args) {
boolean traceDowncalls = Boolean.getBoolean("jextract.trace.downcalls");
System.out.println("Property: jextract.trace.downcalls = " + traceDowncalls);

System.out.print("Property: java.library.path = " +SwiftKit.getJavaLibraryPath());
System.out.print("Property: java.library.path = " + SwiftLibraries.getJavaLibraryPath());

examples();
}
Expand All @@ -43,12 +38,12 @@ static void examples() {
MySwiftLibrary.globalTakeInt(1337);

// Example of using an arena; MyClass.deinit is run at end of scope
try (var arena = SwiftArena.ofConfined()) {
try (var arena = AllocatingSwiftArena.ofConfined()) {
MySwiftClass obj = MySwiftClass.init(2222, 7777, arena);

// just checking retains/releases work
SwiftKit.retain(obj);
SwiftKit.release(obj);
SwiftRuntime.retain(obj);
SwiftRuntime.release(obj);

obj.voidMethod();
obj.takeIntMethod(42);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@

import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.swift.swiftkit.SwiftArena;
import org.swift.swiftkit.SwiftKit;
import org.swift.swiftkit.core.SwiftLibraries;
import org.swift.swiftkit.ffm.AllocatingSwiftArena;

import java.io.File;
import java.util.stream.Stream;
Expand All @@ -27,7 +27,7 @@
public class MySwiftClassTest {

void checkPaths(Throwable throwable) {
var paths = SwiftKit.getJavaLibraryPath().split(":");
var paths = SwiftLibraries.getJavaLibraryPath().split(":");
for (var path : paths) {
System.out.println("CHECKING PATH: " + path);
Stream.of(new File(path).listFiles())
Expand All @@ -42,7 +42,7 @@ void checkPaths(Throwable throwable) {

@Test
void test_MySwiftClass_voidMethod() {
try(var arena = SwiftArena.ofConfined()) {
try(var arena = AllocatingSwiftArena.ofConfined()) {
MySwiftClass o = MySwiftClass.init(12, 42, arena);
o.voidMethod();
} catch (Throwable throwable) {
Expand All @@ -52,7 +52,7 @@ void test_MySwiftClass_voidMethod() {

@Test
void test_MySwiftClass_makeIntMethod() {
try(var arena = SwiftArena.ofConfined()) {
try(var arena = AllocatingSwiftArena.ofConfined()) {
MySwiftClass o = MySwiftClass.init(12, 42, arena);
var got = o.makeIntMethod();
assertEquals(12, got);
Expand All @@ -62,7 +62,7 @@ void test_MySwiftClass_makeIntMethod() {
@Test
@Disabled // TODO: Need var mangled names in interfaces
void test_MySwiftClass_property_len() {
try(var arena = SwiftArena.ofConfined()) {
try(var arena = AllocatingSwiftArena.ofConfined()) {
MySwiftClass o = MySwiftClass.init(12, 42, arena);
var got = o.getLen();
assertEquals(12, got);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,10 @@

package com.example.swift;

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.swift.swiftkit.SwiftKit;

import java.util.Arrays;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;

import static org.junit.jupiter.api.Assertions.*;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//

package org.swift.swiftkit;
package org.swift.swiftkit.ffm;

import static org.junit.jupiter.api.Assertions.assertEquals;

Expand All @@ -24,16 +24,16 @@ public class MySwiftClassTest {

@Test
void call_retain_retainCount_release() {
var arena = SwiftArena.ofConfined();
var arena = AllocatingSwiftArena.ofConfined();
var obj = MySwiftClass.init(1, 2, arena);

assertEquals(1, SwiftKit.retainCount(obj));
assertEquals(1, SwiftRuntime.retainCount(obj));
// TODO: test directly on SwiftHeapObject inheriting obj

SwiftKit.retain(obj);
assertEquals(2, SwiftKit.retainCount(obj));
SwiftRuntime.retain(obj);
assertEquals(2, SwiftRuntime.retainCount(obj));

SwiftKit.release(obj);
assertEquals(1, SwiftKit.retainCount(obj));
SwiftRuntime.release(obj);
assertEquals(1, SwiftRuntime.retainCount(obj));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,15 @@
//
//===----------------------------------------------------------------------===//

package org.swift.swiftkit;
package org.swift.swiftkit.ffm;

import com.example.swift.MySwiftClass;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledIf;
import org.swift.swiftkit.util.PlatformUtils;
import org.swift.swiftkit.core.util.PlatformUtils;

import java.util.Arrays;
import java.util.stream.Collectors;

import static org.junit.jupiter.api.Assertions.*;
import static org.swift.swiftkit.SwiftKit.*;
import static org.swift.swiftkit.SwiftKit.retainCount;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.swift.swiftkit.ffm.SwiftRuntime.*;

public class SwiftArenaTest {

Expand All @@ -38,7 +33,7 @@ static boolean isAmd64() {
@Test
@DisabledIf("isAmd64")
public void arena_releaseClassOnClose_class_ok() {
try (var arena = SwiftArena.ofConfined()) {
try (var arena = AllocatingSwiftArena.ofConfined()) {
var obj = MySwiftClass.init(1, 2, arena);

retain(obj);
Expand Down
4 changes: 2 additions & 2 deletions Samples/SwiftKitSampleApp/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import groovy.json.JsonSlurper
import org.swift.swiftkit.gradle.BuildUtils

import java.nio.file.*
import kotlinx.serialization.json.*

plugins {
id("build-logic.java-application-conventions")
Expand Down Expand Up @@ -148,7 +147,8 @@ tasks.clean {
}

dependencies {
implementation(project(':SwiftKit'))
implementation(project(':SwiftKitCore'))
implementation(project(':SwiftKitFFM'))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick, no need to fix up right now -- since FFM depends on Core we could just list the FFM dependency here, it'd resolve properly I think even with project dependencies


testImplementation(platform("org.junit:junit-bom:5.10.0"))
testImplementation("org.junit.jupiter:junit-jupiter")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//

package org.swift.swiftkit;
package org.swift.swiftkit.ffm;

import com.example.swift.HelloJava2Swift;
import com.example.swift.MySwiftLibrary;
Expand All @@ -31,12 +31,12 @@ public class JavaToSwiftBenchmark {

@State(Scope.Benchmark)
public static class BenchmarkState {
ClosableSwiftArena arena;
ClosableAllocatingSwiftArena arena;
MySwiftClass obj;

@Setup(Level.Trial)
public void beforeAll() {
arena = SwiftArena.ofConfined();
arena = AllocatingSwiftArena.ofConfined();
obj = MySwiftClass.init(1, 2, arena);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,14 @@
//
//===----------------------------------------------------------------------===//

package org.swift.swiftkit;
package org.swift.swiftkit.ffm;

import com.example.swift.HelloJava2Swift;
import com.example.swift.MySwiftClass;
import com.example.swift.MySwiftLibrary;
import org.openjdk.jmh.annotations.*;
import org.swift.swiftkit.core.ClosableSwiftArena;

import java.lang.foreign.Arena;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;

@BenchmarkMode(Mode.AverageTime)
Expand All @@ -40,12 +39,12 @@ public class StringPassingBenchmark {
public int stringLen;
public String string;

ClosableSwiftArena arena;
ClosableAllocatingSwiftArena arena;
MySwiftClass obj;

@Setup(Level.Trial)
public void beforeAll() {
arena = SwiftArena.ofConfined();
arena = AllocatingSwiftArena.ofConfined();
obj = MySwiftClass.init(1, 2, arena);
string = makeString(stringLen);
}
Expand Down
Loading
Loading