Reputation: 4008
As part of an Android app that uses the NDK, I need to export some constants from the C/C++ world into Java. For obvious reasons, I'd rather have this automated. I'm using Android Studio with the NDK support.
How can I generate some .java
file on the fly from a shell script that would be ran by Gradle whenever the app builds? Ideally this .java
file would go in an build intermediaries directory somewhere and wouldn't have to be in the app source directory.
As an example, the shell script would generate this Java source:
public enum Type {
FOO,
BAR
}
from this C++ source:
enum class Type {
FOO,
BAR
}
For reference here's a simplified version of the Gradle file I'm starting from in Android Studio:
apply plugin: 'com.android.model.application'
model {
compileOptions.with {
sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7
}
android {
compileSdkVersion = 23
buildToolsVersion = "23.0.2"
defaultConfig.with {
applicationId = "..."
minSdkVersion.apiLevel = 18
targetSdkVersion.apiLevel = 23
}
defaultConfig.multiDexEnabled = true
}
android.ndk {
platformVersion = "18"
moduleName = "jni"
...
}
android.buildTypes {
release {
minifyEnabled = false
proguardFiles.add(file('proguard-rules.txt'))
ndk.with {
CFlags.add("-Werror")
cppFlags.add("-Werror")
}
}
}
android.productFlavors {
create("arm7") {
ndk.abiFilters.add("armeabi-v7a")
}
}
}
repositories {
...
}
dependencies {
...
}
apply plugin: 'com.google.gms.google-services'
Upvotes: 2
Views: 2055
Reputation: 11405
You could just write the generated file to the $buildDir/generatedJava
then add that directory as a source folder. Then make the task javaCompile
depend on your task that generates the source. Something like this could be used inside a build.gradle
def outputJavaFile = new File("$buildDir.absolutePath/generatedJava", 'MyEnum.java')
task generateSources(type: Exec) {
def source = $/
package com.example;
public enum Something {
One,
Two
}
/$
if (!outputJavaFile.parentFile.exists()) {
outputJavaFile.parentFile.mkdirs()
}
outputJavaFile.withWriter {
it << source
}
}
compileJava.dependsOn outputJavaFile
sourceSets {
main {
java {
srcDirs 'src/main/java', outputJavaFile.absolutePath
}
}
}
// if the goal is to generate the source from a script then just call the script
// inside the Exec closure
task shellScriptToGenerateSources(type: Exec) {
commandLine 'myShellScript.sh'
}
// then make compileJava depend on the task that runs the script
compileJava.dependsOn shellScriptToGenerateSources
Edit: To apply the same logic to your updated build.gradle
file might look something like this
apply plugin: 'com.android.model.application'
// define an output folder for our generated .java files
def GENERATED_JAVA_OUTPUT = "$buildDir/generatedJava"
// if the goal is to generate the source from a script then just call the script
// inside the Exec closure
task shellScriptToGenerateSources(type: Exec) {
commandLine 'myShellScript.sh'
}
// then make compileJava depend on the task that runs the script
compileJava.dependsOn shellScriptToGenerateSources
model {
compileOptions.with {
sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7
}
android {
compileSdkVersion = 23
buildToolsVersion = "23.0.2"
defaultConfig.with {
applicationId = "..."
minSdkVersion.apiLevel = 18
targetSdkVersion.apiLevel = 23
}
defaultConfig.multiDexEnabled = true
}
android.ndk {
platformVersion = "18"
moduleName = "jni"
...
}
android.buildTypes {
release {
minifyEnabled = false
proguardFiles.add(file('proguard-rules.txt'))
ndk.with {
CFlags.add("-Werror")
cppFlags.add("-Werror")
}
}
}
android.productFlavors {
create("arm7") {
ndk.abiFilters.add("armeabi-v7a")
}
}
// let android know that our java sources shoudl also consider the generated java for the compiler
android.sourceSet {
main {
java {
srcDir(GENERATED_JAVA_OUTPUT)
}
}
}
}
repositories {
...
}
dependencies {
...
}
apply plugin: 'com.google.gms.google-services'
Upvotes: 2