I'm trying to compile libfuse with NDK, my environment:
Win10(64bit) + NDK(r14b,64bit) + libfuse(3.1.0)
Error occurs in fuse_common.h, it checks size of off_t:
$ ndk-build
[armeabi-v7a] Compile thumb : fuse <= buffer.c
In file included from jni/../../libfuse/lib/buffer.c:15:
In file included from jni/../../libfuse/lib/fuse_i.h:9:
In file included from jni/../../libfuse/include\fuse.h:19:
jni/../../libfuse/include/fuse_common.h:745:13: error: bit-field
'_fuse_off_t_must_be_64bit' has negative width (-1)
{ unsigned _fuse_off_t_must_be_64bit:((sizeof(off_t) == 8) ? 1 : -1); };
^
1 error generated.
make: *** [obj/local/armeabi-v7a/objs/fuse/__/__/libfuse/lib/buffer.o] Error 1
here's the check in fuse_common.h:
struct _fuse_off_t_must_be_64bit_dummy_struct \
{ unsigned _fuse_off_t_must_be_64bit:((sizeof(off_t) == 8) ? 1 : -1); };
I searched on google, there's _FILE_OFFSET_BITS=64 definition, which can be used to change the size of off_t, I have this defined my 'Android.mk' file:
LOCAL_CFLAGS := \
....
-D_FILE_OFFSET_BITS=64 \
....
And even add this line at the beginning of fuse_common.h
#define _FILE_OFFSET_BITS 64
Still not working, how to fix it?
Update to NDK r15c. _FILE_OFFSET_BITS=64 works from there on out.
Note that most off64_t system calls weren't available until android-21. If your minSdkVersion is set below that and you use _FILE_OFFSET_BITS=64, many functions will not be available.
NOTE Provided solution is much like workaround, see #Dan's answer for reliable and official way to get 64-bit off_t.
On Android off_t is always 32-bit length, and there is no preprocessor macro that controls its size. (Though it is true only for NDK development since modern bionic allow to configure off_t size at compile time). And because of this you cannot compile your library directly.
But I guess there is some way to workaround it. Android NDK offers non-POSIX extended type - off64_t, and also it provides a complementary set of library functions that accept it instead of off_t. They are distinguished by 64 suffix, i.e. lseek64(), mmap64(). So to make things work you may try to add global configuration header to your project:
/* let off_t to be a 64-bit length */
typedef off64_t off_t;
/* use appropriate versions of system functions */
/* list here only functions that have off_t parameters and are used by your library */
#define mmap mmap64
#define lseek lseek64
And of course keep in mind that compiled code now is linked against *64() functions instead of regular ones and any public interfaces expect off64_t instead of off_t.
Related
I setup conan for cross building android app on my linux, i have my_profile below for conan for this cross building, which that I run conan create . user/testing -pr=my_profile
include(default)
target_host=aarch64-linux-android
android_ndk=$HOME/android-ndk-r21
api_level=21
[settings]
arch=armv8
build_type=Release
compiler=clang
compiler.libcxx=libc++
compiler.version=9
os=Android
os.api_level=$api_level
[build_requires]
[options]
[env]
PATH=[$android_ndk/toolchains/llvm/prebuilt/linux-x86_64/bin]
CHOST=$target_host
AR=$target_host-ar
AS=$target_host-as
LD=$target_host-ld
STRIP=$target_host-strip
RANLIB=$target_host-ranlib
CC=$target_host$api_level-clang
CXX=$target_host$api_level-clang++
CONAN_MAKE_PROGRAM=$android_ndk/prebuilt/linux-x86_64/bin/make
CONAN_CMAKE_TOOLCHAIN_FILE=$android_ndk/build/cmake/android.toolchain.cmake
and I made a very simple file:
#include <fcntl.h>
int raw_fallocate(int fd, off_t length) {
if (fallocate(fd, 0, 0, length) == 0) return 0;
return -1;
}
I found that in the fcntl.h, it only defines fallocate when __ANDROID_API >=21 with #ifdef
so in my CMakeLists.txt, I need to put
target_compile_definitions(hello PRIVATE __ANDROID_API__=21) to make it compile, otherwise, the compiler will complain it cannot find definition of fallocate.
That all make sense. However, when I put this preprocessor definition, I still got a warning message saying:
In file included from <built-in>:413:
<command line>:1:9: warning: '__ANDROID_API__' macro redefined [-Wmacro-redefined]
#define __ANDROID_API__ 21
^
<built-in>:405:9: note: previous definition is here
#define __ANDROID_API__ 16
^
1 warning generated.
What I don't understand is I could not find this built-in thing..., i searched my whole android_ndk folder, and could not find where is this #define __ANDROID_API__ 16
Also I only have android_ndk v21 installed, I have no idea where this version of 16 came from.
Any idea?
This #define __ANDROID_API__ 16 comes from the NDK itself (this is the lowest supported API for android-ndk-r21. To set it to 21, you must pass ANDROID_PLATFORM parameter to CMake. Update: this is actually wrong. For ABI arm64-v8a the minimal API is 21. So, the problem is that arch=armv8 didn't work.
According to the conan instructions, set os.api_level=21 should have worked. But with this approach, you should not supply the CONAN_CMAKE_TOOLCHAIN_FILE. Update: this does not work because conan is not compatible with NDK r21.
I assume that when you do supply CONAN_CMAKE_TOOLCHAIN_FILE, all the settings, like CC= and AR= become irrelevant. Same for os.api_level and arch. But if you replace cmake with a script that calls the original cmake binary and sets the necessarycommand-line parameters, including -DANDROID_PLATFORM=android-21, you should be set. Simply add to my_profile:
CONAN_CMAKE_PROGRAM=cmake-wrapper
This approach is used in https://github.com/bincrafters/conan-android_ndk_installer package.
So I've been digging into this a little bit, and I think I found where the problem is. As #Alex Cohn said, the android ndk sets the min api level to 16 in the file
$android_ndk/build/cmake/platforms.cmake, it says on the first line set(NDK_MIN_PLATFORM_LEVEL "16"). After I change it to 21, everything works.
Now the question becomes: How can I override this value externally without touching this platforms.cmake file (I just don't want to touch files come with ndk package)? I tried to put set(NDK_MIN_PLATFORM_LEVEL "16") in my CMakelists.txt file for my project, but that does not work as I believe it is overridden later on by platforms.cmake.
Of course the second method of using conan's ndk-installer also works, and I checked the same platforms.cmake file in the installed ndk folder, it has the same value of 16. So there must be somewhere in conan settings that updated the value to 21, and I would like to learn where / how this is changed when using ndk-installer, so I can do the same for my manually installled android ndk.
I have a .cpp file which has usage of NULL at several places. When I try to compile this cpp file for Android/x86 platform using clang++ on Windows machine + standalone tool chain, I am running into "expected expression" error at the places where NULL is used. I find the definition of NULL in stddef.h of clang headers provided by Android NDK as below.
#if defined(__need_NULL)
#undef NULL
#ifdef __cplusplus
# if !defined(__MINGW32__) && !defined(_MSC_VER)
# define NULL __null
# else
# define NULL 0
# endif
#else
# define NULL ((void*)0)
#endif
As far as I know, __null is specific to GNU compiler. In my case both _MSC_VER and __MINGW32__ are undefined because I am compiling for Android platform using clang++ and standalone tool chain. So it is hitting into define NULL __null. Since clang++ has no clue of what __null is, it is resulting into "expected expression" error.
My question is, why is clang using macros(like __null) provided by GNU compiler? Or am I missing something here?
Could somebody please help me understand. Thanks
Why is clang defining NULL as __null?
__null is superior to 0, because former is only a null pointer constant, while the latter is also an integer constant. This difference is significant in case of overload resolution and type deduction:
void foo(int);
void foo(void*);
foo(0); // calls foo(int)
foo(__null); // call is ambiguous, program is ill-formed
foo(NULL); // could have either behaviour
// call to foo(int) would be undesirable
foo(nullptr); // calls foo(void*)
The reason is same or similar as why nullptr was introduced to the language in C++11.
Another reason to do so is that clang strives to be closely compatible with GCC.
Since clang++ has no clue of what __null is
clang++ appears to know what __null is.
I compiled the gRPC Android example from here.
I want to run the program as executable from adb shell.
Added these lines to grpc-helloworld.cc:
#include <iostream>
int main() {
std::cout << "qwerty" << std::endl;
return 0;
}
And these lines to its CMakeLists.txt:
add_executable(avocado
src/main/cpp/grpc-helloworld.cc)
target_include_directories(avocado
PRIVATE ${HELLOWORLD_PROTO_HEADERS})
target_link_libraries(avocado
helloworld_proto_lib
android
${log-lib})
Then I pushed the generated executable and libs file and tried to run it:
LD_LIBRARY_PATH=. ./avocado
I got the following error:
[libprotobuf FATAL
/home/buga/grpc/third_party/protobuf/src/google/protobuf/stubs/common.cc:79]
This program was compiled against version 3.0.0 of the Protocol Buffer
runtime library, which is not compatible with the installed version
(3.5.1). Contact the program author for an update. If you compiled
the program yourself, make sure that your headers are from the same
version of Protocol Buffers as your link-time library. (Version
verification failed in
"out/soong/.intermediates/frameworks/av/drm/libmediadrm/libmediadrm/android_arm64_armv8-a_kryo300_shared_core/gen/proto/frameworks/av/drm/libmediadrm/protos/plugin_metrics.pb.cc".)terminating
with uncaught exception of type google::protobuf::FatalException: This
program was compiled against version 3.0.0 of the Protocol Buffer
runtime library, which is not compatible with the installed version
(3.5.1). Contact the program author for an update. If you compiled
the program yourself, make sure that your headers are from the same
version of Protocol Buffers as your link-time library. (Version
verification failed in
"out/soong/.intermediates/frameworks/av/drm/libmediadrm/libmediadrm/android_arm64_armv8-a_kryo300_shared_core/gen/proto/frameworks/av/drm/libmediadrm/protos/plugin_metrics.pb.cc".)
Aborted
What am I doing wrong?
We realized that there is a version of the protobuf library called libprotobuf-cpp-full.so and libprotobuf-cpp-lite.so, and it seems that their version is 3.0.0. This is conflicting with our version (3.5.1) which is compiled into either a static lib, or as a shared lib.
I'm not quite sure why this happens. Something about once the linker loads helloworld_proto_lib, it overrides all loaded protobuf symbols, and for some reason another library that you had nothing to do with crashes your program. But that's not telling you anything new.
Here's one way to solve this problem:
1. Changes to grpc-helloworld.cc
Make the main extern "C", and change its name maybe. For example:
extern "C" int my_main() {
std::cout << "qwerty" << std::endl;
return 0;
}
2. Add file grpc-avocado.cc
This will contain the actual main of the executable, which will dynamically load the libraries helloworld_proto_lib and grpc-helloworld. Here's how to do it:
#include <iostream>
#include <android/dlext.h>
#include <dlfcn.h>
int main() {
android_dlextinfo extinfo;
extinfo.flags = ANDROID_DLEXT_FORCE_LOAD;
void* proto_lib = android_dlopen_ext("/path/to/libhelloworld_proto_lib.so", RTLD_LAZY, &extinfo);
void* helloworld = dlopen("/path/to/libgrpc-helloworld.so", RTLD_LAZY);
int (*my_main)() = (int (*)())dlsym(helloworld, "my_main");
return my_main();
}
The function android_dlopen_ext from #include <android/dlext.h>, and its flag argument, are described here: https://developer.android.com/ndk/reference/group/libdl . In the above code we pass the flag ANDROID_DLEXT_FORCE_LOAD, which is documented as:
When set, do not use stat(2) to check if the library has already been loaded.
This flag allows forced loading of the library in the case when for some reason multiple ELF files share the same filename (because the already-loaded library has been removed and overwritten, for example).
Note that if the library has the same DT_SONAME as an old one and some other library has the soname in its DT_NEEDED list, the first one will be used to resolve any dependencies.
I think the text in bold is what explains why this solution works.
3. Change CMakeLists.txt
Since you'll be loading helloworld_proto_lib dynamically, you can now remove it from the executable definition, and there's no need for any proto headers:
add_executable(avocado
src/main/cpp/grpc-avocado.cc)
target_link_libraries(avocado
android
${log-lib})
Build, push, and run
You can now build, push the executable avocado and the two libraries libgrpc-helloworld.so, libhelloworld_proto_lib.so, and run. You don't need LD_LIBRARY_PATH. Good luck with the rest of your project!
In android mk files it is possible to call a shell command right after generating assembly files with LOCAL_FILTER_ASM.
I was wondering is there any workaround to have something similar in cmake?
I admit I had lookup what LOCAL_FILTER_ASM does.
So the following is my piece of code (same functionality just in CMake):
cmake_minimum_required(VERSION 3.0)
project(LocalFilterASM C ASM)
set(LOCAL_FILTER_ASM "cp")
string(
REPLACE
"<ASSEMBLY_SOURCE>" "<OBJECT>.S.original"
MY_CREATE_ASSEMBLY "${CMAKE_C_CREATE_ASSEMBLY_SOURCE}"
)
string(
REPLACE
"<SOURCE>" "<OBJECT>.S"
MY_COMPILE_OBJECT "${CMAKE_ASM_COMPILE_OBJECT}"
)
set(
CMAKE_C_COMPILE_OBJECT
"${MY_CREATE_ASSEMBLY}"
"${LOCAL_FILTER_ASM} <OBJECT>.S.original <OBJECT>.S"
"${MY_COMPILE_OBJECT}"
)
file(WRITE main.c "int main(void) { return 0; }")
add_executable(${PROJECT_NAME} main.c)
This just takes some of the existing CMake compiler rules and combines it into a new multi-line rule for CMAKE_C_COMPILE_OBJECT. Please note that this will only work with CMake's makefile generators.
It's very hard to say since you haven't provided any example of what you currently have.
However, you can use the add_custom_command() function to add before and after scripts to any target (see the bottom of the page in the "Build Events" section for the syntax you want).
I am trying to set the bit-rate in i.Mx6 processor in android.
I am using iproute2 utility to set bitrate for CAN controller. The command used to set the bitrate is given below:
#ip link set can0 type can bitrate 125000
While I am trying to set the bitrate in android using below command, I am getting error message.
The error message is given below:
Garbage instead of arguments \"bitrate ...\". " "Try \"ip link help\""
I analysed and debugged inside the source code of this utility and compared with the Linux utility source. I found that the error was occurred in the system call dlsym().
l = dlsym(dlh, buf);
if (l == NULL)
return NULL;
This function suppose to return some valid address. But in my case, its returning the NULL.
Add the following line to external/iproute2/ip/Android.mk
+LOCAL_LDFLAGS := -Wl,-export-dynamic -Wl,--no-gc-sections
include $(BUILD_EXECUTABLE)
Compile again, and it should work.
(1) (Android Source Code)/external/iproute2/ip/iplink.c
#define LIBDIR "/usr/lib/"
to
#define LIBDIR "/usr/lib"
(2) (Android Source Code)/external/iproute2/ip/Android.mk
+LOCAL_LDFLAGS := -Wl,-export-dynamic -Wl,--no-gc-sections
include $(BUILD_EXECUTABLE)
PS. This bug only on Android ICS(4.0.4).