I'm trying to get C++ code to work with react-native (see this for the general steps).
I've generated my project with react-native init, generated the JNI bindings by using Djinni. I'm now trying to build the application and test it on my android emulator (cd $PROJECT_ROOT/android && ./gradlew installDebug). It seems like the header files aren't found, their directories aren't included :
> ./gradlew installDebug
(...)
:app:compileDebugJavaWithJavac UP-TO-DATE
:app:compileDebugNdk
Warning: Deprecated NDK integration enabled by useDeprecatedNdk flag in gradle.properties will be removed from Android Gradle plugin soon.
Consider using CMake or ndk-build integration with the stable Android Gradle plugin:
https://developer.android.com/studio/projects/add-native-code.html
or use the experimental plugin:
http://tools.android.com/tech-docs/new-build-system/gradle-experimental.
In file included from $PROJECT_ROOT/android/app/src/main/jni/NativeCppBridgeText.cpp:4:
$PROJECT_ROOT/android/app/src/main/jni/NativeCppBridgeText.hpp:6:10: fatal error: 'cpp_bridge_text.hpp' file not found
#include "cpp_bridge_text.hpp"
^~~~~~~~~~~~~~~~~~~~~
1 error generated.
make: *** [$PROJECT_ROOT/android/app/build/intermediates/ndk/debug/obj/local/armeabi-v7a/objs/app/$PROJECT_ROOT/android/app/src/main/jni/NativeCppBridgeText.o] Error 1
:app:compileDebugNdk FAILED
FAILURE: Build failed with an exception.
I managed to get past this small issue by creating hard links to the headers causing issues. Which leads me to this :
> ./gradlew installDebug
(...)
:app:compileDebugJavaWithJavac UP-TO-DATE
:app:compileDebugNdk
Warning: Deprecated NDK integration enabled by useDeprecatedNdk flag in gradle.properties will be removed from Android Gradle plugin soon.
Consider using CMake or ndk-build integration with the stable Android Gradle plugin:
https://developer.android.com/studio/projects/add-native-code.html
or use the experimental plugin:
http://tools.android.com/tech-docs/new-build-system/gradle-experimental.
In file included from $PROJECT_ROOT/android/app/src/main/jni/NativeCppBridgeText.cpp:4:
In file included from $PROJECT_ROOT/android/app/src/main/jni/NativeCppBridgeText.hpp:7:
$PROJECT_ROOT/app/src/main/jni/djinni_support.hpp:20:10: fatal error: 'exception' file not found
#include <exception>
^~~~~~~~~~~
1 error generated.
make: *** [$PROJECT_ROOT/android/app/build/intermediates/ndk/debug/obj/local/armeabi-v7a/objs/app/$PROJECT_ROOT/android/app/src/main/jni/NativeCppBridgeText.o] Error 1
:app:compileDebugNdk FAILED
FAILURE: Build failed with an exception.
In this case, it seems like even standard libraries aren't included.
My question is : how do I explicitly specify gradle to add directories to its search/indlude path?
In regular Android projects, it seems that you can edit Android.mk/Application.mk files. There aren't such files in my folders ; I think that gradle actually generates an Android.mk file (in $PROJECT_ROOT/android/app/build/intermediates/ndk/debug/Android.mk), I tried editing it (LOCAL_C_INCLUDES field) to add my directories, but it gets overwritten when I try another build.
Thanks in advance.
You can edit this in $PROJECTROOT/android/app/build.gradle :
android {
defaultConfig {
(...)
ndk {
(...)
cFlags = "-Ipath/to/directory/"
}
}
}
However, you will most likely encounter other issues (I know that for a fact, because I did). I'd recommend you to use the modern and user-friendly CMake integration.
I'm gonna write down the general steps so that I can find it again sometime in the future :
Add your files to the android project (under android studio or another IDE). There should be files in your java/ folder, files in your jni/ folder (JNI bridge files), and files in your cpp/ folder (the native C++).
Add a CMakeLists.txt file to your module (usually named app if you're using react-native).
In this file, respect the following structure :
cmake_minimum_required(VERSION 3.4.1)
add_library( # Name of the library
$(YOUR_LIBRARY_NAME)
# Sets it as a shared library
SHARED
# Relative path to the source file(s)
path/to/your/file.cpp path/to/other/file.cpp )
# Allows you to add folders to the search path : similar to -Ipath/to/your/headerfolder/
include_directories(path/to/your/headerfolder/)
# Allows you to have special compilation flags for the specified library's compilation
target_compile_options( $(YOUR_LIBRARY_NAME)
PRIVATE # You can also use PUBLIC/INTERFACE
-std=gnu++11 ) # Your option ; I needed this in my case
Once it's done, you need to link gradle to your native library :
If you're using android studio, just use the information available in this guide as it's very well explained.
If you aren't, I also advise you to check out this guide, because it's really well explained.
After that, you can either build the project in android studio, or cd $(PROJECTROOT)/android && ./gradlew installDebug. It should work.
Good luck!
Related
I'm trying to start a native app project with Android Studio and CMake on Windows 10, but I'm stuck at including libpng.
For starters it's the first time I've seen a CMakeLists.txt file. It took me a day to figure out target_link_libraries(native-activity ... png) could not be target_link_libraries(png native-activity ...) since all the error messages were about files not being created and commands failing due to missing requirements from the toolchain (why were the essential errors at the end of the list? not cool!).
After finally managing to include libpng in the project I now get a build error:
Error:Execution failed for task ':app:externalNativeBuildDebug'.
...
error: unknown target CPU 'armv5te'
CMake Error at scripts/genout.cmake:78 (message):
Failed to generate
C:/APP_PATH/app/libpng-1.6.28/build/scripts/symbols.out.tf1
ninja: build stopped: subcommand failed.
I've recursively grep'ed my project, .android, .AndroidStudio2.2 directories, as well as filenames, and found absolutely nothing with armv5te except for the genout.cmake. My abiFilters line is abiFilters 'x86'.
How do I build libpng to link to my native app? Also, in Android Studio it shows the project now includes the libpng source files (with no less than 9 projects dedicated to it!). Is there any way to remove it?
Here is my CMakeLists.txt:
cmake_minimum_required(VERSION 3.4.1)
# build native_app_glue as a static lib
add_library(app-glue STATIC ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c)
set(png_src_dir ../../../../libpng-1.6.28)
set(PNG_STATIC ON)
add_subdirectory(${png_src_dir} ${png_src_dir}/build)
# now build app's shared lib
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++14")
add_library(native-activity SHARED
main.cpp logger.cpp logger.h game.cpp game.h
shaders.cpp shaders.h assets.cpp assets.h)
target_include_directories(native-activity PRIVATE ${ANDROID_NDK}/sources/android/native_app_glue
C:/devlibs/include
${png_src_dir})
# add lib dependencies
target_link_libraries(native-activity app-glue android log EGL GLESv2 png)
I've managed libpng to work with android NDK app (CMake build system instead of Android.mk) as static library. I used libpng-android repackaging. Here are things I've done:
git clone https://github.com/julienr/libpng-android.git into ${YOUR_LIBS_FOLDER} (I used ${ANDROID_NDK_ROOT_DIRECTORY}/sources/android).
Add ${ANDROID_NDK_ROOT_DIRECTORY} (home/username/Android/sdk/ndk-bundle for me) to global $PATH variable which is needed for build script).
Build lib with ndk-build (there is ./build.sh for that in directory with lib). Library will be built for different ABI targets ( arm64-v8a, armeabi, x86_64 etc).
At this point you have library headers at ${YOUR_LIBS_FOLDER}/libpng-android/jni and libpng.a at ${YOUR_LIBS_FOLDER}/libpng-android/obj/local/${ANDROID_ABI}/, where ${ANDROID_ABI} is target platform.
Finally you could include lib at CMakeLists.txt. libpng requires zlib compression library so you need to link against it aswell (zlib is provided by android studio so just add -lz flag).
Here is related piece from my CMakeLists.txt:
add_library(libpng STATIC IMPORTED)
set_target_properties(libpng PROPERTIES IMPORTED_LOCATION
${YOUR_LIBS_FOLDER}/libpng-android/obj/local/${ANDROID_ABI}/libpng.a)
add_library(appManager SHARED src/main/cpp/appManager.cpp)
target_include_directories(appManager PRIVATE ${YOUR_LIBS_FOLDER}/libpng-android/jni/)
target_link_libraries(appManager
android
libpng
z)
Few things to note there:
${ANDROID_ABI} is a variable set by Android Studio build system.
Once again: you need to link against zlib, that is why we have libpng z instead of libpng in target_link_libraries.
With Android Studio 3.6, including libpng into your project is rather easy.
Download the latest sources from sourceforge and unpack the zip file.
In Android Studio, make sure you have NDK and CMake installed (in SDK Manager)
Create a new Android Library module, call it pngAndroid (I would recommend
to set the Package Name to org.libpng.libpng, same as MacOS). Keep it Java, and choose the min SDK that fits your app.
For this module, choose File/Link C++ Project with Gradle. Find CMakleLists.txt of libpng that you downloaded as step 1.
In the pngAndroid's build.gradle, add
android.defaultConfig.externalNativeBuild.cmake.targets "png_static"
In Project Structure dialog, specify module dependency between your Module and pngAndroid.
When you build the pngAndroid Module, you will see files libpng16d.a in build/intermediates/cmake/debug/obj directory under pngAndroid.
In your Module, you also have CMakleLists.txt. In this script, you have a target, e.g.
add_library(native-library SHARED …
You should add libpng as dependency of native-library:
target_link_libraries(native-library libpng)
Elsewhere in this CMakleLists.txt you should define the imported libpng:
add_library(libpng STATIC IMPORTED)
set_target_properties(libpng PROPERTIES IMPORTED_LOCATION
../pngAndroid/build/intermediates/cmake/debug/obj/${ANDROID_ABI}/libpng16d.a)
set_target_properties(libpng PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
../../lpng1637)
set_target_properties(libpng PROPERTIES IMPORTED_LINK_INTERFACE_LIBRARIES
z)
Note that here I used relative paths a) to the pngAndroid Module that you added to your Android Studio project, and b) to the libpng sources that you downloaded. In your setup, the relative paths may be different.
For completeness, here is a cleaned-up build.gradle script for pngAndroid to build shared library libpng16d.so:
apply plugin: 'com.android.library'
android {
compileSdkVersion 29
defaultConfig {
minSdkVersion 16
targetSdkVersion 29
versionCode 1
versionName "1.0"
externalNativeBuild {
cmake {
arguments "-DSKIP_INSTALL_ALL=YES"
targets "png"
}
}
}
externalNativeBuild {
cmake {
path file('../../lpng1637/CMakeLists.txt')
}
}
}
When you build the module, you get in build/outputs an aar file that contains the jni directory with armeabi-v7a/libpng16d.so and all other ABI variants.
Last, it's worth mentioning that Google is working on an easier native package manager. Unfortunately, it's still not released.
I'm passing in preprocessor directives via CMakeLists.txt for the build of a native android library using android NDK.
add_definitions(-DMY_DIRECTIVE=1)
It would be great to double check that those preprocessor directives are actually finding their way into the calls to the compiler (llvm ?)
But the gradle build output doesn't seem to include the calls to the compiler, I just get:
Building C object CMakeFiles/my_project.dir/home/me/projects/my_proj/src/my_native.c.o
Is there a means to make the gradle output more verbose such that I can see the actual compiler calls and check those preprocessor directives are present?
The answer is to understand that Gradle utilises CMake to build the android NDK component (shared library) of an android project, and CMake utilises Ninja as a build system to handle the calls to the compiler. The compiler used by android NDK now defaults to LLVM->Clang.
So in order to actually see the Clang calls you have to find the build.ninja files for each target of your android project.
In my case I am only building for an armeabi-v7a target architecture. Therefore the relevant build.ninja files are found in:
/home/me/projects/my_proj/app/.externalNativeBuild/cmake/debug/armeabi-v7a
/home/me/projects/my_proj/app/.externalNativeBuild/cmake/release/armeabi-v7a
cd to either directory and run:
ninja -v
i.e. the -v option is the key to see all the calls to the clang compiler that the native build (android NDK) part of your android project generates.
Note if you have installed CMake via the android package manager, you may find that ninja is not installed in a location that is on your PATH. For me the ninja binary is located as follows:
~/Android/Sdk/cmake/3.6.3155560/bin/ninja
(same directory as cmake binary)
Therefore for me to see all the clang compiler calls for my android project's debug armeabi-v7a build I have to run:
cd /home/me/projects/my_proj/app/.externalNativeBuild/cmake/debug/armeabi-v7a
~/Android/Sdk/cmake/3.6.3155560/bin/ninja -v
Note if ninja tells you ninja: no work to do.
Then run:
~/Android/Sdk/cmake/3.6.3155560/bin/ninja clean
Relevant ninja documentation is -> https://ninja-build.org/manual.html#_extra_tools
I have an aosp code copy, and do a full build some days ago,
recently I sync the code to the latest, and try to modify some code in Contacts module, and try to build it with:
mmm packages/apps/Contacts
there is an error:
1 error during configuration. Try --help-properties for help.
Property 'jack.library.import' (in Options): element #1: The version of the library file 'out/target/common/obj/JAVA_LIBRARIES/android-support-test_intermediates/classes.jack' is not supported anymore. Library version: 3.4 - Current version: 3.5 - Minimum compatible version: 3.5
ninja: build stopped: subcommand failed.
build/core/ninja.mk:84: recipe for target 'ninja_wrapper' failed
make: *** [ninja_wrapper] Error 1
I search android-support-test in opengrok, and find android-support-test in prebuilts/misc/common/android-support-test
then I do:
mmm prebuilts/misc/common/android-support-test/
still error:
1 error during configuration. Try --help-properties for help.
Property 'jack.classpath': element #1: The version of the library file 'out/target/common/obj/JAVA_LIBRARIES/sdk_v23_intermediates/classes.jack' is not supported anymore. Library version: 3.4 - Current version: 3.5 - Minimum compatible version: 3.5
ninja: build stopped: subcommand failed.
build/core/ninja.mk:84: recipe for target 'ninja_wrapper' failed
make: *** [ninja_wrapper] Error 1
but I can't find sdk_23 module in opengrok.
then I delete
out/target/common/obj/JAVA_LIBRARIES/android-support-test_intermediates/classes.jack
and do
make android-support-test
It doesn't rebuild the module.
So, how can I solve the dependency when using "mmm" building a module?
Looks like Jack keeps on not liking your prebuilt material (/out dir), is it from an entire different Android version?
I would suggest to do make clean OR just delete all /out/ directory from root repo.
Then do mma Contacts from root repo directory.
For further info on mm, mmm, mma, etc. Check build/envsetup.sh:
Invoke ". build/envsetup.sh" from your shell to add the following functions to your environment:
lunch: lunch <product_name>-<build_variant>
tapas: tapas [<App1> <App2> ...] [arm|x86|mips|armv5] [eng|userdebug|user]
croot: Changes directory to the top of the tree.
m: Makes from the top of the tree.
mm: Builds all of the modules in the current directory, but not their dependencies.
mmm: Builds all of the modules in the supplied directories, but not their dependencies.
To limit the modules being built use the syntax: mmm dir/:target1,target2.
mma: Builds all of the modules in the current directory, and their dependencies.
mmma: Builds all of the modules in the supplied directories, and their dependencies.
cgrep: Greps on all local C/C++ files.
jgrep: Greps on all local Java files.
resgrep: Greps on all local res/*.xml files.
godir: Go to the directory containing a file.
I want to use dlib library in my android project which is written in c++.
I selected c++ language because it will support iOS also.
So I follow these steps:
I created android ndk project and I included that dlib library
directly in my c++ code folder.
I import .h files and I generated a app gradle file in android studio
project.
But when I am getting library .h files errors, means internal .h files getting errors.
Error:error: linker command failed with exit code 1 (use -v to see invocation)
Error:Build command failed.
Error:org.gradle.internal.UncheckedException:
I want to use andengine in my android studio project but I have ndk error while building.
Error:Execution failed for task ':andEngine:compileReleaseNdk'.
> com.android.ide.common.internal.LoggedErrorException: Failed to run command:
D:\Android\android-ndk-r9d\ndk-build.cmd NDK_PROJECT_PATH=null APP_BUILD_SCRIPT=D:\Android\workspace\simpleclock\simple_clock_as\andEngine\build\intermediates\ndk\release\Android.mk APP_PLATFORM=android-19 NDK_OUT=D:\Android\workspace\simpleclock\simple_clock_as\andEngine\build\intermediates\ndk\release\obj NDK_LIBS_OUT=D:\Android\workspace\simpleclock\simple_clock_as\andEngine\build\intermediates\ndk\release\lib APP_ABI=all
Error Code:
2
Output:
D:/Android/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/windows-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld.exe: D:\Android\workspace\simpleclock\simple_clock_as\andEngine\build\intermediates\ndk\release\obj/local/armeabi-v7a/objs/andengine_shared/D_\Android\workspace\simpleclock\simple_clock_as\andEngine\src\main\jni\src\GLES20Fix.o: in function Java_org_andengine_opengl_GLES20Fix_glVertexAttribPointer:GLES20Fix.c(.text.Java_org_andengine_opengl_GLES20Fix_glVertexAttribPointer+0x40): error: undefined reference to 'glVertexAttribPointer'
D:/Android/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/windows-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld.exe: D:\Android\workspace\simpleclock\simple_clock_as\andEngine\build\intermediates\ndk\release\obj/local/armeabi-v7a/objs/andengine_shared/D_\Android\workspace\simpleclock\simple_clock_as\andEngine\src\main\jni\src\GLES20Fix.o: in function Java_org_andengine_opengl_GLES20Fix_glDrawElements:GLES20Fix.c(.text.Java_org_andengine_opengl_GLES20Fix_glDrawElements+0x30): error: undefined reference to 'glDrawElements'
collect2: ld returned 1 exit status
make.exe: *** [D:\Android\workspace\simpleclock\simple_clock_as\andEngine\build\intermediates\ndk\release\obj/local/armeabi-v7a/libandengine_shared.so] Error 1
I suppose I'm missing some OpenGL files?
The Android Gradle plugin's NDK task does not actually use any Android.mk file that you may have provided in your jni/ folder. This was a great source of confusion for me until I figured that out.
It generates a intermediate Android.mk file during the build, based on parameters that you have set in your Gradle build script and on the content of your jni/ folder.
You can see this for yourself by inspecting the source for its NdkCompile task at https://android.googlesource.com/platform/tools/base/+/55aebda607efcc29b8d9d5e1a99d446e320ff288/build-system/gradle/src/main/groovy/com/android/build/gradle/tasks/NdkCompile.groovy.
Note the writeMakeFile(...) method on line 126.
This is why the error you are getting from the ndk-build command that runs as part of your Gradle build references the build script APP_BUILD_SCRIPT=D:\Android\workspace\simpleclock\simple_clock_as\andEngine\build\intermediates\ndk\release\Android.mk, not something like APP_BUILD_SCRIPT=D:\Android\workspace\simpleclock\simple_clock_as\andEngine\src\main\jni\Android.mk as you might expect and want it to.
There is no way of getting the Android Gradle plugin's NDK task to use your own Android.mk file (believe me if there was I would have found it!).
You have two options for getting your NDK code compiling as part of Gradle:
Figure out the correct configuration to put in your build.gradle so that the generated Android.mk file contains the required LOCAL_LDLIBS := -lGLESv2 line and any of the other lines from https://github.com/nicolasgramlich/AndEngine/blob/GLES2/jni/Android.mk that are required.
Write a custom NDK compile task that uses the AndEnginge's Android.mk file directly. I've recently had to do this myself for an NDK source set that requires more parameters than the Android Gradle plugin currently supports passing via Gradle, so it if comes to this I can provide help.
I think in this case option 1 is open and so of course the preferable solution.
Something like this added to the android defaultConfig block should work:
android {
defaultConfig {
ndk {
moduleName "myNDKModule"
stl "stlport_shared"
ldLibs "lGLESv2"
cFlags "-Werror"
}
}
}
Unfortunately I am very much not a C/native code expert (I know practically nothing) so cannot guess whether AndEngine needs LOCAL_MODULE_FILENAME and LOCAL_EXPORT_C_INCLUDES to be set to build correctly. If it does, you'll need to go with approach 2 (at least until if/when the Android Gradle NDK task supports configuring them). Though I have just checked out the AndEngine git repo and successfully run ndk-build after having removed them from its Android.mk file, which is promising.
(I found which NDK properties can be parametrised via inspection of https://android.googlesource.com/platform/tools/base/+/55aebda607efcc29b8d9d5e1a99d446e320ff288/build-system/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/NdkConfigDsl.java).
I had a similar issue, and this video https://www.youtube.com/watch?v=0-rYK2oh8oo helped me to fix the build issues. Basically, you need to download (and extract) NDK from here: http://developer.android.com/ndk/downloads/index.html and specify the NDK location in Module Settings. Also, you need to alter the andEngine's build.gradle file to include
sourceSets{
main{
jni.srcDirs = []
}
}
Android.mk actually includes the line?
https://github.com/nicolasgramlich/AndEngine/blob/GLES2/jni/Android.mk#L10
LOCAL_LDLIBS := -lGLESv2
These errors indicate it.
error: undefined reference to 'glVertexAttribPointer'
error: undefined reference to 'glDrawElements'