reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    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
# On Windows, CMAKE_*_FLAGS are built for MSVC but we use the GCC clang.exe,
# which uses completely different flags. Translate some common flag types, and
# drop the rest.
function(translate_msvc_cflags out_flags msvc_flags)
  # Insert an empty string in the list to simplify processing.
  set(msvc_flags ";${msvc_flags}")

  # Canonicalize /flag to -flag.
  string(REPLACE ";/" ";-" msvc_flags "${msvc_flags}")

  # Make space separated -D and -U flags into joined flags.
  string(REGEX REPLACE ";-\([DU]\);" ";-\\1" msvc_flags "${msvc_flags}")

  set(clang_flags "")
  foreach(flag ${msvc_flags})
    if ("${flag}" MATCHES "^-[DU]")
      # Pass through basic command line macro definitions (-DNDEBUG).
      list(APPEND clang_flags "${flag}")
    elseif ("${flag}" MATCHES "^-O[2x]")
      # Canonicalize normal optimization flags to -O2.
      list(APPEND clang_flags "-O2")
    endif()
  endforeach()
  set(${out_flags} "${clang_flags}" PARENT_SCOPE)
endfunction()

# Compile a sanitizer test with a freshly built clang
# for a given architecture, adding the result to the object list.
#  - obj_list: output list of objects, populated by path
#              of a generated object file.
#  - source:   source file of a test.
#  - arch:     architecture to compile for.
# sanitizer_test_compile(<obj_list> <source> <arch>
#                        KIND <custom namespace>
#                        COMPILE_DEPS <list of compile-time dependencies>
#                        DEPS <list of dependencies>
#                        CFLAGS <list of flags>
# )
function(sanitizer_test_compile obj_list source arch)
  cmake_parse_arguments(TEST
      "" "" "KIND;COMPILE_DEPS;DEPS;CFLAGS" ${ARGN})
  get_filename_component(basename ${source} NAME)
  set(output_obj
    "${CMAKE_CFG_RESOLVED_INTDIR}${obj_list}.${basename}.${arch}${TEST_KIND}.o")

  # Write out architecture-specific flags into TARGET_CFLAGS variable.
  get_target_flags_for_arch(${arch} TARGET_CFLAGS)
  set(COMPILE_DEPS ${TEST_COMPILE_DEPS})
  if(NOT COMPILER_RT_STANDALONE_BUILD)
    list(APPEND COMPILE_DEPS ${TEST_DEPS})
  endif()
  clang_compile(${output_obj} ${source}
                CFLAGS ${TEST_CFLAGS} ${TARGET_CFLAGS}
                DEPS ${COMPILE_DEPS})
  list(APPEND ${obj_list} ${output_obj})
  set("${obj_list}" "${${obj_list}}" PARENT_SCOPE)
endfunction()

# Compile a source into an object file with COMPILER_RT_TEST_COMPILER using
# a provided compile flags and dependenices.
# clang_compile(<object> <source>
#               CFLAGS <list of compile flags>
#               DEPS <list of dependencies>)
function(clang_compile object_file source)
  cmake_parse_arguments(SOURCE "" "" "CFLAGS;DEPS" ${ARGN})
  get_filename_component(source_rpath ${source} REALPATH)
  if(NOT COMPILER_RT_STANDALONE_BUILD)
    list(APPEND SOURCE_DEPS clang compiler-rt-headers)
  endif()
  if (TARGET CompilerRTUnitTestCheckCxx)
    list(APPEND SOURCE_DEPS CompilerRTUnitTestCheckCxx)
  endif()
  string(REGEX MATCH "[.](cc|cpp)$" is_cxx ${source_rpath})
  string(REGEX MATCH "[.](m|mm)$" is_objc ${source_rpath})
  if(is_cxx)
    string(REPLACE " " ";" global_flags "${CMAKE_CXX_FLAGS}")
  else()
    string(REPLACE " " ";" global_flags "${CMAKE_C_FLAGS}")
  endif()

  if (MSVC)
    translate_msvc_cflags(global_flags "${global_flags}")
  endif()

  if (APPLE)
    set(global_flags ${OSX_SYSROOT_FLAG} ${global_flags})
  endif()
  if (is_objc)
    list(APPEND global_flags -ObjC)
  endif()

  # Ignore unknown warnings. CMAKE_CXX_FLAGS may contain GCC-specific options
  # which are not supported by Clang.
  list(APPEND global_flags -Wno-unknown-warning-option)
  set(compile_flags ${global_flags} ${SOURCE_CFLAGS})
  add_custom_command(
    OUTPUT ${object_file}
    COMMAND ${COMPILER_RT_TEST_COMPILER} ${compile_flags} -c
            -o "${object_file}"
            ${source_rpath}
    MAIN_DEPENDENCY ${source}
    DEPENDS ${SOURCE_DEPS})
endfunction()

# On Darwin, there are no system-wide C++ headers and the just-built clang is
# therefore not able to compile C++ files unless they are copied/symlinked into
# ${LLVM_BINARY_DIR}/include/c++
# The just-built clang is used to build compiler-rt unit tests. Let's detect
# this before we try to build the tests and print out a suggestion how to fix
# it.
# On other platforms, this is currently not an issue.
macro(clang_compiler_add_cxx_check)
  if (APPLE)
    set(CMD
      "echo '#include <iostream>' | ${COMPILER_RT_TEST_COMPILER} ${OSX_SYSROOT_FLAG} -E -x c++ - > /dev/null"
      "if [ $? != 0 ] "
      "  then echo"
      "  echo 'Your just-built clang cannot find C++ headers, which are needed to build and run compiler-rt tests.'"
      "  echo 'You should copy or symlink your system C++ headers into ${LLVM_BINARY_DIR}/include/c++'"
      "  if [ -d $(dirname $(dirname $(xcrun -f clang)))/include/c++ ]"
      "    then echo 'e.g. with:'"
      "    echo '  cp -r' $(dirname $(dirname $(xcrun -f clang)))/include/c++ '${LLVM_BINARY_DIR}/include/'"
      "  elif [ -d $(dirname $(dirname $(xcrun -f clang)))/lib/c++ ]"
      "    then echo 'e.g. with:'"
      "    echo '  cp -r' $(dirname $(dirname $(xcrun -f clang)))/lib/c++ '${LLVM_BINARY_DIR}/include/'"
      "  fi"
      "  echo 'This can also be fixed by checking out the libcxx project from llvm.org and installing the headers'"
      "  echo 'into your build directory:'"
      "  echo '  cd ${LLVM_MAIN_SRC_DIR}/projects && svn co http://llvm.org/svn/llvm-project/libcxx/trunk libcxx'"
      "  echo '  cd ${LLVM_BINARY_DIR} && make -C ${LLVM_MAIN_SRC_DIR}/projects/libcxx installheaders HEADER_DIR=${LLVM_BINARY_DIR}/include'"
      "  echo"
      "  false"
      "fi"
      )
    add_custom_target(CompilerRTUnitTestCheckCxx
      COMMAND bash -c "${CMD}"
      COMMENT "Checking that just-built clang can find C++ headers..."
      VERBATIM)
    if (NOT COMPILER_RT_STANDALONE_BUILD AND NOT RUNTIMES_BUILD)
      ADD_DEPENDENCIES(CompilerRTUnitTestCheckCxx clang)
    endif()
  endif()
endmacro()