在 Gradle 中使用 cppFlags

在 build.gradle 的 defaultConfig - externalNativeBuild - cmake 下有一个 cppFlags 的配置项。它的作用是定义 C++ 编译时的 flags:

1
2
3
4
5
6
7
8
9
10
11
12
android {
// Similar to other properties in the defaultConfig block, you can override
// these properties for each product flavor in your build configuration.
defaultConfig {
externalNativeBuild {
cmake {
// Sets optional flags for the C++ compiler.
cppFlags "-fexceptions", "-frtti"
}
}
}
}

除了可以像上述代码一样启用 RTTI 和 C++ 异常支持外,还可以加入一些自定义的宏,以方便在 C++ 代码中做不同的逻辑处理。例如我们在 C++ 中有如下代码:

1
2
3
4
5
#define ANDROID_SUPPORT_X_FEATURE
// logic
#else
// logic
#endif

此时,在 build.gradle 中我们可以根据逻辑需要来决定是否在 cppFlags 中加入自定义的宏”-DANDROID_SUPPORT_X_FEATURE”,从而让 C++ 层执行不同的代码。

当然,这只是最基础的用法。还有一些场景除了需要知道是否定义了宏,还需要使用该宏的值。例如我们想使用数值型的值:

1
2
3
4
#ifdef ANDROID_BUILD_NUMBER
int build_number = ANDROID_BUILD_NUMBER;
// ...
#endif

此时,在 build.gradle 中我们可以加入带值的 Flag:

1
2
3
4
5
def flags = ""
// ...
flags = " -DANDROID_BUILD_NUMBER=" + buildNumber
// ...
cppFlags flags

带数值的 Flag 使用起来还是很简单的,写这篇文章的主要原因还是在使用字符串值的 Flag 时遇到了一些问题。

假设我们想使用字符串型的宏:

1
2
3
4
#ifdef ANDROID_AUTH_API_SECRET
const char* api_secret = ANDROID_AUTH_API_SECRET;
// ...
#endif

这时如果我们像上面定义数值型的 Flag 那样做,编译就通不过:

1
2
3
4
5
def flags = ""
// ...
flags = " -DANDROID_AUTH_API_SECRET=" + authSecret
// ...
cppFlags flags

因为这样生成出来的宏定义是下面这样的,没有双引号,显然是不正确的:

1
#define ANDROID_AUTH_API_SECRET auth_secret_value

所以理所当然的,我们在 gradle 中定义的时候通过转义符把双引号给它加上:

1
2
3
4
5
def flags = ""
// ...
flags = " -DANDROID_AUTH_API_SECRET=\"${authSecret}\""
// ...
cppFlags flags

此时问题…还是没有解决(微笑),通过编译报的错来看,还是和上面一样的原因,生成出来的宏定义还是没有字符串引号:

1
#define ANDROID_AUTH_API_SECRET auth_secret_value

最终通过查资料和测试,发现在 gradle 中定义的时候还得给字符串的双引号添加一个转义符:

1
2
3
4
5
def flags = ""
// ...
flags = " -DANDROID_AUTH_API_SECRET=\\\"${authSecret}\\\""
// ...
cppFlags flags

这样最终生成出来的宏定义就是正确的了:

1
#define ANDROID_AUTH_API_SECRET "auth_secret_value"

全文完

感谢阅读