Merge pull request #577 from tfarina/structs
[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 import platform_helper
27
28 os.chdir(os.path.dirname(os.path.abspath(__file__)))
29
30 parser = OptionParser()
31
32 parser.add_option('--verbose', action='store_true',
33                   help='enable verbose build',)
34 parser.add_option('--x64', action='store_true',
35                   help='force 64-bit build (Windows)',)
36 parser.add_option('--platform',
37                   help='target platform (' + '/'.join(platform_helper.platforms()) + ')',
38                   choices=platform_helper.platforms())
39 (options, conf_args) = parser.parse_args()
40
41
42 platform = platform_helper.Platform(options.platform)
43 conf_args.append("--platform=" + platform.platform())
44
45 def run(*args, **kwargs):
46     returncode = subprocess.call(*args, **kwargs)
47     if returncode != 0:
48         sys.exit(returncode)
49
50 # Compute system-specific CFLAGS/LDFLAGS as used in both in the below
51 # g++ call as well as in the later configure.py.
52 cflags = os.environ.get('CFLAGS', '').split()
53 ldflags = os.environ.get('LDFLAGS', '').split()
54 if platform.is_freebsd() or platform.is_openbsd():
55     cflags.append('-I/usr/local/include')
56     ldflags.append('-L/usr/local/lib')
57
58 print('Building ninja manually...')
59
60 try:
61     os.mkdir('build')
62 except OSError:
63     e = sys.exc_info()[1]
64     if e.errno != errno.EEXIST:
65         raise
66
67 sources = []
68 for src in glob.glob('src/*.cc'):
69     if src.endswith('test.cc') or src.endswith('.in.cc'):
70         continue
71     if src.endswith('bench.cc'):
72         continue
73
74     filename = os.path.basename(src)
75     if filename == 'browse.cc':  # Depends on generated header.
76         continue
77
78     if platform.is_windows():
79         if src.endswith('-posix.cc'):
80             continue
81     else:
82         if src.endswith('-win32.cc'):
83             continue
84
85     sources.append(src)
86
87 if platform.is_windows():
88     sources.append('src/getopt.c')
89
90 if platform.is_msvc():
91     cl = 'cl'
92     vcdir = os.environ.get('VCINSTALLDIR')
93     if vcdir:
94         if options.x64:
95             cl = os.path.join(vcdir, 'bin', 'x86_amd64', 'cl.exe')
96             if not os.path.exists(cl):
97                 cl = os.path.join(vcdir, 'bin', 'amd64', 'cl.exe')
98         else:
99             cl = os.path.join(vcdir, 'bin', 'cl.exe')
100     args = [cl, '/nologo', '/EHsc', '/DNOMINMAX']
101 else:
102     args = shlex.split(os.environ.get('CXX', 'g++'))
103     cflags.extend(['-Wno-deprecated',
104                    '-DNINJA_PYTHON="' + sys.executable + '"',
105                    '-DNINJA_BOOTSTRAP'])
106     if platform.is_windows():
107         cflags.append('-D_WIN32_WINNT=0x0501')
108     if options.x64:
109         cflags.append('-m64')
110 args.extend(cflags)
111 args.extend(ldflags)
112 binary = 'ninja.bootstrap'
113 if platform.is_windows():
114     binary = 'ninja.bootstrap.exe'
115 args.extend(sources)
116 if platform.is_msvc():
117     args.extend(['/link', '/out:' + binary])
118 else:
119     args.extend(['-o', binary])
120
121 if options.verbose:
122     print(' '.join(args))
123
124 try:
125     run(args)
126 except:
127     print('Failure running:', args)
128     raise
129
130 verbose = []
131 if options.verbose:
132     verbose = ['-v']
133
134 if platform.is_windows():
135     print('Building ninja using itself...')
136     run([sys.executable, 'configure.py'] + conf_args)
137     run(['./' + binary] + verbose)
138
139     # Copy the new executable over the bootstrap one.
140     shutil.copyfile('ninja.exe', binary)
141
142     # Clean up.
143     for obj in glob.glob('*.obj'):
144         os.unlink(obj)
145
146     print("""
147 Done!
148
149 Note: to work around Windows file locking, where you can't rebuild an
150 in-use binary, to run ninja after making any changes to build ninja itself
151 you should run ninja.bootstrap instead.""")
152 else:
153     print('Building ninja using itself...')
154     run([sys.executable, 'configure.py'] + conf_args)
155     run(['./' + binary] + verbose)
156     os.unlink(binary)
157     print('Done!')