I did run into issue with running gradle with cmake.
This part of the code inside cmake file does not seem to work correctly
git_describe(GIT_DESCRIBE "--abbrev=7")
Because there is part of the code that depends on defined GIT_DESCRIBE and because git_describe fails block of that code does not gets execute. And I want to make it work as expected thus executing this block of code.
Here is the scheme of the Project:
-Root Dir of the Project:
-Submodule of git repo
-Rest of the files
Gradle File where it does set the Cmake (CMakeLists is contained inside of that submodule)
externalNativeBuild {
cmake {
path 'path/to/CMakeLists.txt'
}
}
It should work out of the box but when using this combination gradle + cmake it fails.
Running git describe --abbrev=7 in terminal shows the expected value.
I have replaced git_describe with execute_process
execute_process(COMMAND git describe --abbrev=7
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE GIT_DESCRIBE)
This solved issue.
Related
I followed the manual written by Bugsplat to build Crashpad for Android.
The build was successful and I got all necessary libraries. However I noticed that the prebuilt library libcrashpad_handler.so in Bugsplat's sample weighs about 26Mb. And mine is only 700Kb.
Moreover I got errors from linker when trying to catch signals from system.
/lib/arm64/libcrashpad_handler.so": library "libc++_shared.so" not found: needed by main executable
Is the instructions are not up-to-date on Bugsplat? Maybe there should be some extra_cflags passed to gn gen --args ?
Btw, I tried to include c++shared into apk with:
externalNativeBuild {
cmake {
arguments "-DANDROID_STL=c++_shared"
}
}
But i got no success to load it.
Really appreciate your assistance in building libcrashpad_handler.so.
What I'm trying to achieve
I'm trying to generate my REST API client for Android using OpenAPI Generator from the build.gradle script. That way, I wouldn't have to run the generator command line every time the specs change. Ideally, this would be generated when I build/assemble my app, and the sources would end up in the java (generated) folder, where generated sources are then accessible from the code (this is what happens with the BuildConfig.java file for example).
What I've tried so far
Following this link from their official GitHub, here's the build.gradle file I ended up with:
apply plugin: 'com.android.application'
apply plugin: 'org.openapi.generator'
...
openApiValidate {
inputSpec = "$rootDir/app/src/main/openapi/my-api.yaml"
recommend = true
}
openApiGenerate {
generatorName = "java"
inputSpec = "$rootDir/app/src/main/openapi/my-api.yaml"
outputDir = "$buildDir/generated/openapi"
groupId = "$project.group"
id = "$project.name-openapi"
version = "$project.version"
apiPackage = "com.example.mypackage.api"
invokerPackage = "com.example.mypackage.invoker"
modelPackage = "com.example.mypackage.model"
configOptions = [
java8 : "true",
dateLibrary : "java8",
library : "retrofit2"
]
}
...
First, I've never managed to get the API generated with the build/assemble task, even when I tried adding:
compileJava.dependsOn tasks.openApiGenerate
or
assemble.dependsOn tasks.openApiGenerate
The only way I could generate the sources was by manually triggering the openApiGenerate task:
Then, when I do generate my sources this way, they end up in the build folder but aren't accessible from my code, and aren't visible in the java (generated) folder:
I then have to manually copy/paste the generated source files to my project sources in order to use the API.
Even though I'm able to work around these issues by adding manual procedures, it would be way more maintainable if the whole process was simply automatic. I was able to achieve a similar result with another tool, Protobuf. Indeed, my gradle task gets triggered every time I build the app, and the sources end up in the java (generated) folder, so I don't have to do any additional work. The task is much simpler though, so I assume the main work that I'm not able to replicate with OpenAPI Generator is handled by the Protobuf plugin itself.
You have to specify path to the generated sources as a custom source set for your Gradle module, which is app in this case, as described here – https://developer.android.com/studio/build/build-variants#configure-sourcesets. That way Gradle will treat your sources as accessible from your code.
Something like this:
android {
...
sourceSets {
main {
java.srcDirs = ['build/generated/openapi/src/main/java']
}
}
...
}
I solved the issue you described like this, I'm using gradle.kts however.
See my build.gradle.kts
plugins {
// Your other plugins
id("org.openapi.generator") version "5.3.0"
}
openApiGenerate {
generatorName.set("kotlin")
inputSpec.set("$rootDir/app/src/main/openapi/my-api.yaml")
outputDir.set("$buildDir/generated/api")
// Your other specification
}
application {
// Your other code
sourceSets {
main {
java {
// TODO: Set this path according to what was generated for you
srcDir("$buildDir/generated/api/src/main/kotlin")
}
}
}
}
tasks.compileKotlin {
dependsOn(tasks.openApiGenerate)
}
You need to build the application at least once for the IDE to detect the library (at least this is the case for me in Intellij)
Your build should automatically generate the open api classes , to refer the generated classes in your java project you should add the generated class path to your source directory like it was mentioned in the other answers
https://developer.android.com/studio/build/build-variants#configure-sourcesets
As far as the task dependency goes , in android tasks are generated after configuration thus for gradle to recognize the task , wrap it inside afterEvaluate block like
afterEvaluate {
tasks.compileDebugJavaWithJavac.dependsOn(tasks.openApiGenerate)
}
I had this issue, and this answer https://stackoverflow.com/a/55646891/14111809 led me to a more informative error:
error: incompatible types: Object cannot be converted to Annotation
#java.lang.Object()
Taking a look at the generated files that were causing this error, noticed:
import com.squareup.moshi.Json;
After including a Moshi in the app build.gradle, the build succeeded and the generated code was accessible.
implementation("com.squareup.moshi:moshi-kotlin:1.13.0")
Before, when I was using ndkBuld for building native code on Android I was able to pass an argument to make to define a number of CPU cores to be used. If I wanted to utilize 4 cores I could add something like this
externalNativeBuild {
ndkBuild {
arguments "-j4", "APP_SHORT_COMMANDS=true"
abiFilters "armeabi-v7a"
}
}
Can somebody give an advice how can I do something similar with Cmake and Ninja? Is there some equivalent parameter for cmake configuration?
externalNativeBuild {
cmake {
arguments "-DANDROID_STL=c++_static"
abiFilters getAbis()
}
}
Thanks.
controlling ninja parallelism
Ninja also support the same parameter:
$ ninja --help
usage: ninja [options] [targets...]
[...]
options:
[...]
-j N run N jobs in parallel [default=10, derived from CPUs available]
[...]
controlling ninja parallelism differentiating compile and link jobs
Now, if you want more granularity. For example, if you would like to limit the number of simultaneous link jobs, or compile jobs, or both.
Starting with CMake 3.11, it is now possible to limit the number of compile and/or link jobs.
You could then configure your project with these options:
-DCMAKE_JOB_POOL_COMPILE:STRING=compile
-DCMAKE_JOB_POOL_LINK:STRING=link
'-DCMAKE_JOB_POOLS:STRING=compile=5;link=2'
Now, if your project end up spawning other child processed that are themselves building projects using ninja, you would have to:
use the fork of ninja that include Job Server support like it is done in make. Binaries are also available in the associated GitHub releases. See https://github.com/kitware/ninja#readme
make sure sub-project are also configured with the same -DCMAKE_JOB_ options
in the context of externalNativeBuild
This means you could try something like this:
externalNativeBuild {
cmake {
arguments "-DANDROID_STL=c++_static -DCMAKE_JOB_POOL_COMPILE:STRING=compile -DCMAKE_JOB_POOL_LINK:STRING=link '-DCMAKE_JOB_POOLS:STRING=compile=5;link=2'"
abiFilters getAbis()
}
}
I was able to fix this by adding:
if (PARALLEL_COMPILE_JOBS)
set(CMAKE_JOB_POOL_COMPILE compile_job_pool${CMAKE_CURRENT_SOURCE_DIR})
string (REGEX REPLACE "[^a-zA-Z0-9]+" "_" CMAKE_JOB_POOL_COMPILE ${CMAKE_JOB_POOL_COMPILE})
set_property(GLOBAL APPEND PROPERTY JOB_POOLS ${CMAKE_JOB_POOL_COMPILE}=${PARALLEL_COMPILE_JOBS})
endif ()
if (PARALLEL_COMPILE_JOBS)
message(STATUS "${CMAKE_CURRENT_SOURCE_DIR}: Limiting compiler jobs to ${PARALLEL_COMPILE_JOBS}")
endif ()
to my base CMakeLists.txt, and then in my build.gradle I added to cmake arguments: "-DPARALLEL_COMPILE_JOBS=8" to specify max 8 parallel clang++ compile processes. This works on current Android Studio cmake (3.10) and ninja (1.8.2) versions
I created a workaround: wrap the ninja executable used by Android Studio with a script that calls ninja with all given parameter plus "-j1" at the end.
Locate the ninja executable used by Android Studio. Something like, for example, somefolder/Android/Sdk/cmake/3.10.2.4988404/bin/ninja
Rename it to something else, like ninja_orig
Create a shell script (and add execution permission to it) to replace the original ninja executable at somefolder/Android/Sdk/cmake/3.10.2.4988404/bin/ninja with the following content:
#!/bin/sh
somefolder/Android/Sdk/cmake/3.10.2.4988404/bin/ninja_orig $# -j1
Ok it seems it is a bug / missing feature in NDK. I've talked to some "NDK Googlers" and they were not able to help me either. Hopefully it will be supported in later versions of NDK / AS.
Here are the issues you can track the progress:
https://github.com/android-ndk/ndk/issues/983
and
https://issuetracker.google.com/issues/137878831
Is there a functionality inside android studio to do things like this.
Basically my gradle script reads parameter named version based on which it sets dependency version of a certain library.
So when I do gradlew -Pversion=‘1.2.3' I get this string inside gradle. But this only works if I invoke gradle from console.
Is there a way to pass parameters to gradle when started using configuration for project inside Android Studio (pressing little play triangle)?
NOTE:I did find Gradle VM options and Script prameters under default configs but adding -Pversion=‘1.2.3' there doesn't seem to have an effect.
In order to provide parameter to run option of Android Studio you should setup them under AndroidStudios Compile Preferences
AndroidStudio > Preferences...
Under Compiler: ComandLineOptions
Run > Edit Configurations..
Replace "abcdef" in Script parameters by your params.
For example let's try to pass server base endpoint while building project. First we need to define a method which gets url and sets it
def serverUrl = "https://mydefaulturl.com"
task(runProgram){
if(project.hasProperty("url")){
serverUrl = url;
}
}
In your buildTypes create your base url with this value:
debug{
buildConfigField("java.lang.String","BASE_URL","$serverUrl")
}
Now we can pass debug build an url and use it.
You can build your project from terminal with the command below:
./gradlew installDebug task runProgram '-Purl="https://yournewurl.com"'
Put version="1.2.3" in gradle.properties or under
buildscript {
ext{
version="1.2.3"
}
...
}
I have build a SDK JAR project with a Logger class which notify about system logs.
for example:
Logger.log("error on line 123 please check", Logger.SDK_DEBUG);
At the moment there are few log levels that i can use.
I would on release build to remove all log messages that are with Logger.SDK_DEBUG in my code before the JAR build proccess. is it possible doing that with Gradle?
I wrote a gradle script which handle the deletion of all Logger lines in the project. You will want to run this before any Gradle build command.
task deleteJavaDebugLogs << {
description("This function will delete all SDK DEBUG log level from the project, be careful with it!")
//Put your project full path for exmple 'src/main/java/myproject' , the path must be with quotes
FileTree javaFiles = fileTree('[your_project_path]') {
// if you have more files that are not .java include them also.
include '**/*.java'
}
String regex = "Logger.log[^,]+[^L]+(.*)Logger.SDK_DEBUG[^;];"
javaFiles.each { File javaFile ->
println "Start replacing regex on $javaFile.name"
String content = javaFile.getText()
content = content.replaceAll(regex, "")
javaFile.setText(content)
}
}
Good luck! :)
I havent tested it but from the definithion of code obfuscator, it should do this for you. Since it should find all unreachable code and remove it. If the Logger.SDK_DEBUG is final, he should know it is unreachable right?