Website | Source | Plugin Portal
Docs: User Guide | DSL Reference | Forums
Introduction into C++ Builds with Gradle
Shadow plugin: "Shadow is a Gradle plugin for combining a project's dependency classes and resources into a single output Jar. The combined Jar is often referred to a fat-jar or uber-jar. ... Shadowing a project output has 2 major use cases: (1) Creating an executable JAR distribution, and Bundling and relocating common dependencies in libraries to avoid classpath conflicts."
Gradle uses a 1:1 relationship of a build script to a Project instance. Most "magic" comes from the use of plugins (listed below). Thus, the world's simplest Gradle build:
// build.gradle.kts
println("Hello Gradle")
... when run with gradle -b build.gradle.kts
:
~/Projects/Exploration.git/Gradle % gradle -b build.gradle.kts
> Configure project :
Hello Gradle
> Task :help
Welcome to Gradle 8.10.
To run a build, run gradle <task> ...
To see a list of available tasks, run gradle tasks
To see more detail about a task, run gradle help --task <task>
To see a list of command-line options, run gradle --help
For more detail on using Gradle, see https://docs.gradle.org/8.10/userguide/command_line_interface.html
For troubleshooting, visit https://help.gradle.org
Deprecated Gradle features were used in this build, making it incompatible with Gradle 9.0.
You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.
For more on this, please refer to https://docs.gradle.org/8.10/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation.
BUILD SUCCESSFUL in 843ms
1 actionable task: 1 executed
Wrote a custom task that invokes javap
on compiled class files (here):
open class Javap: DefaultTask() {
@Internal var workingDir = "./build/classes/java/main"
@Internal var outputDir: String = ""
@Internal lateinit var classFiles: List<String>
@Internal lateinit var javapArguments: List<String>
@Internal var projectDir = project.projectDir
@TaskAction
fun runCommand() {
logger.warn("Running 'disasm' replaces the marked javap files with newly-generated content!")
for (classFile in classFiles) {
val commandLine = ("javap " + javapArguments.joinToString(" ") + " " + classFile)
try {
val workingDir = File(projectDir, workingDir)
val outputDir = File(projectDir, outputDir)
val parts = commandLine.split("\\s".toRegex())
// Transform the classFile string/path to a dotted name
val dottedClassFile = classFile.split("/").joinToString(".")
val outputFile = File(outputDir, dottedClassFile + ".bytecode")
val proc = ProcessBuilder(*parts.toTypedArray())
.directory(workingDir)
.redirectOutput(outputFile)
.redirectError(ProcessBuilder.Redirect.PIPE)
.start()
proc.waitFor(60, TimeUnit.MINUTES)
println("Success processing ${classFile}")
} catch(e: Exception) {
e.printStackTrace()
println("Failure processing ${classFile}: ${e.message}")
}
}
}
}
tasks.register<Javap>("disasm") {
group = "build"
description = "Produce disassembly listings of Java code"
javapArguments = listOf("-v")
outputDir = ""
classFiles = listOf(
"com/newardassociates/demo/App.class",
"com/newardassociates/demo/Greeter.class",
"com/newardassociates/demo/Math.class",
"com/newardassociates/demo/Outer.class",
"com/newardassociates/demo/Outer\$Inner.class",
"com/newardassociates/demo/StringConcat.class",
"com/newardassociates/demo/Varargs.class",
)
dependsOn("compileJava")
}
group
and description
are inherited from DefaultTask
, so I should probably figure out how to pass those in a constructor or somethingLast modified 28 April 2025