googletest (gtest)の標準的なビルド方法が、「あるようでない」ので

configure があるのにやらせてくれない、make install すると「するな」と叱られる。

「Windows 環境だ」との合わせ業一本、で、gtest はなんだか「どう管理していいものやら」問題になりがち。「install するな」は、そうかもしれない。所詮はテストのためだけ、エンドユーザのためではないのだ、ということでもあるのだろうし、こと Windows となれば、「DLL地獄へ猫まっしぐら」となるのは火を見るよりもなんとやら。

そして、だ。Microsoft Visual C++ Compiler for Python 2.7なんてのがあるわけだ。こやつには「sln」「vcproj」を扱う能力はない。本当にコンパイラセット群しかついてないのだから。あー、なんてこった、と。

てわけでなんだかんだ、gtest 環境を準備するだけでヘンな時間の浪費をしてもおかしくないわけなんだな。linux なんかだったら install するなと言われてもしちゃうけどね、アタシなら。「プロジェクト内標準にしやすいがヘンな場所」に置けばいい。ノーマルな /usr/local ではなく、/usr/local/opt/ とかさ。けど、Windows では…そもそもが「開発に必要なライブラリ、ヘッダファイルの標準置き場」なんてものはないので、すぐに「開発者依存」が多発するハメになる。あーぁ。

「make install するな問題」は、つまりは極論すれば「自プロジェクト内に抱え込め」ちぅことになるわけなんだけれど、正直言って gtest のソースツリー丸ごと維持管理するような馬鹿な真似はしたくはないので、ちょっとこんなん作ってみた:

mk_gtest.py
 1 # -*- coding: utf-8 -*-
 2 import sys
 3 import os
 4 from zipfile import ZipFile
 5 from distutils.dir_util import copy_tree, remove_tree, mkpath
 6 from distutils import log
 7 from distutils import ccompiler, sysconfig, dep_util
 8 
 9 log.set_verbosity(1)  # INFO
10 
11 arch = "gtest-1.7.0.zip"
12 if len(sys.argv) == 2:
13     arch = sys.argv[1]
14 
15 # -------------------------------------------------------------
16 # specify build environment
17 #
18 tmpdir = ".tmp"
19 if not os.path.exists(tmpdir):
20     mkpath(tmpdir)
21 cc = ccompiler.new_compiler()
22 sysconfig.customize_compiler(cc)
23 cc.set_include_dirs([sysconfig.get_python_inc(plat_specific=1)])
24 cc.set_library_dirs([
25         os.path.join(sys.prefix, "libs"),  # for windows
26         ])
27 src = os.path.join(tmpdir, "z.c")
28 open(src, "w").write("""
29 #include <stdio.h>
30 #include <pyconfig.h>
31 int main()
32 {
33     printf("%s", COMPILER);
34 }
35 """)
36 objs = cc.compile([src])
37 cc.link_executable(objs, "z", tmpdir)
38 # -----------------------------------
39 from subprocess import Popen, PIPE
40 p = Popen([".tmp/z"], stdout=PIPE)
41 COMPILER = p.communicate()[0]
42 
43 # -------------------------------------------------------------
44 remove_tree(".tmp")
45 
46 tl = None
47 with ZipFile(arch, "r") as zf:
48     for fn in zf.namelist():
49         spl = fn.split("/")
50         if "include" not in spl and "src" not in spl:
51             continue
52         tl = spl[0]
53         zf.extract(fn, ".tmp")
54 # -------------------------------------------------------------
55 
56 os.chdir(os.path.join(".tmp", tl))
57 
58 # ------------------------------------------------------------- 
59 cc = ccompiler.new_compiler()  # refresh cc (gtest doesn't need python.)
60 sysconfig.customize_compiler(cc)
61 cc.set_include_dirs(['./include', '.'])
62 extra_preargs = []
63 if cc.compiler_type == 'msvc':
64     extra_preargs.extend(['-EHsc'])
65 
66 os.mkdir("lib")
67 
68 # build static link library
69 for targ in (
70     ('src/gtest-all.cc', 'gtest'), ('src/gtest_main.cc', 'gtest_main')):
71     objs = cc.compile([targ[0]], extra_preargs=extra_preargs)
72     cc.create_static_lib(objs, targ[1], "lib")
73 # -------------------------------------------------------------
74 remove_tree("src")
75 os.chdir("..")
76 # -------------------------------------------------------------
77 newname = "{}-prebuilt-{}".format(
78         tl,
79         COMPILER)
80 os.rename(tl, newname)
81 os.chdir("..")
82 copy_tree(".tmp", ".")
83 remove_tree(".tmp")

みてわかるかもしれないけど、この投稿は実は今回のこれがしたかったの。

何するものかというと、ダウンロードしてきた「gtest-1.7.0.zip」(等)を受け取って、「一時フォルダに展開してビルドして、出来上がったライブラリとヘッダファイルだけを抜き出す」ということをする。

こんな動きをする:
mk_gtest


なんでこんなことをしたくなったかと言うと。

なんかどのサイトみても皆「独自」なんですもの。cl.exe で直接ビルドしとる人もおったが、これ、気持ちはとてもわかるけれど、「多数の開発者が皆自前で cl.exe を叩け」は酷だし。あとさ、「気軽に OSS や便利ツールをインストールできない」(例えば許可が必要とか)もあるでしょ。CMake 関連の GUI なんか、使い始めれば便利なのかもしれんけど、「評価すらさせてくれない」とこなんかザラです。「一億人が知っているもの」くらいのものじゃないとそうそう許されない、みたいな。CMake はそんなわけで、どっちかといえば「禿げしくドマイナー」なわけです。入れさせてもらえない可能性が高い。

てなわけで、「アタシも」独自してみたけれど、これであれば「プロジェクト内の標準手順化」しやすいでしょ? (distutils 任せなので、そこさえクリア出来ればの話だけど。)