bootstrap: make --windows usable for cl.exe-on-wine
[platform/upstream/ninja.git] / bootstrap.py
1 #!/usr/bin/env python
2 # Copyright 2011 Google Inc. All Rights Reserved.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 from __future__ import print_function
17
18 from optparse import OptionParser
19 import sys
20 import os
21 import glob
22 import errno
23 import shlex
24 import shutil
25 import subprocess
26
27 os.chdir(os.path.dirname(os.path.abspath(__file__)))
28
29 parser = OptionParser()
30 parser.add_option('--verbose', action='store_true',
31                   help='enable verbose build',)
32 parser.add_option('--x64', action='store_true',
33                   help='force 64-bit build (Windows)',)
34 # TODO: make this --platform to match configure.py.
35 parser.add_option('--windows', action='store_true',
36                   help='force native Windows build',
37                   default=sys.platform.startswith('win32'))
38 (options, conf_args) = parser.parse_args()
39
40 def run(*args, **kwargs):
41     returncode = subprocess.call(*args, **kwargs)
42     if returncode != 0:
43         sys.exit(returncode)
44
45 # Compute system-specific CFLAGS/LDFLAGS as used in both in the below
46 # g++ call as well as in the later configure.py.
47 cflags = os.environ.get('CFLAGS', '').split()
48 ldflags = os.environ.get('LDFLAGS', '').split()
49 if sys.platform.startswith('freebsd'):
50     cflags.append('-I/usr/local/include')
51     ldflags.append('-L/usr/local/lib')
52
53 print('Building ninja manually...')
54
55 try:
56     os.mkdir('build')
57 except OSError:
58     e = sys.exc_info()[1]
59     if e.errno != errno.EEXIST:
60         raise
61
62 sources = []
63 for src in glob.glob('src/*.cc'):
64     if src.endswith('test.cc') or src.endswith('.in.cc'):
65         continue
66     if src.endswith('bench.cc'):
67         continue
68
69     filename = os.path.basename(src)
70     if filename == 'browse.cc':  # Depends on generated header.
71         continue
72
73     if options.windows:
74         if src.endswith('-posix.cc'):
75             continue
76     else:
77         if src.endswith('-win32.cc'):
78             continue
79
80     sources.append(src)
81
82 if options.windows:
83     sources.append('src/getopt.c')
84
85 if options.windows:
86     cl = 'cl'
87     vcdir = os.environ.get('VCINSTALLDIR')
88     if vcdir:
89         if options.x64:
90             cl = os.path.join(vcdir, 'bin', 'x86_amd64', 'cl.exe')
91             if not os.path.exists(cl):
92                 cl = os.path.join(vcdir, 'bin', 'amd64', 'cl.exe')
93         else:
94             cl = os.path.join(vcdir, 'bin', 'cl.exe')
95     args = [cl, '/nologo', '/EHsc', '/DNOMINMAX']
96 else:
97     args = shlex.split(os.environ.get('CXX', 'g++'))
98     cflags.extend(['-Wno-deprecated',
99                    '-DNINJA_PYTHON="' + sys.executable + '"',
100                    '-DNINJA_BOOTSTRAP'])
101     if options.windows:
102         cflags.append('-D_WIN32_WINNT=0x0501')
103         conf_args.append("--platform=mingw")
104     if options.x64:
105         cflags.append('-m64')
106 args.extend(cflags)
107 args.extend(ldflags)
108 binary = 'ninja.bootstrap'
109 if options.windows:
110     binary = 'ninja.bootstrap.exe'
111 args.extend(sources)
112 if options.windows:
113     args.extend(['/link', '/out:' + binary])
114 else:
115     args.extend(['-o', binary])
116
117 if options.verbose:
118     print(' '.join(args))
119
120 try:
121     run(args)
122 except:
123     print('Failure running:', args)
124     raise
125
126 verbose = []
127 if options.verbose:
128     verbose = ['-v']
129
130 if options.windows:
131     print('Building ninja using itself...')
132     run([sys.executable, 'configure.py'] + conf_args)
133     run(['./' + binary] + verbose)
134
135     # Copy the new executable over the bootstrap one.
136     shutil.copyfile('ninja.exe', binary)
137
138     # Clean up.
139     for obj in glob.glob('*.obj'):
140         os.unlink(obj)
141
142     print("""
143 Done!
144
145 Note: to work around Windows file locking, where you can't rebuild an
146 in-use binary, to run ninja after making any changes to build ninja itself
147 you should run ninja.bootstrap instead.""")
148 else:
149     print('Building ninja using itself...')
150     run([sys.executable, 'configure.py'] + conf_args)
151     run(['./' + binary] + verbose)
152     os.unlink(binary)
153     print('Done!')