Skip to content

Commit 1f719f3

Browse files
committed
[build_script.py] Add "test" subcommand
This "FIXME" describes a problem with the swift-corelibs-xctest build script when invoked in the context of the greater Swift build script: https://github.com/apple/swift/blob/6ccf5da2dfc8a74c84b2fd99c32dcdf2255699d7/utils/build-script-impl#L2070-L2072 The problem is that there is currently no way to test an *already built* XCTest.so. Instead, the XCTest build script re-builds the entire project, then tests the newly build XCTest.so. Add a "test" subcommand to build_script.py, which allows users to test an already built XCTest.so: ``` $ ./build_script.py test --swiftc `which swiftc` /path/to/build/dir ``` Users may still choose to build *and* test, by using the old build_script.py invocation: ``` $ ./build_script.py --swiftc `which swiftc` --test ```
1 parent e480d02 commit 1f719f3

File tree

1 file changed

+130
-56
lines changed

1 file changed

+130
-56
lines changed

build_script.py

Lines changed: 130 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import argparse
1313
import os
1414
import subprocess
15+
import sys
1516
import tempfile
1617

1718
SOURCE_DIR = os.path.dirname(os.path.abspath(__file__))
@@ -23,50 +24,12 @@ def run(command):
2324
note(command)
2425
subprocess.check_call(command, shell=True)
2526

26-
def main():
27-
parser = argparse.ArgumentParser(
28-
description="Builds XCTest using a Swift compiler.")
29-
parser.add_argument("--swiftc",
30-
help="path to the swift compiler",
31-
metavar="PATH",
32-
required=True)
33-
parser.add_argument("--build-dir",
34-
help="path to the output build directory. If not "
35-
"specified, a temporary directory is used",
36-
metavar="PATH",
37-
default=tempfile.mkdtemp())
38-
parser.add_argument("--swift-build-dir", help="deprecated, do not use")
39-
parser.add_argument("--arch", help="deprecated, do not use")
40-
parser.add_argument("--module-install-path",
41-
help="location to install module files",
42-
metavar="PATH",
43-
dest="module_path")
44-
parser.add_argument("--library-install-path",
45-
help="location to install shared library files",
46-
metavar="PATH",
47-
dest="lib_path")
48-
parser.add_argument("--release",
49-
help="builds for release",
50-
action="store_const",
51-
dest="build_style",
52-
const="release",
53-
default="debug")
54-
parser.add_argument("--debug",
55-
help="builds for debug (the default)",
56-
action="store_const",
57-
dest="build_style",
58-
const="debug",
59-
default="debug")
60-
parser.add_argument("--test",
61-
help="Whether to run tests after building. "
62-
"Note that you must have cloned "
63-
"https://github.com/apple/swift-llvm "
64-
"at {} in order to run this command. ".format(
65-
os.path.join(
66-
os.path.dirname(SOURCE_DIR), 'llvm')),
67-
action="store_true")
68-
args = parser.parse_args()
6927

28+
def _build(args):
29+
"""
30+
Build XCTest and place the built products in the given 'build_dir'.
31+
If 'test' is specified, also executes the 'test' subcommand.
32+
"""
7033
swiftc = os.path.abspath(args.swiftc)
7134
build_dir = os.path.abspath(args.build_dir)
7235

@@ -84,7 +47,6 @@ def main():
8447
for file in sourceFiles:
8548
sourcePaths.append("{0}/Sources/XCTest/{1}".format(SOURCE_DIR, file))
8649

87-
8850
if args.build_style == "debug":
8951
style_options = "-g"
9052
else:
@@ -120,20 +82,132 @@ def main():
12082
subprocess.check_call(cmd)
12183

12284
if args.test:
123-
lit_path = os.path.join(
124-
os.path.dirname(SOURCE_DIR), 'llvm', 'utils', 'lit', 'lit.py')
125-
lit_flags = '-sv --no-progress-bar'
126-
tests_path = os.path.join(SOURCE_DIR, 'Tests', 'Functional')
127-
run('SWIFT_EXEC={swiftc} '
128-
'BUILT_PRODUCTS_DIR={built_products_dir} '
129-
'{lit_path} {lit_flags} '
130-
'{tests_path}'.format(swiftc=swiftc,
131-
built_products_dir=build_dir,
132-
lit_path=lit_path,
133-
lit_flags=lit_flags,
134-
tests_path=tests_path))
85+
# Execute main() using the arguments necessary to run the tests.
86+
main(args=["test", "--swiftc", swiftc, build_dir])
13587

13688
note('Done.')
13789

90+
91+
def _test(args):
92+
"""
93+
Test the built XCTest.so library at the given 'build_dir', using the
94+
given 'swiftc' compiler.
95+
"""
96+
# FIXME: Allow path to lit to be specified as an option, with this
97+
# path as a default.
98+
lit_path = os.path.join(
99+
os.path.dirname(SOURCE_DIR), "llvm", "utils", "lit", "lit.py")
100+
# FIXME: Allow these to be specified by the Swift build script.
101+
lit_flags = "-sv --no-progress-bar"
102+
tests_path = os.path.join(SOURCE_DIR, "Tests", "Functional")
103+
run("SWIFT_EXEC={swiftc} "
104+
"BUILT_PRODUCTS_DIR={build_dir} "
105+
"{lit_path} {lit_flags} "
106+
"{tests_path}".format(swiftc=args.swiftc,
107+
build_dir=args.build_dir,
108+
lit_path=lit_path,
109+
lit_flags=lit_flags,
110+
tests_path=tests_path))
111+
112+
113+
def main(args=sys.argv[1:]):
114+
"""
115+
The main entry point for this script. Based on the subcommand given,
116+
delegates building or testing XCTest to a sub-parser and its corresponding
117+
function.
118+
"""
119+
parser = argparse.ArgumentParser(
120+
description="Builds, tests, and installs XCTest.")
121+
subparsers = parser.add_subparsers(
122+
description="Use one of these to specify whether to build, test, "
123+
"or install XCTest. If you don't specify any of these, "
124+
"'build' is executed as a default. You may also use "
125+
"'build' to also test and install the built products. "
126+
"Pass the -h or --help option to any of the subcommands "
127+
"for more information.")
128+
129+
build_parser = subparsers.add_parser(
130+
"build",
131+
description="Build XCTest.so, XCTest.swiftmodule, and XCTest.swiftdoc "
132+
"using the given Swift compiler. This command may also "
133+
"test and install the built products.")
134+
build_parser.set_defaults(func=_build)
135+
build_parser.add_argument(
136+
"--swiftc",
137+
help="Path to the 'swiftc' compiler that will be used to build "
138+
"XCTest.so, XCTest.swiftmodule, and XCTest.swiftdoc. This will "
139+
"also be used to build the tests for those built products if the "
140+
"--test option is specified.",
141+
metavar="PATH",
142+
required=True)
143+
build_parser.add_argument(
144+
"--build-dir",
145+
help="Path to the output build directory. If not specified, a "
146+
"temporary directory is used",
147+
metavar="PATH",
148+
default=tempfile.mkdtemp())
149+
build_parser.add_argument("--swift-build-dir",
150+
help="deprecated, do not use")
151+
build_parser.add_argument("--arch", help="deprecated, do not use")
152+
build_parser.add_argument(
153+
"--module-install-path",
154+
help="Location at which to install XCTest.swiftmodule and "
155+
"XCTest.swiftdoc. This directory will be created if it doesn't "
156+
"already exist.",
157+
dest="module_path")
158+
build_parser.add_argument(
159+
"--library-install-path",
160+
help="Location at which to install XCTest.so. This directory will be "
161+
"created if it doesn't already exist.",
162+
dest="lib_path")
163+
build_parser.add_argument(
164+
"--release",
165+
help="builds for release",
166+
action="store_const",
167+
dest="build_style",
168+
const="release",
169+
default="debug")
170+
build_parser.add_argument(
171+
"--debug",
172+
help="builds for debug (the default)",
173+
action="store_const",
174+
dest="build_style",
175+
const="debug",
176+
default="debug")
177+
build_parser.add_argument(
178+
"--test",
179+
help="Whether to run tests after building. Note that you must have "
180+
"cloned https://github.com/apple/swift-llvm at {} in order to "
181+
"run this command.".format(os.path.join(
182+
os.path.dirname(SOURCE_DIR), 'llvm')),
183+
action="store_true")
184+
185+
test_parser = subparsers.add_parser(
186+
"test",
187+
description="Tests a built XCTest framework at the given path.")
188+
test_parser.set_defaults(func=_test)
189+
test_parser.add_argument(
190+
"build_dir",
191+
help="An absolute path to a directory containing the built XCTest.so "
192+
"library.",
193+
metavar="PATH")
194+
test_parser.add_argument(
195+
"--swiftc",
196+
help="Path to the 'swiftc' compiler used to build and run the tests.",
197+
required=True)
198+
199+
# Many versions of Python require a subcommand must be specified.
200+
# We handle this here: if no known subcommand (or none of the help options)
201+
# is included in the arguments, then insert the default subcommand
202+
# argument.
203+
if any([a in ["build", "test", "-h", "--help"] for a in args]):
204+
parsed_args = parser.parse_args(args=args)
205+
else:
206+
parsed_args = parser.parse_args(args=["build"] + args)
207+
208+
# Execute the function for the subcommand we've been given.
209+
parsed_args.func(parsed_args)
210+
211+
138212
if __name__ == '__main__':
139213
main()

0 commit comments

Comments
 (0)