GMAKE: force prerequisite rule dependency of all c/cpp files (android NDK) - android-ndk

How can I add prerequisite rule for all source files (c/cpp)? It would be simple if entire make file was done by me, but I use android build system that hides most of the stuff from me.
The reason I want to do it:
I added a rule to generate my header file which is included by some c/cpp files. It works well as long as dependencies are already generated. However, with a clean project there is no dependency info available before compilation and as a result make won't run my rule for a clean project because it doesn't know that certain cpp file depends on a header file that doesn't exist yet. That's why I need to add some kind of rule to ensure that my prerequisite rule runs before any compilation takes place.
So far, I did this:
include $(CLEAR_VARS)
.PHONY: ForceRule
MyHeader.h: ForceRule
ForceRule: CreateHeader.sh
$(shell CreateHeader.sh MyHeader.h)
# below is standard android way to build shared lib from cpp files:
LOCAL_SRC_FILES: File1.cpp File2.cpp
LOCAL_PATH := $(CURDIR)
include $(BUILD_SHARED_LIBRARY)

It's hard to be sure with black-box makefiles (and I think your approach is wrong), but you could try this:
MyHeader.h: CreateHeader.sh
$(shell CreateHeader.sh MyHeader.h)
%.o: %.cpp MyHeader.h

Related

Why Makefile.am is included in the release tarball?

From the description of https://stackoverflow.com/a/2531841/5983841 and https://stackoverflow.com/a/26832773/5983841 , my understanding is that Makefile.am is not needed in the dist tarball.
I tried
wget https://dist.libuv.org/dist/v1.44.2/libuv-v1.44.2-dist.tar.gz
tar xf libuv-v1.44.2-dist.tar.gz
cd libuv-1.44.2/
mv Makefile.am Makefile.am.bak
./configure
make
it gives error when running make:
tian#tian-B250M-Wind:~/Desktop/playground/garage/libuv-1.44.2$ make
make: *** No rule to make target 'Makefile.am', needed by 'Makefile.in'. Stop.
I answered there: autotools are intended to be used with free software. A dist tarball for a free software project should include all the files needed for someone to be able to make changes to the project and rebuild it, as they want to: that's the foundational goal of Free Software.
They can't do that if you omit critical build files, like Makefile.am. If they wanted to add a new file or something to the project, they need the Makefile.am to modify it. So it should be included in the dist tarball.
Saying that the file is not required in order to build the software as-is without modification, is not the same thing as saying that it can be omitted.
In this specific case, automake-generated makefiles contain rules to check whether someone modified the Makefile.am file and if so, the rules will re-run automake to ensure everything is up to date and correct so you don't have to remember to do it by hand. However this of course requires that the Makefile.am file be present so make can determine that it's up to date.

Building shared FFTW library for Android

I am trying to build a shared library of FFTW by means of the following script:
INSTALL_DIR="`pwd`/jni/fftw3"
SRC_DIR="`pwd`/../fftw-3.3.4"
cd $SRC_DIR
NDK_ROOT=/path_to_android/Sdk/ndk-bundle
export PATH="$NDK_ROOT/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/:$PATH"
export SYS_ROOT="$NDK_ROOT/platforms/android-21/arch-arm/"
export CC="arm-linux-androideabi-gcc --sysroot=$SYS_ROOT"
export LD="arm-linux-androideabi-ld"
export AR="arm-linux-androideabi-ar"
export RANLIB="arm-linux-androideabi-ranlib"
export STRIP="arm-linux-androideabi-strip"
mkdir -p $INSTALL_DIR
./configure --enable-shared --host=arm-eabi --build=i386-linux --prefix=$INSTALL_DIR LIBS="-lc -lgcc" --enable-float
make
make install
exit 0
However, after executing the script I always only receive a static FFTW library even though I am using the enable-shared parameter. Is there any other way to generate the shared library file?
I really need a shared library since Android Studio demands a shared library to compile additional JNI sources.
Update:
Based on #bullsy's answer, I could build the shared library by chaning the host parameter to --host=arm-linux-androideabi. The resulting problem is that FFTW generates a versioned shared library with library files libfftw.so.3 and libfftw.so.3.4.4. I found a tutorial that shows how to convert these files into .so files. While working on libfftw3.so or libfftw3.so.3, I always received the error that file is not a (regular) file so I tried everything on libfftw3.so.3.4.4:
rpl -R -e libfftw3.so.3 libfftw3_3.so libfftw3.so.3.4.4
mv libfftw3.so.3.4.4 libfftw3_344.so
ln -sfn libfftw3_344.so libfftw3.so.3
mv libfftw3.so.3 libfftw3_3.so
I had to add the ln command manually. Without changing the symlink, Gradle could not find libfftw3_3.so during the building process of the apk.
So my application is running now with the shared libs but it is also possible to generate shared FFTW libs with single precision (-enable-float)?
Another approach was to take the static library file and to build a shared library file by means of an Android.mk and ndk-build:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := fftw3
LOCAL_SRC_FILES := fftw3/lib/libfftw3.a
include $(PREBUILT_STATIC_LIBRARY)
LOCAL_MODULE := fftw_wrapper
LOCAL_C_INCLUDES := /path_to_fftw_headers/include
LOCAL_C_INCLUDES += /pat_to_wrapper/fftw_wrapper.h
LOCAL_SRC_FILES := fftw_wrapper.cpp
LOCAL_SHARED_LIBRARIES := fftw3f
include $(BUILD_SHARED_LIBRARY)
But this approach always returns undefined reference errors, e.g. undefined reference to 'fftw_malloc'. I have also tried it without the --build parameter as it is explained in this question: Using FFTW on Android undefined references
Whenever I use the static library, my application runs fine, even when I statically link the fftw_wrapper in the Android.mk. However, since my C/C++ imports are all defined in the app Gradle file of Android Studio, I do not want to change back to Android.mk files. Is there any other solution?
Try using
--host=arm-linux-androideabi
instead. This tells configure 'Hey, I'm building for a linux variant', which makes shared libraries the default choice.

Android NDK: how to build and then use a prebuilt library

I have read many posts on how to share prebuilt libraries using the Android.mk system. The solutions boil down to two steps:
A directory with the already-built library uses *include $(PREBUILT_SHARED_LIBRARY)*
The project consuming the library uses *LOCAL_SHARED_LIBRARIES*
(you can substitute "STATIC" for "SHARED" to build and use a .a instead of a .so)
What I am trying to do is add a step 0: build the library from sources. If I change a source file that contributes to the library I want the Android.mk system to execute steps 0, 1, and 2 in order.
I have two projects in Eclipse/ADT:
MyApp - uses MyLibrary
MyLibrary - contains the source files for the library
The question I'm asking here focuses on MyLibrary project. Here is the Android.mk for MyLibrary:
LOCAL_PATH := $(call my-dir)
# step 0: build my library
include $(CLEAR_VARS)
LOCAL_MODULE := mylibrary
LOCAL_LDLIBS := -llog
LOCAL_SRC_FILES := libsrc1.c libsrc2.c
include $(BUILD_SHARED_LIBRARY)
# step 1: export my library (PREBUILT_SHARED_LIBRARY):
include $(CLEAR_VARS)
LOCAL_MODULE := mylibrary-prebuilt
LOCAL_SRC_FILES := ../libs/$(TARGET_ARCH_ABI)/libmylibrary.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
include $(PREBUILT_SHARED_LIBRARY)
If I do a project->clean... and then a project->build project in this project I get the error:
ERROR:jni/Android.mk:mylibrary-prebuilt: LOCAL_SRC_FILES points to a missing file.
The clean removes the .so and I'm guessing PREBUILT_SHARED_LIBRARY detects the missing .so before BUILD_SHARED_LIBRARY rebuilds the library and copies it (even though the steps are in the correct order).
If I comment out step 1 and build, libmylibrary.so is correctly built and copied to libs/armeabi/libmylibrary.so. If I then uncomment step 2 and do a project->build project, that is without doing a clean first, I get these warnings and error:
warning: overriding commands for target `obj/local/armeabi/libmylibrary.so'
warning: ignoring old commands for target `obj/local/armeabi/libmylibrary.so'
warning: overriding commands for target `libs/armeabi/libmylibrary.so'
warning: ignoring old commands for target `libs/armeabi/libmylibrary.so'
make: *** No rule to make target `jni/../libs/armeabi/libmylibrary.so', needed by `obj/local/armeabi/libmylibrary.so'. Stop.
I think I understand these errors, but I do not see a way to accomplish what I want.
What am I missing?
You can simply avoid step 1 entirely and just rebuild the library from sources. I'm not sure I understand the benefits of having the three steps your describe. Feel free to clarify.
In all cases, your analysis of ndk-build's behaviour is spot on, and all of this is completely intentional.
The NDK itself provides several prebuilt libraries and allows you to rebuild them from sources if you want. For example, if you look at sources/cxx-stl/stlport/Android.mk, you will see that a variable (STLPORT_FORCE_REBUILD) is used to control whether to use the prebuilt binaries, or rebuild them from sources.
Maybe using a similar method for your project would work.

Add pre-build step to android ndk-build module for header dependency?

Basically, what I'd like to do in an Android.mk file is:
LOCAL_MODULE := foo
$(LOCAL_MODULE): pre-build
pre-build:
#echo HI
.PHONY: pre-build
# ...
include $(BUILD_SHARED_LIBRARY)
The ndk-build system does work for ndk-build foo, and the pre-build step works, but if you use this library in an application, it won't do the pre-build step.
In particular, I'm trying to generate a header file (with version/date stamps etc) that is placed in the path that is used in LOCAL_EXPORT_C_INCLUDES such that modules that consume the library can enjoy the header file.
Here's what I've done, as a bit of a hack.
It seems you can add a post-build step, fairly easily, but not a pre-build step.
After you include the build process, you can add a dependency to $(LOCAL_BUILT_MODULE) which will effectively be a post-build process that is always executed.
include $(BUILD_SHARED_LIBRARY)
$(LOCAL_BUILT_MODULE): post_build
post_build:
$echo Hi, I'm post-build.
If you need to be fancy and use, for example, things on your $(LOCAL_PATH), then
include $(BUILD_SHARED_LIBRARY)
$(LOCAL_BUILT_MODULE): post_build
define gen_post_build
post_build:
$(hide) python $(1)/MyScript.py
endef
$(eval $(call gen_post_build,$(LOCAL_PATH)))
Here's a way I found to do a pre-build step when building a dynamic library for one or more architectures (ABIs). This may not work in all situations.
Create an Application.mk file (if you don't have one already) with the following:
all: pre_build
pre_build:
echo "This is the pre-build"
Note that using 'all' as above ends up doing a pre-build in Application.mk, and a post-build in Android.mk.

Android NDK - problem linking an external library (can't found it)

I am working with Android NDK r6b under cygwin (the system is updated correctly). I am modifying the hello-jni sample in order to learn working with NDK. Since i have a library written in C++ that i wish to use in the hello-jni (actually, i have created a prj called helloworld with a single .cpp file called ndkfoo.cpp) sample, i created a new Android project in Eclipse (updated for Android), added a jni directory, added a Android.mk and Application.mk files, edited them in order to compile the .cpp. At the end of the compilation, i obtain a .so file.
Now, in the helloworld Android.mk, i need to make some edits in order to tell the linker to include that library. Suppose the library file is libmylib.so, i have the following android.mk script:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := ndkfoo
LOCAL_SRC_FILES := ndkfoo.cpp
LOCAL_C_INCLUDES += $(LOCAL_PATH)/mylib
LOCAL_LDLIBS += -L$(LOCAL_PATH)/../../mylib/libs/armeabi/ -lmylib
include $(BUILD_SHARED_LIBRARY)
My directories are organized in the following way:
d:/android/android-ndk-r6b => android ndk root
d:/android/workspace/helloworld => helloworld project
d:/android/workspace/mylib => mylib project library
(therefore, the path to libmylib.so is: d:/android/workspace/mylib/libs/armeabi).
Unfortunately, this doesn't seems to work. If i remove every reference to mylib from ndkfoo.cpp, it compiles and run even on my phone. If i do not remove references to mylib, it compiles but doens't link: i obtain the following result:
D:/android/android-ndk-r6b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windo
ws/bin/../lib/gcc/arm-linux-androideabi/4.4.3/../../../../arm-linux-androideabi/
bin/ld.exe: cannot find -lmylib
Ps.
I forgot to mention that i run ndk-buld under the jni directory of the helloworld project.
Pss.
I have found a lot of similar questions over the internet. I have always worked with Visual C/C++ IDE, so i am really new to GCC, makefiles and so on...
The message
D:/android/android-ndk-r6b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windo ws/bin/../lib/gcc/arm-linux-androideabi/4.4.3/../../../../arm-linux-androideabi/ bin/ld.exe: cannot find -lmylib
is indicating you that the linker is not finding your library, this should come from a problem in the LD_LIBS' path.
I think that my-dir macro does not include devices' unit identifier so, your LOCAL_PATH variable should miss the D: and, I think, won't work with cygwin. I'm a Linux user and I'm not 100% sure but, if you replace
LOCAL_PATH := $(call my-dir)
by
LOCAL_PATH := D:$(call my-dir)
it should work. On the other hand you can always set the relative path by setting:
LOCAL_LDLIBS += -L$../../mylib/libs/armeabi/ -lmylib

Resources