Skip to content

Commit 0061ee2

Browse files
authored
Merge pull request #22 from TheBlueMatt/main
Support building on OSX
2 parents 3d9f453 + a442b85 commit 0061ee2

File tree

17 files changed

+394
-75
lines changed

17 files changed

+394
-75
lines changed

.github/workflows/build.yml

Lines changed: 110 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,9 @@ jobs:
5151
run: ./genbindings.sh ./ldk-c-bindings/ "-I/usr/lib/jvm/java-11-openjdk-amd64/include/ -I/usr/lib/jvm/java-11-openjdk-amd64/include/linux/" true false
5252
- name: Run Java Tests against Debug Bindings
5353
run: |
54-
rm liblightningjni.so
55-
ln -s liblightningjni_debug.so liblightningjni.so
56-
export LD_LIBRARY_PATH=.
57-
export LD_PRELOAD=/usr/lib/llvm-11/lib/clang/11.0.1/lib/linux/libclang_rt.asan-x86_64.so
54+
mv liblightningjni_debug_Linux-amd64.so liblightningjni.so
5855
export ASAN_OPTIONS=detect_leaks=0
59-
mvn test
60-
git checkout liblightningjni.so
56+
LD_PRELOAD=/usr/lib/llvm-11/lib/clang/11.0.1/lib/linux/libclang_rt.asan-x86_64.so LD_LIBRARY_PATH=. mvn test
6157
- name: Build Java/TS Release Bindings
6258
run: |
6359
# We assume the top commit is just a bindings update commit, so we
@@ -73,8 +69,113 @@ jobs:
7369
fi
7470
echo "Using $LDK_GARBAGECOLLECTED_GIT_OVERRIDE as git version"
7571
./genbindings.sh ./ldk-c-bindings/ "-I/usr/lib/jvm/java-11-openjdk-amd64/include/ -I/usr/lib/jvm/java-11-openjdk-amd64/include/linux/" false false
76-
- name: Check latest headers are in git
72+
- name: Check latest headers and release lib are in git
7773
run: |
78-
# For some reason the debug library is not deterministic, this may be fixed in a future rustc
79-
git checkout liblightningjni_debug.so
8074
git diff --exit-code
75+
- name: Run Java Tests against built release jar
76+
run: |
77+
mvn -DskipTests=true package
78+
mvn install:install-file -Dfile=target/ldk-java-1.0-SNAPSHOT.jar -DgroupId=org.ldk -DartifactId=ldk-java -Dversion=1.0-SNAPSHOT -Dpackaging=jar
79+
cd javatester
80+
mvn package
81+
java -ea -jar target/ldk-java-tests-1.0-SNAPSHOT-jar-with-dependencies.jar
82+
cd ..
83+
84+
osx:
85+
strategy:
86+
matrix:
87+
include:
88+
- platform: macos-10.15
89+
# MacOS 11 is currently in private preview, we've applied for access
90+
# - platform: macos-11
91+
runs-on: ${{ matrix.platform }}
92+
env:
93+
TOOLCHAIN: stable
94+
steps:
95+
- name: Install other Rust platforms
96+
run: rustup target install aarch64-apple-darwin
97+
- name: Fetch upstream LLVM/clang snapshot
98+
run: |
99+
wget -O clang+llvm-12.0.0-x86_64-apple-darwin.tar.xz https://github.com/llvm/llvm-project/releases/download/llvmorg-12.0.0/clang+llvm-12.0.0-x86_64-apple-darwin.tar.xz
100+
if [ "$(shasum -a 256 clang+llvm-12.0.0-x86_64-apple-darwin.tar.xz | awk '{ print $1 }')" != "7bc2259bf75c003f644882460fc8e844ddb23b27236fe43a2787870a4cd8ab50" ]; then
101+
echo "Bad hash"
102+
exit 1
103+
fi
104+
- name: Unpack upstream LLVM+clang and use it by default
105+
run: |
106+
tar xvvf clang+llvm-12.0.0-x86_64-apple-darwin.tar.xz
107+
- name: Checkout source code
108+
uses: actions/checkout@v2
109+
with:
110+
fetch-depth: 0
111+
- name: Install cbindgen
112+
run: cargo install --force cbindgen
113+
- name: Checkout Rust-Lightning and LDK-C-Bindings git
114+
run: |
115+
git config --global user.email "[email protected]"
116+
git config --global user.name "LDK CI"
117+
git clone https://github.com/rust-bitcoin/rust-lightning
118+
cd rust-lightning
119+
git remote add matt https://git.bitcoin.ninja/rust-lightning
120+
git fetch matt
121+
git merge matt/2021-03-java-bindings-base
122+
cd ..
123+
git clone https://github.com/lightningdevkit/ldk-c-bindings
124+
- name: Rebuild C bindings with upstream clang, and check the sample app builds + links
125+
run: |
126+
cd ldk-c-bindings
127+
export PATH=`pwd`/clang+llvm-12.0.0-x86_64-apple-darwin/bin:$PATH
128+
CC=clang ./genbindings.sh ../rust-lightning true
129+
cd ..
130+
- name: Fetch OpenJDK 16
131+
run: |
132+
wget -O openjdk-16.0.1_osx-x64_bin.tar.gz https://download.java.net/java/GA/jdk16.0.1/7147401fd7354114ac51ef3e1328291f/9/GPL/openjdk-16.0.1_osx-x64_bin.tar.gz
133+
if [ "$(shasum -a 256 openjdk-16.0.1_osx-x64_bin.tar.gz | awk '{ print $1 }')" != "6098f839954439d4916444757c542c1b8778a32461706812d41cc8bbefce7f2f" ]; then
134+
echo "Bad hash"
135+
exit 1
136+
fi
137+
tar xvvf openjdk-16.0.1_osx-x64_bin.tar.gz
138+
export JAVA_HOME=`pwd`/jdk-16.0.1.jdk/Contents/Home
139+
export PATH=$JAVA_HOME/bin:$PATH
140+
- name: Build Java/TS Release Bindings
141+
run: |
142+
# We assume the top commit is just a bindings update commit, so we
143+
# check out the previous commit to use as the commit we git describe.
144+
# If the top commit is a merge commit, we need to get the last merge
145+
# head and assume the latest bindings are built against its parent.
146+
COMMIT_PARENTS=$(git show -s --pretty=format:%P HEAD)
147+
if [ "${#COMMIT_PARENTS}" = 40 ]; then
148+
export LDK_GARBAGECOLLECTED_GIT_OVERRIDE="$(git describe --tag HEAD^1)"
149+
else
150+
MERGE_HEAD=$(git show --pretty=format:%P HEAD | ( for last in $(cat /dev/stdin); do true; done; echo $last ))
151+
export LDK_GARBAGECOLLECTED_GIT_OVERRIDE="$(git describe --tag $MERGE_HEAD^1)"
152+
fi
153+
echo "Using $LDK_GARBAGECOLLECTED_GIT_OVERRIDE as git version"
154+
# genbindings.sh always fails as there is no wasm32-wasi library
155+
# available, so instead we delete the expected JNI library and check
156+
# that it was created.
157+
rm src/main/resources/liblightningjni_MacOSX-x86_64.nativelib
158+
./genbindings.sh ./ldk-c-bindings/ "-I$JAVA_HOME/include/ -I$JAVA_HOME/include/darwin -isysroot$(xcrun --show-sdk-path)" false false || echo
159+
cat src/main/resources/liblightningjni_MacOSX-x86_64.nativelib > /dev/null
160+
- name: Fetch Maven 3.8.1
161+
run: |
162+
wget -O apache-maven-3.8.1-bin.tar.gz https://apache.osuosl.org/maven/maven-3/3.8.1/binaries/apache-maven-3.8.1-bin.tar.gz
163+
if [ "$(shasum -a 256 apache-maven-3.8.1-bin.tar.gz | awk '{ print $1 }')" != "b98a1905eb554d07427b2e5509ff09bd53e2f1dd7a0afa38384968b113abef02" ]; then
164+
echo "Bad hash"
165+
exit 1
166+
fi
167+
tar xvvf apache-maven-3.8.1-bin.tar.gz
168+
export PATH=apache-maven-3.8.1/bin:$PATH
169+
- name: Run Java Tests against built jar
170+
run: |
171+
mvn -DskipTests=true package
172+
mvn install:install-file -Dfile=target/ldk-java-1.0-SNAPSHOT.jar -DgroupId=org.ldk -DartifactId=ldk-java -Dversion=1.0-SNAPSHOT -Dpackaging=jar
173+
cd javatester
174+
mvn package
175+
java -ea -jar target/ldk-java-tests-1.0-SNAPSHOT-jar-with-dependencies.jar
176+
cd ..
177+
- name: Check latest headers and release lib are in git
178+
run: |
179+
if [ "${{ matrix.platform }}" = "macos-11" ]; then
180+
git diff --exit-code
181+
fi

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,17 @@ bindings should be built with workarounds required for Android. JNI CFLAGS on de
2525
When running a program linking against the library in debug mode, LD_PRELOAD should likely include
2626
the relevant `libclang_rt.asan-platform.so` path.
2727

28+
Note that building with address sanitizer is only supported on MacOS with upstream clang (ie where
29+
the LLVM version in use matches the LLVM version against which rustc was built), not with Apple clang.
30+
Builds with Apple clang will work fine, but largely only be useful in a release context.
31+
To build on Mac with address sanitizer, you will need to run `ldk-c-bindings`' `genbindings.sh`
32+
script with upstream clang in your PATH and likely replace your $JAVA_HOME/bin/java with a simple
33+
wrapper which calls java after an export like:
34+
`export DYLD_INSERT_LIBRARIES=/path/to/upstream/llvm/lib/clang/12.0.0/lib/darwin/libclang_rt.asan_osx_dynamic.dylib`
35+
36+
To build for Apple M1 (ie aarch64-apple-darwin), you probably want something like
37+
`CC="clang --target=aarch64-apple-darwin" LDK_TARGET=aarch64-apple-darwin LDK_TARGET_CPU=generic ./genbindings.sh ...`
38+
2839
Status
2940
======
3041

genbindings.sh

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,30 @@ usage() {
1010
[ "$3" != "true" -a "$3" != "false" ] && usage
1111
[ "$4" != "true" -a "$4" != "false" ] && usage
1212

13+
set -x
14+
1315
if [ "$CC" != "" ]; then
1416
COMMON_COMPILE="$CC -std=c11 -Wall -Wextra -Wno-unused-parameter -Wno-ignored-qualifiers -Wno-unused-function -Wno-nullability-completeness -Wno-pointer-sign -Wdate-time -ffile-prefix-map=$(pwd)="
1517
else
18+
CC=clang
1619
COMMON_COMPILE="clang -std=c11 -Wall -Wextra -Wno-unused-parameter -Wno-ignored-qualifiers -Wno-unused-function -Wno-nullability-completeness -Wno-pointer-sign -Wdate-time -ffile-prefix-map=$(pwd)="
1720
fi
1821

19-
if [ "$LDK_TARGET" != "" ]; then
20-
LDK_TARGET_SUFFIX="_$LDK_TARGET"
22+
TARGET_STRING="$LDK_TARGET"
23+
if [ "$TARGET_STRING" = "" ]; then
24+
# We assume clang-style $CC --version here, but worst-case we just get an empty suffix
25+
TARGET_STRING="$($CC --version | grep Target | awk '{ print $2 }')"
2126
fi
27+
case "$TARGET_STRING" in
28+
"x86_64-pc-linux"*)
29+
LDK_TARGET_SUFFIX="_Linux-amd64" ;;
30+
"x86_64-apple-darwin"*)
31+
LDK_TARGET_SUFFIX="_MacOSX-x86_64" ;;
32+
"aarch64-apple-darwin"*)
33+
LDK_TARGET_SUFFIX="_MacOSX-aarch64" ;;
34+
*)
35+
LDK_TARGET_SUFFIX=""
36+
esac
2237
if [ "$LDK_TARGET_CPU" = "" ]; then
2338
LDK_TARGET_CPU="sandybridge"
2439
fi
@@ -52,12 +67,23 @@ cat src/main/jni/bindings.c.body >> src/main/jni/bindings.c
5267
javac -h src/main/jni src/main/java/org/ldk/enums/*.java src/main/java/org/ldk/impl/bindings.java
5368
rm src/main/java/org/ldk/enums/*.class src/main/java/org/ldk/impl/bindings*.class
5469

70+
IS_MAC=false
71+
[ "$($CC --version | grep apple-darwin)" != "" ] && IS_MAC=true
72+
5573
echo "Building Java bindings..."
56-
COMPILE="$COMMON_COMPILE -mcpu=$LDK_TARGET_CPU -Isrc/main/jni -pthread -ldl -Wl,--no-undefined -shared -fPIC"
74+
COMPILE="$COMMON_COMPILE -mcpu=$LDK_TARGET_CPU -Isrc/main/jni -pthread -ldl -shared -fPIC"
75+
[ "$IS_MAC" = "false" ] && COMPILE="$COMPILE -Wl,--no-undefined"
76+
[ "$IS_MAC" = "true" ] && COMPILE="$COMPILE -mmacosx-version-min=10.9"
5777
if [ "$3" = "true" ]; then
58-
$COMPILE -o liblightningjni_debug$LDK_TARGET_SUFFIX.so -g -fsanitize=address -shared-libasan -Wl,-wrap,calloc -Wl,-wrap,realloc -Wl,-wrap,reallocarray -Wl,-wrap,malloc -Wl,-wrap,free -rdynamic -I"$1"/lightning-c-bindings/include/ $2 src/main/jni/bindings.c "$1"/lightning-c-bindings/target/$LDK_TARGET/debug/libldk.a -lm
78+
[ "$IS_MAC" = "false" ] && COMPILE="$COMPILE -Wl,-wrap,calloc -Wl,-wrap,realloc -Wl,-wrap,reallocarray -Wl,-wrap,malloc -Wl,-wrap,free"
79+
$COMPILE -o liblightningjni_debug$LDK_TARGET_SUFFIX.so -g -fsanitize=address -shared-libasan -rdynamic -I"$1"/lightning-c-bindings/include/ $2 src/main/jni/bindings.c "$1"/lightning-c-bindings/target/$LDK_TARGET/debug/libldk.a -lm
5980
else
60-
$COMPILE -o liblightningjni_release$LDK_TARGET_SUFFIX.so -Wl,--version-script=libcode.version -flto -fuse-ld=lld -O3 -I"$1"/lightning-c-bindings/include/ $2 src/main/jni/bindings.c "$1"/lightning-c-bindings/target/$LDK_TARGET/release/libldk.a
81+
[ "$IS_MAC" = "false" ] && COMPILE="$COMPILE -Wl,--version-script=libcode.version -fuse-ld=lld"
82+
$COMPILE -o liblightningjni_release$LDK_TARGET_SUFFIX.so -flto -O3 -I"$1"/lightning-c-bindings/include/ $2 src/main/jni/bindings.c "$1"/lightning-c-bindings/target/$LDK_TARGET/release/libldk.a
83+
if [ "$LDK_TARGET_SUFFIX" != "" ]; then
84+
# Copy to JNI native directory for inclusion in JARs
85+
cp liblightningjni_release$LDK_TARGET_SUFFIX.so src/main/resources/liblightningjni$LDK_TARGET_SUFFIX.nativelib
86+
fi
6187
fi
6288

6389
echo "Creating TS bindings..."

java_strings.py

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from bindingstypes import *
22
from enum import Enum
3+
import sys
34

45
class Target(Enum):
56
JAVA = 1,
@@ -23,6 +24,12 @@ def __init__(self, DEBUG: bool, target: Target, **kwargs):
2324

2425
self.bindings_header = """package org.ldk.impl;
2526
import org.ldk.enums.*;
27+
import java.io.File;
28+
import java.io.InputStream;
29+
import java.io.IOException;
30+
import java.nio.file.Files;
31+
import java.nio.file.Path;
32+
import java.nio.file.StandardCopyOption;
2633
2734
public class bindings {
2835
public static class VecOrSliceDef {
@@ -34,7 +41,24 @@ def __init__(self, DEBUG: bool, target: Target, **kwargs):
3441
}
3542
}
3643
static {
37-
System.loadLibrary(\"lightningjni\");
44+
try {
45+
// Try to load natively first, this works on Android and in testing.
46+
System.loadLibrary(\"lightningjni\");
47+
} catch (UnsatisfiedLinkError _ignored) {
48+
// Otherwise try to load from the library jar.
49+
File tmpdir = new File(System.getProperty("java.io.tmpdir"), "ldk-java-nativelib");
50+
tmpdir.mkdir(); // If it fails to create, assume it was there already
51+
tmpdir.deleteOnExit();
52+
String libname = "liblightningjni_" + System.getProperty("os.name").replaceAll(" ", "") +
53+
"-" + System.getProperty("os.arch").replaceAll(" ", "") + ".nativelib";
54+
try (InputStream is = bindings.class.getResourceAsStream("/" + libname)) {
55+
Path libpath = new File(tmpdir.toPath().toString(), "liblightningjni.so").toPath();
56+
Files.copy(is, libpath, StandardCopyOption.REPLACE_EXISTING);
57+
Runtime.getRuntime().load(libpath.toString());
58+
} catch (IOException e) {
59+
throw new IllegalArgumentException(e);
60+
}
61+
}
3862
init(java.lang.Enum.class, VecOrSliceDef.class);
3963
init_class_cache();
4064
if (!get_lib_version_string().equals(get_ldk_java_bindings_version()))
@@ -83,11 +107,13 @@ class CommonBase {
83107
long ptr;
84108
LinkedList<Object> ptrs_to = new LinkedList();
85109
protected CommonBase(long ptr) { this.ptr = ptr; }
86-
public long _test_only_get_ptr() { return this.ptr; }
87110
}
88111
"""
89112

90-
self.c_file_pfx = """#include \"org_ldk_impl_bindings.h\"
113+
self.c_file_pfx = """#include <jni.h>
114+
// On OSX jlong (ie long long) is not equivalent to int64_t, so we override here
115+
#define int64_t jlong
116+
#include \"org_ldk_impl_bindings.h\"
91117
#include <lightning.h>
92118
#include <string.h>
93119
#include <stdatomic.h>
@@ -124,13 +150,15 @@ class CommonBase {
124150
else:
125151
self.c_file_pfx = self.c_file_pfx + "#define DEBUG_PRINT(...) fprintf(stderr, __VA_ARGS__)\n"
126152

127-
if not DEBUG:
153+
if not DEBUG or sys.platform == "darwin":
128154
self.c_file_pfx = self.c_file_pfx + """#define MALLOC(a, _) malloc(a)
129155
#define FREE(p) if ((uint64_t)(p) > 1024) { free(p); }
130-
#define DO_ASSERT(a) (void)(a)
156+
"""
157+
if not DEBUG:
158+
self.c_file_pfx += """#define DO_ASSERT(a) (void)(a)
131159
#define CHECK(a)
132160
"""
133-
else:
161+
if DEBUG:
134162
self.c_file_pfx = self.c_file_pfx + """#include <assert.h>
135163
// Always run a, then assert it is true:
136164
#define DO_ASSERT(a) do { bool _assert_val = (a); assert(_assert_val); } while(0)
@@ -144,16 +172,19 @@ class CommonBase {
144172
DEBUG_PRINT("LDK C Bindings version did not match the header we built against\\n");
145173
DEBUG_PRINT("Loaded LDK-Java Bindings with LDK %s and LDK-C-Bindings %s\\n", check_get_ldk_version(), check_get_ldk_bindings_version());
146174
}
175+
"""
147176

177+
if sys.platform != "darwin":
178+
self.c_file_pfx += """
148179
// Running a leak check across all the allocations and frees of the JDK is a mess,
149180
// so instead we implement our own naive leak checker here, relying on the -wrap
150181
// linker option to wrap malloc/calloc/realloc/free, tracking everyhing allocated
151182
// and free'd in Rust or C across the generated bindings shared library.
152183
#include <threads.h>
153184
"""
154185

155-
if self.target == Target.ANDROID:
156-
self.c_file_pfx = self.c_file_pfx + """
186+
if self.target == Target.ANDROID:
187+
self.c_file_pfx = self.c_file_pfx + """
157188
#include <unwind.h>
158189
#include <dlfcn.h>
159190
@@ -194,9 +225,9 @@ class CommonBase {
194225
}
195226
}
196227
"""
197-
else:
198-
self.c_file_pfx = self.c_file_pfx + "#include <execinfo.h>\n"
199-
self.c_file_pfx = self.c_file_pfx + """
228+
else:
229+
self.c_file_pfx = self.c_file_pfx + "#include <execinfo.h>\n"
230+
self.c_file_pfx = self.c_file_pfx + """
200231
#include <unistd.h>
201232
static mtx_t allocation_mtx;
202233

javatester/pom.xml

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<groupId>org.ldk</groupId>
8+
<artifactId>ldk-java-tests</artifactId>
9+
<version>1.0-SNAPSHOT</version>
10+
<dependencies>
11+
<dependency>
12+
<groupId>org.junit.jupiter</groupId>
13+
<artifactId>junit-jupiter-api</artifactId>
14+
<version>RELEASE</version>
15+
<scope>compile</scope>
16+
</dependency>
17+
<dependency>
18+
<groupId>org.bitcoinj</groupId>
19+
<artifactId>bitcoinj-core</artifactId>
20+
<version>0.15.10</version>
21+
<scope>compile</scope>
22+
</dependency>
23+
<dependency>
24+
<groupId>org.jetbrains</groupId>
25+
<artifactId>annotations</artifactId>
26+
<version>RELEASE</version>
27+
<scope>compile</scope>
28+
</dependency>
29+
<dependency>
30+
<groupId>org.ldk</groupId>
31+
<artifactId>ldk-java</artifactId>
32+
<version>1.0-SNAPSHOT</version>
33+
<scope>compile</scope>
34+
</dependency>
35+
</dependencies>
36+
<properties>
37+
<maven.compiler.source>1.8</maven.compiler.source>
38+
<maven.compiler.target>1.8</maven.compiler.target>
39+
</properties>
40+
41+
<build>
42+
<plugins>
43+
<plugin>
44+
<groupId>org.apache.maven.plugins</groupId>
45+
<artifactId>maven-assembly-plugin</artifactId>
46+
<version>3.2.0</version>
47+
<executions>
48+
<execution>
49+
<phase>package</phase>
50+
<goals>
51+
<goal>single</goal>
52+
</goals>
53+
<configuration>
54+
<archive>
55+
<manifest>
56+
<mainClass>org.ldk.HumanObjectPeerTest</mainClass>
57+
</manifest>
58+
</archive>
59+
<descriptorRefs>
60+
<descriptorRef>jar-with-dependencies</descriptorRef>
61+
</descriptorRefs>
62+
</configuration>
63+
</execution>
64+
</executions>
65+
</plugin>
66+
</plugins>
67+
</build>
68+
</project>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../../../../../src/test/java/org/ldk/HumanObjectPeerTest.java

0 commit comments

Comments
 (0)