このドキュメントは、c-modernization-kit プロジェクトのクロスプラットフォームビルドシステムの設計、実装、および使用方法を説明します。
本プロジェクトは、Linux/Windows クロスプラットフォームビルドシステムを実現しています。GCC と MSVC (Microsoft Visual C++) との両方に対応し、単一の makefile で Linux と Windows の両環境でビルドできます。
標準的な開発ツールが必要です:
注: 環境変数は VS Code 起動時に自動設定済みの前提です。以下の環境が利用可能である必要があります:
ポータブル版 Visual Studio Build Tools
cl.exe)link.exe)Git for Windows (MinGW)
make.exe)環境設定の実行 (手動設定時のみ)
. .\Start-VSCode-With-Env.ps1 -EnvOnlyprod/ ディレクトリでビルドします:
Windows:
cd prod
makeLinux:
cd prod
makeこのコマンドで以下がビルドされます:
ライブラリ / Libraries:
| ライブラリ | Windows | Linux | 説明 |
|---|---|---|---|
| libcalcbase | prod/calc/lib/libcalcbase.lib |
prod/calc/lib/libcalcbase.a |
基本計算関数ライブラリ (静的ライブラリ) |
| libcalc | prod/calc/lib/libcalc.dll + libcalc.lib |
prod/calc/lib/libcalc.so |
計算ハンドラーライブラリ (動的ライブラリ、calcbase を内部に静的リンク) |
コマンド / Commands:
| コマンド | Windows | Linux | リンクライブラリ |
|---|---|---|---|
| add | prod/calc/bin/add.exe |
prod/calc/bin/add |
calcbase のみ |
| calc | prod/calc/bin/calc.exe |
prod/calc/bin/calc |
calc のみ |
| shared-and-static-calc | prod/calc/bin/shared-and-static-calc.exe |
prod/calc/bin/shared-and-static-calc |
calc + calcbase (両方) |
.NET コマンド / .NET Commands:
| コマンド | Windows | Linux | 依存ライブラリ |
|---|---|---|---|
| CalcApp | prod/calc.net/bin/CalcApp.exe |
prod/calc.net/bin/CalcApp |
CalcLib (libcalc の .NET ラッパー) |
重要:
- libcalc は動的ライブラリとして実装されており、calcbase を内部に静的リンクします
- shared-and-static-calc は、コマンドにおいて動的ライブラリと静的ライブラリの両方をリンクする実装例です
- 実行ファイルの出力先は prod/calc/src/makepart.mk および prod/calc.net/src/makepart.mk で OUTPUT_DIR として設定されています
testfw/ ディレクトリおよび test/ ディレクトリでテストをビルド・実行します:
Windows:
cd testfw
make
cd ..\test
makeLinux:
cd testfw
make
cd ../test
makeテストは Google Test フレームワークを使用しています:
test/src/calc/libcalcbaseTest/) および コマンドの単体テスト (test/src/calc/main/)test/libsrc/mock_*/)プロダクションコードのクリーンアップ:
cd prod/calc
make cleanテストコードのクリーンアップ:
cd test
make cleanc-modernization-kit/
+-- makefw/ # makefile フレームワーク (testfw から切り出し)
| +-- makefiles/
| | +-- makelibsrc.mk # ライブラリビルド用共通テンプレート
| | +-- makesrc.mk # 実行ファイルビルド用共通テンプレート
| | +-- prepare.mk # 準備処理
| | +-- _*.mk # 内部処理用ファイル
| +-- docs-src/ # フレームワーク技術ドキュメント
+-- prod/calc/
| +-- makefile # トップレベル makefile (再帰ビルド)
| +-- lib/ # ビルド済みライブラリ
| +-- bin/ # ビルド済み実行ファイル
| +-- libsrc/
| | +-- makefile # libsrc 配下の再帰ビルド
| | +-- makepart.mk # ライブラリ共通設定
| | +-- calcbase/
| | | +-- makefile # calcbase ビルド定義 (静的ライブラリ)
| | +-- calc/
| | +-- makefile # calc ビルド定義 (動的ライブラリ)
| | +-- makepart.mk # calc 固有設定 (LIB_TYPE=shared)
| +-- src/
| +-- makefile # src 配下の再帰ビルド
| +-- makepart.mk # 実行ファイル出力先設定 (OUTPUT_DIR)
| +-- add/
| | +-- makefile # add コマンドビルド定義
| +-- calc/
| | +-- makefile # calc コマンドビルド定義
| +-- shared-and-static-calc/
| +-- makefile # shared-and-static-calc ビルド定義
+-- prod/calc.net/
| +-- lib/ # ビルド済みライブラリ
| +-- bin/ # ビルド済み実行ファイル
| +-- libsrc/CalcLib/ # .NET ライブラリソース
| +-- src/
| +-- makepart.mk # 実行ファイル出力先設定 (OUTPUT_DIR)
| +-- CalcApp/ # .NET アプリケーションソース
+-- test/
+-- makefile # テストトップレベル makefile
+-- makepart.mk # テスト共通設定
+-- libsrc/
| +-- makefile # テスト用ライブラリ配下の再帰ビルド
| +-- mock_calcbase/
| | +-- makefile # calcbase モックライブラリ
| +-- mock_calc/
| +-- makefile # calc モックライブラリ
+-- src/
+-- makefile # テスト配下の再帰ビルド
+-- calc/
+-- libcalcbaseTest/
| +-- addTest/
| +-- makefile # add 関数単体テスト
+-- main/
+-- addTest/
| +-- makefile # add コマンド統合テスト
+-- calcTest/
| +-- makefile # calc コマンド統合テスト
+-- shared-and-static-calcTest/
+-- makefile # shared-and-static-calc 統合テスト
設計方針:
makefile で Linux/Windows 両対応makefw は testfw から makefile 機能を切り出したフレームワークです。共通テンプレートにより、Windows/Linux の差異を吸収します。
makefile の基本形 (ライブラリ・実行ファイル共通):
find-up = \
$(if $(wildcard $(1)/$(2)),$(1),\
$(if $(filter $(1),$(patsubst %/,%,$(dir $(1)))),,\
$(call find-up,$(patsubst %/,%,$(dir $(1))),$(2))\
)\
)
WORKSPACE_FOLDER := $(strip $(call find-up,$(CURDIR),.workspaceRoot))
include $(WORKSPACE_FOLDER)/makefw/makefiles/prepare.mk
##### makepart.mk の内容は、このタイミングで処理される #####
include $(WORKSPACE_FOLDER)/makefw/makefiles/makemain.mkmakemain.mk は、カレントディレクトリのパスを判定して、自動的に適切なテンプレートを選択します:
/libsrc/ を含む → ライブラリ用テンプレート (makelibsrc_c_cpp.mk または makelibsrc_dotnet.mk)/src/ を含む → 実行ファイル用テンプレート (makesrc_c_cpp.mk または makesrc_dotnet.mk).csproj ファイルの有無により、C/C++ 用か .NET 用かを判定各ライブラリ/コマンド固有の設定は makepart.mk に記述できます。
calc/makepart.mk の例:
LIBS += calcbase
ifeq ($(OS),Windows_NT)
# Windows
# DLL エクスポート定義
# DLL export definition
CFLAGS += /DCALC_EXPORTS
CXXFLAGS += /DCALC_EXPORTS
endif
LIB_TYPE = sharedこの設定により、calc は Windows では DLL、Linux では .so として自動的にビルドされます。
prod/calc/src/makepart.mk の例 (実行ファイルの出力先設定):
OUTPUT_DIR := $(WORKSPACE_FOLDER)/prod/calc/binこの設定により、prod/calc/src/ 配下のすべての実行ファイルは prod/calc/bin/ に出力されます。
test/makepart.mk の例:
ifneq ($(OS),Windows_NT)
# Linux
# 詳細な警告レベル設定 (gcc)
CFLAGS=\
-Wall \
-Wextra \
# ... (その他の警告オプション)
CXXFLAGS=\
-Wall \
-Wextra \
# ... (その他の警告オプション)
else
# Windows
CFLAGS =
CXXFLAGS =
LDFLAGS =
endif
ifneq ($(OS),Windows_NT)
# Linux: TARGET_ARCH (e.g., linux-el8-x64)
LIBSDIR += $(WORKSPACE_FOLDER)/testfw/lib/$(TARGET_ARCH)
else
# Windows: TARGET_ARCH/MSVC_CRT_SUBDIR (e.g., windows-x64/md)
LIBSDIR += $(WORKSPACE_FOLDER)/testfw/lib/$(TARGET_ARCH)/$(MSVC_CRT_SUBDIR)
endif
LIBSDIR += \
$(WORKSPACE_FOLDER)/test/lib
LINK_TEST = 1
ifeq ($(OS),Windows_NT)
# Windows
CFLAGS += /DCALC_STATIC
CXXFLAGS += /DCALC_STATIC
endifLINK_TEST = 1 を設定することで、Google Test フレームワークが自動的にリンクされます。
LIB_TYPE=shared の場合、動的ライブラリ (DLL/.so) は依存する静的ライブラリを自動的に内部リンクします。
calc/makefile の例:
include $(WORKSPACE_FOLDER)/makefw/makefiles/makemain.mkcalc/makepart.mk:
LIBS += calcbase
LIB_TYPE = shared動作:
LIBS に指定された calcbase をライブラリ検索パスから検索
libcalcbase.lib を検索libcalcbase.a を検索makefw テンプレートが Windows (MSVC) と Linux (GCC) の両方に自動対応します。
makefw/makefiles/prepare.mk 内の OS 判定:
ifneq ($(OS),Windows_NT)
# Linux (gcc/g++)
ifeq ($(origin CC),default)
CC = gcc
endif
ifeq ($(origin CXX),default)
CXX = g++
endif
ifeq ($(origin LD),default)
LD = g++
endif
ifeq ($(origin AR),default)
AR = ar
endif
else
# Windows (MSVC)
ifeq ($(origin CC),default)
CC = cl
endif
ifeq ($(origin CXX),default)
CXX = cl
endif
ifeq ($(origin LD),default)
LD = link # (MSVC の link.exe)
endif
ifeq ($(origin AR),default)
AR = lib
endif
endif各 makefile はテンプレートを include するだけで、OS 固有の処理は不要です。
本プロジェクトでは、以下の構成でライブラリをビルドします:
| ライブラリ | LIB_TYPE 設定 | Windows | Linux | 説明 |
|---|---|---|---|---|
| libcalcbase | 未設定 (→ static) | .lib |
.a |
静的ライブラリ |
| libcalc | shared (makepart.mk で指定) |
.dll + .lib |
.so |
動的ライブラリ + インポートライブラリ |
LIB_TYPE 変数:
staticmakepart.mk で LIB_TYPE = shared を指定すると動的ライブラリとしてビルドmakefile 内で OS を判定し、コンパイラやツールを切り替えます。
ifeq ($(OS),Windows_NT)
# Windows 環境
CC := cl
LD := link
AR := lib
OBJEXT := .obj
EXEEXT := .exe
else
# Linux 環境
CC := gcc
LD := gcc
AR := ar
OBJEXT := .o
EXEEXT :=
endif$(OS) 環境変数は、Windows では Windows_NT が設定されます。Linux では通常未定義です。
| 項目 | Linux (GCC) | Windows (MSVC) |
|---|---|---|
| C コンパイラ | gcc | cl.exe |
| C++ コンパイラ | g++ | cl.exe |
| リンカー | gcc/g++ | link.exe |
| 静的ライブラリ生成 | ar | lib.exe |
| 静的ライブラリ拡張 | .a | .lib |
| 共有ライブラリ拡張 | .so | .dll |
| 実行ファイル拡張 | なし | .exe |
| オブジェクト拡張 | .o | .obj |
Windows 環境では、Git for Windows に付属する MinGW 環境を活用します。これにより:
bash, pwd, dirname などの Linux コマンドが使えるsh コマンドで既存のシェルスクリプトを実行できるmakefw は testfw から makefile 関連機能を切り出したフレームワークです:
この分離により、ビルドシステムとテストフレームワークの責務が明確になりました。
本プロジェクトでは、以下の構成を採用しています:
LIB_TYPE = shared を指定)この構成により、以下のメリットがあります:
フレームワーク:
makefw/makefiles/prepare.mk - 準備処理makefw/makefiles/makemain.mk - テンプレート自動選択
makefw/makefiles/makelibsrc_c_cpp.mk - C/C++ ライブラリビルド用テンプレートmakefw/makefiles/makesrc_c_cpp.mk - C/C++ 実行ファイルビルド用テンプレートmakefw/makefiles/makelibsrc_dotnet.mk - .NET ライブラリビルド用テンプレートmakefw/makefiles/makesrc_dotnet.mk - .NET 実行ファイルビルド用テンプレートライブラリ:
prod/calc/libsrc/calcbase/makefile - calcbase ビルド定義 (LIB_TYPE 未設定 → static)prod/calc/libsrc/calc/makefile - calc ビルド定義prod/calc/libsrc/calc/makepart.mk - calc 固有設定 (LIB_TYPE = shared)コマンド:
prod/calc/src/add/makefile - add コマンド (calcbase のみリンク)prod/calc/src/calc/makefile - calc コマンド (calc のみリンク)prod/calc/src/shared-and-static-calc/makefile - shared-and-static-calc コマンド (calc + calcbase をリンク)テスト:
test/makepart.mk - テスト共通設定 (テストフレームワークリンク、警告レベル設定)test/libsrc/mock_calcbase/makefile - calcbase モックライブラリtest/libsrc/mock_calc/makefile - calc モックライブラリtest/src/calc/libcalcbaseTest/addTest/makefile - add 関数単体テストtest/src/calc/main/addTest/makefile - add コマンド統合テストtest/src/calc/main/calcTest/makefile - calc コマンド統合テストtest/src/calc/main/shared-and-static-calcTest/makefile - shared-and-static-calc 統合テスト| 項目 | 説明 |
|---|---|
| クロスプラットフォーム | 単一の makefile で Windows/Linux 両対応 |
| OS 判定 | makefw テンプレートが自動処理 |
| ライブラリ構成 | makepart.mk で柔軟に設定可能 |
| 依存関係解決 | LIBS 変数による明示的な指定 |
| 静的リンク自動化 | 動的ライブラリビルド時に静的ライブラリを自動検索・リンク |
| テストフレームワーク統合 | LINK_TEST = 1 で Google Test を自動リンク |
| モック機能 | testfw のインクルードオーバーライド機能によるモック |
makefw テンプレートには debug ターゲットがあり、設定された変数を表示できます:
calcbase のデバッグ:
Windows:
cd prod\calc\libsrc\calcbase
make debugLinux:
cd prod/calc/libsrc/calcbase
make debug出力例 (Windows の場合):
TARGET = libcalcbase.lib
LIB_TYPE = static
OS = Windows_NT
LIBS =
STATIC_LIBS =
OBJS = obj/add.obj
calc のデバッグ:
Windows:
cd prod\calc\libsrc\calc
make debugLinux:
cd prod/calc/libsrc/calc
make debug出力例 (Windows の場合、makepart.mk で LIB_TYPE=shared 設定済み):
TARGET = libcalc.dll
LIB_TYPE = shared
OS = Windows_NT
LIBS = calcbase
STATIC_LIBS = C:/path/to/prod/calc/lib/libcalcbase.lib
OBJS = obj/calcHandler.obj
LIB_TYPE = shared 設定済み)LIBSDIR で指定されたパスから検索$(WORKSPACE_FOLDER)/prod/calc/lib$(WORKSPACE_FOLDER)/test/lib-L オプションの追加サポートこのセクションでは、クロスプラットフォーム対応の実装で得られた重要な知見とベストプラクティスを説明します。
Windows 環境では、Start-VSCode-With-Env.ps1 で環境設定を行う必要があります。VS Code を起動せず環境変数のみを設定する場合は、-EnvOnly パラメータを指定してドットソースで実行します。
. .\Start-VSCode-With-Env.ps1 -EnvOnlyソースコードが UTF-8 で記述されている場合、MSVC のコンパイル時に /utf-8 オプションを追加する必要があります。
CFLAGS := /W4 /Zi /TC /nologo /utf-8 /I$(WORKSPACE_FOLDER)/prod/calc/includeこのオプションを指定しないと、以下の警告が発生します:
warning C4819: The file contains a character that cannot be represented
in the current code page (932). Save the file in Unicode format to prevent data loss
MSVC のデバッグ情報ファイル (PDB) は、以下のように配置します。
ライブラリファイル (.lib) と同じディレクトリに配置します。
CFLAGS := /W4 /Zi /TC /nologo /utf-8 /FS /Fd$(OUTPUT_DIR)/libcalc.pdb /I...生成結果:
prod/calc/lib/
+-- libcalc.lib
+-- libcalc.pdb
実行ファイルと同じディレクトリに配置します。コンパイル時の中間 PDB は obj ディレクトリに配置します。
CFLAGS := /W4 /Zi /TC /nologo /utf-8 /Fd$(OBJDIR)/add.pdb /I...
LDFLAGS := /DEBUG /PDB:$(OUTPUT_DIR)/add.pdb /LIBPATH:...生成結果:
prod/calc/src/add/
+-- add.exe
+-- add.pdb (リンク時の PDB、実行ファイルと同じ場所)
+-- obj/
+-- add.obj
+-- add.pdb (コンパイル時の PDB、obj ディレクトリ)
複数のソースファイルが同じ PDB ファイルに同時に書き込む場合、/FS オプションを追加して同期を保証する必要があります。
CFLAGS := /W4 /Zi /TC /nologo /utf-8 /FS /Fd$(OUTPUT_DIR)/calc.pdb /I...このオプションを指定しないと、以下のエラーが発生することがあります:
fatal error C1041: cannot open program database 'calc.pdb';
if multiple CL.EXE write to the same .PDB file, please use /FS
makefile 内で Unix スタイルのパス (/d/Users/...) を取得した場合、MSVC はこのパスを認識できません。cygpath -w を使用して Windows スタイルのパス (D:\Users\...) に変換する必要があります。
WORKSPACE_FOLDER := $(shell \
dir=`pwd`; \
while [ "$$dir" != "/" ]; do \
if [ -f "$$dir/.workspaceRoot" ]; then \
cygpath -w "$$dir" 2>/dev/null || echo $$dir; \
break; \
fi; \
dir=$$(dirname $$dir); \
done \
)cygpath -w が利用できない環境では、echo $$dir にフォールバックします。
PDB ファイルを OUTPUT_DIR に出力する場合、コンパイルルールに OUTPUT_DIR の依存関係を追加する必要があります。
$(OBJDIR)/%$(OBJEXT): %.c | $(OBJDIR) $(OUTPUT_DIR)
$(CC) $(CFLAGS) /c /Fo$@ $<これにより、コンパイル前に OUTPUT_DIR が作成されることが保証されます。
Windows 環境では、clean ターゲットで PDB ファイルも削除する必要があります。
.PHONY: clean
clean:
rm -rf $(OBJDIR)
rm -f $(OUTPUT_DIR)/$(TARGET)
ifeq ($(OS),Windows_NT)
rm -f $(OUTPUT_DIR)/*.pdb
endifobj ディレクトリの削除により、コンパイル時の PDB と ILK ファイルが削除されます。OUTPUT_DIR に配置されたリンク時の PDB ファイルのみ、明示的に削除します。
本プロジェクトのクロスプラットフォーム対応では、以下の方針を採用しました:
/utf-8 オプションが必要