CMake, vcpkg, Ninja, MSVC / g++ で Vulkan 写経環境を作る

Posted :

Updated :

Category :

Tags :

2026年のGW前に書籍「Vulkan実践入門」を買いました。おとなの自由研究です。

昔からグラフィックスプログラミングに興味がありましたし、低レイヤーを制御するってのはもうロマンでしかありません。
が、いかんせん難しい。DirectX3くらいから興味はあったけれど、そのたびに挫折してきたものです。

ある日、わかりやすい書籍を見つけました。今ではClaude Codeを使った学習支援もできますからね、49歳の今、ふたたびチャレンジすることにしたわけです。

この記事では開発環境の作り方と実行方法、Vulkanへの所感をお伝えします。

このような描画を制御する楽しさ is ロマン

開発環境を整える

まずは写経用の開発環境を整えます。ツール群は以下のとおり。

CategoryToolVersion
SDKVulkan SDK1.4.350.1
ジェネレータCMake4.4.0
ビルドシステムNinjaWindows: VS2026付属
Linux: 1.13.2
コンパイラMSVC
g++
Windows: VS2026付属
Linux: 15.2.0
パッケージマネージャvcpkg2026-05-27
エディタZed
Neovim / tmux
Windows: 1.x.x
Linux: 0.12.4 / 3.7b
  • VulkanのメインターゲットOSはWindowsとLinuxであること、この手の書籍はWindows + Visual Studio前提であることが大半なので、写経環境はWindows11とLinux(Kubuntu 26.04)にしました。
  • 当初はWindowsで写経をはじめて、現在はLinuxで行っています。
  • WindowsのエディタはLSPやフォーマッタが標準で使えるZedを使っていました。Visual Studioのエディタが好きになれなかったので、v1.0がリリースされたてのZedでVulkan開発できるよう環境を整えたかったんですよね。この記事はその軌跡の結果です。

写経の進め方

それでは具体的にどう進めていくかを整理していきます。

前提として、C++環境のインストールが済んでおり、Vulkan SDKとvcpkgはホームディレクトリ直下にインストールし、各種PATH設定がなされているものとします。
(最後にLinux向けにインストールするものをまとめました)

Vulkan Projectの作成手順

  1. vcpkg.jsonの作成
  2. CMakePresets.json / CMakeLists.txtの作成
  3. 章ごとに写経するディレクトリとファイルの作成
  4. compile_commands.jsonの生成
  5. 写経スタート

最終ディレクトリ構成

~/Develop/repo/github/nnamm/vulkan-learning
.
├── 01_triangle             // 写経対象
│   ├── CMakeLists.txt
│   ├── main.cpp
│   ├── triangle_app.cpp
│   └── triangle_app.h

├── 02_xxxxx                // 写経対象(章ごとに作成)

├── assets                  // サンプルリポジトリからコピー(進むごとにコピー)
│   └── shaders
│       └── triangle

├── build
│   └── debug
│       └── compile_commands.json

├── lib                     // 写経対象(進むごとに作成、更新)
│   ├── stage1
│   │  ├── common
│   │  ├── core
│   │  └── render
│   └── stage2
│      ├── common
│      ├── core
│      └── render

├── docs                    // AIに整理してもらう振り返りメモ
│   └── notes
│       ├── learning-log.md
│       └── vulkan-mental-model.md

├── AGENTS.md
├── CLAUDE.md
├── CMakeLists.txt
├── CMakePresets.json
├── LICENSE
├── README.md
└── vcpkg.json

1. vcpkg.jsonの作成(マニフェストモード)

書籍で使っているライブラリ(GLFWGLMAssimpstb)のインストール準備から始めます。
vcpkgのマニフェストモードで依存関係を管理し、バージョンも可能なかぎり書籍に合わせました。

./vcpkg.json (before)
{
  "name": "vulkan-learning",
  "version": "0.1.0",
  "dependencies": ["glfw3", "glm", "assimp", "stb"],
  "overrides": [
    { "name": "glfw3", "version": "3.3.8" },
    { "name": "assimp", "version": "5.4.0" }
  ]
}

builtin-baseline でvcpkg registryの参照コミットを固定する必要があるので、以下のコマンドを叩きます。

# vcpkg.jsonのあるディレクトリで実行 → vcpkg.jsonにbaselineが追加される
vcpkg x-update-baseline --add-initial-baseline

# vcpkgをバージョンアップした際など、builtin-baselineがある状態で更新する場合はこちら
vcpkg x-update-baseline
./vcpkg.json (after)
{
  "name": "vulkan-test-project",
  "version": "0.1.0",
  "dependencies": ["glfw3", "glm", "assimp", "stb"],
  "builtin-baseline": "38d91be5efb2f21fbef4a3c53295002823747431",
  "overrides": [
    { "name": "glfw3", "version": "3.3.8" },
    { "name": "assimp", "version": "5.4.0" }
  ]
}

builtin-baseline は、vcpkg registryの参照コミットを固定するための設定です。
glfw3とassimpは overrides で指定したバージョンが使われ、glmとstbは builtin-baseline の時点でregistryに登録されているバージョンが使われます。

2. CMakePresets.jsonとCMakeLists.txtの作成

プロジェクト全体に関わる準備をします。
CMake用のプリセットを作成しておくと、Debug/Releaseの指定も楽です。

./CMakePresets.json
{
  "version": 6,
  "configurePresets": [
    {
      "name": "base",
      "hidden": true,
      "generator": "Ninja",
      "toolchainFile": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake",
      "cacheVariables": {
        "CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
      }
    },
    {
      "name": "debug",
      "displayName": "Ninja / vcpkg / Debug",
      "inherits": "base",
      "binaryDir": "${sourceDir}/build/debug",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Debug"
      }
    },
    {
      "name": "release",
      "displayName": "Ninja / vcpkg / Release",
      "inherits": "base",
      "binaryDir": "${sourceDir}/build/release",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Release"
      }
    }
  ],
  "buildPresets": [
    {
      "name": "debug",
      "configurePreset": "debug"
    },
    {
      "name": "release",
      "configurePreset": "release"
    }
  ]
}

C++20以上が望ましいので CMakeLists.txt にその設定など。

./CMakeLists.txt
cmake_minimum_required(VERSION 3.25)
project(VulkanLearning LANGUAGES CXX)

# clangd
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

# 全ターゲット共通のビルド設定
add_library(project_options INTERFACE)
target_compile_features(project_options INTERFACE cxx_std_20)
target_compile_options(project_options INTERFACE
  $<$<CXX_COMPILER_ID:MSVC>:/utf-8>
)

# 外部パッケージ
find_package(Vulkan REQUIRED)
find_package(glfw3 CONFIG REQUIRED)
find_package(glm CONFIG REQUIRED)

# 使用する共通ライブラリステージ
set(LIB_STAGE "stage1")

# 章ごとのディレクトリ
add_subdirectory(01_triangle)

LIB_STAGE は変数です。写経を進めるにつれ ./lib/stage1 から ./lib/stage2 へと変わっていくと思ったので変数で指定できるようにしました。

3. 章ごとに写経するディレクトリとファイルの作成

章ごとに起点となるディレクトリ、ファイルを作成します。
最初はグラフィックスプログラミングにおける「Hello World」の三角形描画です。

./
└─01_triangle
   ├─CMakeLists.txt
   ├─main.cpp
   ├─triangle_app.cpp
   └─triangle_app.h

こちらの CMakeLists.txt には VkTriangle に関わるものだけを定義します。また、Windowsでもビルドできるようにしています。

./01_triangle/CMakeLists.txt
# 実行ファイル
add_executable(VkTriangle)

# Windows用の設定
if(WIN32)
  set_target_properties(VkTriangle PROPERTIES WIN32_EXECUTABLE TRUE)
endif()

# 実行ファイルを作成するためのソースファイル
target_sources(VkTriangle PRIVATE
  main.cpp
  triangle_app.cpp

  # 使用する内部ライブラリを明示的に宣言
  "${CMAKE_SOURCE_DIR}/lib/${LIB_STAGE}/core/asset_path.cpp"
  "${CMAKE_SOURCE_DIR}/lib/${LIB_STAGE}/core/buffer_resource.cpp"
  "${CMAKE_SOURCE_DIR}/lib/${LIB_STAGE}/core/command_buffer.cpp"
  "${CMAKE_SOURCE_DIR}/lib/${LIB_STAGE}/core/glfw_surface_provider.cpp"
  "${CMAKE_SOURCE_DIR}/lib/${LIB_STAGE}/core/graphics_pipeline_builder.cpp"
  "${CMAKE_SOURCE_DIR}/lib/${LIB_STAGE}/core/image_barrier.cpp"
  "${CMAKE_SOURCE_DIR}/lib/${LIB_STAGE}/core/shader_loader.cpp"
  "${CMAKE_SOURCE_DIR}/lib/${LIB_STAGE}/core/swapchain.cpp"
  "${CMAKE_SOURCE_DIR}/lib/${LIB_STAGE}/core/vulkan_context.cpp"
)

# 共通ライブラリ
target_include_directories(VkTriangle PRIVATE
  "${CMAKE_SOURCE_DIR}/lib/${LIB_STAGE}"
)

# 外部ライブラリのリンク
target_link_libraries(VkTriangle PRIVATE
  project_options
  Vulkan::Vulkan
  glfw
  glm::glm
)

# マクロ定義(GLMのVulkan向け補正)
target_compile_definitions(VkTriangle PRIVATE
  GLM_FORCE_DEPTH_ZERO_TO_ONE
  GLM_FORCE_RADIANS
)

# ---------------------------------------------------
# 必要なDLLの自動コピー(Windows環境用)
# ---------------------------------------------------
if(WIN32)
  add_custom_command(TARGET VkTriangle POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
    $<TARGET_RUNTIME_DLLS:VkTriangle>
    $<TARGET_FILE_DIR:VkTriangle>
    COMMAND_EXPAND_LISTS
  )
endif()

4. compile_commands.jsonの生成

コード補完してもらうためには compile_commands.json が必要です。補完は便利なのでドンドン使っちゃいましょう。以下を実行することでライブラリのインストールも行われます。

# プロジェクトルートで実行
# Configure(構成・生成)→ ./build/debugにcompile_commands.jsonが生成される
cmake --preset debug

.clangdcompile_commands.json の在り処を明示することで、clangdが正しく機能するようになります。今回はデバッグモードで cmake したので build/debug を指定してます。

./.clangd
CompileFlags:
  CompilationDatabase: build/debug

Diagnostics:
  Includes:
    IgnoreHeader:
      - "glm/.*"

僕は推移的インクルードはわかりにくいので好きではありません。必要なコードに必要なヘッダーを書くようにしています。これに関して、数学系ライブラリのGLMだけは追加の設定があります。

GLMをインクルードする場合、通常 #include "glm/glm.hpp" と書きますが、IgnoreHeader しておかないといろいろ警告が出て煩わしいので上記のようにしました。本来は必要なヘッダーを指定するのが良いのでしょうが、GLMは例外としています。

5. 写経スタート

ここまでくるとLSPによるコード補完やライブラリの参照ができるようになっています。
書籍を読む → コードを書くの繰り返しです。

コンパイル方法、ビルド、実行方法は以下のとおり。ルートディレクトリで実行します。

# 構成・生成とビルド(デバッグモード)
cmake --preset debug
cmake --build --preset debug

# 構成・生成とビルド(リリースモード)
cmake --preset release
cmake --build --preset release

# 実行
./build/debug/01_triangle/VkTriangle

cppファイル等を追加したら適宜 ./01_triangle/CMakeLists.txt を更新し、cmake --preset debug または cmake --preset release を行っていきます。

2026年7月現在の進捗と所感

GWから開始してから約3ヶ月がたちました。Vulkan実践入門は4章までを終え、三角形と立方体を描画するところまで来てます。

ここまでのVulkanに対する所感は、「やっぱ記述することが多い」ってことですね。

根本的なパイプラインそのものはOpenGL時代と根本的には同じだと思います。もちろん、進化はしているそうですけどね。
処理の流れ自体は変わっていませんが、定義することがめちゃくちゃ多いです。さすがは低レイヤー。

それから、書籍のサンプルは著者が開発してきた結果を内部ライブラリ化したのだろうと思います。要は、非常に整理されているんですね。
その分、一見すると描画までの処理がつかみにくい。とくにC++初学者にとっては。

Vulkanのメンタルモデル構築までは多くの復習が必要だな、というのが感想です。

「知る・理解する・できる・教える」で言えば僕はまだ「知る」レベル。
でも、整理されたコードを一つ一つ追っていき、フローを紙に書きだしたり、C++のお作法も調べながらやっていけばメンタルモデルは構築はもちろん、理解もできるはずです。

そのためには2000年代初期、仕事でコードを追っていた頃と同じことをすればいい。今はAIの力も借りられます。牛尾剛さんが書籍で仰っている「ディープコードリーディング」は独学でも十分できる時代。

時間はかかっていますが、今とても楽しい自由研究ができています。
引き続き、コツコツと楽しんでいきますよ。

参考)

写経中のリポジトリ

書籍のサンプルリポジトリ

Fish
# g++ / gcc / make / libcのヘッダ類一式
sudo apt install build-essential

# g++側でデバッグしたいなら
sudo apt install gdb

# clang系がいいなら(デバッガ含む)
sudo apt install clang lldb lld

# フォーマッタ
sudo apt install clang-format

# 静的解析
sudo apt install clang-tidy

# ビルドツール
sudo apt install ninja-build
Fish: Vulkan関係
# 実行時に必要なライブラリ
sudo apt install -y xz-utils libxcb-xinput0 libxcb-xinerama0 libxcb-cursor-dev

# X11向けVulkan開発
# 今回はGLFW v3.3.8のためこちらをインストール
sudo apt install xorg-dev

# GLFW v3.4以降ならWaylandのネイティブ対応も進んでいるのでこちらをインストール
sudo apt install libwayland-dev libxkbcommon-dev wayland-protocols
Fish: Vulkan SDKのインストール
cd ~
mkdir -p vulkan
cd vulkan

# 最新バージョン番号を取得し、バージョンを指定してダウンロード
set -l SDK_VERSION (curl -s https://vulkan.lunarg.com/sdk/latest/linux.txt)
curl -L -o vulkan_sdk.tar.xz https://sdk.lunarg.com/sdk/download/$SDK_VERSION/linux/vulkan_sdk.tar.xz

# チェックサムの確認(念のため)
sha256sum vulkan_sdk.tar.xz

# 展開とシンボリック
tar xf vulkan_sdk.tar.xz
ln -sfn ~/vulkan/$SDK_VERSION ~/vulkan/default

# ダウンロードファイルの削除
rm vulkan_sdk.tar.xz

# シェルに合わせてパスの設定

# 動作確認
vulkaninfo
vkcube
Fish: CMakeのインストール
# CMakeのインストール
cd ~
set CMAKE_VERSION "4.4.0"

wget https://github.com/Kitware/CMake/releases/download/v$CMAKE_VERSION/cmake-$CMAKE_VERSION.tar.gz
tar -zxf cmake-$CMAKE_VERSION.tar.gz
cd cmake-$CMAKE_VERSION
sudo ./bootstrap
sudo make
sudo make install

# ダウンロードファイル等の削除
cd ~
rm cmake-$CMAKE_VERSION.tar.gz
sudo rm -r cmake-$CMAKE_VERSION
Fish
# vcpkgのインストール
cd ~
git clone https://github.com/microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh -disableMetrics

# シェルに合わせてパスの設定

※OSのバージョンによって必要なものは異なりますので、最新情報は公式サイトを参照してください。

nnammのアバター