【问题标题】:Android.mk: How to check if a module already existsAndroid.mk:如何检查模块是否已存在
【发布时间】:2016-10-20 15:48:47
【问题描述】:

我正在尝试为现有构建环境自动生成 Android.mk 文件。这个环境有许多相互链接的库,也可能链接到第 3 方库(如 boost)。

假设我有 libA 使用 boost。 我的目标是通过从 libB 文件夹运行 ndk-build 来构建 libAlibB

所以我为libA 生成了这个Android.mk:

LOCAL_PATH := $(call my-dir)

# Import boost
include $(CLEAR_VARS)
LOCAL_MODULE    := boost_atomic
LOCAL_SRC_FILES := ../dev/libcpp/boost/1.60.1/lib/libboost_atomic.a
include $(PREBUILT_STATIC_LIBRARY)

# libA:
include $(CLEAR_VARS)
LOCAL_MODULE    := libA
LOCAL_SRC_FILES := libA.cpp
LOCAL_C_INCLUDES := ../dev/libcpp/boost/1.60.1

# boost import:
LOCAL_CPPFLAGS += -DHAVE_CONFIG_H -fexceptions -frtti
LOCAL_STATIC_LIBRARIES += boost_atomic

# build libA:
include $(BUILD_SHARED_LIBRARY)

现在我有libB 使用boostlibAlibBAndroid.mklibA 非常相似,只是我添加了libA 文件的导入,如下所示:

# Import libA
include $(CLEAR_VARS)
LOCAL_MODULE := libA
include ../../libA/jni/Android.mk

当我尝试制作libB 时,我被举报了:

Android NDK: Trying to define local module 'boost_atomic' in ../../libA/jni/Android.mk.
Android NDK: But this module was already defined by ../../libA/jni/Android.mk.
B:/Android/android-ndk-r11b/build//../build/core/build-module.mk:34: *** Android
 NDK: Aborting.    .  Stop.

有没有办法让我检查boost_atomic 是否已经定义(如if (exists boost_atomic))以确保它只被定义一次?或者我应该为所有名称添加后缀(以boost_system_for_libAboost_system_for_libB 结尾)以防止冲突?还是有其他选择?

【问题讨论】:

  • 可以避免模块的重复定义,但在您的情况下,为了提升,简单地添加 LOCAL_LDLIBS += ../dev/libcpp/boost/1.60.1/lib/libboost_atomic.a 而不是将其添加为 LOCAL_STATIC_LIBRARIES 会更容易跨度>
  • @AlexCohn:将是一个很好的解决方案。明天试试。我可以对共享库做同样的事情吗?因为我想如果有libC 使用libBlibA,我会遇到同样的问题,libA 最终将被定义两次(由libBlibC 导入)当我编译时libC.
  • 不,这不适用于非预建库,并且无论如何不应在 LDLIBS 中指定共享库。但通常很容易根据子目录的层次结构包含您的 Android.mk 文件。这样可以避免重复。
  • @AlexCohn:谢谢,LOCAL_LDLIBS += ../dev/libcpp/boost/1.60.1/lib/libboost_atomic.a 会给non-system libraries in linkerwarning。如何摆脱这个警告? (简单地尝试了LOCAL_STATIC_LIBRARIES += ../dev/libcpp/boost/1.60.1/lib/libboost_atomic.a,但它不起作用)。
  • 您可以忽略此警告。它仅与共享库相关。

标签: android c++ android-ndk


【解决方案1】:

您有一个 NDK 函数$(modules_get_list)。依靠它,您的 libA/jni/Android.mk 文件可能如下所示:

LOCAL_PATH := $(call my-dir)

include ../../boost/Android.mk

# libA:
include $(CLEAR_VARS)
LOCAL_MODULE    := libA
LOCAL_SRC_FILES := libA.cpp

# boost import:
LOCAL_STATIC_LIBRARIES += boost_atomic

# build libA:
$(if $(call set_is_member,$(modules-get-list),$(LOCAL_MODULE)),\
    ,$(eval include $(BUILD_SHARED_LIBRARY)))

boost/Android.mk文件:

LOCAL_PATH := $(call my-dir)

# Import boost
include $(CLEAR_VARS)
LOCAL_MODULE    := boost_atomic
LOCAL_SRC_FILES := ../dev/libcpp/boost/1.60.1/lib/libboost_atomic.a
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../dev/libcpp/boost/1.60.1
LOCAL_EXPORT_CPPFLAGS += -DHAVE_CONFIG_H -fexceptions -frtti
$(if $(call set_is_member,$(modules-get-list),$(LOCAL_MODULE)),\
    ,$(eval include $(PREBUILT_STATIC_LIBRARY))

最后,libB/jni/Android.mk

LOCAL_PATH := $(call my-dir)

include ../../boost/Android.mk
include ../../libA/jni/Android.mk

# libB:
include $(CLEAR_VARS)
LOCAL_MODULE    := libB
LOCAL_SRC_FILES := libB.cpp

# boost import:
LOCAL_STATIC_LIBRARIES += boost_atomic

# build libA:
$(if $(call set_is_member,$(modules-get-list),$(LOCAL_MODULE)),\
    ,$(eval include $(BUILD_SHARED_LIBRARY)))

我不希望对第 3 方预构建库(如 boost)有重复的定义,而是为每个库使用单独的 Android.mk 定义,并在必要时使用include。这样,如果外部库更新,我就有一个地方可以更改。

更新:如果你不喜欢$(if …) 语法,你可以使用

ifeq ($(filter $(modules-get-list),$(LOCAL_MODULE)),)
    include $(BUILD_…_LIBRARY)
endif

改为。

【讨论】:

  • 很好,我确实设置了自己的变量来跟踪重复定义,但它使代码变得复杂(参见stackoverflow.com/questions/40173692/…)。我会尝试您的解决方案,但仅在几周后(假期回来时)。
  • 没有用。在我做include $(PREBUILT_STATIC_LIBRARY) 之后,我试图打电话给ifndef $(modules_get_list).$(LOCAL_MODULE),这被评估为true。我错过了什么吗?
  • 抱歉,我是$(modules-get-list)。请查看更新后的答案。
  • 谢谢亚历克斯。我怎样才能把它放在一个常规的 if 语句中? ifeq ($(call set_is_member,$(modules-get-list),$(LOCAL_MODULE)),true) 失败,因为 $(call set_is_member,$(modules-get-list),$(LOCAL_MODULE)) 被评估为 T 而不是 true(对不起,我对这些 makefile 语法不是很熟悉。
【解决方案2】:

正如 Alex Cohn 所提到的,人们可以通过替换来解决这个问题:

include $(CLEAR_VARS)
LOCAL_MODULE    := boost_atomic
LOCAL_SRC_FILES := ../dev/libcpp/boost/1.60.1/lib/libboost_atomic.a
include $(PREBUILT_STATIC_LIBRARY)

...

# boost import:
LOCAL_CPPFLAGS += -DHAVE_CONFIG_H -fexceptions -frtti
LOCAL_STATIC_LIBRARIES += boost_atomic

简单地说:

LOCAL_LDLIBS += ../dev/libcpp/boost/1.60.1/lib/libboost_atomic.a

这可行,但是:

  • 引入编译警告:

    警告:/Users/jwalton/Android-CryptoPP/jni/Android.mk:prng: 链接器标志中的非系统库:-lcryptopp -lstlport_shared
    这很可能导致不正确的构建。尝试使用 LOCAL_STATIC_LIBRARIES
    或 LOCAL_SHARED_LIBRARIES 来列出 当前模块

  • 不适用于共享的第三方库

所以我终于解决了这个问题,我添加了一个特定于libAlibB 的新 mk 文件:

libAAndroid.mk 现在是:

LOCAL_PATH := $(call my-dir)

# Import boost
include $(CLEAR_VARS)
LOCAL_MODULE    := boost_atomic
LOCAL_SRC_FILES := ../dev/libcpp/boost/1.60.1/lib/libboost_atomic.a
include $(PREBUILT_STATIC_LIBRARY)

include libA.mk

libAlibA.mk 现在是:

LOCAL_PATH := $(call my-dir)

# libA:
include $(CLEAR_VARS)
LOCAL_MODULE    := libA
LOCAL_SRC_FILES := libA.cpp
LOCAL_C_INCLUDES := ../dev/libcpp/boost/1.60.1

# boost link:
LOCAL_CPPFLAGS += -DHAVE_CONFIG_H -fexceptions -frtti
LOCAL_STATIC_LIBRARIES += boost_atomic

# build libA:
include $(BUILD_SHARED_LIBRARY)

libBlibB.mk 现在有:

# Import libA
include $(CLEAR_VARS)
LOCAL_MODULE := libA
include ../../libA/jni/libA.mk

所以它导入libA而不导入boost(也在libBAndroid.mk中定义)。

然后,没有警告,它编译顺利。

【讨论】:

    【解决方案3】:

    我正在尝试为现有的自动生成 Android.mk 文件 构建环境。这个环境有很多库链接到每个 其他也可能链接到第 3 方库(如 boost)。

    为什么不使用standalone NDK toolchains 而不是痛苦地处理Android.mk 文件?听起来独立工具链非常适合您的情况。

    【讨论】:

    • @jpo38 是的,他们有。 ...对于现有的构建环境... - 似乎您已经有一些 makefile/构建脚本,不是吗?
    • 是的,我正在使用 Visual Studio。它还原生支持 Android 目标,但仅适用于专业版,我使用的是 Express 版...
    • @jpo38 Visual Studio 不是我的最爱,但无论如何我相信即使是 Express 版本也能让您以某种方式使用自定义工具链。也许this answer 会给你一个想法。
    • 我去看看。但是,老实说,从 CMake 手动生成 makefile 并不是什么大问题。我只编写了 100 行 CMake 代码就让它工作了(前段时间已经这样做了,以从 CMake 生成 QtCreator 项目文件,因为在 QtCreator 中导入 CMake 对我来说无法正常工作)。我完全控制正在发生的事情......
    猜你喜欢
    • 2015-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-03
    • 1970-01-01
    • 2019-11-25
    相关资源
    最近更新 更多