I have some C++ source files (with .mm extension) in an XCode project.
I'm trying to compile only those that are pure C++ (no objc syntax or cocoa runtime used) and compile them in an Android NDK build (NDK r8d).
The problem seems to be that g++ will not even consider .mm files as C++ and will fail with:
arm-linux-androideabi-g++: error: Objective-C++ compiler not installed on this system
I tried:
1. LOCAL_CPP_EXTENSION := .mm (in Android.mk) - doesn't help.
2. Search g++ documentation on how to accept custom file extensions - couldn't find any.
I'd really like to find a way to force NDK/g++ to accept .mm files, but open to other ideas like:
copy & rename .mm to .cpp for the Android project - I don't like this since it complicates the build and version control, but it seems like the most basic thing that could work.
build this as a static lib (using xcode) - I tried going there, but I wasn't sure which architecture to build for, or if it even makes sense.
Others?
Does anyone have some experience or ideas on this? Thanks.
Solution (see accepted answer)
LOCAL_CFLAGS += -x c++
Add the "-x c++" option to $CFLAGS variable in .mk file. This should force GCC to use the C++ compiler.
EDIT: sorry for the typo, "-x" option, not "-c" and "c++", not "cpp"
Despite the accepted answer, I'd still say that renaming the files to .CPP would be the right thing to do. What's so controversial about making the extension match the content? Xcode would be fine with compiling C++ files, and as a bonus, it'll protect you from accidentally polluting it with Objective C++ on the iOS side.
Related
I build a C++ project depending on the Boost library using CMake (3.4.1). Host platform is Linux, targets are that host and cross-build Android NDK.
I'm only using Boost header files and I just downloaded/extracted the boost folder (and I don't have a /usr/include/boost directory).
In my CMakeLists.txt file I declare the dependency to Boost like this:
find_package(Boost 1.57 REQUIRED)
And I configure my build like this:
BOOST_ROOT=/path/to/boost cmake ../src
Which actually works as expected for my native build.
When I now configure a build exactly the same way (only specifying some more environment variables and a CMAKE_TOOLCHAIN_FILE) CMake gives me:
BOOST_ROOT=/path/to/boost JAVA_HOME=/bla/bla/bla \
ANDROID_NDK=/bla/bla/bla \
ANDROID_SDK=/bla/bla/bla \
ANT=/usr/bin/ant \
cmake ../src -DCMAKE_TOOLCHAIN_FILE=/bla/bla/android.toolchain.cmake
CMake Error at /usr/share/cmake/Modules/FindBoost.cmake:1247 (message):
Unable to find the requested Boost libraries.
Unable to find the Boost header files. Please set BOOST_ROOT to the root
directory containing Boost or BOOST_INCLUDEDIR to the directory containing
Boost's headers.
Call Stack (most recent call first):
CMakeLists.txt:4 (find_package)
So I believe I did almost the same to build for the Android target but the very same method that finds Boost for the host-build doesn't work here.
I tried to set Boost_DIR, BOOSTROOT and BOOST_INCLUDEDIR all with the same effect. Also I've deleted all content in the build directory before trying anything new.
What can be possible reasons for this behavior? I've already tried to print BOOST_ROOT directly in the FindBoost.cmake script like this:
message("BOOST_ROOT: $ENV{BOOST_ROOT}")
With the expected behavior (writing BOOST_ROOT: /path/to/boost).
Of course I can cheat now and just link the boost folder into the include folder of the cross compiler but that's not nice of course and I want to find out what's going on.
When cross-compiling, the toolchain file normally sets the variable CMAKE_FIND_ROOT_PATH. Combined with the CMAKE_FIND_ROOT_PATH_MODE_LIBRARY variable set to ONLY, CMAKE_FIND_ROOT_PATH variable is used as effective chroot for find_library calls, so only libraries under the given prefix(es) are searched.
Analogue variables exist to adjust the behavior for find_path (used for searching include paths) and find_program.
THe toolchain file you use actually sets CMAKE_FIND_ROOT_PATH at line 1521:
set( CMAKE_FIND_ROOT_PATH "${ANDROID_TOOLCHAIN_ROOT}/bin"
"${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}"
"${ANDROID_SYSROOT}"
"${CMAKE_INSTALL_PREFIX}"
"${CMAKE_INSTALL_PREFIX}/share" )
and below sets CMAKE_FIND_ROOT_PATH_MODE_* variables to ONLY. So you need to have Boost installed under one of these directories, and give hints (like BOOST_ROOT) relative to it.
Note, that Boost should be built for the target platform (Android NDK in you case), not for the platform where you cross-compile (Linux).
I'm cross-compiling a C++ library to Android. I'm using CMake as my build generator and I'm using the toolchain file provided in the NDK (called android.toolchain.cmake). Note, I'm on Windows.
I'd like to compile the android_native_app_glue.c source - also provided by the NDK - to a static library so I can later link it to my final application. After having an error, that said I'm missing the symbol ANativeActivity_onCreate, I've started investigating. ANativeActivity_onCreate is a function defined in android_native_app_glue.c, so I've looked at the compiled library using nm -o libnative_glue.a and it was quite surprising to see this:
libnative_glue.a:android_native_app_glue.c.o:0000000000000000 T ANativeActivity_onCreate
libnative_glue.a:android_native_app_glue.c.o:0000000000000000 t android_app_create
libnative_glue.a:android_native_app_glue.c.o:0000000000000000 t android_app_destroy
libnative_glue.a:android_native_app_glue.c.o:0000000000000000 t android_app_entry
libnative_glue.a:android_native_app_glue.c.o:0000000000000000 t android_app_free
...
Basically my functions are "there", but are zero-sized. I'm assuming they are thrown away at the next link, since they are not valid - looking at the next artifact with nm confirmed that.
The CMake snippet to compile the library is fairly trivial, but I'll provide it for completeness's sake:
add_library(native_glue STATIC "${CMAKE_ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c")
I have two pre-defined cache-entries for CMake, ANDROID_ABI=arm64-v8a and ANDROID_PLATFORM=24.
What could cause this invalid library compilation?
Building a NativeActivity is usually done via libnative_app_glue.a, see https://developer.android.com/ndk/samples/sample_na.
Unfortunately, the instructions there have never been updated for CMake, so it could be easier to add the android_native_app_glue.c file to your shared lib.
The linker attempts to prune any unused symbols that come from non-whole static libraries, and ANativeActivity is not used directory but rather is intended for re-export.
You can either link libnative_app_glue as a whole archive, or use -u to prevent the symbol from being dropped.
With -u:
target_link_libraries(mylib -u ANativeActivity_onCreate native_app_glue)
With whole archives:
target_link_libraries(mylib -Wl,--whole-archive native_app_glue -Wl,--no-whole-archive)
I haven't actually tested either of these with CMake. The ndk-build equivalents are known to work though.
You might also be able to use an object library, which is the CMake flavor of whole archives.
I like to have a high level understanding of how the android build system work. That is when does it complement the GNU make and the Linux build system and when and how does it differ? What I mean by this is how come sometimes we use make files to add functionality to the final image, and sometimes we use Andoroid.mk? Then again sometimes we use both. Does anyone have a good grasp of how these components work together?
For example, I used just a make file to add a simple program as a module. On the other hand, looking at the /external directory some of the modules have Android.mk file and some have a make file also. Then there is the bionic directory. Can anyone elaborate please?
# arkascha- I appreciate this but I think there is a little more to it. It seems to me that GNU make has control over the Linux kernel directories and Android.mk over the Android folders; this sounds intuitive doesn't it? I was looking for a comment that would take this further and elaborate on which files need to be updated in order to add functionality. ie. looking at my build environment I have:
0628Samsung build.sh Documentation include Makefile packages sound
abi config-backup drivers init Makefile.bak pdk system
AndroidKernel.mk COPYING drivres ipc Makefile-original Platform.tar.gz tools
arch CREDITS dtbTool Kbuild mkbootimg prebuilts usr
art crypto external Kconfig mm README vendor
bin cts files kernel modules.order REPORTING-BUGS virt
bionic dalvik firmware Kernel.tar.gz ndk samples
block developers frameworks lib net scripts
bootable development fs libcore note3 sdk
build device github-repo libnativehelper out security
build_msm8974pro_kernel.sh docs hardware MAINTAINERS output
I ask this question since there does not seem to be clear understanding of the AOSP environment. For instance, this link has a section called steps for adding a new program to the Android source tree. In it they advise updating the core/main.mk file. But my environment does not really have the lines they mention. Also sometimes one does not really have a choice of using one, make file vs. android.mk, or the other. At least that has been my experience. Maybe I missed something, but what I did was to add a sample program to the external directory. I was able to compile it with the same toolchain I used to create an image and flash my phone. But the executable did not run on my phone, which led me to believe that perhaps I needed to issue other switches and set various environment variables. So I kept trying to build the image with the program included, but the build environment did not go in that directory. After looking through other directories, I realized that most of them had an Android.mk file so I added one in, and it is chugging along right now. I'll let you know how it turns out. That is why I am asking this question. Maybe I am not looking at the right place, there is no clear stable content about how to add functionality to the final image and what are the differences between what resides in each folder. There is a high level description but no discussion on here is how you add a module to this /external, /bionic, ...and here is what the end result would be.
#Dan Albert- Thanks. I am trying to map what is in the /external directory with what is on my device in an effort to get my code into the image. I am not having much luck. I followed a set of procedures to get a simple kernel module in. But I just used a simple make file as follows:
lib_src := src
lib_headers := headers
.PHONY: all $(lib_src) $(lib_headers)
$(lib_src) :
$(MAKE) --directory=$#
$(lib_*): $(MAKE) --directory=$#
obj-$(CONFIG_TOS) += examples.o
So when you say Android just uses Android.mk, I wonder. The reason being, here I just used a make file and I was able to see the resulting code in my image. Further, I'll share another example with you. Within the Android Studio projects, in order to get some native project in, you have to create a make file as well as an Android.mk. So....? There has to be more; no? Each file does have some unique functionality within the build system; don't you agree?
Please note, I am just making this argument in an effort to get my code into the finale image.
I believe I heard what is in /external directory just goes into the /system folder of the final image. But I can not validate that. Here is what is in my external directory:
aac droiddriver hyphenation libpng nist-sip sonivox
android-clat dropbear icu4c libppp noto-fonts speex
android-mock e2fsprogs iproute2 libselinux oauth sqlite
ant-glob easymock ipsec-tools libsepol objenesis srec
antlr ebtables iptables libusb okhttp srtp
apache-harmony eclipse-basebuilder iputils libusb-compat opencv stlport
apache-http eclipse-windowbuilder jack libvorbis openfst strace
apache-qp eigen javasqlite libvpx openssh stressapptest
apache-xml elfutils javassist libxml2 openssl svox
arduino embunit jdiff libxslt open-vcdiff tagsoup
bison emma jhead libyuv oprofile tcpdump
blktrace esd jmdns linux-tools-perf pixman temp
bluetooth expat jmonkeyengine littlemock ppp timezonepicker-support
bouncycastle eyes-free jpeg llvm proguard tinyalsa
brctl fdlibm jsilver lzma protobuf tinycompress
bsdiff flac jsr305 marisa-trie qemu tinyxml
bzip2 freetype junit markdown qemu-pc-bios tinyxml2
ceres-solver fsck_msdos kernel-headers mdnsresponder regex-re2 tremolo
checkpolicy ganymed-ssh2 libcap-ng mesa3d replicaisland v8
chromium gcc-demangle libffi mksh robolectric valgrind
chromium-libpac genext2fs libgsm mockito safe-iop webkit
chromium_org giflib liblzf mockwebserver scrypt webp
chromium-trace google-diff-match-patch libmtp mp4parser sepolicy webrtc
clang grub libnfc-nci mtpd sfntly wpa_supplicant_8
compiler-rt gtest libnfc-nxp naver-fonts shahin xmlwriter
dexmaker guava libnl-headers netcat sil-fonts xmp_toolkit
dhcpcd hamcrest libogg netperf skia yaffs2
dnsmasq harfbuzz libpcap neven smack zlib
doclava harfbuzz_ng libphonenumber nist-pkits smali zxing
This is basically what I have in the external/shahin directory:
sansari#ubuntu:~/WORKING_DIRECTORY/external/shahin$ more Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= hello_world.S
LOCAL_MODULE := shahin
include $(BUILD_EXECUTABLE)
sansari#ubuntu:~/WORKING_DIRECTORY/external/shahin$ more hello_world.S
.syntax unified
.global main
main:
push {ip, lr}
ldr r0, =message
bl printf
mov r0, #0 # Return 0.
pop {ip, pc}
message:
.asciz "Hello, world.\n"
A simple assembly code and an Android.mk file. But when I issue make from the root of the project I am not sure if this is added to the final image. I don't see any object file created afterwards in this directory. Am I mistaken perhaps? My question is how do I get this into the final image?
Only Android.mk is used by the Android platform build system. There are normal makefiles in the external/ directory because those projects use make when built outside Android, and we just mirror their source. Still, we only use the Android.mk to build it for Android.
Bionic is no different than the other projects in Android, it just has somewhat more complicated Android.mk structure to deal with the complexity of CPU specific sources and various issues that come along with building low level system libraries.
Android.mk is still just make. Each include $(BUILD_*) gets handled in build/core to eventually be rewritten as a normal make rule.
I am trying to build a native daemon on Android. The purpose to to control some specific hardware, and Java applications will be able to communicate to this daemon using sockets.
I have been using cmake meanwhile to compile my libraries, demos and the real daemon (which works fine BTW). I am now trying to do 2 different things:
Build the same apps using ndk-build.
Port the C++ daemon to an Android service, by making JNI calls very similar to the way the c++ daemon works.
As far as I understand, ndk-build cannot make native applications, but only native libraries, which in turn can be loaded by the Java GUI... am I correct? For step1 I don't really need java (and I have proven it already), but I have yet found a way for ndk-build to spit an elf application.
For reference - I am using cmake, as described here: http://opekar.blogspot.com/2011/06/android-cmake-is-much-easier-in-ndk-r5b.html
This way I can have builds for "normal" linux, and also android using out of source builds. Quite nice hack if you ask me.
An alternative is to use the script make-standalone-toolchain.sh bundled with the NDK to create a stand-alone toolchain, then use it to compile your project. The shell code below illustrates how to use it:
# Assumed path to the NDK, change it to suit your environment.
NDK_HOME=$HOME/bin/android-ndk-r8e
# Desired API and NDK versions and destination folder of
# the stand-alone toolchain, change them to suit your needs.
api=14
ver=4.7
folder=$HOME/bin/android-$api-ndk-$ver
# Create folder if it doesn't already exist.
mkdir -p $folder
$NDK_HOME/build/tools/make-standalone-toolchain.sh \
--toolchain=arm-linux-androideabi-$ver \
--platform=android-$api --install-dir=$folder
Running the lines above will generate a new stand-alone toolchain at $HOME/bin/android-14-ndk-4.7, which you can then use as any regular C/C++ cross-compilation toolchain.
The advantage of working with a stand-alone toolchain is that it makes cross-compiling Linux projects to Android a breeze; see for example my port of Valgrind to Android ARMv7.
As mentioned by #Mārtiņš Možeik in one of the comments, this pice of Android.mk will work:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := my_daemon
LOCAL_C_INCLUDES := src
LOCAL_SRC_FILES := src/daemon.c
include $(BUILD_EXECUTABLE)
One thing I do notice is that the binary produced by this "makefile" is 130k, while the binary produced by cmake was ~40 kb. This is because I used -s as a C_FLAG and then gcc will strip the produced object on the fly. This can be done later on by calling $NDK/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-strip or the corresponding strip for your arch.
As I have not found documentation of this feature on the internet, some more words:
This works quite good, no problem here :)
This must be saved in a file called jni/Android.mk.
The code must be saved inside the JNI directory
If your code is outside of the jni directory this get ugly, but not impossible. You just need to prefix the code with the corresponding prefixes, don't forget to modify also the include path. This is left to the reader as an exercise.
Still unsure why the code generated from Android build system is larger then the code generated by cmake. I previously said that strip is not called - but it is called before the *.so are copied to the lib directory.
Still don't know how to package that binary into an android package, and not even how to run it (for example when the system is up) without modifying the Android code. I assume I can write a Java service that starts on boot and then execvps the daemon.
Your option 2 is the only way to do it AFAIK.
I'm trying to load a library I built with the standalone NDK toolchain.
I built libGLmove.so and placed it in libs/armeabi of my Eclipse project
However, the call to System.loadLibrary("GLmove") throws an UnsatisfiedLinkError
Any ideas as to how to resolve the problem or make Android find my library?
How does ndk-build package the library after it builds it?
Edit: The exact compile flags are:
/Users/thomas/Documents/android-ndk-r5b/toolchains/arm-eabi-4.4.0/prebuilt/darwin-x86/bin/arm-eabi-g++ --sysroot=/Users/thomas/Documents/android-ndk-r5b/platforms/android-8/arch-arm -march=armv7-a -mfloat-abi=softfp -mfpu=neon -Wl,--fix-cortex-a8 -fno-exceptions -fno-rtti -nostdlib -fpic -shared -o GLmove.so -O3
Have you checked in the resulting .APK file (use a zip utility to look at/unarchive it) to see if your library makes it through packaging? I'm a little suspicious that it might not, because I notice that everything that gets built into the "libs" folder in the project and on my build machine goes into a folder called "lib" (no 's') in the APK.
I wouldn't be too surprised if it turned out that the Eclipse build process doesn't package up any libraries it doesn't know about. This is, of course, unlike what happens with resources, which just get packaged by virtue of being in the right place.
If you find your library is not in your APK file, I don't think you can just manually put it in there, since it won't show up in the package manifest and will break any signing as well.
You don't mention whether or not your Eclipse project is an NDK project (right click on the project, Android Tools->Add Native Support.) If not, I suspect you'll need to make it into one and then add your library to the Android.mk file as a dependency and not a target.
Or: you could try putting your library into /res in the project and use System.load() instead of System.loadLibrary() to load it. I'll admit that I've never tried that myself, tho.
I was running into this same problem. The things I had wrong.
In the make file I had the "LOCAL_SRC_FILES" spelled wrong.
In the c source file I had the library name inside the method name
Java_com_my_namespace_libname_activity_methodName(JNIEnv* env, jobject _this) {
//Fancy Native Junk Here
}
Once I fixed those two things, re-ran ndk-build and refreshed the eclipse project with F5 it started to work.
You don't give very many details, but it may be that the .so you've built relies on a library that isn't available on the version of phone you're using.
I've not found any way to tell the NDK which Android SDK version you're targeting so don't have any very clear idea of how this side of it should work, but it looks like it would be easy to bring in a dependency from a newer SDK version into your .so so it won't load on all phones.
Could you please check the syntax and the location of System.loadLibrary("GLmove")
the System.loadLibrary call should be in static block of the Java source file
static {
System.loadLibrary("nativelib");
}
http://java.sun.com/developer/onlineTraining/Programming/JDCBook/jniexamp.html
If your native library needs other libraries you'll need to load them first. If that doesn't help, check to see that your project directory does not contain spaces.
Also, you may find this tutorial helpful: http://mindtherobot.com/blog/452/android-beginners-ndk-setup-step-by-step/