diff --git a/src/main/java/com/gluonhq/substrate/target/AndroidTargetConfiguration.java b/src/main/java/com/gluonhq/substrate/target/AndroidTargetConfiguration.java index 53b43bfba..aa8227cd8 100644 --- a/src/main/java/com/gluonhq/substrate/target/AndroidTargetConfiguration.java +++ b/src/main/java/com/gluonhq/substrate/target/AndroidTargetConfiguration.java @@ -33,6 +33,7 @@ import com.gluonhq.substrate.model.InternalProjectConfiguration; import com.gluonhq.substrate.model.ProcessPaths; import com.gluonhq.substrate.model.ReleaseConfiguration; +import com.gluonhq.substrate.model.Triplet; import com.gluonhq.substrate.util.FileOps; import com.gluonhq.substrate.util.Logger; import com.gluonhq.substrate.util.ProcessRunner; @@ -51,6 +52,7 @@ import java.util.Locale; import java.util.Optional; import java.util.Set; +import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -64,30 +66,35 @@ public class AndroidTargetConfiguration extends PosixTargetConfiguration { + private static final String ANDROID_TRIPLET = new Triplet(Constants.Profile.ANDROID).toString(); + private static final String ANDROID_MIN_SDK_VERSION = "21"; + private final String ndk; private final String sdk; private final Path ldlld; private final Path clang; + private final Path objdump; private final String hostPlatformFolder; - private List androidAdditionalSourceFiles = Arrays.asList("launcher.c", "javafx_adapter.c", + private final List androidAdditionalSourceFiles = Arrays.asList("launcher.c", "javafx_adapter.c", "touch_events.c", "glibc_shim.c", "attach_adapter.c", "logger.c"); - private List androidAdditionalHeaderFiles = Arrays.asList("grandroid.h", "grandroid_ext.h"); - private List cFlags = Arrays.asList("-target", "aarch64-linux-android", "-I."); - private List linkFlags = Arrays.asList("-target", "aarch64-linux-android21", "-fPIC", "-fuse-ld=gold", + private final List androidAdditionalHeaderFiles = Arrays.asList("grandroid.h", "grandroid_ext.h"); + private final List cFlags = Arrays.asList("-target", ANDROID_TRIPLET, "-I."); + private final List linkFlags = Arrays.asList("-target", + ANDROID_TRIPLET + ANDROID_MIN_SDK_VERSION, "-fPIC", "-fuse-ld=gold", "-Wl,--rosegment,--gc-sections,-z,noexecstack", "-shared", "-landroid", "-llog", "-lffi", "-llibchelper"); - private List javafxLinkFlags = Arrays.asList("-Wl,--whole-archive", + private final List javafxLinkFlags = Arrays.asList("-Wl,--whole-archive", "-lprism_es2_monocle", "-lglass_monocle", "-ljavafx_font_freetype", "-ljavafx_iio", "-Wl,--no-whole-archive", "-lGLESv2", "-lEGL", "-lfreetype"); private final String capLocation = ANDROID_NATIVE_FOLDER + "cap/"; - public AndroidTargetConfiguration( ProcessPaths paths, InternalProjectConfiguration configuration ) throws IOException { + public AndroidTargetConfiguration(ProcessPaths paths, InternalProjectConfiguration configuration) throws IOException { super(paths,configuration); this.sdk = fileDeps.getAndroidSDKPath().toString(); this.ndk = fileDeps.getAndroidNDKPath().toString(); - this.hostPlatformFolder = configuration.getHostTriplet().getOs() + "-x86_64"; + this.hostPlatformFolder = configuration.getHostTriplet().getOsArch(); Path ldguess = Paths.get(this.ndk, "toolchains", "llvm", "prebuilt", hostPlatformFolder, "bin", "ld.lld"); this.ldlld = Files.exists(ldguess) ? ldguess : null; @@ -95,6 +102,9 @@ public AndroidTargetConfiguration( ProcessPaths paths, InternalProjectConfigurat Path clangguess = Paths.get(this.ndk, "toolchains", "llvm", "prebuilt", hostPlatformFolder, "bin", "clang"); this.clang = Files.exists(clangguess) ? clangguess : null; projectConfiguration.setBackend(Constants.BACKEND_LIR); + + Path objdumpguess = Paths.get(this.ndk, "toolchains", "llvm", "prebuilt", hostPlatformFolder, ANDROID_TRIPLET, "bin", "objdump"); + this.objdump = Files.exists(objdumpguess) ? objdumpguess : null; } @Override @@ -103,6 +113,7 @@ public boolean compile() throws IOException, InterruptedException { if (ndk == null) throw new IOException ("Can't find an Android NDK on your system. Set the environment property ANDROID_NDK"); if (ldlld == null) throw new IOException ("You specified an android NDK, but it doesn't contain "+ndk+"/toolchains/llvm/prebuilt/"+hostPlatformFolder+"/bin/ld.lld"); if (clang == null) throw new IOException ("You specified an android NDK, but it doesn't contain "+ndk+"/toolchains/llvm/prebuilt/"+hostPlatformFolder+"/bin/clang"); + if (objdump == null) throw new IOException ("You specified an android NDK, but it doesn't contain "+ndk+"/toolchains/llvm/prebuilt/"+hostPlatformFolder+"/"+ ANDROID_TRIPLET +"/bin/objdump"); return super.compile(); } @@ -268,6 +279,26 @@ List getTargetSpecificNativeLibsFlags(Path libPath, List libs) { return linkFlags; } + @Override + Predicate getTargetSpecificNativeLibsFilter() { + return this::checkFileArchitecture; + } + + private boolean checkFileArchitecture(Path path) { + try { + ProcessRunner pr = new ProcessRunner(objdump.toString(), "-f", path.toString()); + pr.showSevereMessage(false); + int op = pr.runProcess("objdump"); + if (op == 0) { + return pr.getResponses().stream().anyMatch(line -> line.contains("architecture: " + projectConfiguration.getTargetTriplet().getArch())); + } + } catch (IOException | InterruptedException e) { + Logger.logSevere("Unrecoverable error checking file " + path + ": " + e); + } + Logger.logDebug("Ignore file " + path + " since objdump failed on it"); + return false; + } + @Override public String getAdditionalSourceFileLocation() { return ANDROID_NATIVE_FOLDER + "c/"; diff --git a/src/main/java/com/gluonhq/substrate/target/LinuxTargetConfiguration.java b/src/main/java/com/gluonhq/substrate/target/LinuxTargetConfiguration.java index 477dd2d3a..6fda89460 100644 --- a/src/main/java/com/gluonhq/substrate/target/LinuxTargetConfiguration.java +++ b/src/main/java/com/gluonhq/substrate/target/LinuxTargetConfiguration.java @@ -276,6 +276,7 @@ Predicate getTargetSpecificNativeLibsFilter() { private boolean checkFileArchitecture(Path path) { try { ProcessRunner pr = new ProcessRunner("objdump", "-f", path.toFile().getAbsolutePath()); + pr.showSevereMessage(false); int op = pr.runProcess("objdump"); if (op == 0) return true; } catch (IOException | InterruptedException e) { diff --git a/src/main/java/com/gluonhq/substrate/util/ProcessRunner.java b/src/main/java/com/gluonhq/substrate/util/ProcessRunner.java index ce2a855c3..51e06145e 100644 --- a/src/main/java/com/gluonhq/substrate/util/ProcessRunner.java +++ b/src/main/java/com/gluonhq/substrate/util/ProcessRunner.java @@ -60,6 +60,7 @@ public class ProcessRunner { private final List passwords; private StringBuffer answer; private boolean info; + private boolean showSevere = true; private boolean logToFile; private Path processLogPath; private boolean interactive; @@ -84,6 +85,16 @@ public void setInfo(boolean info) { this.info = info; } + /** + * When set to true, a message with Level.SEVERE will be logged in case + * the process fails. + * By default is true. + * @param showSevere a boolean that allows showing or not a severe message + */ + public void showSevereMessage(boolean showSevere) { + this.showSevere = showSevere; + } + /** * When set to true, it will enable user interaction * during the process. By default is false @@ -197,7 +208,7 @@ public int runProcess(String processName, File workingDirectory) throws IOExcept int result = p.waitFor(); logThread.join(); Logger.logDebug("Result for " + processName + ": " + result); - if (result != 0) { + if (result != 0 && showSevere) { Logger.logSevere("Process " + processName + " failed with result: " + result); } if (logToFile || result != 0) { @@ -236,7 +247,7 @@ public boolean runTimedProcess(String processName, File workingDirectory, long t boolean result = p.waitFor(timeout, TimeUnit.SECONDS); logThread.join(); Logger.logDebug("Result for " + processName + ": " + result); - if (!result) { + if (!result && showSevere) { Logger.logSevere("Process " + processName + " failed with result: " + result); } if (logToFile || !result) {