TCC + cimgui + DirectX11 セットアップ手順書


全体構成

cimgui/                    ← クローン済み
  cimgui.cpp
  cimgui.h
  cimgui_impl.cpp          ← DX11バックエンドのCラッパー
  cimgui_impl.h
  imgui/                   ← サブモジュール
    imgui.cpp
    imgui_draw.cpp
    imgui_tables.cpp
    imgui_widgets.cpp
    backends/
      imgui_impl_dx11.cpp
      imgui_impl_win32.cpp

↓ MSVCでDLLビルド

cimgui.dll                 ← TCCからリンクするDLL
cimgui.def                 ← tiny_impdefで生成

↓ TCCでコンパイル

my_app.c → my_app.exe

Step 1: サブモジュールの初期化

クローン後にサブモジュール(imgui本体)を取得する。

cd cimgui
git submodule update --init --recursive

完了後、imgui/ フォルダ内に imgui.cpp, backends/imgui_impl_dx11.cpp などが入っていることを確認。


Step 2: cimgui.dll を MSVC でビルド

2-1. Developer Command Prompt を開く

「x64 Native Tools Command Prompt for VS 2022」を使用。

2-2. backends_wrapper.cpp を作成

cimgui/ 直下に以下の内容でファイルを作成する。
IMGUI_IMPL_API を空にすることで二重装飾を防ぎ、cimgui_impl.cpp 側のラッパーから正しく呼び出せるようにする。

// backends_wrapper.cpp
#define IMGUI_IMPL_API
#include "imgui/backends/imgui_impl_dx11.cpp"
#include "imgui/backends/imgui_impl_win32.cpp"

2-3. ビルドコマンド

cimgui/ フォルダをカレントにして実行:

cl.exe /LD /O2 /MD /EHsc ^
  /DCIMGUI_DLL ^
  /I. /Iimgui /Iimgui/backends ^
  cimgui.cpp ^
  cimgui_impl.cpp ^
  imgui/imgui.cpp ^
  imgui/imgui_draw.cpp ^
  imgui/imgui_tables.cpp ^
  imgui/imgui_widgets.cpp ^
  imgui/imgui_demo.cpp ^
  backends_wrapper.cpp ^
  /link d3d11.lib dxgi.lib user32.lib ^
  /OUT:cimgui.dll

ビルドオプションの説明

オプション意味
/LDDLLとしてビルド
/DCIMGUI_DLLエクスポートマクロを有効化
/MDマルチスレッドDLL CRT(Releaseビルド)
imgui_demo.cppShowDemoWindow など必須関数を含む(忘れるとリンクエラー)
backends_wrapper.cppバックエンドを IMGUI_IMPL_API 空で取り込むラッパー

2-4. 生成物の確認

cimgui.dll   ← メイン
cimgui.lib   ← インポートライブラリ(TCCでは使わない)
cimgui.exp

Step 3: .def ファイルの生成

tiny_impdef を使って cimgui.dll から .def を生成する。

tiny_impdef cimgui.dll -o cimgui.def

tiny_impdef の場所: TCCのインストールフォルダ(例: C:\tcc\tiny_impdef.exe

生成された cimgui.def の冒頭がこのような形式であることを確認:

LIBRARY cimgui.dll

EXPORTS
igBegin
igEnd
igNewFrame
igRender
ImGui_ImplDX11_Init
ImGui_ImplDX11_NewFrame
ImGui_ImplDX11_RenderDrawData
ImGui_ImplWin32_Init
ImGui_ImplWin32_NewFrame
...

Step 4: TCC 用の C コードを書く

4-1. 必要なヘッダの扱い

cimgui.hcimgui_impl.h はそのままインクルードできる。ただし以下のマクロ定義をインクルードの前に必ず入れる。

#define CIMGUI_DEFINE_ENUMS_AND_STRUCTS
#include "cimgui.h"
#include "cimgui_impl.h"

4-2. 初期化コード

既存の tcc_dx11_mina.cInitD3D() 成功後に追加:

// Win32バックエンド初期化
ImGui_ImplWin32_Init(hwnd);

// DX11バックエンド初期化(g_dev, g_ctx は既存のDX11デバイス)
ImGui_ImplDX11_Init(g_dev, g_ctx);

// ImGuiコンテキスト作成
igCreateContext(NULL);

// スタイル設定(任意)
igStyleColorsDark(NULL);

4-3. Render() に ImGui 描画を追加

void Render()
{
    float clearColor[4] = { 0.0f, 0.2f, 0.4f, 1.0f };
    g_ctx->lpVtbl->ClearRenderTargetView(g_ctx, (void*)g_backbuffer, clearColor);
    g_ctx->lpVtbl->OMSetRenderTargets(g_ctx, 1, (void* const*)&g_backbuffer, NULL);

    // --- ImGui フレーム開始 ---
    ImGui_ImplDX11_NewFrame();
    ImGui_ImplWin32_NewFrame();
    igNewFrame();

    // --- UI 描画 ---
    int show = 1;
    igShowDemoWindow(&show);  // デモウィンドウ

    // 独自ウィンドウ例
    igBegin("Hello from TCC!", NULL, 0);
    igText("DirectX11 + cimgui + TCC");
    if (igButton("Click me", (ImVec2){0,0})) {
        // ボタン押下時の処理
    }
    igEnd();

    // --- ImGui 描画実行 ---
    igRender();
    ImGui_ImplDX11_RenderDrawData(igGetDrawData());

    g_swapchain->lpVtbl->Present(g_swapchain, 1, 0);
}

4-4. WndProc に Win32メッセージ処理を追加

// WndProc の先頭に追加
extern int ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    // ImGuiがメッセージを処理した場合は早期リターン
    if (ImGui_ImplWin32_WndProcHandler(hwnd, msg, wParam, lParam))
        return TRUE;

    switch (msg) {
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
    }
    return DefWindowProcW(hwnd, msg, wParam, lParam);
}

4-5. クリーンアップ

void Cleanup()
{
    ImGui_ImplDX11_Shutdown();
    ImGui_ImplWin32_Shutdown();
    igDestroyContext(NULL);
    CleanupD3D();  // 既存のDX11クリーンアップ
}

Step 5: TCC でコンパイル

my_app.c, cimgui.dll, cimgui.def, d3d11.def を同じフォルダに置いて:

tcc my_app.c cimgui.def d3d11.def -o my_app.exe

実行時の配置

my_app.exe
cimgui.dll    ← 必須(同じフォルダ)
d3d11.dll     ← Windows標準、システムにある
D3DCompiler_47.dll  ← シェーダーコンパイルに必要

よくあるビルドエラーと対処

imgui_impl_win32.cppWndProcHandler をエクスポートしていない

cimgui_impl.cpp を確認し、imgui_impl_win32 の関数が含まれているか確認。 なければ imgui/backends/imgui_impl_win32.cpp を明示的にビルドに追加。

TCC で ImVec2 がエラーになる

cimgui.h の前に必ず #define CIMGUI_DEFINE_ENUMS_AND_STRUCTS を定義する。

DLL が見つからない(実行時エラー)

cimgui.dllmy_app.exe と同じフォルダに置く。 または環境変数 PATH に追加。

igGetDrawData() の戻り値が NULL

igNewFrame()igRender() の間に必ず何かUIを描画すること(igShowDemoWindow だけでもOK)。


ファイル構成まとめ(ビルド後)

project/
  my_app.c          ← TCC でコンパイルするメインコード
  cimgui.h          ← cimguiのヘッダ(インクルード用)
  cimgui_impl.h     ← バックエンドのヘッダ(インクルード用)
  cimgui.dll        ← MSVCでビルドしたDLL
  cimgui.def        ← tiny_impdefで生成
  d3d11.def         ← 添付のもの(既存)
  my_app.exe        ← TCC出力