Android : Run CMake manually via gradle - android

I am working on an android project which use C++ code.
I have added required CMake settings in build.gradle:
externalNativeBuild {
cmake {
path file('jni/CMakeLists.txt')
version '3.18.1'
}
}
But the problem is there are a lot of C++ files. Using gradle for build makes Android Studio index those files and it makes IDE very slow.
Is there a way to invoke CMake task manually outside IDE so that IDE don't index them? Actually what I want is to use a gradle task to build native code via CMake.

Related

Gradle : How to automatically install CMake

I am working on an Android native project which builds using CMake.
In my build.gradle I specify :
if(project.hasProperty("native")) {
externalNativeBuild {
cmake {
path file('jni/CMakeLists.txt')
version '3.18.1+'
}
}
}
I want to invoke externalNativeBuild task from command-line only on an automated build server.
However I am getting this error:
CMake '3.18.1' or higher was not found in SDK, PATH, or by cmake.dir property.
When I build it inside Android Studio normally, It downloads and install CMake but it is not happening from command-line.
Is there a way to do it from command-line?
Android studio will automatically create a local.properties file which contains the cmake.dir property.
When you build on the build server, it's more than likely that you your source doesn't have a local.properties file as that file is not normally checked into code repositories. You'll either need to create this file or modify the PATH environment variable to include the cmake binary. This of course presumes that you have CMake installed on the build server. You can do this manually with a .zip/.tarball or if you have access to the SDK on the build server, you can install with the build tools -> How to install Android SDK Build Tools on the command line?

Gradle fails to build a CMake project with OBJECT libraries because it expects a output file

My build.gradle file contains this to build a project with CMake:
externalNativeBuild {
cmake {
// Provides a relative path to your CMake build script.
version "3.13.0+"
path "../subproj/smcxx/CMakeLists.txt"
}
}
The CMakeList.txt defines multiple targets, but the problematic one is this:
set(SOURCES "src/lib.cc")
add_library(smcxx_obj OBJECT ${SOURCES})
An OBJECT target would not build a .so or .a file, instead, the .o files can be used in other targets.
The problem is (from my understanding) that Gradle analyzes the CMake targets and expects an output file for each target. When I compile the whole project using gradlew, I get the following error message:
> Task :app:externalNativeBuildDebug FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:externalNativeBuildDebug'.
> Expected output file at /home/cytrinox/src/androidapp/app/.cxx/cmake/debug/armeabi-v7a/smcxx_obj for target smcxx_obj but there was none
The object file lib.cc.o was successfully compiled and exists. But there is no smcxx_obj folder nor a smcxx_obj.so file (which is expected).
Is it possible to solve this error, for example by telling Gradle to skip this check for a specific CMake target?
According to the documentation:
Gradle builds all executables and shared object libraries that you define in your CMake (or ndk-build) project.
However, CMake object libraries don't seem to be supported at all, and cause the issue you are experiencing. I actually believe this is a bug: Gradle should just skip building them, as they are mostly only useful within CMake itself.
Anyhow, you can fix this by manually specifying which CMake targets you want Gradle to build (e.g. just omit object library targets and you'll be fine):
android {
...
defaultConfig {
...
externalNativeBuild {
...
cmake {
targets "target1", "target2"
}
}
}

Gradle sync fails with cmake "cause: executing external native build for cmake"

I'm trying to build my colleagues' project in Android Studio, which requires CMake SDK to build the external c/cpp files included in the project. The problem I'm running into is despite having installed the LLDB, NDK, and CMake SDK tools through SDK manager, the gradle for the module that references cmake path fails to sync. My colleagues who already have this project installed and working haven't run into this issue, so I suspect that it has to be something in my environment setting.
So far, I've tried uninstalling and reinstalling CMake SDK, refresh linked C++ projects, and removing the reference to the cmake path from the gradle file and adding the reference by right click the moduel -> Link C++ Project with Gradle, but none of these worked.
When I comment out the reference to my CMakeLists.txt in the gradle, it syncs, indicating that the problem is in regards to the reference to the CMake file. I also tried commenting out library references in my CMakeLists.txt file to see if the error is occurring due to a reference in the file, but even when I comment everything out, the gradle fails to sync.
This is what my gradle file looks like.
externalNativeBuild {
cmake {
path 'src/main/cpp/CMakeLists.txt'
}
}
When I press sync (try again) in build.gradle, the error message simply shows
SIMPLE: Error configuring
When I ignore the fact that gradle sync failed and just try to build, the error message shows as this.
Cause: executing external native build for cmake <my_project_path>\src\main\cpp\CMakeLists.txt
Edit: Added a link to the image capture of my Android Studio NDK path (C:\Users\username\AppData\Local\Android\Sdk\ndk-bundle for Windows).
NDK path Capture
In short - Maybe the problem is in the build.gradle file imported together with the project.
try editing 'build.gradle' line 9: classpath 'com.android.tools.build:gradle:3.1.1'
replace the gradle version number (in my case I replaced '3.1.1' with '3.5.0').
In more detail - I had the same issue when cloning from:
https://github.com/farzaa/DracoPortedToAndroid
I did try the above (setting the ndk path) but that wasn't the problem, since the path to the ndk lib was correct. So the most probable error-cause left was some project settings imported with the cloned project.
Try comparing the "Gradle Scripts" (In the project explorer) of the imported project with a new project built in your Android Studio environment. The new project will have the correct local settings.
In my case I replaced:
classpath 'com.android.tools.build:gradle:3.1.1'
with:
classpath 'com.android.tools.build:gradle:3.5.0'
to set the NDK path in android studio go to :
file -> project structure -> sdk location -> android ndk location -> set path for example my ndk location on mac is /Users/username/Library/Android/sdk/ndk-bundle
This could be because you have a shared library in the project which needs to be linked with the shared version of the STL. Try adding the following to your build.gradle:
android {
defaultConfig {
externalNativeBuild {
cmake {
arguments "-DANDROID_STL=c++_shared"
}
}
}
}
I had the same error message, and it turned out that I had a syntax error in my CMakeLists.txt
I have solved the problem by adding 'abiFilters' to app/build.gradle file:
defaultConfig {
externalNativeBuild {
cmake {
abiFilters 'armeabi-v7a','arm64-v8a'
}
}
}

Android gradle plugin v3.3.0 -> can't find R$raw when using proguard

Just updated to Android gradle plugin version 3.3.0
We have the following setup (not sure which are important):
Application project (app) with 3 library modules (data, domain, utils)
Databinding enabled (databinding.enabled true)
Proguard enabled(proguardFiles 'proguard-rules.pro')
When I build the app using:
./gradlew assembleDevRelease
I get the following error:
can't find referenced class my.package.data.R$raw
When I build the app using:
./gradlew :app:assembleDevRelease
The app builds fine, generates an obfuscated *.apk which I can install
Question:
What's the difference between assembleRelease and :app:assembleRelease
- Why does switching to android gradle plugin 3.3.0 affect which task I have to call to build my apk? We use assembleRelease everywhere in our CI pipelines to build our apks.
What changed in android gradle plugin 3.3.0 that caused the task assembleRelease to break? We use assembleRelease everywhere in our CI pipelines to build our apks.
Any suggestions how we can make 'assembleRelease' working again? (update Proguard config?, enabling R8?)
What's the difference between assembleRelease and :app:assembleRelease
The former runs the assembleRelease task on all modules relative to current level. The latter runs it on the app module only (and its dependencies).
Why does switching to android gradle plugin 3.3.0 affect which task I have to call to build my apk? We use assembleRelease everywhere in our CI pipelines to build our apks.
The question does not have enough info to say for sure, but there are a number of changes listed in the release notes. For example, this issue might be related to:
Faster R class generation for library projects: Previously, the Android Gradle plugin would generate an R.java file for each of your project's dependencies and then compile those R classes alongside your app's other classes. The plugin now generates a JAR containing your app's compiled R class directly, without first building intermediate R.java classes. This optimization may significantly improve build performance for projects that include many library subprojects and dependencies, and improve the indexing speed in Android Studio.

Android Studio: Add .cpp file tree without building

Is it possible to add a tree of .h/.cpp files to the Android Studio editor for reference - so that they can be edited but not actually built/compiled by Android Studio?
I have JNI/NDK files which I want to build manually from the command line but I don't want Gradle/Android Studio to build these files.
There is a Gradle 'exclude' command/function which may be what I need but I cannot get it to work.
sourceSets {
main {
exclude 'jni'
//exclude ("jni/**")
//jni.srcDirs = []
}
}
I get the following error:
Error:(10, 0) Gradle DSL method not found: 'exclude()'
I didn't manage to figure this out with a vanilla Android Studio set-up but by using the Gradle Experimental Plugin I have ended up with the desired outcome. Once I got the 0.7.0 experimental plugin working (and my build.gradle configured for the new 'model' scoping), I was able to remove the sourceSets statement, successfull sync, edit within Android Studio and build from the command line via ndk-build.

Categories

Resources