libreactnativejni.so is built as elf32-i386 on 64bit android ndk (linux) - android-ndk

EDIT: I managed to built x86_64 version of libreactnativejni.so (see my answer). However it didn't resolved my problem.
To sum up what I learned here is:
You cannot test android components, which are using native libraries on Linux, because "libandroid.so" (core android lib), doesn't exists for Linux.
Original question:
My goal is to run tests on my Linux box using PowerMockito similar to RootViewTest.java.
Not sure how react-native team managed to run this test, but from my experience mocking Arguments.createArray is not possible, without loading jni library reactnativejni. Reason is that Arguments.createArray() calls WritableNativeArray which in static initializer ReactBridge.staticInit() calls SoLoader.loadLibrary("reactnativejni").
So I thought I've no other option, but compile this reactnativejni shared library for linux, using 64bit android-ndk-r10e
I managed to load this jni lib and test my code using:
ndkDir=$(pwd)/react-ndk/all/x86 \
JAVA_OPTS="-Djava.library.path=\".:$ndkDir\"" \
LD_LIBRARY_PATH="$ndkDir:$LD_LIBRARY_PATH" ./gradlew app:test
But test failed with:
libreactnativejni.so: wrong ELF class: ELFCLASS32 (Possible cause: architecture word width mismatch)
Checked platform with objdump:
objdump -s --section .comment libreactnativejni.so
libreactnativejni.so: file format elf32-i386
My question how is possible that 64 bit ndk produced 32 bit library and how to force to produce 64 bit.
Library build script is written as gradle script:
https://github.com/facebook/react-native/blob/26684cf3adf4094eb6c405d345a75bf8c7c0bf88/ReactAndroid/build.gradle#L199

ReactAndroid explicitly requests 32-bit targets. If you wish, you can replace this line to read
APP_ABI := all

I'm going to answer my own question (thank Alex for good APP_ABI lead). To compile x86_64 variant of reactnativejni follow this steps:
Update APP_ABI to APP_ABI := armeabi-v7a x86_64 x86 in file ReactAndroid/src/main/jni/Application.ml
The next problem is dependency jsc-android, which is not build for X86_64 target. There is alternative jsc-android-buildscripts which is also built for X86_64.
Extract folder X86_64 directly from aar and put it in ReactAndroid/build/third-party-ndk/jsc/jni/x86_64
However compilation will be failing on X86_64 with errors: lambda capture initializers only available with -std=c++1y or -std=gnu++1y
Fix that error, by replacing all occurrences of -std=c++1y with -std=c++11 in all Android.mk files.
Now you can start build with: ./gradlew buildReactNdkLib
Optionally you might need to clean build folder with ./gradlew cleanReactNdkLib
Built reactnativejni - libreactnativejni.so will be present in ReactAndroid/build/react-ndk/all/x86_64.
But unfortunately libreactnativejni.so will not work on Linux, as it has dependency on libandroid.so, which doesn't exists for Linux.

Related

Emscripten Clang produce ELF 64-bit executabel and wasm binary cross compiler targets

I have a prepared a minimal Cmake project containing one cpp file which represent the main and one cpp file which represent the shared library, that prints basically hello world.
https://github.com/courteous/wasmELF.git
The target is to compile this miniaml code with emscripten/clang only and produce
1) one WebAssembly (wasm) binary module version 0x1 (MVP)
2) one ELF 64-bit LSB
without clearing the cmake build directory and rebuilding it again.
Currently i can successfully produce them bought by running the commands
emconfigure cmake ../ -DCMAKE_BUILD_TYPE=WASM
make
and
cmake ../ -DCMAKE_BUILD_TYPE=Linux
make
However the problem is that in order to do that i need to compile the first one with Clang the to remove the build and then to do a second compilation with GCC. I would like Emscripten/Clang to produce them bought instead. I do not want to delete the build directory since the compilation times is taking too long. (Well not in this Project but imagine if the project was much larger)
What i see is that emscripten/clang selects always a target "wasm32-unknown-emscripten"
clang++ -target wasm32-unknown-emscripten
and if i understand that correctly the target should change
I do see that the project is producing LLVM IR bitcode since i have send the flag "flto"
i.e.
file TestSharedClass.cpp.o
TestSharedClass.cpp.o: LLVM IR bitcode
and in the CMakeLists.txt
set(CMAKE_CXX_FLAGS "-flto")
x86_64-unknown-linux-gnu is a supported target by emscripten/Clang
~/Projects/emscripten/emsdk/upstream/bin$ ./llc --version
LLVM (http://llvm.org/):
LLVM version 11.0.0git
Optimized build with assertions.
Default target: x86_64-unknown-linux-gnu
Host CPU: haswell
Registered Targets:
wasm32 - WebAssembly 32-bit
wasm64 - WebAssembly 64-bit
x86 - 32-bit X86: Pentium-Pro and above
x86-64 - 64-bit X86: EM64T and AMD64
In cmake i do have
SET(TARGET x86_64-unknown-linux-gnu)
however when i run
emconfigure cmake ../ -DCMAKE_BUILD_TYPE=Linux
make
i get mainTestFile.js and mainTestFile.wasm instead of ELF 64-bitcode.
what i am doing wrong here. How to tell clang to product once ELF and once wasm from the same code run without having to clear the build directory. This should be possible since clang is producing LLVM IR bitcode. Or do i understand that wrong?
https://github.com/emscripten-core/emscripten/issues/10361
OK that seems to not be possible i.e. the reply from the dev on github states that emcc or emmake can not be used with another target other then wasm32-unknown-emscripten.

Input/output error using Android ndk-build

Using Android NDK R10E, I am trying to build a shared library for all supported ABI's and I am getting the following error for some but not all ABI's:
[armeabi] SharedLibrary : libMyLib.so /home/user/android-ndk-r10e/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.8/../../../../arm-linux-androideabi/bin/ld:
fatal error: /home/user/source/MyLib/obj/local/armeabi/libMyLib.so: Input/output error
The project successfully builds for arm64-v8a, mips and mips64 but fails with the above error for armeabi, armeabi-v7a, x86 and x86_64.
I have a static library project and another shared library project and they both build successfully for all 7 ABI's.
If I compare the contents of obj/local/ for an ABI that builds and one that does not, they both contain all the same files except for libMyLib.so.
The difference between those two sets of ABIs is that the failing ones link using ld.gold and the working ones use ld.bfd.
Two things to try:
Use the 4.9 toolchain. It hopefully has the bug fix.
If that doesn't work, you can add -fuse-ld=bfd to your ldflags to use bfd even on the architectures that default to gold.
Same issue happened to me in r15c.
The fix was to copy
android-ndk-r15c/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/arm-linux-androideabi/bin/ld.bfd over ld.
I had to copy it because I could not easily find a way to specify this flag to CMake to use it while detecting the compiler features.

How do I compile and link a 32-bit Windows executable using mingw-w64

I am using Ubuntu 13.04 and installed mingw-w64 using apt-get install mingw-w64. I can compile and link a working 64-bit version of my program with the following command:
x86_64-w64-mingw32-g++ code.cpp -o app.exe
Which generates a 64-bit app.exe file.
What binary or command line flags do I use to generate a 32-bit version of app.exe?
That depends on which variant of toolchain you're currently using. Both DWARF and SEH variants (which come starting from GCC 4.8.0) are only single-target. You can see it yourself by inspecting the directory structure of their distributions, i.e. they contain only the libraries with either 64- or 32-bit addressing, but not both. On the other hand, plain old SJLJ distributions are indeed dual-target, and in order to build 32-bit target, just supply -m32 flag. If that doesn't work, then just build with i686-w64-mingw32-g++.
BONUS
By the way, the three corresponding dynamic-link libraries (DLLs) implementing each GCC exception model are
libgcc_s_dw2-1.dll (DWARF);
libgcc_s_seh-1.dll (SEH);
libgcc_s_sjlj-1.dll (SJLJ).
Hence, to find out what exception model does your current MinGW-w64 distribution exactly provide, you can either
inspect directory and file structure of MinGW-w64 installation in hope to locate one of those DLLs (typically in bin); or
build some real or test C++ code involving exception handling to force linkage with one of those DLLs and then see on which one of those DLLs does the built target depend (for example, can be seen with Dependency Walker on Windows); or
take brute force approach and compile some test code to assembly (instead of machine code) and look for presence of references like ___gxx_personality_v* (DWARF), ___gxx_personality_seh* (SEH), ___gxx_personality_sj* (SJLJ); see Obtaining current GCC exception model.

build c file with openssl by NDK under cygwin

I am trying to build c file included by ndk under cygwin
In Android.mk, I add -I/usr/include to LOCAL_FLAGS like
LOCAL_FLAGS := -I/usr/include
And I have checked that openssl does under /usr/include
But when I run ndk-build under by project dir, it output
"fatal error: openssl/ssl.h: No such file or directory"
I think I have specified the include directory, but not solve this problem.
Is there any other way can I try?
You seem to have some gaps in your knowledge:
C code compiles to processor's native instruction set. Your desktop/build machine probably has a different architecture from your Android device(thus a different instruction set).
NDK doesn't just compile, it cross-compiles. It means that the NDK runs on the build machine, but the executable it produces cannot run on the build machine(different instruction sets).
All libraries on your desktop are in your desktop's processoer's instruction set. Thus, you cannot link any program build by the NDK using the desktop's libraries. This means:
No includes from '/usr/include/'
No libs from /lib, /usr/lib, /lib64 or /usr/lib64
No Cygwin packages under on Windows
What you need to do is build your own openssl using the NDK and use that to link against when you build your executable.
Please note that the answer is missing a lot of information (at least 3 Bachelor's level Computer Science courses worth of information).

QT building applications for arm linux

I got a little confused when it comes to QT and cross compiling
appliations for my arm-linux:
So far I have a linux running on my AT91SAM9263-EK and an appropriate
filessystem including QT libs build via buildroot.
Also I have build QT-4.8 on my ubuntu.
Now I want to build an example application:
I created a makefile in an examples folder in QT on my ubuntu using
qmake; I used the given qmake.conf in mkspecs/qws/linux-arm-g++.
when executing make I get an error because it includes qatomic_i386.h
and the message "error: impossible constraint in 'asm'".
this header file does obviously not match to my arm toolchain.
my question:
how to configure Qt on my ubuntu to build Qt binaries for my embedded linux
on arm? Do I need to include any libs build by the arm toolchain?
any help is appreciated!
regards
EDIT:
I use the -spec flag and pass the path to "mkspecs/qws/arm-linux-g++" where a "qmake.conf" is located. I did not change anything in here because I dont know wich qmake variable are relevant to link to my arm related libs.
So the right compiler is used, which I could verify when the make process starts. But I observed that in a config file called qconfig.h there is an ARCH flag which is set to i386 but I didnt figure out how one can configure this. I dont think I should manually edit this file.
EDIT2:
someone knows whats behind the file qconfig.h?? should I adjust it manually?
I will solve it by myself :)
After struggling a while and scanning the web I got a little deeper involved how everything works together. I did not understand how to generate an executable for my ARM target device. I figured out two things:
do not add your QT path for X11 at the beginning in your PATH variable. this might mess up your cross compilation.
edit the qmake.conf correspondingly. add your libs build for the target device which in my case are located within buildroot. Add theses lines to your qmake.conf file:
QMAKE_CFLAGS += -O3 -march=armv5te
QMAKE_CXXFLAGS += -O3 -march=armv5te
QMAKE_INCDIR_QT = /home/user/arm/toolchain/buildroot-2010.11/output/staging/usr/include
QMAKE_LIBDIR_QT = /home/user/arm/toolchain/buildroot-2010.11/output/staging/usr/lib
I got it running now. thanks to everyone!
Yes, either you provide the Qt libraries in your toolchain or you tell qmake where to find them. Also, I suspect you're calling qmake without the -spec parameters. If you are using the qmake you find in your distribution, it will use the default spec, which is not arm I guess. Add the -spec parameter and point it to the arm mkspec. Also, make sure the generated g++ commands link to the correct Qt libs compiled for arm.
You shall install QtSDK for embedded linux befor you use it to build your application. I'm afraid you just have QtSDK for x86 right now. After QtSDK for embedded linux installed, it has qws/linux-arm-g++ as the default mkspace typically. If you don't have QtSDK for embedded linux, you can build it from source. Then run qmake to create Makefile for you application.
$QTDIR_FOR_ARM/qmake
Reference:
Installing Qt for Embedded Linux and Cross-Compiling Qt for Embedded Linux Applications

Resources