1include(ExternalProject) 2include(CompilerRTUtils) 3 4# Tries to add an "object library" target for a given list of OSs and/or 5# architectures with name "<name>.<arch>" for non-Darwin platforms if 6# architecture can be targeted, and "<name>.<os>" for Darwin platforms. 7# add_compiler_rt_object_libraries(<name> 8# OS <os names> 9# ARCHS <architectures> 10# SOURCES <source files> 11# CFLAGS <compile flags> 12# DEFS <compile definitions>) 13function(add_compiler_rt_object_libraries name) 14 cmake_parse_arguments(LIB "" "" "OS;ARCHS;SOURCES;CFLAGS;DEFS" ${ARGN}) 15 set(libnames) 16 if(APPLE) 17 foreach(os ${LIB_OS}) 18 set(libname "${name}.${os}") 19 set(libnames ${libnames} ${libname}) 20 set(extra_cflags_${libname} ${DARWIN_${os}_CFLAGS}) 21 list_intersect(LIB_ARCHS_${libname} DARWIN_${os}_ARCHS LIB_ARCHS) 22 endforeach() 23 else() 24 foreach(arch ${LIB_ARCHS}) 25 set(libname "${name}.${arch}") 26 set(libnames ${libnames} ${libname}) 27 set(extra_cflags_${libname} ${TARGET_${arch}_CFLAGS}) 28 if(NOT CAN_TARGET_${arch}) 29 message(FATAL_ERROR "Architecture ${arch} can't be targeted") 30 return() 31 endif() 32 endforeach() 33 endif() 34 35 foreach(libname ${libnames}) 36 add_library(${libname} OBJECT ${LIB_SOURCES}) 37 set_target_compile_flags(${libname} 38 ${CMAKE_CXX_FLAGS} ${extra_cflags_${libname}} ${LIB_CFLAGS}) 39 set_property(TARGET ${libname} APPEND PROPERTY 40 COMPILE_DEFINITIONS ${LIB_DEFS}) 41 if(APPLE) 42 set_target_properties(${libname} PROPERTIES 43 OSX_ARCHITECTURES "${LIB_ARCHS_${libname}}") 44 endif() 45 endforeach() 46endfunction() 47 48# Takes a list of object library targets, and a suffix and appends the proper 49# TARGET_OBJECTS string to the output variable. 50# format_object_libs(<output> <suffix> ...) 51macro(format_object_libs output suffix) 52 foreach(lib ${ARGN}) 53 list(APPEND ${output} $<TARGET_OBJECTS:${lib}.${suffix}>) 54 endforeach() 55endmacro() 56 57# Adds static or shared runtime for a list of architectures and operating 58# systems and puts it in the proper directory in the build and install trees. 59# add_compiler_rt_runtime(<name> 60# {STATIC|SHARED} 61# ARCHS <architectures> 62# OS <os list> 63# SOURCES <source files> 64# CFLAGS <compile flags> 65# LINKFLAGS <linker flags> 66# DEFS <compile definitions> 67# LINK_LIBS <linked libraries> (only for shared library) 68# OBJECT_LIBS <object libraries to use as sources> 69# PARENT_TARGET <convenience parent target>) 70function(add_compiler_rt_runtime name type) 71 if(NOT type MATCHES "^(STATIC|SHARED)$") 72 message(FATAL_ERROR "type argument must be STATIC or SHARED") 73 return() 74 endif() 75 cmake_parse_arguments(LIB 76 "" 77 "PARENT_TARGET" 78 "OS;ARCHS;SOURCES;CFLAGS;LINKFLAGS;DEFS;LINK_LIBS;OBJECT_LIBS" 79 ${ARGN}) 80 set(libnames) 81 if(APPLE) 82 foreach(os ${LIB_OS}) 83 if(type STREQUAL "STATIC") 84 set(libname "${name}_${os}") 85 else() 86 set(libname "${name}_${os}_dynamic") 87 set(extra_linkflags_${libname} ${DARWIN_${os}_LINKFLAGS} ${LIB_LINKFLAGS}) 88 endif() 89 list_intersect(LIB_ARCHS_${libname} DARWIN_${os}_ARCHS LIB_ARCHS) 90 if(LIB_ARCHS_${libname}) 91 list(APPEND libnames ${libname}) 92 set(extra_cflags_${libname} ${DARWIN_${os}_CFLAGS} ${LIB_CFLAGS}) 93 set(output_name_${libname} ${libname}${COMPILER_RT_OS_SUFFIX}) 94 set(sources_${libname} ${LIB_SOURCES}) 95 format_object_libs(sources_${libname} ${os} ${LIB_OBJECT_LIBS}) 96 endif() 97 endforeach() 98 else() 99 foreach(arch ${LIB_ARCHS}) 100 if(NOT CAN_TARGET_${arch}) 101 message(FATAL_ERROR "Architecture ${arch} can't be targeted") 102 return() 103 endif() 104 if(type STREQUAL "STATIC") 105 set(libname "${name}-${arch}") 106 set(output_name_${libname} ${libname}${COMPILER_RT_OS_SUFFIX}) 107 else() 108 set(libname "${name}-dynamic-${arch}") 109 set(extra_linkflags_${libname} ${TARGET_${arch}_CFLAGS} ${LIB_CFLAGS} ${LIB_LINKFLAGS}) 110 if(WIN32) 111 set(output_name_${libname} ${name}_dynamic-${arch}${COMPILER_RT_OS_SUFFIX}) 112 else() 113 set(output_name_${libname} ${name}-${arch}${COMPILER_RT_OS_SUFFIX}) 114 endif() 115 endif() 116 set(sources_${libname} ${LIB_SOURCES}) 117 format_object_libs(sources_${libname} ${arch} ${LIB_OBJECT_LIBS}) 118 set(libnames ${libnames} ${libname}) 119 set(extra_cflags_${libname} ${TARGET_${arch}_CFLAGS} ${LIB_CFLAGS}) 120 endforeach() 121 endif() 122 123 if(NOT libnames) 124 return() 125 endif() 126 127 if(LIB_PARENT_TARGET) 128 # If the parent targets aren't created we should create them 129 if(NOT TARGET ${LIB_PARENT_TARGET}) 130 add_custom_target(${LIB_PARENT_TARGET}) 131 endif() 132 if(NOT TARGET install-${LIB_PARENT_TARGET}) 133 # The parent install target specifies the parent component to scrape up 134 # anything not installed by the individual install targets, and to handle 135 # installation when running the multi-configuration generators. 136 add_custom_target(install-${LIB_PARENT_TARGET} 137 DEPENDS ${LIB_PARENT_TARGET} 138 COMMAND "${CMAKE_COMMAND}" 139 -DCMAKE_INSTALL_COMPONENT=${LIB_PARENT_TARGET} 140 -P "${CMAKE_BINARY_DIR}/cmake_install.cmake") 141 endif() 142 endif() 143 144 foreach(libname ${libnames}) 145 # If you have are using a multi-configuration generator we don't generate 146 # per-library install rules, so we fall back to the parent target COMPONENT 147 if(CMAKE_CONFIGURATION_TYPES AND LIB_PARENT_TARGET) 148 set(COMPONENT_OPTION COMPONENT ${LIB_PARENT_TARGET}) 149 else() 150 set(COMPONENT_OPTION COMPONENT ${libname}) 151 endif() 152 153 add_library(${libname} ${type} ${sources_${libname}}) 154 set_target_compile_flags(${libname} ${extra_cflags_${libname}}) 155 set_target_link_flags(${libname} ${extra_linkflags_${libname}}) 156 set_property(TARGET ${libname} APPEND PROPERTY 157 COMPILE_DEFINITIONS ${LIB_DEFS}) 158 159 # For RUNTIME_OUTPUT_DIRECTORY variable, Multi-configuration generators 160 # append a per-configuration subdirectory to the specified directory. 161 # To avoid the appended folder, the configuration specific variable must be 162 # set 'RUNTIME_OUTPUT_DIRECTORY_${CONF}': 163 # RUNTIME_OUTPUT_DIRECTORY_DEBUG, RUNTIME_OUTPUT_DIRECTORY_RELEASE, ... 164 if(CMAKE_CONFIGURATION_TYPES) 165 foreach(build_mode ${CMAKE_CONFIGURATION_TYPES}) 166 string(TOUPPER "${build_mode}" CONFIG_SUFFIX) 167 set_target_properties(${libname} PROPERTIES 168 "ARCHIVE_OUTPUT_DIRECTORY_${CONFIG_SUFFIX}" ${COMPILER_RT_LIBRARY_OUTPUT_DIR} 169 "LIBRARY_OUTPUT_DIRECTORY_${CONFIG_SUFFIX}" ${COMPILER_RT_LIBRARY_OUTPUT_DIR} 170 "RUNTIME_OUTPUT_DIRECTORY_${CONFIG_SUFFIX}" ${COMPILER_RT_LIBRARY_OUTPUT_DIR}) 171 endforeach() 172 else() 173 set_target_properties(${libname} PROPERTIES 174 ARCHIVE_OUTPUT_DIRECTORY ${COMPILER_RT_LIBRARY_OUTPUT_DIR} 175 LIBRARY_OUTPUT_DIRECTORY ${COMPILER_RT_LIBRARY_OUTPUT_DIR} 176 RUNTIME_OUTPUT_DIRECTORY ${COMPILER_RT_LIBRARY_OUTPUT_DIR}) 177 endif() 178 179 set_target_properties(${libname} PROPERTIES 180 OUTPUT_NAME ${output_name_${libname}}) 181 if(LIB_LINK_LIBS AND ${type} STREQUAL "SHARED") 182 target_link_libraries(${libname} ${LIB_LINK_LIBS}) 183 endif() 184 install(TARGETS ${libname} 185 ARCHIVE DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR} 186 ${COMPONENT_OPTION} 187 LIBRARY DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR} 188 ${COMPONENT_OPTION} 189 RUNTIME DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR} 190 ${COMPONENT_OPTION}) 191 192 # We only want to generate per-library install targets if you aren't using 193 # an IDE because the extra targets get cluttered in IDEs. 194 if(NOT CMAKE_CONFIGURATION_TYPES) 195 add_custom_target(install-${libname} 196 DEPENDS ${libname} 197 COMMAND "${CMAKE_COMMAND}" 198 -DCMAKE_INSTALL_COMPONENT=${libname} 199 -P "${CMAKE_BINARY_DIR}/cmake_install.cmake") 200 # If you have a parent target specified, we bind the new install target 201 # to the parent install target. 202 if(LIB_PARENT_TARGET) 203 add_dependencies(install-${LIB_PARENT_TARGET} install-${libname}) 204 endif() 205 endif() 206 if(APPLE) 207 set_target_properties(${libname} PROPERTIES 208 OSX_ARCHITECTURES "${LIB_ARCHS_${libname}}") 209 endif() 210 211 if(type STREQUAL "SHARED") 212 rt_externalize_debuginfo(${libname}) 213 endif() 214 endforeach() 215 if(LIB_PARENT_TARGET) 216 add_dependencies(${LIB_PARENT_TARGET} ${libnames}) 217 endif() 218endfunction() 219 220# when cross compiling, COMPILER_RT_TEST_COMPILER_CFLAGS help 221# in compilation and linking of unittests. 222string(REPLACE " " ";" COMPILER_RT_UNITTEST_CFLAGS "${COMPILER_RT_TEST_COMPILER_CFLAGS}") 223set(COMPILER_RT_UNITTEST_LINKFLAGS ${COMPILER_RT_UNITTEST_CFLAGS}) 224 225# Unittests support. 226set(COMPILER_RT_GTEST_PATH ${LLVM_MAIN_SRC_DIR}/utils/unittest/googletest) 227set(COMPILER_RT_GTEST_SOURCE ${COMPILER_RT_GTEST_PATH}/src/gtest-all.cc) 228set(COMPILER_RT_GTEST_CFLAGS 229 -DGTEST_NO_LLVM_RAW_OSTREAM=1 230 -DGTEST_HAS_RTTI=0 231 -I${COMPILER_RT_GTEST_PATH}/include 232 -I${COMPILER_RT_GTEST_PATH} 233) 234 235append_list_if(COMPILER_RT_DEBUG -DSANITIZER_DEBUG=1 COMPILER_RT_UNITTEST_CFLAGS) 236 237if(MSVC) 238 # clang doesn't support exceptions on Windows yet. 239 list(APPEND COMPILER_RT_UNITTEST_CFLAGS -D_HAS_EXCEPTIONS=0) 240 241 # We should teach clang to understand "#pragma intrinsic", see PR19898. 242 list(APPEND COMPILER_RT_UNITTEST_CFLAGS -Wno-undefined-inline) 243 244 # Clang doesn't support SEH on Windows yet. 245 list(APPEND COMPILER_RT_GTEST_CFLAGS -DGTEST_HAS_SEH=0) 246 247 # gtest use a lot of stuff marked as deprecated on Windows. 248 list(APPEND COMPILER_RT_GTEST_CFLAGS -Wno-deprecated-declarations) 249 250 # Visual Studio 2012 only supports up to 8 template parameters in 251 # std::tr1::tuple by default, but gtest requires 10 252 if(MSVC_VERSION EQUAL 1700) 253 list(APPEND COMPILER_RT_GTEST_CFLAGS -D_VARIADIC_MAX=10) 254 endif() 255endif() 256 257# Link objects into a single executable with COMPILER_RT_TEST_COMPILER, 258# using specified link flags. Make executable a part of provided 259# test_suite. 260# add_compiler_rt_test(<test_suite> <test_name> 261# SUBDIR <subdirectory for binary> 262# OBJECTS <object files> 263# DEPS <deps (e.g. runtime libs)> 264# LINK_FLAGS <link flags>) 265macro(add_compiler_rt_test test_suite test_name) 266 cmake_parse_arguments(TEST "" "SUBDIR" "OBJECTS;DEPS;LINK_FLAGS" "" ${ARGN}) 267 set(output_bin ${CMAKE_CURRENT_BINARY_DIR}) 268 if(TEST_SUBDIR) 269 set(output_bin "${output_bin}/${TEST_SUBDIR}") 270 endif() 271 if(CMAKE_CONFIGURATION_TYPES) 272 set(output_bin "${output_bin}/${CMAKE_CFG_INTDIR}") 273 endif() 274 set(output_bin "${output_bin}/${test_name}") 275 if(MSVC) 276 set(output_bin "${output_bin}.exe") 277 endif() 278 279 # Use host compiler in a standalone build, and just-built Clang otherwise. 280 if(NOT COMPILER_RT_STANDALONE_BUILD) 281 list(APPEND TEST_DEPS clang) 282 endif() 283 # If we're not on MSVC, include the linker flags from CMAKE but override them 284 # with the provided link flags. This ensures that flags which are required to 285 # link programs at all are included, but the changes needed for the test 286 # trump. With MSVC we can't do that because CMake is set up to run link.exe 287 # when linking, not the compiler. Here, we hack it to use the compiler 288 # because we want to use -fsanitize flags. 289 if(NOT MSVC) 290 set(TEST_LINK_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${TEST_LINK_FLAGS}") 291 separate_arguments(TEST_LINK_FLAGS) 292 endif() 293 add_custom_target(${test_name} 294 COMMAND ${COMPILER_RT_TEST_COMPILER} ${TEST_OBJECTS} 295 -o "${output_bin}" 296 ${TEST_LINK_FLAGS} 297 DEPENDS ${TEST_DEPS}) 298 # Make the test suite depend on the binary. 299 add_dependencies(${test_suite} ${test_name}) 300endmacro() 301 302macro(add_compiler_rt_resource_file target_name file_name component) 303 set(src_file "${CMAKE_CURRENT_SOURCE_DIR}/${file_name}") 304 set(dst_file "${COMPILER_RT_OUTPUT_DIR}/${file_name}") 305 add_custom_command(OUTPUT ${dst_file} 306 DEPENDS ${src_file} 307 COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src_file} ${dst_file} 308 COMMENT "Copying ${file_name}...") 309 add_custom_target(${target_name} DEPENDS ${dst_file}) 310 # Install in Clang resource directory. 311 install(FILES ${file_name} 312 DESTINATION ${COMPILER_RT_INSTALL_PATH} 313 COMPONENT ${component}) 314 add_dependencies(${component} ${target_name}) 315endmacro() 316 317macro(add_compiler_rt_script name) 318 set(dst ${COMPILER_RT_EXEC_OUTPUT_DIR}/${name}) 319 set(src ${CMAKE_CURRENT_SOURCE_DIR}/${name}) 320 add_custom_command(OUTPUT ${dst} 321 DEPENDS ${src} 322 COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src} ${dst} 323 COMMENT "Copying ${name}...") 324 add_custom_target(${name} DEPENDS ${dst}) 325 install(FILES ${dst} 326 PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE 327 DESTINATION ${COMPILER_RT_INSTALL_PATH}/bin) 328endmacro(add_compiler_rt_script src name) 329 330# Builds custom version of libc++ and installs it in <prefix>. 331# Can be used to build sanitized versions of libc++ for running unit tests. 332# add_custom_libcxx(<name> <prefix> 333# DEPS <list of build deps> 334# CFLAGS <list of compile flags>) 335macro(add_custom_libcxx name prefix) 336 if(NOT COMPILER_RT_HAS_LIBCXX_SOURCES) 337 message(FATAL_ERROR "libcxx not found!") 338 endif() 339 340 cmake_parse_arguments(LIBCXX "" "" "DEPS;CFLAGS" ${ARGN}) 341 foreach(flag ${LIBCXX_CFLAGS}) 342 set(flagstr "${flagstr} ${flag}") 343 endforeach() 344 set(LIBCXX_CFLAGS ${flagstr}) 345 346 if(NOT COMPILER_RT_STANDALONE_BUILD) 347 list(APPEND LIBCXX_DEPS clang) 348 endif() 349 350 ExternalProject_Add(${name} 351 PREFIX ${prefix} 352 SOURCE_DIR ${COMPILER_RT_LIBCXX_PATH} 353 CMAKE_ARGS -DCMAKE_MAKE_PROGRAM:STRING=${CMAKE_MAKE_PROGRAM} 354 -DCMAKE_C_COMPILER=${COMPILER_RT_TEST_COMPILER} 355 -DCMAKE_CXX_COMPILER=${COMPILER_RT_TEST_CXX_COMPILER} 356 -DCMAKE_C_FLAGS=${LIBCXX_CFLAGS} 357 -DCMAKE_CXX_FLAGS=${LIBCXX_CFLAGS} 358 -DCMAKE_BUILD_TYPE=Release 359 -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> 360 -DLLVM_PATH=${LLVM_MAIN_SRC_DIR} 361 LOG_BUILD 1 362 LOG_CONFIGURE 1 363 LOG_INSTALL 1 364 ) 365 set_target_properties(${name} PROPERTIES EXCLUDE_FROM_ALL TRUE) 366 367 ExternalProject_Add_Step(${name} force-reconfigure 368 DEPENDERS configure 369 ALWAYS 1 370 ) 371 372 ExternalProject_Add_Step(${name} clobber 373 COMMAND ${CMAKE_COMMAND} -E remove_directory <BINARY_DIR> 374 COMMAND ${CMAKE_COMMAND} -E make_directory <BINARY_DIR> 375 COMMENT "Clobberring ${name} build directory..." 376 DEPENDERS configure 377 DEPENDS ${LIBCXX_DEPS} 378 ) 379endmacro() 380 381function(rt_externalize_debuginfo name) 382 if(NOT COMPILER_RT_EXTERNALIZE_DEBUGINFO) 383 return() 384 endif() 385 386 if(NOT COMPILER_RT_EXTERNALIZE_DEBUGINFO_SKIP_STRIP) 387 set(strip_command COMMAND xcrun strip -Sl $<TARGET_FILE:${name}>) 388 endif() 389 390 if(APPLE) 391 if(CMAKE_CXX_FLAGS MATCHES "-flto" 392 OR CMAKE_CXX_FLAGS_${uppercase_CMAKE_BUILD_TYPE} MATCHES "-flto") 393 394 set(lto_object ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${name}-lto.o) 395 set_property(TARGET ${name} APPEND_STRING PROPERTY 396 LINK_FLAGS " -Wl,-object_path_lto -Wl,${lto_object}") 397 endif() 398 add_custom_command(TARGET ${name} POST_BUILD 399 COMMAND xcrun dsymutil $<TARGET_FILE:${name}> 400 ${strip_command}) 401 else() 402 message(FATAL_ERROR "COMPILER_RT_EXTERNALIZE_DEBUGINFO isn't implemented for non-darwin platforms!") 403 endif() 404endfunction() 405