誰にも見えないブログ

雑なメモ。まとまってない文章等

自作Cコンパイラのビルド基盤をMakeからCMakeに移行してます(途中)

  • compiler bookの古い版のmake file
CFLAGS=-std=c11 -g -static
SRCS=$(wildcard *.c)
OBJS=$(SRCS:.c=.o)

ycc: $(OBJS)
    $(CC) -o ycc $(OBJS) $(LDFLAGS)

$(OBJS): ycc.h

test: ycc
    ./test.sh

clean:
    rm -f ycc *.o *~

.PHONY: test clean

適当に以降要件を洗い出してみます。

  • debug buildできること
  • ISO C11の規格に対応したビルドにすること
  • テストが実行できるようにすること

※全てのコマンドはプロジェクトの最上位(.gitが格納されているフォルダ)から打ち始めるものとします

debug build

このMakefileだとビルドスクリプト内にdebug optionがベタ書きになっていますが、cmakeの場合は実行時に

mkdir ../debug_build && cd ../debug_build
cmake -DCMAKE_BUILD_TYPE=Debug ../ycc
cmake --build .

このオプション付きでビルドするとデバッグ情報がバイナリに埋めこれます。gdbで確認してみます

$ gdb ycc -q
Reading symbols from ycc...done.
(gdb) list
1   #include "ycc.h"
2   
3   
4   // 現在着目しているトークン
5   Token *token;
6   
7   // 入力プログラム
8   char *user_input;
9   
10  
(gdb) 

-DCMAKE_BUILD_TYPE=Debugなしだとシンボル情報は埋め込まれません

mkdir ../build && cd ../build
cmake ../ycc
cmake --build .
  • check
$ gdb ./ycc -q
Reading symbols from ./ycc...(no debugging symbols found)...done.
(gdb) list
No symbol table is loaded.  Use the "file" command.
(gdb) 

C11オプション

  • これをCMakeLists.txtの最初の方に書くだけ。
set(CMAKE_C_STANDARD 11)

テスト(途中)

  • testは全てctestに書き換えます
  • originalのテスト用のshell script
test.sh 
#!/bin/bash
try() {
  expected="$1"
  input="$2"

  ./ycc "$input" > tmp.s
  gcc -o tmp tmp.s
  ./tmp
  actual="$?"

  if [ "$actual" = "$expected" ]; then
    echo "$input => $actual"
  else
    echo "$input => $expected expected, but got $actual"
    exit 1
  fi
}

try 0 '0;'
...テストケース省略...
try 8 'returnx = 3;return returnx + 5;'
echo OK
  • テストデータに大量のメタ文字を含んでいるため、cmake上でのデータ受け渡しに苦労しています
    • 今の私のcmake力だとテストの完全対応は難しそうです。
  • しばらくコマンドからテストを叩くことにします
 ../test.sh 
0; => 0
42; => 42
5+20-4; => 21
 12 + 34 - 5; => 41
5+6*7; => 47
5*(9-6); => 15
(3+5)/2; => 4
-(-3); => 3
-(3-11); => 8
-(-3*+5); => 15
 4==4; => 1
3==-3; => 0
4!=-3; => 1
-3!=-3; => 0
3<4; => 1
-3<-4; => 0
-4 <= 100; => 1
4<=4; => 1
8<=11; => 1
-3<=-4; => 0
2>-4; => 1
21>199; => 0
10>=10; => 1
1 >=0; => 1
-101 >= -100; => 0
a = 3;b = 5 * 6 - 8; a + b / 2; => 14
aa=10;b=20;ccc=b-aa;ccc+1; => 11
aa=10;bb=20;bb=bb/2;aa==bb; => 1
a = 3;b = 5 * 6 - 8;return a + b / 2; => 14
return 5;return 8; => 5
returnx = 3;return returnx + 5; => 8
OK
  • コンパイラのテストはcmake内でやるのは厳しそうなのでgoogle testなどを別途学習すればいけそうな気がする。

結果

  • こんな感じのcmakefileになってしまいましたが、CLionがドハデにリファクタリングしてくれました...
cmake_minimum_required(VERSION 3.10)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
project(ycc)

add_library(container STATIC container.c)
add_library(parse STATIC parse.c)

target_link_libraries(parse PRIVATE container)

add_library(codegen STATIC codegen.c)
add_library(main STATIC main.c)

target_include_directories(container PRIVATE "${PROJECT_SOURCE_DIR}")

target_include_directories(codegen PRIVATE "${PROJECT_SOURCE_DIR}")
target_include_directories(parse PRIVATE "${CMAKE_SOURCE_DIR}")


add_executable(ycc main.c)
target_link_libraries(ycc PRIVATE 
        container
        parse
        codegen
    )
target_include_directories(main PRIVATE "${PROJECT_SOURCE_DIR}")
  • refacter後
cmake_minimum_required(VERSION 3.14)
project(ycc)

set(CMAKE_C_STANDARD 11)

include_directories(.)

add_executable(ycc
        CMakeLists.txt
        codegen.c
        container.c
        main.c
        parse.c
        ycc.h)
  • どっかに設定とかあるんだろうけど、cmake_minimum_requiredのバージョン勝手に変えるのやめてもらえませんかねぇ

ninjaでビルド

せっかくMakeからCMakeに移行したんだから、Makeには出来ないことをやってみようと思います。 CMakeはメタビルドシステムなので下位のビルドツールを柔軟に変更することができます。今回はmakeの変わりにninjaを使います

$ cmake -GNinja ../ycc/
-- The C compiler identification is GNU 7.4.0
-- The CXX compiler identification is GNU 7.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/yabu/Documents/study/compiler/ninja_build
$ ninja
[5/5] Linking C executable ycc
$ ls
CMakeCache.txt  CMakeFiles  build.ninja  cmake_install.cmake  rules.ninja  ycc

ninjaで実行バイナリが作成されることが確認できました。