Skip to content

Commit

Permalink
Use objdump on Android to check static native libraries (#746)
Browse files Browse the repository at this point in the history
* Add showSevere to show or not the severe message in case of process failure

* Don’t show severe message when checking native libs on Linux

* Add objdump to Android, and check native libraries

* Changes based on feedback

Co-authored-by: jose.pereda <[email protected]>
  • Loading branch information
José Pereda and jperedadnr authored Aug 21, 2020
1 parent ddd1f6b commit 6bff962
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -64,37 +66,45 @@

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<String> androidAdditionalSourceFiles = Arrays.asList("launcher.c", "javafx_adapter.c",
private final List<String> androidAdditionalSourceFiles = Arrays.asList("launcher.c", "javafx_adapter.c",
"touch_events.c", "glibc_shim.c", "attach_adapter.c", "logger.c");
private List<String> androidAdditionalHeaderFiles = Arrays.asList("grandroid.h", "grandroid_ext.h");
private List<String> cFlags = Arrays.asList("-target", "aarch64-linux-android", "-I.");
private List<String> linkFlags = Arrays.asList("-target", "aarch64-linux-android21", "-fPIC", "-fuse-ld=gold",
private final List<String> androidAdditionalHeaderFiles = Arrays.asList("grandroid.h", "grandroid_ext.h");
private final List<String> cFlags = Arrays.asList("-target", ANDROID_TRIPLET, "-I.");
private final List<String> 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<String> javafxLinkFlags = Arrays.asList("-Wl,--whole-archive",
private final List<String> 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;

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
Expand All @@ -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();
}
Expand Down Expand Up @@ -268,6 +279,26 @@ List<String> getTargetSpecificNativeLibsFlags(Path libPath, List<String> libs) {
return linkFlags;
}

@Override
Predicate<Path> 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/";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ Predicate<Path> 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) {
Expand Down
15 changes: 13 additions & 2 deletions src/main/java/com/gluonhq/substrate/util/ProcessRunner.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public class ProcessRunner {
private final List<String> passwords;
private StringBuffer answer;
private boolean info;
private boolean showSevere = true;
private boolean logToFile;
private Path processLogPath;
private boolean interactive;
Expand All @@ -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
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down

0 comments on commit 6bff962

Please sign in to comment.