I have some native libs and want to build them into NDK package, then release the built NDK package to other developers.
Are there any hints about building the customized NDK package?
I can run "make ndk" based on AOSP r81 source code and get the "ndk" folder under the out/soong directory.
but there are only "platform" and "sysroot" subdirectories only under the out/soong/ndk.
furtherly, I cannot find any zip files like the NDK package released from google website.
Are there any suggestions?
Best regards
I wouldn't recommend doing it that way. Distributing an entire NDK sounds like overkill for distributing your libraries. I think you (and more importantly, your users) would be better served by a more traditional distribution method.
We do have a tool called cdep that can help with this, but the build system integration that it generates isn't idiomatic for CMake, so that may not be your preferred option.
Both CMake and ndk-build have built in mechanisms for importing third-party libraries. https://cmake.org/cmake/help/latest/manual/cmake-packages.7.html documents the CMake approach.
ndk-build's mechanisms for this are currently undocumented (I just filed https://github.com/android-ndk/ndk/issues/998 to remind myself to fix that). It's fairly straightforward though:
You ship a directory with the following layout:
mylib
├── Android.mk
├── include
│ └── mylib
│ └── mylib.h
└── libs
├── arm64-v8a
│ └── libmylib.so
├── armeabi-v7a
│ └── libmylib.so
├── x86
│ └── libmylib.so
└── x86_64
└── libmylib.so
Your Android.mk would be:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libmylib
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_SRC_FILES := libs/$(TARGET_ARCH_ABI)/libmylib.so
include $(PREBUILT_SHARED_LIBRARY)
Your users would then install your package into some package directory (for this example, $PACKAGES) as $PACKAGES/mylib. They would then use this in their Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libfoo
LOCAL_SRC_FILES := foo.cpp
LOCAL_SHARED_LIBRARIES := libmylib
include $(BUILD_SHARED_LIBRARY)
$(call import-add-path,$(PACKAGES))
$(call import-module,mylib)
If you need to support other build systems, consult the documentation for those.
You're probably interested in subscribing to https://github.com/android-ndk/ndk/issues/916. I'm currently working on making distribution of NDK packages easier, it's just still a work in progress.
Related
I'm learning how to use makefiles for complex projects. I got it working but I don't know how to add pre-requisites under certain conditions without specifying them one by one. In this particular case I'm trying to add header files as requisites of objects goals so if any header file is modified, that particular cpp has to be rebuild again and linked with the rest.
After looking for clues on the manual I tried to use some shell scripting but I guess the substitution I'm doing is expanded after checking for dependencies so it does nothing. I have tried to use the $(if ) expression in the requisites too but I ended up moving it just in case it was some kind of conflict with using it inside a static pattern rule.
Some additional notes:
I'm learning the tool so I would prefer to avoid CMake or any kind of utility that builds the makefile for me (I would gladly use the facilities after being sure I can replicate at some degree what they do by myself)
I also prefer to avoid solutions tied to the language I'm using in the example as it should work with any compiler and other kind of files and goals/requisites.
I have the following files in my working directory:
.
├── Makefile
└── src
├── main.cpp
└── somemodule
├── module.cpp
└── module.h
My makefile has to generate the following structure:
.
├── app
├── Makefile
├── obj
│ ├── main.o
│ └── somemodule
│ └── module.o
└── src
├── main.cpp
└── somemodule
├── module.cpp
└── module.h
My current makefile:
APP := app
SRCDIR := src
OBJDIR := obj
OBJS := obj/main.o obj/somemodule/module.o
SRCS := $(OBJS:.o=.cpp)
$(APP): $(OBJDIR) $(OBJS)
g++ $(OBJS) -o $(APP)
$(OBJDIR):
mkdir -p $(patsubst $(SRCDIR)%,$(OBJDIR)%,$(shell tree src -fid --noreport))
$(OBJS): HEADERS += $(if $(shell if [ -e $(#:obj%.o=src%.h) ]; then echo "y"; fi), $(#:obj%.o=src%.h))
$(OBJS): $(OBJDIR)%.o: $(SRCDIR)%.cpp $(HEADERS)
g++ -c $(patsubst $(OBJDIR)%.o,$(SRCDIR)%.cpp,$#) -o $#
.PHONY: clean
clean:
rm -rf $(OBJDIR)
rm $(APP)
trying to add header files as requisites of objects goals so if any header file is modified, that particular cpp has to be rebuild again and linked with the rest doesn't sound complex: that's table-stakes for a good build system, if I understood it correctly.
I don't understand what your syntax of setting HEADERS is trying to do here but there's no way it can work. Please read carefully the introduction to automatic variables in the GNU make manual; in particular this text:
It’s very important that you recognize the limited scope in which automatic variable values are available: they only have values within the recipe. In particular, [...] they cannot be accessed directly within the prerequisite list of a rule.
Luckily I see no need for any of that. Have you considered using dependency generation methods such as the one discussed here?
In response to the requirement you added when you updated the question:
I also prefer to avoid solutions tied to the language I'm using in the example as it should work with any compiler and other kind of files and goals/requisites.
I answered:
There is no way to do this only using only make because make doesn't know how to parse your code, and so it can't figure out what the dependencies of a source file are. Similarly, you can't do it in a generic way for all different languages because different languages use different syntax for declaring dependencies. If you want to have automatic dependency tracking, and not do it by hand, you must have SOME tool that can parse your source to find the dependencies. You can use GCC or makedepend or even some fancy shell script if you don't need it to be too accurate.
I want to run Vulkan on my android phone, and currently, I'm stuck at the point trying to make CMake find the libshaderc.
What I did is first build the shaderc:
cd <my-ndk-root>/sources/third_party/shaderc
../../../ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk APP_STL:=c++_static APP_ABI=all NDK_TOOLCHAIN_VERSION:=clang libshaderc_combined -j16
And inside my CMakeLists.txt, I have:
get_filename_component(SHADERC_SRC
${ANDROID_NDK}/sources/third_party/shaderc
ABSOLUTE)
add_library(shaderc_lib STATIC IMPORTED)
set_target_properties(shaderc_lib PROPERTIES IMPORTED_LOCATION
${SHADERC_SRC}/libs/${ANDROID_STL}/${ANDROID_ABI}/libshaderc.a)
But the CMake can't find the shaderc_lib, and failed with error:
CMake Error: The following variables are used in this project, but they are set to NOTFOUND.
Please set them or make sure they are set and tested correctly in the CMake files:
shaderc_lib
Please note that I already checked that I have libshaderc.a under the [my-ndk-root]/sources/third_party/shaderc/libs:
.
└── c++_static
├── arm64-v8a
│ └── libshaderc.a
├── armeabi-v7a
│ └── libshaderc.a
├── x86
│ └── libshaderc.a
└── x86_64
└── libshaderc.a
5 directories, 4 files
I'm not very familiar with CMake and NDK, so if I made some stupid mistakes, please correct me. Thanks in advance!
Make sure your CMake path points to the correct place. Also, your libshaderc.a is static library and you need to link it to your shared lib, e.g. libshaderc-shared.so using below CMake configuration:
target_link_libraries( libshaderc-shared
[my-ndk-root]/sources/third_party/shaderc/libs/c++_static/${ANDROID_ABI}/libshaderc.a )
References:
Here is the guide for how to properly build shaderc https://github.com/google/shaderc.
https://developer.android.com/ndk/guides/graphics/shader-compilers
I am busy learning Vulkan as well, and the only help I can currently provide is the vulkan samples. They work on an android device which supports vulkan. I am using a nokia scirocco 8 as my test device. Have a look at the CMakeLists.txt in the samples as to how to link the shaderc static library. https://github.com/googlesamples/vulkan-basic-samples/
I have a project structure as follows. All I want to do is build a static library with SQLite source but for some reason when I run ndk-build, it builds other source too - as if it is including Android.mk files in other locations.
jni/SQLite
jni/SQLite/Android.mk (the only .mk file that I want to build)
jni/TT
jni/Application.mk
jni/Android.mk (for building everything such as SDL2)
TT is a symbolic link to /work/TT which contains a number of cross-platform source files including SQLite, SDL2 and other source.
/work/TT
/work/TT/SQLite
/work/TT/SQLite/sqlite3.c
/work/TT/SDL2
..
Here is jni/SQLite/Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
TT_PATH := /work/TT
SRC_SQLITE := $(TT_PATH)/SQLite/sqlite3.c
LOCAL_C_INCLUDES += $(NDK_APP_PROJECT_PATH)/jni
LOCAL_MODULE := SQLite
LOCAL_SRC_FILES := $(SRC_SQLITE)
include $(BUILD_STATIC_LIBRARY)
Why are other files being built? What do I need to do to build SQLite only?
At the command prompt I am in the following folder:
jni/SQLite
I run ndk-build (same folder as the Android.mk contents above)
I expect to see sqlite3.c being the only file compiled. But no, I see all of the SDL2 project files being built..
Once all files have been compiled, if I run ndk-build again I see this:
MacbookPro:SQLite admin$ ndk-build
[armeabi-v7a] Install : libSDL2.so => libs/armeabi-v7a/libSDL2.so
[armeabi-v7a] Install : libmain.so => libs/armeabi-v7a/libmain.so
This clearly shows modules SDL2 and main being built.. but why?
Perhaps I am supposed to use:
ndk-build -f Android.mk
..to build my one and only desired Android.mk instead of automatically having my jni folder searched/built?
When I do that I get the following error but at least it looks as though it is trying to run the one specific Android.mk:
MacbookPro:SQLite admin$ ndk-build -f Android.mk
Android NDK: Trying to define local module 'SQLite' in Android.mk.
Android NDK: But this module was already defined by /Work/TT/android-TT/app/src/main/jni/SQLite/Android.mk.
/Android/android-ndk-r9d/build/core/build-module.mk:34: *** Android NDK: Aborting. . Stop.
My Application.mk is as follows but this is not present in the SQLite folder where I run ndk-build, this is the jni/Application.mk:
# Uncomment this if you're using STL in your project
# See CPLUSPLUS-SUPPORT.html in the NDK documentation for more information
APP_STL := gnustl_static
APP_PLATFORM := android-14
APP_ABI := armeabi-v7a
UPDATE: I tried:
ndk-build -d -f Android.mk
..and the debug output shows that the SDL2/Android.mk and other .mk files are still being called. How do I stop this recursive behaviour so it only builds the Android.mk in the current folder?
This is a snippet of the debug output that I see:
Reading makefile `/Work/TT/android-TT/app/src/main/jni/SDL/Android.mk' (search path) (no ~ expansion)...
Reading makefile `/Work/TT/android-TT/app/src/main/obj/local/armeabi-v7a/objs/main/SQLite/sqlite3.o.d' (search path) (don't care) (no ~ expansion)...
The answer to my problem is to do this:
ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk
This will build the current folder Android.mk as required.
I have two native modules to be build as shared library. Both the modules have dependecy on some other common modules.
I am giving the dependecy in Android.mk file using "PREBUILT_SHARED_LIBRARY", but the problem is the libraries specified with "PREBUILT_SHARED_LIBRARY" will get copied to libs/armeabi folder too.. :(
When I include their respective .jars in the main application it throws an eror saying duplicate copy of libraries..
I have to solve this problem by linking the common libraries in ndk build without using "PREBUILT_SHARED_LIBRARY" so that it will not copy the all dependent libraries to libs/areabi.
Can anybody please tell me how can I resolve this problem ? I have googled about this, but everywhere I see the answer use "PREBUILT_SHARED_LIBRARY" to link with already built shared libraries.
Your prebuilt's Android.mk is probably wrong, if you do something like this
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := mygreatlibrary-prebuilt
MY_LIBRARY_NAME := myGreatLibrary
### export include path
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
### path to library
LOCAL_SRC_FILES := libs/$(TARGET_ARCH_ABI)/lib$(MY_LIBRARY_NAME).so
### export dependency on the library
LOCAL_EXPORT_LDLIBS := -L$(LOCAL_PATH)/libs/$(TARGET_ARCH_ABI)/
LOCAL_EXPORT_LDLIBS += -l$(MY_LIBRARY_NAME)
include $(PREBUILT_SHARED_LIBRARY)
Then the correct library will be copied to the correct place
I want to build a static library link to a third_part static library. And then provide the static library which I built to other people to use. But when others use my library, they found an error "undefined reference to 'Func1()'", "Func1()" is a function defined in the third_part static library. Does anyone have an idea how to fix it?
Here's my Android.mk:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := ThirdLib_Rebuild
LOCAL_SRC_FILES := libThird.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := MyLib
LOCAL_STATIC_LIBRARIES := ThirdLib_Rebuild
LOCAL_SRC_FILES := MyLib.c
include $(BUILD_STATIC_LIBRARY)
ndk-build supports transitive dependencies, i.e. if you define a shared library or executable that depends on your MyLib module, then both libMyLib.a and libThird.a will be linked into it (if not, this is a bug, which NDK are you using exactly?).
However, you're not very clear about what you're doing when distributing your libraries to other people. For the record, you need to distribute both libraries to your users, because libMyLib.a does not include the code from libThird.a, the use of LOCAL_STATIC_LIBRARIES in the MyLib module definition only serves to record a dependency between the two libs, unlike what happens when you use it for a shared library or executable.