Cコンパイラ作成入門をcmakeでやる。
はじめに
「低レイヤを知りたい人のための C コンパイラ作成入門」を読んでいます。
IDE を使ってコードを書いてると、Makefile を使うより Cmake を使った方がデバッグ機能を使えて便利なので、Makefile を Cmake に書き換えてみました。
この記事では私が書いた CMakeLists.txt を紹介します。なお私は cmake を書くのはこれが初めてです。
シェルスクリプトによるテスト
chibicc の最初期はシェルスクリプトでテストを記述し、それを Makefile から呼び出しています。chibicc が単一の main.c を tokeninze.c と parse.c と codegen.c に分離したコミットの Makefile が以下です。
これを次のように書き換えました。
cmake_minimum_required(VERSION 3.14)
project(chibicc C)
set(CMAKE_C_STANDARD 17)
# build chibicc
file(GLOB SRCS *.c)
add_executable(chibicc ${SRCS})
# tests
enable_testing()
add_test(NAME test COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/test.sh)
1 行目で cmake のバージョンを指定します。
cmake_minimum_required(VERSION 3.14)
手元の Mac には3.27.4
がインストールされていました。ただ、3.0 以降のバージョンだとどれを指定しても結果は変わらなかったのでキリよく3.14
を指定しました。
2,3 行目でプロジェクト名と C 言語の仕様のバージョンを指定します。
project(chibicc C)
set(CMAKE_C_STANDARD 17)
C 言語の仕様のバージョンは 11 を指定しても 17 を指定しても結果は変わらなかったので新しい方の 17 を指定しました。
以下ではchibicc
のコンパイルに必要なファイルを指定します。
# build chibicc
file(GLOB SRCS *.c)
add_executable(chibicc ${SRCS})
*.c
で指定すると、一時的に作成したtmp.c
などにもマッチしてしまうのに注意が必要です。高々数個のファイルしかないのでベタ書きした方が便利かもしれません。
テストのシェルスクリプトは以下のように呼び出します。
# tests
enable_testing()
add_test(NAME test COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/test.sh)
COMMAND でシェルスクリプトを呼び出せます。
C によるテスト
chibicc の開発が進んでくると、テストの量が多くなってきてシェルスクリプトでは開発しづらくなってきます。chibicc ではある程度言語が育ってきた段階で C 言語によるテストに変更し高速化を行います。そのコミットが以下です。
この段階の Makefile を次のように書き換えました。
cmake_minimum_required(VERSION 3.14)
project(chibicc C)
set(CMAKE_C_STANDARD 17)
# build chibicc
file(GLOB SRCS *.c)
add_executable(chibicc ${SRCS})
# build tests
enable_testing()
add_test(NAME driver COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/test/driver.sh)
file(GLOB TEST_SRCS test/*.c)
foreach (TEST_SRC ${TEST_SRCS})
get_filename_component(TEST_NAME ${TEST_SRC} NAME_WE)
add_custom_target(
${TEST_NAME}.exe ALL
COMMAND clang -o- -P -E -C ${TEST_SRC} | ./chibicc -o ${TEST_NAME}.s -
COMMAND clang -o ${TEST_NAME}.exe ${TEST_NAME}.s -x c ${CMAKE_CURRENT_SOURCE_DIR}/test/common
DEPENDS chibicc
)
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME}.exe)
endforeach ()
テストファイルの拡張子を除いたファイル名を取得する関数です。
get_filename_component(TEST_NAME ${TEST_SRC} NAME_WE)
add_custom_target でテストの実行ファイルを生成します。
add_custom_target(
${TEST_NAME}.exe ALL
COMMAND clang -o- -P -E -C ${TEST_SRC} | ./chibicc -o ${TEST_NAME}.s -
COMMAND clang -o ${TEST_NAME}.exe ${TEST_NAME}.s -x c ${CMAKE_CURRENT_SOURCE_DIR}/test/common
DEPENDS chibicc
)
テストの実行ファイルを、テストに追加します。
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME}.exe)
おわりに
chibicc を cmake でビルドとテストをできるようにしました。私が使ってる CLion は cmake と相性が良いので、これで快適にデバッグできるようになりました。セルフホストができるようになったらその時の cmake は追記します。今後も chibicc の写経を続けたい。
参考
Discussion