Gradle Native C++ - Set prebuild task based on platform (32 or 64 bit)

Hi to all. I’m a newbie in using Gradle, so sorry if my questions would sound naive. I’m trying to migrate from Makefiles to Gradle, in order to setup a basic Continuous Integration Server for several “legacy” C++ projects in Linux.
Specifically, I have to call a Sybase pre-compiler for some files, which generates cpp files to be passed to the gcc compiler along with other ordinary cpp files. The final output consists of a shared library.

The precompiler comes with two distinct executables, c_pre32 (for 32 bit) and c_pre64 (for 64 bit).

I successfully created a task (precompileSybase) that iteratively calls the precompiler on every Sybase file.

Now I have 2 distinct problems:

  1. I want to call precompileSybase before every call to a build task: by this way, the build task will find in the main directory also the cpp generated files, and should correctly compile and link
  2. Gradle automatically creates 2 build tasks: x32DebugFooSharedLibrary and x64DebugFooSharedLibrary. I need a way to set the correct Sybase executable name (c_pre32 or c_pre64) depending on the bitness of the build task. I suppose this string should be passed to the precompileSybase task, rather than having two distinct task (e.g. precompileSybase_32 and precompileSybase_64)

For the first problem, I tried with this:

tasks.getByPath('x64DebugFooSharedLibrary').dependsOn precompileSybase

but I get this error:

Task with path 'x64DebugFooSharedLibrary' not found in root project 'Foo'.

For the second problem, I tried using TaskInputs map:

tasks.getByPath('precompileSybase').inputs.property("sybasePrecompiler", "cpre_r64")

but I don’t know where to call it.

Any help is appreciated!

Thanks,
Mauro

So for 1, generated source is a pretty common pattern. The best way to handle this is to model it as a sourceset that is generated by a task. See the native-binaries/idl sample for an example of setting up a generated sourceset.

For 2, the best way to do this would be to define a custom task with the platform as part of it’s api. See the userguide section for information on creating custom tasks. You would still have two distinct task instances, but one would be configured to use the 32bit executable and the other the 64 bit executable. The common logic would be tied up in the custom task class.

Thanks Gary,

I successfully solved problem 1 using the example you gave. I just had to modify the following part:

sources {        
                cpp    {
                    source {
                        srcDir "./"
                        include "**/*.cpp"
                    
                        //Call the task that generates cpp files from Sybase files
                        generatedBy tasks.compileSybase
                    }
                }
            }

By this way, the generated cpp files will be added to the set of regular cpp files. After this task, the compiler will find the entire augmented set of source files and will regularly proceed in creation of objects files.

Problem 2 is still unsolved. I can’t filter by the platform.

Thank you again,
Mauro

If I understand correctly, you essentially have two different (generated) source sets and you only want to include one or the other when building each platform. Changing the source of a single component by platform is not readily available. Off the top of my head, the simplest way to achieve what you want would be to model this as two components (each targeted at the appropriate platform).

Thanks for the hint. So, I did:

model {
components {
        foo32(NativeLibrarySpec) {            
            targetPlatform "x86"
            sources {        
                cpp    {
                    source {
                        srcDir "./"
                        include "**/*.cpp"

                        generatedBy tasks.compileSybase32
                    }
                }
            }
        }

        foo64(NativeLibrarySpec) {            
            targetPlatform "x64"
            sources {        
                cpp    {
                    source {
                        srcDir "./"
                        include "**/*.cpp"

                        generatedBy tasks.compileSybase64
                    }
                }
            }
        }
   }
}

I admit I came to the same idea, but I thought it was too verbose. I wonder if I could be more succint, because this kind of configuration will be the same for a lot of projects.
As an example, let’s suppose I got 10 project Foo_1, Foo_2, …, Foo_10. For each Foo_k I shall replicate the same build.gradle, except for the components names Foo_k32 and Foo_k64. Can I put a parametrized version of this configuration in a separate script common.gradle, in which the parameter consists in the actual project name?

Thank you very much for your help!