Update: Android.mk 中的 LOCAL_SRC_FILES, LOCAL_C_INCLUDES

我在先前的两篇post
编写Android.mk中的LOCAL_SRC_FILES的终极技巧

编写 android.mk 中 LOCAL_C_INCLUDES 的技巧

中提到了一些编译android.mk文件的技巧, 由于都涉及到了shell命令, 导致不能完全在windows下工作, 下面我使用纯净的makefile语法重新编写了脚本

# 配置自己的源文件目录和源文件后缀名
MY_FILES_PATH  :=  $(LOCAL_PATH) \
                   $(LOCAL_PATH)/../../Classes

MY_FILES_SUFFIX := %.cpp %.c

# 递归遍历目录下的所有的文件
rwildcard=$(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2))

# 获取相应的源文件
MY_ALL_FILES := $(foreach src_path,$(MY_FILES_PATH), $(call rwildcard,$(src_path),*.*) ) 
MY_ALL_FILES := $(MY_ALL_FILES:$(MY_CPP_PATH)/./%=$(MY_CPP_PATH)%)
MY_SRC_LIST  := $(filter $(MY_FILES_SUFFIX),$(MY_ALL_FILES)) 
MY_SRC_LIST  := $(MY_SRC_LIST:$(LOCAL_PATH)/%=%)

# 去除字串的重复单词
define uniq =
  $(eval seen :=)
  $(foreach _,$1,$(if $(filter $_,${seen}),,$(eval seen += $_)))
  ${seen}
endef

# 递归遍历获取所有目录
MY_ALL_DIRS := $(dir $(foreach src_path,$(MY_FILES_PATH), $(call rwildcard,$(src_path),*/) ) )
MY_ALL_DIRS := $(call uniq,$(MY_ALL_DIRS))

# 赋值给NDK编译系统
LOCAL_SRC_FILES  := $(MY_SRC_LIST)
LOCAL_C_INCLUDES := $(MY_ALL_DIRS)

完全使用makefile语法编写, 可以工作在所有平台上

我已经在cocos2d-x中提交了一个pull request https://github.com/cocos2d/cocos2d-x/pull/3921, 希望能被集成到cocos2d-x的代码库中, 以后使用就不需要自己修改了

cocos2d-x 2.1.4 启用C++11后使用 NDK r9 gcc 4.8无法编译

下载android ndk r9版本后,发现cocos2d-x无法编译通过报一大堆错误和警告,仔细查看是这两个

    warning: invalid suffix on literal; C++11 requires a space between literal and identifier
    error: format not a string literal and no format arguments

第一个警告是由于头文件不符合C++11的标准引起的,第二个警告是因为格式化字串函数产生的,只需要给gcc参数让其忽略掉这两个错误即可。
打开android项目的Application.mk文件,在APP_CPPFLAGS变量后面添加

    -Wno-format-security -Wno-literal-suffix

就可以了。

编写 android.mk 中 LOCAL_C_INCLUDES 的技巧

已废弃, 请参考Update: Android.mk 中的 LOCAL_SRC_FILES, LOCAL_C_INCLUDES

在编写android.mk的过程中,免不了要修改LOCAL_C_INCLUDES来设置头文件的include目录, 一般写成这样

LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../Classes \
                     $(LOCAL_PATH)/../../Classes/game \
                     $(LOCAL_PATH)/../../Classes/logic \
                     $(LOCAL_PATH)/../../Classes/view                    

有一个目录就要写一行, 实在繁琐, 有没有写法可以把源码目录下的所有子目录都引入呢, 看下面

LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../Classes
LOCAL_C_INCLUDES += $(shell ls -FR $(LOCAL_C_INCLUDES) | grep $(LOCAL_PATH)/$ )
LOCAL_C_INCLUDES := $(LOCAL_C_INCLUDES:$(LOCAL_PATH)/%:=$(LOCAL_PATH)/%)

即可把$(LOCAL_PATH)/../../Classes目录和子目录全部包含进来

还有一种写法, 就是使用sed命令, 效果是一样的, 我对sed不是很熟悉, 简单写了一下

LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../Classes    
LOCAL_C_INCLUDES += $(shell ls -FR $(LOCAL_C_INCLUDES) | grep $(LOCAL_PATH)/$ | sed "s/:/ /g" )

这两行和上面三行的结果是一样的

如果要方便的引入源文件到android.mk文件里, 可以参考我的这篇post:编写Android.mk中的LOCAL_SRC_FILES的终极技巧

以上代码在 mac + NDK r8e 下测试通过

[原创]编写Android.mk中的LOCAL_SRC_FILES的终极技巧

已废弃, 请参考Update: Android.mk 中的 LOCAL_SRC_FILES, LOCAL_C_INCLUDES

问题的引入

在使用NDK编译C/C++项目的过程中,免不了要编写Android.mk文件,其中最重要的就是LOCAL_SRC_FILES源文件列表.
考虑有如下源文件分布的情况:

cpp文件全部位于android项目下的jni文件夹下,结构如下

    jni    
     |---1.cpp
     |---2.cpp
     |---Android.mk
     |---Application.mk
     |---ndk_test.cpp
     |---src    
     |    |---core
     |    |    |---core1.cpp
     |    |    |---core2.cpp
     |    |---src1.cpp
     |    |---src2.cpp

按照通常的写法,在android.mk中,应该写入

LOCAL_SRC_FILES := ndk_test.cpp \
                1.cpp \
                2.cpp \
                src/src1.cpp \
                src/src2.cpp \
                src/core/core1.cpp \
                src/core/core2.cpp

繁琐不堪!

初步解法:一句话引入单个目录(不包括子目录)下的所有cpp源文件

Read More

去除警告 Android NDK: WARNING: APP_PLATFORM android-14 is larger than android:minSdkVersion 8

使用ndk-build编译项目的时候会看到一个警告“Android NDK: WARNING: APP_PLATFORM android-14 is larger than android:minSdkVersion 8”,虽然”不怎么”影响结果,看着碍眼

解决方法

在项目里的jni/Application.mk文件里加入一行

APP_PLATFORM := android-8

即可.

为什么会有这个警告?

在android上项目里,可以在AndroidManifest.xml中写入

<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17"/>

来表示程序可以运行的最低android设备是android 2.2(API Version 8), 经过详细测试的目标android版本是android 4.2.2(API Version 17).这里定义的是Java API Version

再来看一下ndk(版本r8e)目录下的platforms文件夹,可以看到

android-3
android-4
android-5
android-8
android-9
android-14

一共有6个文件夹,分别表示相应的Native API Version


看到这里就明白了,那个警告的意思就是说,使用的Native API Version比最低版本Java API要高,可能导致的问题就是:
在Native Code里使用了一个platforms/android-14下的API函数,然后程序在 android-8 的设备上运行,当然这个函数在android-8设备上是不存在的,就会崩溃了


为什么Native API的版本数量会少于Java API?

因为android在版本升级的时候,有时候只升级了Java层的API,而Native层的却没有变化