Skip to content

Commit 534a191

Browse files
committed
Merge pull request #997 from lplarson/code-coverage
[CMake] Support code coverage analysis
2 parents c0df537 + ba619a9 commit 534a191

File tree

10 files changed

+135
-4
lines changed

10 files changed

+135
-4
lines changed

cmake/modules/AddSwift.cmake

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,9 @@ function(compute_library_subdir result_var_name sdk arch)
4747
set("${result_var_name}" "${SWIFT_SDK_${sdk}_LIB_SUBDIR}/${arch}" PARENT_SCOPE)
4848
endfunction()
4949

50-
5150
function(_add_variant_c_compile_link_flags
52-
sdk arch build_type enable_assertions result_var_name)
51+
sdk arch build_type enable_assertions analyze_code_coverage
52+
result_var_name)
5353
set(result
5454
${${result_var_name}}
5555
"-target" "${SWIFT_SDK_${sdk}_ARCH_${arch}_TRIPLE}")
@@ -62,20 +62,27 @@ function(_add_variant_c_compile_link_flags
6262
"-arch" "${arch}"
6363
"-F" "${SWIFT_SDK_${sdk}_PATH}/../../../Developer/Library/Frameworks"
6464
"-m${SWIFT_SDK_${sdk}_VERSION_MIN_NAME}-version-min=${SWIFT_SDK_${sdk}_DEPLOYMENT_VERSION}")
65+
66+
if(analyze_code_coverage)
67+
list(APPEND result "-fprofile-instr-generate=swift-%p.profraw"
68+
"-fcoverage-mapping")
69+
endif()
6570
endif()
6671

6772
set("${result_var_name}" "${result}" PARENT_SCOPE)
6873
endfunction()
6974

7075
function(_add_variant_c_compile_flags
71-
sdk arch build_type enable_assertions result_var_name)
76+
sdk arch build_type enable_assertions analyze_code_coverage
77+
result_var_name)
7278
set(result ${${result_var_name}})
7379

7480
_add_variant_c_compile_link_flags(
7581
"${sdk}"
7682
"${arch}"
7783
"${build_type}"
7884
"${enable_assertions}"
85+
FALSE
7986
result)
8087

8188
is_build_type_optimized("${build_type}" optimized)
@@ -103,6 +110,11 @@ function(_add_variant_c_compile_flags
103110
list(APPEND result "-DNDEBUG")
104111
endif()
105112

113+
if(analyze_code_coverage)
114+
list(APPEND result "-fprofile-instr-generate=swift-%p.profraw"
115+
"-fcoverage-mapping")
116+
endif()
117+
106118
set("${result_var_name}" "${result}" PARENT_SCOPE)
107119
endfunction()
108120

@@ -139,7 +151,8 @@ function(_add_variant_swift_compile_flags
139151
endfunction()
140152

141153
function(_add_variant_link_flags
142-
sdk arch build_type enable_assertions result_var_name)
154+
sdk arch build_type enable_assertions analyze_code_coverage
155+
result_var_name)
143156

144157
if("${sdk}" STREQUAL "")
145158
message(FATAL_ERROR "Should specify an SDK")
@@ -156,6 +169,7 @@ function(_add_variant_link_flags
156169
"${arch}"
157170
"${build_type}"
158171
"${enable_assertions}"
172+
"${analyze_code_coverage}"
159173
result)
160174

161175
if("${sdk}" STREQUAL "LINUX")
@@ -1041,18 +1055,21 @@ function(_add_swift_library_single target name)
10411055
else()
10421056
set(build_type "${CMAKE_BUILD_TYPE}")
10431057
set(enable_assertions "${LLVM_ENABLE_ASSERTIONS}")
1058+
set(analyze_code_coverage "${SWIFT_ANALYZE_CODE_COVERAGE}")
10441059
endif()
10451060
_add_variant_c_compile_flags(
10461061
"${SWIFTLIB_SINGLE_SDK}"
10471062
"${SWIFTLIB_SINGLE_ARCHITECTURE}"
10481063
"${build_type}"
10491064
"${enable_assertions}"
1065+
"${analyze_code_coverage}"
10501066
c_compile_flags)
10511067
_add_variant_link_flags(
10521068
"${SWIFTLIB_SINGLE_SDK}"
10531069
"${SWIFTLIB_SINGLE_ARCHITECTURE}"
10541070
"${build_type}"
10551071
"${enable_assertions}"
1072+
"${analyze_code_coverage}"
10561073
link_flags)
10571074

10581075
# Handle gold linker flags for shared libraries.
@@ -1618,12 +1635,14 @@ function(_add_swift_executable_single name)
16181635
"${SWIFTEXE_SINGLE_ARCHITECTURE}"
16191636
"${CMAKE_BUILD_TYPE}"
16201637
"${LLVM_ENABLE_ASSERTIONS}"
1638+
"${SWIFT_ANALYZE_CODE_COVERAGE}"
16211639
c_compile_flags)
16221640
_add_variant_link_flags(
16231641
"${SWIFTEXE_SINGLE_SDK}"
16241642
"${SWIFTEXE_SINGLE_ARCHITECTURE}"
16251643
"${CMAKE_BUILD_TYPE}"
16261644
"${LLVM_ENABLE_ASSERTIONS}"
1645+
"${SWIFT_ANALYZE_CODE_COVERAGE}"
16271646
link_flags)
16281647

16291648
list(APPEND link_flags

test/lit.site.cfg.in

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ if "@SWIFT_OPTIMIZED@" == "TRUE":
4242
if "@SWIFT_HAVE_WORKING_STD_REGEX@" == "FALSE":
4343
config.available_features.add('broken_std_regex')
4444

45+
if "@SWIFT_ANALYZE_CODE_COVERAGE@" == "TRUE":
46+
lit_config.useValgrind = True
47+
lit_config.valgrindArgs = [os.path.join(config.swift_src_root,
48+
"utils/use_profdir.py")]
49+
4550
# Let the main config do the real work.
4651
if config.test_exec_root is None:
4752
config.test_exec_root = os.path.dirname(os.path.realpath(__file__))

tools/SourceKit/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ function(add_sourcekit_symbol_exports target_name export_file)
4646

4747
set_property(TARGET ${target_name} APPEND_STRING PROPERTY
4848
LINK_FLAGS " -Wl,-exported_symbols_list,${CMAKE_CURRENT_BINARY_DIR}/symbol.exports")
49+
4950
add_dependencies(${target_name} ${target_name}_exports)
5051
endif()
5152
endfunction()
@@ -63,17 +64,20 @@ function(add_sourcekit_default_compiler_flags target)
6364
# Add variant-specific flags.
6465
set(build_type "${CMAKE_BUILD_TYPE}")
6566
set(enable_assertions "${LLVM_ENABLE_ASSERTIONS}")
67+
set(analyze_code_coverage "${SWIFT_ANALYZE_CODE_COVERAGE}")
6668
_add_variant_c_compile_flags(
6769
"${sdk}"
6870
"${arch}"
6971
"${build_type}"
7072
"${enable_assertions}"
73+
"${analyze_code_coverage}"
7174
c_compile_flags)
7275
_add_variant_link_flags(
7376
"${sdk}"
7477
"${arch}"
7578
"${build_type}"
7679
"${enable_assertions}"
80+
"${analyze_code_coverage}"
7781
link_flags)
7882

7983
# Convert variables to space-separated strings.
@@ -234,6 +238,11 @@ macro(add_sourcekit_executable name)
234238
set_target_properties(${name}
235239
PROPERTIES
236240
LINK_FLAGS "-Wl,-exported_symbol,_main")
241+
242+
if(SWIFT_ANALYZE_CODE_COVERAGE)
243+
set_property(TARGET "${name}" APPEND_STRING PROPERTY
244+
LINK_FLAGS " -fprofile-instr-generate=swift-%p.profraw -fcoverage-mapping")
245+
endif()
237246
endif()
238247
endif()
239248
add_sourcekit_default_compiler_flags("${name}")

tools/SourceKit/tools/complete-test/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
1414
set_target_properties(complete-test
1515
PROPERTIES
1616
LINK_FLAGS "-Wl,-rpath -Wl,@executable_path/../lib")
17+
18+
if(SWIFT_ANALYZE_CODE_COVERAGE)
19+
set_property(TARGET complete-test APPEND_STRING PROPERTY
20+
LINK_FLAGS " -fprofile-instr-generate=swift-%p.profraw -fcoverage-mapping")
21+
endif()
1722
endif()
1823

1924
swift_install_in_component(tools

tools/SourceKit/tools/sourcekitd-repl/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
88
set_target_properties(sourcekitd-repl
99
PROPERTIES
1010
LINK_FLAGS "-Wl,-rpath -Wl,@executable_path/../lib")
11+
12+
if(SWIFT_ANALYZE_CODE_COVERAGE)
13+
set_property(TARGET sourcekitd-repl APPEND_STRING PROPERTY
14+
LINK_FLAGS " -fprofile-instr-generate=swift-%p.profraw -fcoverage-mapping")
15+
endif()
1116
endif()
1217

1318
swift_install_in_component(tools

tools/SourceKit/tools/sourcekitd-test/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
2222
set_target_properties(sourcekitd-test
2323
PROPERTIES
2424
LINK_FLAGS "-Wl,-rpath -Wl,@executable_path/../lib")
25+
26+
if(SWIFT_ANALYZE_CODE_COVERAGE)
27+
set_property(TARGET sourcekitd-test APPEND_STRING PROPERTY
28+
LINK_FLAGS " -fprofile-instr-generate=swift-%p.profraw -fcoverage-mapping")
29+
endif()
2530
endif()
2631

2732
swift_install_in_component(tools

unittests/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ function(add_swift_unittest test_dirname)
2626
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
2727
set_property(TARGET "${test_dirname}" APPEND_STRING PROPERTY
2828
LINK_FLAGS " -Xlinker -rpath -Xlinker ${SWIFT_LIBRARY_OUTPUT_INTDIR}/swift/macosx")
29+
30+
if(SWIFT_ANALYZE_CODE_COVERAGE)
31+
set_property(TARGET "${test_dirname}" APPEND_STRING PROPERTY
32+
LINK_FLAGS " -fprofile-instr-generate=swift-%p.profraw -fcoverage-mapping")
33+
endif()
2934
endif()
3035
endfunction()
3136

utils/build-script

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,12 @@ also build for tvOS, but disallow tests that require an tvos device""",
491491
also build for Apple watchos, but disallow tests that require an watchOS device""",
492492
action="store_true")
493493

494+
parser.add_argument("--swift-analyze-code-coverage",
495+
help="enable code coverage analysis in Swift",
496+
action="store_const",
497+
const=True,
498+
dest="swift_analyze_code_coverage")
499+
494500
parser.add_argument("--build-subdir",
495501
help="""
496502
name of the directory under $SWIFT_BUILD_ROOT where the build products will be
@@ -526,6 +532,10 @@ the number of parallel build jobs to use""",
526532
'--cmake',
527533
]))
528534

535+
# Code coverage analysis disabled by default.
536+
if args.swift_analyze_code_coverage is None:
537+
args.swift_analyze_code_coverage = False
538+
529539
# Build cmark if any cmark-related options were specified.
530540
if (args.cmark_build_variant is not None):
531541
args.build_cmark = True
@@ -685,6 +695,8 @@ the number of parallel build jobs to use""",
685695
swift_build_dir_label = args.swift_build_variant
686696
if args.swift_assertions:
687697
swift_build_dir_label += "Assert"
698+
if args.swift_analyze_code_coverage:
699+
swift_build_dir_label += "Coverage"
688700

689701
swift_stdlib_build_dir_label = args.swift_stdlib_build_variant
690702
if args.swift_stdlib_assertions:
@@ -756,6 +768,7 @@ the number of parallel build jobs to use""",
756768
"--llvm-enable-assertions", str(args.llvm_assertions).lower(),
757769
"--swift-enable-assertions", str(args.swift_assertions).lower(),
758770
"--swift-stdlib-enable-assertions", str(args.swift_stdlib_assertions).lower(),
771+
"--swift-analyze-code-coverage", str(args.swift_analyze_code_coverage).lower(),
759772
"--cmake-generator", args.cmake_generator,
760773
"--build-jobs", str(args.build_jobs),
761774
"--workspace", SWIFT_SOURCE_ROOT

utils/build-script-impl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ KNOWN_SETTINGS=(
7171
llvm-enable-assertions "1" "enable assertions in LLVM and Clang"
7272
swift-build-type "Debug" "the CMake build variant for Swift"
7373
swift-enable-assertions "1" "enable assertions in Swift"
74+
swift-analyze-code-coverage "0" "enable code coverage analysis in Swift"
7475
swift-stdlib-build-type "Debug" "the CMake build variant for Swift"
7576
swift-stdlib-enable-assertions "1" "enable assertions in Swift"
7677
lldb-build-type "Debug" "the CMake build variant for LLDB"
@@ -1619,6 +1620,7 @@ for deployment_target in "${NATIVE_TOOLS_DEPLOYMENT_TARGETS[@]}" "${CROSS_TOOLS_
16191620
-DCMAKE_CXX_FLAGS="$(swift_c_flags ${deployment_target})"
16201621
-DCMAKE_BUILD_TYPE:STRING="${SWIFT_BUILD_TYPE}"
16211622
-DLLVM_ENABLE_ASSERTIONS:BOOL=$(true_false "${SWIFT_ENABLE_ASSERTIONS}")
1623+
-DSWIFT_ANALYZE_CODE_COVERAGE:BOOL=$(true_false "${SWIFT_ANALYZE_CODE_COVERAGE}")
16221624
-DSWIFT_STDLIB_BUILD_TYPE:STRING="${SWIFT_STDLIB_BUILD_TYPE}"
16231625
-DSWIFT_STDLIB_ASSERTIONS:BOOL=$(true_false "${SWIFT_STDLIB_ENABLE_ASSERTIONS}")
16241626
-DSWIFT_NATIVE_LLVM_TOOLS_PATH:STRING="${native_llvm_tools_path}"

utils/use_profdir.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#!/usr/bin/env python
2+
3+
# utils/use_profdir.py
4+
#
5+
# This source file is part of the Swift.org open source project
6+
#
7+
# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
8+
# Licensed under Apache License v2.0 with Runtime Library Exception
9+
#
10+
# See http://swift.org/LICENSE.txt for license information
11+
# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
12+
13+
# This script is used to help prevent profile data clobbering during code
14+
# coverage profiling.
15+
16+
import sys
17+
import subprocess
18+
import os
19+
import string
20+
import random
21+
22+
def random_string(N):
23+
"""Return a random ascii_uppercase + digits string of length `N`"""
24+
return ''.join(random.choice(string.ascii_uppercase + string.digits)
25+
for _ in range(N))
26+
27+
def main():
28+
# Grab passed in bash command
29+
cmd = sys.argv[1:]
30+
31+
# Search arguments for test identifiers
32+
script_files = [f for f in cmd if f.endswith('.script')]
33+
gtests = [f.split('=')[1] for f in cmd if f.startswith('--gtest_filter')]
34+
35+
# Generate directory name using first test identifier, defaulting to
36+
# random characters if no test identifier can be found
37+
if script_files:
38+
profdir = script_files[0] + '.profdir'
39+
elif gtests:
40+
profdir = os.path.join(os.path.dirname(cmd[0]), gtests[0] + '.profdir')
41+
else:
42+
profdir = random_string(12) + '.profdir'
43+
44+
# Create the directory using the generated name
45+
try:
46+
os.makedirs(profdir)
47+
except OSError as e:
48+
ERROR_FILE_EXISTS = 17
49+
if e.errno != ERROR_FILE_EXISTS:
50+
raise
51+
52+
# cd into the new directory and execute the passed in command
53+
previous_cwd = os.getcwd()
54+
os.chdir(profdir)
55+
try:
56+
return_code = subprocess.call(cmd)
57+
finally:
58+
os.chdir(previous_cwd)
59+
60+
return return_code
61+
62+
if __name__ == '__main__':
63+
exit(main())

0 commit comments

Comments
 (0)