load native libraries directly from application image

This commit is contained in:
Craig Raw
2026-03-13 07:59:39 +02:00
parent 019b11c95e
commit 98ae891898
5 changed files with 148 additions and 26 deletions
@@ -88,7 +88,6 @@ public class AppController implements Initializable {
public static final String LOADING_TRANSACTIONS_MESSAGE = "Loading wallet, select Transactions tab to view...";
public static final String CONNECTION_FAILED_PREFIX = "Connection failed: ";
public static final String TRYING_ANOTHER_SERVER_MESSAGE = "trying another server...";
public static final String JPACKAGE_APP_PATH = "jpackage.app-path";
@FXML
private VBox rootBox;
@@ -420,7 +419,7 @@ public class AppController implements Initializable {
networkItem.setOnAction(event -> restart(event, network));
restart.getItems().add(networkItem);
}
restart.setVisible(System.getProperty(JPACKAGE_APP_PATH) != null);
restart.setVisible(System.getProperty(SparrowWallet.JPACKAGE_APP_PATH) != null);
saveTransaction.setDisable(true);
showTransaction.visibleProperty().bind(Bindings.and(saveTransaction.visibleProperty(), saveTransaction.disableProperty().not()));
@@ -597,7 +596,7 @@ public class AppController implements Initializable {
sudo groupadd -f -r plugdev
sudo usermod -aG plugdev `whoami`
""";
String home = System.getProperty(JPACKAGE_APP_PATH);
String home = System.getProperty(SparrowWallet.JPACKAGE_APP_PATH);
if(home != null && !home.startsWith("/opt/sparrowwallet") && home.endsWith("bin/Sparrow")) {
home = home.replace("bin/Sparrow", "");
commands = commands.replace("/opt/sparrowwallet/", home);
@@ -1045,8 +1044,8 @@ public class AppController implements Initializable {
}
public void restart(ActionEvent event, Network network) {
if(System.getProperty(JPACKAGE_APP_PATH) == null) {
throw new IllegalStateException("Property " + JPACKAGE_APP_PATH + " is not present");
if(System.getProperty(SparrowWallet.JPACKAGE_APP_PATH) == null) {
throw new IllegalStateException("Property " + SparrowWallet.JPACKAGE_APP_PATH + " is not present");
}
Args args = getRestartArgs();
@@ -1067,7 +1066,7 @@ public class AppController implements Initializable {
private void restart(ActionEvent event, Args args) {
try {
List<String> cmd = new ArrayList<>();
cmd.add(System.getProperty(JPACKAGE_APP_PATH));
cmd.add(System.getProperty(SparrowWallet.JPACKAGE_APP_PATH));
cmd.addAll(args.toParams());
final ProcessBuilder builder = new ProcessBuilder(cmd);
if(OsType.getCurrent() == OsType.UNIX) {
@@ -22,10 +22,20 @@ public class SparrowWallet {
public static final String APP_VERSION_SUFFIX = "";
public static final String APP_HOME_PROPERTY = "sparrow.home";
public static final String NETWORK_ENV_PROPERTY = "SPARROW_NETWORK";
public static final String JPACKAGE_APP_PATH = "jpackage.app-path";
private static Instance instance;
public static void main(String[] argv) {
if(System.getProperty(JPACKAGE_APP_PATH) != null) {
String libDir = System.getProperty("java.home") + File.separator + "lib";
System.setProperty("jna.boot.library.path", libDir);
System.setProperty("jna.library.path", libDir);
System.setProperty("jSerialComm.library.path", libDir);
System.setProperty("org.usb4java.LibraryName", "usb4java");
System.setProperty("java.library.path", libDir);
}
Args args = new Args();
JCommander jCommander = JCommander.newBuilder().addObject(args).programName(APP_NAME.toLowerCase(Locale.ROOT)).acceptUnknownOptions(true).build();
jCommander.parse(argv);
@@ -23,6 +23,7 @@ import javafx.concurrent.Task;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.time.Duration;
@@ -42,22 +43,47 @@ public class Bwt {
public synchronized static void initialize() {
if(!initialized) {
OsType osType = OsType.getCurrent();
String osArch = System.getProperty("os.arch");
String libName;
if(osType == OsType.MACOS) {
libName = "libbwt_jni.dylib";
} else if(osType == OsType.WINDOWS) {
libName = "bwt_jni.dll";
} else {
libName = "libbwt_jni.so";
}
// Try loading from the application image lib/ directory
String javaHome = System.getProperty("java.home");
if(javaHome != null) {
File libFile = new File(javaHome, "lib" + java.io.File.separator + libName);
if(libFile.exists()) {
try {
System.load(libFile.getAbsolutePath());
initialized = true;
return;
} catch(UnsatisfiedLinkError e) {
log.debug("Could not load bwt from java.home, falling back to JAR extraction", e);
}
}
}
// Fallback: extract from JAR
try {
OsType osType = OsType.getCurrent();
String osArch = System.getProperty("os.arch");
if(osType == OsType.MACOS && osArch.equals("aarch64")) {
NativeUtils.loadLibraryFromJar("/native/osx/aarch64/libbwt_jni.dylib");
NativeUtils.loadLibraryFromJar("/native/osx/aarch64/" + libName);
} else if(osType == OsType.MACOS) {
NativeUtils.loadLibraryFromJar("/native/osx/x64/libbwt_jni.dylib");
NativeUtils.loadLibraryFromJar("/native/osx/x64/" + libName);
} else if(osType == OsType.WINDOWS) {
NativeUtils.loadLibraryFromJar("/native/windows/x64/bwt_jni.dll");
NativeUtils.loadLibraryFromJar("/native/windows/x64/" + libName);
} else if(osArch.equals("aarch64")) {
NativeUtils.loadLibraryFromJar("/native/linux/aarch64/libbwt_jni.so");
NativeUtils.loadLibraryFromJar("/native/linux/aarch64/" + libName);
} else {
NativeUtils.loadLibraryFromJar("/native/linux/x64/libbwt_jni.so");
NativeUtils.loadLibraryFromJar("/native/linux/x64/" + libName);
}
initialized = true;
} catch(IOException e) {
} catch(UnsatisfiedLinkError | IOException e) {
log.error("Error loading bwt library", e);
}
}