前言
- 最近在项目中反复运用到
colcon build编译指令,为了方便,这里分享一个编写的一键编译脚本。
- 最终效果如下:


完整代码实现
#!/bin/bash
WS_DIR=$(pwd)
SRC_DIR="$WS_DIR/src"
BUILD_DIR="$WS_DIR/build"
INSTALL_DIR="$WS_DIR/install"
LOG_DIR="$WS_DIR/log"
COLCON_BASE_CMD="colcon build --event-handlers console_direct+ --parallel-workers 4"
echo "===================================="
echo " ROS2 COLCON BUILD HELPER "
echo "===================================="
echo "1) 全部编译"
echo "2) 编译指定功能包"
echo "3) 轻量修复(推荐)"
echo "4) 强制修复(clean rebuild)"
echo "5) 时间戳修复(touch 全工程)"
echo "===================================="
read -p "请选择操作: " main_choice
# =========================
# 获取 package 列表
# =========================
get_packages() {
packages=()
index=1
for pkg in $(colcon list --names-only); do
packages+=("$pkg")
echo "$index) $pkg"
index=$((index + 1))
done
}
# =========================
# 全部编译
# =========================
build_all() {
echo "全部编译..."
$COLCON_BASE_CMD
}
# =========================
# 指定包编译
# =========================
build_selected() {
echo "扫描功能包..."
get_packages
echo ""
read -p "输入编号(如 1 2 3,空格隔开): " pkg_indexes
selected_packages=""
for i in $pkg_indexes; do
pkg_name="${packages[$((i-1))]}"
selected_packages="$selected_packages $pkg_name"
done
echo "编译: $selected_packages"
$COLCON_BASE_CMD --packages-select $selected_packages
}
# =========================
# 轻量修复(推荐)
# =========================
light_fix() {
echo "===================================="
echo "1) 修复全部包(轻量)"
echo "2) 修复指定包(轻量)"
echo "===================================="
read -p "请选择: " fix_choice
if [ "$fix_choice" == "1" ]; then
echo "轻量修复:clean cache + force configure"
$COLCON_BASE_CMD --cmake-clean-cache
elif [ "$fix_choice" == "2" ]; then
echo "扫描功能包..."
get_packages
read -p "输入编号(如 1 2 3,空格隔开) " pkg_indexes
selected_packages=""
for i in $pkg_indexes; do
pkg_name="${packages[$((i-1))]}"
selected_packages="$selected_packages $pkg_name"
done
echo "轻量修复包: $selected_packages"
$COLCON_BASE_CMD \
--packages-select $selected_packages \
--cmake-force-configure
else
echo "无效"
fi
}
# =========================
# 强制修复(最干净)
# =========================
hard_fix() {
echo "===================================="
echo "1) 修复全部(删除重建)"
echo "2) 修复指定包(删除重建)"
echo "===================================="
read -p "请选择: " fix_choice
if [ "$fix_choice" == "1" ]; then
echo "删除全部 build/install/log"
rm -rf "$BUILD_DIR" "$INSTALL_DIR" "$LOG_DIR"
echo "重新全量编译"
$COLCON_BASE_CMD
elif [ "$fix_choice" == "2" ]; then
echo "扫描功能包..."
get_packages
read -p "输入编号(如 1 2 3,空格隔开)" pkg_indexes
selected_packages=""
for i in $pkg_indexes; do
pkg_name="${packages[$((i-1))]}"
selected_packages="$selected_packages $pkg_name"
done
echo "删除指定包 build/install/log"
for pkg in $selected_packages; do
rm -rf "$BUILD_DIR/$pkg"
rm -rf "$INSTALL_DIR/$pkg"
rm -rf "$LOG_DIR/$pkg"
done
echo "重新编译: $selected_packages"
$COLCON_BASE_CMD --packages-select $selected_packages
else
echo "无效"
fi
}
# =========================
# 时间戳修复(touch 全工程)
# =========================
time_fix() {
echo "===================================="
echo "时间戳修复(Clock Skew Fix)"
echo "===================================="
echo "执行 find . -exec touch {} +"
find "$WS_DIR" -exec touch {} + 2>/dev/null
echo "✔workspace 时间戳已刷新"
}
# =========================
# 主入口
# =========================
case $main_choice in
1)
build_all
;;
2)
build_selected
;;
3)
light_fix
;;
4)
hard_fix
;;
5)
time_fix
;;
*)
echo "无效选择"
;;
esac
#!/bin/bash
WS_DIR=$(pwd)
SRC_DIR="$WS_DIR/src"
BUILD_DIR="$WS_DIR/build"
DEVEL_DIR="$WS_DIR/devel"
LOG_DIR="$WS_DIR/log"
CATKIN_BASE_CMD="catkin_make -j4"
echo "===================================="
echo " ROS1 CATKIN BUILD HELPER "
echo "===================================="
echo "1) 全部编译"
echo "2) 编译指定功能包"
echo "3) 轻量修复(推荐)"
echo "4) 强制修复(clean rebuild)"
echo "5) 时间戳修复(touch 全工程)"
echo "===================================="
read -p "请选择操作: " main_choice
# =========================
# 获取 package 列表
# =========================
get_packages() {
packages=()
index=1
for pkg in $(catkin_topological_order "$SRC_DIR" 2>/dev/null); do
pkg_name=$(basename "$pkg")
packages+=("$pkg_name")
echo "$index) $pkg_name"
index=$((index + 1))
done
}
# =========================
# 全部编译
# =========================
build_all() {
echo "全部编译..."
$CATKIN_BASE_CMD
}
# =========================
# 编译指定包
# =========================
build_selected() {
echo "扫描功能包..."
get_packages
echo ""
read -p "输入编号(如 1 2 3,空格隔开): " pkg_indexes
selected_packages=""
for i in $pkg_indexes; do
pkg_name="${packages[$((i-1))]}"
selected_packages="$selected_packages $pkg_name"
done
echo "编译:$selected_packages"
catkin_make --pkg $selected_packages -j4
}
# =========================
# 轻量修复
# =========================
light_fix() {
echo "===================================="
echo "1) 修复全部包(轻量)"
echo "2) 修复指定包(轻量)"
echo "===================================="
read -p "请选择: " fix_choice
if [ "$fix_choice" == "1" ]; then
echo "轻量修复:删除 CMakeCache"
rm -f "$BUILD_DIR/CMakeCache.txt"
$CATKIN_BASE_CMD
elif [ "$fix_choice" == "2" ]; then
echo "扫描功能包..."
get_packages
read -p "输入编号(如 1 2 3,空格隔开): " pkg_indexes
selected_packages=""
for i in $pkg_indexes; do
pkg_name="${packages[$((i-1))]}"
selected_packages="$selected_packages $pkg_name"
done
echo "轻量修复:$selected_packages"
catkin_make --pkg $selected_packages -j4
else
echo "无效"
fi
}
# =========================
# 强制修复
# =========================
hard_fix() {
echo "===================================="
echo "1) 修复全部(删除重建)"
echo "2) 修复指定包(删除重建)"
echo "===================================="
read -p "请选择: " fix_choice
if [ "$fix_choice" == "1" ]; then
echo "删除 build/devel/log"
rm -rf "$BUILD_DIR"
rm -rf "$DEVEL_DIR"
rm -rf "$LOG_DIR"
echo "重新全量编译"
$CATKIN_BASE_CMD
elif [ "$fix_choice" == "2" ]; then
echo "扫描功能包..."
get_packages
read -p "输入编号(如 1 2 3,空格隔开): " pkg_indexes
selected_packages=""
for i in $pkg_indexes; do
pkg_name="${packages[$((i-1))]}"
selected_packages="$selected_packages $pkg_name"
done
echo "删除指定包 build"
for pkg in $selected_packages; do
rm -rf "$BUILD_DIR/$pkg"
done
echo "重新编译:$selected_packages"
catkin_make --pkg $selected_packages -j4
else
echo "无效"
fi
}
# =========================
# 时间戳修复
# =========================
time_fix() {
echo "===================================="
echo "时间戳修复(Clock Skew Fix)"
echo "===================================="
echo "执行 find . -exec touch {} +"
find "$WS_DIR" -exec touch {} + 2>/dev/null
echo "✔ workspace 时间戳已刷新"
}
# =========================
# 主入口
# =========================
case $main_choice in
1)
build_all
;;
2)
build_selected
;;
3)
light_fix
;;
4)
hard_fix
;;
5)
time_fix
;;
*)
echo "无效选择"
;;
esac
1-1 基础参数
WS_DIR=$(pwd)
SRC_DIR="$WS_DIR/src"
BUILD_DIR="$WS_DIR/build"
INSTALL_DIR="$WS_DIR/install"
LOG_DIR="$WS_DIR/log"
COLCON_BASE_CMD="colcon build --event-handlers console_direct+ --parallel-workers 4"
- 这里获取了当前的工作空间
$(pwd),同时获取了功能包应该存在的src和编译后的三大输出目录:
build:编译中间文件
install:最终安装结果
log:编译日志
COLCON_BASE_CMD="colcon build --event-handlers console_direct+ --parallel-workers 4"
--event-handlers console_direct+:实时输出编译日志(不缓存)
--parallel-workers 4:并行编译 4 个 package
1-2 读取用户选择
echo "===================================="
echo " ROS2 COLCON BUILD HELPER "
echo "===================================="
echo "1) 全部编译"
echo "2) 编译指定功能包"
echo "3) 轻量修复(推荐)"
echo "4) 强制修复(clean rebuild)"
echo "5) 时间戳修复(touch 全工程)"
echo "===================================="
read -p "请选择操作: " main_choice
1-3 获取 package 列表
get_packages() {
packages=()
index=1
for pkg in $(colcon list --names-only); do
packages+=("$pkg")
echo "$index) $pkg"
index=$((index + 1))
done
}
- 区别于直接搜寻
src下的全部目录,这里借助colcon list获取 package,避免了src还存在其他非ros2的目录影响判断
packages+=("$pkg"):数组,保存所有 package 名称
1-4 指定包编译
build_all() {
echo "全部编译..."
$COLCON_BASE_CMD
}
build_selected() {
echo "扫描功能包..."
get_packages
echo ""
read -p "输入编号(如 1 2 3,空格隔开): " pkg_indexes
selected_packages=""
for i in $pkg_indexes; do
pkg_name="${packages[$((i-1))]}"
selected_packages="$selected_packages $pkg_name"
done
echo "编译: $selected_packages"
$COLCON_BASE_CMD --packages-select $selected_packages
}
- 调用
get_packages更新全部包的数组packages
- 读取用户输入的编号,然后便利存储有全部包的数组
packages
pkg_name="${packages[$((i-1))]}":把编号转换为对应的包名
selected_packages="$selected_packages $pkg_name"拼接字符串,变成pkgA pkgB pkgC
- 最后执行编译
1-5 轻量修复
light_fix() {
echo "===================================="
echo "1) 修复全部包(轻量)"
echo "2) 修复指定包(轻量)"
echo "===================================="
read -p "请选择: " fix_choice
if [ "$fix_choice" == "1" ]; then
echo "轻量修复:clean cache + force configure"
$COLCON_BASE_CMD --cmake-clean-cache
elif [ "$fix_choice" == "2" ]; then
echo "扫描功能包..."
get_packages
read -p "输入编号(如 1 2 3,空格隔开) " pkg_indexes
selected_packages=""
for i in $pkg_indexes; do
pkg_name="${packages[$((i-1))]}"
selected_packages="$selected_packages $pkg_name"
done
echo "轻量修复包: $selected_packages"
$COLCON_BASE_CMD \
--packages-select $selected_packages \
--cmake-force-configure
else
echo "无效"
fi
}
- 轻量修复主要用于如下情况:
CMakeLists改了
find_package失败
dependency变化
- 核心主要依赖于
--cmake-clean-cache:删除 CMakeCache.txt,重新 configure
--cmake-force-configure:--cmake-force-configure
1-6 强制修复
hard_fix() {
echo "===================================="
echo "1) 修复全部(删除重建)"
echo "2) 修复指定包(删除重建)"
echo "===================================="
read -p "请选择: " fix_choice
if [ "$fix_choice" == "1" ]; then
echo "删除全部 build/install/log"
rm -rf "$BUILD_DIR" "$INSTALL_DIR" "$LOG_DIR"
echo "重新全量编译"
$COLCON_BASE_CMD
elif [ "$fix_choice" == "2" ]; then
echo "扫描功能包..."
get_packages
read -p "输入编号(如 1 2 3,空格隔开)" pkg_indexes
selected_packages=""
for i in $pkg_indexes; do
pkg_name="${packages[$((i-1))]}"
selected_packages="$selected_packages $pkg_name"
done
echo "删除指定包 build/install/log"
for pkg in $selected_packages; do
rm -rf "$BUILD_DIR/$pkg"
rm -rf "$INSTALL_DIR/$pkg"
rm -rf "$LOG_DIR/$pkg"
done
echo "重新编译: $selected_packages"
$COLCON_BASE_CMD --packages-select $selected_packages
else
echo "无效"
fi
}
rm -rf build install log
1-7 时间戳修复
time_fix() {
echo "===================================="
echo "时间戳修复(Clock Skew Fix)"
echo "===================================="
echo "执行 find . -exec touch {} +"
find "$WS_DIR" -exec touch {} + 2>/dev/null
echo "✔workspace 时间戳已刷新"
}
Clock skew detected. Your build may be incomplete
1-8 主入口
case $main_choice in
1)
build_all
;;
2)
build_selected
;;
3)
light_fix
;;
4)
hard_fix
;;
5)
time_fix
;;
*)
echo "无效选择"
;;
esac
测试
.
├── build
├── colcon_helper.sh
├── install
├── log
└── src
├── test01
├── test_package01
│ ├── CMakeLists.txt
│ ├── include
│ ├── package.xml
│ └── src
├── test_package02
│ ├── CMakeLists.txt
│ ├── include
│ ├── package.xml
│ └── src
└── test_package03
├── CMakeLists.txt
├── include
├── package.xml
└── src
- 其中
test_package01,test_package02,test_package03均为ros2功能包,test01只是普通目录
colcon_helper.sh放在工作空间下即可


总结
- 本文实现了一个基于 colcon 的 ROS2 一键编译与分级修复管理脚本,支持 package 选择编译、轻量修复、强制重建以及时间戳修复,用于提升工作空间编译效率与稳定性。
- 如有错误!欢迎指出!
- 感谢支持!