How to add a pre compile task into cpp plugin

plugins

(Christian) #1

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


(Christian) #2

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


(Jason Chown) #3

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?


(Christian) #4

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.


(Jason Chown) #5

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)?


(Christian) #6

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.


(Christian) #7

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


(Jason Chown) #8

Awesome, I will give it a try!