CMakeLists.txt raw

   1  # Copyright 2017 The CRC32C Authors. All rights reserved.
   2  # Use of this source code is governed by a BSD-style license that can be
   3  # found in the LICENSE file. See the AUTHORS file for names of contributors.
   4  
   5  cmake_minimum_required(VERSION 3.1)
   6  project(Crc32c VERSION 1.1.0 LANGUAGES C CXX)
   7  
   8  # C standard can be overridden when this is used as a sub-project.
   9  if(NOT CMAKE_C_STANDARD)
  10    # This project can use C11, but will gracefully decay down to C89.
  11    set(CMAKE_C_STANDARD 11)
  12    set(CMAKE_C_STANDARD_REQUIRED OFF)
  13    set(CMAKE_C_EXTENSIONS OFF)
  14  endif(NOT CMAKE_C_STANDARD)
  15  
  16  # C++ standard can be overridden when this is used as a sub-project.
  17  if(NOT CMAKE_CXX_STANDARD)
  18    # This project requires C++11.
  19    set(CMAKE_CXX_STANDARD 11)
  20    set(CMAKE_CXX_STANDARD_REQUIRED ON)
  21    set(CMAKE_CXX_EXTENSIONS OFF)
  22  endif(NOT CMAKE_CXX_STANDARD)
  23  
  24  # https://github.com/izenecloud/cmake/blob/master/SetCompilerWarningAll.cmake
  25  if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
  26    # Use the highest warning level for Visual Studio.
  27    set(CMAKE_CXX_WARNING_LEVEL 4)
  28    if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
  29      string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
  30    else(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
  31      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
  32    endif(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
  33  
  34    # Disable C++ exceptions.
  35    string(REGEX REPLACE "/EH[a-z]+" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
  36    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHs-c-")
  37    add_definitions(-D_HAS_EXCEPTIONS=0)
  38  
  39    # Disable RTTI.
  40    string(REGEX REPLACE "/GR" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
  41    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GR-")
  42  else(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
  43    # Use -Wall for clang and gcc.
  44    if(NOT CMAKE_CXX_FLAGS MATCHES "-Wall")
  45      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
  46    endif(NOT CMAKE_CXX_FLAGS MATCHES "-Wall")
  47  
  48    # Use -Wextra for clang and gcc.
  49    if(NOT CMAKE_CXX_FLAGS MATCHES "-Wextra")
  50      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra")
  51    endif(NOT CMAKE_CXX_FLAGS MATCHES "-Wextra")
  52  
  53    # Use -Werror for clang and gcc.
  54    if(NOT CMAKE_CXX_FLAGS MATCHES "-Werror")
  55      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
  56    endif(NOT CMAKE_CXX_FLAGS MATCHES "-Werror")
  57  
  58    # Disable C++ exceptions.
  59    string(REGEX REPLACE "-fexceptions" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
  60    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")
  61  
  62    # Disable RTTI.
  63    string(REGEX REPLACE "-frtti" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
  64    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
  65  endif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
  66  
  67  option(CRC32C_BUILD_TESTS "Build CRC32C's unit tests" ON)
  68  option(CRC32C_BUILD_BENCHMARKS "Build CRC32C's benchmarks" ON)
  69  option(CRC32C_USE_GLOG "Build CRC32C's tests with Google Logging" ON)
  70  option(CRC32C_INSTALL "Install CRC32C's header and library" ON)
  71  
  72  include(TestBigEndian)
  73  test_big_endian(BYTE_ORDER_BIG_ENDIAN)
  74  
  75  include(CheckCXXCompilerFlag)
  76  # Used by glog.
  77  check_cxx_compiler_flag(-Wno-deprecated CRC32C_HAVE_NO_DEPRECATED)
  78  # Used by glog.
  79  check_cxx_compiler_flag(-Wno-sign-compare CRC32C_HAVE_NO_SIGN_COMPARE)
  80  # Used by glog.
  81  check_cxx_compiler_flag(-Wno-unused-parameter CRC32C_HAVE_NO_UNUSED_PARAMETER)
  82  # Used by googletest.
  83  check_cxx_compiler_flag(-Wno-missing-field-initializers
  84                          CRC32C_HAVE_NO_MISSING_FIELD_INITIALIZERS)
  85  
  86  # Check for __builtin_prefetch support in the compiler.
  87  include(CheckCXXSourceCompiles)
  88  check_cxx_source_compiles("
  89  int main() {
  90    char data = 0;
  91    const char* address = &data;
  92    __builtin_prefetch(address, 0, 0);
  93    return 0;
  94  }
  95  "  HAVE_BUILTIN_PREFETCH)
  96  
  97  # Check for _mm_prefetch support in the compiler.
  98  include(CheckCXXSourceCompiles)
  99  check_cxx_source_compiles("
 100  #if defined(_MSC_VER)
 101  #include <intrin.h>
 102  #else  // !defined(_MSC_VER)
 103  #include <xmmintrin.h>
 104  #endif  // defined(_MSC_VER)
 105  
 106  int main() {
 107    char data = 0;
 108    const char* address = &data;
 109    _mm_prefetch(address, _MM_HINT_NTA);
 110    return 0;
 111  }
 112  "  HAVE_MM_PREFETCH)
 113  
 114  # Check for SSE4.2 support in the compiler.
 115  set(OLD_CMAKE_REQURED_FLAGS ${CMAKE_REQUIRED_FLAGS})
 116  if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
 117    set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} /arch:AVX")
 118  else(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
 119    set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -msse4.2")
 120  endif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
 121  check_cxx_source_compiles("
 122  #if defined(_MSC_VER)
 123  #include <intrin.h>
 124  #else  // !defined(_MSC_VER)
 125  #include <cpuid.h>
 126  #include <nmmintrin.h>
 127  #endif  // defined(_MSC_VER)
 128  
 129  int main() {
 130    _mm_crc32_u8(0, 0); _mm_crc32_u32(0, 0);
 131  #if defined(_M_X64) || defined(__x86_64__)
 132     _mm_crc32_u64(0, 0);
 133  #endif // defined(_M_X64) || defined(__x86_64__)
 134    return 0;
 135  }
 136  "  HAVE_SSE42)
 137  set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQURED_FLAGS})
 138  
 139  # Check for ARMv8 w/ CRC and CRYPTO extensions support in the compiler.
 140  set(OLD_CMAKE_REQURED_FLAGS ${CMAKE_REQUIRED_FLAGS})
 141  if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
 142    # TODO(pwnall): Insert correct flag when VS gets ARM CRC32C support.
 143    set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} /arch:NOTYET")
 144  else(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
 145    set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -march=armv8-a+crc+crypto")
 146  endif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
 147  check_cxx_source_compiles("
 148  #include <arm_acle.h>
 149  #include <arm_neon.h>
 150  
 151  int main() {
 152    __crc32cb(0, 0); __crc32ch(0, 0); __crc32cw(0, 0); __crc32cd(0, 0);
 153    vmull_p64(0, 0);
 154    return 0;
 155  }
 156  " HAVE_ARM64_CRC32C)
 157  set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQURED_FLAGS})
 158  
 159  # Check for strong getauxval() support in the system headers.
 160  check_cxx_source_compiles("
 161  #include <arm_acle.h>
 162  #include <arm_neon.h>
 163  #include <sys/auxv.h>
 164  
 165  int main() {
 166    getauxval(AT_HWCAP);
 167    return 0;
 168  }
 169  " HAVE_STRONG_GETAUXVAL)
 170  
 171  # Check for weak getauxval() support in the compiler.
 172  check_cxx_source_compiles("
 173  unsigned long getauxval(unsigned long type) __attribute__((weak));
 174  #define AT_HWCAP 16
 175  
 176  int main() {
 177    getauxval(AT_HWCAP);
 178    return 0;
 179  }
 180  " HAVE_WEAK_GETAUXVAL)
 181  
 182  if(CRC32C_USE_GLOG)
 183    # glog requires this setting to avoid using dynamic_cast.
 184    set(DISABLE_RTTI ON CACHE BOOL "" FORCE)
 185  
 186    # glog's test targets trigger deprecation warnings, and compiling them burns
 187    # CPU cycles on the CI.
 188    set(BUILD_TESTING_SAVED "${BUILD_TESTING}")
 189    set(BUILD_TESTING OFF CACHE BOOL "" FORCE)
 190    add_subdirectory("third_party/glog" EXCLUDE_FROM_ALL)
 191    set(BUILD_TESTING "${BUILD_TESTING_SAVED}" CACHE BOOL "" FORCE)
 192  
 193    # glog triggers deprecation warnings on OSX.
 194    # https://github.com/google/glog/issues/185
 195    if(CRC32C_HAVE_NO_DEPRECATED)
 196      set_property(TARGET glog APPEND PROPERTY COMPILE_OPTIONS -Wno-deprecated)
 197    endif(CRC32C_HAVE_NO_DEPRECATED)
 198  
 199    # glog triggers sign comparison warnings on gcc.
 200    if(CRC32C_HAVE_NO_SIGN_COMPARE)
 201      set_property(TARGET glog APPEND PROPERTY COMPILE_OPTIONS -Wno-sign-compare)
 202    endif(CRC32C_HAVE_NO_SIGN_COMPARE)
 203  
 204    # glog triggers unused parameter warnings on clang.
 205    if(CRC32C_HAVE_NO_UNUSED_PARAMETER)
 206      set_property(TARGET glog
 207                   APPEND PROPERTY COMPILE_OPTIONS -Wno-unused-parameter)
 208    endif(CRC32C_HAVE_NO_UNUSED_PARAMETER)
 209  
 210    set(CRC32C_TESTS_BUILT_WITH_GLOG 1)
 211  endif(CRC32C_USE_GLOG)
 212  
 213  configure_file(
 214    "src/crc32c_config.h.in"
 215    "${PROJECT_BINARY_DIR}/include/crc32c/crc32c_config.h"
 216  )
 217  
 218  include_directories("${PROJECT_BINARY_DIR}/include")
 219  
 220  # ARM64 CRC32C code is built separately, so we don't accidentally compile
 221  # unsupported instructions into code that gets run without ARM32 support.
 222  add_library(crc32c_arm64 OBJECT "")
 223  target_sources(crc32c_arm64
 224    PRIVATE
 225      "${PROJECT_BINARY_DIR}/include/crc32c/crc32c_config.h"
 226      "src/crc32c_arm64.cc"
 227      "src/crc32c_arm64.h"
 228  )
 229  if(HAVE_ARM64_CRC32C)
 230    if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
 231      # TODO(pwnall): Insert correct flag when VS gets ARM64 CRC32C support.
 232      target_compile_options(crc32c_arm64 PRIVATE "/arch:NOTYET")
 233    else(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
 234      target_compile_options(crc32c_arm64 PRIVATE "-march=armv8-a+crc+crypto")
 235    endif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
 236  endif(HAVE_ARM64_CRC32C)
 237  
 238  # CMake only enables PIC by default in SHARED and MODULE targets.
 239  if(BUILD_SHARED_LIBS)
 240    set_property(TARGET crc32c_arm64 PROPERTY POSITION_INDEPENDENT_CODE TRUE)
 241  endif(BUILD_SHARED_LIBS)
 242  
 243  # SSE4.2 code is built separately, so we don't accidentally compile unsupported
 244  # instructions into code that gets run without SSE4.2 support.
 245  add_library(crc32c_sse42 OBJECT "")
 246  target_sources(crc32c_sse42
 247    PRIVATE
 248      "${PROJECT_BINARY_DIR}/include/crc32c/crc32c_config.h"
 249      "src/crc32c_sse42.cc"
 250      "src/crc32c_sse42.h"
 251  )
 252  if(HAVE_SSE42)
 253    if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
 254      target_compile_options(crc32c_sse42 PRIVATE "/arch:AVX")
 255    else(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
 256      target_compile_options(crc32c_sse42 PRIVATE "-msse4.2")
 257    endif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
 258  endif(HAVE_SSE42)
 259  
 260  # CMake only enables PIC by default in SHARED and MODULE targets.
 261  if(BUILD_SHARED_LIBS)
 262    set_property(TARGET crc32c_sse42 PROPERTY POSITION_INDEPENDENT_CODE TRUE)
 263  endif(BUILD_SHARED_LIBS)
 264  
 265  # Must be included before CMAKE_INSTALL_INCLUDEDIR is used.
 266  include(GNUInstallDirs)
 267  
 268  add_library(crc32c ""
 269    # TODO(pwnall): Move the TARGET_OBJECTS generator expressions to the PRIVATE
 270    # section of target_sources when cmake_minimum_required becomes 3.9 or above.
 271    $<TARGET_OBJECTS:crc32c_arm64>
 272    $<TARGET_OBJECTS:crc32c_sse42>
 273  )
 274  target_sources(crc32c
 275    PRIVATE
 276      "${PROJECT_BINARY_DIR}/include/crc32c/crc32c_config.h"
 277      "src/crc32c_arm64.h"
 278      "src/crc32c_arm64_check.h"
 279      "src/crc32c_internal.h"
 280      "src/crc32c_portable.cc"
 281      "src/crc32c_prefetch.h"
 282      "src/crc32c_read_le.h"
 283      "src/crc32c_round_up.h"
 284      "src/crc32c_sse42.h"
 285      "src/crc32c_sse42_check.h"
 286      "src/crc32c.cc"
 287  
 288    # Only CMake 3.3+ supports PUBLIC sources in targets exported by "install".
 289    $<$<VERSION_GREATER:CMAKE_VERSION,3.2>:PUBLIC>
 290      "include/crc32c/crc32c.h"
 291  )
 292  
 293  target_include_directories(crc32c
 294    PUBLIC
 295      $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
 296      $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
 297  )
 298  
 299  set_property(
 300    TARGET crc32c_arm64 crc32c_sse42 crc32c
 301    APPEND
 302    PROPERTY COMPILE_DEFINITIONS CRC32C_HAVE_CONFIG_H
 303  )
 304  
 305  set_target_properties(crc32c
 306    PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR})
 307  
 308  # Warnings as errors in Visual Studio for this project's targets.
 309  if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
 310    set_property(TARGET crc32c APPEND PROPERTY COMPILE_OPTIONS "/WX")
 311    set_property(TARGET crc32c_arm64 APPEND PROPERTY COMPILE_OPTIONS "/WX")
 312    set_property(TARGET crc32c_sse42 APPEND PROPERTY COMPILE_OPTIONS "/WX")
 313  endif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
 314  
 315  if(CRC32C_BUILD_TESTS)
 316    enable_testing()
 317  
 318    # Prevent overriding the parent project's compiler/linker settings on Windows.
 319    set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
 320    set(install_gtest OFF)
 321    set(install_gmock OFF)
 322  
 323    # This project is tested using GoogleTest.
 324    add_subdirectory("third_party/googletest")
 325  
 326    # GoogleTest triggers a missing field initializers warning.
 327    if(CRC32C_HAVE_NO_MISSING_FIELD_INITIALIZERS)
 328      set_property(TARGET gtest
 329          APPEND PROPERTY COMPILE_OPTIONS -Wno-missing-field-initializers)
 330      set_property(TARGET gmock
 331          APPEND PROPERTY COMPILE_OPTIONS -Wno-missing-field-initializers)
 332    endif(CRC32C_HAVE_NO_MISSING_FIELD_INITIALIZERS)
 333  
 334    add_executable(crc32c_tests "")
 335    target_sources(crc32c_tests
 336      PRIVATE
 337        "${PROJECT_BINARY_DIR}/include/crc32c/crc32c_config.h"
 338        "src/crc32c_arm64_unittest.cc"
 339        "src/crc32c_extend_unittests.h"
 340        "src/crc32c_portable_unittest.cc"
 341        "src/crc32c_prefetch_unittest.cc"
 342        "src/crc32c_read_le_unittest.cc"
 343        "src/crc32c_round_up_unittest.cc"
 344        "src/crc32c_sse42_unittest.cc"
 345        "src/crc32c_unittest.cc"
 346        "src/crc32c_test_main.cc"
 347    )
 348    target_link_libraries(crc32c_tests crc32c gtest)
 349  
 350    # Warnings as errors in Visual Studio for this project's targets.
 351    if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
 352      set_property(TARGET crc32c_tests APPEND PROPERTY COMPILE_OPTIONS "/WX")
 353    endif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
 354  
 355    if(CRC32C_USE_GLOG)
 356      target_link_libraries(crc32c_tests glog)
 357    endif(CRC32C_USE_GLOG)
 358  
 359    add_test(NAME crc32c_tests COMMAND crc32c_tests)
 360  
 361    add_executable(crc32c_capi_tests "")
 362    target_sources(crc32c_capi_tests
 363      PRIVATE
 364        "src/crc32c_capi_unittest.c"
 365    )
 366    target_link_libraries(crc32c_capi_tests crc32c)
 367  
 368    # Warnings as errors in Visual Studio for this project's targets.
 369    if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
 370      set_property(TARGET crc32c_capi_tests APPEND PROPERTY COMPILE_OPTIONS "/WX")
 371  
 372      # The Windows SDK version currently on CI produces warnings when some
 373      # headers are #included using C99 compatibility mode or above. This
 374      # workaround can be removed once the Windows SDK on our CI is upgraded.
 375      set_property(TARGET crc32c_capi_tests
 376          APPEND PROPERTY COMPILE_OPTIONS "/wd5105")
 377    endif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
 378  
 379    add_test(NAME crc32c_capi_tests COMMAND crc32c_capi_tests)
 380  endif(CRC32C_BUILD_TESTS)
 381  
 382  if(CRC32C_BUILD_BENCHMARKS)
 383    add_executable(crc32c_bench "")
 384    target_sources(crc32c_bench
 385      PRIVATE
 386        "${PROJECT_BINARY_DIR}/include/crc32c/crc32c_config.h"
 387        "src/crc32c_benchmark.cc"
 388    )
 389    target_link_libraries(crc32c_bench crc32c)
 390  
 391    # This project uses Google benchmark for benchmarking.
 392    set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "" FORCE)
 393    set(BENCHMARK_ENABLE_EXCEPTIONS OFF CACHE BOOL "" FORCE)
 394    add_subdirectory("third_party/benchmark")
 395    target_link_libraries(crc32c_bench benchmark)
 396  
 397    if(CRC32C_USE_GLOG)
 398      target_link_libraries(crc32c_bench glog)
 399    endif(CRC32C_USE_GLOG)
 400  
 401    # Warnings as errors in Visual Studio for this project's targets.
 402    if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
 403      set_property(TARGET crc32c_bench APPEND PROPERTY COMPILE_OPTIONS "/WX")
 404    endif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
 405  endif(CRC32C_BUILD_BENCHMARKS)
 406  
 407  if(CRC32C_INSTALL)
 408    install(TARGETS crc32c
 409      EXPORT Crc32cTargets
 410      RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
 411      LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
 412      ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
 413    )
 414    install(
 415      FILES
 416        "include/crc32c/crc32c.h"
 417      DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/crc32c"
 418    )
 419  
 420    include(CMakePackageConfigHelpers)
 421    configure_package_config_file(
 422      "${PROJECT_NAME}Config.cmake.in"
 423      "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
 424      INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
 425    )
 426    write_basic_package_version_file(
 427      "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
 428      COMPATIBILITY SameMajorVersion
 429    )
 430    install(
 431      EXPORT Crc32cTargets
 432      NAMESPACE Crc32c::
 433      DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
 434    )
 435    install(
 436      FILES
 437        "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
 438        "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
 439      DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
 440    )
 441  endif(CRC32C_INSTALL)
 442