尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

基于 Docker 的 C++ 开发环境搭建与 CLion 集成教程

基于 Docker 的 C++ 开发环境搭建与 CLion 集成教程 基于 Docker 的 C 开发环境搭建与 CLion 集成教程本教程完整记录制作 C 开发 Docker 镜像 → 集成到 CLion的全过程。文中所有【自定义...】标记处均可按需修改其余命令经过实测可直接使用。SSH 远程访问、gdb 版本定制属于可选附加操作作为附录放在文末。目录总体架构创建 Fedora 开发容器安装 C 工具链安装其他工具镜像持久化与导出在 CLion 中配置 Docker 环境C23 模块配置常见问题排查附录完整命令速查表附录A可选附加配置 SSH 远程访问附录B可选附加定制 gdb 版本源码编译结语教程完结后的清理1. 总体架构┌─────────────────────────────────────────────────────┐ │ 宿主机 │ │ │ │ ├── Docker │ │ │ └── 开发容器 (fedora44-cpp-dev) │ │ │ ├── GCC/Clang/CMake/Ninja/GDB 工具链 │ │ │ └── 挂载 ~/cpp-projects → /workspace │ │ │ │ │ ├── CLion (IDE) │ │ │ └── Docker 工具链 → 容器内编译运行 │ │ └── (可选) 其他机器 → SSH 远程连接容器 (见附录A) │ └─────────────────────────────────────────────────────┘核心思想开发环境全部装在 Docker 容器里宿主机只保留 IDE 和代码同一套镜像可在任何机器上复现便于团队统一环境。 教程结束后所有容器都可以停用甚至删除只保留镜像即可随时重建详见结语。2. 创建 Fedora 开发容器2.1 准备基础镜像# 拉取基础镜像若网络受限可换国内镜像源dockerpull fedora:44# 【自定义可换成 ubuntu:24.04 / debian:12 等其他发行版后续命令中的包管理器需相应调整apt 等】 实测提示本机直连 Docker Hub 可能失败connection reset by peer可改用镜像源例如dockerpull docker.1ms.run/library/fedora:44dockertag docker.1ms.run/library/fedora:44 fedora:442.2 创建并启动容器# 创建代码挂载目录宿主机mkdir-p~/cpp-projects# 【自定义容器名 fedora44-cpp-dev、挂载目录 ~/cpp-projects、主机名 cpp-dev 均可改】dockerrun-d\--namefedora44-cpp-dev\-hcpp-dev\-v~/cpp-projects:/workspace\fedora:44\sleepinfinity# 查看容器状态dockerps--filternamefedora44-cpp-dev参数说明--name容器名【自定义】-h容器主机名-v挂载目录宿主机~/cpp-projects↔ 容器/workspace代码持久化 这里用sleep infinity保持容器运行后续在容器内通过docker exec操作即可。若需要 SSH 远程访问见附录A。3. 安装 C 工具链3.1 安装编译工具dockerexecfedora44-cpp-dev dnfinstall-y\gcc gcc-cmakecmake ninja-build\gdbgitvalgrind cppcheck clang3.2 验证版本dockerexecfedora44-cpp-devsh-c g --version | head -1 clang --version | head -1 cmake --version | head -1 ninja --version gdb --version | head -1 3.3 编译测试可选dockerexecfedora44-cpp-devsh-c echo int main(){return 0;} /workspace/t.cpp g -stdc20 -o /workspace/t /workspace/t.cpp echo 工具链正常 rm -f /workspace/t /workspace/t.cpp 3.4 工具链自定义空间【自定义需要 Boost / OpenCV / Eigen 等库时追加安装】dockerexecfedora44-cpp-dev dnfinstall-yboost-devel opencv-devel eigen3-devel【自定义需要 Python 开发头文件时】dockerexecfedora44-cpp-dev dnfinstall-ypython3-devel4. 安装其他工具4.1 rsync文件同步dockerexecfedora44-cpp-dev dnfinstall-yrsyncdockerexecfedora44-cpp-devrsync--version|head-1# 3.5.0常用场景# 宿主机 ↔ 容器文件同步容器需已配置 SSH见附录Arsync-avz-essh -p 2222~/cpp-projects/ rootlocalhost:/workspace/# 容器内目录同步dockerexecfedora44-cpp-devrsync-av--delete/workspace/ /backup/4.2 ninja快速构建工具# ninja-build 通常在装 CMake 工具链时已附带验证即可dockerexecfedora44-cpp-dev ninja--version# 1.13.2# 若未安装docker exec fedora44-cpp-dev dnf install -y ninja-build5. 镜像持久化与导出⚠️ 容器是一次性的容器内的更改装软件、改配置默认只存在于运行中的容器可写层。若删除容器重建这些更改会丢失。因此完成配置后要提交为镜像——镜像才是真正的持久化产物。5.1 提交为镜像# 把当前容器状态保存为新镜像# 【自定义标签名 gdb171 可改成任意名称如 v1 / latest】dockercommit fedora44-cpp-dev fedora44-cpp-dev:gdb171# 之后每次改动配置重新 commit 覆盖即可dockercommit fedora44-cpp-dev fedora44-cpp-dev:gdb1715.2 导出镜像为 tar分享/迁移# 导出docker save 保留完整镜像结构可原样 load 复现# 【自定义输出路径和文件名】dockersave-o~/Desktop/fedora44-cpp-dev.tar fedora44-cpp-dev:gdb171ls-lh~/Desktop/fedora44-cpp-dev.tar# 约 1.6GB 常用镜像仓库名写法docker save -o xxx.tar 仓库名:标签名5.3 在另一台机器加载镜像# 加载镜像创建容器的方法见第 2 章按需创建即可dockerload-ifedora44-cpp-dev.tardockerimages|grepfedora44-cpp-dev5.4 压缩导出节省空间可选dockersave fedora44-cpp-dev:gdb171|gzip~/Desktop/fedora44-cpp-dev.tar.gz# 加载时自动解压gunzip-cfedora44-cpp-dev.tar.gz|dockerload5.5 自定义空间【自定义推送到远程仓库如私有 registry / Docker Hub】dockertag fedora44-cpp-dev:gdb171 your-registry.com/dev/fedora44-cpp-dev:latestdockerpush your-registry.com/dev/fedora44-cpp-dev:latest6. 在 CLion 中配置 Docker 环境CLion 通过Docker 工具链把编译、运行、调试都放进容器执行宿主机只当编辑器。前提已按第 2~3 章准备好镜像如fedora44-cpp-dev:gdb171。6.1 配置 Docker 工具链打开SettingsCtrlAltS→Build, Execution, Deployment→Toolchains点击→ 选择Docker配置Image选择镜像fedora44-cpp-dev:gdb171或填写自定义镜像名CMake选择容器内的 cmakeCLion 一般自动检测点击“Docker” 旁的复制图标→ CLion 自动检测容器内编译器gcc/g/gdb 等检测结果应显示容器内的GCC 16.2、GDB 17.1等 若 CLion 未自动检测可在Credentials配置 SSH 连接host:localhost, port:2222需先完成附录A让 CLion 通过 SSH 进容器检测。6.2 配置 CMake ProfileSettings→Build, Execution, Deployment→CMake点击新建 Profile如Debug-DockerToolchain选择上一步的 Docker 工具链Build directorycmake-build-debug-docker或默认CMake options留空模块配置已写在 CMakeLists.txt见第 7 章确定后CLion 会调用容器内的 CMake 生成构建文件6.3 加载并构建项目打开项目如mcpp/lesson1右下角选择Debug-Docker配置点击Reload CMake Project或自动触发点击Run / Debug按钮 → 构建过程在容器内完成6.4 项目结构建议mcpp/ # 课程总目录 ├── CMakeLists.template.txt # 复用的 CMake 模板见第 7 章 └── lesson1/ ├── CMakeLists.txt # 从模板复制 └── main.cpp # import iostream; 等每个新课程复制CMakeLists.template.txt→ 改名CMakeLists.txt→ 改project()名和目标名。6.5 自定义空间【自定义IDE 也可用 VS Code Remote-SSH 方案】配置# ~/.ssh/config Host cpp-dev HostName 172.16.29.124 # 【自定义】 Port 2222 User cppdev # 【自定义】然后 VS Code 安装Remote-SSH插件连接cpp-dev即可需先完成附录A。7. C23 模块配置若课程需要使用 C20/23 模块语法import本节提供两种方案。推荐使用头文件单元方案一因为 CLion 的代码分析器无法识别import std;std 模块接口未参与索引编辑器会持续报std未定义的红色语法错误影响开发体验而头文件单元import header;能被 CLion 正确解析无语法误报。7.1 问题根源import iostream;头文件单元或import std;都需要先预编译生成.gcm文件否则编译报错error: failed to read compiled module: No such file or directory此外CMake 对 GCC 的模块支持不完整需要关闭 CMake 模块扫描让 GCC 直接从gcm.cache解析。7.2 方案一推荐头文件单元import header;用add_header_units()函数一条命令自动预编译所有列出的头文件单元新增库只需往参数里加一个名字。CMakeLists.txt 模板已实测通过cmake_minimum_required(VERSION 3.28) project(lesson CXX) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) add_compile_options(-fmodules-ts) # 关键关闭 CMake 模块扫描由 GCC 直接从构建目录 gcm.cache 解析 set(CMAKE_CXX_SCAN_FOR_MODULES OFF) # 头文件单元自动预编译函数 # 用法: add_header_units(iostream vector string map ...) function(add_header_units) set(_headers ${ARGN}) add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/header_units.done COMMAND ${CMAKE_CXX_COMPILER} -stdc20 -fmodules-ts -x c-system-header -c ${_headers} COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/header_units.done WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT Precompiling header units: ${_headers} ) add_custom_target(header_units DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/header_units.done) endfunction() # 使用把课程用到的标准库头文件列一次即可 add_header_units(iostream vector string map algorithm memory) add_executable(lesson main.cpp) add_dependencies(lesson header_units)源码用法importiostream;// 用到的头文件逐个 importimportvector;importstring;intmain(){std::coutHellostd::endl;std::vectorintv{1,2,3};}7.3 方案二备选import std;一条预编译覆盖整个标准库但CLion 会报语法错误编辑器无法识别std仅编译能通过。CMakeLists.txt 模板已实测通过cmake_minimum_required(VERSION 3.28) project(lesson CXX) set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) add_compile_options(-fmodules-ts) set(CMAKE_CXX_SCAN_FOR_MODULES OFF) # 自动定位 GCC 的 std 模块源码兼容 GCC 版本升级 file(GLOB _std_cc_candidates /usr/include/c/*/bits/std.cc /usr/lib/gcc/*/*/include/c/*/bits/std.cc) list(GET _std_cc_candidates -1 _std_cc) # 预编译 std 模块每个构建目录只执行一次 add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/std_prebuilt.done COMMAND ${CMAKE_CXX_COMPILER} -stdc23 -fmodules-ts -x c -c ${_std_cc} COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/std_prebuilt.done WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT Precompiling C23 std module ) add_custom_target(stdlib_prebuilt DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/std_prebuilt.done) add_executable(lesson main.cpp) add_dependencies(lesson stdlib_prebuilt)源码用法importstd;// 一次导入整个标准库intmain(){std::coutHellostd::endl;std::vectorintv{1,2,3};}8. 常见问题排查现象原因解决方法docker pull报connection reset by peer直连 Docker Hub 网络受限换国内镜像源见 2.1容器停止Exited主进程退出或手动停止docker start 容器名importdoes not name a type缺-fmodules-ts或在宿主机编译加-stdc20 -fmodules-ts必须在容器内编译failed to read compiled module头文件单元/std 模块未预编译先执行预编译见 7.2/7.3-fmodule-mapper相关报错CMake 模块扫描与 GCC 不兼容设CMAKE_CXX_SCAN_FOR_MODULES OFF见第 7 章CMake 报No SOURCES given to target模块目标声明方式不对使用第 7 章的模板写法不要混用两种声明CLion 无法检测 Docker 编译器工具链未配置 / 镜像未就绪确认镜像存在用 SSH credentials 检测见 6.1CLion 对import std;报红色语法错误CLion 分析器无法索引 std 模块改用头文件单元方案见 7.2 推荐方案9. 附录完整命令速查表容器管理dockerps-a# 查看所有容器dockerexec-itfedora44-cpp-devbash# 进入容器终端dockerstart / stop fedora44-cpp-dev# 启停容器dockerrm-ffedora44-cpp-dev# 删除容器注意先 commitdockerimages# 查看镜像dockercommit fedora44-cpp-dev fedora44-cpp-dev:gdb171# 保存镜像常用路径用途宿主机容器内代码挂载~/cpp-projects/workspace导出镜像~/Desktop/fedora44-cpp-dev.tar—std 模块源码方案二用—/usr/include/c/16/bits/std.cc最终验证清单全部 ✅ 表示环境就绪# 容器运行dockerps--filternamefedora44-cpp-dev# 工具链dockerexecfedora44-cpp-dev g--version|head-1# GCC 16.2dockerexecfedora44-cpp-dev gdb--version|head-1# GDB 17.2如需 17.1 见附录Bdockerexecfedora44-cpp-dev ninja--version# 1.13.2dockerexecfedora44-cpp-devrsync--version|head-1# 3.5.0# CLion# 右下角选择 Debug-Docker 配置 → Run 按钮能编译运行即 OK10. 附录A可选附加配置 SSH 远程访问目的让容器可以被宿主机或局域网内其他机器远程连接。仅当需要远程开发/部署时执行本地用 CLion Docker 工具链则不需要。10.1 安装 OpenSSHdockerexecfedora44-cpp-dev dnfinstall-yopenssh-server openssh-clients10.2 配置 sshd 并设置密码dockerexecfedora44-cpp-devsh-c ssh-keygen -A sed -i s/^#PermitRootLogin.*/PermitRootLogin yes/ /etc/ssh/sshd_config sed -i s/^#PasswordAuthentication.*/PasswordAuthentication yes/ /etc/ssh/sshd_config sed -i s/^PasswordAuthentication no/PasswordAuthentication yes/ /etc/ssh/sshd_config # 【自定义root 密码生产环境请改成强密码】 echo root:dev123456 | chpasswd # 【自定义可选创建非 root 开发用户】 useradd -m -s /bin/bash cppdev echo cppdev:dev123456 | chpasswd 10.3 重建容器并映射 SSH 端口容器创建时未映射端口需先提交镜像再重建容器加端口映射。# 1) 把当前配置提交为新镜像dockercommit fedora44-cpp-dev fedora44-cpp-dev:ssh# 2) 删除旧容器dockerrm-ffedora44-cpp-dev# 3) 重建容器映射 宿主机2222 → 容器22sshd 作为主进程# 【自定义宿主机端口 2222、挂载目录】dockerrun-d\--namefedora44-cpp-dev\-hcpp-dev\-p2222:22\-v~/cpp-projects:/workspace\fedora44-cpp-dev:ssh\/usr/sbin/sshd-Ddockerps--filternamefedora44-cpp-devsshd -D作为主进程PID 1容器启动即自动运行 SSH重启容器后无需手动开启。10.4 配置 SSH 密钥免密登录推荐# 1) 宿主机生成密钥若已存在可跳过ssh-keygen-ted25519-N-f~/.ssh/id_ed25519# 2) 把公钥放入容器PUBKEY$(cat~/.ssh/id_ed25519.pub)dockerexecfedora44-cpp-devsh-c mkdir -p /root/.ssh echo $PUBKEY /root/.ssh/authorized_keys chmod 700 /root/.ssh chmod 600 /root/.ssh/authorized_keys # 【自定义如创建了 cppdev 用户同样配置】 mkdir -p /home/cppdev/.ssh cp /root/.ssh/authorized_keys /home/cppdev/.ssh/ chown -R cppdev:cppdev /home/cppdev/.ssh chmod 700 /home/cppdev/.ssh chmod 600 /home/cppdev/.ssh/authorized_keys 10.5 验证 SSH 连接# 本机连接测试ssh-p2222rootlocalhostg --version | head -1# 局域网/远程机器连接# 【自定义将 IP 换成宿主机实际 IP】ssh-p2222root172.16.29.12410.6 提交配置关键步骤# 把 SSH 配置/密钥持久化到镜像之后重建容器不丢失dockercommit fedora44-cpp-dev fedora44-cpp-dev:ssh11. 附录B可选附加定制 gdb 版本源码编译背景某些课程/工具对 gdb 版本有硬性要求例要求7.8.x - 17.1.x而 Fedora 44 自带 gdb 17.2 可能超出上限。本节以降到 17.1为例演示源码编译安装到/usr/local覆盖系统版本的通用方法。无版本要求时请跳过本节。11.1 方案决策方案结论换 Fedora 43 镜像❌ 实测其 updates 仓库也已升级到 17.2无效安装旧版本 rpm降级⚠️ 可能触发依赖冲突gdb 拆分为多个子包源码编译指定版本✅ 版本精确可控、无依赖冲突推荐 本实例中 rpm 降级确实触发了依赖冲突gdb-17.1-4.fc43缺少配套gdb-headless子包因此切换源码编译。11.2 下载源码# 【自定义按需求改版本号 17.1 → 如 17.1 / 16.2 / 15.2】# 先下载到宿主机再拷贝进容器容器内直连 sourceware 可能 SSL 失败curl-sfL-o/tmp/gdb-17.1.tar.xz https://ftp.gnu.org/gnu/gdb/gdb-17.1.tar.xzdockercp/tmp/gdb-17.1.tar.xz fedora44-cpp-dev:/tmp/ 备选镜像源国内https://mirrors.tuna.tsinghua.edu.cn/gnu/gdb/gdb-17.1.tar.xz11.3 安装编译依赖dockerexecfedora44-cpp-dev dnfinstall-y\gcc gcc-cmaketexinfo flex bison\gmp-devel mpfr-devel libmpc-devel\readline-devel ncurses-devel python3-devel zlib-devel11.4 配置、编译、安装dockerexecfedora44-cpp-devsh-c cd /tmp tar xf gdb-17.1.tar.xz cd gdb-17.1 mkdir -p build cd build # 安装到 /usr/localPATH 中优先于 /usr/bin从而覆盖系统 gdb ../configure \ --prefix/usr/local \ --with-python/usr/bin/python3 \ --enable-tui \ --disable-werror make -j$(nproc) # 多核并行编译 make install 11.5 验证dockerexecfedora44-cpp-devsh-c hash -r command -v gdb # 应显示 /usr/local/bin/gdb gdb --version | head -1 # 应显示 GNU gdb (GDB) 17.1 重要安装到/usr/local后该目录在 PATH 中排在/usr/bin之前gdb命令自动使用新版系统原有 gdb 保留在后备互不冲突。11.6 自定义空间【自定义要装其他版本】只需改 11.2 的版本号和下载 URL。【自定义若编译时想启用 LZMA消除.gnu_debugdata警告】dockerexecfedora44-cpp-dev dnfinstall-ylzma-devel# 然后重新执行 11.4 的 configure/make/make install12. 结语教程完结后的清理本教程的所有容器都是可丢弃的环境真正保存在镜像里已 commit 的fedora44-cpp-dev:gdb171及导出的 tar容器随时可以从镜像重建。12.1 停用容器保留容器可随时再启动dockerstop fedora44-cpp-dev# 需要时docker start fedora44-cpp-dev12.2 删除容器彻底清理仅保留镜像# 确认镜像已提交见第 5 章然后删除容器dockercommit fedora44-cpp-dev fedora44-cpp-dev:gdb171# 保险起见再提交一次dockerrm-ffedora44-cpp-dev12.3 随时重建容器从镜像# 【自定义容器名 / 端口 / 挂载目录 / 镜像标签】dockerrun-d\--namefedora44-cpp-dev\-hcpp-dev\-v~/cpp-projects:/workspace\fedora44-cpp-dev:gdb171\sleepinfinity12.4 完整清理含镜像谨慎# 连镜像也删除此时只能从导出的 tar 恢复dockerrmi fedora44-cpp-dev:gdb171# 需要时docker load -i ~/Desktop/fedora44-cpp-dev.tar建议教程结束 → 导出镜像 tar 到桌面 → 删除容器 → 保留 tar 即等于保留了整个开发环境。教程完。所有命令均在本环境实测通过【自定义...】标记处请按需调整。
返回列表