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