/* ### * 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") } } } if (isCurrentFreeBSD()) { gcc(Gcc) { if (isCurrentArm_64()) { target("freebsd_arm_64") } else { target("freebsd_x86_64") } } } if (isCurrentWindows() && VISUAL_STUDIO_INSTALL_DIR) { // specify installDir because Gradle doesn't find VS Build Tools. // See https://github.com/gradle/gradle-native/issues/617#issuecomment-575735288 visualCpp(VisualCpp) { installDir VISUAL_STUDIO_INSTALL_DIR } } } } /******************************************************************************************* * 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("Supported Windows native toolchain 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 /build/os// ?? 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"