How to: build an executable, execute it, which produces artifacts which are required by other parts of the project?


Background: First off, I’m a complete gradle/groovy newb. I’ve got a passing familiarity w/ gradle from looking at some projects that some of my colleagues’ projects.I’m a very experienced C/C++ programmer, working with a large, (>8MLOC), legacy code base. Currently, building w/ make, but it’s become cumbersome, (more than 16 targets, this code/build has been around for >25years).

I’m at a good place for major refactoring, and dropping support for some of these targets.

The problem: During the build process several utility programs are built, which are then executed and produce artifacts that other parts of the build depend upon. (E.g. They produce source files, which must be compiled, or .h files which are expected by the compilation of other source files.).

The question: Is there a “Gradle Way™” of doing this? I’ve been able to create the appropriate build.gradle entries to create one of the utility programs, but I’m at a loss for understanding how to cause it to execute at the correct point in the build.

I’m using model { components { gen(NativeExecutableSpec)} …}

This produces: “…/build/exe/{platform}/gen” as expected, but now I need to run that before attempting to build the next (NativeLibrarySpec) item(s).

Any thoughts?

I do not think such a build system is a good idea to begin with. I would have separated the tooling from the production code and built them separately with appropriate testing for each.

Things that generate code in general would be gradle plugins which could wrap your tools that generate artifacts with Gradle tasks. These Gradle tasks would be referenced in “generatedBy” methods provided by Gradle native SourceSets that then take care of the compilation of the generated code.

For each of the native tools that you have accomplished a full build you would use the “installExecutable” task as a dependency of the Gradle “run” task. The Gradle “run” task would be how you would use these tools as Gradle tasks, probably based on the Gradle Exec task. Ideally you would create a new Exec task subclass that provides proper behavior modeling for your tools and declares outputs. If these are tools generating sources like C++ headers/sources then you can add the headerDir/sourceDir properties to them to make them automatically adaptable to use in SourceSet generatedBy method calls.

This is just random thoughts off the top of my head. You have a long way to get this done. I did something similar and succeeded in the task by applying a full on refactoring of Gradle plugins to replace home grown tools like that. If no suitable Gradle plugins existed for a specific tool a new plugin was created either to recreate the tool’s operation or to wrap the tool as I described. In some cases the Gradle DSL was extended to make all this more natural to developers.