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 3 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 @@ -51,6 +51,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 +65,45 @@

public class AndroidTargetConfiguration extends PosixTargetConfiguration {

private static final String ANDROID_TRIPLET = "aarch64-linux-android";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this be in Constants.Profile (full name)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have Constants.PROFILE_ANDROID, but that is only for android. The target triplet is created with Triplet(Constants.Profiles.ANDROID), based on three constants, so probably we could have all possible triplets names as constants?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@johanvos Your suggestion of doing Constants.Profile (full name) brings back this PR: #229, where TripletProfile was created precisely.

I guess this is a big refactoring that should be tackled in a follow-up PR?

For now, what if we just do:

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().getOs() + "-" + Constants.ARCH_AMD64;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't this Triplet.getOsArch() ?

Copy link
Contributor Author

@jperedadnr jperedadnr Aug 19, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using configuration.getHostTriplet() we get the Linux triplet, right, I'll change it


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 +112,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 +278,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: " + Constants.ARCH_AARCH64));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better to replace with the getArch() on the targetTriplet (e.g. when we support x86-64 emulator/devices)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

}
} 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