Skip to content

Commit 62597ea

Browse files
committed
build_script: Add an option to build the swift libraries multiple times to check if incremental compilation works.
A script checks if the output object file is written only once even if the compiler is invoked multiple times. The main purpose of this check is to ensure that the compiler is deterministic (until IRGen).
1 parent c88720e commit 62597ea

File tree

4 files changed

+102
-0
lines changed

4 files changed

+102
-0
lines changed

CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ option(SWIFT_STDLIB_SIL_DEBUGGING
3636
"Compile the Swift standard library with -gsil to enable debugging and profiling on SIL level"
3737
FALSE)
3838

39+
option(SWIFT_CHECK_INCREMENTAL_COMPILATION
40+
"Check if incremental compilation works when compiling the Swift libraries"
41+
FALSE)
42+
3943
option(SWIFT_BUILD_TOOLS
4044
"Build the Swift compiler and other tools"
4145
TRUE)

cmake/modules/SwiftSource.cmake

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,10 @@ function(_compile_swift_files dependency_target_out_var_name)
369369
set(main_command "-emit-sib")
370370
endif()
371371

372+
if (SWIFT_CHECK_INCREMENTAL_COMPILATION)
373+
set(swift_compiler_tool "${SWIFT_SOURCE_DIR}/utils/check-incremental" "${swift_compiler_tool}")
374+
endif()
375+
372376
add_custom_command_target(
373377
dependency_target
374378
${command_create_dirs}

utils/build-script-impl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ KNOWN_SETTINGS=(
166166
build-swift-examples "1" "set to 1 to build examples"
167167
build-serialized-stdlib-unittest "0" "set to 1 to build the StdlibUnittest module with -sil-serialize-all"
168168
build-sil-debugging-stdlib "0" "set to 1 to build the Swift standard library with -gsil to enable debugging and profiling on SIL level"
169+
check-incremental-compilation "0" "set to 1 to compile swift libraries multiple times to check if incremental compilation works"
169170
source-tree-includes-tests "1" "set to 0 to allow the build to proceed when 'test' directory is missing (required for B&I builds)"
170171
native-llvm-tools-path "" "directory that contains LLVM tools that are executable on the build machine"
171172
native-clang-tools-path "" "directory that contains Clang tools that are executable on the build machine"
@@ -1645,6 +1646,7 @@ for deployment_target in "${HOST_TARGET}" "${CROSS_COMPILE_TOOLS_DEPLOYMENT_TARG
16451646
-DSWIFT_BUILD_STDLIB:BOOL=$(true_false "${BUILD_SWIFT_STDLIB}")
16461647
-DSWIFT_SERIALIZE_STDLIB_UNITTEST:BOOL=$(true_false "${BUILD_SERIALIZED_STDLIB_UNITTEST}")
16471648
-DSWIFT_STDLIB_SIL_DEBUGGING:BOOL=$(true_false "${BUILD_SIL_DEBUGGING_STDLIB}")
1649+
-DSWIFT_CHECK_INCREMENTAL_COMPILATION:BOOL=$(true_false "${CHECK_INCREMENTAL_COMPILATION}")
16481650
-DSWIFT_BUILD_SDK_OVERLAY:BOOL=$(true_false "${BUILD_SWIFT_SDK_OVERLAY}")
16491651
-DSWIFT_BUILD_STATIC_STDLIB:BOOL=$(true_false "${BUILD_SWIFT_STATIC_STDLIB}")
16501652
-DSWIFT_BUILD_PERF_TESTSUITE:BOOL=$(true_false "${build_perf_testsuite_this_time}")

utils/check-incremental

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
#!/usr/bin/env python
2+
# check-incremental - Check if incremental compilation works -*- python -*-
3+
#
4+
# This source file is part of the Swift.org open source project
5+
#
6+
# Copyright (c) 2014 - 2016 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 the list of Swift project authors
11+
#
12+
# ----------------------------------------------------------------------------
13+
#
14+
# This is a wrapper for the swift compiler.
15+
# It invokes the compiler multiple times and checks if the output object file
16+
# is only written a single time.
17+
# The main purpose of the check is to ensure that the compiler is
18+
# deterministic.
19+
#
20+
# ----------------------------------------------------------------------------
21+
22+
import subprocess
23+
import os
24+
import sys
25+
import time
26+
27+
28+
def main():
29+
verbose = False
30+
num_iterations = 4
31+
32+
write_obj_file = False
33+
next_arg_is_output = False
34+
compare_time = True
35+
output_file = None
36+
37+
for arg in sys.argv:
38+
if next_arg_is_output:
39+
output_file = arg
40+
next_arg_is_output = False
41+
elif arg == '-c':
42+
write_obj_file = True
43+
elif arg == '-disable-incremental-llvm-codegen':
44+
compare_time = False
45+
elif arg == '-o':
46+
next_arg_is_output = True
47+
48+
if not write_obj_file or output_file is None:
49+
return
50+
51+
new_args = sys.argv[1:]
52+
subprocess.check_call(new_args)
53+
54+
if verbose:
55+
print "Reference compilation of " + output_file + ":"
56+
57+
reference_md5 = subprocess.check_output(["md5", "-q", output_file])
58+
reference_time = os.path.getmtime(output_file)
59+
60+
if verbose:
61+
print " time = {}".format(reference_time)
62+
print " md5 = " + reference_md5
63+
64+
subprocess.check_call(["cp", output_file, output_file + ".ref.o"])
65+
66+
for iteration in range(0, num_iterations):
67+
68+
if verbose:
69+
print "Iteration {}:".format(iteration)
70+
71+
subprocess.check_call(new_args)
72+
73+
second_md5 = subprocess.check_output(["md5", "-q", output_file])
74+
second_time = os.path.getmtime(output_file)
75+
76+
if verbose:
77+
print " time = {}".format(second_time)
78+
print " md5 = " + second_md5
79+
80+
# This is the most important check: is the output file exactly the same.
81+
if reference_md5 != second_md5:
82+
sys.exit("non-determinism when generating: " + output_file)
83+
84+
# This is the bonus check: does the compiler not re-write the output file.
85+
# (For compilations < 1sec this check may succeed even if the file was
86+
# overwritten).
87+
if compare_time and reference_time != second_time:
88+
sys.exit("file re-written: " + output_file)
89+
90+
91+
main()
92+

0 commit comments

Comments
 (0)