Skip to content

Commit b1fdbad

Browse files
authored
Merge pull request #39 from apple/helper
Add build-script-helper
2 parents a3386ad + 30d6722 commit b1fdbad

File tree

1 file changed

+234
-0
lines changed

1 file changed

+234
-0
lines changed

Utilities/build-script-helper.py

Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
#!/usr/bin/env python
2+
3+
"""
4+
This source file is part of the Swift.org open source project
5+
6+
Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
7+
Licensed under Apache License v2.0 with Runtime Library Exception
8+
9+
See http://swift.org/LICENSE.txt for license information
10+
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
11+
12+
-------------------------------------------------------------------------
13+
"""
14+
15+
from __future__ import print_function
16+
17+
import argparse
18+
import json
19+
import os
20+
import platform
21+
import re
22+
import shutil
23+
import subprocess
24+
import subprocess
25+
import sys
26+
import errno
27+
28+
def note(message):
29+
print("--- %s: note: %s" % (os.path.basename(sys.argv[0]), message))
30+
sys.stdout.flush()
31+
32+
def error(message):
33+
print("--- %s: error: %s" % (os.path.basename(sys.argv[0]), message))
34+
sys.stdout.flush()
35+
raise SystemExit(1)
36+
37+
def mkdir_p(path):
38+
"""Create the given directory, if it does not exist."""
39+
try:
40+
os.makedirs(path)
41+
except OSError as e:
42+
# Ignore EEXIST, which may occur during a race condition.
43+
if e.errno != errno.EEXIST:
44+
raise
45+
46+
def call(cmd, cwd=None, verbose=False):
47+
"""Calls a subprocess."""
48+
if verbose:
49+
print(' '.join(cmd))
50+
try:
51+
subprocess.check_call(cmd, cwd=cwd)
52+
except Exception as e:
53+
if not verbose:
54+
print(' '.join(cmd))
55+
error(str(e))
56+
57+
def call_output(cmd, cwd=None, stderr=False, verbose=False):
58+
"""Calls a subprocess for its return data."""
59+
if verbose:
60+
print(' '.join(cmd))
61+
try:
62+
return subprocess.check_output(cmd, cwd=cwd, stderr=stderr, universal_newlines=True).strip()
63+
except Exception as e:
64+
if not verbose:
65+
print(' '.join(cmd))
66+
error(str(e))
67+
68+
def main():
69+
parser = argparse.ArgumentParser(description="""
70+
This script will build a TSC using CMake.
71+
""")
72+
subparsers = parser.add_subparsers(dest='command')
73+
74+
# build
75+
parser_build = subparsers.add_parser("build", help="builds TSC using CMake")
76+
parser_build.set_defaults(func=build)
77+
add_build_args(parser_build)
78+
79+
args = parser.parse_args()
80+
args.func = args.func or build
81+
args.func(args)
82+
83+
# -----------------------------------------------------------
84+
# Argument parsing
85+
# -----------------------------------------------------------
86+
87+
def add_global_args(parser):
88+
"""Configures the parser with the arguments necessary for all actions."""
89+
parser.add_argument(
90+
"--build-dir",
91+
help="path where products will be built [%(default)s]",
92+
default=".build",
93+
metavar="PATH")
94+
parser.add_argument(
95+
"-v", "--verbose",
96+
action="store_true",
97+
help="whether to print verbose output")
98+
parser.add_argument(
99+
"--reconfigure",
100+
action="store_true",
101+
help="whether to always reconfigure cmake")
102+
103+
def add_build_args(parser):
104+
"""Configures the parser with the arguments necessary for build-related actions."""
105+
add_global_args(parser)
106+
parser.add_argument(
107+
"--swiftc-path",
108+
help="path to the swift compiler",
109+
metavar="PATH")
110+
parser.add_argument(
111+
'--cmake-path',
112+
metavar='PATH',
113+
help='path to the cmake binary to use for building')
114+
parser.add_argument(
115+
'--ninja-path',
116+
metavar='PATH',
117+
help='path to the ninja binary to use for building with CMake')
118+
119+
def parse_global_args(args):
120+
"""Parses and cleans arguments necessary for all actions."""
121+
args.build_dir = os.path.abspath(args.build_dir)
122+
args.project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
123+
124+
if platform.system() == 'Darwin':
125+
args.sysroot = call_output(["xcrun", "--sdk", "macosx", "--show-sdk-path"], verbose=args.verbose)
126+
else:
127+
args.sysroot = None
128+
129+
def parse_build_args(args):
130+
"""Parses and cleans arguments necessary for build-related actions."""
131+
parse_global_args(args)
132+
133+
args.swiftc_path = get_swiftc_path(args)
134+
args.cmake_path = get_cmake_path(args)
135+
args.ninja_path = get_ninja_path(args)
136+
137+
def get_swiftc_path(args):
138+
"""Returns the path to the Swift compiler."""
139+
if args.swiftc_path:
140+
swiftc_path = os.path.abspath(args.swiftc_path)
141+
elif os.getenv("SWIFT_EXEC"):
142+
swiftc_path = os.path.realpath(os.getenv("SWIFT_EXEC"))
143+
elif platform.system() == 'Darwin':
144+
swiftc_path = call_output(
145+
["xcrun", "--find", "swiftc"],
146+
stderr=subprocess.PIPE,
147+
verbose=args.verbose
148+
)
149+
else:
150+
swiftc_path = call_output(["which", "swiftc"], verbose=args.verbose)
151+
152+
if os.path.basename(swiftc_path) == 'swift':
153+
swiftc_path = swiftc_path + 'c'
154+
155+
return swiftc_path
156+
157+
def get_cmake_path(args):
158+
"""Returns the path to CMake."""
159+
if args.cmake_path:
160+
return os.path.abspath(args.cmake_path)
161+
elif platform.system() == 'Darwin':
162+
return call_output(
163+
["xcrun", "--find", "cmake"],
164+
stderr=subprocess.PIPE,
165+
verbose=args.verbose
166+
)
167+
else:
168+
return call_output(["which", "cmake"], verbose=args.verbose)
169+
170+
def get_ninja_path(args):
171+
"""Returns the path to Ninja."""
172+
if args.ninja_path:
173+
return os.path.abspath(args.ninja_path)
174+
elif platform.system() == 'Darwin':
175+
return call_output(
176+
["xcrun", "--find", "ninja"],
177+
stderr=subprocess.PIPE,
178+
verbose=args.verbose
179+
)
180+
else:
181+
return call_output(["which", "ninja"], verbose=args.verbose)
182+
183+
# -----------------------------------------------------------
184+
# Actions
185+
# -----------------------------------------------------------
186+
187+
def build(args):
188+
parse_build_args(args)
189+
build_tsc(args)
190+
191+
# -----------------------------------------------------------
192+
# Build functions
193+
# -----------------------------------------------------------
194+
195+
def build_with_cmake(args, cmake_args, source_path, build_dir):
196+
"""Runs CMake if needed, then builds with Ninja."""
197+
cache_path = os.path.join(build_dir, "CMakeCache.txt")
198+
if args.reconfigure or not os.path.isfile(cache_path) or not args.swiftc_path in open(cache_path).read():
199+
swift_flags = ""
200+
if args.sysroot:
201+
swift_flags = "-sdk %s" % args.sysroot
202+
203+
cmd = [
204+
args.cmake_path, "-G", "Ninja",
205+
"-DCMAKE_MAKE_PROGRAM=%s" % args.ninja_path,
206+
"-DCMAKE_BUILD_TYPE:=Debug",
207+
"-DCMAKE_Swift_FLAGS=" + swift_flags,
208+
"-DCMAKE_Swift_COMPILER:=%s" % (args.swiftc_path),
209+
] + cmake_args + [source_path]
210+
211+
if args.verbose:
212+
print(' '.join(cmd))
213+
214+
mkdir_p(build_dir)
215+
call(cmd, cwd=build_dir, verbose=True)
216+
217+
# Build.
218+
ninja_cmd = [args.ninja_path]
219+
220+
if args.verbose:
221+
ninja_cmd.append("-v")
222+
223+
call(ninja_cmd, cwd=build_dir, verbose=args.verbose)
224+
225+
def build_tsc(args):
226+
cmake_flags = []
227+
if platform.system() == 'Darwin':
228+
cmake_flags.append("-DCMAKE_C_FLAGS=-target x86_64-apple-macosx10.10")
229+
cmake_flags.append("-DCMAKE_OSX_DEPLOYMENT_TARGET=10.10")
230+
231+
build_with_cmake(args, cmake_flags, args.project_root, args.build_dir)
232+
233+
if __name__ == '__main__':
234+
main()

0 commit comments

Comments
 (0)