I was getting 'Unable to detect application ABI's' when trying to natively debug in Eclipse. I didn't get anywhere so I tried ndk-gdb (ndk-gdb.py as I am on Windows).
But using ndk-gdb gives me :
ERROR: The device does not support the application's targetted CPU ABIs!
Device supports: armeabi-v7a armeabi
Package supports: .
This happens because the ndk-gdb.py function :
def get_build_var(var):
global GNUMAKE_CMD, GNUMAKE_FLAGS, NDK, PROJECT
text = subprocess.check_output([GNUMAKE_CMD,
'--no-print-dir',
'-f',
NDK+'/build/core/build-local.mk',
'-C',
PROJECT,
'DUMP_'+var] + GNUMAKE_FLAGS
)
# replace('\r', '') due to Windows crlf (\r\n)
# ...universal_newlines=True causes bytes to be returned
# rather than a str
return text.decode('ascii').replace('\r', '').splitlines()[0]
returns a '.' when asked for APP_ABI. I have dummped the subprocess make call parameters and when I execute the make call from the command line I get the correct response of 'armeabi-v7a armeabi'
I don't think this is to do with python as the error is so similar to my Eclipse only problem.
Try to run ndk-build DUMP_APP_ABI and make sure the output is clean. Check you Application.mk for weird encoding and/or CRLFs.
All use of $(info …) or $(__ndk_info), etc. should be disabled for this target.
Related
I have been trying to build a c++ library for android using cmake cross compilation.
The library itself is a trivial test I made purely for testing the androind build process.
I have been using the cmake gui (v 3.25.0) on a windows machine.
I use a visual studio 2019 generator in cmake and specify a toolchain file.
Unfortunately, I seem to get the same error whatever I try. I tried searching for similar problems and trouble shooting, but have so far been unable to make any progress. If anyone with more experience could lend a hand, I would be very grateful!
I have attempted setting many different variables in the toolchain file in an attempt to resolve the problem, but the basic version of what I am working with is:
set(CMAKE_SYSTEM_NAME Android)
set(CMAKE_ANDROID_ARCH_ABI armeabi-v7a)
set(CMAKE_ANDROID_NDK C:/Microsoft/AndroidNDK64/android-ndk-r16b/)
The error I run into happens whenever I configure cmake. The outut I get from cmake looks something like this:
Android: Targeting API '27' with architecture 'arm', ABI 'armeabi-v7a', and processor 'armv7-a'
Android: Selected Clang toolchain 'arm-linux-androideabi-clang' with GCC toolchain 'arm-linux-androideabi-4.9'
The C compiler identification is Clang 5.0.300080
The CXX compiler identification is Clang 5.0.300080
Detecting C compiler ABI info
Detecting C compiler ABI info - failed
Check for working C compiler: C:/Microsoft/AndroidNDK64/android-ndk-r16b//toolchains/llvm/prebuilt/windows-x86_64/bin/clang.exe
Check for working C compiler: C:/Microsoft/AndroidNDK64/android-ndk-r16b//toolchains/llvm/prebuilt/windows-x86_64/bin/clang.exe - broken
CMake Error at C:/Program Files/CMake/share/cmake-3.25/Modules/CMakeTestCCompiler.cmake:70 (message):
The C compiler
"C:/Microsoft/AndroidNDK64/android-ndk-r16b//toolchains/llvm/prebuilt/windows-x86_64/bin/clang.exe"
is not able to compile a simple test program.
It fails with the following output:
Change Dir: C:/Users/username/Documents/Code Projects/Android Test/build/CMakeFiles/CMakeScratch/TryCompile-zqgcqm
Run Build Command(s):C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/MSBuild/Current/Bin/MSBuild.exe cmTC_b0f1d.vcxproj /p:Configuration=Debug /p:Platform=x64 /p:VisualStudioVersion=16.0 /v:m && Microsoft (R) Build Engine version 16.11.2+f32259642 for .NET Framework
Copyright (C) Microsoft Corporation. All rights reserved.
ANDROID_HOME=C:\\Microsoft\AndroidSDK\25
ANT_HOME=C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Apps\apache-ant-1.9.3
JAVA_HOME=C:\Program Files\Eclipse Foundation\jdk-8.0.302.8-hotspot
NDK_ROOT=C:\\Microsoft\AndroidNDK64\android-ndk-r16b
testCCompiler.c
clang.exe : warning : argument unused during compilation: '-mthumb' [-Wunused-command-line-argument] [C:\Users\username\Documents\Code Projects\Android Test\build\CMakeFiles\CMakeScratch\TryCompile-zqgcqm\cmTC_b0f1d.vcxproj]
clang.exe : warning : argument unused during compilation: '-mfpu=vfpv3-d16' [-Wunused-command-line-argument] [C:\Users\username\Documents\Code Projects\Android Test\build\CMakeFiles\CMakeScratch\TryCompile-zqgcqm\cmTC_b0f1d.vcxproj]
clang.exe : warning : argument unused during compilation: '-mfloat-abi=softfp' [-Wunused-command-line-argument] [C:\Users\username\Documents\Code Projects\Android Test\build\CMakeFiles\CMakeScratch\TryCompile-zqgcqm\cmTC_b0f1d.vcxproj]
CLANGCOMPILE : error : unknown target CPU 'armv7-a' [C:\Users\username\Documents\Code Projects\Android Test\build\CMakeFiles\CMakeScratch\TryCompile-zqgcqm\cmTC_b0f1d.vcxproj]
CMake will not be able to correctly generate this project.
Call Stack (most recent call first):
CMakeLists.txt:4 (project)
Configuring incomplete, errors occurred!
I initially used used the NDK version found in the android tools for visual studio found at: "C:/Microsoft/AndroidNDK64/android-ndk-r16b/"
as an NDK version.
I have also tried directly downloading the latest version of the NDK and pointing to that with CMAKE_ANDROID_NDK in the toolchain file, though this did not seem to make any change.
I have tried directly using the toolchain.cmake files found at "NDK/build/cmake/android.toolchain.cmake"
for both the NDK versions described above. This too gave the same error.
Any ideas what could be causing this or how to fix?
Ok, so I was misunderstanding a few things about cross-compiling to android.
First, if I want to be able to use the static library (e.g in android studio), I will need to generate and build a solution for more than one android ABI.
The ABI's to build for are: armeabi-v7a, arm64-v8a, x86_64, x86. I then need to check for each android ABI in the CMakeLists.txt file of Android studio (e.g. elseif(ANDROID_ABI STREQUAL arm64-v8a)) and swap out the location of the library to import to the build folder of that particular ABI.
As far as I am aware, it is unfortunately not possible to generate for all these ABI's as seperate platforms within the same visual studio solution. Given that, cmake must be run 4 seperate times to different build folders, each time targeting a different ABI and generator platform. To save the hassle of doing this manually, creating a batch (.bat) script to automate the process seems the best way to go. This will involve using cmake from the command line instead of the GUI version. The script can also be made to build the generated projects to save opening each one in visual studio and building there.
The batch script I have made to generate and build cross-compilation projects for android is as follows:
#echo OFF
set BUILD_DIR=build
set ANDROID_NDK=C:\Microsoft\AndroidNDK\android-ndk-r23c
set GENERATOR="Visual Studio 17 2022"
set CMAKE_GENERATOR=-G %GENERATOR%
set CMAKE_TOOLCHAIN_FILE=-DCMAKE_TOOLCHAIN_FILE=%ANDROID_NDK%\build\cmake\android.toolchain.cmake
set CMAKE_SYSTEM_NAME=-DCMAKE_SYSTEM_NAME=Android
set EXTRA_CMAKE_ARGS=-DBUILD_SHARED_LIBS=true -DANDROID_TOOLCHAIN=clang -DANDROID_STL=c++_static
CALL :build_android armeabi-v7a ARM 16
CALL :build_android arm64-v8a ARM64 21
CALL :build_android x86_64 x64 21
CALL :build_android x86 x86 16
EXIT /B %ERRORLEVEL%
:build_android
set ABI_VERSION=%~1
set GENERATOR_PLATFORM=%~2
set MINIMUM_API_LEVEL=%~3
set CMAKE_ANDROID_ARCH_ABI=-DANDROID_ABI=%ABI_VERSION%
set ABI_BUILD_DIR=%BUILD_DIR%\%ABI_VERSION%
set CMAKE_GENERATOR_PLATFORM=-A %GENERATOR_PLATFORM%
set CMAKE_BUILD_DIR=-B %ABI_BUILD_DIR%
set CMAKE_MIN_API=-DANDROID_PLATFORM=android-%MINIMUM_API_LEVEL%
set CMAKE_ARGS=%CMAKE_BUILD_DIR% %CMAKE_ANDROID_ARCH_ABI% %CMAKE_GENERATOR% %CMAKE_GENERATOR_PLATFORM% %CMAKE_SYSTEM_NAME% %CMAKE_TOOLCHAIN_FILE% %CMAKE_MIN_API%
echo building for android ABI: %ABI_VERSION%
echo cmake arguments = %CMAKE_ARGS%
echo:
cmake %CMAKE_ARGS% %EXTRA_CMAKE_ARGS%
echo:
cmake --build %ABI_BUILD_DIR% --target ALL_BUILD
echo:
echo:
EXIT /B 0
This worked for my simple test library, but I guess depending on the project the arguments to the cmake commands may need to be tweaked.
I've been trying to get a Go application running on Android 10 and hit a snag. I'm pretty sure I now know why I'm hitting this snag, but not sure how to fix it. First, simple things work with cross compilation. For example,
package main
import "fmt"
func main() {
fmt.Println("Hello, Android!")
}
will run just fine compiled with GOARM=arm64 GOOS=linux go build
But now if I add some networking code:
package main
import (
"fmt"
"net/http"
"io/ioutil"
)
func main() {
fmt.Println("Hello, Android!")
client := &http.Client{}
resp, err := client.Get("https://www.google.com")
if err != nil {
fmt.Println(err)
return
}
bodyBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%s", bodyBytes)
}
And compile the same way it will run, but I'll get an error like:
Get "https://www.google.com": dial tcp: lookup www.google.com on [::1]:53: read udp [::1]:47618->[::1]:53: read: connection refused
Initially I thought this was some networking config on my Android device, but after lots of messing around I'm pretty sure it has to do with the fact that Android networking is "different". Maybe this is a bionic vs libc thing (?) but at least one other person seems to have hit the same snag and solved by building using the toolchain that comes with the NDK.
Does anyone know how to actually get this to work though?
Initially I was hoping it was as easy as GOOS=android GOARCH=arm64 go build but that fails with:
# command-line-arguments
/usr/lib/golang/pkg/tool/linux_amd64/link: running gcc failed: exit status 1
/usr/bin/ld: /tmp/go-link-384615804/go.o: Relocations in generic ELF (EM: 183)
<bunch of these>
/usr/bin/ld: /tmp/go-link-384615804/go.o: error adding symbols: file in wrong format
collect2: error: ld returned 1 exit status
Some Googling turned up https://github.com/golang/go/issues/30216 - which says you need to explicitly enable CGO. But GOARCH=arm64 GOOS=android CGO_ENABLED=1 go build still fails, this time with:
# runtime/cgo
gcc_android.c:6:10: fatal error: android/log.h: No such file or directory
6 | #include <android/log.h>
| ^~~~~~~~~~~~~~~
compilation terminated.
I messed around with a lot of other combinations and the closest I got was pointing Go to compilers in my NDK installation. Basically something like GOARCH=arm64 GOOS=android CC=$NDKROOT/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gcc CGO_ENABLED=1 CGO_CFLAGS="--sysroot $NDKROOT/sysroot -I$NDKROOT/sysroot/usr/include/arm-linux-androideabi/" go build. But this failed with:
# runtime/cgo
In file included from _cgo_export.c:4:0:
cgo-gcc-export-header-prolog:25:14: error: size of array '_check_for_64_bit_pointer_matching_GoInt' is negative
There's something broken in the way I'm pointing to the compiler - for example I won't find any header files (stdlib.h) without specifying sysroot, and even then it won't find the architecture specific includes (asm/types.h) without specifying the additional include path. So the error is probably a mismatch between architecture and compiler I'm just not sure where or how to fix it.
If you've read all this, thanks! Some additional info:
go version: 1.14.13 linux/amd64
NDK version: r16b
I've also looked at things like gomobile but that seems more geared towards building Android applications (like apks) although maybe I'm missing something here.
Figured it out! Well, got my specific example working but I'm not really sure why this works. The answer came basically from https://github.com/golang/go/issues/20755 and you have to:
Build a standalone version of the NDK (the comment in the Python script that does this says it packages it in a more convenient way for other tools to use)
Rebuild Go's standard library using the cross compiler in your NDK
Build your application using the NDK cross compiler.
So for my example:
$ $(NDKROOT)/build/tools/make_standalone_toolchain.py --arch arm64 --api 24 --install-dir $(HOME)/ndk_standalone
$ CC=$(HOME)/ndk_standalone/bin/clang CXX=$(HOME)/ndk_standalone/bin/clang GOOS=android GOARCH=arm64 go install std
$ CC=$(HOME)/ndk_standalone/bin/clang CXX=$(HOME)/ndk_standalone/bin/clang GOOS=android GOARCH=arm64 CGO_ENABLED=1 go build
And networking works!
I'm not really sure why (or if) clang makes a difference as opposed to invoking the compiler directly. Maybe I'll play around with this more. Also, I had to still enabled CGO explicitly when compiling my application (but not for the go std library) otherwise linking failed.
We are attempting to add first class build support for Android to a C++ library. We want to supply a stock Android.mk, and disgorge it from dependencies like a jni subfolder in an Eclipse or Android Studio project directory. That is, we want to:
cd library-src
ndk-build <options>
In the above, library-src is not NDK_PROJECT_PATH. Rather, its the root folder for the library.
We visited the NDK's help (ndk-build -?), but it did not tell us how to remove the assumptions. We tried the following, but it produced an errors:
$ ndk-build -f Android.mk
Android NDK: Could not find application project directory !
Android NDK: Please define the NDK_PROJECT_PATH variable to point to it.
/opt/android-ndk-r10e/build/core/build-local.mk:143: *** Android NDK: Aborting
Stop.
Attempting to set NDK_PROJECT_PATH results in a similar error:
$ NDK_PROJECT_PATH=. ndk-build -f Android.mk
Android NDK: Your APP_BUILD_SCRIPT points to an unknown file: ./jni/Android.mk
/opt/android-ndk-r10e/.../add-application.mk:199: *** Android NDK: Aborting...
Stop.
And attempting to set APP_BUILD_SCRIPT results in a similar error:
$ NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk ndk-build -f Android.mk
Android NDK: Your APP_BUILD_SCRIPT points to an unknown file: ./jni/Android.mk
/opt/android-ndk-r10e/.../add-application.mk:199: *** Android NDK: Aborting...
Stop.
How do we use ndk-build without the jni directory?
Its important that we remove the limitations/assumptions. If we can't remove them, then we can't automate building and testing. If we can't automate building and testing, then we can't add the support because our governance has some QA and testing gates that we won't be able to pass through. (I'm willing to tolerate a manual adb push to test on-device).
I must admit that I don't understand your limitations. Why adding file library-src/Android.mk is OK, but library-src/jni/Android.mk breaks your QA and testing gates. Furthermore, Android.mk is usually not enough to launch a build. Whether you want to choose the STL variation, or ABI, or toolchain, it is natural to define these settings in a different file, Application.mk, which also goes to the jni directory by convention. Add library-src/jni directory, and Android developers will thank you when their tools of trade get upgrades and they can stay with the standard configuration.
But Android build is a very flexible system, and you can achieve literally what you ask for.
The experiments that you made did not work because ndk-build is simply a thin wrapper around GNU make, and treats environment variables with low priority.
ndk-build APP_BUILD_SCRIPT=Android.mk NDK_PROJECT_PATH=.
will most likely simply work for you. If you need more control, you can use something like
ndk-build APP_BUILD_SCRIPT=Android.mk NDK_PROJECT_PATH=. APP_STL=gnustl_static APP_ABI=armeabi-v7a APP_PLATFORM=android-19 NDK_TOOLCHAIN_VERSION=4.9
You can control the output directories, too. See NDK_APP_OUT, NDK_APP_LIBS_OUT.
One last hint: if your global build process is based on make, you can invoke $(MAKE) directly instead of going through ndk-build. It is also OK if you require standalone toolchain to keep platform-independent make logic.
I am currently trying to debug native code in Android via ndk-gdb but I am having some troubles.
Even if I start a very simple project (let's say for example a default cocos2d-x v3 project) and run
ndk-build NDK_DEBUG=1
I end up with the following folder structure inside my android project
...
libs/
armeabi/
libcocos2dcpp.so
...
instead of the expected:
...
libs/
armeabi/
gdb.setup
gdbserver
libcocos2dcpp.so
...
In order to use ndk-gdb I need those two gdb files.
I am using cocos version 3.2 and Android NDK version r9d.
Isn't NDK_DEBUG=1enough for the gdb files to be generated? I have also tried withandroid:debuggable="true" inside my manifest file but it didn't work.
Edit
After running the command suggested by Digit I found a very suspicious line
Android NDK: Application 'local' forced *not* debuggable through NDK_DEBUG
when running the command ndk-build NDK_LOG=1 NDK_DEBUG=1
BUT
if I change to ndk-build NDK_LOG=1 NDK_DEBUG=true I get
Android NDK: Application 'local' forced debuggable through NDK_DEBUG
So it is ok now, really weird though how =1 is not considered true.
Can you paste the output of 'ndk-build NDK_LOG=1 NDK_DEBUG=1', this should contain more information about what ndk-build is doing, and is likely to provide an explanation.
I have a really simple helloworld.cpp program
#include <iostream>
using namespace std;
int main ()
{
cout << "Hello World!";
return 0;
}
And I'm trying to compile it for android x86 with the cross-compiler from the toolchain:
/Users/me/android-ndk-r8/toolchains/x86-4.4.3/prebuilt/darwin-x86/bin/i686-android-linux-g++ helloworld.cpp -L "/Users/me/android-ndk-r8/sources/cxx-stl/stlport/libs/x86/" -lstlport_static
However, I get errors:
helloworld.cpp:2:20: error: iostream: No such file or directory
Any idea why?
Check the documentation.html file included with the NDK, under "Standalone Toolchain". It says that if you invoke the compiler in this way you won't be able to "use any C++ STL". However it is possible, as the documentation explains, if you first create a "customized" toolchain installation, using something like the following command:
$NDK/build/tools/make-standalone-toolchain.sh --platform=android-8 --install-dir=/tmp/my-android-toolchain --arch=x86
where $NDK is the path to your NDK directory. Note the --arch=x86 which means that the toolchain is prepared specifically for the x86 Android. This prepares what you need in one directory, including the STL headers and folders. You should then be able to use -lstdc++ to link against the STL (static version), i.e. something like:
/tmp/my-android-toolchain/bin/i686-android-linux-g++ helloworld.cpp -lstdc++
For a more complete explanation, please see the NDK documentation.
The NDK documentation is not entirely accurate, at least not currently. In fact, it states when using the prebuilt toolchain "You won't be able to use any C++ STL (either STLport or the GNU libstdc++) with it.", but this is out of date. I created a small hello world program using the include with the same error. It can be solved without creating your own toolchain though, which is nice if you don't want to have to add one more step to your configuration process and allows you to always use the latest SDK platform without creating a new toolchain every time.
The NDK ships with the source code for several versions of standard C++ libraries: GAbi++, STLport, and GNU STL. Each flavor comes with prebuilt shared and static libs as well. My example below will use stlport.
To use the stand-alone toolchain at its installed location, you can do something like this:
export CXX='$NDK_ROOT/toolchains/arm-linux-androideabi-4.8/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-g++ --sysroot="$NDK_ROOT/platforms/android-19/arch-arm"'
This, for example, would set your CXX compiler to compile ARM on the OS X system using SDK platform level 19. This much you probably already knew. Also, you would want to export your CC, CPP, LD, AR, and RANLIB if you use it. I also personally create an envar for READELF.
To add support for C++ libs, you could do something like follows:
$CXX helloworld.cpp -I$NDK_ROOT/sources/cxx-stl/stlport/stlport -L$NDK_ROOT/sources/cxx-stl/stlport/libs/armeabi -lstlport_shared
Note that this will link the libstlport_shared.so which will now be required at runtime, so you may need to add a relative path to the command above to support that, depending on your APK structure. If you want to just test this simple case, you can just run this on the emulator as follows:
adb push a.out /data
adb push $NDK_ROOT/sources/cxx-stl/stlport/libs/armeabi/libstlport_shared.so /data
adb shell
# su
# cd /data
# chmod 777 a.out
# ./a.out
To get rid of the headache of dealing with shared library paths, you can also statically link the C++ library in by changing "-lstlport_shared" to "-lstlport_static". There are some consequences of doing this, as explained in the NDK Dev Guide. The biggest issue is due to having the static library linked in multiple places, causing:
- memory allocated in one library, and freed in the other would leak or even corrupt the heap.
- exceptions raised in libfoo.so cannot be caught in libbar.so (and may simply crash the program).
- the buffering of std::cout not working properly
A useful tool is also included to see what dependencies your program has, the readelf tool.
To see what other shared libraries your program requires, you can run the following:
$NDK_ROOT/toolchains/arm-linux-androideabi-4.8/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-readelf -a a.out | grep NEEDED
Other cool standard tools:
addr2line - convert a stack trace address to a line of code
nm - Displays the symbol table
objdump - displays info on an object
i call one of the functions from gnustl after it runs fine from prebuilt aosp arm-linux-androideabi-gcc --std=c++11 and after crashing error i cant get a backtrace from logs or reason, my hope is turning to crossbuilt qemu-linux-user to run host compiled i686 binary on the arm, difficulty is interacting with crosshost libs aapt from adt always crashes on any other than platform specific libs, unless kernel module packaged update is possible...