From 3c07ca2962bc1ae74294b6a3d01d1390f68951fd Mon Sep 17 00:00:00 2001 From: Ryan Kurtz Date: Mon, 27 Sep 2021 08:16:14 -0400 Subject: [PATCH] GP-1209: Support for building natives from a release. --- DevGuide.md | 23 +- GPL/DMG/settings.gradle | 3 - GPL/DemanglerGnu/settings.gradle | 3 - GPL/nativeBuildProperties.gradle | 63 +++-- GPL/settings.gradle | 12 + GPL/vsconfig.gradle | 14 +- Ghidra/Features/Decompiler/build.gradle | 218 +--------------- .../Features/Decompiler/buildNatives.gradle | 233 ++++++++++++++++++ Ghidra/Features/PDB/build.gradle | 54 +--- Ghidra/Features/PDB/buildNatives.gradle | 59 +++++ Ghidra/Features/PDB/src/pdb/pdb.vcxproj | 12 - .../java/ghidra/framework/Application.java | 22 +- .../RuntimeScripts/Linux/support/buildNatives | 41 +++ .../Windows/support/buildNatives.bat | 39 +++ Ghidra/RuntimeScripts/certification.manifest | 2 + GhidraDocs/InstallationGuide.html | 34 +++ README.md | 9 +- gradle/nativeProject.gradle | 20 +- gradle/root/distribution.gradle | 9 + gradle/root/usage.gradle | 18 +- gradle/support/ip.gradle | 1 + settings.gradle | 1 + 22 files changed, 541 insertions(+), 349 deletions(-) delete mode 100644 GPL/DMG/settings.gradle delete mode 100644 GPL/DemanglerGnu/settings.gradle create mode 100644 GPL/settings.gradle create mode 100644 Ghidra/Features/Decompiler/buildNatives.gradle create mode 100644 Ghidra/Features/PDB/buildNatives.gradle create mode 100755 Ghidra/RuntimeScripts/Linux/support/buildNatives create mode 100644 Ghidra/RuntimeScripts/Windows/support/buildNatives.bat diff --git a/DevGuide.md b/DevGuide.md index 95573732a0..5bcb127e95 100644 --- a/DevGuide.md +++ b/DevGuide.md @@ -262,33 +262,16 @@ You may see build path errors until the environment is properly prepared, as des ### Building the natives Some of Ghidra's components are built for the native platform. -We currently support Linux, macOS, and Windows 64-bit x86 systems. -Others should be possible, but we do not test on them. +We currently support 64-bit Linux x86/ARM, macOS x86/ARM, and Windows x86. -Now build using Gradle: - -On Linux: +Build the natives for your current platform using Gradle: ```bash -gradle buildNatives_linux_x86_64 -``` - -On macOS: - -```bash -gradle buildNatives_mac_x86_64 -``` - -On Windows: - -```bash -gradle buildNatives_win_x86_64 +gradle buildNatives ``` This will build the decompiler, the demangler for GNU toolchains, the sleigh compiler, and (on Windows only) the PDB parser. -**NOTE:** `buildNatives_linux_arm_64` and `buildNatives_mac_arm_64` are also supported. - ### Pre-compile Language Modules (optional) Optionally, to pre-compile all the language modules, you may also execute: diff --git a/GPL/DMG/settings.gradle b/GPL/DMG/settings.gradle deleted file mode 100644 index 1092a7aaab..0000000000 --- a/GPL/DMG/settings.gradle +++ /dev/null @@ -1,3 +0,0 @@ -/* ### - * IP: Public Domain - */ diff --git a/GPL/DemanglerGnu/settings.gradle b/GPL/DemanglerGnu/settings.gradle deleted file mode 100644 index 1092a7aaab..0000000000 --- a/GPL/DemanglerGnu/settings.gradle +++ /dev/null @@ -1,3 +0,0 @@ -/* ### - * IP: Public Domain - */ diff --git a/GPL/nativeBuildProperties.gradle b/GPL/nativeBuildProperties.gradle index 494e2be7f8..1b2d4feb82 100644 --- a/GPL/nativeBuildProperties.gradle +++ b/GPL/nativeBuildProperties.gradle @@ -108,17 +108,27 @@ def shouldSkipNative(task) { } /******************************************************************************************* - * Task Rule : builds all the natives in this module for a given platform. + * Task Rule : buildNatives[_PlatformName] * - * Example : gradle buildNatives_win_x86_64 will build all win_x86_64 native executables and shared libraries. + * 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. - * + * NOTE: you must be on the appropriate platform for this to work. ******************************************************************************************/ -tasks.addRule("Pattern: buildNatives_]: build all natives for given platform") { String taskName -> +tasks.addRule("Pattern: buildNatives[_PlatformName]: build all natives for given platform") { String taskName -> - if (taskName.startsWith("buildNatives_")) { - String platform = taskName - "buildNatives_" + 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 -> @@ -157,20 +167,30 @@ tasks.addRule("Pattern: buildNatives_]: build all natives for giv } } -/******************************************************************************************* - * Task Rule : builds all the natives in this module for a given platform and copies the - * results to the bin repo. + /******************************************************************************************* + * Task Rule : prebuildNatives[_PlatformName] * - * Example : gradle prebuildNatives_win_x86_64 will build all win_x86_64 native executables and shared - * libraries and copy the results to the appropriate project/os directory in the bin - * repo. - * - * NOTE: you must be on the appropriate platform for this to work. + * Summary: Builds all the natives in this module for a given platform and copies the results + * to the bin repo. * + * Args: PlatformName - The name of the platform. If not specified, the current platform is used. + * + * Example: gradle prebuildNatives_win_x86_64 will build all win_x86_64 native executables and + * shared libraries and copy the results to the appropriate project/os directory in + * the bin repo. + * + * NOTE: you must be on the appropriate platform for this to work. ******************************************************************************************/ -tasks.addRule("Pattern: prebuildNatives_]: build all natives for given platform") { String taskName -> - if (taskName.startsWith("prebuildNatives_")) { - String platform = taskName - "prebuildNatives_" +tasks.addRule("Pattern: prebuildNatives<_platform name>]: build all natives for given platform") { String taskName -> + if (taskName.startsWith("prebuildNatives")) { + def currentPlatform = getCurrentPlatformName() + def platform = taskName - "prebuildNatives" + if (platform.length() == 0) { + platform = currentPlatform + } + if (platform.startsWith("_")) { + platform = platform - "_" + } task(taskName) { myTask -> dependsOn "buildNatives_$platform" @@ -214,8 +234,7 @@ gradle.taskGraph.whenReady { } /***************************************************************************************** - * The following block of code ensures that the buildNatives_ task is used - * during assembly to ensure that missing toolchain generates an appropriate error + * 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 ****************************************************************************************/ -def currentPlatform = getCurrentPlatformName() -assemble.dependsOn "buildNatives_$currentPlatform" +assemble.dependsOn "buildNatives" diff --git a/GPL/settings.gradle b/GPL/settings.gradle new file mode 100644 index 0000000000..2f7a52d862 --- /dev/null +++ b/GPL/settings.gradle @@ -0,0 +1,12 @@ +/* ### + * IP: Public Domain + */ +// Recurse root project subdirectories and include all discovered projects +// (directories containing a build.gradle file) +fileTree(rootProject.projectDir) { + exclude 'build.gradle' // exclude root project + include '**/build.gradle' +}.each { + include it.parentFile.name; + project(":$it.parentFile.name").projectDir = it.parentFile; +} diff --git a/GPL/vsconfig.gradle b/GPL/vsconfig.gradle index a21190cb0b..915b90ea90 100644 --- a/GPL/vsconfig.gradle +++ b/GPL/vsconfig.gradle @@ -1,17 +1,5 @@ /* ### - * IP: GHIDRA - * - * 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. + * IP: Public Domain */ /**************************************************************************** * Establish Visual Studio configuration environment for Windows native builds diff --git a/Ghidra/Features/Decompiler/build.gradle b/Ghidra/Features/Decompiler/build.gradle index e5f9069112..f95278172b 100644 --- a/Ghidra/Features/Decompiler/build.gradle +++ b/Ghidra/Features/Decompiler/build.gradle @@ -20,6 +20,7 @@ apply from: "$rootProject.projectDir/gradle/nativeProject.gradle" apply from: "$rootProject.projectDir/gradle/helpProject.gradle" apply from: "$rootProject.projectDir/gradle/distributableGhidraModule.gradle" apply from: "$rootProject.projectDir/gradle/javadoc.gradle" +apply from: "buildNatives.gradle" apply plugin: 'eclipse' @@ -35,6 +36,14 @@ dependencies { helpPath project(path: ":Base", configuration: 'helpPath') } +// Include buildable native source in distribution +rootProject.assembleDistribution { + from (this.project.projectDir.toString()) { + include "src/decompile/**" + into { getZipPath(this.project) } + } +} + ext.cppSourceDir = "src/decompile/cpp" /** @@ -371,215 +380,6 @@ task buildDecompilerDocumentationHtml(type: Exec) { } } -/** - * Define the "native build model" for building the decompiler executables. - */ -model { - - // Define the source files that are compiled and linked to become the decompiler. - // The decompiler source is a bit weird in that all the cpp and headers all live in - // the same directory with other files that are not used by the decompiler. - // That is why we have to list every cpp file that makes up the decomplier. - components { - - decompile(NativeExecutableSpec) { - - baseName "decompile" - - // these tell gradle for which platforms to build a decompiler executable. - targetPlatform "win_x86_64" - targetPlatform "linux_x86_64" - targetPlatform "linux_arm_64" - targetPlatform "mac_x86_64" - targetPlatform "mac_arm_64" - sources { - cpp { - // NOTE: The bison/flex generated files are assumed to be up-to-date. - // The task `generateParsers` should be executed if needed. - // builtBy yaccDecompiler - source { - srcDir "src/decompile/cpp" - - include "space.cc" - include "float.cc" - include "address.cc" - include "pcoderaw.cc" - include "translate.cc" - include "opcodes.cc" - include "globalcontext.cc" - include "capability.cc" - include "architecture.cc" - include "options.cc" - include "graph.cc" - include "cover.cc" - include "block.cc" - include "cast.cc" - include "typeop.cc" - include "database.cc" - include "cpool.cc" - include "comment.cc" - include "stringmanage.cc" - include "fspec.cc" - include "action.cc" - include "loadimage.cc" - include "varnode.cc" - include "op.cc" - include "type.cc" - include "variable.cc" - include "varmap.cc" - include "jumptable.cc" - include "emulate.cc" - include "emulateutil.cc" - include "flow.cc" - include "userop.cc" - include "funcdata.cc" - include "funcdata_block.cc" - include "funcdata_varnode.cc" - include "funcdata_op.cc" - include "pcodeinject.cc" - include "heritage.cc" - include "prefersplit.cc" - include "rangeutil.cc" - include "ruleaction.cc" - include "subflow.cc" - include "transform.cc" - include "blockaction.cc" - include "merge.cc" - include "double.cc" - include "coreaction.cc" - include "condexe.cc" - include "override.cc" - include "dynamic.cc" - include "crc32.cc" - include "prettyprint.cc" - include "printlanguage.cc" - include "printc.cc" - include "printjava.cc" - include "memstate.cc" - include "opbehavior.cc" - include "paramid.cc" - include "ghidra_arch.cc" - include "inject_ghidra.cc" - include "ghidra_translate.cc" - include "loadimage_ghidra.cc" - include "typegrp_ghidra.cc" - include "database_ghidra.cc" - include "ghidra_context.cc" - include "cpool_ghidra.cc" - include "ghidra_process.cc" - include "comment_ghidra.cc" - include "string_ghidra.cc" - // include "callgraph.cc" // uncomment for debug - // include "ifacedecomp.cc" // uncomment for debug - // include "ifaceterm.cc" // uncomment for debug - // include "interface.cc" // uncomment for debug - - // generated source files - - include "xml.cc" - // include "grammar.cc" // used by diagnostic console mode - } - exportedHeaders { - srcDir "src/decompile/cpp" - } - } // end cpp - } // end sources - } // end decompile - - sleigh(NativeExecutableSpec) { - targetPlatform "win_x86_64" - targetPlatform "linux_x86_64" - targetPlatform "linux_arm_64" - targetPlatform "mac_x86_64" - targetPlatform "mac_arm_64" - sources { - cpp { - // NOTE: The bison/flex generated files are assumed to be up-to-date. - // The task `generateParsers` should be executed if needed. - // builtBy lexSleigh - source { - srcDir "src/decompile/cpp" - - include "space.cc" - include "float.cc" - include "address.cc" - include "pcoderaw.cc" - include "translate.cc" - include "opcodes.cc" - include "globalcontext.cc" - include "sleigh.cc" - include "pcodecompile.cc" - include "sleighbase.cc" - include "slghsymbol.cc" - include "slghpatexpress.cc" - include "slghpattern.cc" - include "semantics.cc" - include "context.cc" - include "filemanage.cc" - include "slgh_compile.cc" - - // generated source files - - include "xml.cc" - include "pcodeparse.cc" - include "slghparse.cc" - include "slghscan.cc" - } - exportedHeaders { - srcDir "src/decompile/cpp" - } - } // end cpp - } // end sources (sleigh) - } // end sleigh - - } // end components - - binaries { - all{ b -> - if (b.toolChain in Gcc) { - b.cppCompiler.args "-std=c++11" - b.cppCompiler.args "-Wall" - b.cppCompiler.args "-O2" // for DEBUG, comment this line out - // b.cppCompiler.args "-g" // for DEBUG, uncomment this line - b.cppCompiler.args "-Wno-sign-compare" - if (b.targetPlatform.operatingSystem.linux) { -// b.linker.args "-static" - b.cppCompiler.define "LINUX" - b.cppCompiler.define "_LINUX" - } - } - else if (b.toolChain in VisualCpp) { - b.cppCompiler.args "/EHsc" - b.cppCompiler.define "_SECURE_SCL=0" - b.cppCompiler.define "_HAS_ITERATOR_DEBUGGING=0" - // b.cppCompiler.args "/Zi" // for DEBUG, uncomment this line - // b.cppCompiler.args "/FS" // for DEBUG, uncomment this line - // b.linker.args "/DEBUG" // for DEBUG, uncomment this line - if (b.targetPlatform.operatingSystem.windows) { - b.cppCompiler.define "WINDOWS" - b.cppCompiler.define "_WINDOWS" - b.cppCompiler.define "WIN32" - b.cppCompiler.define "_WIN32" - if (b.targetPlatform.name == "win_x86_64") { - b.cppCompiler.define "WIN64" - b.cppCompiler.define "_WIN64" - } - } - } - else if (b.toolChain in Clang) { - b.cppCompiler.args "-std=c++11" - b.cppCompiler.args "-Wall" - b.cppCompiler.args "-O2" // for DEBUG, comment this line out - // b.cppCompiler.args "-g" // for DEBUG, uncomment this line - b.cppCompiler.args "-Wno-sign-compare" - b.cppCompiler.args "-w" - if (b.targetPlatform.operatingSystem.linux) { -// b.linker.args "-static" - } - } - } - } -} // end model // Perform simple dependency change detection for generated files // produced by bison or flex. A 5-second tolerance is used diff --git a/Ghidra/Features/Decompiler/buildNatives.gradle b/Ghidra/Features/Decompiler/buildNatives.gradle new file mode 100644 index 0000000000..a05736f686 --- /dev/null +++ b/Ghidra/Features/Decompiler/buildNatives.gradle @@ -0,0 +1,233 @@ +/* ### + * IP: GHIDRA + * + * 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. + */ + +// Native build files are already applied in development mode (indicated by presence of the +// Generic project). Only need to apply them if we are in a distribution. +if (findProject(':Generic') == null) { + apply from: "../../../GPL/utils.gradle" + apply from: "../../../GPL/nativePlatforms.gradle" + apply from: "../../../GPL/nativeBuildProperties.gradle" +} + +/** + * Define the "native build model" for building the decompiler executables. + */ +model { + + // Define the source files that are compiled and linked to become the decompiler. + // The decompiler source is a bit weird in that all the cpp and headers all live in + // the same directory with other files that are not used by the decompiler. + // That is why we have to list every cpp file that makes up the decomplier. + components { + + decompile(NativeExecutableSpec) { + + baseName "decompile" + + // these tell gradle for which platforms to build a decompiler executable. + targetPlatform "win_x86_64" + targetPlatform "linux_x86_64" + targetPlatform "linux_arm_64" + targetPlatform "mac_x86_64" + targetPlatform "mac_arm_64" + sources { + cpp { + // NOTE: The bison/flex generated files are assumed to be up-to-date. + // The task `generateParsers` should be executed if needed. + // builtBy yaccDecompiler + source { + srcDir "src/decompile/cpp" + + include "space.cc" + include "float.cc" + include "address.cc" + include "pcoderaw.cc" + include "translate.cc" + include "opcodes.cc" + include "globalcontext.cc" + include "capability.cc" + include "architecture.cc" + include "options.cc" + include "graph.cc" + include "cover.cc" + include "block.cc" + include "cast.cc" + include "typeop.cc" + include "database.cc" + include "cpool.cc" + include "comment.cc" + include "stringmanage.cc" + include "fspec.cc" + include "action.cc" + include "loadimage.cc" + include "varnode.cc" + include "op.cc" + include "type.cc" + include "variable.cc" + include "varmap.cc" + include "jumptable.cc" + include "emulate.cc" + include "emulateutil.cc" + include "flow.cc" + include "userop.cc" + include "funcdata.cc" + include "funcdata_block.cc" + include "funcdata_varnode.cc" + include "funcdata_op.cc" + include "pcodeinject.cc" + include "heritage.cc" + include "prefersplit.cc" + include "rangeutil.cc" + include "ruleaction.cc" + include "subflow.cc" + include "transform.cc" + include "blockaction.cc" + include "merge.cc" + include "double.cc" + include "coreaction.cc" + include "condexe.cc" + include "override.cc" + include "dynamic.cc" + include "crc32.cc" + include "prettyprint.cc" + include "printlanguage.cc" + include "printc.cc" + include "printjava.cc" + include "memstate.cc" + include "opbehavior.cc" + include "paramid.cc" + include "ghidra_arch.cc" + include "inject_ghidra.cc" + include "ghidra_translate.cc" + include "loadimage_ghidra.cc" + include "typegrp_ghidra.cc" + include "database_ghidra.cc" + include "ghidra_context.cc" + include "cpool_ghidra.cc" + include "ghidra_process.cc" + include "comment_ghidra.cc" + include "string_ghidra.cc" + // include "callgraph.cc" // uncomment for debug + // include "ifacedecomp.cc" // uncomment for debug + // include "ifaceterm.cc" // uncomment for debug + // include "interface.cc" // uncomment for debug + + // generated source files + + include "xml.cc" + // include "grammar.cc" // used by diagnostic console mode + } + exportedHeaders { + srcDir "src/decompile/cpp" + } + } // end cpp + } // end sources + } // end decompile + + sleigh(NativeExecutableSpec) { + targetPlatform "win_x86_64" + targetPlatform "linux_x86_64" + targetPlatform "linux_arm_64" + targetPlatform "mac_x86_64" + targetPlatform "mac_arm_64" + sources { + cpp { + // NOTE: The bison/flex generated files are assumed to be up-to-date. + // The task `generateParsers` should be executed if needed. + // builtBy lexSleigh + source { + srcDir "src/decompile/cpp" + + include "space.cc" + include "float.cc" + include "address.cc" + include "pcoderaw.cc" + include "translate.cc" + include "opcodes.cc" + include "globalcontext.cc" + include "sleigh.cc" + include "pcodecompile.cc" + include "sleighbase.cc" + include "slghsymbol.cc" + include "slghpatexpress.cc" + include "slghpattern.cc" + include "semantics.cc" + include "context.cc" + include "filemanage.cc" + include "slgh_compile.cc" + + // generated source files + + include "xml.cc" + include "pcodeparse.cc" + include "slghparse.cc" + include "slghscan.cc" + } + exportedHeaders { + srcDir "src/decompile/cpp" + } + } // end cpp + } // end sources (sleigh) + } // end sleigh + + } // end components + + binaries { + all{ b -> + if (b.toolChain in Gcc) { + b.cppCompiler.args "-std=c++11" + b.cppCompiler.args "-Wall" + b.cppCompiler.args "-O2" // for DEBUG, comment this line out + // b.cppCompiler.args "-g" // for DEBUG, uncomment this line + b.cppCompiler.args "-Wno-sign-compare" + if (b.targetPlatform.operatingSystem.linux) { +// b.linker.args "-static" + b.cppCompiler.define "LINUX" + b.cppCompiler.define "_LINUX" + } + } + else if (b.toolChain in VisualCpp) { + b.cppCompiler.args "/EHsc" + b.cppCompiler.define "_SECURE_SCL=0" + b.cppCompiler.define "_HAS_ITERATOR_DEBUGGING=0" + // b.cppCompiler.args "/Zi" // for DEBUG, uncomment this line + // b.cppCompiler.args "/FS" // for DEBUG, uncomment this line + // b.linker.args "/DEBUG" // for DEBUG, uncomment this line + if (b.targetPlatform.operatingSystem.windows) { + b.cppCompiler.define "WINDOWS" + b.cppCompiler.define "_WINDOWS" + b.cppCompiler.define "WIN32" + b.cppCompiler.define "_WIN32" + if (b.targetPlatform.name == "win_x86_64") { + b.cppCompiler.define "WIN64" + b.cppCompiler.define "_WIN64" + } + } + } + else if (b.toolChain in Clang) { + b.cppCompiler.args "-std=c++11" + b.cppCompiler.args "-Wall" + b.cppCompiler.args "-O2" // for DEBUG, comment this line out + // b.cppCompiler.args "-g" // for DEBUG, uncomment this line + b.cppCompiler.args "-Wno-sign-compare" + b.cppCompiler.args "-w" + if (b.targetPlatform.operatingSystem.linux) { +// b.linker.args "-static" + } + } + } + } +} // end model diff --git a/Ghidra/Features/PDB/build.gradle b/Ghidra/Features/PDB/build.gradle index 43fe526337..beea3a7c24 100644 --- a/Ghidra/Features/PDB/build.gradle +++ b/Ghidra/Features/PDB/build.gradle @@ -19,6 +19,7 @@ apply from: "$rootProject.projectDir/gradle/helpProject.gradle" apply from: "$rootProject.projectDir/gradle/jacocoProject.gradle" apply from: "$rootProject.projectDir/gradle/javaTestProject.gradle" apply from: "$rootProject.projectDir/gradle/nativeProject.gradle" +apply from: "buildNatives.gradle" apply plugin: 'eclipse' eclipse.project.name = 'Features PDB' @@ -40,55 +41,10 @@ dependencies { testImplementation project(path: ':SoftwareModeling', configuration: 'testArtifacts') } -/** - * Include PDB native source with sample Visual Studio project to allow users to - * rebuild against other versions. - * - * Note that we use 'this.project' to reference the PDB project - this is because - * inside the closure, 'project' refers to the root project, while 'this' refers to - * PDB. - */ +// Include buildable native source in distribution rootProject.assembleDistribution { - into (getZipPath(this.project) + "/src/pdb") { - from projectDir.toString() + "/src/pdb" + from (this.project.projectDir.toString()) { + include "src/pdb/**" + into { getZipPath(this.project) } } } - -if ("win_x86_64".equals(getCurrentPlatformName())) { - - String makeName = "win_x86_64PDBMake" - task(type: Exec, makeName) { - - def projectPath = projectDir.toString() - def solutionBatchFilePath = projectPath + "/build/buildSolution.bat" - def projectPathWindows = projectPath.replace("/", File.separator) - def solutionPathWindows = "\"${projectPathWindows}\\src\\pdb\\pdb.sln\"" - - doFirst { - file("build/os/win_x86_64").mkdirs() - - def platformToolset = 'v' + VISUAL_STUDIO_TOOLS_VERSION_DEFAULT.substring(0, 4).replace('.', ''); - def windowsTargetPlatformVersion = VISUAL_STUDIO_SDK_VERSION_OVERRIDE ?: VISUAL_STUDIO_SDK_VERSION_DEFAULT - def msbuildCmd = "msbuild ${solutionPathWindows} /p:Configuration=Release /p:PlatformToolset=${platformToolset} /p:WindowsTargetPlatformVersion=${windowsTargetPlatformVersion}" - - println "Executing: " + msbuildCmd - - new File(solutionBatchFilePath).withWriter { out -> - out.println "call " + VISUAL_STUDIO_VCVARS_CMD - out.println msbuildCmd - } - } - - doLast { - assert file("build/os/win_x86_64/pdb.exe").exists() : "Failed to build pdb.exe" - } - - executable "cmd" - - args "/c" - args solutionBatchFilePath.replace("/", File.separator) - } - - - -} diff --git a/Ghidra/Features/PDB/buildNatives.gradle b/Ghidra/Features/PDB/buildNatives.gradle new file mode 100644 index 0000000000..a29e190008 --- /dev/null +++ b/Ghidra/Features/PDB/buildNatives.gradle @@ -0,0 +1,59 @@ +/* ### + * IP: GHIDRA + * + * 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. + */ + +// Native build files are already applied in development mode (indicated by presence of the +// Generic project). Only need to apply them if we are in a distribution. +if (findProject(':Generic') == null) { + apply from: "../../../GPL/utils.gradle" + apply from: "../../../GPL/nativePlatforms.gradle" + apply from: "../../../GPL/nativeBuildProperties.gradle" +} + +if ("win_x86_64".equals(getCurrentPlatformName())) { + + String makeName = "win_x86_64PDBMake" + task(type: Exec, makeName) { + + def projectPath = projectDir.toString() + def solutionBatchFilePath = projectPath + "/build/buildSolution.bat" + def projectPathWindows = projectPath.replace("/", File.separator) + def solutionPathWindows = "\"${projectPathWindows}\\src\\pdb\\pdb.sln\"" + + doFirst { + file("build/os/win_x86_64").mkdirs() + + def platformToolset = 'v' + VISUAL_STUDIO_TOOLS_VERSION_DEFAULT.substring(0, 4).replace('.', ''); + def windowsTargetPlatformVersion = VISUAL_STUDIO_SDK_VERSION_OVERRIDE ?: VISUAL_STUDIO_SDK_VERSION_DEFAULT + def msbuildCmd = "msbuild ${solutionPathWindows} /p:Configuration=Release /p:PlatformToolset=${platformToolset} /p:WindowsTargetPlatformVersion=${windowsTargetPlatformVersion}" + + println "Executing: " + msbuildCmd + + new File(solutionBatchFilePath).withWriter { out -> + out.println "call " + VISUAL_STUDIO_VCVARS_CMD + out.println msbuildCmd + } + } + + doLast { + assert file("build/os/win_x86_64/pdb.exe").exists() : "Failed to build pdb.exe" + } + + executable "cmd" + + args "/c" + args solutionBatchFilePath.replace("/", File.separator) + } +} diff --git a/Ghidra/Features/PDB/src/pdb/pdb.vcxproj b/Ghidra/Features/PDB/src/pdb/pdb.vcxproj index cf7d709341..f77ba5f770 100644 --- a/Ghidra/Features/PDB/src/pdb/pdb.vcxproj +++ b/Ghidra/Features/PDB/src/pdb/pdb.vcxproj @@ -73,12 +73,6 @@ rem copy /y /v /b "$(VSInstallDir)DIA SDK\bin\amd64\msdia*.dll" "$(OutDir)" -set OS_DIR=$(SolutionDir)..\..\os -if exist "%OS_DIR%\win_x86_64" ( - mkdir "%OS_DIR%" - mkdir "%OS_DIR%\win_x86_64" - xcopy /Y /S "$(OutDir)" "%OS_DIR%" -) @@ -106,12 +100,6 @@ if exist "%OS_DIR%\win_x86_64" ( rem copy /y /v /b "$(VSInstallDir)DIA SDK\bin\amd64\msdia*.dll" "$(OutDir)" -set OS_DIR=$(SolutionDir)..\..\os -if exist "%OS_DIR%\win_x86_64" ( - mkdir "%OS_DIR%" - mkdir "%OS_DIR%\win_x86_64" - xcopy /Y /S "$(OutDir)" "%OS_DIR%" -) diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/framework/Application.java b/Ghidra/Framework/Generic/src/main/java/ghidra/framework/Application.java index 2b82f0f754..854a81b691 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/framework/Application.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/framework/Application.java @@ -470,7 +470,7 @@ public class Application { exactFilename); } - // Allow win32 to be used for win64 as fallback + // Allow win_x86_32 to be used for win_x86_64 as fallback if (file == null && Platform.CURRENT_PLATFORM == Platform.WIN_X86_64) { file = getModuleFile(module, "build/os/" + Platform.WIN_X86_32.getDirectoryName(), exactFilename); @@ -479,6 +479,16 @@ public class Application { file = getModuleFile(module, "os/" + Platform.WIN_X86_32.getDirectoryName(), exactFilename); } + + // Allow mac_x86_64 to be used for mac_arm_64 as fallback (requires macOS Rosetta 2) + if (file == null && Platform.CURRENT_PLATFORM == Platform.MAC_ARM_64) { + file = getModuleFile(module, "build/os/" + Platform.MAC_X86_64.getDirectoryName(), + exactFilename); + } + if (file == null && Platform.CURRENT_PLATFORM == Platform.MAC_ARM_64) { + file = getModuleFile(module, "os/" + Platform.MAC_X86_64.getDirectoryName(), + exactFilename); + } if (file == null) { throw new OSFileNotFoundException(moduleName, exactFilename); @@ -506,13 +516,21 @@ public class Application { file = findModuleFile("os/" + Platform.CURRENT_PLATFORM.getDirectoryName(), path); } - // Allow win32 to be used for win64 as fallback + // Allow win_x86_32 to be used for win_x86_64 as fallback if (file == null && Platform.CURRENT_PLATFORM == Platform.WIN_X86_64) { file = findModuleFile("build/os/" + Platform.WIN_X86_32.getDirectoryName(), path); } if (file == null && Platform.CURRENT_PLATFORM == Platform.WIN_X86_64) { file = findModuleFile("os/" + Platform.WIN_X86_32.getDirectoryName(), path); } + + // Allow mac_x86_64 to be used for mac_arm_64 as fallback (requires macOS Rosetta 2) + if (file == null && Platform.CURRENT_PLATFORM == Platform.MAC_ARM_64) { + file = findModuleFile("build/os/" + Platform.MAC_X86_64.getDirectoryName(), path); + } + if (file == null && Platform.CURRENT_PLATFORM == Platform.MAC_ARM_64) { + file = findModuleFile("os/" + Platform.MAC_X86_64.getDirectoryName(), path); + } if (file == null) { throw new OSFileNotFoundException(path); diff --git a/Ghidra/RuntimeScripts/Linux/support/buildNatives b/Ghidra/RuntimeScripts/Linux/support/buildNatives new file mode 100755 index 0000000000..76dafe9722 --- /dev/null +++ b/Ghidra/RuntimeScripts/Linux/support/buildNatives @@ -0,0 +1,41 @@ +#!/usr/bin/env bash + +#---------------------------------------- +# Build Native Binaries +# +# args: forwarded to gradle (-i, -s, etc) +#---------------------------------------- + +# Make sure gradle is on the path +if ! [ -x "$(command -v gradle)" ] ; then + echo "Gradle not found on the PATH." + exit 1 +fi + +# Resolve symbolic link if present and get the directory this script lives in. +# NOTE: "readlink -f" is best but works on Linux only, "readlink" will only work if your PWD +# contains the link you are calling (which is the best we can do on macOS), and the "echo" is the +# fallback, which doesn't attempt to do anything with links. +SCRIPT_FILE="$(readlink -f "$0" 2>/dev/null || readlink "$0" 2>/dev/null || echo "$0")" +SCRIPT_DIR="${SCRIPT_FILE%/*}" + +buildGhidraNatives () { + echo "Building natives in Ghidra..." + pushd ${SCRIPT_DIR}/../Ghidra &>/dev/null + gradle "$@" buildNatives + result=$? + popd &>/dev/null + return $result +} + +buildGplNatives () { + echo "Building natives in GPL..." + pushd ${SCRIPT_DIR}/../GPL &>/dev/null + gradle "$@" buildNatives + result=$? + popd &>/dev/null + return $result +} + +buildGhidraNatives "$@" && buildGplNatives "$@" + diff --git a/Ghidra/RuntimeScripts/Windows/support/buildNatives.bat b/Ghidra/RuntimeScripts/Windows/support/buildNatives.bat new file mode 100644 index 0000000000..5fae87b936 --- /dev/null +++ b/Ghidra/RuntimeScripts/Windows/support/buildNatives.bat @@ -0,0 +1,39 @@ +:: Build Native Binaries +:: +:: args: forwarded to gradle (-i, -s, etc) + +@echo off + +:: See if we were doubled clicked or run from a command prompt +set DOUBLE_CLICKED=n +for /f "tokens=2" %%# in ("%cmdcmdline%") do if /i "%%#" equ "/c" set DOUBLE_CLICKED=y + +:: Make sure gradle is on the path +call gradle -h >nul 2>nul +if not %ERRORLEVEL% == 0 ( + echo Gradle not found on the PATH + goto exit +) + +echo Building natives in Ghidra... +pushd "%~dp0..\Ghidra" +call gradle %* buildNatives +popd +if not %ERRORLEVEL% == 0 ( + goto exit +) + +echo Building natives in GPL... +pushd "%~dp0..\GPL" +call gradle %* buildNatives +popd +if not %ERRORLEVEL% == 0 ( + goto exit +) + +:exit +if "%DOUBLE_CLICKED%"=="y" ( + pause +) + +exit /B %ERRORLEVEL% diff --git a/Ghidra/RuntimeScripts/certification.manifest b/Ghidra/RuntimeScripts/certification.manifest index c01853669d..cfc9b7e8c7 100644 --- a/Ghidra/RuntimeScripts/certification.manifest +++ b/Ghidra/RuntimeScripts/certification.manifest @@ -14,6 +14,7 @@ Linux/server/svrInstall||GHIDRA||||END| Linux/server/svrUninstall||GHIDRA||||END| Linux/support/analyzeHeadless||GHIDRA||||END| Linux/support/buildGhidraJar||GHIDRA||||END| +Linux/support/buildNatives||GHIDRA||||END| Linux/support/convertStorage||GHIDRA||||END| Linux/support/ghidraDebug||GHIDRA||||END| Linux/support/pythonRun||GHIDRA||||END| @@ -26,6 +27,7 @@ Windows/server/svrUninstall.bat||GHIDRA||||END| Windows/support/README_createPdbXmlFiles.txt||GHIDRA||||END| Windows/support/analyzeHeadless.bat||GHIDRA||||END| Windows/support/buildGhidraJar.bat||GHIDRA||||END| +Windows/support/buildNatives.bat||GHIDRA||||END| Windows/support/convertStorage.bat||GHIDRA||||END| Windows/support/createPdbXmlFiles.bat||GHIDRA||||END| Windows/support/ghidra.ico||GHIDRA||||END| diff --git a/GhidraDocs/InstallationGuide.html b/GhidraDocs/InstallationGuide.html index 811fc7dfad..65219dd50b 100644 --- a/GhidraDocs/InstallationGuide.html +++ b/GhidraDocs/InstallationGuide.html @@ -31,6 +31,7 @@ future releases.
  • Java Notes
  • Ghidra Installation Directory Layout
  • +
  • Building Ghidra Native Components
  • Running Ghidra
    • GUI Mode
    • @@ -298,6 +299,39 @@ is complete.

      (Back to Top)

      +

      Building Ghidra Native Components

      +

      Ghidra requires several native binaries to be present in order to successfully run. An official +Ghidra release includes native binaries for the following platforms:

      +
        +
      • Windows x86 64-bit
      • +
      • Linux x86 64-bit
      • +
      • macOS x86 64-bit
      • +
      • macOS ARM 64-bit (x86 using Rosetta translation)
      • +
      +

      Ghidra supports running on the following additional platforms with user-built native binaries: +

      +
        +
      • Linux ARM 64-bit
      • +
      • macOS ARM 64-bit (Apple silicon)
      • +
      +

      In order to build native binaries for your platform, you will need the following installed on your +system:

      + +

      To build the native binaries for your current platform, execute the following script:

      +
      <GhidraInstallDir>/support/buildNatives(.bat)
      +

      When this script successfully completes, Ghidra will contain newly built native binaries in +the relevant modules' build/os/<platform>/ subdirectories, which will override any +existing pre-built native binaries in the os/<platform>/ subdirectories.

      +

      (Back to Top)

      +

      Running Ghidra

      GUI Mode

        diff --git a/README.md b/README.md index 65153b66a9..6e1891729d 100644 --- a/README.md +++ b/README.md @@ -79,13 +79,10 @@ development process has been highly customized for. * Follow the above build instructions so the build completes without errors * Install [Eclipse IDE for Java Developers][eclipse] -##### Prepare the development environment (Linux/x86-only, see **NOTE** for other platforms): +##### Prepare the development environment: ``` -$ gradle prepdev eclipse buildNatives_linux_x86_64 +$ gradle prepdev eclipse buildNatives ``` -**NOTE:** If you are on a different platform, change `buildNatives_linux_x86_64` to the gradle task -that is appropriate for your platform: `buildNatives_win_x86_64`, `buildNatives_mac_x86_64`, -`buildNatives_mac_arm_64`, or `buildNatives_linux_arm_64` ##### Import Ghidra projects into Eclipse: * *File* -> *Import...* @@ -114,4 +111,4 @@ source project. [gradle]: https://gradle.org/releases/ [vs]: https://visualstudio.microsoft.com/vs/community/ [eclipse]: https://www.eclipse.org/downloads/packages/ -[master]: https://github.com/NationalSecurityAgency/ghidra/archive/refs/heads/master.zip \ No newline at end of file +[master]: https://github.com/NationalSecurityAgency/ghidra/archive/refs/heads/master.zip diff --git a/gradle/nativeProject.gradle b/gradle/nativeProject.gradle index fb2a369aa1..5e67309675 100644 --- a/gradle/nativeProject.gradle +++ b/gradle/nativeProject.gradle @@ -19,10 +19,28 @@ A gradle project can add native code support by including the following it its build.gradle file: - apply from: "$rootProject.projectDir/gradle/javaProject.gradle" + apply from: "$rootProject.projectDir/gradle/nativeProject.gradle" *****************************************************************************************/ // These same settings are needed in the GPL native, so rather than duplicating this file, we will just call the other file def projectRootDir = rootProject.projectDir.path apply from: "$projectRootDir/GPL/nativeBuildProperties.gradle" + +// Include and rename native projects' buildNative.gradle files to build.gradle in the distribution +// so a user can build or rebuild natives for their specific platform. +// NOTE: GPL projects' build.gradle files are already written to build their natives from a release, +// so we can just include their build.gradle as as-is. +rootProject.assembleDistribution { + def p = this.project + from (p.projectDir.toString()) { + if (p.projectDir.parentFile.name == "GPL") { + include "build.gradle" + } + else { + include "buildNatives.gradle" + rename "buildNatives.gradle", "build.gradle" + } + into { getZipPath(p) } + } +} diff --git a/gradle/root/distribution.gradle b/gradle/root/distribution.gradle index a8f88b0f16..4e364bdc40 100644 --- a/gradle/root/distribution.gradle +++ b/gradle/root/distribution.gradle @@ -352,6 +352,15 @@ task assembleDistribution (type: Copy) { from (ROOT_PROJECT_DIR + "/GhidraBuild/patch") { into "Ghidra/patch" } + + ///////////////////////////////// + // Distro native build support + ///////////////////////////////// + from (ROOT_PROJECT_DIR + "/GPL") { + include "settings.gradle" + into "Ghidra" + } + } /********************************************************************************* diff --git a/gradle/root/usage.gradle b/gradle/root/usage.gradle index 59fba64401..b82158a7dd 100644 --- a/gradle/root/usage.gradle +++ b/gradle/root/usage.gradle @@ -34,18 +34,18 @@ Primary gradle tasks for Ghidra usage Displays this text [root/usage.gradle] prepDev Prepares development environment [root/prepDev.gradle] + eclipse Create eclipse projects [root/eclipse.gradle] buildHelp Builds help [root/buildHelp.gradle] - buildGhidra Builds Ghidra for the current platform [root/distribution.gradle] - buildGhidra -PallPlatforms Builds Ghidra for all platforms (assumes natives [root/distribution.gradle] - for other platforms are already built into - appropriate os dirs) + buildGhidra Builds Ghidra for the current platform [root/distribution.gradle] + buildGhidra -PallPlatforms Builds Ghidra for all platforms (assumes natives [root/distribution.gradle] + for other platforms are already built into + appropriate os dirs) Task rules: - buildNatives_[platform] builds the native executables and libraries for the - specified platform (win_x86_64, linux_arm_64, mac_x86_64, etc.) [nativeProject.gradle] - prebuildNatives_[platform] builds the native executables and libraries for the - specified platform and copies results to bin repo. [nativeProject.gradle] - + buildNatives[_platform] Builds the native executables and libraries for the [GPL/nativeBuildProperties.gradle] + current or specified platform (win_x86_64, + linux_arm_64, mac_x86_64, etc.) + """ } } diff --git a/gradle/support/ip.gradle b/gradle/support/ip.gradle index d8fc9f89d2..2b01fac95d 100644 --- a/gradle/support/ip.gradle +++ b/gradle/support/ip.gradle @@ -126,6 +126,7 @@ def Map> getIpForModule(Project p) { exclude ".classpath" exclude "Module.manifest" exclude "build.gradle" + exclude "buildNatives.gradle" exclude "**/Misc/Tips.htm" exclude "**/*.sla" exclude "**/.gradle/**" diff --git a/settings.gradle b/settings.gradle index 66751b3fc6..13335a393d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -41,6 +41,7 @@ includeProject('GhidraTest', '.', true) includeProject('decompile', 'Ghidra/Features/Decompiler/src', true) includeProject('RuntimeScripts', 'Ghidra', true) includeProject('IDAPro', 'GhidraBuild', true) +includeProject('NativeSupport', 'GhidraBuild', true) includeProject('GhidraDocs', '.', true) includeProjects('GhidraBuild/EclipsePlugins/GhidraDev') // requires Eclipse PDE includeProjects('GhidraBuild/EclipsePlugins/GhidraSleighEditor') // requires Eclipse DSL