android / ndk-samples

Android NDK samples with Android Studio
http://developer.android.com/ndk
Apache License 2.0
10.06k stars 4.18k forks source link

Create/port cmake samples #211

Closed ggfan closed 8 years ago

ggfan commented 8 years ago

android studio 2.2 supports cmake / ndk-build, we should add or porting existing samples. one option is to port the existing gradle samples to cmake, and put them into "master-cmake" branch. share your thought in this issue here so we could talk about it.

sugo999 commented 8 years ago

Seems like there is no way to include Application.mk in the build. How can i remove/add ABIs?

jomof commented 8 years ago

Hi Sugo999, Application.mk support is not there yet. In the meantime, you can specify abis like this: defaultConfig { cmake { abiFilters "x86", "x86_64" } }

tichang99 commented 8 years ago

What's the way to specify other variables in Application.mk such as APP_STL, APP_CPPFLAGS, APP_LDFLAGS, ...?

jomof commented 8 years ago

APP_CPPFLAGS is ndkBuild.cppFlags, APP_CFLAGS is ndkBuild.cFlags. There's no support for other flags yet. When it comes it will be something like ndkBuild.arguments = "NDK_TOOLCHAIN_VERSION:=clang"

ggfan commented 8 years ago

pushed in sample hello-jni to master-cmake branch to start the branch holder

tichang99 commented 8 years ago

@jomof Thanks. No way to specify STL in the meantime? My cocos2d-x project use gnustl_static and I can't use it now.

jomof commented 8 years ago

@tichang99: Just confirming you're using ndk-build not CMake? If ndk-build then you'll be blocked until b.android.com/210537 makes it to a 2.2 preview. I'm not sure off-hand when that will be (end of the month?)

ggfan commented 8 years ago

merged native-activity sample. with these 3 samples, the rest of the merge should be smooth now.

ggfan commented 8 years ago

with 3 simple samples in master-cmake branch, you could get a feeling about the difference between gradle and cmake ( not touching ndk-build yet); the build script syntax are quite different, specifically for native code related scripts, almost not related to each other.

we might keep them as separate branches with come maintenance overhead for C/C++ code: if there is bug in C/C++ code, need to checkin to both branches ( maybe 3 branches including ndk-build ). please kindly speak out your mind, thanks!

ian-hutchinson commented 8 years ago

@ggfan Thanks for getting the CMake samples up so quick! I was wondering if you've attempted to run an AS NDK project with more complex CMake setups (pulling in source from a variety of locations, pulling in other CMakeLists.txt files)?

I've got quite a big, native-heavy project that currently uses Eclipse/ndk-build that I've been wanting to move to AS for some time. The experimental plugin seems inadequate for current use (there are a couple of blocking bugs that prohibit moving forward with it) so I was hoping to find some luck with the externalNativeBuild additions (naturally I gravitated towards ndkBuild as a lowest effort, but b.android.com/210537 appears to be a blocker since I can't specify ABI, STL etc).

CMake would actually be a pretty good fit (the iOS and Windows flavours of this project are both CMake'd up), but I'm somewhat reluctant to spend the effort on setting up CMake for the Android code only to find that the CMake external build option might be inadequate (a la the ndkBuild option). Trying to get a feel for whether this is a well-rounded enough feature to depend on for larger projects.

As for an opinion on the branches, it makes more sense to me to keep them in separate branches (probably two in total, one for each plugin). The stable and experimental plugins seem to be pulling in different directions - if examples that swapped between the two existed in one branch it's quite easy to overlook which project is using which plugin and I reckon folk will flit between gradle.build files within the branch for reference (I know I did).

Again, thanks for the great work!

ggfan commented 8 years ago

@ian-hutchinson, thank you for your input! really!

Cmake support could not configure stl type either; very similar to ndk-build status, where both use gcc + gnustl_static. I was thinking to try complicated projects after clang and stl controls are added to the support. Jomof put some tips you could do a quick try for ndk-build: ABI: as he said in this thread [very similar to cmake syntax] ndkbuild { abiFilters "x86", "x86_64" etc } He also pointed out CppFlags and CFlags.

Maybe you give it a "quick try", and also do not be surprised if other things emerges along the way. I will personally try with other projects on cmake side[please expect some delay from my side]

jomof commented 8 years ago

@ian-hutchinson, as far as more complicated projects goes the largest public one I know of is at https://github.com/chaoren/cocos2d-x

These are early days but we're committed to CMake and ndk-build support. You can track our open issues here: https://code.google.com/p/android/issues/list?cursor=android%3A211261&q=label%3ASubcomponent-Tools-cpp&sort=-opened%20-stars&ts=1464361805&updated=211261

b.android.com/210537 is fixed in internal builds but I'm not sure right now when that will appear in a new preview.

If you take the leap and translate your large project to integrated CMake or ndk-build please let me know where the pain points are by opening bugs.

ian-hutchinson commented 8 years ago

@ggfan Thanks for the reply.

The abiFilters didn't seem to do anything as far as ndkBuild goes - I had a build failure that looked like it was the result of trying to build a mips64 flavour when specifying filters for a bunch of arm archs. I can double-check this to verify. Not sure if it's worth raising a bug or whether this might come out in the wash once Application.mk support is added (presumably in that case, the archs to build will be driven from APP_ABI).

For clarity, my build.gradle portion for that section looks like this: defaultConfig { ndkBuild { abiFilters 'armeabi-v7a', 'arm64-v8a' } }

I'll see if I can make some time to check out the CMake side of things on our end over the weekend. Fortunately, gnustl_static and gcc are cool with me for now - they're what is currently specified in my Application makefile, so might've had a bit of luck there.

I've checked out the CMake branch of the samples here. It looks to me like abiFilters are working as expected there (zipinfo'd the APK produced from a gradle assembleRelease and the lib portion contains only the three architectures specified).

This looks like it's aligned with https://code.google.com/p/android/issues/detail?id=211395 and the issue is known (abiFilters working for CMake, not for ndkBuild).

@jomof Thanks for the response

With regards to b.android.com/210537, I noticed that in your earlier comment. I tried building from source to no avail (chokes when it's looking for FormFactorApiComboBox.java - no doubt this is something I've messed up/not set correctly on my end).

I'll be sure highlight any issues I find with either build system. I did notice that (going from idea.log) it looks like the APP_PLATFORM in the ndk-build command is currently being derived from compileSdkVersion (i.e. the Android Java SDK against which to compile). As far as I'm aware, those two things are orthogonal (as in it's legit to compile against, say, Android SDK 23 and NDK platform 9, for example). Again, since this is an Application.mk-driven setting, I assumed that this would probably come out in the wash with Application.mk support but let me know if you think it's worthy enough to bug.

ggfan commented 8 years ago

you are right, abiFilter does not work for ndk-build yet. For APP_PLATFORM, with gradle build "platformVersion" is used to overwrite it, looks like it is not added for cmake /ndk-build yet. I will check and file bug if needed. thanks

ggfan commented 8 years ago

@ian-hutchinson actually use (cmake) abitfilter: defaultConfig { cmake { abiFilters "x86", "x86_64" } }

for your NDK-BUILD, that works. My mis-understanding for changing them to ndkBuild, sorry.

ian-hutchinson commented 8 years ago

@ggfan Thanks for that. Can confirm that the cmake.abiFilters setting does seems to work for ndkBuild.

Think I got a little further with this. Looks like there was something up with my project structure - looks like AS was creating it's own makefile for source in my jni directory and building out that. Moved those files to a cpp directory instead, leaving only the Android/Application.mk in the jni directory.

My Android.mk builds a static library from a bunch of files then builds the native SO linked to that static library (among others). Patched up my paths so that everything works respective to the Android Studio directory setup.

Seems to work fine when I run a command-line ndk-build (I run this from the app directory). However, when I'm running from within Android Studio it trips over when looking for C++ library headers (can't find <map> etc). Is there something that needs to be specified in order to pick these up? With the command-line ndk-build, I guess it's probably interrogating the Application.mk for a STL setting and adding relevant linker flags there. I'm not sure what should be happening in the default case (I thought it might've done this from within Android Studio for a default gnustl_static case).

On the subject of Application.mk, I downloaded 2.2 p2 yesterday to see Application.mk support made it's way back. Doesn't look like it has yet (unless I attempted to use it incorrectly - I just added an additional path to externalNativeBuild.ndkBuild pointing to my mk).

jomof commented 8 years ago

Ian, There is an older deprecated build system that attempts to pick up c++ source automatically from a */jni source folder. We're going to turn this off when externalNativeBuild is on (b.android.com/211355) and later remove it altogether (b.android.com/211356). In the meantime, only workaround is to move those sources to a different folder (like src/main/cpp).

The issue you're seeing with is indeed because Application.mk isn't picked up. It will be picked up if it exists in the same folder as Android.mk (so if you don't see this behavior I think it didn't make it into p2). In the meantime, you can also specify defaultConfig { ndkBuild { arguments="NDK_APPLICATION_MK=Application.mk" } } (if the change to add arguments support is in 2.2p2).

Hope this helps

On Sun, May 29, 2016 at 7:16 AM, Ian Hutchinson notifications@github.com wrote:

@ggfan https://github.com/ggfan Thanks for that. Can confirm that the cmake.abiFilters setting does seems to work for ndkBuild.

Think I got a little further with this. Looks like there was something up with my project structure - looks like AS was creating it's own makefile for source in my jni directory and building out that. Moved those files to a cpp directory instead, leaving only the Android/Application.mk in the jni directory.

My Android.mk builds a static library from a bunch of files then builds the native SO linked to that static library (among others). Patched up my paths so that everything works respective to the Android Studio directory setup.

Seems to work fine when I run a command-line ndk-build (I run this from the app directory). However, when I'm running from within Android Studio it trips over when looking for C++ library headers (can't find etc). Is there something that needs to be specified in order to pick these up? With the command-line ndk-build, I guess it's probably interrogating the Application.mk for a STL setting and adding relevant linker flags there. I'm not sure what should be happening in the default case (I thought it might've done this from within Android Studio for a default gnustl_static case).

On the subject of Application.mk, I downloaded 2.2 p2 yesterday to see Application.mk support made it's way back. Doesn't look like it has yet (unless I attempted to use it incorrectly - I just added an additional path to externalNativeBuild.ndkBuild pointing to my mk).

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/googlesamples/android-ndk/issues/211#issuecomment-222362885, or mute the thread https://github.com/notifications/unsubscribe/AE6z9Hp7W14NPINXKf3CyP_bXOEPN2g9ks5qGZ-wgaJpZM4Ik4hd .

ian-hutchinson commented 8 years ago

@jomof

Thanks for the clarification - had a feeling that something like that was happening with the source in the jni directory.

Thanks for the arguments tip too, though it looks like it hasn't made it's way into p2 (Gradle throws a no such property error). Looking forward to it, though, seems like a handy addition.

ggfan commented 8 years ago

@hivemind02 ok, somehow could not see this email on github anymore. could not build it, may you try to build with ndk-r12-beta2? make it buildable in your repo, I could download have a look

thanks

error I saw is: Error:error: unrecognized command line option '-fno-integrated-as'

On Wed, Jun 1, 2016 at 9:50 PM, hivemind02 notifications@github.com wrote:

I'm not sure right place for question, but I have problems with cmake multi lib project for native debugging.

My sample multi lib cmake based project that native debugging not working.

But if I changed project to no library single project, then nativie debugging works fine.

AndroidStudio version: 2.2preview2 gradle plugin version: 2.2.0-alpha2 NDK version: r10e

Thanks!

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/googlesamples/android-ndk/issues/211#issuecomment-223194742, or mute the thread https://github.com/notifications/unsubscribe/AKEzqUeuCaj_e0_02rt5C6PDaM7hLJl8ks5qHmD5gaJpZM4Ik4hd .

ggfan commented 8 years ago

just merged 3 more into master-cmake branch, now we have: hello-jni, hello-jniCallback, hello-libs --- for basic java <--> jni commucation teapot, endless-tunnel --- graphics app and a game I think they cover most of cmake technics used in the whole master branch. we could port others at any time pretty quickly.

we will move forward with 2 branches: master --> gradle-experiemental plugin master-cmake --> cmake support please add your input if we should do otherwise.

And you may also add your favorite apps here into the sample (buildable, runnable, and then pull request) :-). Thanks

lkmoe commented 8 years ago

Thanks a lot for the examples in the master-cmake branch!!

I'm able to compile and run the 'hello-libs' (master-cmake branch) example without any problems, but I cannot manage to get my own library working properly.

What I did:

  1. imported project 'hello-libs' make branch
  2. gradle sync failed -> changed buildToolsVersion to '23.0.3' (may I need gradle-experimental plugin?)
  3. create subdirectory in libsrc for 'newlib' with CMakeLists.txt and src-folder
  4. added code for 'newlib' in main CMakeLists.txt file (app/src/main/cpp)
  5. added 'newlib' to app.iml (as source folder)

My problem: /distribution/newlib/... is only created when not linked in 'target_link_libraries(hello-libs log android lib_gperf lib_gmath)' (instead of: target_link_libraries(hello-libs log android lib_gperf lib_gmath lib_newlib)) When I re-insert lib_newlib to target_link_libraries everything works fine so far and I can use my library in my project.

Did I miss any detail while adding the library for not working the correct way? Any help is appreciated!

ggfan commented 8 years ago

yeah, you never need gradle-experimental plugin anymore if you use cmake/ndkbuild support -- they are mutually exclusive ( at least for the near future we could see :-))

when I build lib, I tried to copy it out, and then remove the cmake bin directory[this works for shared lib, but gradle complains about shared lib. but it is irrelevant to your issue I believe ]. maybe those remove added some noise.

you might try this: enable lib build for only the first time; once you have libs in distribution directory, you do not need to build the lib anymore. So you could comment out the 2 add_subdirectory() statement.

then you could focus on using the lib: for static lib, gmath is the example; for shared lib, gperf is the one to refer. The difference is that shared lib will be packed into apk, so for shared lib, it has to be imported that way. for static lib, there are more ways to get work done with normal cmake scripts

hope it helps; if you still have problem, you could upload your code somewhere, I will find time to study it.

lkmoe commented 8 years ago

@ggfan Thanks for the fast reply! Where do you mean to enable/disable the lib build? Manually in the CMakeLists.txt file by commenting out?

My problem only exists when trying to build the library for the first time.

Scenario 1: distribution folder all empty; 'Rebuild project' with _target_link_libraries(hello-libs log android lib_gperf lib_gmath libnewlib) in main CMakeLists.txt -> gperf and gmath are created, newlib is not -> error [Error: '/Users/.../hello-libs/distribution/newlib/lib/x86_64/libnewlib.so', needed by '/Users/.../hello-libs/app/build/intermediates/cmake/debug/obj/x86_64/libhello-libs.so', missing and no known rule to make it]

Scenario 2: (my workaround) distribution folder empty; 'Rebuild project' with _target_link_libraries(hello-libs log android lib_gperf libgmath) AND commenting out all codelines which are referring to 'newly' -> all 3 libs (gperf, gmath, newly) are created -> changing target_link_libraries statement back to _target_link_libraries(hello-libs log android lib_gperf lib_gmath libnewlib) AND bringing back the previously out-commented lines -> Rebuild & Run Successful -> great (even in case of changes in the newlib's source code the library is getting rebuild -> works as expected)

As everything's working fine with your gpref and gmath library I thought I might have missed setting an option/reference maybe somewhere in gradle or something similar?! My weird workaround is fine enough for me atm but I was wondering how to fix it/ do it the correct way.

ggfan commented 8 years ago

the libs are copied manually with cmake steps like: add_custom_command(TARGET gmath POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy "$" "${distribution_DIR}/gmath/lib/${ANDROID_ABI}/$" COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/src/gmath.h" "${distribution_DIR}/gmath/include/gmath.h" you could see this in gmath/gperf's CMakeLists.txt; you probably have it already; this was triggered by app's CMakeList.txt add_subdirectories(), which is before add_library(); so I assume they will be executed before building app's shared lib(libhello-lib.so). there is not anything special inside gradle, the top level CMakeLists.txt is the only one connecting to CMake build system. Drop your simplified code somewhere when you get a chance, we could have a look[my code might just worked by accident]

ggfan commented 8 years ago

Well, indeed, there is a problem with hello-libs: the imported shared lib need to be explicitly packed into apk by gradle script; added a patch for it in https://github.com/googlesamples/android-ndk/pull/225

will merge it in pretty soon. Once the pull is merged, all samples are merged into master-cmake branch, we could close this discussion thread and get to normal business with 2 branches.

lkmoe commented 8 years ago

@ggfan unfortunately adding the changes in the build.gradle script (as you did in your project in ggfan/android-nkd) still doesn't fix my code.

In case you still want to have a look and should find the time - I created a repository and committed my attempt here (see readme.md for problem description).

ggfan commented 8 years ago

yes, I downloaded and looking at this: suspecting there is timing issue: cmake might spawn more process to build libs in different processes; the usage of the LIBs are REALLY not depending on the building of the LIBs: in between is the IMPORT statement; the IMPORT statement will not wait for the build to finish at all.

I am suspecting it is just luck that 2 libs are built before hello-libs using them. I was using the the sample to show how to generate a lib, and how consume a lib: generate-lib --> give to someone --> someone use it. looks like it caught up with build timing issue.

that is my suspect. your findings would align with the assumption. To get over it, do it in 2 passes similar to what you did: 1) comment out the final lib generation -- hello-libs; do not do add_library(hello-libs...). then build this will force generate all libs since they are build by add_subdirectory(), they all build independently, and should all success 2) comment lib generation ( or you could leave there, but does not matter too much ), enable hellp-libs lib to build. this time it would go through the second step of building hello-libs is using the lib ALREADY in distribution dir, NOT waiting to use newly built newlib ( it might not finish building yet when libhello-libs.so finished)

I need to add some big comments in there or break it into 2.

If you want to build a lib and only used in your app, it is much simpler: 1) throw away the distribution step (in generating libs, and using lib -- no copy, no import) 2) directly add lib name into target_link_libraries(), cmake will find them in the its build directory Teapot building native_app_glue with that.

thank you for your findings and patience. let me know too if you find I am wrong :-)

lkmoe commented 8 years ago

I will do it in two steps as you've recommend. This will work better for me anyway, cause I need to build some bigger libraries too. Thanks for time and help! (:

ggfan commented 8 years ago

all samples are merged into master-came; some doc to be updated soon. I think this bug number served its purpose, closing it and we will fix bugs in their own individual tracking numbers... Ndk release 12 is released too.

For useful variables available to cmake scrpts, refer to: ${sdk-root}/cmake/android.toolchain.cmake remember to add your complicated cmake + android projects to the branch at any time, cheers

thanks

MyJesus commented 8 years ago

may be you should update your NDK