__attribute__ ((__constructor__)) in android - android

I am trying to develop on android NDK.
I actually have a project + subfolder with modules (compiled as static libraries) and linked together with the main project files (libs .a + main object .o --> executable). Everything done via ndk-build.
I am trying to make use of constructors, after digging for some hours I figured out that constructors are NOT called as long as a function of that lib (.o) is not invoked.
e.g.
__attribute__ ((__constructor__))
void pre_func(void) {
printf("pre_func2\n");
}
void my_init(){
printf ("tutto funge!");
//return 0;
}
called only when (and before) my_init(); is explicitly invoked in test.c
$ adb shell /data/local/tmp/test
pre_func2
tutto funge!
now, my issue is very simple. By architecture I need some modules I prepared to be initialized when the object is loaded... I searched several stuff (--init, _init()) none of them helps.
Since the same code on standard linux (glibc and no bionic linker) looks to work fine, is there something wrong in my compilation gcc statement which avoids the constructor to be executed at .a loading time? how can I solve?
Compile thumb :
modules <= libtest.c
/opt/android-ndk-r8e/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin/arm- linux-androideabi-gcc -MMD -MP -MF ./obj/local/armeabi/objs/modules/libtest.o.d -fpic -ffunction-sections -funwind-tables -fstack-protector -no-canonical-prefixes -march=armv5te -mtune=xscale -msoft-float -mthumb -Os -g -DNDEBUG -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -Ijni/modules -DANDROID -D_FORTIFY_SOURCE=2 -D_GNU_SOURCE -Wa,--noexecstack -I/opt/android-ndk-r8e/platforms/android-3/arch-arm/usr/include -c jni/modules/libtest.c -o ./obj/local/armeabi/objs/modules/libtest.o
StaticLibrary : libmodules.a
rm -f obj/local/armeabi/libmodules.a
/opt/android-ndk-r8e/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin/arm-linux-androideabi-ar crs ./obj/local/armeabi/libmodules.a ./obj/local/armeabi/objs/modules/libtest.o ./obj/local/armeabi/objs/modules/module.o

I guess that the problem is that if some .o is not called from test.c, it is not linked into the test executable. That's how the liner treats static libraries (.a files). To force all compilation units (a.k.a. .o files) to be present in the executable, use
-Wl,-whole-archive libmodules.a -Wl,-no-whole-archive
for building. You can achieve this in NDK by specifying
LOCAL_WHOLE_STATIC_LIBRARIES := modules
but I must confess that I have never tried this with $(BUILD_EXECUTABLE). It works fine for $(BUILD_SHARED_LIBRARY). If something goes wrong, simply write
LOCAL_LDFLAGS := -Wl,-whole-archive $(PATH_TO_LIBMODULES)/libmodules.a -Wl,-no-whole-archive
and don't forget to set PATH_TO_LIBMODULES correctly.

Related

Updating application with C++ native library to NDK 18, cmake isn't including required sysroot platform include directory

I have an Android application, developed with Android Studio, that is using a very old build system - NDK 14 with CMake 3.6 and AGP 3.5. I'm trying to update it to NDK 18 (I eventually want to update it to latest NDK, but baby steps) using CMake 3.18.1 and AGP 4.2.2 with Gradle 6.7.1, but the build fails due to errors finding a system include file asm/types.h.
Looking at the clang++ compile command that CMake generates, it is clearly missing the ${SYSROOT}/usr/include/<platform-abi> directory.
My CMake (which worked well for NDK 14 with CMake 3.6.1) has these lines:
if(${CMAKE_ANDROID_ARCH_ABI} STREQUAL arm64-v8a)
include_directories(${ANDROID_SYSROOT}/usr/include/aarch64-linux-android)
elseif(${CMAKE_ANDROID_ARCH_ABI} STREQUAL x86_64)
include_directories(${ANDROID_SYSROOT}/usr/include/x86_64-linux-android)
endif()
Running CMake with --trace-expand, I can see it correctly parses those lines:
…
… arm64Release|arm64-v8a :/home/…/myapp/mynativelib/CMakeLists.txt(5):
if(arm64-v8a STREQUAL arm64-v8a )
… arm64Release|arm64-v8a :/home/…/myapp/mynativelib/CMakeLists.txt(6):
include_directories(/home/…/Android/Sdk/ndk/18.1.5063045/sysroot/usr/include/aarch64-linux-android )
…
But the build.ninja file generated does not have this include directory - it contains compile directives that look like so:
build CMakeFiles/mynativelib.dir/home/…/mynativelib/MyClass.cpp.o: \
CXX_COMPILER__mynativelib_Debug /home/…/mynativelib/MyClass.cpp || \
cmake_object_order_depends_target_mynativelib
DEFINES = -DANDROID -DCMAKE_BUILD_TYPE=Debug -DDEBUG -DMIXIT=0 -DNDEBUG -DRELEASE=0 … -D__GXX_EXPERIMENTAL_CXX0X__ -D__STDC_CONSTANT_MACROS
DEP_FILE = CMakeFiles/mynativelib.dir/home/…/mynativelib/MyClass.cpp.o.d
FLAGS = -std=c++14 -fno-stack-protector -ffor-scope -fexceptions -O0 -fno-limit-debug-info \
-fPIC -fno-stack-protector -fpic -ffunction-sections -funwind-tables -no-canonical-prefixes \
-Os -fomit-frame-pointer -fomit-frame-pointer -UNDEBUG -fno-omit-frame-pointer -Ijni -Wformat \
-Wa,--noexecstack -fno-stack-protector -std=c++14
INCLUDES = -I/home/…/Android/Sdk/ndk/18.1.5063045/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/include \
-I../../../../../../../some-custom-include-from-cmake \
-isystem /home/…/Android/Sdk/ndk/18.1.5063045/sources/cxx-stl/llvm-libc++/include
-isystem /home/…/Android/Sdk/ndk/18.1.5063045/sources/cxx-stl/llvm-libc++abi/include
OBJECT_DIR = CMakeFiles/mynativelib.dir
OBJECT_FILE_DIR = CMakeFiles/mynativelib.dir/home/…/mynativelib
I can see that the build command include the some-custom-include-from-cmake include directory, that is added in my CMakeLists.txt file, as well as all the cxx-stl/llvm-libc++ includes that are also added in the CMakeLists.txt file, but the /usr/include/<android-abi> platform include dir is missing.
Even if I use the include_directories(${ANDROID_SYSROOT}/usr/include/aarch64-linux-android) command without the if check, right near where the other include_directories() commands that do make it into the build file, it is still missing from the build file. I even tried to add the -I flag directly using set(CMAKE_CXX_FLAGS) and that didn't cause the required include dir to be listed.
OTOH, if I change the include_directories(${ANDROID_SYSROOT}…) to be something that doesn't start with ${ANDROID_SYSROOT}, or points to a non-existing directory - then whatever I put there does make it to the build.ninja file.
Looks like something is very purposefully removing include directories that are in ${ANDROID_SYSROOT} maybe?

Vulkan API samples building fails

I'm following this instruction: https://developer.android.com/ndk/guides/graphics/getting-started
And keep gettig the following error when compilling any module:
Build command failed.
Error while executing process /home/sophour/Android/Sdk/cmake/3.6.4111459/bin/cmake with arguments {--build /home/sophour/Code/Android/VulkanAPIsamples/API-Samples/android/texel_buffer/.externalNativeBuild/cmake/debug/x86 --target vulkan_sample}
[1/5] Building CXX object utils/CMakeFiles/vsamputils.dir/util.cpp.o
FAILED: /home/sophour/Android/Sdk/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++ --target=i686-none-linux-android --gcc-toolchain=/home/sophour/Android/Sdk/ndk-bundle/toolchains/x86-4.9/prebuilt/linux-x86_64 --sysroot=/home/sophour/Android/Sdk/ndk-bundle/sysroot -I/home/sophour/Code/Android/API-Samples/data -I/home/sophour/Android/Sdk/ndk-bundle/sources/third_party/shaderc/third_party/glslang -I/home/sophour/Code/Android/VulkanAPIsamples/API-Samples/utils -I/home/sophour/Android/Sdk/ndk-bundle/sources/android/native_app_glue -I/home/sophour/Code/Android/VulkanAPIsamples/API-Samples/utils/../android/vulkan_wrapper -I/home/sophour/Code/Android/VulkanAPIsamples/API-Samples/utils/../data -I/home/sophour/Android/Sdk/ndk-bundle/sources/third_party/shaderc/include -isystem /home/sophour/Android/Sdk/ndk-bundle/sources/cxx-stl/gnu-libstdc++/4.9/include -isystem /home/sophour/Android/Sdk/ndk-bundle/sources/cxx-stl/gnu-libstdc++/4.9/libs/x86/include -isystem /home/sophour/Android/Sdk/ndk-bundle/sources/cxx-stl/gnu-libstdc++/4.9/include/backward -isystem /home/sophour/Android/Sdk/ndk-bundle/sysroot/usr/include/i686-linux-android -D__ANDROID_API__=24 -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -mstackrealign -Wa,--noexecstack -Wformat -Werror=format-security -std=c++11 -Werror -DVK_USE_PLATFORM_ANDROID_KHR -O0 -fno-limit-debug-info -fPIC -MD -MT utils/CMakeFiles/vsamputils.dir/util.cpp.o -MF utils/CMakeFiles/vsamputils.dir/util.cpp.o.d -o utils/CMakeFiles/vsamputils.dir/util.cpp.o -c /home/sophour/Code/Android/VulkanAPIsamples/API-Samples/utils/util.cpp
In file included from /home/sophour/Code/Android/VulkanAPIsamples/API-Samples/utils/util.cpp:40:
In file included from /home/sophour/Android/Sdk/ndk-bundle/sources/third_party/shaderc/include/shaderc/shaderc.hpp:18:
In file included from /home/sophour/Android/Sdk/ndk-bundle/sources/cxx-stl/gnu-libstdc++/4.9/include/memory:81:
/home/sophour/Android/Sdk/ndk-bundle/sources/cxx-stl/gnu-libstdc++/4.9/include/bits/unique_ptr.h:76:2: error: delete called on 'shaderc::CompileOptions::IncluderInterface' that is abstract but has non-virtual destructor [-Werror,-Wdelete-non-virtual-dtor]
delete __ptr;
^
/home/sophour/Android/Sdk/ndk-bundle/sources/cxx-stl/gnu-libstdc++/4.9/include/bits/unique_ptr.h:236:4: note: in instantiation of member function 'std::default_delete<shaderc::CompileOptions::IncluderInterface>::operator()' requested here
get_deleter()(__ptr);
^
/home/sophour/Android/Sdk/ndk-bundle/sources/third_party/shaderc/include/shaderc/shaderc.hpp:133:3: note: in instantiation of member function 'std::unique_ptr<shaderc::CompileOptions::IncluderInterface, std::default_delete<shaderc::CompileOptions::IncluderInterface> >::~unique_ptr' requested here
CompileOptions() { options_ = shaderc_compile_options_initialize(); }
^
1 error generated.
ninja: build stopped: subcommand failed.
I'm absolutely new to this and have no experience in native android development. Help me solve this, please-please! A need it badly for my thesis!
Ubuntu 14.04;
Android Studio 3.1.2;
NDK: r17;
Compile SDK: API 24: Android 7.0 (Nougat);
Gradle 3.3
It looks like the problem is in the android NDK headers. Specifically in:
Android/Sdk/ndk-bundle/sources/third_party/shaderc/include/shaderc/shaderc.hpp
They declare shaderc::CompileOptions::IncluderInterface as a virtual class, but have no virtual destructor:
class IncluderInterface {
public:
// Handles shaderc_include_resolver_fn callbacks.
virtual shaderc_include_result* GetInclude(const char* requested_source,
shaderc_include_type type,
const char* requesting_source,
size_t include_depth) = 0;
// Handles shaderc_include_result_release_fn callbacks.
virtual void ReleaseInclude(shaderc_include_result* data) = 0;
};
I would not normally recommend this, but it seems you have no other choice. You could remove the -Wdelete-non-virtual-dtor or -Werror from the make files so that it will not error out for that mistake? Probably not a solution for the long term... The better solution would be to find out who makes the third party header: shaderc.hpp and ask them nicely to fix it...
Other options would be to use OpenGL in the Java SDK, or to write the Vulkan part from scrap and not use the sample code. I recently wrote an android app which uses Vulkan, and have not encountered this error.

Running CMake from command line within an Android NDK project

How might one run an NDK Cmake build independently from the rest of an Android project, ideally from the command line, external to Android Studio?
The equivalent of running ndk-build from the jni directory for slightly older Android NDK projects.
I need to investigate exactly what the calls to the compiler look like, and I can't seem to get this information when building the whole project from within Android Studio
My first attempt was just to run cmake from the project/app directory containing CMakeLists.txt, but this informs me that cmake is not installed - so how is Android Studio managing to build it then?
If your goal is to just run from the command line (as opposed to trying to do exactly what gradle is doing), just use cmake the way you normally would:
$ cmake -DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=whatever $YOUR_SOURCE_DIR
Alternatively, you can just run ./gradlew from the command line.
Your original problem is that you cannot see the command-line invocation when building with Android Studio.
You can get the command line arguments to the compiler by editing your app/build.gradle file.
defaultConfig {
...
externalNativeBuild {
cmake {
...
arguments "-DCMAKE_VERBOSE_MAKEFILE=1", ...
}
}
}
In Adroid Studio's Gradle Console pane, you will then see the command line for the compiler and linker like so:
[1/176] /home/bram/android-sdk-linux/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/bin/clang --target=armv7-none-linux-androideabi --gcc-toolchain=/home/bram/android-sdk-linux/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64 --sysroot=/home/bram/android-sdk-linux/ndk-bundle/sysroot -isystem /home/bram/android-sdk-linux/ndk-bundle/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=19 -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -fno-integrated-as -marm -mfpu=neon -Wa,--noexecstack -Wformat -Werror=format-security -Os -DNDEBUG -fPIC -MD -MT /home/bram/src/GPGOAP/CMakeFiles/gpgoap.dir/astar.c.o -MF /home/bram/src/GPGOAP/CMakeFiles/gpgoap.dir/astar.c.o.d -o /home/bram/src/GPGOAP/CMakeFiles/gpgoap.dir/astar.c.o -c /home/bram/src/GPGOAP/astar.c
As detail to the accepted answer:
The complete set of parameters passed to CMake is written to:
<project-root>/<module-root>/.externalNativeBuild/cmake/<build-type>/<ABI>/cmake_build_command.txt`
See for details: https://developer.android.com/ndk/guides/cmake.html#build-command

Getting debug symbols in final SO file even when building Release in CMake

I'm using CMake (generator is ninja) to build a shared library using the NDK toolchain (g++ 4.9). Below is the verbose output for building a single CPP file in the library when I build with ninja:
[34/164] /usr/local/bin/android-ndk/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-g++ -DANDROID -DBOOST_ALL_NO_LIB -fexceptions -frtti -fpic -Wno-psabi --sysroot=/usr/local/bin/android-ndk/platforms/android-15/arch-arm -funwind-tables -finline-limit=64 -fsigned-char -no-canonical-prefixes -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -fdata-sections -ffunction-sections -Wa,--noexecstack -mthumb -fomit-frame-pointer -fno-strict-aliasing -O3 -DNDEBUG -isystem /usr/local/bin/android-ndk/platforms/android-15/arch-arm/usr/include -isystem /usr/local/bin/android-ndk/sources/cxx-stl/gnu-libstdc++/4.9/include -isystem /usr/local/bin/android-ndk/sources/cxx-stl/gnu-libstdc++/4.9/libs/armeabi-v7a/include -isystem /usr/local/bin/android-ndk/sources/cxx-stl/gnu-libstdc++/4.9/include/backward -I/usr/local/bin/android-ndk/sources/android/cpufeatures -I/usr/local/bin/android-ndk/sources/android/native_app_glue -ICore/Artifacts/Android -IApplications/Survey/Source -ICore/UI/. -ICore/UI/Source -ICore/ThirdParty/PowerVR/sdk/Include -ICore/ThirdParty/PowerVR/tools/include -ICore/ThirdParty/PowerVR/tools/include/OGLES2 -ICore/ThirdParty/boost/include -ICore/ThirdParty/openssl/include -ICore/ThirdParty/sqlite/include -ICore/WebServices/Source -std=gnu++14 -MMD -MT Applications/Survey/CMakeFiles/Survey.dir/Source/View/RadioGroup.cpp.o -MF Applications/Survey/CMakeFiles/Survey.dir/Source/View/RadioGroup.cpp.o.d -o Applications/Survey/CMakeFiles/Survey.dir/Source/View/RadioGroup.cpp.o -c Applications/Survey/Source/View/RadioGroup.cpp
Note that I specify -DCMAKE_BUILD_TYPE=Release when I generate.
The -g option is not present in the command line invocation, however the final binary is 19MB:
-rwxrwxr-x 1 bamboo bamboo 19173588 Jul 15 10:30 libzApp.so*
I ran size on it to determine what was making it so huge, but I got this:
$ size libzApp.so
text data bss dec hex filename
7097019 201268 53488 7351775 702ddf libzApp.so
That only accounts for 7mb of data. So I ran this:
$ objdump --debugging libzApp.so | head -25
libzApp.so: file format elf32-little
Contents of the .debug_abbrev section:
Number TAG (0x0)
1 DW_TAG_compile_unit [has children]
DW_AT_producer DW_FORM_strp
DW_AT_language DW_FORM_data1
DW_AT_name DW_FORM_strp
DW_AT_comp_dir DW_FORM_strp
DW_AT_low_pc DW_FORM_addr
DW_AT_entry_pc DW_FORM_addr
DW_AT_ranges DW_FORM_data4
DW_AT_stmt_list DW_FORM_data4
DW_AT value: 0 DW_FORM value: 0
2 DW_TAG_typedef [no children]
DW_AT_name DW_FORM_strp
DW_AT_decl_file DW_FORM_data1
DW_AT_decl_line DW_FORM_data1
DW_AT_type DW_FORM_ref4
DW_AT value: 0 DW_FORM value: 0
3 DW_TAG_base_type [no children]
DW_AT_byte_size DW_FORM_data1
DW_AT_encoding DW_FORM_data1
I think this pretty much confirms that it has debug symbols. Can anyone help me understand why the .so is so large? Assuming it's because of debug symbols, what about the command line invocation would cause this?
EDIT
As suggested in the comments section, running strip on the SO file definitely brings its size down to expected value (basically what we see from the result of the size command). However, why would debug symbols be built into the shared object when I specifically told GCC to not build debug symbols? Am I missing something here?
I can suggest you to use strip to remove the debugging information, eg:
strip libzApp.so
That is not so bad to do that because, for example, Qt's build system qmake always do that in it's install target of resulting Makefile.
By default, compiler always add a relocation information and symbol table into the binary. It also adds a lot of other information which may be stripped out (see link on answer below).
You may also use -s parameter to the compiler:
g++ -s ...
According to the docs:
-s:
Remove all symbol table and relocation information from the executable.
This flag should work exactly as strip. Here is also some similiar answer on stackoverflow.

newlib.h: No such file or directory in ffmpeg

I am getting this error
/AppData/Local/Temp/ffconf.dkWUWsGo.c:1:20: fatal error: newlib.h: No such file or directory
#include <newlib.h>
while compiling for ffmpeg.
check_cpp_condition newlib.h defined _NEWLIB_VERSION check_cpp BEGIN
/tmp/ffconf.dkWUWsGo.c
1 #include
2 #if !(defined _NEWLIB_VERSION)
3 #error "unsatisfied condition: defined _NEWLIB_VERSION"
4 #endif END /tmp/ffconf.dkWUWsGo.c D:/android-ndk-r10b/toolchains/arm-linux-androideabi-4.8/prebuilt/windows/bin/arm-linux-androideabi-gcc
--sysroot=D:/android-ndk-r10b/platforms/android-8/arch-arm/ -D_ISOC99_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -O3 -fpic -DANDROID -DHAVE_SYS_UIO_H=1 -Dipv6mr_interface=ipv6mr_ifindex -fasm -Wno-psabi -fno-short-enums -fno-strict-aliasing -finline-limit=300 -mfloat-abi=softfp -mfpu=vfpv3-d16 -marm -march=armv7-a -march=armv7-a -std=c99 -E -o /tmp/ffconf.BMIcTDua.o /tmp/ffconf.dkWUWsGo.c C:/Users/vmewada/AppData/Local/Temp/ffconf.dkWUWsGo.c:1:20: fatal
error: newlib.h: No such file or directory #include
^ compilation terminated.
From the path you provided, I guess the file is not present there anymore, because the Temp folder is used for temporary files. Probably you opened an archive (.zip, .rar, .tar, .jar), and after you closed it, the temporary files were deleted. Extract the files to a permanent directory from where you can use them.
As far as I understand from the error log you are trying to cross compile FFmpeg for Android, but I am not sure if Android NDK has a prebuilt newlib version shipped with it. You could check the corresponding platform directory in NDK if it has the include or library, but my assumption is that you will have to build newlib for ARM before you can do this. Btw - last time I compiled FFmpeg for Android I didn't have the issues you got - are you using a correct target? Maybe the newlib is imported because of a wrong architecture.

Categories

Resources