aboutsummaryrefslogtreecommitdiff
path: root/cmake/modules/TestSuite.cmake
blob: e09a85eb0da6f90347a160ac85198ae6b7c2883f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
##===- TestSuite.cmake ----------------------------------------------------===##
#
# Defines helper functions to build benchmarks and the corresponding .test files
#
##===----------------------------------------------------------------------===##
include(TestFile)
include(CopyDir)

set(_DEFAULT_TEST_SUITE_COPY_DATA OFF)
if(TEST_SUITE_REMOTE_HOST)
  set(_DEFAULT_TEST_SUITE_COPY_DATA ON)
endif()
option(TEST_SUITE_COPY_DATA "Always copy benchmark data to builddir"
       ${_DEFAULT_TEST_SUITE_COPY_DATA})
mark_as_advanced(TEST_SUITE_COPY_DATA)

# Copies files and directories to be used as benchmark input data to the
# directory of the benchmark executable.
# Paths are interepreted relative to CMAKE_CURRENT_SOURCE_DIR by default but
# this can be changed with the SOURCE_DIR argument.
# If DEST_SUFFIX is specified, it's appended to the destination file names.
function(llvm_test_data target)
  cmake_parse_arguments(_LTDARGS "MUST_COPY" "SOURCE_DIR;DEST_SUFFIX" "" ${ARGN})
  set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
  if(_LTDARGS_SOURCE_DIR)
    set(SOURCE_DIR ${_LTDARGS_SOURCE_DIR})
  endif()
  set(SUFFIX ${_LTDARGS_DEST_SUFFIX})
  foreach(file ${_LTDARGS_UNPARSED_ARGUMENTS})
    set(full_path ${SOURCE_DIR}/${file})
    if(_LTDARGS_MUST_COPY OR TEST_SUITE_COPY_DATA)
      if(IS_DIRECTORY ${full_path})
        llvm_copy_dir(${target} $<TARGET_FILE_DIR:${target}>/${file}${SUFFIX} ${full_path})
      else()
        llvm_copy(${target} $<TARGET_FILE_DIR:${target}>/${file}${SUFFIX} ${full_path})
      endif()
    else()
      get_filename_component(file_subdir ${file} DIRECTORY)
      if(file_subdir)
        llvm_make_directory(${target} ${file_subdir})
      endif()
      llvm_create_symlink(${target} $<TARGET_FILE_DIR:${target}>/${file}${SUFFIX} ${full_path})
    endif()
  endforeach()
endfunction()

function(llvm_test_executable_no_test target)
  add_executable(${target} ${ARGN})
  append_target_flags(COMPILE_FLAGS ${target} ${CFLAGS})
  append_target_flags(COMPILE_FLAGS ${target} ${CPPFLAGS})
  append_target_flags(COMPILE_FLAGS ${target} ${CXXFLAGS})
  # Note that we cannot use target_link_libraries() here because that one
  # only interprets inputs starting with '-' as flags.
  append_target_flags(LINK_LIBRARIES ${target} ${LDFLAGS})
  set(target_path ${CMAKE_CURRENT_BINARY_DIR}/${target})
  if(TEST_SUITE_PROFILE_USE)
    append_target_flags(COMPILE_FLAGS ${target} -fprofile-instr-use=${target_path}.profdata)
    append_target_flags(LINK_LIBRARIES ${target} -fprofile-instr-use=${target_path}.profdata)
  endif()

  llvm_codesign(${target})
  set_property(GLOBAL APPEND PROPERTY TEST_SUITE_TARGETS ${target})
  test_suite_add_build_dependencies(${target})
endfunction()

# Creates a new executable build target. Use this instead of `add_executable`.
# It applies CFLAGS, CPPFLAGS, CXXFLAGS and LDFLAGS. Creates a .test file if
# necessary, registers the target with the TEST_SUITE_TARGETS list and makes
# sure we build the required dependencies for compiletime measurements
# and support the TEST_SUITE_PROFILE_USE mode.
function(llvm_test_executable target)
  llvm_test_executable_no_test(${target} ${ARGN})
  llvm_add_test_for_target(${target})
  set(TESTSCRIPT "" PARENT_SCOPE)
endfunction()

# Creates a new library build target. Use this instead of `add_library`.
# Behaves like `llvm_test_executable`, just produces a library instead of an
# executable.
function(llvm_test_library target)
  add_library(${target} ${ARGN})

  append_target_flags(COMPILE_FLAGS ${target} ${CFLAGS})
  append_target_flags(COMPILE_FLAGS ${target} ${CPPFLAGS})
  append_target_flags(COMPILE_FLAGS ${target} ${CXXFLAGS})
  # Note that we cannot use target_link_libraries() here because that one
  # only interprets inputs starting with '-' as flags.
  append_target_flags(LINK_LIBRARIES ${target} ${LDFLAGS})

  # TODO: How to support TEST_SUITE_PROFILE_USE properly?

  test_suite_add_build_dependencies(${target})
endfunction()

# Add dependencies required for compiletime measurements to a target. You
# usually do not need to call this directly when using `llvm_test_executable`
# or `llvm_test_library`.
function(test_suite_add_build_dependencies target)
  add_dependencies(${target}
    build-HashProgramOutput.sh
    build-timeit
    build-timeit-target
    build-fpcmp
    build-fpcmp-target
  )
endfunction()

# Internal function that transforms a list of flags to a string and appends
# it to a given property of a target.
function(append_target_flags propertyname target)
  if(NOT "${ARGN}" STREQUAL "")
    get_target_property(old_flags ${target} ${propertyname})
    if(${old_flags} STREQUAL "old_flags-NOTFOUND")
      set(old_flags)
    endif()
    # Transform ${ARGN} which is a cmake list into a series of commandline
    # arguments. This requires some shell quoting (the approach here isn't
    # perfect)
    string(REPLACE " " "\\ " quoted "${ARGN}")
    string(REPLACE "\"" "\\\"" quoted "${quoted}")
    string(REPLACE ";" " " quoted "${quoted}")
    # Ensure that there is no leading or trailing whitespace
    # This is especially important if old_flags is empty and the property
    # is LINK_LIBRARIES, as extra whitespace violates CMP0004
    string(STRIP "${old_flags} ${quoted}" new_flags)
    set_target_properties(${target} PROPERTIES ${propertyname} "${new_flags}")
  endif()
endfunction()

# Usage: llvm_codesign(name [FORCE] [ENTITLEMENTS file] [BUNDLE_PATH path])
function(llvm_codesign name)
  cmake_parse_arguments(ARG "FORCE" "ENTITLEMENTS;BUNDLE_PATH" "" ${ARGN})
  if(NOT LLVM_CODESIGNING_IDENTITY)
    return()
  endif()

  if(CMAKE_GENERATOR STREQUAL "Xcode")
    set_target_properties(${name} PROPERTIES
      XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY ${LLVM_CODESIGNING_IDENTITY}
    )
    if(DEFINED ARG_ENTITLEMENTS)
      set_target_properties(${name} PROPERTIES
        XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS ${ARG_ENTITLEMENTS}
      )
    endif()
  elseif(APPLE AND CMAKE_HOST_SYSTEM_NAME MATCHES Darwin)
    if(NOT CMAKE_CODESIGN)
      set(CMAKE_CODESIGN xcrun codesign)
    endif()
    if(NOT CMAKE_CODESIGN_ALLOCATE)
      execute_process(
        COMMAND xcrun -f codesign_allocate
        OUTPUT_STRIP_TRAILING_WHITESPACE
        OUTPUT_VARIABLE CMAKE_CODESIGN_ALLOCATE
      )
    endif()
    if(DEFINED ARG_ENTITLEMENTS)
      set(pass_entitlements --entitlements ${ARG_ENTITLEMENTS})
    endif()

    if (NOT ARG_BUNDLE_PATH)
      set(ARG_BUNDLE_PATH $<TARGET_FILE:${name}>)
    endif()

    if(ARG_FORCE)
      set(force_flag "-f")
    endif()

    add_custom_command(
      TARGET ${name} POST_BUILD
      COMMAND ${CMAKE_COMMAND} -E
              env CODESIGN_ALLOCATE=${CMAKE_CODESIGN_ALLOCATE}
              ${CMAKE_CODESIGN} -s ${LLVM_CODESIGNING_IDENTITY}
              ${pass_entitlements} ${force_flag} ${ARG_BUNDLE_PATH}
      COMMENT "Codesign ${name}"
    )
  endif()
endfunction()