Closed bessermt closed 7 years ago
which branch( master or master-cmake) you are using? please also check whether you are building the 2 libs in your app ( that is: app/build.gradle). Recently they are changed to use binary directly for libs, so by default it is not built together with app. please let me know the above info.
I am on branch "master". I don't know how to check whether I am building the 2 libs as you describe. I am doing a full rebuild if that answers the question. It sounds like you are claiming it should work, but maybe I need to do some special building of the modules?
I looked at how to build modules as standalone, but I'm not sure how to our do that. I did add a #error to the code in each function I'm attempting to debug into and did a Build | Rebuild Project. The #errors did stop the compiler, so I am quite confused by your comment about "by default not built together with app". If not built, then I would expect the #error to not fail in a Rebuild Project. Can you please explain with some more detail?
yes, master should still be building the libs when app module is being built. master-cmake branch is not building anymore. build or not mainly depends the following in app/build.gradle
tasks.whenTaskAdded { task -> if (task.name.contains('compile')) { task.dependsOn ':gmath:distributeLib' task.dependsOn ':gperf:distributeLib' } }
the setting for these 2 libs are treated as external, app does not know where the symbols are actually. I just put them together and let gradle to trigger a build for lib, but app module does NOT depends on the build location of gmath and gperf; app only depends on libs in directory distribution/gmath and distribution/gperf; and those libs are copied from release build: task(distributeLib, type : Copy) { // trigger build library dependsOn assemble // <=== this one cause both debug and release to be built, but... into '../distribution/gmath/' from('src/main/jni/gmath.h') { into 'include/' } from('build/outputs/native/release/lib') { into 'lib/' //<== only the release lib is copied (and released to customers) } }
so app module will not be able to debug. If you want to really debug into a lib, it is much easier to build together as app AND make app's jni depends on lib module; that way it builds and knows where the symbols are. All samples in the repo using app-native-glue are built and used that way, and traceable: Teapot is one of them: https://github.com/googlesamples/android-ndk/blob/master/Teapot/app/build.gradle
thought I copied the debug libs, I was wrong.
This sample(hello-libs) is to show how to user 3rd party libs, not in-app libs. In lib-lib ones are in teapot/moreTeapot/native-activities .
hope this clarifies things. If you are not very deep into gradle experimental yet, maybe you could check out cmake branch (master-cmake), and it is guaranteed long time support and could only be better and better. Gradle experimental might be stale for a while before taking off big time.
Some of this makes sense, but I still have a lot of confusion. My goal is to use a 3rd party open source library "as is" but debug into it so I can learn how it works. The library is both Java and C++ NDK.
Is hello-libs a good starting point to learn how to build a 3rd party C++ library and debug into it?
How do I tell Android Studio where to find the source symbols for the library?
since you already have the source code, that matches teapot's use of app-native-glue, you could directly follow that path. it will be much smoother
in your situation, I would recommend cmake branch, teapot sample. read through the cmakelists.txt you should be fine.
Thanks for the tip. I'm still concerned this path won't be easy because I don't have much (if any) control over their test project. You can take a look at:
https://github.com/mapbox/mapbox-gl-native/tree/master/platform/android
Note they have a test app named: MapboxGLAndroidSDKTestApp and they have the library: MapboxGLAndroidSDK
I would need to debug the MapboxGLAndroidSDKTestApp and trace into MapboxGLAndroidSDK's C++ code. Still think your suggestion is a good idea for someone that knows little about Gradle and Android Studio?
I took a look at the teapot example app. Android Studio detected some problem building and then suggested a fix. I said okay, and the project doesn't load anymore. I'll rollback and say no to the fix when it asks again.
Can you clarify if I'll need to modify the library code or the app code? I'm unclear on what is the C++ library code in the teapot example. It looks more like a C++ android app to me and not a Java app calling a C++ library. I'm new so maybe I'm not reading it correctly.
I think getting the hello-libs to debug into the C++ library is a better proxy for the problem I'm solving. It looks just like the Mapbox project structure, but simpler. Mapbox is a library written in C++ and I can't debug it, exactly the same as hello-libs in Android Studio. . Can you help me figure out how to fix the hello-libs project to work with debugging? If not, how can I change teapot to be a C++ library called from a Java Android app?
Thanks.
for how to make mapbox debuggable with android studio, it might be easier for you to get in touch with that repo owner.
I could try to get hellp-libs to be debuggable from app. But it is a twist and not the very purpose of this sample.
Here it is: ` apply plugin: 'com.android.model.application'
// Root of 3rd party lib(s): location could be anywhere on the host system def lib_distribution_root = '../distribution' model {
android {
compileSdkVersion = 23
buildToolsVersion = '23.0.2'
defaultConfig {
applicationId = 'com.example.hellolibs'
minSdkVersion.apiLevel = 13
targetSdkVersion.apiLevel = 23
versionCode = 1
versionName = '1.0'
}
ndk {
platformVersion = 21
moduleName = 'hello-libs'
toolchain = 'clang'
stl = 'gnustl_static'
cppFlags.addAll(['-std=c++11',
"-I" + file("${lib_distribution_root}/gperf/include"),
"-I" + file("${lib_distribution_root}/gmath/include")])
ldLibs.addAll(['android', 'log'])
// build a default combined apk including all ABIs.
// abiFilters.addAll(['x86'])
}
sources {
main {
jni {
dependencies {
project ':gmath' linkage 'static'
// if gperf were *.a, change shared --> static
project ':gperf' linkage 'static'
}
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles.add(file('proguard-android.txt'))
}
}
}
}
dependencies { println rootProject.getName() compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:23.3.0' } `
replace your app/build.gradle, with the above content; then resync, clean project, and re-build app project set a breakpoint to gmath / gperf, or trace code into it from hello-libs.cpp.
I used ndk-r12, android studio 2.2 preview 4 ( download from canary ).
you could see that it is changed to build static libs, and dependency is "project", not lib anymore. No change on lib source code or gradle scripts; try it out.
Oops, I clicked the wrong button and closed it
Thanks @ggfan,
I have contacted the Mapbox team many times over the last year to find someone that could help me. In the end they admitted no one knew how to debug their code in Android. They debug on other platforms and hope it works on Android. When I saw hello-libs, this looked like the simplest example I could find. An added bonus was it failed to debug exactly the same as Mapbox does, so I figured if I could figure out how to change hello-libs to allow debugging, I could do the same to Mapbox's build. I only get a few moments at night to look into this stuff, so I'll get back with questions once I get a good look at what you have posted.
Thanks for all the help. Stay tuned.
I had super shallow scan of their code, felt: they build lib into AAR format, and your application will link with aar. the jni code is inside aar, so your app may not directly calling jni code inside sdk; app calls sdk's java interface, and sdk's java interface call into its own jni interface; jni interface functions are injected into java class at run time inside jni_onLoad() ( I might be wrong ). it is going to be a interesting route :-)
I tried you suggested build.gradle for the app and it lets me debug into the C++. So now all I need is to figure out what you did and why it works so I can attempt to apply it to the Mapbox Android Studio project. I'll likely have questions as I go. Thanks for the help.
sure. I might be slow for the next 3 weeks ( taking a break ), will try to keep up.
No worries @ggfan, any help you can provide is appreciated. I'll leave a trail here (unless you prefer elsewhere) of questions.
First question is:
What is the difference between these 2?: apply plugin: 'com.android.model.native' [comment] this builds a shared native lib, .so file , it needs to be tucked inside final apk apply plugin: 'com.android.model.library' [comment] this builds a java lib (.aar), it is very java oriented, and it is meant to be static. So it DOES generate a static lib for your native code, *.a, in your model.library module[grep it you will be able to find it after build your apk]. With this, I see there are 2 ways for app to use the generated static lib:
dependencies { project ':nativeactivity' linkage 'static' }
your header files will be exported, in LIBRARY module, with
exportedHeaders { srcDir "${ndkDir}/sources/android/native_app_glue" }
No need for to do anything on app side for header files anymore.I seem to get further with the library plugin over native, but by that I simply mean I'm getting an error further down the build.gradle during the sync assuming it is parsed and errors reported from top to bottom. For now I'll do my best to follow http://tools.android.com/tech-docs/new-build-system/gradle-experimental and use com.android.model.library.
I've moved forward making changes. I've had to take guesses.
For example, there was an error for android.libraryVariants.all which appeared to be solved by adding the "model" surrounding it.
model{ android.libraryVariants.all { variant -> def name = variant.buildType.name def checkstyle = project.tasks.create "checkstyle${name.capitalize()}", Checkstyle checkstyle.dependsOn variant.javaCompile checkstyle.source variant.javaCompile.source checkstyle.classpath = project.fileTree(variant.javaCompile.destinationDir) checkstyle.exclude('/BuildConfig.java') checkstyle.exclude('/R.java') checkstyle.exclude('/com/almeros/android/multitouch/') project.tasks.getByName("check").dependsOn checkstyle } }
The documentation "http://tools.android.com/tech-docs/new-build-system/gradle-experimental" isn't clear for this use case, but does state: "The DSL for modifying variants and their tasks is very, very limited right now." so I'm not confident this was the right choice.
After some more changes, the following appeared:
./mapbox-gl-native/platform/android/MapboxGLAndroidSDK/build.gradle Error:(252, 0) Could not find property 'android' on task ':MapboxGLAndroidSDK:androidJavadocs'. Open File
The build.gradle file starting on line 251 is:
task androidJavadocs(type: Javadoc) {
source = android.sourceSets.main.java.sourceFiles
classpath = files(android.bootClasspath)
}
I'm not sure the correct way to fix this. I could guess, but the more guessing I do, the less confidence I have. Do you know the correct way to fix this error?
Take a look at these instructions:
https://github.com/mapbox/mapbox-gl-native/blob/master/platform/android/DISTRIBUTE.md
This looks like the C++ code is built using a makefile. The C++ source doesn't appear to be listed in the Android Studio projects. Maybe I should avoid changing the build.gradle files entirely and figure out how to tell Android Studio how to find the source files and symbols?
Is this task simply too hard for anyone to accomplish. The Mapbox people don't know how to do it and if they can't, maybe I'm just wasting my time?
I left a question at:
Gradle project sync failed: Error:Cause: org.gradle.api.internal.ExtensibleDynamicObject
The files are also posted there. I have no idea on how to get past the error.
If I add .apiLevel to the minSdkVersion and targetSdkVersion in the library, AND put sources to sourceSets {sources.main.res.srcDirs += 'src/main/res-public'} I get a different error:
Error:(43, 1) A problem occurred configuring project ':MapboxGLAndroidSDK'.
Exception thrown while executing model rule: android { ... } @ MapboxGLAndroidSDK/build.gradle line 33, column 5 Attempt to read a write only view of model of type 'org.gradle.model.ModelMap
' given to rule 'android { ... } @ MapboxGLAndroidSDK/build.gradle line 33, column 5'
Not sure this is a better or worse error.
I applied all the changes I could think to apply but I'm still getting errors and have no idea how to fix them.
Here's the files I've changed:
https://github.com/bessermt/mapbox-gl-native/blob/master/platform/android/build.gradle
Using git diff -w to ignore whitespace will be helpful in seeing the differences since the model {} causes it too appear as if there are far more changes that actually exist.
If you can help me get past this I would very much appreciate the help.
Hi bessermt, I think you can solve the "Attempt to read a write only view of model of type" error by replacing sources.main.res.srcDirs += 'src/main/res-public' with sources.main.res.srcDirs.add('src/main/res-public')
Hi @rschiu, thanks for the suggestion. I pushed the changes, but it didn't fix the problem. Feel free to take a look at the changes I posted. I expect @ggfan to return from vacation next week. I hope he'll also have a suggestion.
Hi @ggfan,
My notes say you should be back from vacation. Can you take a look at:
https://github.com/bessermt/mapbox-gl-native
Thanks for all your help so far.
yes, will get to it with help from rschiu, I will get to it(will be slow since I am in a conference this week ).
@bessermt most of your usage is not beyond my knowledge of it. for that specific error, if I do:
sources { main { res { source { srcDir 'src/main/res-public' } } } }
, it does not complain anymore, but other complaints coming out like
No signature of method: com.android.build.gradle.managed.AndroidConfig.lintOptions()
maybe you could try out the above, see if you get to the next error?
Hi @ggfan, I used your suggestion and it appears to get past the error and as you indicated, creates a new error:
Error:(52, 1) A problem occurred configuring project ':MapboxGLAndroidSDK'.
Exception thrown while executing model rule: android { ... } @ MapboxGLAndroidSDK/build.gradle line 33, column 5 No signature of method: com.android.build.gradle.managed.AndroidConfig.compileOptions() is applicable for argument types: (build_ej6bt6za0oplgezep6o1v50v7$_run_closure5$_closure18$_closure22) values: [build_ej6bt6za0oplgezep6o1v50v7$_run_closure5$_closure18$_closure22@24458ff2]
If I compile, I get a better indication of the location of the error, which is here:
compileOptions { sourceCompatibility JavaVersion.VERSION_1_7 targetCompatibility JavaVersion.VERSION_1_7 }
I will take a look at the error in more detail this weekend, but I have no experience in this area, so any help is still appreciated.
Oh, you never need those anymore: those are java7 for old android studio, new one could take java8, just delete them. I should have said that.
got a question not related to this: is mapbox better than google maps?
also I like to recommend your to CMake, rather than gradle-experimental, may we drink tea or coffee for this to get you on CMake? gradle-experimental is on a risky path my personal feel
Hey @ggfan, Ask away. I would be happy with Google Maps if it would do what I need. My research shows that it is missing custom projection along with offline use. Mapbox almost does what I want, but it is missing custom projection for using thematic maps (my main goal). It turns out Google Maps v3 does allow custom projections, but is missing offline usage. Mapbox (claims) it has offline capabilities, although I think it is really a cache and not true offline. In the end whatever meets all my requirements is what I'll use. Since Mapbox is open source, I hope to add custom projections to their library. Happy to share the details of the project. It's a volunteer job to help some non-profits, so it's not a secret and I could use all the help I can get. :-)
I would be happy to use CMake if it gets me to debugging a new custom projection feature inside Mapbox. If you think gradle-experimental is "risky", I will look into switching.
Do you have a suggested website I can learn CMake for debugging a C++ Android library?
thank you for the explanation about Google Maps :-).
the cmake is recently added but lot of energy behinds it: 1) branch master-cmake of this repo, are the samples 2) http://tools.android.com/tech-docs/external-c-builds
[master-ndkbuild is for android studio + old-fashioned ndkbuild].
Thanks. I'll take a look at the samples soon. The page link seems a little sparse on info. I assume I should read a bit about CMake since I only have a vague idea what it is about.
I did attempt to remove the compileOptions and that did "fix" the problem, but like always it caused a new error to appear.
I'll take a look at CMake and see how it goes.
I've started to look at CMake, but I'm not sure where to start learning. I did a short tutorial on it, but there is nothing that specifically refers to Android let alone something as complex as the Mapbox. Do you have a suggestion on what I can do to learn using CMake to create Android ndk libraries? I see you have examples, but I probably need more handholding before I can even hope to tackle Mapbox.
CMake material on their website will probably not mention Android: Android Studio added cmake support into android studio. Some description about invoking CMake scripts from gradle is on tool's website. The interface is there; once get into cmake side, it is pure cmake scripts. My understanding is: CMake things need to be found at cmake website, the interface calling to cmake from build.gradle is on google website there, which maybe related to cmake cross compiling. this is very biased personal view, very personal. Hope you get mapbox through and share your experience. thanks
Cool. I'll take a look.
BTW, I'd be happy to use Google maps if I could only replace the default Mercator Projection with my own maths. The v3 api allows this, but is only in Javascript, so I assume I would need a data connection which I can't rely on having. The v2 works on Android and doesn't need the connection for the code, but the Projection class is marked "final". So close to working for me, but frustratingly just barely not there. I wish I could find out if this will ever be a feature in the near future.
On Mon, Aug 15, 2016 at 8:40 AM, Gerry notifications@github.com wrote:
CMake material on their website will probably not mention Android: Android Studio added cmake support into android studio. Some description about invoking CMake scripts from gradle is on tool's website http://tools.android.com/system/app/pages/search?scope=search-site&q=cmake. The interface is there; once get into cmake side, it is pure cmake scripts. My understanding is: CMake things need to be found at cmake website, the interface calling to cmake from build.gradle is on google website there, which maybe related to cmake cross compiling http://www.vtk.org/Wiki/CMake_Cross_Compiling. this is very biased personal view, very personal. Hope you get mapbox through and share your experience. 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/238#issuecomment-239836358, or mute the thread https://github.com/notifications/unsubscribe-auth/AA4FiEkTKaEGLsyOCprytOhB0YzxSrKhks5qgIh4gaJpZM4I-uHD .
email: bessermt@gmail.com
"лось и белка"
It probably is a bigger task for me to approach map team, to be honest...
I've been reading and playing with CMake a bit, but I can't figure out how to build the code here using it. Are there instructions on how to build the ndk examples here using CMake. I'm confident I simply don't have enough information on how to build using CMake. What folder I should be in, what the command should be. I have tried running from the folder where the CMakeLists.txt file is located, but that didn't work. Hints?
Thank you.
Oh, samples using cmake + android studio are here: https://github.com/googlesamples/android-ndk/tree/master-cmake look at the samples under teapots, it including 3 sub projects ( classic, more-teapots and 30fps ), or any other samples in that branch.
So far the calling CMake is only through Android Studio/Gradle, this is big difference from other platforms: Android studio will take in CMakeLists.txt and produce a native shared lib. If you want to know the exact syntax that Android Studio calling cmake, turn on --debug or --info. I sometimes just plant an error inside cmakelist.txt and fire up build, error window will display what the command Android Studio uses when it was calling cmake.
there is no samples on calling cmake directly from terminal/command line.
to just try build cmake on command line, I could get something with ndk-r12: ${SDK_HOME}/cmake/3.6.3133135/bin/cmake -GNinja -DCMAKE_MAKE_PROGRAM=${SDK_HOME}/cmake/3.6.3133135/bin/ninja -DCMAKE_TOOLCHAIN_FILE=${SDK_HOME}/cmake/3.6.3133135/android.toolchain.cmake -DANDROID_PLATFORM=android-24 src/main/jni/CMakeLists.txt
then call ninja to build *.so file at the SAME dir: ${SDK_HOME}/cmake/3.6.3133135/bin/ninja all
with future ndk(s), android.toolchain.cmake is in ndk, not sdk. the -DCMAKE_TOOLCHAIN_FILE has to point to that NDK version
this is pure hack: try it once and throw it away kind of thing. Let android studio handle this tedious work would be good, I think.
Related to this I'm having issue debugging. I have app & libModule. app pure pure java. libModule is java/c++ mostly c++. When I run app it always builds libModule cmake/c++ in release despite what settings I have specified in the build variants. I can't set breakpoints or anything. The workaround in experimental plugin was to do this
model {
android.sources{
main{
jniLibs{
dependencies{
project ":libModule" buildType "debug"
}
}
}
}
}
Then I could debug in experimental plugin. What is the equivalent when using android 2.2 & the new cmake build system?
I did not try it. what happen if you add this: -DCMAKE_BUILD_TYPE=Debug in defultConfig { externalNativeBuild { cmake { arguments -DCMAKE_BUILD_TYPE=Debug }}} ?
Based on my current experience. That will build in Debug, but put it in the Release folder. On Monday when I'm back at work I'll try it and see which folder it puts results in. When building from Android Studio it creates 2 folders in .externalNativeBuild
a Debug & release. Debug Folder is empty. Release folder is filled and fully compiled. What's interesting is when I do "Build APK" from the menu it fully compiles the "Debug" folder as expected, When I do "Run" or "Run & Debug" it compiles Release only.
I'll try -DCMAKE_BUILD_TYPE=Debug
and see if it makes a difference to debugging and report back next week.
Just tried it -DCMAKE_BUILD_TYPE=Debug
does not help in debugging a library project. And it still builds in the release
folder.
A hacky solution is in the main project do this:
// default config
externalNativeBuild {
cmake {
abiFilters'armeabi-v7a'
arguments "-DANDROID_PLATFORM=android-${platformVersion}",
'-DANDROID_TOOLCHAIN=clang', '-DANDROID_STL=gnustl_shared'
}
}
// in android {}
externalNativeBuild {
cmake {
path "../libModule/src/main/cpp/CMakeLists.txt"
}
}
and I can debug just fine. So far it's fine. This has the disadvantage of compiling everything twice.
thank you for reporting the issue, I will replicate the issue later in the week and go from there
Ok thanks I added this bug report as it's NDK bug not a google samples bug.
added back the link to the equivalent studio bug: https://code.google.com/p/android/issues/detail?id=222276
this coming back as: add a sample to showcase the usage
@bessermt : your cooked hello-jni ( one app, one lib ) project could be debugged with the following modifications (doc is at http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Product-flavors):
"final" version of the solution: 1) in app's build.gradle, change dependency to compile project(path: ':layerlib', configuration: 'debug') so debug lib build will be used 2) on lib's build.gradle, enable debug version lib to be built and copied (published) to apk android.publishNonDefault true
added to vulkan validation's layer build: https://github.com/googlesamples/android-vulkan-tutorials/tree/master/tutorial03_traceable_layers
works on my system, please check it out. thank you for chasing after it!
@graph, @bessermt like to let go of this one, may you kindly check it out? thanks
Hi I wanted to check out the samples fully before replying but it looks like I won't have time for a while. The core problem of the issue is in the build system which you already linked to. If the workarounds you have added work in the samples and you have tested them out then I think it's ok to close this issue. I briefly scanned the hello-libs and don't see how to apply the workaround right away to my project. But it was only a very brief scan I probably missed it. Perhaps add better comments to so it's clear. I look forward for the core of the debugging issue to be fixed.
Thank you.
Reporting back in. Looking at the Vulkan sample, and doing a quick test. It was very easy to apply the workaround and get debugging to work.
Thank you
thank you for your confirmation! please help to close this issue if it works for you ( this one is important and useful one, like to make sure you get it working) thanks
I'm not sure if this means this issue was solved. I had given up and started learning CMake to see if I can build the Mapbox code using CMake. I've made very little progress so far, so should go back to using the Gradle Experimental version?
I am running Android Studio 2.2 Preview 4 on Linux Mint 17.2 64 bit using a Nexus 5 device.
I am able to debug into
Java_com_example_hellolibs_MainActivity_stringFromJNI(JNIEnv *env, jobject thiz),
but I am unable to debug into
GMATH_EXPORT unsigned gpower(unsigned n)
GPERF_EXPORT uint64_t GetTicks(void)
The only difference I can see is that these are located in a module, but maybe there is some other problem.
How can I debug into these C++ functions?