How do I get incremental native c++ compilation to handle generated headers?


(Joel Klinghed) #1

I have project that uses JNI and generates headers for each Java class and have trouble getting the JNI library to rebuild correctly after the headers have been updated. I made a minimal project without both the Java and JNI parts just to illustrate the problem I’m having.

The problem is that even tho the header is changed and the compileMainCpp task recognizes this (with help) the incremental compilation will not pick up the change and recompile the source file.

The build.gradle file I have so far (github project link below):
apply plugin: ‘cpp’

model {
  binaries {
    all {
      cppCompiler.args "-I$buildDir/gen"
    }
  }
  components {
    test(NativeExecutableSpec) {
      sources {
        cpp {
          source {
            srcDir "."
            include "*.cpp"
          }
        }
      }
    }
  }
}

task generateHeader(type: Copy) {
  into "$buildDir/gen"
  from(rootProject.file('template.h')) {
    rename(/template/, 'generated')
    expand([text: 'foo'])
  }
}

tasks.all { task ->
  def match = task.name =~ /^compile.*Cpp$/
  if (match) {
    task.dependsOn generateHeader

    task.inputs.files project.fileTree(dir: "$buildDir/gen").matching {
      include '*.h'
    }
  }
}

Sample project is available: https://github.com/thejk/gradle-incremental-cpp-generated-header


(Gary Hale) #2

In your example, the issue is that the generated header dir is added as a command line argument to the compiler, so it is not well understood by the Gradle model. You would need to add the directory to test.sources.cpp.exportedHeaders to make the incremental compiler pick it up.

On the other hand, there is some limited support for generated sources built into Gradle. Take a look at this sample from the distribution: https://github.com/gradle/gradle/blob/master/subprojects/docs/src/samples/native-binaries/idl/build.gradle

Note the generatedBy method on the source set and the headerDir and sourceDir properties on the task. This is the linkage that makes this work. Gradle will add those directories from the task to the source set and infer the task dependency for the compile task.


(Joel Klinghed) #3

Thanks, I had missed that sample - very helpful.