I'm trying to figure out how to use Gradle. I'm having this problem, which is trivial to solve in Makefiles, CMake, etc, but I have not idea how to do it in Gradle.
Let's say I have an application that contains some resource files inside. Those resource files are generated from a set of input files, and are put inside the application in compiled form.
I'd like to instruct Gradle to automatically generate those resources when it's needed by pointing it to the resource input files. So, effectively I'd like to do something like this:
all: out1 out2
@echo done
out1: in1
cat in1 | xxd > out1
out2: temp1
cat temp1 | xxd > out2
temp1: in1
cat in2 | tr '[:lower:]' '[:upper:]' > temp1
(let's skip this unfortunate effect when if xxd
will fail then an invalid out1
will be generated)
Let's say out1
and out2
are my resource files that I'd like to embed inside the application. These files are generated by different rules:
out1
is generated from in1
by processing it with xxd
(it's just an example),out2
is generated from in2
by first uppercasing it, and then piping it through xxd
. A temporary file, temp1
is being created in the meantime, but that's just a temporary file and it's not important at all.So what I'd like to achieve in Gradle is basically an equivalent of the Makefile script pasted above with all its features; I mostly mean that out1
and out2
shouldn't be generated if in1
and in2
didn't change (because the resource generation phase can be expensive and time consuming, so I'd like to avoid having to run it on each build), and the possibility of the build system to automatically figure out how to run the build in parallel, so that out1
and out2
is being generated at the same time.
I'm trying to dig up the docs for Gradle and some examples, but 95% of what I find are some opaque scripts that use some particular plugin, which nobody explains how it works inside. The docs say that Gradle is an "automation tool", so it should be perfectly doable what I'm trying to achieve, but is it really the case? Is there any sense in trying to use Gradle as a tool for the use-case described in this post?
Minimal example code generation Gradle task is being presented here:
https://github.com/gradle/native-samples/blob/master/cpp/source-generation/build.gradle
plugins {
id 'cpp-application'
id 'xcode'
id 'visual-studio'
}
def codeGeneration = tasks.register("codeGeneration", CodeGenerator) {
cppDir = project.layout.buildDirectory.dir("generated/cpp")
headersDir = project.layout.buildDirectory.dir("generated/headers")
}
application {
source.from codeGeneration.flatMap { it.cppDir }
privateHeaders.from codeGeneration.flatMap { it.headersDir }
}
// Code generation implementation could be in another plugin or buildSrc
class CodeGenerator extends DefaultTask {
@OutputDirectory
DirectoryProperty cppDir = project.objects.directoryProperty()
@OutputDirectory
DirectoryProperty headersDir = project.objects.directoryProperty()
@TaskAction
public void generate() {
generateSources(cppDir.getAsFile().get())
generateHeaders(headersDir.getAsFile().get())
}
private void generateSources(File generatedDir) {
new File(generatedDir, "main.cpp").text = """
#include <iostream>
#include "header.h"
int main() {
std::cout << MESSAGE << std::endl;
return 0;
}
"""
}
private void generateHeaders(File generatedDir) {
new File(generatedDir, "header.h").text = """
#pragma once
#define MESSAGE "Hello, World!"
"""
}
}```