add a TODO from a pull request
[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 (when using Cygwin Python)',
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 vcdir = os.environ.get('VCINSTALLDIR')
86 if vcdir:
87     if options.x64:
88         cl = [os.path.join(vcdir, 'bin', 'amd64', 'cl.exe')]
89     else:
90         cl = [os.path.join(vcdir, 'bin', 'cl.exe')]
91     args = cl + ['/nologo', '/EHsc', '/DNOMINMAX']
92 else:
93     args = shlex.split(os.environ.get('CXX', 'g++'))
94     cflags.extend(['-Wno-deprecated',
95                    '-DNINJA_PYTHON="' + sys.executable + '"',
96                    '-DNINJA_BOOTSTRAP'])
97     if options.windows:
98         cflags.append('-D_WIN32_WINNT=0x0501')
99     if options.x64:
100         cflags.append('-m64')
101 args.extend(cflags)
102 args.extend(ldflags)
103 binary = 'ninja.bootstrap'
104 if options.windows:
105     binary = 'ninja.bootstrap.exe'
106 args.extend(sources)
107 if vcdir:
108     args.extend(['/link', '/out:' + binary])
109 else:
110     args.extend(['-o', binary])
111
112 if options.verbose:
113     print(' '.join(args))
114
115 try:
116     run(args)
117 except:
118     print('Failure running:', args)
119     raise
120
121 verbose = []
122 if options.verbose:
123     verbose = ['-v']
124
125 if options.windows:
126     print('Building ninja using itself...')
127     run([sys.executable, 'configure.py', '--with-ninja=%s' % binary] +
128         conf_args)
129     run(['./' + binary] + verbose)
130
131     # Copy the new executable over the bootstrap one.
132     shutil.copyfile('ninja.exe', binary)
133
134     # Clean up.
135     for obj in glob.glob('*.obj'):
136         os.unlink(obj)
137
138     print("""
139 Done!
140
141 Note: to work around Windows file locking, where you can't rebuild an
142 in-use binary, to run ninja after making any changes to build ninja itself
143 you should run ninja.bootstrap instead.  Your build is also configured to
144 use ninja.bootstrap.exe as the MSVC helper; see the --with-ninja flag of
145 the --help output of configure.py.""")
146 else:
147     print('Building ninja using itself...')
148     run([sys.executable, 'configure.py'] + conf_args)
149     run(['./' + binary] + verbose)
150     os.unlink(binary)
151     print('Done!')