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