Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cannot locate symbol "rand" on pre-Android 5.0 devices #844

Closed
neevek opened this issue Nov 13, 2018 · 17 comments
Closed

cannot locate symbol "rand" on pre-Android 5.0 devices #844

neevek opened this issue Nov 13, 2018 · 17 comments

Comments

@neevek
Copy link

neevek commented Nov 13, 2018

  • NDK Version: r18b
  • Build system: cmake
  • Host OS: Mac
  • Compiler: Clang
  • ABI: armv7a
  • STL: c++_shared
  • NDK API level: android-21 and android-19
  • Device API level: 19

The code compiles and runs fine on Android 5.0 and above, but crashes on pre-5.0 devices, I tried 4.0.4 and 4.4, I tried setting ANDROID_PLATFORM=android-19, but it didn't work. The error message is as below:

java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "rand" referenced by "libabc.so"...
    at java.lang.Runtime.loadLibrary(Runtime.java:364)
    at java.lang.System.loadLibrary(System.java:526)
@alexcohn
Copy link

If you rebuild libabc.so passing -DANDROID_PLATFORM=android-19 to CMake, you will see that it looks for external symbol lrand48, not rand.

Probably, you did not set ANDROID_PLATFORM correctly in your build.gradle. The best way is to set minSdkVersion 19 and make delete the .extrenalNativeBuild directory (sometimes, AS forgets to rebuild everything).

You should expect to see clang++.exe --target=i686-none-linux-android19 … for compilation, and then the library will not look for rand anymore.

@neevek
Copy link
Author

neevek commented Nov 14, 2018

Hi, Alex @alexcohn
I tried the method as you suggested, but it still didn't work.

I use standalone toolchain to build libabc.so, and use it in AS with gradle/cmake. I think the problem is with the configuration of the standalone toolchain or the parameters passed to cmake when building libabc.so, but not related to the -DANDROID_PLATFORM setting in build.gradle.

I use the following command to generate the toolchain and call the cmake command:

ANDROID_TOOLCHAIN=/path/to/android_toolchain
API=19
$NDK/build/tools/make-standalone-toolchain.sh \
  --arch=arm \
  --stl=libc++ \
  --install-dir=$ANDROID_TOOLCHAIN \
  --platform=android-$API \
  --force

export CC=$ANDROID_TOOLCHAIN/bin/arm-linux-androideabi-clang
export CXX=$ANDROID_TOOLCHAIN/bin/arm-linux-androideabi-clang++
export LINK=$ANDROID_TOOLCHAIN/bin/arm-linux-androideabi-clang++
export AR=$ANDROID_TOOLCHAIN/bin/arm-linux-androideabi-ar
export RANLIB=$ANDROID_TOOLCHAIN/bin/arm-linux-androideabi-ranlib
export PLATFORM=android
export CFLAGS="-D__ANDROID_API__=$API -DANDROID_PLATFORM=android-$API"
export CPPFLAGS="-D__ANDROID_API__=$API -DANDROID_PLATFORM=android-$API"

mkdir build && cd build  
cmake \
    -DCMAKE_ANDROID_STANDALONE_TOOLCHAIN=$ANDROID_TOOLCHAIN \
    -DCMAKE_SYSTEM_NAME=Android \
    -DCMAKE_SYSTEM_VERSION=$API \
    -DCMAKE_ANDROID_ARCH_ABI=armeabi-v7a \
    -DCMAKE_ANDROID_ARCH=armv7-a \
    -DCMAKE_CROSSCOMPILING=TRUE \
    ..

@alexcohn
Copy link

alexcohn commented Nov 14, 2018

@neevek with standalone toolchain rules of the game are entirely different. You must supply the appropriate standalone toolchain up-front. It will ignore ANDROID_PLATFORM altogether, and in CFLAGS especally. -D__ANDROID_API__ may help a litlle bit, but not resolve all problems, as we witness here.

The problem is that CMake does not work well with latest NDK releases, see for example #623. NDK installs its 'private' CMake toolchain file (I am sorry about the inevitable confusion between the CMake toolchain, NDK standalone toolchain, and the Clang toolchain in NDK).

Personally, I believe that the best way is to let Android Studio build your native libraries, and tune your CMakeLists.txt to comply with the NDK way of defining the things. This path will allow easy upgrades when NDK r19, r20, and on are released.

If you cannot afford such change, then you should stay with an NDK version that is supported by 'official' CMake Cross Compiling for Android with a Standalone Toolchain. This depends on your version of CMake, and is not well documented. I believe that r15 is OK, but your mileage may vary.

Please understand that it is not impossible to tweak your build scripts so that you can use NDK r18. But this is a lot of nitpicking work which will inevitably need redoing when NDK r19 is released.

@neevek
Copy link
Author

neevek commented Nov 15, 2018

Thanks @alexcohn, it's good to know such issues with standalone toolchain. I can't afford to make big changes to the build procedure at the moment, I will just leave pre-5.0 users behind, and move all my native code to Android Studio later when I have time.

@DanAlbert
Copy link
Member

In theory the quick and dirty fix is just to pass the correct API level to make_standalone_toolchain.py. Like Alex says, your best bet is to move to externalNativeBuild (at the very least, I'd recommend moving to our toolchain file and away from a standalone toolchain), but fixing your standalone toolchain to target your minSdkVersion should keep things working in their current form until then.

What is $API set to? If that's not 21 then you're leaving a lot more than 5.0 users behind.

@neevek
Copy link
Author

neevek commented Nov 15, 2018

Hi @DanAlbert
Of course I have specified correct API level (--platform=android-19) when creating the standalone toolchain, but it still didn't work when the built library is used in Android Studio, at run time it crashes with the message ... cannot locate symbol "rand" .... This confuses me because everything referenced when building the library is from the android-19 toolchain, how come it still fails?

Yes, now I use the standalone toolchain created with --platform=android-21, it works perfectly on 5.0 and above.

@alexcohn
Copy link

@DanAlbert I am afraid it's worse than you believe.

In theory, results of make_standalone_toolchain for r18 should be as good as those for NDK r12. But you forget that this does not go to ./configure. There is CMake in the picture, and it applies its advanced logic of CMAKE_ANDROID_STANDALONE_TOOLCHAIN, which fails for NDK r18, see https://gitlab.kitware.com/cmake/cmake/issues/18469.

@DanAlbert
Copy link
Member

DanAlbert commented Nov 15, 2018

😱

Hadn't seen that bug before. Yeah, that complicates things quite a bit. Is removing your use of the standalone toolchain an option? They're unnecessary with CMake.

Any idea what version CMake is choosing to build for? If you check the ninja -v build output you can see what it's passing to clang for the triple/-D__ANDROID_API__.

@neevek
Copy link
Author

neevek commented Nov 16, 2018

@DanAlbert OK, I will try it without standalone toolchain.

ninja -v prints the following:

/Users/neevek/Library/Android/sdk/ndk-bundle/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang++
--target=armv7-none-linux-androideabi19
--gcc-toolchain=/Users/neevek/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64
--sysroot=/Users/neevek/Library/Android/sdk/ndk-bundle/sysroot
-Drproj_native_EXPORTS
-I../../../../src/main/cpp
-I../../../../src/main/cpp/r
-I../../../../src/main/cpp/ffmpeg
-I../../../../src/main/cpp/r/include
-isystem
/Users/neevek/Library/Android/sdk/ndk-bundle/sources/cxx-stl/llvm-libc++/include
-isystem
/Users/neevek/Library/Android/sdk/ndk-bundle/sources/android/support/include
-isystem
/Users/neevek/Library/Android/sdk/ndk-bundle/sources/cxx-stl/llvm-libc++abi/include
-isystem
/Users/neevek/Library/Android/sdk/ndk-bundle/sysroot/usr/include/arm-linux-androideabi
-g
-DANDROID
-ffunction-sections
-funwind-tables
-fstack-protector-strong
-no-canonical-prefixes
-march=armv7-a
-mfloat-abi=softfp
-mfpu=vfpv3-d16
-mthumb
-Wa,--noexecstack
-Wformat
-Werror=format-security
-std=c++11
-Wall
-Os
-std=c++14
-fexceptions
-DLOG_DEBUG
-DLOG_TAG_NAME='"rproj_native"'
-O0
-fno-limit-debug-info
-fPIC
-MD
-MT
CMakeFiles/rproj_native.dir/src/main/cpp/main.cc.o
-MF
CMakeFiles/rproj_native.dir/src/main/cpp/main.cc.o.d
-o
CMakeFiles/rproj_native.dir/src/main/cpp/main.cc.o
-c
/Users/neevek/workspace/android/rproject/app/src/main/cpp/main.cc

@DanAlbert
Copy link
Member

Looks like that did at least compile for 19. Check the link command just in case, but that looks right to me.

@neevek
Copy link
Author

neevek commented Nov 16, 2018

Hi @DanAlbert
I tried using the prebuilt toolchain bundled with NDK, but couldn't make it work. I pass -DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake as parameter to CMake, it seems to have found the correct compilers (variables like ANDROID_TOOLCHAIN_PREFIX and CMAKE_C_COMPILER are all set), but a subproject included with ExternalProject_Add failed to configure, in its config.log I see these errors:

checking for -Werror=unknown-warning-option... no
Failed commandline was:
--------------------------------------------------
/Users/neevek/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-gcc conftest.c  -Wall -I. -I$(SRCPATH)  -Werror=unknown-warning-option   -o conftest
/Users/neevek/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-ld: error: cannot open crtbegin_dynamic.o: No such file or directory
/Users/neevek/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-ld: error: cannot open crtend_android.o: No such file or directory
/Users/neevek/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-ld: error: cannot find -lgcc
/Users/neevek/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-ld: error: cannot find -ldl
/Users/neevek/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-ld: error: cannot find -lc
/Users/neevek/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-ld: error: cannot find -lgcc
/Users/neevek/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-ld: error: cannot find -ldl
clang: error: linker command failed with exit code 1 (use -v to see invocation)
--------------------------------------------------
Failed program was:
--------------------------------------------------
int main (void) {  return 0; }
--------------------------------------------------
x264 configure script
Command line options: "--prefix=/Users/neevek/dev/rproject/build/deps/src/libx264-build" "--cross-prefix=/Users/neevek/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-" "--enable-asm" "--disable-cli" "--disable-opencl" "--enable-static" "--enable-pic" "--host=arm-linux"

checking whether /Users/neevek/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-gcc works... no
Failed commandline was:
--------------------------------------------------
/Users/neevek/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-gcc conftest.c  -Wall -I. -I$(SRCPATH)     -lm -o conftest
/Users/neevek/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-ld: error: cannot open crtbegin_dynamic.o: No such file or directory
/Users/neevek/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-ld: error: cannot open crtend_android.o: No such file or directory
/Users/neevek/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-ld: error: cannot find -lm
/Users/neevek/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-ld: error: cannot find -lgcc
/Users/neevek/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-ld: error: cannot find -ldl
/Users/neevek/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-ld: error: cannot find -lc
/Users/neevek/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-ld: error: cannot find -lgcc
/Users/neevek/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-ld: error: cannot find -ldl
clang: error: linker command failed with exit code 1 (use -v to see invocation)
--------------------------------------------------
Failed program was:
--------------------------------------------------
int main (void) {  return 0; }
--------------------------------------------------
DIED: No working C compiler found.

The included subproject failed to find necessary libraries. With standalone toolchain, there's no such issue. The question is what configuration should I adjust to make the subproject find the libraries?

I also notice that there are no header files (no include subdirectory) in all $NDK/platforms/android-*/usr/ directories, I can see one under $NDK/sysroot/usr/. Does that mean for a specific version of NDK, the headers for all API levels (android-* platforms) are the same, but the libraries are different, that's why there exists the $NDK/platforms/ directory?

@alexcohn
Copy link

The included subproject failed to find necessary libraries.

I recommend to use standalone toolchain to build x264 and ffmpeg. Well, for the latter I know the magic enchantmnet that works with NDK r18 and does not require preparing standalone toolchain, but there is no guarantee that some other version of ffmpeg or NDK will work without modifications.

But IMO there is very little gain in calling such library build from your CMake script. I would recommend to build the ffmpage libraries (including libx264) once (for all supported ABIs, which means up to 4 sets of binaries), and use the prebuilt libraries in your project. Simpy launchin make to verify that ffmpeg build is up-to-date has been taking too long in my experience.

So, I usually prepare the standalone toolchains for the minimal API Livel supported by my app, build all third-party dependencies, like ffmpeg, and keep the binaries as large files in my git repo. Once in a while, when a new release happens to be desireable enough, I build a new set of binaries, run all compatibility tests, and when (and if) all subtle incompatibilities of the new version are resolved, push the next set of binaries to the repo.

My collegues and I use these prebuilt binaries when we compile our project (many times a day), using the integrated externalNativeBuild of Android Studio. This practice saves us a lot of time and makes on-boarding of new team members less painful.

@alexcohn
Copy link

I also notice that there are no header files (no include subdirectory) in all $NDK/platforms/android-/usr/ directories, I can see one under $NDK/sysroot/usr/. Does that mean for a specific version of NDK, the headers for all API levels (android- platforms) are the same, but the libraries are different, that's why there exists the $NDK/platforms/ directory?

Yes, that's what Unified Headers are about.

@neevek
Copy link
Author

neevek commented Nov 17, 2018

The included subproject failed to find necessary libraries.

I recommend to use standalone toolchain to build x264 and ffmpeg. Well, for the latter I know the magic enchantmnet that works with NDK r18 and does not require preparing standalone toolchain, but there is no guarantee that some other version of ffmpeg or NDK will work without modifications.

But IMO there is very little gain in calling such library build from your CMake script. I would recommend to build the ffmpage libraries (including libx264) once (for all supported ABIs, which means up to 4 sets of binaries), and use the prebuilt libraries in your project. Simpy launchin make to verify that ffmpeg build is up-to-date has been taking too long in my experience.

So, I usually prepare the standalone toolchains for the minimal API Livel supported by my app, build all third-party dependencies, like ffmpeg, and keep the binaries as large files in my git repo. Once in a while, when a new release happens to be desireable enough, I build a new set of binaries, run all compatibility tests, and when (and if) all subtle incompatibilities of the new version are resolved, push the next set of binaries to the repo.

My collegues and I use these prebuilt binaries when we compile our project (many times a day), using the integrated externalNativeBuild of Android Studio. This practice saves us a lot of time and makes on-boarding of new team members less painful.

That's what I did. I use standalone toolchain to build ffmpeg, x264 and my own library code into a single shared library, and reference it in my gradle project, but it doesn't work as expected hence this issue. I wrote a small script to check if ffmpeg and x264 are built, if the .a files exist, I will just skip running ffmpeg.cmake and x264.cmake, when I want to upgrade them to the latest, I simply remove the build directory and rebuild all of the libraries, which solves the taking-too-long problem you just mentioned.

@DanAlbert
Copy link
Member

I also notice that there are no header files (no include subdirectory) in all $NDK/platforms/android-/usr/ directories, I can see one under $NDK/sysroot/usr/. Does that mean for a specific version of NDK, the headers for all API levels (android- platforms) are the same, but the libraries are different, that's why there exists the $NDK/platforms/ directory?

Until r19, yes. In r19 everything is in sysroot.

ExternalProject_Add

This corner of CMake is open ended enough that there's no way I'm going to be able to guess at what went wrong. I'll need more details (preferably a repro case) to do anything about that.

I use standalone toolchain to build ffmpeg, x264 and my own library code into a single shared library, and reference it in my gradle project

Wait, what are you using cmake for then? Do you just want jniLibs? https://developer.android.com/studio/projects/gradle-external-native-builds#jniLibs

@neevek
Copy link
Author

neevek commented Nov 27, 2018

Until r19, yes. In r19 everything is in sysroot.

Does that mean there will be no android-platforms? everything in NDK is unified, so standalone toolchain is also unnecessary in that case?

Wait, what are you using cmake for then? Do you just want jniLibs? https://developer.android.com/studio/projects/gradle-external-native-builds#jniLibs

More than that, I usually need to write some wrapper code and JNI code around the referenced libraries, so jniLibs is not enough.

@DanAlbert
Copy link
Member

Does that mean there will be no android-platforms? everything in NDK is unified, so standalone toolchain is also unnecessary in that case?

Correct. #780

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants