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 5cmake_minimum_required(VERSION 3.1) 6project(Crc32c VERSION 1.1.0 LANGUAGES C CXX) 7 8# C standard can be overridden when this is used as a sub-project. 9if(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) 14endif(NOT CMAKE_C_STANDARD) 15 16# C++ standard can be overridden when this is used as a sub-project. 17if(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) 22endif(NOT CMAKE_CXX_STANDARD) 23 24# https://github.com/izenecloud/cmake/blob/master/SetCompilerWarningAll.cmake 25if(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-") 42else(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") 65endif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 66 67option(CRC32C_BUILD_TESTS "Build CRC32C's unit tests" ON) 68option(CRC32C_BUILD_BENCHMARKS "Build CRC32C's benchmarks" ON) 69option(CRC32C_USE_GLOG "Build CRC32C's tests with Google Logging" ON) 70option(CRC32C_INSTALL "Install CRC32C's header and library" ON) 71 72include(TestBigEndian) 73test_big_endian(BYTE_ORDER_BIG_ENDIAN) 74 75include(CheckCXXCompilerFlag) 76# Used by glog. 77check_cxx_compiler_flag(-Wno-deprecated CRC32C_HAVE_NO_DEPRECATED) 78# Used by glog. 79check_cxx_compiler_flag(-Wno-sign-compare CRC32C_HAVE_NO_SIGN_COMPARE) 80# Used by glog. 81check_cxx_compiler_flag(-Wno-unused-parameter CRC32C_HAVE_NO_UNUSED_PARAMETER) 82# Used by googletest. 83check_cxx_compiler_flag(-Wno-missing-field-initializers 84 CRC32C_HAVE_NO_MISSING_FIELD_INITIALIZERS) 85 86# Check for __builtin_prefetch support in the compiler. 87include(CheckCXXSourceCompiles) 88check_cxx_source_compiles(" 89int 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. 98include(CheckCXXSourceCompiles) 99check_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 106int 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. 115set(OLD_CMAKE_REQURED_FLAGS ${CMAKE_REQUIRED_FLAGS}) 116if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 117 set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} /arch:AVX") 118else(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 119 set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -msse4.2") 120endif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 121check_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 129int 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) 137set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQURED_FLAGS}) 138 139# Check for ARMv8 w/ CRC and CRYPTO extensions support in the compiler. 140set(OLD_CMAKE_REQURED_FLAGS ${CMAKE_REQUIRED_FLAGS}) 141if(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") 144else(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 145 set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -march=armv8-a+crc+crypto") 146endif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 147check_cxx_source_compiles(" 148#include <arm_acle.h> 149#include <arm_neon.h> 150 151int 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) 157set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQURED_FLAGS}) 158 159# Check for strong getauxval() support in the system headers. 160check_cxx_source_compiles(" 161#include <arm_acle.h> 162#include <arm_neon.h> 163#include <sys/auxv.h> 164 165int main() { 166 getauxval(AT_HWCAP); 167 return 0; 168} 169" HAVE_STRONG_GETAUXVAL) 170 171# Check for weak getauxval() support in the compiler. 172check_cxx_source_compiles(" 173unsigned long getauxval(unsigned long type) __attribute__((weak)); 174#define AT_HWCAP 16 175 176int main() { 177 getauxval(AT_HWCAP); 178 return 0; 179} 180" HAVE_WEAK_GETAUXVAL) 181 182if(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) 211endif(CRC32C_USE_GLOG) 212 213configure_file( 214 "src/crc32c_config.h.in" 215 "${PROJECT_BINARY_DIR}/include/crc32c/crc32c_config.h" 216) 217 218include_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. 222add_library(crc32c_arm64 OBJECT "") 223target_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) 229if(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") 236endif(HAVE_ARM64_CRC32C) 237 238# CMake only enables PIC by default in SHARED and MODULE targets. 239if(BUILD_SHARED_LIBS) 240 set_property(TARGET crc32c_arm64 PROPERTY POSITION_INDEPENDENT_CODE TRUE) 241endif(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. 245add_library(crc32c_sse42 OBJECT "") 246target_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) 252if(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") 258endif(HAVE_SSE42) 259 260# CMake only enables PIC by default in SHARED and MODULE targets. 261if(BUILD_SHARED_LIBS) 262 set_property(TARGET crc32c_sse42 PROPERTY POSITION_INDEPENDENT_CODE TRUE) 263endif(BUILD_SHARED_LIBS) 264 265# Must be included before CMAKE_INSTALL_INCLUDEDIR is used. 266include(GNUInstallDirs) 267 268add_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) 274target_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 293target_include_directories(crc32c 294 PUBLIC 295 $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include> 296 $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> 297) 298 299set_target_properties(crc32c 300 PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR}) 301 302# Warnings as errors in Visual Studio for this project's targets. 303if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 304 set_property(TARGET crc32c APPEND PROPERTY COMPILE_OPTIONS "/WX") 305 set_property(TARGET crc32c_arm64 APPEND PROPERTY COMPILE_OPTIONS "/WX") 306 set_property(TARGET crc32c_sse42 APPEND PROPERTY COMPILE_OPTIONS "/WX") 307endif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 308 309if(CRC32C_BUILD_TESTS) 310 enable_testing() 311 312 # Prevent overriding the parent project's compiler/linker settings on Windows. 313 set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) 314 set(install_gtest OFF) 315 set(install_gmock OFF) 316 317 # This project is tested using GoogleTest. 318 add_subdirectory("third_party/googletest") 319 320 # GoogleTest triggers a missing field initializers warning. 321 if(CRC32C_HAVE_NO_MISSING_FIELD_INITIALIZERS) 322 set_property(TARGET gtest 323 APPEND PROPERTY COMPILE_OPTIONS -Wno-missing-field-initializers) 324 set_property(TARGET gmock 325 APPEND PROPERTY COMPILE_OPTIONS -Wno-missing-field-initializers) 326 endif(CRC32C_HAVE_NO_MISSING_FIELD_INITIALIZERS) 327 328 add_executable(crc32c_tests "") 329 target_sources(crc32c_tests 330 PRIVATE 331 "${PROJECT_BINARY_DIR}/include/crc32c/crc32c_config.h" 332 "src/crc32c_arm64_unittest.cc" 333 "src/crc32c_extend_unittests.h" 334 "src/crc32c_portable_unittest.cc" 335 "src/crc32c_prefetch_unittest.cc" 336 "src/crc32c_read_le_unittest.cc" 337 "src/crc32c_round_up_unittest.cc" 338 "src/crc32c_sse42_unittest.cc" 339 "src/crc32c_unittest.cc" 340 "src/crc32c_test_main.cc" 341 ) 342 target_link_libraries(crc32c_tests crc32c gtest) 343 344 # Warnings as errors in Visual Studio for this project's targets. 345 if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 346 set_property(TARGET crc32c_tests APPEND PROPERTY COMPILE_OPTIONS "/WX") 347 endif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 348 349 if(CRC32C_USE_GLOG) 350 target_link_libraries(crc32c_tests glog) 351 endif(CRC32C_USE_GLOG) 352 353 add_test(NAME crc32c_tests COMMAND crc32c_tests) 354 355 add_executable(crc32c_capi_tests "") 356 target_sources(crc32c_capi_tests 357 PRIVATE 358 "src/crc32c_capi_unittest.c" 359 ) 360 target_link_libraries(crc32c_capi_tests crc32c) 361 362 # Warnings as errors in Visual Studio for this project's targets. 363 if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 364 set_property(TARGET crc32c_capi_tests APPEND PROPERTY COMPILE_OPTIONS "/WX") 365 endif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 366 367 add_test(NAME crc32c_capi_tests COMMAND crc32c_capi_tests) 368endif(CRC32C_BUILD_TESTS) 369 370if(CRC32C_BUILD_BENCHMARKS) 371 add_executable(crc32c_bench "") 372 target_sources(crc32c_bench 373 PRIVATE 374 "${PROJECT_BINARY_DIR}/include/crc32c/crc32c_config.h" 375 "src/crc32c_benchmark.cc" 376 ) 377 target_link_libraries(crc32c_bench crc32c) 378 379 # This project uses Google benchmark for benchmarking. 380 set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "" FORCE) 381 set(BENCHMARK_ENABLE_EXCEPTIONS OFF CACHE BOOL "" FORCE) 382 add_subdirectory("third_party/benchmark") 383 target_link_libraries(crc32c_bench benchmark) 384 385 if(CRC32C_USE_GLOG) 386 target_link_libraries(crc32c_bench glog) 387 endif(CRC32C_USE_GLOG) 388 389 # Warnings as errors in Visual Studio for this project's targets. 390 if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 391 set_property(TARGET crc32c_bench APPEND PROPERTY COMPILE_OPTIONS "/WX") 392 endif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 393endif(CRC32C_BUILD_BENCHMARKS) 394 395if(CRC32C_INSTALL) 396 install(TARGETS crc32c 397 EXPORT Crc32cTargets 398 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 399 LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 400 ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 401 ) 402 install( 403 FILES 404 "include/crc32c/crc32c.h" 405 DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/crc32c" 406 ) 407 408 include(CMakePackageConfigHelpers) 409 configure_package_config_file( 410 "${PROJECT_NAME}Config.cmake.in" 411 "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" 412 INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" 413 ) 414 write_basic_package_version_file( 415 "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" 416 COMPATIBILITY SameMajorVersion 417 ) 418 install( 419 EXPORT Crc32cTargets 420 NAMESPACE Crc32c:: 421 DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" 422 ) 423 install( 424 FILES 425 "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" 426 "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" 427 DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" 428 ) 429endif(CRC32C_INSTALL) 430