i'm trying to integrate the ndkBuild functionality into an existing android studio project, using the new android studio 2.2 , in order to enable c++ debugging etc.
i have tried out one of the ndk example projects which android studio 2.2 offers, which works perfectly fine. However, when i try to run the gradle commands in my own project, i get this error message:
Error:(73, 0) Could not find method externalNativeBuild() for arguments [build_c6heui1f67l8o1c3ifgpntw6$_run_closure2$_closure9#4329c1c9] on project ':core' of type org.gradle.api.Project.
By following this description
http://tools.android.com/tech-docs/external-c-builds
i ended up with a gradle script which includes the following commands:
externalNativeBuild{
ndkBuild{
path "$projectDir/jni/Android.mk"
}
}
externalNativeBuild {
ndkBuild {
arguments "NDK_APPLICATION_MK:=$projectDir/jni/Application.mk"
abiFilters "armeabi-v7a", "armeabi","arm64-v8a","x86"
cppFlags "-frtti -fexceptions"
}
}
Did i perhaps miss out on something here with the project setup?
I have set the Android NDK location properly under
File -> Project Structure ... -> SDK Location -> Android NDK location
in my android studio.
Anything else i might have forgotton?
Has anyone run into a similar problem before?
Advice would be much appreciated =)
Just had this error myself. In your root build.gradle, make sure that gradle is set to at least version 2.2.0:
So you should have the following in buildscript {...}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.0'
}
Suggested by Kun Ming Xies answer, I have separated my cmake part in two to get rid of the annoying error:
Could not find method arguments() for arguments [-DREVISION=1.3.1] on object of type com.android.build.gradle.internal.dsl.CmakeOptions.
The first part in defaultConfig contains the configuration (command line arguments for CMake and C++ flags), and the second contains the path to CMakeLists.txt:
def revision = "1.3.1"
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
versionCode = ...
versionName "${revision}"
externalNativeBuild {
cmake {
arguments "-DREVISION=${revision}"
cppFlags '-fexceptions', '-frtti', '-std=c++11'
}
}
}
buildTypes { }
lintOptions { }
externalNativeBuild {
cmake {
path 'CMakeLists.txt'
}
}
}
android {
defaultConfig {
externalNativeBuild {
cmake {
arguments '-DANDROID_TOOLCHAIN=clang'
}
}
}
Related
I downloaded the code from this repository (its a app to control a parrot drone):
Github
with the hopes of getting it to work so i can study the code, however im getting this error that seems hard to find a solution after searching the web, i mostly found things for IOS, xcode, etc
I imported the project into android studio, when i try to execute the app i get the following error:
Error:error: linker command failed with exit code 1 (use -v to see invocation)
I am not really into NDK, but from what i saw it could be the reason, things i tried:
Downloaded NDK and added the correct path to it.
Using latest SDK.
Changes to build.gradle like setting buildToolsVersion "25.0.0", etc
Build.gradle (Project: ardrone)
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.2'
}
}
allprojects {
repositories {
jcenter()
}
}
Build.gradle (Module:app)
import org.apache.tools.ant.taskdefs.condition.Os
apply plugin: 'com.android.application'
android {
compileSdkVersion 24
buildToolsVersion "25.0.0"
defaultConfig {
multiDexEnabled true
applicationId "com.parrot.freeflight"
minSdkVersion 9
targetSdkVersion 24
versionCode 20000
versionName "2.0-SDK"
ndk {
moduleName "adfreeflight"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
// TODO proguard-rules seem outdated and useless cause it's only Android stuff
}
}
sourceSets.main {
jni.srcDirs = [] // This prevents the auto generation of Android.mk
jniLibs.srcDir 'src/main/jniLibs'
// This is not necessary unless you have precompiled libraries in your project.
}
task buildNative(type: Exec, description: 'Compile JNI source via NDK') {
def ndkCommand = "${android.ndkDirectory}/ndk-build"
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
ndkCommand += ".cmd"
}
commandLine ndkCommand,
'-C', file('src/main/jni').absolutePath,
'-j', Runtime.runtime.availableProcessors(),
'all',
'NDK_DEBUG=1'
}
task cleanNative(type: Exec, description: 'Clean JNI object files') {
def ndkCommand = "${android.ndkDirectory}/ndk-build"
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
ndkCommand += ".cmd"
}
commandLine ndkCommand,
'-C', file('src/main/jni').absolutePath,
'clean'
}
clean.dependsOn 'cleanNative'
tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn buildNative
}
}
dependencies {
compile 'com.google.android.gms:play-services:10.0.0'
compile files('libs/android-support-v13.jar')
compile files('libs/com.sony.rdis.receiver-20111206.jar')
compile files('libs/com.sony.rdis.receiver.utility-20111206.jar')
}
local.properties
ndk.dir=C\:\\Users\\BugDroid\\AppData\\Local\\Android\\Sdk\\ndk-bundle
sdk.dir=C\:\\Users\\BugDroid\\AppData\\Local\\Android\\Sdk
You need to check your log for more details as the error 'Linker command failed with exit code 1' is usually followed by the more detailed error.
So to find more details, in Xcode click on the error under Buildtime and choose Reveal in log. This should give you extra hint. Without any specific error, it's difficult to know what's the problem.
I have an ndk project with two modules:
abwrenderer - native library module
app - native and java hybrid, glues java to the abwrenderer
I just updated to AS 2.0 Preview 5 this morning, and encountered some gradle related issues.
I upgraded to gradle-2.10 and switched to gradle-experimental:0.6.0-alpha5. When attempting to debug, an ndk build is triggered and I run into the following problem:
Error:error: C:\android\projects\foo\abwrenderer\build\intermediates\binaries\debug\obj\armeabi-v7a\libabwrenderer.so: No such file or directory
Now when I was on gradle-2.9 & gradle-experimental:0.6.0-alpha3, the libraries were built in this directory. After this morning's upgrades, the libraries are now located in:
C:\android\projects\foo\abwrenderer\build\libs\abwrenderer\shared\armeabi-v7a\debug
Is there a way to update the search location for project dependencies that build libraries?
For reference, I define the dependency on abwrenderer project as follows (build.gradle (app)):
android.sources {
main {
jni {
source {
srcDirs 'src/main/jni'
}
dependencies {
project ":abwrenderer" buildType "debug" linkage "shared"
}
}
jniLibs {
source {
srcDirs 'src/main/libs'
}
}
}
}
And build.gradle for abwrenderer project is as follows:
apply plugin: "com.android.model.native"
model {
android {
compileSdkVersion = 23
}
android.ndk {
moduleName = "abwrenderer"
cppFlags.addAll(["--std=c++11",
"-fexceptions",
"-frtti"])
ldLibs.addAll(["android", "EGL", "GLESv3", "log", "dl"])
stl = "c++_static"
debuggable = true
}
android.sources {
main {
jni {
exportedHeaders {
srcDir "src/main/jni"
}
}
}
}
}
I have invalidated caches and restarted, done a clean build, etc. Any help would be greatly appreciated!
Your defaultConfig and ndk blocks were missing some info. They should look similar to this:
defaultConfig {
applicationId = 'com.myapp.abwrenderer'
minSdkVersion.apiLevel = 13
targetSdkVersion.apiLevel = 23
versionCode = 1
versionName = '1.0'
}
ndk {
platformVersion = 21
moduleName = 'abwrenderer'
toolchain = 'clang'
stl = 'gnustl_static'
cppFlags.addAll(['-std=c++11'])
ldLibs.addAll(['android', 'EGL', 'GLESv3', 'log', 'dl'])
}
You should take a look at the following NDK sample from Google to see how they did it: hello-libs
Using the old Makefile-based Android build system it is possible to using clang to compile sources by adding
NDK_TOOLCHAIN_VERSION=clang
Is there some way to achieve the same thing using the new gradle build system?
It's not directly possible for now, but you can still use the regular Makefiles from gradle:
import org.apache.tools.ant.taskdefs.condition.Os
apply plugin: 'android'
android {
...
sourceSets.main {
jniLibs.srcDir 'src/main/libs' //set jniLibs directory to ./libs
jni.srcDirs = [] //disable automatic ndk-build call
}
// call regular ndk-build(.cmd) script from main src directory
task ndkBuild(type: Exec) {
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
commandLine 'ndk-build.cmd', '-C', file('src/main').absolutePath
} else {
commandLine 'ndk-build', '-C', file('src/main').absolutePath
}
}
tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn ndkBuild
}
}
Newer NDK revisions default to Clang. However, you can explicitly request a toolchain using the -DANDROID_TOOLCHAIN switch.
As of the Android Gradle Plugin 2.2.0 things have become much better. You can also adopt cmake. You should look over the new documentation.
android {
...
defaultConfig {
...
// This block is different from the one you use to link Gradle
// to your CMake or ndk-build script.
externalNativeBuild {
// For ndk-build, instead use ndkBuild {}
cmake {
// Passes optional arguments to CMake.
arguments "-DANDROID_TOOLCHAIN=clang"
// Sets optional flags for the C compiler.
cFlags "-D_EXAMPLE_C_FLAG1", "-D_EXAMPLE_C_FLAG2"
// Sets a flag to enable format macro constants for the C++ compiler.
cppFlags "-D__STDC_FORMAT_MACROS"
}
}
}
buildTypes {...}
productFlavors {
...
demo {
...
externalNativeBuild {
cmake {
...
// Specifies which native libraries to build and package for this
// product flavor. If you don't configure this property, Gradle
// builds and packages all shared object libraries that you define
// in your CMake or ndk-build project.
targets "native-lib-demo"
}
}
}
paid {
...
externalNativeBuild {
cmake {
...
targets "native-lib-paid"
}
}
}
}
// Use this block to link Gradle to your CMake or ndk-build script.
externalNativeBuild {
cmake {...}
// or ndkBuild {...}
}
}
I have an Android project that links together a bunch of sources into a single monolithic JNI library. I would like to split this single library out into multiple smaller libraries with some dependencies between them. How can I achieve this with the new gradle build system?
You can achieve this with the standalone android native plugin from the experimental gradle plugin family. The new plugins are based on the gradle component approach towards modeling builds. There are many advantages to using the new system.
For example:
root
+ lib -> 'com.android.model.native'
+ lub -> 'com.android.model.native'
+ aar -> 'com.android.model.library'
+ app -> 'com.android.model.application'
build.gradle
configure([project(':lib'), project(':lub'), project(':aar'), project(':app')]) {
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle-experimental:0.6.0-alpha5'
}
}
}
lib/build.gradle
apply plugin: "com.android.model.native"
model {
android {
compileSdkVersion 23
ndk {
moduleName "foo"
}
sources {
main {
jni {
exportedHeaders {
srcDir "src/main/headers"
}
}
}
}
}
lub/build.gradle
apply plugin: "com.android.model.native"
model {
android {
compileSdkVersion 23
ndk {
moduleName "bar"
}
sources {
main {
jni {
exportedHeaders {
srcDir "include"
}
}
}
}
}
aar/build.gradle
apply plugin: "com.android.model.library"
model {
android {
buildToolsVersion '23.0.2'
compileSdkVersion 23
ndk {
moduleName "aggregate-jni"
stl "stlport_shared" // using cpp?
}
sources {
main {
jni {
dependencies {
project ":lib"
project ":lub"
}
}
}
}
}
app/build.gradle
apply plugin: 'com.android.model.application'
model {
android {
buildToolsVersion '23.0.2'
compileSdkVersion 23
defaultConfig {
applicationId "com.example.app"
minSdkVersion.apiLevel 21
targetSdkVersion.apiLevel 23
versionCode 1
versionName "1.0"
}
}
}
dependencies {
compile project(':aar')
}
If linkage is dynamic (default for ndk), the aar will contain:
libfoo.so libbar.so libaggregate-jni.so libstlport.so
and your mirror java classes. You can simply
System.load("aggregate-jni");
in your java classes and referenced libraries will load too. If linkage is static, you'll end up with a single libaggregate-jni.so anyway. Note that it's bad to link a bunch of things statically against the stl as you will end up with multiple copies of the stl in your binary. This can really mess things up.
Note that the default gcc toolchain is now deprecated. It's probably best to use:
model {
android {
ndk {
toolchain 'clang'
stl 'c++_shared'
}
}
}
Finally, you absolutely don't need an aar, I simply included it for completeness. The app project can depend directly on standalone native lib projects as the application plugin fully support the ndk, too.
I have a problem with Android Studio 0.3.0 and my project folder containing a plain old java library project, two Android library projects, and three Android apps. It's all built with Gradle.
The problem is that the initial import into Android Studio works fine (using Android Studio's Import Project..., then choosing my settings.gradle file), but when I press the refresh button in the Gradle sidebar, I get the message "The modules below are not backed by Gradle anymore. Check those to be removed from the ide project too:", and then it lists ALL my modules for removal. Everything builds fine from the terminal.
Output of gradle projects is (with edited names):
------------------------------------------------------------
Root project
------------------------------------------------------------
Root project 'root'
+--- Project ':android-lib1'
+--- Project ':android-app1'
+--- Project ':android-app2'
+--- Project ':android-app3'
+--- Project ':android-lib2'
\--- Project ':java-lib'
In the root folder, I have settings.gradle:
include ':java-lib'
include ':android-lib1'
include ':android-lib2'
include ':android-app1'
include ':android-app2'
include ':android-app3'
My build.gradle in the root folder:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.6.+'
}
}
allprojects {
repositories {
mavenCentral()
ivy {
name 'repo'
artifactPattern 'http://repo.example.com:8081/artifactory/libs-release-local/[organisation]/[module]/[revision]/[type]s/[artifact].[ext]'
credentials {
username 'example'
password 'example'
}
}
}
}
task wrapper(type: Wrapper) {
gradleVersion = '1.8'
}
build.gradle for java-lib:
apply plugin: 'java'
apply plugin: 'eclipse'
compileJava.options.encoding = 'UTF-8'
group 'example'
version '0.1.0'
status 'release'
sourceCompatibility = '1.6'
targetCompatibility = '1.6'
dependencies {
compile 'com.google.protobuf:protobuf-java:2.5.0'
compile 'com.google.guava:guava:15.0'
compile 'org.slf4j:slf4j-api:1.7.5'
testCompile group: 'junit', name: 'junit', version: '4.+'
}
uploadArchives {
repositories {
add project.repositories.repo
}
}
build.gradle for the two Android libs (they are the same apart from dependencies and version numbers:
apply plugin: 'android-library'
dependencies {
compile project(':java-lib')
}
android {
compileSdkVersion 18
buildToolsVersion "18.1.1"
defaultConfig {
versionCode 1
versionName '0.1.0'
minSdkVersion 9
targetSdkVersion 18
}
}
And finally, build.gradle for the Android apps (again, almost identical):
apply plugin: 'android'
dependencies {
compile project(':android-lib1')
compile project(':android-lib2')
}
android {
compileSdkVersion 18
buildToolsVersion "18.1.1"
defaultConfig {
versionCode 1
versionName '0.1.0'
}
signingConfigs {
release
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
}
if (project.hasProperty('storeFile')) {
android.signingConfigs.release.storeFile = file(storeFile)
}
if (project.hasProperty('storePassword')) {
android.signingConfigs.release.storePassword = storePassword
}
if (project.hasProperty('keyAlias')) {
android.signingConfigs.release.keyAlias = keyAlias
}
if (project.hasProperty('keyPassword')) {
android.signingConfigs.release.keyPassword = keyPassword
}
Perhaps it's a bug in Android Studio 0.3.0? I didn't experience it in earlier versions, but I want to make sure it's not just something in my build files.
Thanks a bunch for reading!
This was a bug which has now been fixed (working for me since Android Studio 0.3.5): https://code.google.com/p/android/issues/detail?id=61453
Also got this or very similar error (don't know if I did refresh) I see you posted bug at code.google.com and agree it must be their bug. My work around fix was just to cancel out of "not backed by Gradle" message and then I ran gradle build from command line. Then everything worked.