如何透明地两次重写CMake的add_executable函数?
解决CMake中
add_executable透明重写的无限循环问题 问题本质
你遇到的核心问题是:CMake对函数重写的默认处理会导致多次重写时,前一次自定义函数的调用目标被后续重写覆盖,最终触发无限循环。
当你第一次重写add_executable时,CMake会将原生的add_executable重命名为_add_executable;但第二次重写时,CMake会把**第一次自定义的add_executable**重命名为_add_executable,覆盖了之前原生的备份。此时第一次自定义函数里调用的_add_executable,在执行时会指向它自己,从而引发无限循环。
解决方案
我们需要让每次重写的函数都“捕获”重写前的add_executable实现,而不是依赖执行时的全局_add_executable。可以通过封装一个辅助宏来自动处理这个逻辑,让后续重写无需感知前一次的存在,实现完全透明的链式调用。
步骤1:封装重写宏
这个宏会自动保存当前的add_executable实现,然后生成新的自定义函数,新函数会先执行你的自定义逻辑,再调用之前保存的版本:
macro(override_add_executable NEW_FUNC_BODY) # 动态生成临时函数,保存当前add_executable的实现 cmake_language(EVAL CODE " function(_add_executable_prev) cmake_language(CALL add_executable \${ARGV}) endfunction() ") # 移除旧的add_executable定义,为新定义让路 unset(add_executable) # 定义新的add_executable函数,包含自定义逻辑和链式调用 function(add_executable) ${NEW_FUNC_BODY} _add_executable_prev(\${ARGV}) endfunction() # 清理临时函数,避免命名空间污染 unset(_add_executable_prev) endmacro()
步骤2:使用宏进行透明重写
现在你可以多次调用这个宏来重写add_executable,每次只需要传入自定义逻辑即可,无需关心前一次的实现:
cmake_minimum_required(VERSION 3.18) project(interposition LANGUAGES C) # 第一次重写:添加自定义日志 override_add_executable(" message(STATUS \"Inside of \${CMAKE_CURRENT_FUNCTION}\") ") # 第二次重写:添加另一层自定义日志 override_add_executable(" message(STATUS \"Inside of the second copy of \${CMAKE_CURRENT_FUNCTION}\") ") # 正常调用add_executable,会触发链式执行 add_executable(main main.c)
执行结果
运行上述代码后,输出会是:
-- Inside of the second copy of add_executable -- Inside of add_executable
之后会正常调用原生的add_executable完成目标构建,不会出现无限循环。
原理说明
cmake_language(EVAL CODE)用于动态生成临时函数_add_executable_prev,这个函数在定义时就绑定了当前的add_executable实现(不管是原生还是上一次自定义的),不会被后续重写影响。unset(add_executable)确保我们可以重新定义函数,避免CMake报错“函数已存在”。- 新的
add_executable函数先执行你的自定义逻辑,再调用临时函数完成链式传递,完美实现了“后一次重写调用前一次,最终调用原生”的透明效果。
内容的提问来源于stack exchange,提问作者TallChuck
相关产品推荐
相关产品推荐

