We recently added cpu-features to detect platform features like ARMV8 and CRC, AES and SHA. We caught a bug report for building against the latest NDK. When we attempt to include <cpu-features.h> in an armeabi project it results in:
$ make -f GNUmakefile-cross
arm-linux-androideabi-g++ -DNDEBUG -g2 -O3 -fPIC -pipe -march=armv5te -mtune=xscale -mthumb -msoft-float
-funwind-tables -fexceptions -frtti -DANDROID --sysroot=/opt/android-ndk/platforms/android-21/arch-arm
-Wa,--noexecstack -I/opt/android-ndk/sources/cxx-stl/gnu-libstdc++/4.9/include
-I/opt/android-ndk/sources/cxx-stl/gnu-libstdc++/4.9/libs/armeabi/include -c cpu.cpp
In file included from cpu.cpp:26:0:
/opt/android-ndk/platforms/android-21/arch-arm/usr/include/machine/cpu-features.h:52:6: error:
# error Unknown or unsupported ARM architecture
^
cpu.cpp: In function 'bool CryptoPP::CPU_QueryNEON()':
cpu.cpp:402:29: error: 'android_getCpuFeatures' was not declared in this scope
if (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON)
^
cpu.cpp:402:33: error: 'ANDROID_CPU_ARM_FEATURE_NEON' was not declared in this scope
if (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON)
^
make: *** [cpu.o] Error 1
The CXXFLAGS we are using come directly from a JNI project I created a few years ago. I used ndk-build to examine the flags Android's build system sets, and then transferred them to our script. We are not making them up; they are official NDK compiler options.
When I cat the header cpu-features.h I see an ominous sign:
/* __ARM_ARCH__ is a number corresponding to the ARM revision
* we're going to support. Our toolchain doesn't define __ARM_ARCH__
* so try to guess it.
*/
#ifndef __ARM_ARCH__
# if defined __ARM_ARCH_7__ || defined __ARM_ARCH_7A__ || \
defined __ARM_ARCH_7R__ || defined __ARM_ARCH_7M__
# define __ARM_ARCH__ 7
# elif defined __ARM_ARCH_6__ || defined __ARM_ARCH_6J__ || \
defined __ARM_ARCH_6K__ || defined __ARM_ARCH_6Z__ || \
defined __ARM_ARCH_6KZ__ || defined __ARM_ARCH_6T2__
# define __ARM_ARCH__ 6
# else
# error Unknown or unsupported ARM architecture
# endif
#endif
We seem to be missing something in our process and implementation. First, all the definitions needed are provided by the preprocessor (see below). The preprocessor provides __ARM_ARCH, but Android's header checks for __ARM_ARCH__.
Second, <machine/cpu-features.h> does not seem to include needed declarations:
$ cat /opt/android-ndk/platforms/android-21/arch-arm/usr/include/machine/cpu-features.h | grep -i android_getCpuFeatures
$
We don't use Android's build system, so very little of this applies: The cpufeatures Library. Its also too high level and lacks some of the details we need.
My question is, how do we use cpu-features in a regular native library? What are we missing for the first and second problems?
Our script sets CXX, CXXFLAGS, etc. They are available for use once the script is sourced. In this case:
$ echo $CXX
arm-linux-androideabi-g++
And:
$ $CXX -dM -E - </dev/null | sort
#define __ACCUM_EPSILON__ 0x1P-15K
#define __ACCUM_FBIT__ 15
#define __ACCUM_IBIT__ 16
#define __ACCUM_MAX__ 0X7FFFFFFFP-15K
#define __ACCUM_MIN__ (-0X1P15K-0X1P15K)
#define __ANDROID__ 1
#define __APCS_32__ 1
#define __arm__ 1
#define __ARM_32BIT_STATE 1
#define __ARM_ARCH 5
#define __ARM_ARCH_5TE__ 1
#define __ARM_ARCH_ISA_ARM 1
#define __ARM_ARCH_ISA_THUMB 1
#define __ARM_EABI__ 1
#define __ARMEL__ 1
#define __ARM_FEATURE_CLZ 1
#define __ARM_FEATURE_DSP 1
#define __ARM_FEATURE_QBIT 1
#define __ARM_FP 12
#define __ARM_NEON_FP 4
#define __ARM_PCS 1
#define __ARM_SIZEOF_MINIMAL_ENUM 4
#define __ARM_SIZEOF_WCHAR_T 4
#define __ATOMIC_ACQ_REL 4
#define __ATOMIC_ACQUIRE 2
#define __ATOMIC_CONSUME 1
#define __ATOMIC_RELAXED 0
#define __ATOMIC_RELEASE 3
#define __ATOMIC_SEQ_CST 5
#define __BIGGEST_ALIGNMENT__ 8
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
...
None of the cpu-features seem to be declared or defined:
$ echo $AOSP_SYSROOT
/opt/android-ndk/platforms/android-21/arch-arm
$ grep -IR android_getCpuFeatures $AOSP_SYSROOT
$ grep -IR ANDROID_CPU_ARM_FEATURE_NEON $AOSP_SYSROOT
$
The library isn't prebuilt as part of the NDK, but is shipped as source. When building with ndk-build, this library can be built automatically by referencing it, but when using an external build system, you need to make sure to include and build it yourself.
The source is in android-ndk/sources/android/cpufeatures, and there you'll find a different cpu-features.h. (In order to reach the one you found, you probably included machine/cpu-features.h instead, which is a completely diffrent thing.)
So you need to include cpu-features.h from android-ndk/sources/android/cpufeatures and build cpu-features.c as part of your build process. Or if you're producing a static library, it can also be enough to build your code against this header, and document that the user of the library needs to include the cpufeatures library when producing the final shared library.
Related
I am trying to cross compile PuTTY utilities to run under Termux and despite using API level 28 it says the function 'futimes' is not present.
Here is where it gets stuck:
/home/xb/Desktop/android-ndk-r21d/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android28-clang -DHAVE_CONFIG_H -I. -I././ -I./charset/ -I./windows/ -I./unix/ -Wall -Werror -Wpointer-arith -Wvla -g -O2 -MT unix/uxsftpserver.o -MD -MP -MF $depbase.Tpo -c -o unix/uxsftpserver.o unix/uxsftpserver.c &&\
mv -f $depbase.Tpo $depbase.Po
unix/uxsftpserver.c:472:18: error: implicit declaration of function 'futimes' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
SETSTAT_GUTS(FD_PREFIX, fd, attrs, success);
^
You can browse the source file in question by downloading PuTTY source code version 0.74.
This page shows futimes was added in API version 26.
I am aware of the binary package for PuTTY avaliable in Termux's repo, I just want to learn how to cross compile.
The issue is that while we may have our minimum SDK version to be 26, we do not have the __USE_BSD macro defined, not adding the definition.
#if defined(__USE_BSD)
#if __ANDROID_API__ >= 26
int futimes(int __fd, const struct timeval __times[2]) __INTRODUCED_IN(26);
int lutimes(const char* __path, const struct timeval __times[2]) __INTRODUCED_IN(26);
#endif /* __ANDROID_API__ >= 26 */
#endif
sys/time.h source (same as above)
Looking deeper into where that macro is defined, we see this definition:
/*
* With bionic, you always get all C and POSIX API.
*
* If you want BSD and/or GNU extensions, _BSD_SOURCE and/or _GNU_SOURCE are
* expected to be defined by callers before *any* standard header file is
* included.
*
* In our header files we test against __USE_BSD and __USE_GNU.
*/
#if defined(_GNU_SOURCE)
# define __USE_BSD 1
# define __USE_GNU 1
#endif
#if defined(_BSD_SOURCE)
# define __USE_BSD 1
#endif
sys/cdefs.h source (same as above)
As a result, we must add either _GNU_SOURCE or _BSD_SOURCE as a compiler cFlag, which in gradle looks as such:
android {
compileSdkVersion 30
...
defaultConfig {
minSdkVersion 26
targetSdkVersion 30
...
externalNativeBuild {
cmake {
cFlags "-D_BSD_SOURCE" // or cFlags "-D_GNU_SOURCE"
...
}
}
}
It turns out that it is not necessarily guaranteed anywhere that NDK will use those flags, as shown by the comment in sys/cdefs.h. Instead, we have to provide the preprocessor macro definition ourselves.
I am trying to compile Lame sound library with Android NDK for x86_64 architecture. I am getting the below link error for undefined references to bcopy and index:
jni/libmp3lame/encoder.c:471: error: undefined reference to 'bcopy'
jni/libmp3lame/encoder.c:476: error: undefined reference to 'bcopy'
jni/libmp3lame/id3tag.c:1125: error: undefined reference to 'index'
jni/libmp3lame/newmdct.c:1036: error: undefined reference to 'bcopy'
jni/libmp3lame/util.c:685: error: undefined reference to 'bcopy'
The code successfully compiles for x86 and arm architectures.
So I digged through NDK's libs a bit and noticed that bcopy and index are both exported in libc.so for x86 and arm platforms but not for x86_64 (see below objdump outputs).
$> objdump -d android-ndk-r10d/platforms/android-21/arch-arm/usr/lib/libc.so | grep bcopy -A 6
0000b000 <bcopy>:
b000: e52db004 push {fp} ; (str fp, [sp, #-4]!)
b004: e28db000 add fp, sp, #0
b008: e28bd000 add sp, fp, #0
b00c: e8bd0800 ldmfd sp!, {fp}
b010: e12fff1e bx lr
$> objdump -d android-ndk-r10d/platforms/android-21/arch-x86/usr/lib/libc.so | grep -A 6 bcopy
00009fb0 <bcopy>:
9fb0: 55 push %ebp
9fb1: 89 e5 mov %esp,%ebp
9fb3: 5d pop %ebp
9fb4: c3 ret
$> objdump -d android-ndk-r10d/platforms/android-21/arch-x86_64/usr/lib/libc.so | grep -A 6 bcopy
<<NOTHING FOUND>>
Any thoughts? Below are my Android.mk and Application.mk files.
Application.mk:
APP_ABI:=x86_64
APP_PLATFORM := android-21
Android.mk:
LOCAL_PATH := $(call my-dir)
APP_PLATFORM := android-21
include $(CLEAR_VARS)
LOCAL_MODULE := libmp3lame
LOCAL_SRC_FILES := \
...<list-of-.c-files>...
LOCAL_LDLIBS += -llog
include $(BUILD_SHARED_LIBRARY)
You can fix this cleanly with a single line in Application.mk (docs):
APP_CFLAGS += -DSTDC_HEADERS
Why?
LAME assumes that certain symbols will be accessible without explicit inclusion via #include. However, it also provides a way to signal that explicit inclusion is necessary.
In my distribution, the conflictive files (machine.h and id3tag.c) have something like this:
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <string.h>
#endif
This is the block you need to trigger, by setting the STDC_HEADERS preprocessor variable. The line above, with the -D flag, tells the C compiler to create it.
To fix bcopy issue, I added #include <strings.h> in machine.h and id3tag.h.
To fix index issue, I ended up commenting out the #define strchar index line in both machine.h and id3tag.c:
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <string.h>
#else
# ifndef HAVE_STRCHR
//# define strchr index
# define strrchr rindex
# endif
char *strchr(), *strrchr();
# ifndef HAVE_MEMCPY
# define memcpy(d, s, n) bcopy ((s), (d), (n))
# define memmove(d, s, n) bcopy ((s), (d), (n))
# endif
#endif
I have it in strings.h, but its a #define:
$ cd /opt/android-ndk-r10d
$ grep -R bcopy * | grep x86_64
platforms/android-21/arch-x86_64/usr/include/linux/mroute6.h:#define IF_COPY(f, t) bcopy(f, t, sizeof(*(f)))
platforms/android-21/arch-x86_64/usr/include/strings.h:#define bcopy(b1, b2, len) \
platforms/android-21/arch-x86_64/usr/include/strings.h:#define bcopy(b1, b2, len) (void)(__builtin_memmove((b2), (b1), (len)))
Here's what it looks like (taken from the header strings.h):
#if defined(__BIONIC_FORTIFY)
# define bcopy(b1, b2, len) \
(void)(__builtin___memmove_chk((b2), (b1), (len), __bos0(b2)))
# define bzero(b, len) \
(void)(__builtin___memset_chk((b), '\0', (len), __bos0(b)))
#else
# define bcopy(b1, b2, len) (void)(__builtin_memmove((b2), (b1), (len)))
# define bzero(b, len) (void)(__builtin_memset((b), '\0', (len)))
#endif
Earlier version of the Android runtime provided it as a library call. See, for example, How to understand this code snippet in the bcopy.c of bionic?.
It sounds like its another case of the headers changing at android-21. That is, its a function that used to present as an export in a library, but now available in a headers. See, for example, Cannot load library: reloc_library[1285]: cannot locate 'rand'.
I think the workaround is to re-compile the Lame sound library with android-21, and not an earlier version of the toolchain.
Also, there are various config.h that have the following comment:
/* HAS_BCOPY:
* This symbol is defined if the bcopy() routine is available to
* copy blocks of memory.
*/
#define HAS_BCOPY /**/
You can find the config.h at, for example, android-ndk-r10d/prebuilt/darwin-x86_64/lib/perl5/5.16.2/darwin-2level/CORE/config.h.
If its not something obvious (like you already are compiling under android-21 and arch is correct), then we'll need to see how your project is setup (like what does Application.mk look like, or what --sysroot is being used).
I am trying to Compile C daemon of oNaiPs/droid-VNC-server available in GitHub, I am facing an error makes me spending lot of time on the same issue, please give me solution on this,
* while I am giving the command it running and stuck with the error that
/home/akhil/android/android-ndk-r10_64/build/core/build-binary.mk:448: warning: overriding commands for target obj/local/armeabi-v7a/objs/simd/asm/armv7'
/home/akhil/android/android-ndk-r10_64/build/core/build-binary.mk:448: warning: ignoring old commands for targetobj/local/armeabi-v7a/objs/simd/asm/armv7'
[armeabi] Compile arm : jpeg <= jidctfst.S
In file included from jni/jpeg/jidctfst.S:17:0:
/home/akhil/android/android-ndk-r10_64/platforms/android-L/arch-arm/usr/include/machine/cpu-features.h:52:6: error: #error Unknown or unsupported ARM architecture
# error Unknown or unsupported ARM architecture
^
make: * [obj/local/armeabi/objs/jpeg/jidctfst.o] Error 1
here is the epu-feature.h
#ifndef _ARM_MACHINE_CPU_FEATURES_H
#define _ARM_MACHINE_CPU_FEATURES_H
#ifndef __ARM_ARCH__
# if defined __ARM_ARCH_7__ || defined __ARM_ARCH_7A__ || \
defined __ARM_ARCH_7R__ || defined __ARM_ARCH_7M__
# define __ARM_ARCH__ 7
# elif defined __ARM_ARCH_6__ || defined __ARM_ARCH_6J__ || \
defined __ARM_ARCH_6K__ || defined __ARM_ARCH_6Z__ || \
defined __ARM_ARCH_6KZ__ || defined __ARM_ARCH_6T2__
# define __ARM_ARCH__ 6
# else
# error Unknown or unsupported ARM architecture
# endif
#endif
#define __ARM_HAVE_HALFWORD_MULTIPLY 1
#if __ARM_ARCH__ >= 7
# define __ARM_HAVE_LDREXD
#endif
#if __ARM_ARCH__ >= 7 && defined __VFP_FP__
# define __ARM_HAVE_VFP
#endif
#if __ARM_ARCH__ >= 7 && defined __ARM_NEON__
# define __ARM_HAVE_NEON
#endif
#endif
onaip source code is available on git repository :
https://github.com/oNaiPs/droid-VNC-server
It will solve if,
change PLD() to PLD[] ( change to square bracket)
build with android ndk 32 bit
I am trying to compile my OpenGL application in Android. I'm using [GLM library] (0.9.4)1
The compilation works until I include:
#include <glm/glm.hpp>
This header add cmath and linker complain about:
cmath:102:11: error: '::acos' has not been declared
...
cstdio:107:11: error: '::fprintf' has not been declared
It seems like std have some problem with using std, or libc++ of flags configuration on CMakeLists.txt
My CMakeLists.txt is:
status("")
status("* Adding module Core C++ ")
SET(PROJ_NAME CORE_CPP)
PROJECT(${PROJ_NAME})
# Helper to set libs & bin paths
INCLUDE(${PATH_MAIN}/cmake_tools/scripts/helperPaths.cmake)
# Include header from Module Core
INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR}/include )
IF(DEP_GLM)
INCLUDE_DIRECTORIES( ${PATH_GLM} )
ENDIF(DEP_GLM)
# Source
#---------------------------------------------------#
file(GLOB CORE_CPP_SRC
"src/*.cpp"
)
file(GLOB CORE_CPP_HEADERS
"include/*.h"
)
# Create Library
ADD_LIBRARY(${PROJ_NAME} STATIC ${CORE_CPP_SRC} ${CORE_CPP_HEADERS})
#message("Link: ${LIBRARY_DEPS}")
SET( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -pedantic -fPIC" )
SET( LIBRARY_DEPS GLESv2 log android)
TARGET_LINK_LIBRARIES(${PROJ_NAME} ${LIBRARY_DEPS})
status("- module ${PROJ_NAME} added! ")
In previous versions of gcc, It was needed to add #define _GLIBCXX_USE_C99_MATH 1 inside its includes, but it is already added in my version (4.8)
Any idea what is the problem?
I have found the problem, I was including the header INSIDE my namespace, so linker was looking for another namespace into std.
#ifndef MYNAME_MATH_H
#define MYNAME_MATH_H
#include <glm/glm.hpp> // Linker Work
namespace myname
{
//#define _GLIBCXX_USE_C99_MATH 1
//#include <glm/glm.hpp> // Make linker FAIL!
//typedef glm::vec2 Vector2;
//typedef glm::vec3 Vector3;
//typedef glm::vec4 Vector4;
}
#endif // MYNAME_MATH_H
I am building AOSP for a device. Is there a way to get the current AOSP version at native code compile time? I am looking for something similar to the LINUX_VERSION_CODE and KERNEL_VERSION(X,Y,Z) directives in Linux. More specifically, I would like to do something that looks like this in one of my own AOSP add-on projects:
#if (ANDROID_VERSION_CODE >= ANDROID_VERSION(4,2,1))
... compile something ...
#else
... compile something else...
#endif
Probably, you can use PLATFORM_VERSION and/or PLATFORM_SDK_VERSION, please see version_defaults.mk
The PLATFORM_VERSION is defined in the AOSP build directory:
build/core/version_defaults.mk:
ifeq "" "$(PLATFORM_VERSION)"
# This is the canonical definition of the platform version,
# which is the version that we reveal to the end user.
# Update this value when the platform version changes (rather
# than overriding it somewhere else). Can be an arbitrary string.
PLATFORM_VERSION := 5.1
endif
In a makefile of your product (or anywhere else) define the following make variables and pass them as macros to the compiler:
# Passing Android version to C compiler
PLATFORM_VERSION_MAJOR := $(word 1, $(subst ., ,$(PLATFORM_VERSION)))
PLATFORM_VERSION_MINOR := $(word 2, $(subst ., ,$(PLATFORM_VERSION)))
PLATFORM_VERSION_REVISION := $(word 3, $(subst ., ,$(PLATFORM_VERSION)))
COMMON_GLOBAL_CFLAGS += -DPLATFORM_VERSION_MAJOR=$(PLATFORM_VERSION_MAJOR) \
-DPLATFORM_VERSION_MINOR=$(PLATFORM_VERSION_MINOR)
ifneq ($(PLATFORM_VERSION_REVISION),)
COMMON_GLOBAL_CFLAGS += -DPLATFORM_VERSION_REVISION=$(PLATFORM_VERSION_REVISION)
endif
Define a header file with the version code:
android_version.h:
#define ANDROID_VERSION(major, minor, rev) \
((rev) | (minor << 8) | (major << 16))
#ifndef PLATFORM_VERSION_REVISION
#define PLATFORM_VERSION_REVISION 0
#endif
#define ANDROID_VERSION_CODE ANDROID_VERSION( \
PLATFORM_VERSION_MAJOR, \
PLATFORM_VERSION_MINOR, \
PLATFORM_VERSION_REVISION)
Now, to make compile time decisions based on android version simply include the android_version.h file and use pre-processer #if's.