From 34ab22710f7ca0454a706b22ddf6e61f532bacc1 Mon Sep 17 00:00:00 2001 From: Johan Vos Date: Wed, 22 Feb 2023 17:45:10 +0100 Subject: [PATCH 1/6] Add required code so that plugins can request to build a static library. This is currently a no-op. Having this PR integrated allows the plugins to add the static lib option as well. Fix #1203 --- .../gluonhq/substrate/SubstrateDispatcher.java | 16 ++++++++++++++++ .../model/InternalProjectConfiguration.java | 9 +++++++++ .../target/AbstractTargetConfiguration.java | 15 ++++++++++++++- .../substrate/target/TargetConfiguration.java | 9 +++++++++ 4 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/gluonhq/substrate/SubstrateDispatcher.java b/src/main/java/com/gluonhq/substrate/SubstrateDispatcher.java index 35a030d1..bf01fe4a 100644 --- a/src/main/java/com/gluonhq/substrate/SubstrateDispatcher.java +++ b/src/main/java/com/gluonhq/substrate/SubstrateDispatcher.java @@ -510,4 +510,20 @@ public boolean nativeSharedLibrary() throws Exception { config.setSharedLibrary(true); return targetConfiguration.createSharedLib(); } + + /** + * This method builds a static library that can be used by third + * party projects, considering it contains one or more entry points. + * + * Static entry points, callable from C, can be created with the {@code @CEntryPoint} + * annotation. + * + * @throws Exception + */ + public boolean nativeStaticLibrary() throws Exception { + Logger.logInfo(logTitle("STATIC LIBRARY TASK")); + config.setStaticLibrary(true); + return targetConfiguration.createStaticLib(); + } + } diff --git a/src/main/java/com/gluonhq/substrate/model/InternalProjectConfiguration.java b/src/main/java/com/gluonhq/substrate/model/InternalProjectConfiguration.java index 76fa1bfe..bc56db1b 100644 --- a/src/main/java/com/gluonhq/substrate/model/InternalProjectConfiguration.java +++ b/src/main/java/com/gluonhq/substrate/model/InternalProjectConfiguration.java @@ -66,6 +66,7 @@ public class InternalProjectConfiguration { private boolean enableCheckHash = true; private boolean usesJDK11 = false; private boolean sharedLibrary = false; + private boolean staticLibrary = false; private String backend; private List initBuildTimeList; @@ -335,6 +336,14 @@ public void setSharedLibrary(boolean sharedLibrary) { this.sharedLibrary = sharedLibrary; } + public boolean isStaticLibrary() { + return staticLibrary; + } + + public void setStaticLibrary(boolean staticLibrary) { + this.staticLibrary = staticLibrary; + } + public Triplet getTargetTriplet() { return Objects.requireNonNull( publicConfig.getTargetTriplet(), "Target triplet is required"); } diff --git a/src/main/java/com/gluonhq/substrate/target/AbstractTargetConfiguration.java b/src/main/java/com/gluonhq/substrate/target/AbstractTargetConfiguration.java index 50fe4070..676bd1a8 100644 --- a/src/main/java/com/gluonhq/substrate/target/AbstractTargetConfiguration.java +++ b/src/main/java/com/gluonhq/substrate/target/AbstractTargetConfiguration.java @@ -201,7 +201,9 @@ public boolean link() throws IOException, InterruptedException { new IllegalArgumentException( "Linking failed, since there is no objectfile named " + objectFilename + " under " + gvmPath.toString()) ); - + if (projectConfiguration.isStaticLibrary()) { + return createStaticLib(); + } ProcessRunner linkRunner = new ProcessRunner(getLinker()); Path gvmAppPath = gvmPath.resolve(appName); @@ -317,6 +319,17 @@ public boolean createSharedLib() throws IOException, InterruptedException { return true; } + /** + * Creates a static library + * @return true if the process succeeded or false if the process failed + * @throws IOException + * @throws InterruptedException + */ + @Override + public boolean createStaticLib() throws IOException, InterruptedException { + return true; + } + // --- private methods protected boolean compileAdditionalSources() diff --git a/src/main/java/com/gluonhq/substrate/target/TargetConfiguration.java b/src/main/java/com/gluonhq/substrate/target/TargetConfiguration.java index 262926e9..4552f2f2 100644 --- a/src/main/java/com/gluonhq/substrate/target/TargetConfiguration.java +++ b/src/main/java/com/gluonhq/substrate/target/TargetConfiguration.java @@ -91,4 +91,13 @@ public interface TargetConfiguration { * @throws InterruptedException */ boolean createSharedLib() throws IOException, InterruptedException; + + /** + * Creates a static library + * @return true if the process succeeded or false if the process failed + * @throws IOException + * @throws InterruptedException + */ + boolean createStaticLib() throws IOException, InterruptedException; + } From df6fed36da0b7a0470d03218c5fc5417d73205ec Mon Sep 17 00:00:00 2001 From: Johan Vos Date: Wed, 22 Feb 2023 19:35:05 +0100 Subject: [PATCH 2/6] move javadoc to superclass and add explicit reference that linking can also be used to link to a library --- .../substrate/target/AbstractTargetConfiguration.java | 5 ----- .../com/gluonhq/substrate/target/TargetConfiguration.java | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/gluonhq/substrate/target/AbstractTargetConfiguration.java b/src/main/java/com/gluonhq/substrate/target/AbstractTargetConfiguration.java index 676bd1a8..0ab15be9 100644 --- a/src/main/java/com/gluonhq/substrate/target/AbstractTargetConfiguration.java +++ b/src/main/java/com/gluonhq/substrate/target/AbstractTargetConfiguration.java @@ -184,11 +184,6 @@ public boolean compile() throws IOException, InterruptedException { return validateCompileResult(result); } - /** - * Links a previously created objectfile with the required - * dependencies into a native executable. - * @return true if linking succeeded, false otherwise - */ @Override public boolean link() throws IOException, InterruptedException { compileAdditionalSources(); diff --git a/src/main/java/com/gluonhq/substrate/target/TargetConfiguration.java b/src/main/java/com/gluonhq/substrate/target/TargetConfiguration.java index 4552f2f2..da00a1d7 100644 --- a/src/main/java/com/gluonhq/substrate/target/TargetConfiguration.java +++ b/src/main/java/com/gluonhq/substrate/target/TargetConfiguration.java @@ -39,6 +39,11 @@ public interface TargetConfiguration { */ boolean compile() throws Exception; + /** + * Links a previously created objectfile with the required + * dependencies into a native executable or library + * @return true if linking succeeded, false otherwise + */ boolean link() throws IOException, InterruptedException; /** From c85cb2cfe2497354fe80737e6e0916450eddc254 Mon Sep 17 00:00:00 2001 From: Johan Vos Date: Wed, 22 Feb 2023 19:59:03 +0100 Subject: [PATCH 3/6] Add this branch to GA --- .github/workflows/build.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4540c94c..8ba2f1dc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,9 +2,11 @@ name: Substrate Build on: push: branches: + - entropy - master pull_request: branches: + - entropy - master jobs: From 31e013a8595af4b0f13c8560d0de2029dca98bc9 Mon Sep 17 00:00:00 2001 From: Johan Vos Date: Wed, 1 Mar 2023 10:22:33 +0100 Subject: [PATCH 4/6] add link to static archive for iOS --- .../target/AbstractTargetConfiguration.java | 48 +++++++++++++++---- .../target/AndroidTargetConfiguration.java | 1 + .../target/IosTargetConfiguration.java | 15 ++++++ 3 files changed, 54 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/gluonhq/substrate/target/AbstractTargetConfiguration.java b/src/main/java/com/gluonhq/substrate/target/AbstractTargetConfiguration.java index 0ab15be9..4004f09a 100644 --- a/src/main/java/com/gluonhq/substrate/target/AbstractTargetConfiguration.java +++ b/src/main/java/com/gluonhq/substrate/target/AbstractTargetConfiguration.java @@ -190,23 +190,16 @@ public boolean link() throws IOException, InterruptedException { ensureClibs(); String appName = projectConfiguration.getAppName(); - String objectFilename = projectConfiguration.getMainClassName().toLowerCase(Locale.ROOT) + "." + getObjectFileExtension(); Path gvmPath = paths.getGvmPath(); - Path objectFile = FileOps.findFile(gvmPath, objectFilename).orElseThrow( () -> - new IllegalArgumentException( - "Linking failed, since there is no objectfile named " + objectFilename + " under " + gvmPath.toString()) - ); + Path objectFile = getProjectObjectFile(); + if (projectConfiguration.isStaticLibrary()) { return createStaticLib(); } ProcessRunner linkRunner = new ProcessRunner(getLinker()); Path gvmAppPath = gvmPath.resolve(appName); - linkRunner.addArgs(getAdditionalSourceFiles().stream() - .map(s -> s.replaceAll("\\..*", "." + getObjectFileExtension())) - .distinct() - .map(sourceFile -> gvmAppPath.resolve(sourceFile).toString()) - .collect(Collectors.toList())); + linkRunner.addArgs(getAdditionalObjectFiles()); linkRunner.addArg(objectFile.toString()); linkRunner.addArgs(getTargetSpecificObjectFiles()); @@ -986,6 +979,7 @@ List getTargetSpecificAOTCompileFlags() throws IOException { return Collections.emptyList(); } + @Deprecated List getTargetSpecificObjectFiles() throws IOException { return Collections.emptyList(); } @@ -1038,4 +1032,38 @@ protected List getStaticJDKLibPaths() throws IOException { return Arrays.asList(staticJDKLibPath); } } + + /** + * Get the objectfiles that are compiled from the additionalSourceFiles + * + * @return + */ + final List getAdditionalObjectFiles() { + String appName = projectConfiguration.getAppName(); + Path gvmPath = paths.getGvmPath(); + Path gvmAppPath = gvmPath.resolve(appName); + List answer = getAdditionalSourceFiles().stream() + .map(s -> s.replaceAll("\\..*", "." + getObjectFileExtension())) + .distinct() + .map(sourceFile -> gvmAppPath.resolve(sourceFile).toString()) + .collect(Collectors.toList()); + + return answer; + } + + /** + * Return the location of the compiled application file. This is the file + * that is generated by the AOT compiler. + * + * @return the Path to the compiled application + */ + final Path getProjectObjectFile() throws IOException { + Path gvmPath = paths.getGvmPath(); + String objectFilename = projectConfiguration.getMainClassName().toLowerCase(Locale.ROOT) + "." + getObjectFileExtension(); + Path objectFile = FileOps.findFile(gvmPath, objectFilename).orElseThrow(() + -> new IllegalArgumentException( + "Linking failed, since there is no objectfile named " + objectFilename + " under " + gvmPath.toString()) + ); + return objectFile; + } } diff --git a/src/main/java/com/gluonhq/substrate/target/AndroidTargetConfiguration.java b/src/main/java/com/gluonhq/substrate/target/AndroidTargetConfiguration.java index f484d05b..934b1f9d 100644 --- a/src/main/java/com/gluonhq/substrate/target/AndroidTargetConfiguration.java +++ b/src/main/java/com/gluonhq/substrate/target/AndroidTargetConfiguration.java @@ -249,6 +249,7 @@ List getTargetSpecificAOTCompileFlags() throws IOException { return flags; } + @Deprecated @Override List getTargetSpecificObjectFiles() throws IOException { if (projectConfiguration.isUseLLVM()) { diff --git a/src/main/java/com/gluonhq/substrate/target/IosTargetConfiguration.java b/src/main/java/com/gluonhq/substrate/target/IosTargetConfiguration.java index 0a097183..508a8049 100644 --- a/src/main/java/com/gluonhq/substrate/target/IosTargetConfiguration.java +++ b/src/main/java/com/gluonhq/substrate/target/IosTargetConfiguration.java @@ -203,6 +203,7 @@ List copyAdditionalSourceFiles(Path workDir) throws IOException { return files; } + @Deprecated @Override List getTargetSpecificObjectFiles() throws IOException { if (isSimulator() || !projectConfiguration.isUseLLVM()) { @@ -342,6 +343,20 @@ String getAppPath(String appName) { return appPath.toString() + "/" + appName; } + @Override + public boolean createStaticLib() throws IOException, InterruptedException { + ProcessRunner linkRunner = new ProcessRunner("ar"); + linkRunner.addArg("rcs"); + Path dest = paths.getGvmPath().resolve("lib"+projectConfiguration.getAppName()+".a"); + linkRunner.addArg(dest.toString()); + linkRunner.addArg(getProjectObjectFile().toString()); + linkRunner.addArgs(getAdditionalObjectFiles()); + linkRunner.setInfo(true); + linkRunner.setLogToFile(true); + int result = linkRunner.runProcess("archive"); + return result == 0; + } + private String getTargetArch() { return projectConfiguration.getTargetTriplet().getArch(); } From ca315a6cb4263c6d87eecebe93283eb53da4ac43 Mon Sep 17 00:00:00 2001 From: Johan Vos Date: Wed, 1 Mar 2023 10:50:38 +0100 Subject: [PATCH 5/6] Add static link procedure to create a static library on iOS. --- .../target/AbstractTargetConfiguration.java | 48 +++++++++++++++---- .../target/AndroidTargetConfiguration.java | 1 + .../target/IosTargetConfiguration.java | 15 ++++++ 3 files changed, 54 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/gluonhq/substrate/target/AbstractTargetConfiguration.java b/src/main/java/com/gluonhq/substrate/target/AbstractTargetConfiguration.java index 0ab15be9..4004f09a 100644 --- a/src/main/java/com/gluonhq/substrate/target/AbstractTargetConfiguration.java +++ b/src/main/java/com/gluonhq/substrate/target/AbstractTargetConfiguration.java @@ -190,23 +190,16 @@ public boolean link() throws IOException, InterruptedException { ensureClibs(); String appName = projectConfiguration.getAppName(); - String objectFilename = projectConfiguration.getMainClassName().toLowerCase(Locale.ROOT) + "." + getObjectFileExtension(); Path gvmPath = paths.getGvmPath(); - Path objectFile = FileOps.findFile(gvmPath, objectFilename).orElseThrow( () -> - new IllegalArgumentException( - "Linking failed, since there is no objectfile named " + objectFilename + " under " + gvmPath.toString()) - ); + Path objectFile = getProjectObjectFile(); + if (projectConfiguration.isStaticLibrary()) { return createStaticLib(); } ProcessRunner linkRunner = new ProcessRunner(getLinker()); Path gvmAppPath = gvmPath.resolve(appName); - linkRunner.addArgs(getAdditionalSourceFiles().stream() - .map(s -> s.replaceAll("\\..*", "." + getObjectFileExtension())) - .distinct() - .map(sourceFile -> gvmAppPath.resolve(sourceFile).toString()) - .collect(Collectors.toList())); + linkRunner.addArgs(getAdditionalObjectFiles()); linkRunner.addArg(objectFile.toString()); linkRunner.addArgs(getTargetSpecificObjectFiles()); @@ -986,6 +979,7 @@ List getTargetSpecificAOTCompileFlags() throws IOException { return Collections.emptyList(); } + @Deprecated List getTargetSpecificObjectFiles() throws IOException { return Collections.emptyList(); } @@ -1038,4 +1032,38 @@ protected List getStaticJDKLibPaths() throws IOException { return Arrays.asList(staticJDKLibPath); } } + + /** + * Get the objectfiles that are compiled from the additionalSourceFiles + * + * @return + */ + final List getAdditionalObjectFiles() { + String appName = projectConfiguration.getAppName(); + Path gvmPath = paths.getGvmPath(); + Path gvmAppPath = gvmPath.resolve(appName); + List answer = getAdditionalSourceFiles().stream() + .map(s -> s.replaceAll("\\..*", "." + getObjectFileExtension())) + .distinct() + .map(sourceFile -> gvmAppPath.resolve(sourceFile).toString()) + .collect(Collectors.toList()); + + return answer; + } + + /** + * Return the location of the compiled application file. This is the file + * that is generated by the AOT compiler. + * + * @return the Path to the compiled application + */ + final Path getProjectObjectFile() throws IOException { + Path gvmPath = paths.getGvmPath(); + String objectFilename = projectConfiguration.getMainClassName().toLowerCase(Locale.ROOT) + "." + getObjectFileExtension(); + Path objectFile = FileOps.findFile(gvmPath, objectFilename).orElseThrow(() + -> new IllegalArgumentException( + "Linking failed, since there is no objectfile named " + objectFilename + " under " + gvmPath.toString()) + ); + return objectFile; + } } diff --git a/src/main/java/com/gluonhq/substrate/target/AndroidTargetConfiguration.java b/src/main/java/com/gluonhq/substrate/target/AndroidTargetConfiguration.java index f484d05b..934b1f9d 100644 --- a/src/main/java/com/gluonhq/substrate/target/AndroidTargetConfiguration.java +++ b/src/main/java/com/gluonhq/substrate/target/AndroidTargetConfiguration.java @@ -249,6 +249,7 @@ List getTargetSpecificAOTCompileFlags() throws IOException { return flags; } + @Deprecated @Override List getTargetSpecificObjectFiles() throws IOException { if (projectConfiguration.isUseLLVM()) { diff --git a/src/main/java/com/gluonhq/substrate/target/IosTargetConfiguration.java b/src/main/java/com/gluonhq/substrate/target/IosTargetConfiguration.java index 0a097183..508a8049 100644 --- a/src/main/java/com/gluonhq/substrate/target/IosTargetConfiguration.java +++ b/src/main/java/com/gluonhq/substrate/target/IosTargetConfiguration.java @@ -203,6 +203,7 @@ List copyAdditionalSourceFiles(Path workDir) throws IOException { return files; } + @Deprecated @Override List getTargetSpecificObjectFiles() throws IOException { if (isSimulator() || !projectConfiguration.isUseLLVM()) { @@ -342,6 +343,20 @@ String getAppPath(String appName) { return appPath.toString() + "/" + appName; } + @Override + public boolean createStaticLib() throws IOException, InterruptedException { + ProcessRunner linkRunner = new ProcessRunner("ar"); + linkRunner.addArg("rcs"); + Path dest = paths.getGvmPath().resolve("lib"+projectConfiguration.getAppName()+".a"); + linkRunner.addArg(dest.toString()); + linkRunner.addArg(getProjectObjectFile().toString()); + linkRunner.addArgs(getAdditionalObjectFiles()); + linkRunner.setInfo(true); + linkRunner.setLogToFile(true); + int result = linkRunner.runProcess("archive"); + return result == 0; + } + private String getTargetArch() { return projectConfiguration.getTargetTriplet().getArch(); } From f770220b5f55623b28e0a1cfbb3146b7af1edaa2 Mon Sep 17 00:00:00 2001 From: Johan Vos Date: Thu, 9 Mar 2023 09:44:36 +0100 Subject: [PATCH 6/6] Process reviewer comments --- .github/workflows/build.yml | 2 -- .../gluonhq/substrate/model/InternalProjectConfiguration.java | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8ba2f1dc..4540c94c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,11 +2,9 @@ name: Substrate Build on: push: branches: - - entropy - master pull_request: branches: - - entropy - master jobs: diff --git a/src/main/java/com/gluonhq/substrate/model/InternalProjectConfiguration.java b/src/main/java/com/gluonhq/substrate/model/InternalProjectConfiguration.java index bc56db1b..7e5de20e 100644 --- a/src/main/java/com/gluonhq/substrate/model/InternalProjectConfiguration.java +++ b/src/main/java/com/gluonhq/substrate/model/InternalProjectConfiguration.java @@ -369,6 +369,7 @@ public void setBackend(String backend) { this.backend = backend; } + @Deprecated public boolean isUseLLVM() { return Constants.BACKEND_LLVM.equals(backend); } @@ -520,6 +521,7 @@ public void checkGraalVMVendor() throws IOException { * @throws IOException * @throws InterruptedException */ + @Deprecated public void canRunLLVM(Triplet triplet) throws IOException, InterruptedException { if (!new Triplet(Constants.Profile.IOS).equals(triplet) && !new Triplet(Constants.Profile.ANDROID).equals(triplet) &&