如何在CMake中配置DESTDIR,让运行脚本适配自定义安装路径?
你的问题核心在于:DESTDIR是CMake安装阶段的临时根目录,它不会改变编译阶段生成的脚本里的绝对路径变量。编译时BINDIR被固定为/usr/local/bin,所以当你用make DESTDIR=./dist install把文件安装到临时目录后,脚本依然会去系统的/usr/local/bin找二进制文件,而不是./dist/usr/local/bin。
下面给你两种实用的解决方案,分别适配不同的场景:
方案1:让脚本自动推导二进制文件路径(推荐生产环境使用)
这种方法不依赖硬编码的绝对路径,而是通过脚本自身的位置来推导二进制文件的所在目录,只要你的项目目录结构保持一致(脚本在sbin,二进制在bin),不管安装到哪里都能正常工作。
步骤1:修改脚本为模板文件
把你的启停脚本改成模板(比如命名为conf/startscript.sh.in),替换硬编码的路径逻辑:
#!/bin/bash # ############################################### # runscript for my program # date: 2018/05/21 # ############################################### export G_MESSAGES_DEBUG=all export LOGFILE=~/.logfile.log # 获取脚本所在的绝对目录(兼容符号链接) SCRIPT_DIR=$(dirname $(realpath "$0")) # 从脚本目录推导二进制文件目录(sbin的上一级目录下的bin文件夹) BINDIR="${SCRIPT_DIR}/../bin" pushd "${BINDIR}" "${BINDIR}/${PROJECTNAME}" 1>> "$LOGFILE" 2>> "$LOGFILE" popd
步骤2:用CMake处理模板生成脚本
在CMakeLists.txt中添加configure_file命令,替换模板里的${PROJECTNAME}变量:
configure_file(conf/startscript.sh.in ${CMAKE_CURRENT_BINARY_DIR}/startscript.sh @ONLY)
步骤3:安装生成的脚本
修改你的安装命令,安装生成好的脚本:
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/startscript.sh PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE DESTINATION ${SBINDIR} COMPONENT binary)
这样不管你是否使用DESTDIR,脚本都会自动找到对应的二进制文件,完全不需要担心路径问题。
方案2:安装时动态替换路径(仅用于本地DESTDIR测试)
如果你只是想在本地测试DESTDIR下的安装环境,可以通过CMake的install(CODE)命令,在安装时用sed动态替换脚本里的路径占位符。
步骤1:修改脚本模板为占位符形式
调整脚本模板(conf/startscript.sh.in),把${BINDIR}改成@BINDIR@占位符:
#!/bin/bash # ############################################### # runscript for my program # date: 2018/05/21 # ############################################### export G_MESSAGES_DEBUG=all export LOGFILE=~/.logfile.log pushd @BINDIR@ @BINDIR@/@PROJECTNAME@ 1>> "$LOGFILE" 2>> "$LOGFILE" popd
步骤2:CMake中配置动态替换逻辑
在CMakeLists.txt中,先通过configure_file生成初始脚本,然后在安装时用sed替换占位符为DESTDIR拼接后的路径:
# 生成初始脚本(替换PROJECTNAME) configure_file(conf/startscript.sh.in ${CMAKE_CURRENT_BINARY_DIR}/startscript.sh @ONLY) # 复制临时副本用于修改 set(TEMP_SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/temp_startscript.sh) file(COPY ${CMAKE_CURRENT_BINARY_DIR}/startscript.sh DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) file(RENAME ${CMAKE_CURRENT_BINARY_DIR}/startscript.sh ${TEMP_SCRIPT}) # 安装时动态替换BINDIR为DESTDIR+实际路径 install(CODE " execute_process( COMMAND sed -e 's|@BINDIR@|${DESTDIR}${CMAKE_INSTALL_FULL_BINDIR}|g' ${TEMP_SCRIPT} OUTPUT_FILE ${CMAKE_CURRENT_BINARY_DIR}/startscript.sh ) ") # 安装修改后的脚本 install(FILES ${CMAKE_CURRENT_BINARY_DIR}/startscript.sh PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE DESTINATION ${SBINDIR} COMPONENT binary)
当你运行make DESTDIR=./dist install时,脚本里的@BINDIR@会被替换成./dist/usr/local/bin,这样就能在本地测试DESTDIR下的完整运行环境了。
关键提示
DESTDIR的设计目的是用于打包(比如制作deb/rpm包),此时脚本里的路径应该是目标系统的实际路径(比如/usr/local/bin),而不是临时目录路径。因此方案1更适合生产环境,方案2仅用于本地调试。- 如果目标系统没有
realpath命令,可以用readlink -f替代(Linux系统通用)。
内容的提问来源于stack exchange,提问作者TecDroiD

