【问题标题】:How to run custom rule in Android.mk before compilation?编译前如何在 Android.mk 中运行自定义规则?
【发布时间】:2012-09-04 13:09:18
【问题描述】:

在 Android NDK 中,我构建了由 SWIG 自动生成的 JNI 文件。 callmanager_wrap.cpp 是共享库的一部分:

LOCAL_SRC_FILES += callmanager_wrap.cpp
include $(BUILD_SHARED_LIBRARY)

但我想在编译之前附加/编辑callmanager_wrap.cpp。更明确地说:

cat jnistuff.txt >> callmanager_wrap.cpp

我需要添加的内容是事先知道的,但 callmanager_wrap.cpp 不知道。它由 SWIG 生成。最终,我的自定义规则必须运行以下命令来生成 callmanager_wrap.cpp:

swig -c++ -java -package com.package.my -o callmanager_wrap.cpp callmanager.i

根据this post,无法给Android.mk添加自定义规则。但在 Android 资源中,我相信在 BUILT 或 INSTALLED 之后会有一些Android.mk 处理步骤。我尝试了以下方法:

MY_JNI_WRAP=callmanager_wrap.cpp

include $(CLEAR_VARS)

LOCAL_SRC_FILES += callmanager_wrap.cpp

LOCAL_INTERMEDIATE_TARGETS += myjni
myjni:
    echo "in myjni target"
    swig -c++ -java -package com.package.my -o $(MY_JNI_WRAP) callmanager.i
    cat jnistuff.txt >> $(MY_JNI_WRAP)

include $(BUILD_SHARED_LIBRARY)

但是myjni 目标永远不会被调用。

  1. LOCAL_INTERMEDIATE_TARGETS 有什么用途?
  2. 我是否可以在不编写外部脚本或 makefile 的情况下实现我想要在此处执行的操作?

【问题讨论】:

  • 你能澄清这句话“我想在编译之前附加 callmanager_wrap.cpp”吗?如果你把它弄清楚一点,我可以帮你。
  • 你真的需要在每个构建中运行 swig 吗?
  • 一方面,它更干净并且可以防止对生成的文件进行版本控制。另一方面,如果开发人员在git rebase 之后没有make clean,则不对这些文件进行版本控制可能会破坏构建。但这是开发人员的问题。是不是可以自定义 android makefile 到那种程度?我不会隐瞒我正在考虑编写一个顶级脚本来做到这一点,但我仍然对这个 android 限制感到好奇。

标签: android android-ndk makefile


【解决方案1】:

我建议如下:

include $(CLEAR_VARS)

LOCAL_SRC_FILES += callmanager_wrap.cpp
MY_JNI_WRAP := $(LOCAL_PATH)/callmanager_wrap.cpp

$(MY_JNI_WRAP):
    echo "in myjni target"
    swig -c++ -java -package com.package.my -o $(MY_JNI_WRAP) callmanager.i
    cat jnistuff.txt >> $(MY_JNI_WRAP)
.PHONY: $(MY_JNI_WRAP)

include $(BUILD_SHARED_LIBRARY)

就是这样。

我可能欠你一些解释。所以我们开始:

  1. $(LOCAL_SRC_FILES) 是相对于$(LOCAL_PATH) 的文件名列表,因此要从标准 NDK 操作之外寻址文件,您需要文件的完整路径,即 $(LOCAL_PATH)/callmanager_wrap.cpp

  2. 我们将文件指定为.PHONY,以保证每次运行ndk-build 时都会执行自定义操作。但是如果你知道 callmanager_wrap.cpp 的实际依赖项,你可以指定它们,比如

    $(MY_JNI_WRAP): callmanager.i jnistuff.txt $(LOCAL_PATH)/../src/com/package/my/Something.java

    在这种情况下,您将不需要 .PHONY 行。

  3. 如果您希望源目录保持干净,可以将包装文件声明为.INTERMEDIATE,如下所示:

    .INTERMEDIATE: $(MY_JNI_WRAP)

现在 ma​​ke 将在构建后删除包装文件,如果它在构建之前不存在。

【讨论】:

  • 我已经尝试过您的建议,例如:MY_JNI_WRAP:=bus/callmanager_wrap.cpp LOCAL_SRC_FILES += $(MY_JNI_WRAP) $(MY_JNI_WRAP): echo "in myjni target" touch mememe .PHONY: $(MY_JNI_WRAP) 但在我运行rm -rf obj/local/ libs/armeabi && ndk-build -j5 之后,find -name mememe 永远不会返回任何东西。您确定 .PHONY 被 ndk-build 识别吗?
  • 在上面的示例中,虚假目标与我添加到 LOCAL_SRC_FILES 的字符串不同。诀窍是 LOCAL_SRC_FILES 与 Android.mk 相关,但 make 本身及其目标与当前目录相关。 tl;nr 在除 LOCAL_SRC_FILES 行之外的任何地方都使用 $(LOCAL_PATH)/$(MY_JNI_WRAP)。
  • 哇,你让我的一天亚历克斯!谢谢大家
  • 使用 all: $(MY_JNI_WRAP) 而不是 .PHONY: $(MY_JNI_WRAP) 对我有用。
  • 是的,由于某种原因它没有。并且规则实际上在编译后运行,这对我来说很好,但不是 OP。
【解决方案2】:

我是这样做的: 假设我需要从 .ll 文件创建 .s 文件

# custom build
source_ll_files := $(wildcard *.ll)
%.s:
    llc -o $@ $(patsubst %.s,%.ll,$@)

LOCAL_SRC_FILES += $(patsubst %.ll,%.s,$(source_ll_files))
# end

【讨论】:

    猜你喜欢
    • 2015-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-01
    • 2017-09-25
    • 1970-01-01
    • 2012-01-06
    • 2021-12-23
    相关资源
    最近更新 更多