2014年08月12日

米Facebook社のC/C++プリプロセッサWarpをWindows環境でビルド

Warp は Facebook 社が D 言語の作者 Walter Bright 氏と協力して開発した C/C++ プリプロセッサで、自社のビルドシステムの高速化のために開発したそうです。D 言語で書かれていて、非常に緩い Boost Software License 1.0 で GitHub に公開されています。

「Under the Hood: warp, a fast C and C++ preprocessor」
https://code.facebook.com/posts/476987592402291/under-the-hood-warp-a-fast-c-and-c-preprocessor/
https://github.com/facebook/warp

Cent OS 6 以外では動作確認されていないそうですが、いろいろ試行錯誤した結果、Windows の MSYS + GDC(D Programming Language for GCC)環境で、とりあえず warp の生成までは成功したので、その時のメモです。(builtin_defines.sh というシェルスクリプトが git リポジトリに入っていないようで、ドライバプログラム warpdrive の生成は失敗しました。)



ソースコードは git clone https://github.com/facebook/warp.git で、適当な場所に取得しておいてください。

(1) MSYS + GDC 環境構築

VMWare 上のまっさらな Windows 7 64bit 環境で試しました。
(git や 7-zip のインストールや使い方は省略します。)

- MSYS のインストール

今回は MinGW は使用しないので、mingw-get-setup.exe で「msys-base」のみをインストールしました。
http://sourceforge.net/projects/mingw/files/Installer/mingw-get/

- GDC のインストール

今回は、以下の x64 バイナリを使用しました。
http://gdcproject.org/downloads/binaries/x86_64-w64-mingw32/native_2.065_gcc4.9.0_a8ad6a6678_20140615.7z

7-zip で圧縮されているので、適当な所に x86_64-gdcproject-mingw32 というフォルダを展開して PATH を通しておいてください。
(今回は C:\ 直下に展開して、MSYS 上で一時的に PATH を設定しました。)
$ export PATH=$PATH:/c/x86_64-gdcproject-mingw32/bin/

(2) warp のビルド

Makefile が、おそらく facebook 社のビルド環境(Cent OS 6)に決め打ちになっているようなので、今回の環境に合わせて修正してから make します。(Windows の GDC だと、プログラム名が gdc ではなく gdc.exe だったり、libphobos2.a が、libgphobos2.a になっていたり、微妙な差異があります。)
$ diff -u Makefile.orig Makefile
--- Makefile.orig       2014-08-12 10:29:35 +0900
+++ Makefile    2014-08-12 13:34:52 +0900
@@ -6,7 +6,7 @@
 endif
 endif

-ifeq (gdc,$(notdir $(DC)))
+ifeq (gdc.exe,$(notdir $(DC)))
        DFLAGS=-c -O4 -frelease -fno-bounds-check -fbuiltin
        OFSYNTAX=-o
 else
@@ -44,7 +44,7 @@
        $(DC) $(DFLAGS) $(OFSYNTAX)$@ $(SRCS)

 warp : warp.o
-       gcc -m64 -Bthird-party2/binutils/2.21.1/centos6-native/da39a3e/bin/gold
-Bthird-party2/glibc/2.17/gcc-4.8.1-glibc-2.17-fb/99df8fc/lib -L/home/aalexandre
/bin/../d/phobos/generated/linux/release/default -l:libphobos2.a -lpthread -lm -
lrt -o $@ $^
+       gcc -m64 -o $@ $^ -lgphobos2

 $(WARPDRIVE) : warpdrive.d $(GENERATED_DEFINES)
        $(DC) $(DFLAGS) $(OFSYNTAX)$@ $^
$ make
/c/x86_64-gdcproject-mingw32/bin/gdc.exe -c -O4 -frelease -fno-bounds-check -fbu
iltin -owarp.o cmdline.d constexpr.d context.d directive.d expanded.d file.d id.
d lexer.d loc.d macros.d main.d number.d outdeps.d ranges.d skip.d sources.d str
inglit.d textbuf.d charclass.d
gcc -m64 -o warp warp.o -lgphobos2
./builtin_defines.sh 'cc ' 'c++ ' >generated_defines.d.tmp
/bin/sh: ./builtin_defines.sh: No such file or directory
make: *** [generated_defines.d] Error 127
おそらく builtin_defines.sh というシェルスクリプトが git リポジトリに存在しないことが原因で、ドライバプログラム warpdrive の生成には失敗してしまいますが、とりあえず warp.exe はできました。

warp だけでは、コンパイラ固有の定義済みマクロなどが何も設定されていないので、windows.h などはこのままではプリプロセスできませんが(例えば _WIN32 が定義されていないと、ヘッダのプリプロセス途中で #error になる)、純粋なプリプロセス機能は warp 単体で動作するようです。可変長引数などもサポートしています。
$ cat test.c
#define FOO 1

#define dbg(fmt, ...) \
    printf("debug:" fmt, __VA_ARGS__)

int f()
{
    dbg("%d %d %d\n", 1, 2, 3);
    return FOO;
}

$ warp.exe test.c --stdout
# 1 "test.c"
# 1 "c:\Work\warp//"
# 1 ""
# 1 "test.c"


# 6 "test.c"
int f()
{
    printf("debug:" "%d %d %d\n", 1, 2, 3);
    return 1;
# 10 "test.c"
}
余談

成功手順だけ書くと簡単ですが、最初に作った GDC の環境では大量のコンパイルエラーが出てしまい(D は言語仕様やランタイム環境の変化が激しいようで、また GDC は様々な人がビルドして配布しているので、どれを使えば良いのかも手探り状態でした)、デジタルマース社の DMD 環境で試して途中までコンパイルはできたものの、今度は DMD で生成したオブジェクトファイルが GCC でうまくリンクできず(TDM-GCC の環境に GDC を上書きして使っていたりと、この時はかなり環境がゴチャゴチャしていた)、これは Windows なのが悪いのかと問題の切り分けのために Cent OS 7 の環境を VMWare 上に準備して試したりと、不慣れな D 言語と Cent OS の環境で試行錯誤し、そこで成功した環境の Windows 版を MSYS 環境に持ってきて整理して、やっと Windows 上で成功と、実際はかなり手間取ってしまいました。(今思えば、Cent OS が特に Warp のビルドや D 言語のセットアップが楽ということも無かったので、使い慣れた Ubuntu 環境でも良かったと思います。)

トラックバックURL

コメントする

名前
URL
 
  絵文字
 
 
記事検索
最新コメント
アクセスカウンター
  • 今日:
  • 昨日:
  • 累計:

QRコード
QRコード