How to add a pre compile task into cpp plugin

Hello Folks,

I have a Qt based cpp application and I want to migrate the build scripts from qmake to gradle.
To do so I need to run the Qt moc tool over all header files that contain the Q_OBJECT key word.

I’ve done some research on how to achieve that, but I’m struggling.
Can someone give me a hint?

Should I extend the cpp plugin, and if so, where can I inject my task.
I looked at the sources of the cpp plugin, but didn’t see a point to extend it.

Or should I do it in the model space or with the rule mechanism?

Thank you in advance
Christian

So, after a long journey I found a solution by myself.

import org.gradle.api.file.FileCollection
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.SourceTask
import org.gradle.api.tasks.TaskAction

class QtMocTask extends SourceTask {
    @OutputDirectory
    File destinationDir
        
    @TaskAction
    void generateMocFile() {
         source.filter { x -> x.isFile() && x.text.contains('Q_OBJECT') }.each {
             def mocFileName = "${destinationDir}/moc_${it.name}.cpp"
             def process = "moc -o ${mocFileName} ${it.path}".execute()
             process.waitFor()
             if (process.exitValue()) {
                 println process.err.text
             } 
         }
    }
}
import org.apache.commons.lang.StringUtils
import org.gradle.model.Defaults
import org.gradle.model.Mutate
import org.gradle.model.ModelMap
import org.gradle.model.Path
import org.gradle.model.RuleSource
import org.gradle.platform.base.BinarySpec
import org.gradle.language.cpp.CppSourceSet
import org.gradle.language.cpp.tasks.CppCompile

class QtPlugin extends RuleSource {

    @Defaults
    void createQtMocTask(ModelMap<BinarySpec> binaries, final @Path("buildDir") File buildDir) {
        binaries.beforeEach { binary ->
            binary.inputs.withType(CppSourceSet.class) { sourceSet ->
                def taskName = "${binary.getNamingScheme().getTaskName('qtMoc')}${StringUtils.capitalize(sourceSet.parentName)}${StringUtils.capitalize(sourceSet.name)}"
                binary.tasks.create(taskName, QtMocTask) { task ->
                    task.source = sourceSet.source
                    task.destinationDir = new File(buildDir, "generated/${binary.name}/moc")
                    task.description = "Creates qt moc-files for ${binary.displayName}"
                }

                sourceSet.source.srcDir(new File(buildDir, "generated/${binary.name}/moc"))
                binary.tasks.withType(CppCompile.class) { compileTask ->
                    compileTask.dependsOn(taskName)
                }
            }
        }
    }
}

Would be nice to here some comments.
Christian

Hi Christian,

I don’t know if you are still using this, but I’d like to try it out (not knowing anything about extending Gradle…).

Do you have an example script?

Hello Jason,

what exactly do you want to know? Currently I’m not working with gradle any more because I had no time in the last months, but I still do have the sources.

Hi Christian, thanks for getting back to me…

I take it you have to build the two Java snippets (or does Groovy interpret them?)

What does the build.gradle file look like for a simple Qt project (i.e. how do I inject the plugins)?

This how my build.gradle looks like:

apply plugin: 'cpp'

model {
    repositories {
        libs(PrebuiltLibraries) {
          QtHeaders {
            headers.srcDir "/usr/include/qt4/"
          }

          ["QtCore", "QtGui"].each { libName -> "${libName}" {
                // You have to locate where qt installed the header files
                headers.srcDir "/usr/include/qt4/${libName}"
                binaries.withType(SharedLibraryBinary) {
                    // You have to locate where qt installed the libs
                    sharedLibraryFile = file("/usr/lib/lib${libName}.so")
                }
              }
          }
        }
    }

    components {
        main(NativeExecutableSpec) {
          sources {
              cpp {
                  lib library: 'QtHeaders', linkage: 'api'
                  lib library: 'QtCore', linkage: 'shared'
                  lib library: 'QtGui', linkage: 'shared'
              }
          }
        }
    }

}

import my.gradle.qt.QtPlugin
apply plugin: QtPlugin

task wrapper(type: Wrapper) {
    gradleVersion = '2.10'
}

I do not know if it still works with the new gradle versions.

I created a repo with the whole source code here:
https://github.com/nesayus/gradle.qt

Awesome, I will give it a try!