【问题标题】:How to incorporate existing make file with Android NDK如何将现有的 make 文件与 Android NDK 合并
【发布时间】:2013-06-25 11:27:13
【问题描述】:

所以我有一个巨大的现有 C 项目,我已将其放置在 $PROJECT/jni 目录中。这个项目通常是通过运行一个配置脚本来创建的,该脚本创建 Makefiles 然后允许通过make 编译项目。

这个项目比较大,有很多包含源文件和头文件的目录。

我想我在这里缺少对 Android.mk 应该如何工作的基本理解。是否应该替换当前用于编译项目的配置和生成文件?或者我会将配置脚本中生成的 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 编译器。

【问题讨论】:

    标签: android c android-ndk makefile


    【解决方案1】:

    要回答你的问题,是的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 系统,使用它进行交叉编译可能非常乏味、令人困惑、容易出错甚至是不可能的。此处描述的方法是一种黑客攻击,使用时应自担风险。

    抱歉,我没有更积极的建议。

    【讨论】:

    • 我完全同意你的看法。从config.h.in 生成config.h 在交叉编译环境中是不可能的。但是,本机运行配置 might possibly 工作,但这是另一回事:)。
    【解决方案2】:

    我的回答与Gene 的回答配合使用效果最好。

    ./configure 的配置文件的创建是基于为每个测试编译(并可能运行)C 代码的小 sn-ps。每个测试的成功都会在config.h.in模板中设置一个对应的变量来创建config.h。仅编译测试可以在交叉编译环境中成功测试。但是,编译运行测试不可能在交叉编译环境中运行。

    因此,要开始转换过程,您需要将环境变量 CPPCCLD 和其他工具别名设置为交叉编译器工具集(可能来自 @ 987654331@) 然后运行./configure。完成此操作后,您需要更正 config.h 以匹配您的目标环境。 这是您最关键且最容易出错的步骤。

    至于Android.mk,它的格式非常接近Makefile.am,可以很容易地转换成它。您可以忽略Makefile.inMakefile,因为它们是从Makefile.am 生成的。

    file(5.11 版)为例,我使用以下选项运行配置,

    ./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 获得。

    【讨论】:

      【解决方案3】:

      这里有一个相反的解决方案:构建 来自标准 Makefile 的外部库和 Android 包。

      作为先决条件,您需要安装执行命令行所需的一切 安卓开发:

      • 独立工具链,请参阅 Android NDK 中包含的文档;
      • 蚂蚁。

      例子的结构是:外部库的目录 以及与 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 的内容;
      • android 包依赖于 Java 源和共享库。

      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 文件提供了在构建中包含静态库作为预构建的规则。 我们使用LOCAL_EXPORT_C_INCLUDES 包含来自mylib 库的标头。

      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 源的任何更改都将触发重建 包的。

      【讨论】:

      • 感谢您的建议。您能否澄清几点:1)您所说的“为 NDK 东西添加构建规则”是什么意思?什么构建规则?您的意思是通常在 Android.mk 文件中指定的命令? 2) 我在哪里可以找到有关此独立工具链的信息?谢谢!
      • 您可以在 NDK 附带的文档中找到有关独立工具链的更多信息,这里有一个在线副本:kandroid.org/ndk/docs/STANDALONE-TOOLCHAIN.html 至于 NDK 的构建规则,我的意思是保留 Android.mk,但是从你的 Makefile 运行 ndk-build(见我的例子)
      • 我可以直接链接到已编译的 c 对象吗?例如,如果我现在在我的 c 软件上进行 make,它将输出 3 个.so 文件。有没有办法使用链接到库文件中对象的 JNI 方法制作 C 文件?
      • 我试过了,但没能成功,这就是为什么我建议构建一个静态库 (.a) 并将该静态库作为预构建的。
      • 只是想我会让你知道我提供 500 代表赏金以获得非常详细的答案,以防你想参与其中。
      猜你喜欢
      • 1970-01-01
      • 2019-12-05
      • 1970-01-01
      • 1970-01-01
      • 2012-09-01
      • 2022-11-17
      • 1970-01-01
      • 2020-07-30
      • 1970-01-01
      相关资源
      最近更新 更多