All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.moe.gradle.tasks.Dex2Oat Maven / Gradle / Ivy
/*
Copyright (C) 2016 Migeran
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package org.moe.gradle.tasks;
import org.gradle.api.GradleException;
import org.gradle.api.file.ConfigurableFileCollection;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.Internal;
import org.gradle.api.tasks.OutputFile;
import org.gradle.api.tasks.SourceSet;
import org.moe.gradle.MoeExtension;
import org.moe.gradle.MoePlugin;
import org.moe.gradle.MoeSDK;
import org.moe.gradle.anns.IgnoreUnused;
import org.moe.gradle.anns.NotNull;
import org.moe.gradle.anns.Nullable;
import org.moe.gradle.remote.Server;
import org.moe.gradle.remote.file.FileList;
import org.moe.gradle.utils.Arch;
import org.moe.gradle.utils.Mode;
import org.moe.gradle.utils.Require;
import org.moe.gradle.utils.TaskUtils;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
public class Dex2Oat extends AbstractBaseTask {
private static final String CONVENTION_DEX2OAT_EXEC = "dex2oatExec";
private static final String CONVENTION_ARCH_FAMILY = "archFamily";
private static final String CONVENTION_BASE = "base";
private static final String CONVENTION_IMAGE_CLASSES = "imageClasses";
private static final String CONVENTION_EMIT_DEBUG_INFO = "emitDebugInfo";
private static final String CONVENTION_INPUT_FILES = "inputFiles";
private static final String CONVENTION_COMPILER_BACKEND = "compilerBackend";
private static final String CONVENTION_DEST_IMAGE_FILE = "destImageFile";
private static final String CONVENTION_DEST_OAT_FILE = "destOatFile";
private static final String BACKEND_QUICK = "Quick";
private static final String BACKEND_OPTIMIZING = "Optimizing";
private static final String[] ALL_BACKENDS = new String[]{BACKEND_QUICK, BACKEND_OPTIMIZING};
@Nullable
private Object dex2oatExec;
@InputFile
@NotNull
public File getDex2oatExec() {
return getProject().file(getOrConvention(dex2oatExec, CONVENTION_DEX2OAT_EXEC));
}
@IgnoreUnused
public void setDex2oatExec(@Nullable Object dex2oatExec) {
this.dex2oatExec = dex2oatExec;
}
@Nullable
private String archFamily;
@Input
@NotNull
public String getArchFamily() {
return getOrConvention(archFamily, CONVENTION_ARCH_FAMILY);
}
@IgnoreUnused
public void setArchFamily(@Nullable String archFamily) {
this.archFamily = archFamily == null ? null : Arch.validateArchFamily(archFamily);
}
@Nullable
private Long base;
@Input
@NotNull
public Long getBase() {
return getOrConvention(base, CONVENTION_BASE);
}
@IgnoreUnused
public void setBase(@Nullable Long base) {
this.base = base;
}
@Nullable
private Object imageClasses;
@InputFile
@NotNull
public File getImageClasses() {
return getProject().file(getOrConvention(imageClasses, CONVENTION_IMAGE_CLASSES));
}
@IgnoreUnused
public void setImageClasses(@Nullable Object imageClasses) {
this.imageClasses = imageClasses;
}
@Nullable
private Boolean emitDebugInfo;
@Input
@NotNull
public Boolean getEmitDebugInfo() {
return getOrConvention(emitDebugInfo, CONVENTION_EMIT_DEBUG_INFO);
}
@IgnoreUnused
public void setEmitDebugInfo(@Nullable Boolean emitDebugInfo) {
this.emitDebugInfo = emitDebugInfo;
}
@Nullable
private Set inputFiles;
@InputFiles
@NotNull
public ConfigurableFileCollection getInputFiles() {
return getProject().files(getOrConvention(inputFiles, CONVENTION_INPUT_FILES));
}
@IgnoreUnused
public void setInputFiles(@Nullable Collection inputFiles) {
this.inputFiles = inputFiles == null ? null : new HashSet<>(inputFiles);
}
@Nullable
private String compilerBackend;
@Input
@NotNull
public String getCompilerBackend() {
return getOrConvention(compilerBackend, CONVENTION_COMPILER_BACKEND);
}
@IgnoreUnused
public void setCompilerBackend(@Nullable String compilerBackend) {
this.compilerBackend = compilerBackend == null ? null : validateBackend(compilerBackend);
}
@Nullable
private Object destImageFile;
@OutputFile
@NotNull
public File getDestImageFile() {
return getProject().file(getOrConvention(destImageFile, CONVENTION_DEST_IMAGE_FILE));
}
@IgnoreUnused
public void setDestImageFile(@Nullable Object destImageFile) {
this.destImageFile = destImageFile;
}
@Nullable
private Object destOatFile;
@OutputFile
@NotNull
public File getDestOatFile() {
return getProject().file(getOrConvention(destOatFile, CONVENTION_DEST_OAT_FILE));
}
@IgnoreUnused
public void setDestOatFile(@Nullable Object destOatFile) {
this.destOatFile = destOatFile;
}
@Override
protected void run() {
getMoePlugin().requireMacHostOrRemoteServerConfig(this);
final Server remoteServer = getMoePlugin().getRemoteServer();
if (remoteServer != null) {
final String dex2oatExec;
final String imageClasses;
try {
dex2oatExec = remoteServer.getSDKRemotePath(getDex2oatExec());
imageClasses = remoteServer.getSDKRemotePath(getImageClasses());
} catch (IOException e) {
throw new GradleException("Unsupported configuration", e);
}
final FileList fileList = new FileList(getProject().getProjectDir(), remoteServer.getBuildDir());
StringBuilder dexFiles = new StringBuilder();
StringBuilder remoteDexFilesCheck = new StringBuilder();
getInputFiles().forEach(it -> {
String path;
boolean needsUpload = false;
try {
path = remoteServer.getSDKRemotePath(it);
} catch (IOException ignore) {
needsUpload = true;
try {
path = getInnerProjectRelativePath(it).toString();
} catch (IOException e) {
throw new GradleException("Unsupported configuration", e);
}
}
if (dexFiles.length() > 0) {
dexFiles.append(':');
remoteDexFilesCheck.append(" && ");
}
if (needsUpload) {
final String remotePath = fileList.add(it);
dexFiles.append(remotePath);
remoteDexFilesCheck.append("[ -f '").append(remotePath).append("' ]");
} else {
dexFiles.append(path);
remoteDexFilesCheck.append("[ -f '").append(path).append("' ]");
}
});
remoteServer.upload("dex2oat inputs", fileList);
remoteServer.exec("dex2oat inputs check", remoteDexFilesCheck.toString());
final Path destArtRel;
final Path destOatRel;
try {
destArtRel = getInnerProjectRelativePath(getDestImageFile());
destOatRel = getInnerProjectRelativePath(getDestOatFile());
} catch (IOException e) {
throw new GradleException("Unsupported configuration", e);
}
final String remoteDestArt = remoteServer.getRemotePath(destArtRel);
final String remoteDestOat = remoteServer.getRemotePath(destOatRel);
remoteServer.exec("prepare output directories", "" +
"mkdir -p `dirname " + remoteDestArt + "` && " +
"mkdir -p `dirname " + remoteDestOat + "`");
remoteServer.exec("dex2oat", dex2oatExec + " " +
"--instruction-set=" + Arch.validateArchFamily(getArchFamily()) + " " +
"--base=0x" + Long.toHexString(getBase()) + " " +
"--compiler-backend=" + validateBackend(getCompilerBackend()) + " " +
(getEmitDebugInfo() ? "--generate-debug-info" : "--no-generate-debug-info") + " " +
"--image=" + remoteDestArt + " " +
"--image-classes=" + imageClasses + " " +
"--oat-file=" + remoteDestOat + " " +
"--dex-file=" + dexFiles
);
remoteServer.downloadFile("art", remoteDestArt, getDestImageFile().getParentFile());
remoteServer.downloadFile("oat", remoteDestOat, getDestOatFile().getParentFile());
} else {
exec(spec -> {
// Set executable
if (TaskUtils.isHostAARCH64() && !Arch.FAMILY_ARM64.equalsIgnoreCase(getArchFamily())) {
// Run dex2oat using rosetta 2 when compiling non-arm64 target on Apple silicon
// because currently the arm64 version of dex2oat does not work reliably due to
// the issue of word size & alignment mismatch.
// TODO: solve this?
spec.setExecutable("arch");
spec.args("--x86_64");
spec.args(getDex2oatExec());
} else {
spec.setExecutable(getDex2oatExec());
}
// Set target options
spec.args("--instruction-set=" + Arch.validateArchFamily(getArchFamily()));
spec.args("--base=0x" + Long.toHexString(getBase()));
// Set compiler backend
spec.args("--compiler-backend=" + validateBackend(getCompilerBackend()));
// Include or not include ELF symbols in oat file
if (getEmitDebugInfo()) {
spec.args("--generate-debug-info");
} else {
spec.args("--no-generate-debug-info");
}
// Set files
spec.args("--image=" + getDestImageFile().getAbsolutePath());
spec.args("--image-classes=" + getImageClasses().getAbsolutePath());
spec.args("--oat-file=" + getDestOatFile().getAbsolutePath());
// Set inputs
StringBuilder dexFiles = new StringBuilder();
getInputFiles().forEach(it -> {
if (dexFiles.length() > 0) {
dexFiles.append(':');
}
dexFiles.append(it.getAbsolutePath());
});
spec.args("--dex-file=" + dexFiles);
});
}
}
private Dex dexTaskDep;
@NotNull
@Internal
public Dex getDexTaskDep() {
return Require.nonNull(dexTaskDep);
}
@NotNull
protected final void setupMoeTask(@NotNull SourceSet sourceSet, @NotNull Mode mode, @NotNull String archFamily) {
Require.nonNull(sourceSet);
Require.nonNull(mode);
Require.nonNull(archFamily);
setSupportsRemoteBuild(true);
final MoeExtension ext = getMoeExtension();
final MoeSDK sdk = getMoeSDK();
// Construct default output path
final Path out = Paths.get(MoePlugin.MOE, sourceSet.getName(), "dex2oat", mode.name + "-" + archFamily);
setDescription("Generates art+oat files (sourceset: " + sourceSet.getName() + ", mode: " + mode.name +
", arch-family: " + archFamily + ").");
// Add dependencies
final Dex dexTask = getMoePlugin().getTaskBy(Dex.class, sourceSet);
dexTaskDep = dexTask;
dependsOn(dexTask);
// Update convention mapping
addConvention(CONVENTION_DEX2OAT_EXEC, sdk::getDex2OatExec);
addConvention(CONVENTION_ARCH_FAMILY, () -> archFamily);
addConvention(CONVENTION_BASE, () -> {
if (Arch.FAMILY_ARM.equals(archFamily)) {
return 0x10000000L;
} else if (Arch.FAMILY_ARM64.equals(archFamily)) {
return 0x10000000L;
} else if (Arch.FAMILY_X86.equals(archFamily)) {
return 0x40000000L;
} else if (Arch.FAMILY_X86_64.equals(archFamily)) {
return 0x40000000L;
} else {
throw new GradleException("Unexpected arch family '" + archFamily + "'");
}
});
addConvention(CONVENTION_IMAGE_CLASSES, sdk::getPreloadedClassesFile);
addConvention(CONVENTION_EMIT_DEBUG_INFO, () -> mode == Mode.DEBUG);
addConvention(CONVENTION_INPUT_FILES, () -> {
final Set files = new HashSet<>();
files.add(dexTask.getDestJar());
switch (ext.getProguardLevelRaw()) {
case MoeExtension.PROGUARD_LEVEL_APP:
files.add(sdk.getCoreDex());
if (ext.getPlatformDex() != null) {
files.add(ext.getPlatformDex());
}
break;
case MoeExtension.PROGUARD_LEVEL_PLATFORM:
files.add(sdk.getCoreDex());
break;
case MoeExtension.PROGUARD_LEVEL_ALL:
break;
default:
throw new IllegalStateException();
}
return files;
});
addConvention(CONVENTION_COMPILER_BACKEND, () -> BACKEND_QUICK);
addConvention(CONVENTION_DEST_IMAGE_FILE, () -> resolvePathInBuildDir(out, "image.art"));
addConvention(CONVENTION_DEST_OAT_FILE, () -> resolvePathInBuildDir(out, "application.oat"));
addConvention(CONVENTION_LOG_FILE, () -> resolvePathInBuildDir(out, "Dex2Oat.log"));
}
private static String validateBackend(@NotNull String name) {
Require.nonNull(name);
for (String backend : ALL_BACKENDS) {
if (backend.equalsIgnoreCase(name)) {
return backend;
}
}
throw new GradleException("Unknown backend '" + name + "', supported: " + Arrays.asList(ALL_BACKENDS));
}
}