ghidra/GPL/nativeBuildProperties.gradle
2021-09-29 07:47:55 -04:00

200 lines
7.3 KiB
Groovy

/* ###
* IP: Public Domain
*/
/****************************************************************************
* nativeBuildProperties.gradle
*
* This script contains global settings used by all projects that have
* native build requirements.
*
* This is NOT a complete build script for those
* projects; it is only meant to capture items that are common to all so
* we don't need to define them over and over again.
****************************************************************************/
/****************************************************************************
* Always apply the cpp and c plugin, for obvious reasons
****************************************************************************/
apply plugin: 'cpp'
apply plugin: 'c'
/****************************************************************************
* Defines the platforms we have to support in Ghidra. This model is used
* for all native builds and should be extended by each module as-needed.
****************************************************************************/
model {
// Use the PLATFORMS list to create the platforms that Ghidra supports.
platforms {
project.PLATFORMS.each { platform ->
"${platform.name}" {
architecture platform.arch
operatingSystem platform.os
}
}
}
// The toolChains block is needed because Gradle doesn't find gcc/clang on ARM-based Linux
// and macOS platforms without explicitly declaring their targets. Might be a bug in the
// native Gradle plugin.
toolChains {
if (isCurrentLinux()) {
gcc(Gcc) {
if (isCurrentArm_64()) {
target("linux_arm_64")
}
}
}
if (isCurrentMac()) {
clang(Clang) {
if (isCurrentArm_64()) {
target("mac_arm_64")
}
}
}
}
}
/*******************************************************************************************
* Task: verify presence of correct tool chain version for current platform
******************************************************************************************/
task CheckToolChain {
// Native C/Cpp plugins will trigger failure if no tool chain found
doFirst {
if (isCurrentWindows()) {
// ensure that required MS Visual Studio is installed
if (!VISUAL_STUDIO_INSTALL_DIR) {
throw new GradleException("Visual Studio not found!");
}
}
}
}
/*******************************************************************************************
* If task1 contains the given platform name, then it needs to be executed before
* task2. The task1 must be of type LinkExecutable or LinkSharedLibrary so that the
* targetPlatform may be inspected.
*
******************************************************************************************/
def addTaskDependencyForMyPlatform(task1, task2, platform) {
if (platform.equals(task1.targetPlatform.get().name)) {
task2.dependsOn task1.path
task1.dependsOn CheckToolChain
}
}
/*******************************************************************************************
* Returns true if the given task is a custom Make task (starts with the platform name and
* ends with "Make").
*
* Note that this is a Ghidra-specific task and is not one created dynamically by Gradle.
*
******************************************************************************************/
def isNativeBinaryMakeTask(Task task, String platform) {
if (task.name.startsWith(platform) && task.name.endsWith("Make")) {
return true
}
return false
}
/*******************************************************************************************
* Returns true if the native binaries for the given task should be skipped during build.
*
* NOTE: Some native binaries are test-only and should not be built for a distribution.
*
******************************************************************************************/
def shouldSkipNative(task) {
return task.ext.has("skipNative") && task.ext.get("skipNative")
}
/*******************************************************************************************
* Task Rule : buildNatives[_PlatformName]
*
* Summary: Builds all the natives in this module for a given platform.
*
* Args: PlatformName - The name of the platform. If not specified, the current platform is used.
*
* Example: gradle buildNatives_win_x86_64 will build all win_x86_64 native executables and shared libraries.
*
* NOTE: you must be on the appropriate platform for this to work.
******************************************************************************************/
tasks.addRule("Pattern: buildNatives[_PlatformName]: build all natives for given platform") { String taskName ->
if (taskName.startsWith("buildNatives")) {
String currentPlatform = getCurrentPlatformName()
String platform = taskName - "buildNatives"
if (platform.length() == 0) {
platform = currentPlatform
}
if (platform.startsWith("_")) {
platform = platform - "_"
}
task(taskName) { myTask ->
project.tasks.withType(LinkExecutable) { t ->
addTaskDependencyForMyPlatform(t, myTask, platform)
}
project.tasks.withType(LinkSharedLibrary) { t ->
addTaskDependencyForMyPlatform(t, myTask, platform)
}
project.tasks.each { t ->
if (isNativeBinaryMakeTask(t, platform)) {
myTask.dependsOn t.path
t.dependsOn CheckToolChain
}
// buildNatives task natives end up in the distribution...mark test natives as "skip"
if (project.findProperty("nativesTestOnly") ?: false) {
t.ext.set("skipNative", true)
}
}
// add callbacks to look for native build tasks when new tasks are added later
project.tasks.withType(LinkExecutable).whenTaskAdded { t ->
addTaskDependencyForMyPlatform(t, myTask, platform)
}
project.tasks.withType(LinkSharedLibrary).whenTaskAdded { t ->
addTaskDependencyForMyPlatform(t, myTask, platform)
}
project.tasks.whenTaskAdded { t ->
if (isNativeBinaryMakeTask(t, platform)) {
myTask.dependsOn t.path
t.dependsOn CheckToolChain
}
}
}
}
}
/*****************************************************************************************
* The following block of code changes the output directory for native builds
* to <projectDir>/build/os/<platform>/<executable> ?? is there a better way to do this?
****************************************************************************************/
gradle.taskGraph.whenReady {
def p = this.project
p.tasks.withType(LinkExecutable).each { t ->
if (!shouldSkipNative(t)) {
File f = t.linkedFile.getAsFile().get()
String filename = f.getName()
NativePlatform platform = t.targetPlatform.get()
String osName = platform.getName()
t.linkedFile = p.file("build/os/${osName}/$filename")
}
}
p.tasks.withType(LinkSharedLibrary).each { t ->
if (!shouldSkipNative(t)) {
File f = t.linkedFile.getAsFile().get()
String filename = f.getName()
NativePlatform platform = t.targetPlatform.get()
String osName = platform.getName()
t.linkedFile = p.file("build/os/${osName}/$filename")
}
}
}
/*****************************************************************************************
* The following block of code ensures that the buildNatives (for current plaform) task is
* used during assembly to ensure that missing toolchain generates an appropriate error
****************************************************************************************/
assemble.dependsOn "buildNatives"