LLVM/clangとWSLのmake使ってWindowsの実行ファイルをビルドするためのMakefile

　clangでPDBファイルが出力できるようになったりしたので、WSLのmake使ってWindowsの実行ファイルをビルドするMakefileを書いてみました。

方針としては、clang++.exeで依存関係ファイルの生成、clang-cl.exeでコンパイル、lld-link.exeでリンクを行います。

# 準備

次のものをインストールしておきます。

- Visual Studio
- LLVM/clang
- Windows Subsystem for Linux (WSL) [^1]

LLVM/clangのパスを通して、WSLのLinuxのclangではなくWindowsのclangを使用します。WSLならclang++.exe等を利用できるようにします。

今回の環境は以下のようにしています。

- [ArchWSL](https://github.com/yuk7/ArchWSL)
- GNU Make 4.2.1
- Visual Studio 2017 Community（14.13.26128）
- LLVM/clang 6.0.0

[^1]: MSYS2とかのmakeのある他の環境で出来るかどうかは試してない。

# コード
ここでは、特にsrcフォルダなどを作らず、cppファイルと同じ場所にexeファイルが生成されるようにします。

```makefile:Makefile
CXXFLAGS := \
	-EHsc -W4 -utf-8 -std:c++17 \
	-fcolor-diagnostics -fansi-escape-codes \
	-DUNICODE -D_UNICODE

INCLUDE :=

LDFLAGS := \
	-libpath:"c:/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Tools/MSVC/14.13.26128/lib/x64"

LIBS := \
	kernel32.lib user32.lib gdi32.lib

TARGET := example.exe

SRCS := $(shell ls | grep '.cpp')
OBJS := $(patsubst %.cpp, %.o, $(SRCS))
PDB := $(patsubst %.exe, %.pdb, $(TARGET))
DEPENDS := $(patsubst %.cpp, %.d, $(SRCS))

.PHONY: all clean debug release

debug: CXXFLAGS += -MTd -Zi -D_DEBUG -DDEBUG
debug: LDFLAGS += -debug
debug: $(TARGET)

release: CXXFLAGS += -MT -O2 -DNDEBUG
release: $(TARGET)

%.o: %.cpp
	clang++.exe -E -std=c++17 $(INCLUDE) -MMD $< > /dev/null
	sed -i 's/\\\([^\f\n\r\t]\)/\/\1/g' $(patsubst %.cpp, %.d, $<)
	clang-cl.exe -c $(CXXFLAGS) $(INCLUDE) $< -o $@

$(TARGET): $(OBJS)
	lld-link.exe $(LDFLAGS) $^ $(LIBS) -out:$@

all: debug

clean:
	-rm $(OBJS)
	-rm $(DEPENDS)
	-rm $(PDB)
	-rm $(TARGET)

-include $(DEPENDS)
```
コードはここに置いておきます。
https://github.com/LNSEAB/clang_cl_makefile

# 解説

## CXXFLAGS
clang-cl.exeのオプションを設定しています。
以下にCXXFLAGSを抜粋します。

```Makefile
CXXFLAGS := \
	-EHsc -W4 -utf-8 -std:c++17 \
	-fcolor-diagnostics -fansi-escape-codes \
	-DUNICODE -D_UNICODE
```

オプションを`/`の代わりに`-`にしています。ただし、clと同じオプションで値や文字列を指定する時は`-std:c++17`のように`=`ではなく`:`を使います。
`-fcolor-diagnostics -fansi-escape-codes`はWSLでclangのメッセージに色をつけるためのオプションです。
`-DUNICODE`等の`-D`はマクロを定義するオプションですが、ここで値を指定する時は`-DWINNT=0x0A00`のように`=`で指定します。

## LDFLAGS
lld-link.exeのオプションを設定しています。
以下にLDFLAGSを抜粋します。

```Makefile
LDFLAGS := \
	-libpath:"c:/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Tools/MSVC/14.13.26128/lib/x64"
```

lld-linkはVisual C++のlinkと同じオプションを使えます。

ライブラリのパスを通すのに`-libpath`を使っており、CXXFLAGSと同様に`=`の代わりに`:`を使っています。
また、上記のようにVisual Studioにあるlibcmt.libなどのCライブラリまでのパスを通す必要があります。

## SRCSからDEPENDSまで
以下にSRCSからDEPENDSまでを抜粋します。

```Makefile
SRCS := $(shell ls | grep '.cpp')
OBJS := $(patsubst %.cpp, %.o, $(SRCS))
PDB := $(patsubst %.exe, %.pdb, $(TARGET))
DEPENDS := $(patsubst %.cpp, %.d, $(SRCS))
```

.cppファイルを自分で列挙したくないので`ls`と`grep`を使って列挙しています。さらに、それを元にmakeの組み込み関数`patsubst`を使ってcppファイルの拡張子をそれぞれoとdに変えて列挙しています。

## debugとrelease
debugとreleaseをルールを分けて別々にオプションを指定したい時、以下のような書き方ができます。

```Makefile
debug: CXXFLAGS += -MTd -Zi -D_DEBUG -DDEBUG
debug: LDFLAGS += -debug
debug: $(TARGET)

release: CXXFLAGS += -MT -O2 -DNDEBUG
release: $(TARGET)
```

## %.o: %.cpp
%.oのルールを以下に抜粋します。

```Makefile
%.o: %.cpp
    clang++.exe -E -std=c++17 $(INCLUDE) -MMD $< > /dev/null
    sed -i 's/\\\([^\f\n\r\t]\)/\/\1/g' $(patsubst %.cpp, %.d, $<)
    clang-cl.exe -c $(CXXFLAGS) $(INCLUDE) $< -o $@
```

clang++.exeの行について、`-MMD`でdファイルの生成し、コンパイルはしないように`-E`と`> /dev/null`で標準出力されたプリプロセス済のソースを読み捨てることで、dファイルだけを出力します。しかし、dファイル内の依存関係のパスに何故か`\`が混じるので、次の行で`sed`で`/`に置き換えてます。
あとは、clang-cl.exeでコンパイルを行います。

# おわりに
ターミナルにWSLを使っているVSCodeでのデバッグもやりやすくなりました。

# 参考
サンプルコード
https://github.com/LNSEAB/clang_cl_makefile