CMake 默认不提供 uninstall 目标,因其不记录安装路径或文件归属;需手动添加 uninstall 目标并读取 install_manifest.txt 清单执行删除,且仅适用于开发调试。

卸载目标为什么不能直接用 make uninstall
CMake 本身不生成 uninstall 目标,这是常见误解。你执行 make uninstall 报错 make: *** No rule to make target 'uninstall'. Stop.,不是因为你写错了,而是 CMake 默认根本不提供这个目标——它不记录安装路径、不跟踪文件归属、也不生成反向操作逻辑。
手动添加 uninstall 目标的正确写法
必须显式在 CMakeLists.txt 末尾追加一段逻辑,核心是:读取 install_manifest.txt(CMake 生成的已安装文件清单),逐行删除。
- 确保你已启用
INSTALL命令(否则没有清单可读) - 把以下代码块放在
CMakeLists.txt最后(不能在project()前,也不能被条件编译包裹)
if(EXISTS "${CMAKE_BINARY_DIR}/install_manifest.txt")
file(READ "${CMAKE_BINARY_DIR}/install_manifest.txt" files)
string(REPLACE "\n" ";" files "${files}")
foreach(file ${files})
message(STATUS "Uninstalling $<TARGET_FILE:${file}>")
if(EXISTS "${file}")
file(REMOVE "${file}")
message(STATUS "Deleted ${file}")
else()
message(WARNING "File not found: ${file}")
endif()
endforeach()
endif()注意:install_manifest.txt 只在执行过 make install 后才存在,路径固定为构建目录下,不是源码目录。
cmake -P 方式比 make uninstall 更可靠
上面那段代码只是定义了逻辑,但没绑定到 uninstall 目标。真正让 make uninstall 可用,得再加一个自定义目标:
add_custom_target(uninstall
COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake")然后把上面那段逻辑单独存为 cmake_uninstall.cmake(和 CMakeLists.txt 同级),内容不变。这样 make uninstall 就能调用它。
- 别把逻辑硬塞进
CMakeLists.txt里用COMMAND ${CMAKE_COMMAND} -E rm拼接,容易路径转义出错 -
${CMAKE_COMMAND} -P是唯一安全执行 CMake 脚本的方式,支持file(READ)等完整 API - 如果项目用了
DESTINATION动态变量(如${CMAKE_INSTALL_PREFIX}),清单里存的是绝对路径,无需额外拼接
卸载失败的三个典型原因
即使脚本写对了,uninstall 仍可能静默失败或删错文件:
-
install_manifest.txt被手动删过,或make install是用不同构建目录执行的——清单路径不对,脚本直接跳过 - 安装时用了
sudo make install,但卸载时没加sudo,权限不足导致file(REMOVE)静默失败(CMake 不报错) - 多个 target 安装到同一路径(比如两个库都装到
lib/),卸载会删掉别人的东西——CMake 不做依赖隔离
真正的生产环境卸载,从来不是靠 make uninstall,而是用包管理器(deb/rpm)或带事务回滚的安装器;CMake 的卸载逻辑只适合开发调试阶段临时清理。


















