所以我有一个庞大的现有C项目,我放在$PROJECT/jni
目录中。该项目通常通过运行configure脚本来创建,该脚本创建Makefile,然后允许通过make
编译项目。
这个项目相当大,有很多包含源文件和头文件的目录。
我想我错过了Android.mk
应该如何运作的基本理解。是否应该替换当前用于编译项目的configure和makefile?或者我是否将生成的makefile从我的配置脚本合并到Android.mk
?他们提供的示例相当简单,只有少量源文件。我的jni
目录看起来更像:
jni/
folder1/subfolder1
folder1/subfolder2
folder1/source
folder2/source
.....
foldern/source
configure/
configure/configure.sh
Makefile
Android.mk
生成的makefile非常广泛(配置量很大,每个目录中都有一个)所以我很少迷失方法。
编辑:
主要问题是NDK附带的示例是微不足道的例子。它们在顶级jni目录中有3-5个源文件。我的问题是,这是一个庞大的项目,配置复杂,有4个顶级文件夹,每个文件夹都有许多子目录。我不能简单地将源移动到jni文件夹并运行ndk编译器。
答案 0 :(得分:13)
要回答您的问题,是Android.mk
是 Android构建系统。谷歌几乎没有提到这个文件的“语言”是作为GNU make宏实现的。文档希望您根据这些宏描述您的项目。它们处理所有蹩脚的交叉编译细节。我非常确定Google已经采用这种方法来改进Android.mk
文件的前向可移植性,因为开发工具不断发展。
结果是(我知道你不想听到这个)最好的答案可能就是从头开始为你的大项目编写一个合适的NDK Android.mk
。
This article列出了我移植大约800个文件和300k SLOC的库的相同观察结果。不幸的是,我烧了差不多两个星期才得出相同的结论:交叉编译导致至少一些configure
脚本失败(导致错误的config.h
文件)。我“发明”了他在文章中使用的几乎相同的技术。但即使我得到一个干净的构建,生成的静态库也无法完全运行。调试时间没有获得有用的信息。 [警告:我不是配置工具专家。大师可能会发现我的错误。所以它。我花了几天时间来创建一个干净的Android.mk
。生成的库首次运行所有测试。它已通过几次开发工具的清晰移植。
不幸的是,在没有自动工具的情况下构建使用configure
的库意味着为目标环境手动构建自己的config.h
。这可能没有听起来那么糟糕。 IME系统倾向于在configure
环境中定义比实际使用更多的内容。清楚地了解真正的依赖关系可能会在未来的重构过程中回报繁琐的工作。
文章中的摘要声明说明了一切:
Autotool仅适用于GNU系统,使用它进行交叉编译可能非常繁琐,令人困惑,容易出错甚至无法实现。这里描述的方法是一个黑客,应该由您自己承担风险。
对不起,我没有更积极的建议。
答案 1 :(得分:5)
我的答案最适合Gene的答案。
./configure
创建配置文件是基于为每个测试编译(并可能运行)C
代码的小片段。每个测试的成功都会在config.h.in
模板中设置相应的变量以创建config.h
。可以在交叉编译环境中成功测试仅编译测试。但是,编译和运行测试无法在交叉编译环境中运行。
因此,要开始转换过程,您需要将环境变量CPP
,CC
,LD
和其他工具别名设置为交叉编译器工具集(可能是来自NDK
的那些,然后运行./configure
。完成此操作后,您需要更正config.h
以匹配您的目标环境。 这是您最关键且最容易出错的一步。
对于Android.mk
,它遵循非常接近Makefile.am
的格式,可以很容易地转换为它。您可以忽略Makefile.in
和Makefile
,因为它们是从Makefile.am
生成的。
以file(版本5.11)为例,我使用以下选项运行configure,
./configure --host arm-toshiba-linux-androideabi --build x86_64-linux-gnu \
--prefix=/data/local/ host_alias=arm-linux-androideabi \
"CFLAGS=--sysroot=~/ndk/platforms/android-8/arch-arm -Wall -Wextra" \
"CPPFLAGS=--sysroot=~/ndk/platforms/android-8/arch-arm" \
CPP=arm-linux-androideabi-cpp
下一步是采用src/Makefile.am
,如下所示:
MAGIC = $(pkgdatadir)/magic
lib_LTLIBRARIES = libmagic.la
include_HEADERS = magic.h
bin_PROGRAMS = file
AM_CPPFLAGS = -DMAGIC='"$(MAGIC)"'
AM_CFLAGS = $(CFLAG_VISIBILITY) @WARNINGS@
libmagic_la_SOURCES = magic.c apprentice.c softmagic.c ascmagic.c \
encoding.c compress.c is_tar.c readelf.c print.c fsmagic.c \
funcs.c file.h readelf.h tar.h apptype.c \
file_opts.h elfclass.h mygetopt.h cdf.c cdf_time.c readcdf.c cdf.h
libmagic_la_LDFLAGS = -no-undefined -version-info 1:0:0
if MINGW
MINGWLIBS = -lgnurx -lshlwapi
else
MINGWLIBS =
endif
libmagic_la_LIBADD = $(LTLIBOBJS) $(MINGWLIBS)
file_SOURCES = file.c
file_LDADD = libmagic.la
CLEANFILES = magic.h
EXTRA_DIST = magic.h.in
HDR= $(top_srcdir)/src/magic.h.in
BUILT_SOURCES = magic.h
magic.h: ${HDR}
sed -e "s/X.YY/$$(echo @VERSION@ | tr -d .)/" < ${HDR} > $@
从此创建Android.mk
。
最后也是最重要的一步是修改config.h
以准确反映目标系统的状态。这将是一个手动过程,我无法给出解决方法,主要涉及查看configure.log,查看标题和“调用”Google。这项工作的成果可用on XDA。
答案 2 :(得分:4)
这是一个以相反方式做事的解决方案:构建 标准Makefile中的外部库和Android包。
作为先决条件,您需要安装执行命令行所需的所有操作 Android开发:
示例的结构是:外部库的目录 以及与Makefile在同一级别的Android源目录 在每个目录和顶级递归Makefile:
Makefile
mylib/
Makefile
android/
Makefile
mylib/Makefile
构建一个静态库:
AR=/path/to/standalone/bin/arm-linux-androideabi-ar
CC=/path/to/standalone/bin/arm-linux-androideabi-gcc
libmylib.a: mylib.o
$(AR) rcs libmylib.a mylib.o
mylib.o: mylib.c
$(CC) -c mylib.c -o mylib.o
android/Makefile
正在提供构建Android程序包的规则:
mylib
; jni/ndkmake.c
文件将调用包装到mylib
并提供特定于Android的内容; Makefile提供两个目标:release
(默认值)和debug
来构建发布包或调试包。
NDK_BUILD=/path/to/ndk-build
JAVASRC=src/com/example/ndkmake/NdkMake.java
release: bin/NdkMake-release-unsigned.apk
debug: bin/NdkMake-debug.apk
bin/NdkMake-release-unsigned.apk: libs/armeabi/libndkmake.so $(JAVASRC)
ant release
bin/NdkMake-debug.apk: libs/armeabi/libndkmake.so $(JAVASRC)
ant debug
libs/armeabi/libndkmake.so: jni/ndkmake.c jni/libmylib.a
$(NDK_BUILD)
jni/libmylib.a: ../mylib/libmylib.a
cp ../mylib/libmylib.a jni/libmylib.a
Android.mk
文件提供了在构建中包含静态库的规则,作为预构建。
我们使用mylib
包含LOCAL_EXPORT_C_INCLUDES
库中的标题。
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := ndkmake
LOCAL_SRC_FILES := ndkmake.c
LOCAL_STATIC_LIBRARIES := mylib-prebuilt
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := mylib-prebuilt
LOCAL_SRC_FILES := libmylib.a
LOCAL_EXPORT_C_INCLUDES := ../mylib/
include $(PREBUILT_STATIC_LIBRARY)
现在我们只需要一个顶级Makefile来构建两个子目录:
all: libmylib package
libmylib:
cd mylib && $(MAKE)
package:
cd android && $(MAKE)
对库,jni源或Java源的任何更改都将触发重建 包裹。