Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use objdump on Android to check static native libraries #746

Merged
merged 4 commits into from
Aug 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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