CMake配置阶段环境测试结果的存储位置及与autotools宏的变量映射咨询
我太懂这种把依赖autotools的老库转成CMake构建的头疼了——尤其是要精准对齐config.h里那些由configure检测生成的宏,确实容易找不到头绪。下面结合CMake的机制给你梳理清楚:
CMake里的检测逻辑和变量对应方式
和autotools不同,CMake不会预先自动生成一堆HAVE_*类的全局变量,而是需要你主动调用对应的检测模块和函数,来定义对应结果的变量——不过好在大部分autotools常用的检测,CMake都有现成的模块可以直接用,而且变量名你可以和autotools的宏名保持一致,减少映射成本:
- 检测某个标准库函数是否存在:用
CheckFunctionExists模块,比如你提到的strerror,写法是:
执行后,include(CheckFunctionExists) check_function_exists(strerror HAVE_STRERROR)HAVE_STRERROR变量就会被设为YES或NO,完全对应autotools里的HAVE_STRERROR宏。 - 检测头文件是否存在:用
CheckIncludeFiles模块,比如检测unistd.h:include(CheckIncludeFiles) check_include_files(unistd.h HAVE_UNISTD_H) - 检测某个库中的函数是否存在:用
CheckLibraryExists模块,比如检测m库中的sqrt:include(CheckLibraryExists) check_library_exists(m sqrt "" HAVE_LIBM_SQRT)
如何配合configure_file生成目标config.h
首先你需要创建一个CMake风格的模板文件,比如命名为config.h.cmake.in,把autotools模板里的#undef HAVE_STRERROR这类行,替换成CMake的模板语法:
/* Define if you have the strerror function. */ #cmakedefine HAVE_STRERROR
CMake会自动根据HAVE_STRERROR变量的取值,把这一行替换成#define HAVE_STRERROR 1(当变量为YES时)或者#undef HAVE_STRERROR(当变量为NO时)。如果需要带具体值的定义,还可以写成#cmakedefine HAVE_STRERROR @HAVE_STRERROR@。
然后在你的CMakeLists.txt里,先执行所有检测逻辑,再调用configure_file生成最终的头文件:
# 先执行所有检测步骤... configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/config.h @ONLY )
最后记得把生成config.h的目录(也就是CMAKE_CURRENT_BINARY_DIR)加入头文件搜索路径:
target_include_directories(your_lib_target PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
关于检测结果的存储
你提到的.cache文件确实会存储CMake缓存的变量,包括这些检测生成的HAVE_*变量。另外,你也可以在构建目录下执行cmake -L命令,来列出所有缓存中的变量,方便查看检测结果是否符合预期。
需要注意的是:这些变量都是你通过检测函数主动定义的,不是CMake预设的全局变量——这和autotools的configure自动扫描生成一堆变量的逻辑不同,CMake更强调“按需检测”。
针对libwww的具体实操步骤
- 先把libwww的
configure.ac文件里的检测逻辑梳理一遍,把所有AC_CHECK_FUNC、AC_CHECK_HEADERS、AC_CHECK_LIB这类命令列出来,这些就是你需要在CMake里复现的检测点。 - 对应每个autotools检测命令,找到CMake的等价检测模块和函数,写出对应的CMake代码,变量名尽量和autotools生成的宏名保持一致(比如autotools里的
HAVE_STRERROR,CMake里就用同名变量)。 - 把libwww的
config.h.in改成CMake模板文件config.h.cmake.in,替换所有autotools的#undef行为CMake的#cmakedefine语法。 - 在CMakeLists.txt里按顺序执行检测、调用
configure_file、添加头文件路径。
一些实用小技巧
- 如果遇到autotools里的自定义检测逻辑(比如某些复杂的代码编译测试),CMake没有现成模块的话,可以用
try_compile或try_run函数来实现自定义检测,灵活性很高。 - 检测时如果需要指定额外的头文件路径或链接库,可以临时设置
CMAKE_REQUIRED_INCLUDES、CMAKE_REQUIRED_LIBRARIES这些变量,比如:set(CMAKE_REQUIRED_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/libwww/include) check_function_exists(custom_func HAVE_CUSTOM_FUNC) # 检测完记得重置,避免影响后续检测 unset(CMAKE_REQUIRED_INCLUDES)
备注:内容来源于stack exchange,提问作者cycollins

