我正在使用 arm-linux-androideabi-g++
编译器。当我尝试编译一个简单的“Hello, World!”程序编译得很好。当我通过在该代码中添加一个简单的异常处理来测试它时,它也可以工作(在添加 -fexceptions
.. 我猜它默认是禁用的)。
这是针对 Android 设备的,我只想使用 CMake,而不是 ndk-build
。
例如 - first.cpp
#include <iostream>
using namespace std;
int main()
{
try
{
}
catch (...)
{
}
return 0;
}
./arm-linux-androideadi-g++ -o first-test first.cpp -fexceptions
它工作没有问题...
问题...我正在尝试使用 CMake 文件编译该文件。
我想将 -fexceptions
添加为标志。我试过了
set (CMAKE_EXE_LINKER_FLAGS -fexceptions ) or set (CMAKE_EXE_LINKER_FLAGS "fexceptions" )
和
set ( CMAKE_C_FLAGS "fexceptions")
它仍然显示错误。
注意:鉴于 CMake 的演变,因为这是 2012 年编写的答案,这里的大多数建议现在已经过时/不推荐使用,并且有更好的选择。
假设您要添加这些标志(最好在常量中声明它们):
SET(GCC_COVERAGE_COMPILE_FLAGS "-fprofile-arcs -ftest-coverage")
SET(GCC_COVERAGE_LINK_FLAGS "-lgcov")
有几种方法可以添加它们:
最简单的一个(不干净,但简单方便,仅适用于编译标志,C 和 C++ 一次): add_definitions(${GCC_COVERAGE_COMPILE_FLAGS}) 附加到相应的 CMake 变量: SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS }") SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}") 使用目标属性,参见。 doc CMake 编译标志目标属性,需要知道目标名称。 get_target_property(TEMP ${THE_TARGET} COMPILE_FLAGS) if(TEMP STREQUAL "TEMP-NOTFOUND") SET(TEMP "") # 设置为空字符串 else() SET(TEMP "${TEMP} ") # 一个空格来干净地分开现有内容 endif() # 附加我们的值 SET(TEMP "${TEMP}${GCC_COVERAGE_COMPILE_FLAGS}" ) set_target_properties(${THE_TARGET} PROPERTIES COMPILE_FLAGS ${TEMP} )
现在我使用方法2。
在较新版本的 CMake 中,您可以分别使用 target_compile_options
和 target_link_libraries
为单个目标设置编译器和链接器标志(是的,后者也设置链接器选项):
target_compile_options(first-test PRIVATE -fexceptions)
此方法的优点是您可以通过 PUBLIC
和 PRIVATE
控制选项传播到依赖此选项的其他目标。
从 CMake 3.13 开始,您还可以使用 target_link_options
添加链接器选项,使意图更加清晰。
target_compile_options(main_static PRIVATE --static)
但它似乎不起作用,知道为什么吗?
-static
可能是链接器,而不是编译器选项。尝试将其传递给 target_link_libraries
。
target_link_libraries
我错过了文档的那一部分:“指定链接给定目标时要使用的库或标志。”。谢谢。
target_link_options
作为指定链接器标志的更简洁方式。以后应避免将 target_link_libraries
用作链接器标志,而应改用 target_link_options
。
尝试设置变量 CMAKE_CXX_FLAGS
而不是 CMAKE_C_FLAGS
:
set (CMAKE_CXX_FLAGS "-fexceptions")
变量 CMAKE_C_FLAGS
仅影响 C 编译器,但您正在编译 C++ 代码。
将标志添加到 CMAKE_EXE_LINKER_FLAGS
是多余的。
指定工具链特定选项的首选方法是使用 CMake 的 toolchain facility。这确保了以下之间的清晰划分:
关于如何将源文件组织成目标的说明——以 CMakeLists.txt 文件表示,完全与工具链无关;和
应如何配置某些工具链的详细信息 - 分为 CMake 脚本文件,可由项目的未来用户扩展,可扩展。
理想情况下,您的 CMakeLists.txt 文件中不应有编译器/链接器标志,即使在 if
/endif
块内也是如此。并且您的程序应该使用默认工具链(例如 GNU/Linux 上的 GCC 或 Windows 上的 MSVC)为本地平台构建,而不需要任何额外的标志。
添加工具链的步骤:
使用全局工具链设置创建一个文件,例如 arm-linux-androideadi-gcc.cmake: set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++) set(CMAKE_CXX_FLAGS_INIT "-fexceptions") (您可以找到一个示例 Linux 交叉编译工具链文件此处。)当您想使用此工具链生成构建系统时,请在命令行中指定 CMAKE_TOOLCHAIN_FILE 参数: mkdir android-arm-build && cd android-arm-build cmake -DCMAKE_TOOLCHAIN_FILE=$(pwd)/../arm -linux-androideadi-gcc.cmake ..(注意:您不能使用相对路径。)正常构建: cmake --build 。
工具链文件使交叉编译更容易,但它们还有其他用途:
为您的单元测试提供强化诊断。设置(CMAKE_CXX_FLAGS_INIT “-Werror -Wall -Wextra -Wpedantic”)
难以配置的开发工具。 # 用于 gcov 集的工具链文件(CMAKE_CXX_FLAGS_INIT "--coverage -fno-exceptions -g")
加强安全检查。 # 用于 gdb 的工具链文件 set(CMAKE_CXX_FLAGS_DEBUG_INIT "-fsanitize=address,undefined -fsanitize-undefined-trap-on-error") set(CMAKE_EXE_LINKER_FLAGS_INIT "-fsanitize=address,undefined -static-libasan")
CMAKE_<LANG>_FLAGS
。并且没有 CMAKE_CXX_DEBUG_FLAGS
这样的东西。这是CMAKE_CXX_FLAGS_DEBUG
。你也不应该使用 that 。仅在工具链中设置 CMAKE_<LANG>_FLAGS[_<CONFIG>]_INIT
CMAKE_<LANG>_FLAGS[_<CONFIG>]
是由构建您的应用程序/库的客户端设置的。它们不应该以编程方式设置。附加,很少。
CMAKE_EXE_LINKER_FLAGS_INIT
。
您还可以使用 LINK_FLAGS
属性将链接器标志添加到特定目标:
set_property(TARGET ${target} APPEND_STRING PROPERTY LINK_FLAGS " ${flag}")
如果您想将此更改传播到其他目标,您可以创建一个虚拟目标以链接到。
当我需要一个名为“NO_DEBUG”的预编译定义时,这对我有用:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -DNO_DEBUG")
然后从代码
#ifdef NO_DEBUG
.....
在 CMake 3.4+ 中,APPEND
可以与 string
命令一起使用来添加标志。
string(APPEND CMAKE_EXE_LINKER_FLAGS " -fexceptions")
string(APPEND CMAKE_EXE_LINKER_FLAGS "new_value")
比set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} new_value")
更短更简洁