用 Podman 和 Dev Containers 管理 C++ 开发环境
写 C++ 之前,常常得先凑齐编译器、头文件、链接库和运行时 DLL。习惯了 dotnet restore 和 cargo build,再给 CMake 工程配环境,难免想把这些准备工作一次做完。
最近整理了几个项目:工具链和依赖放进容器或独立 SDK,CMake 负责查找依赖和生成构建规则,Ninja 执行构建,VS Code 通过 Dev Containers 进入环境。
Linux 部分记录 Arch + Podman + VS Code 的实际配置,包括 NVIDIA GPU 和 Wayland 窗口。Windows 部分介绍已有的 LLVM-MinGW 脚本和待尝试的 portable MSYS2;Windows 上的 OCCT 构建还没做。
1 先确定依赖由谁管理
1.1 CMake 的工作可以少一点
CMake 既能用 FetchContent 下载第三方源码,也能用 find_package() 查找已安装的库。小项目可以随项目声明源码依赖;多个项目共用大型 SDK 时,我选择在开发环境中安装一次。参见 CMake 依赖指南。
职责分层:
| 内容 | 放在哪里 | 何时更新 |
|---|---|---|
| 编译器、CMake、Ninja、调试器 | 开发镜像或独立工具链目录 | 更新开发环境时 |
| 发行版提供的开发库 | 镜像的包安装步骤 | 调整包列表时 |
| 指定版本的第三方 SDK | 镜像内的 /opt | 升级 SDK 或修改构建选项时 |
| 项目源文件、链接关系、编译标准 | CMakeLists.txt | 修改项目时 |
| 构建类型和构建目录 | CMakePresets.json | 调整开发配置时 |
| 缓存、目标文件和可执行文件 | 项目的 build/ | 每次构建时 |
例如,一个使用 SDL3 和 Vulkan 的项目,CMake 可以只有:
cmake_minimum_required(VERSION 3.24)
project(viewer LANGUAGES CXX)
find_package(SDL3 CONFIG REQUIRED)
find_package(Vulkan REQUIRED)
add_executable(viewer src/main.cpp)
target_compile_features(viewer PRIVATE cxx_std_20)
target_link_libraries(viewer PRIVATE SDL3::SDL3 Vulkan::Vulkan)缺少依赖时,CMake 配置阶段报错,回到镜像配方补齐即可。项目不用写 pacman 命令、下载地址或本机绝对库路径。
优先链接库导出的 CMake target,让它携带头文件路径、编译定义和传递依赖。只有 pkg-config 信息的库,可以用 pkg_check_modules(... IMPORTED_TARGET ...)。
依赖也可以由 Conan、vcpkg 或脚本准备。本文使用发行版包和自行安装的 SDK。
1.2 构建目录与依赖安装目录分开
我的项目会保存一份类似这样的 CMakePresets.json:
{
"version": 3,
"configurePresets": [
{
"name": "release",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/release",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"CMAKE_EXPORT_COMPILE_COMMANDS": true
}
}
],
"buildPresets": [
{
"name": "release",
"configurePreset": "release"
}
]
}进入开发环境后,配置与构建分别执行:
cmake --preset release
cmake --build --preset release --parallel 4首次配置确定编译器和依赖位置,生成 Ninja 文件。之后只改源码时,通常直接构建即可。
共享配置提交到 CMakePresets.json;本机 SDK 路径放在不提交的 CMakeUserPresets.json。参见 Presets 文档。
删除 build/release/ 不影响容器 /usr、/opt 中的依赖,大型 SDK 无需重编。源码依赖也能做到,但需另设缓存和安装目录。
2 把开发环境写进 Containerfile
2.1 从 Arch 镜像准备工具链
我选 Arch 镜像,方便一起更新编译器和开发库。希望版本变化少一些,可以选 Debian Stable 或 Ubuntu LTS;容器发行版不必与宿主机一致。
下面提取两份实际配方的公共部分,保留窗口与 Vulkan 工具,计算库按需增减:
FROM docker.io/library/archlinux:latest
RUN sed -i '1iServer = https://mirrors.cernet.edu.cn/archlinux/$repo/os/$arch' /etc/pacman.d/mirrorlist
RUN pacman -Syu --noconfirm --needed \
base-devel cmake ninja pkgconf git curl ca-certificates \
clang lld gdb python \
zlib libpng fftw nlohmann-json glm eigen \
sdl3 wayland wayland-protocols wayland-utils libdecor libxkbcommon \
libxext libglvnd \
vulkan-headers vulkan-icd-loader vulkan-validation-layers vulkan-tools \
shader-slang shaderc glslang spirv-tools \
fontconfig freetype2 onetbb rapidjson gtk3 ttf-dejavu noto-fonts-cjk \
&& fc-cache -f \
&& pacman -Scc --noconfirm
RUN install -d -m 0700 /tmp/xdg-runtime
WORKDIR /workspaces
CMD ["/bin/bash"]换源后执行完整更新。包列表可按用途删减:
| 用途 | 软件包 |
|---|---|
| 编译与构建 | base-devel、cmake、ninja |
| Vulkan 开发与诊断 | 头文件、加载器、验证层、工具 |
| 着色器编译 | shader-slang、shaderc、glslang |
GTK、Wayland、OpenGL 运行库不决定应用的渲染后端。例如 SDL3 的 Wayland 窗口装饰可能使用 libdecor,其插件另有运行时依赖。
构建这个公共环境:
podman build --pull=always \
-t localhost/arch-cpp-dev:20261110 \
-f Containerfile .此镜像只有系统开发包。 后文的 arch-occt:8.0.1 另含 SDK 和演示程序,不能直接互换。
2.2 指定版本的 SDK 放进 /opt
仓库版本不合适时,在镜像构建阶段编译 SDK,用 cmake --install 安装到带版本号的 /opt 前缀:
/opt/
├── occt/8.0.1/
│ ├── include/
│ ├── lib/
│ └── share/
├── imgui/1.93.0-docking/
│ ├── bin/
│ ├── include/
│ └── lib/
└── src/
├── OCCT-8_0_1/
└── imgui-1.93.0-docking/宿主机提前下载源码并记录版本、来源、校验和,Containerfile 用 COPY 导入。测试、文档及自动下载依赖等构建选项也在配方中设置。
多阶段构建分三步:
- 基础阶段安装工具。
- SDK 阶段编译依赖。
- 从相同基础阶段创建开发镜像,复制
/opt。
最终镜像保留编译工具和源码,供开发、调试使用;临时目标文件可以删除。
ImGui 需要补一层安装配置:把固定版本的核心、SDL3 和 Vulkan 后端编译为静态库,安装头文件,导出 imgui::imgui、imgui::sdl3、imgui::vulkan。项目中使用:
find_package(imgui 1.93.0 EXACT CONFIG REQUIRED)
target_link_libraries(viewer PRIVATE imgui::sdl3 imgui::vulkan)镜像通过环境变量提供 SDK 前缀:
ENV CMAKE_PREFIX_PATH=/opt/occt/8.0.1:/opt/imgui/1.93.0-docking路径分隔符取决于传入方式:
| 方式 | 多个路径的分隔符 |
|---|---|
Linux 环境变量 CMAKE_PREFIX_PATH | 冒号 : |
CMake 参数 -DCMAKE_PREFIX_PATH="..." | 分号 ;,加引号保护 |
查找失败时,先检查 SDK 是否安装了 *Config.cmake:
CMAKE_PREFIX_PATH:安装前缀。imgui_DIR:包含imguiConfig.cmake的目录。
两者都不是头文件目录。查看搜索过程:
cmake --preset release --debug-find-pkg=SDL3CMake 找到链接库后,运行时加载器仍需找到共享库。镜像中为 OCCT 配置:
RUN printf '%s\n' '/opt/occt/8.0.1/lib' > /etc/ld.so.conf.d/occt.conf \
&& ldconfig这样不用每次设置 LD_LIBRARY_PATH。并行安装不兼容版本时,需检查加载顺序。
2.3 保存配方,也保存已经构建好的环境
一次 SDK 构建耗时约 13 分 35 秒,镜像约 3.8 GB。日常直接引用成品,升级依赖时再构建。
配方不等于版本锁。 archlinux:latest 和 pacman -Syu 随仓库变化;固定基础镜像 digest,随后下载的包不一定固定。
如果需要恢复当前环境,可以保存镜像和包清单:
podman run --rm localhost/arch-occt:8.0.1 pacman -Q > packages.txt
podman save --format oci-archive \
-o arch-occt-8.0.1.oci.tar localhost/arch-occt:8.0.1
# Restore the saved image when needed.
podman load -i arch-occt-8.0.1.oci.tar包清单用于核对版本,OCI 归档用于恢复镜像。GPU 仍依赖宿主机,还需记录驱动版本和测试设备。
无标签的 <none>:<none> 镜像可能来自中间阶段或旧构建。先用 podman system df 查看空间,确认不再需要缓存后再运行 podman image prune。
3 在 VS Code 中使用同一套工具链
3.1 项目只引用开发镜像
宿主机安装 VS Code 和 Dev Containers 扩展,在用户设置中指定 Podman:
{
"dev.containers.dockerPath": "podman"
}这是 VS Code 文档提供的配置方式,但 Podman 等兼容 Docker CLI 的引擎不在其正式支持范围内。
项目里的 .devcontainer/devcontainer.json 可以从下面这个配置开始:
{
"name": "Arch C++ development",
"image": "localhost/arch-cpp-dev:20261110",
"workspaceMount": "source=${localWorkspaceFolder},target=/workspaces/project,type=bind",
"workspaceFolder": "/workspaces/project",
"customizations": {
"vscode": {
"extensions": [
"ms-vscode.cmake-tools",
"ms-vscode.cpptools"
],
"settings": {
"cmake.useCMakePresets": "always"
}
}
}
}打开项目,执行 Dev Containers: Reopen in Container。此时终端中的 cmake、c++ 和调试器应来自容器,C/C++ 扩展也在容器中解析头文件,宿主机只显示编辑器界面。
多个项目共用一个开发镜像,各自维护 devcontainer.json 和 CMake 文件。临时装包可以用于排查,长期依赖要写回 Containerfile。
同名镜像更新后,需要在 Dev Containers 中重新创建容器;已有容器不会自动换用新镜像。
3.2 挂载路径决定数据保存在哪里
工作区使用 bind mount:宿主机项目目录映射到 /workspaces/project。源码和 build/ 留在宿主机;未挂载出去的文件保存在容器内。
如需读取其他源码或数据,可以额外挂载目录。下面是我用过的 Home 挂载片段:
{
"mounts": [
"source=${localEnv:HOME},target=/host-home,type=bind"
]
}将片段合并进已有配置。整个 Home 可写意味着容器也能修改其中的文件;通常只挂需要的子目录即可,必要时加 readonly。
写权限要结合运行方式检查:
| 运行方式 | 需要注意 |
|---|---|
| 默认 rootless Podman | 容器 root 通常映射到启动它的宿主用户 |
| 容器内普通用户 | 检查 UID 映射,必要时使用 --userns=keep-id |
| rootful Podman | 不套用 rootless 的映射假设 |
Dev Containers 的用户配置也会参与其中。参见 Podman 用户与挂载选项。
小型构建脚本还可以只读挂载源码和依赖缓存,只向临时目录写入,成功后再复制产物。第 5 部分给出例子。
代理可在 containerEnv 中设置为 http://host.containers.internal:7890,但端口需匹配实际配置,宿主服务也要允许容器访问。注意:
- 容器中的
127.0.0.1指向容器自身。 containerEnv不负责镜像拉取和构建阶段的网络。
4 让容器访问 GPU 和 Wayland
4.1 NVIDIA 驱动与 Container Toolkit 放在宿主机
普通构建不需要 GPU 参数。运行 Vulkan 程序时,再接入设备和显示连接。以下配置使用 Arch 宿主机、RTX 4050 Laptop GPU 和 Wayland 桌面。
先确认宿主机上的 NVIDIA 驱动可以正常工作,再安装容器工具:
nvidia-smi
sudo pacman -Syu --needed podman nvidia-container-toolkit
sudo systemctl enable --now nvidia-cdi-refresh.path
sudo systemctl enable --now nvidia-cdi-refresh.service
nvidia-ctk cdi list实测 NVIDIA Container Toolkit 为 1.20.1。nvidia-cdi-refresh 生成 CDI 设备描述,Podman 据此接入 GPU 和所需的宿主机文件。该服务完成任务后退出,成功执行后显示 inactive (dead) 可以是正常状态。参见 NVIDIA CDI 文档。
如果 nvidia-ctk cdi list 没有列出设备,先检查服务日志:
journalctl -u nvidia-cdi-refresh.service
sudo systemctl restart nvidia-cdi-refresh.serviceCDI 方案中,镜像安装 Vulkan 加载器、头文件和工具;NVIDIA 驱动由宿主机提供,无需在镜像中安装内核驱动。
本文使用 --gpus=all,也可按 Podman 版本选择显式 CDI 参数 --device=nvidia.com/gpu=all。参见 GPU 参数说明。
4.2 用一个临时容器先测试窗口
分别检查 GPU 和窗口。Wayland 使用桌面会话的 Unix socket,不需要开放 TCP 端口。
将实际配置保存为 run-wayland.sh,从宿主机 Wayland 桌面终端执行。默认运行 SDK 镜像中的 ImGui SDL3/Vulkan 示例;第 2.1 节的公共镜像不包含它。
#!/usr/bin/env bash
set -euo pipefail
image="${OCCT_DEV_IMAGE:-localhost/arch-occt:8.0.1}"
runtime_directory="${XDG_RUNTIME_DIR:?Run from a desktop session}"
display_name="${WAYLAND_DISPLAY:?WAYLAND_DISPLAY is not set}"
case "$display_name" in
/*) wayland_socket="$display_name" ;;
*) wayland_socket="$runtime_directory/$display_name" ;;
esac
if [[ ! -S "$wayland_socket" ]]; then
printf 'Wayland socket not found: %s\n' "$wayland_socket" >&2
exit 1
fi
if [[ $# -eq 0 ]]; then
set -- imgui-sdl3-vulkan-demo
fi
exec podman run --rm -it \
--network=none \
--gpus=all \
--security-opt=label=disable \
--env NVIDIA_DRIVER_CAPABILITIES=graphics,display,utility \
--env XDG_RUNTIME_DIR=/tmp/xdg-runtime \
--env WAYLAND_DISPLAY=wayland-0 \
--env SDL_VIDEODRIVER=wayland \
--env VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation \
--mount "type=bind,source=$wayland_socket,target=/tmp/xdg-runtime/wayland-0" \
"$image" "$@"脚本中的几个约定:
- 镜像预先创建权限为
0700的/tmp/xdg-runtime,桌面 socket 挂载到其中。 SDL_VIDEODRIVER=wayland强制使用原生 Wayland。--security-opt=label=disable关闭该容器的 SELinux 标签隔离;启用 SELinux 的系统需按挂载策略决定是否保留。
随后分别检查设备和窗口:
chmod +x run-wayland.sh
./run-wayland.sh vulkaninfo --summary
./run-wayland.sh实测识别到 RTX 4050 Laptop GPU,并显示了 ImGui 窗口:
| 项目 | 输出 |
|---|---|
| NVIDIA 驱动 | 615.78.08 |
| GPU 支持的 Vulkan API | 1.4.351 |
| Vulkan Instance Version | 1.4.363 |
Instance Version 与具体 GPU 的 API 版本不是同一项信息。
这次试运行还暴露了几个具体问题:
| 输出或现象 | 排查结果 |
|---|---|
提示设置了 VK_INSTANCE_LAYERS | 脚本主动启用了验证层,是加载提示 |
DISPLAY 未设置 | 这次使用 Wayland,没有提供 X11 的显示连接 |
libgtk-3.so.0 找不到 | libdecor 的 GTK 插件缺运行时依赖,配方补充了 gtk3 |
| 系统标题栏显示方框 | 容器的 fc-list 没有输出,配方补充字体并更新缓存 |
non-acquired-swapchain-image-used | ImGui 交换链辅助代码提前转换图像布局,存在对应的上游问题 |
交换链问题不能靠关闭验证层解决,见 ImGui #9496。配方已为示例的 render-pass 路径加入局部补丁。
系统字体供标题栏等组件使用;ImGui 内部显示中文,仍需应用自行加载字体。
4.3 把已确认的运行参数加入 Dev Containers
命令行测试后,可以把 GPU 和 Wayland 相关配置合并到第 3.1 节的 devcontainer.json:
{
"runArgs": [
"--gpus=all",
"--security-opt=label=disable"
],
"containerEnv": {
"NVIDIA_DRIVER_CAPABILITIES": "graphics,display,utility",
"XDG_RUNTIME_DIR": "/tmp/xdg-runtime",
"WAYLAND_DISPLAY": "wayland-0",
"SDL_VIDEODRIVER": "wayland"
},
"mounts": [
"source=${localEnv:XDG_RUNTIME_DIR}/${localEnv:WAYLAND_DISPLAY},target=/tmp/xdg-runtime/wayland-0,type=bind"
]
}该片段假设宿主机 WAYLAND_DISPLAY 是 wayland-0 这样的相对名称。若已是绝对路径,需调整 source;其他挂载追加到同一个 mounts 数组。
原配置使用 /tmp/wayland-0 绝对路径,这里统一为运行脚本的布局。验证层按程序需要单独开启即可。
5 Windows 和小型工具也能沿用这种分工
5.1 已有脚本中的便携工具链
另一个小型 Windows 工具项目使用两个构建脚本,工具链管理方式也能复用。
Linux 的 build.sh 固定 mstorsjo/llvm-mingw:20261104 镜像及 MinHook 版本、commit。宿主机准备依赖缓存,容器只读挂载源码和依赖,向临时目录写入:
# Run from the project directory after preparing the dependency cache.
work_dir="$(mktemp -d /tmp/cpp-build.XXXXXX)"
dependency_dir="${MINHOOK_SOURCE_DIR:?Set the prepared dependency directory}"
podman run --rm --pull=never \
--userns=keep-id --network=none \
--volume "$PWD:/src:ro" \
--volume "$dependency_dir:/minhook:ro" \
--volume "$work_dir:/work:rw" \
--workdir /work \
docker.io/mstorsjo/llvm-mingw:20261104 \
x86_64-w64-mingw32-clang++ --version此处只演示挂载和工具链。实际脚本编译 EXE/DLL,确认产物齐全后复制到 artifacts/;容器退出即清理,临时目录留在 /tmp 供排查。
Windows 的 build.ps1 使用 LLVM-MinGW UCRT 便携包:
- 将工具链和 MinHook 归档缓存到
%TEMP%下的专用目录。 - 校验 SHA-256,再解压;工具链解压成功后复用缓存。
- 编译并复制产物。
- 恢复当前进程的 PATH,清理本次工作目录。
少量源文件可以由脚本直接调用编译器。以后改用 CMake,仍可保留工具链准备、缓存、校验和产物复制流程。
5.2 portable MSYS2 的后续思路
依赖较多时,可以把 MSYS2 放进独立目录。官方提供自解压包和 .tar.zst 归档,解压后运行一次登录 Shell 初始化;相比安装器,主要缺少快捷方式和卸载项等系统集成。参见 安装方式说明。
例如环境放在 C:\Dev\msys64,项目放在 C:\Projects,启动 UCRT64 Shell:
C:\Dev\msys64\msys2_shell.cmd -ucrt64在打开的 Shell 中完整更新,然后安装对应工具:
pacman -Syu
pacman -S --needed \
mingw-w64-ucrt-x86_64-toolchain \
mingw-w64-ucrt-x86_64-cmake \
mingw-w64-ucrt-x86_64-ninja若更新要求退出终端,重新打开后继续完成更新。构建原生 Windows 程序,应使用对应 MinGW 环境的 CMake,可搭配 Ninja。参见 MSYS2 CMake 文档。
工具与 C++ 库保持在同一套环境中:
| 环境 | 工具链与 C++ 标准库 |
|---|---|
| UCRT64 | GCC / libstdc++ |
| CLANG64 | Clang / libc++ |
| MSVC | MSVC 工具链及其 C++ 标准库 |
同为 Windows x64,即使共用 UCRT,也不保证 C++ ABI 兼容。参见 MSYS2 环境说明。
便携目录便于备份,但没有容器的进程与文件系统隔离。使用时:
- 项目放在环境目录之外,通过启动脚本使用工具,少改全局 PATH。
- 滚动仓库的包清单用于重装,完整目录快照用于恢复已知可用环境。
- 恢复时尽量保留原路径,并重新创建项目构建目录。
源码、依赖缓存、工具链和构建产物分开保存后,清理项目就不会顺手删掉整套 SDK。
附录:完整的 OCCT 开发镜像配方
配方使用 OCCT 8.0.1 和 ImGui 1.93.0-docking。OCCT 保留建模、应用框架和数据交换模块,关闭 OpenGL 后端与 DRAW;部分工具库仍随模块依赖构建。ImGui 单独编译 SDL3/Vulkan 后端和示例。
配套文件包括构建过滤规则、ImGui 安装配置、补丁、Wayland 脚本及源码来源和 SHA-256 清单。源码需另行下载,GUI 测试状态见 4.2 节。
示例构建目录应当包含:
occt-8.0.1-build/
├── Containerfile
├── .containerignore
├── cmake/imgui/
│ ├── CMakeLists.txt
│ └── imguiConfig.cmake.in
├── patches/imgui-renderpass-acquire.patch
├── run-wayland.sh
└── sources/
├── SHA256SUMS
├── ORIGINS.txt
├── OCCT-8_0_1/
└── imgui-1.93.0-docking/其中两个源码目录按以下命令准备。在解压出的 occt-8.0.1-build 目录执行:
cd sources
curl --fail --location --retry 3 \
-o occt-8.0.1.tar.gz \
https://github.com/Open-Cascade-SAS/OCCT/archive/refs/tags/V8_0_1.tar.gz
curl --fail --location --retry 3 \
-o imgui-1.93.0-docking.tar.gz \
https://github.com/ocornut/imgui/archive/refs/tags/v1.93.0-docking.tar.gz
sha256sum --check SHA256SUMS确认两项校验都通过后再解压:
tar -xzf occt-8.0.1.tar.gz
tar -xzf imgui-1.93.0-docking.tar.gz
cd ..完整的 Containerfile 如下。COPY 使用的路径均相对于上述构建目录,配套的 CMake 文件和补丁不能省略。
FROM docker.io/library/archlinux:latest AS base
RUN sed -i '1iServer = https://mirrors.cernet.edu.cn/archlinux/$repo/os/$arch' /etc/pacman.d/mirrorlist
RUN pacman -Syu --noconfirm --needed \
base-devel cmake ninja pkgconf git curl ca-certificates \
clang lld gdb python \
zlib libpng fftw nlohmann-json glm eigen \
sdl3 wayland wayland-protocols wayland-utils libdecor libxkbcommon libxext libglvnd \
vulkan-headers vulkan-icd-loader vulkan-validation-layers vulkan-tools \
shader-slang shaderc glslang spirv-tools \
fontconfig freetype2 onetbb rapidjson gtk3 ttf-dejavu noto-fonts-cjk \
&& fc-cache -f \
&& pacman -Scc --noconfirm
FROM base AS sdk-builder
ARG BUILD_JOBS=4
COPY sources/OCCT-8_0_1/ /opt/src/OCCT-8_0_1/
RUN cmake -S /opt/src/OCCT-8_0_1 -B /tmp/occt-build -G Ninja \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DBUILD_CPP_STANDARD=C++17 \
-DBUILD_LIBRARY_TYPE=Shared \
-DCMAKE_INSTALL_PREFIX=/opt/occt/8.0.1 \
-DINSTALL_DIR_LAYOUT=Unix \
-DINSTALL_DIR_WITH_VERSION=OFF \
-DBUILD_USE_VCPKG=OFF \
-DBUILD_GTEST=OFF \
-DBUILD_DOC_Overview=OFF \
-DBUILD_DOC_RefMan=OFF \
-DBUILD_USE_PCH=OFF \
-DBUILD_RELEASE_DISABLE_EXCEPTIONS=OFF \
-DBUILD_MODULE_FoundationClasses=ON \
-DBUILD_MODULE_ModelingData=ON \
-DBUILD_MODULE_ModelingAlgorithms=ON \
-DBUILD_MODULE_ApplicationFramework=ON \
-DBUILD_MODULE_DataExchange=ON \
-DBUILD_MODULE_Visualization=OFF \
-DBUILD_MODULE_Draw=OFF \
-DUSE_OPENGL=OFF \
-DUSE_GLES2=OFF \
-DUSE_XLIB=OFF \
-DUSE_TK=OFF \
-DUSE_FREETYPE=ON \
-DUSE_TBB=ON \
-DUSE_RAPIDJSON=ON \
-DUSE_FREEIMAGE=OFF \
-DUSE_FFMPEG=OFF \
-DUSE_OPENVR=OFF \
-DUSE_VTK=OFF \
-DUSE_DRACO=OFF \
-DUSE_MMGR_TYPE=NATIVE \
&& cmake --build /tmp/occt-build --parallel "${BUILD_JOBS}" \
&& cmake --install /tmp/occt-build \
&& rm -rf /tmp/occt-build
COPY sources/imgui-1.93.0-docking/ /opt/src/imgui-1.93.0-docking/
COPY cmake/imgui/ /tmp/imgui-cmake/
COPY patches/imgui-renderpass-acquire.patch /tmp/imgui-renderpass-acquire.patch
RUN patch -d /opt/src/imgui-1.93.0-docking -p1 < /tmp/imgui-renderpass-acquire.patch \
&& cmake -S /tmp/imgui-cmake -B /tmp/imgui-build -G Ninja \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_POSITION_INDEPENDENT_CODE=ON \
-DCMAKE_INSTALL_PREFIX=/opt/imgui/1.93.0-docking \
-DIMGUI_SOURCE_DIR=/opt/src/imgui-1.93.0-docking \
&& cmake --build /tmp/imgui-build --parallel "${BUILD_JOBS}" \
&& cmake --install /tmp/imgui-build \
&& rm -rf /tmp/imgui-build
FROM base AS development
COPY --from=sdk-builder /opt/ /opt/
RUN printf '%s\n' '/opt/occt/8.0.1/lib' > /etc/ld.so.conf.d/occt-8.0.1.conf \
&& ldconfig \
&& install -d -m 0700 /tmp/xdg-runtime
ENV CMAKE_PREFIX_PATH=/opt/occt/8.0.1:/opt/imgui/1.93.0-docking
ENV PATH=/opt/imgui/1.93.0-docking/bin:${PATH}
WORKDIR /workspaces
CMD ["/bin/bash"]在该目录构建并保留日志:
set -o pipefail
podman build --pull=always \
--build-arg BUILD_JOBS=4 \
-t localhost/arch-occt:8.0.1 \
-f Containerfile . 2>&1 | tee build.log排查同一配方时可改用 --pull=never,复用本地基础镜像。缓存失效范围取决于修改位置:
- 改基础阶段包列表:后续 SDK 层需重新构建。
- 只改 OCCT 步骤之后的 ImGui 配置:可能复用 OCCT 层。
构建完成后,在宿主机 Wayland 桌面终端运行配套脚本:
./run-wayland.sh vulkaninfo --summary
./run-wayland.sh