1# Copyright (c) 2018 Yubico AB. All rights reserved. 2# Use of this source code is governed by a BSD-style 3# license that can be found in the LICENSE file. 4 5# detect AppleClang; needs to come before project() 6cmake_policy(SET CMP0025 NEW) 7 8project(libfido2 C) 9cmake_minimum_required(VERSION 3.0) 10 11include(CheckCCompilerFlag) 12include(CheckFunctionExists) 13include(CheckIncludeFiles) 14include(CheckTypeSize) 15include(GNUInstallDirs) 16 17set(CMAKE_COLOR_MAKEFILE off) 18set(CMAKE_VERBOSE_MAKEFILE on) 19set(CMAKE_POSITION_INDEPENDENT_CODE ON) 20 21set(FIDO_MAJOR "1") 22set(FIDO_MINOR "3") 23set(FIDO_PATCH "1") 24set(FIDO_VERSION ${FIDO_MAJOR}.${FIDO_MINOR}.${FIDO_PATCH}) 25 26add_definitions(-D_FIDO_MAJOR=${FIDO_MAJOR}) 27add_definitions(-D_FIDO_MINOR=${FIDO_MINOR}) 28add_definitions(-D_FIDO_PATCH=${FIDO_PATCH}) 29 30if(CYGWIN OR MSYS) 31 set(WIN32 1) 32 add_definitions(-DWINVER=0x0a00) 33endif() 34 35if(WIN32) 36 add_definitions(-DWIN32_LEAN_AND_MEAN) 37endif() 38 39if(APPLE) 40 set(CMAKE_INSTALL_NAME_DIR 41 "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}") 42endif() 43 44# Observe OpenBSD's library versioning scheme. 45if(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") 46 set(LIB_VERSION ${FIDO_MAJOR}.${FIDO_MINOR}) 47 set(LIB_SOVERSION ${LIB_VERSION}) 48else() 49 set(LIB_VERSION ${FIDO_VERSION}) 50 set(LIB_SOVERSION ${FIDO_MAJOR}) 51endif() 52 53if(MSVC) 54 if((NOT CBOR_INCLUDE_DIRS) OR (NOT CBOR_LIBRARY_DIRS) OR 55 (NOT CRYPTO_INCLUDE_DIRS) OR (NOT CRYPTO_LIBRARY_DIRS)) 56 message(FATAL_ERROR "please provide definitions for " 57 "{CBOR,CRYPTO}_{INCLUDE,LIBRARY}_DIRS when building " 58 "under msvc") 59 endif() 60 set(CBOR_LIBRARIES cbor) 61 set(CRYPTO_LIBRARIES crypto-45) 62 set(MSVC_DISABLED_WARNINGS_LIST 63 "C4200" # nonstandard extension used: zero-sized array in 64 # struct/union; 65 "C4204" # nonstandard extension used: non-constant aggregate 66 # initializer; 67 "C4706" # assignment within conditional expression; 68 "C4996" # The POSIX name for this item is deprecated. Instead, 69 # use the ISO C and C++ conformant name 70 ) 71 # The construction in the following 3 lines was taken from LibreSSL's 72 # CMakeLists.txt. 73 string(REPLACE "C" " -wd" MSVC_DISABLED_WARNINGS_STR 74 ${MSVC_DISABLED_WARNINGS_LIST}) 75 string(REGEX REPLACE "[/-]W[1234][ ]?" "" CMAKE_C_FLAGS ${CMAKE_C_FLAGS}) 76 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -MP -W4 ${MSVC_DISABLED_WARNINGS_STR}") 77 set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /Z7") 78 set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Zi") 79else() 80 include(FindPkgConfig) 81 pkg_search_module(CBOR libcbor) 82 pkg_search_module(CRYPTO libcrypto) 83 84 # XXX workaround libcbor's missing .pc file 85 if(NOT CBOR_FOUND) 86 check_include_files(cbor.h HAVE_CBOR_H) 87 if(NOT HAVE_CBOR_H) 88 message(FATAL_ERROR "could not find cbor header files") 89 endif() 90 set(CBOR_LIBRARIES "cbor") 91 endif() 92 93 # XXX workaround libcrypto's missing .pc file 94 if(NOT CRYPTO_FOUND) 95 check_include_files(openssl/opensslv.h HAVE_OPENSSLV_H) 96 if(NOT HAVE_OPENSSLV_H) 97 message(FATAL_ERROR "could not find crypto header files") 98 endif() 99 set(CRYPTO_LIBRARIES "crypto") 100 endif() 101 102 if(CMAKE_SYSTEM_NAME STREQUAL "Linux") 103 pkg_search_module(UDEV libudev REQUIRED) 104 set(UDEV_NAME "udev") 105 # Define be32toh(). 106 add_definitions(-D_GNU_SOURCE) 107 # If using hidapi, use hidapi-hidraw. 108 set(HIDAPI_SUFFIX -hidraw) 109 elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR 110 CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") 111 set(BASE_LIBRARIES usbhid) 112 endif() 113 114 if(MINGW) 115 # MinGW is stuck with a flavour of C89. 116 add_definitions(-DFIDO_NO_DIAGNOSTIC) 117 add_definitions(-DWC_ERR_INVALID_CHARS=0x80) 118 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-parameter") 119 endif() 120 121 if(USE_HIDAPI) 122 add_definitions(-DUSE_HIDAPI) 123 pkg_search_module(HIDAPI hidapi${HIDAPI_SUFFIX} REQUIRED) 124 if(HIDAPI_FOUND) 125 set(HIDAPI_LIBRARIES hidapi${HIDAPI_SUFFIX}) 126 endif() 127 endif() 128 129 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") 130 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wextra") 131 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") 132 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wshadow") 133 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wwrite-strings") 134 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmissing-prototypes") 135 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wbad-function-cast") 136 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic") 137 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic-errors") 138 check_c_compiler_flag("-fstack-protector-all" HAVE_STACK_PROTECTOR_ALL) 139 if(HAVE_STACK_PROTECTOR_ALL) 140 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector-all") 141 endif() 142 143 add_definitions(-D_DEFAULT_SOURCE) 144 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") 145 146 set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g2") 147 set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fno-omit-frame-pointer") 148 149 if(FUZZ) 150 if(LIBFUZZER) 151 set(FUZZ_LDFLAGS "-fsanitize=fuzzer") 152 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=fuzzer-no-link") 153 endif() 154 add_definitions(-DFIDO_FUZZ) 155 endif() 156 157 if(ASAN) 158 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address,leak") 159 endif() 160 161 if(MSAN) 162 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=memory") 163 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-memory-track-origins") 164 endif() 165 166 if(UBSAN) 167 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined") 168 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-trap=undefined") 169 endif() 170 171 if(COVERAGE) 172 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-instr-generate -fcoverage-mapping") 173 endif() 174endif() 175 176# Use -Wshorten-64-to-32 if available. 177check_c_compiler_flag("-Wshorten-64-to-32" HAVE_SHORTEN_64_TO_32) 178if(HAVE_SHORTEN_64_TO_32) 179 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wshorten-64-to-32") 180endif() 181 182# Avoid https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425 183if(CMAKE_COMPILER_IS_GNUCC) 184 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-result") 185endif() 186 187# Decide which keyword to use for thread-local storage. 188if(CMAKE_COMPILER_IS_GNUCC OR 189 CMAKE_C_COMPILER_ID STREQUAL "Clang" OR 190 CMAKE_C_COMPILER_ID STREQUAL "AppleClang") 191 set(TLS "__thread") 192elseif(WIN32) 193 set(TLS "__declspec(thread)") 194endif() 195 196add_definitions(-DTLS=${TLS}) 197 198# endian.h 199check_include_files(endian.h HAVE_ENDIAN_H) 200if(HAVE_ENDIAN_H) 201 add_definitions(-DHAVE_ENDIAN_H) 202endif() 203 204# err.h 205check_include_files(err.h HAVE_ERR_H) 206if(HAVE_ERR_H) 207 add_definitions(-DHAVE_ERR_H) 208endif() 209 210# unistd.h 211check_include_files(unistd.h HAVE_UNISTD_H) 212if(HAVE_UNISTD_H) 213 add_definitions(-DHAVE_UNISTD_H) 214endif() 215 216# signal.h 217check_include_files(signal.h HAVE_SIGNAL_H) 218if(HAVE_SIGNAL_H) 219 add_definitions(-DHAVE_SIGNAL_H) 220endif() 221 222# sys/random.h 223check_include_files(sys/random.h HAVE_SYS_RANDOM_H) 224if(HAVE_SYS_RANDOM_H) 225 add_definitions(-DHAVE_SYS_RANDOM_H) 226endif() 227 228# strlcpy 229check_function_exists(strlcpy HAVE_STRLCPY) 230if(HAVE_STRLCPY) 231 add_definitions(-DHAVE_STRLCPY) 232endif() 233 234# strlcat 235check_function_exists(strlcpy HAVE_STRLCAT) 236if(HAVE_STRLCAT) 237 add_definitions(-DHAVE_STRLCAT) 238endif() 239 240# recallocarray 241check_function_exists(recallocarray HAVE_RECALLOCARRAY) 242if(HAVE_RECALLOCARRAY) 243 add_definitions(-DHAVE_RECALLOCARRAY) 244endif() 245 246# XXX getpagesize is incorrectly detected when cross-compiling 247# with mingw on Linux. Avoid. 248if(NOT WIN32) 249 check_function_exists(getpagesize HAVE_GETPAGESIZE) 250endif() 251if(HAVE_GETPAGESIZE) 252 add_definitions(-DHAVE_GETPAGESIZE) 253endif() 254 255# sysconf 256check_function_exists(sysconf HAVE_SYSCONF) 257if(HAVE_SYSCONF) 258 add_definitions(-DHAVE_SYSCONF) 259endif() 260 261# memset_s 262if(APPLE) 263 add_definitions(-D__STDC_WANT_LIB_EXT1__=1) 264endif() 265check_function_exists(memset_s HAVE_MEMSET_S) 266if(HAVE_MEMSET_S) 267 add_definitions(-DHAVE_MEMSET_S) 268endif() 269 270# explicit_bzero 271if(NOT LIBFUZZER) 272 check_function_exists(explicit_bzero HAVE_EXPLICIT_BZERO) 273 if(HAVE_EXPLICIT_BZERO) 274 add_definitions(-DHAVE_EXPLICIT_BZERO) 275 endif() 276endif() 277 278# timingsafe_bcmp 279check_function_exists(timingsafe_bcmp HAVE_TIMINGSAFE_BCMP) 280if(HAVE_TIMINGSAFE_BCMP) 281 add_definitions(-DHAVE_TIMINGSAFE_BCMP) 282endif() 283 284# readpassphrase 285check_function_exists(readpassphrase HAVE_READPASSPHRASE) 286if(HAVE_READPASSPHRASE) 287 add_definitions(-DHAVE_READPASSPHRASE) 288endif() 289 290# getline 291check_function_exists(getline HAVE_GETLINE) 292if(HAVE_GETLINE) 293 add_definitions(-DHAVE_GETLINE) 294endif() 295 296# getopt 297check_function_exists(getopt HAVE_GETOPT) 298if(HAVE_GETOPT) 299 add_definitions(-DHAVE_GETOPT) 300 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wcast-qual") 301else() 302 if(CMAKE_COMPILER_IS_GNUCC) 303 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-discarded-qualifiers") 304 endif() 305 if(CMAKE_C_COMPILER_ID STREQUAL "Clang") 306 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-incompatible-pointer-types-discards-qualifiers") 307 endif() 308endif() 309 310# usable sigaction 311set(CMAKE_EXTRA_INCLUDE_FILES signal.h) 312check_function_exists(sigaction HAVE_SIGACTION) 313check_type_size("sig_atomic_t" HAVE_SIG_ATOMIC_T) 314if(HAVE_SIGACTION AND (NOT HAVE_SIG_ATOMIC_T STREQUAL "")) 315 add_definitions(-DSIGNAL_EXAMPLE) 316endif() 317set(CMAKE_EXTRA_INCLUDE_FILES) 318 319# arc4random_buf 320check_function_exists(arc4random_buf HAVE_ARC4RANDOM_BUF) 321if(HAVE_ARC4RANDOM_BUF) 322 add_definitions(-DHAVE_ARC4RANDOM_BUF) 323endif() 324 325# getrandom 326check_function_exists(getrandom HAVE_GETRANDOM) 327if(HAVE_GETRANDOM) 328 add_definitions(-DHAVE_GETRANDOM) 329endif() 330 331# /dev/urandom 332if(UNIX) 333 add_definitions(-DHAVE_DEV_URANDOM) 334endif() 335 336# export list 337if(APPLE AND (CMAKE_C_COMPILER_ID STREQUAL "Clang" OR 338 CMAKE_C_COMPILER_ID STREQUAL "AppleClang")) 339 # clang + lld 340 string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} 341 " -exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/src/export.llvm") 342elseif(NOT MSVC) 343 # clang/gcc + gnu ld 344 if(FUZZ) 345 string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} 346 " -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/fuzz/export.gnu") 347 else() 348 string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} 349 " -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/src/export.gnu") 350 endif() 351 if(NOT WIN32) 352 string(CONCAT CMAKE_SHARED_LINKER_FLAGS 353 ${CMAKE_SHARED_LINKER_FLAGS} 354 " -Wl,-z,noexecstack -Wl,-z,relro,-z,now") 355 string(CONCAT CMAKE_EXE_LINKER_FLAGS 356 ${CMAKE_EXE_LINKER_FLAGS} 357 " -Wl,-z,noexecstack -Wl,-z,relro,-z,now") 358 if(FUZZ) 359 file(STRINGS fuzz/wrapped.sym WRAPPED_SYMBOLS) 360 foreach(s ${WRAPPED_SYMBOLS}) 361 string(CONCAT CMAKE_SHARED_LINKER_FLAGS 362 ${CMAKE_SHARED_LINKER_FLAGS} 363 " -Wl,--wrap=${s}") 364 endforeach() 365 endif() 366 endif() 367else() 368 string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} 369 " /def:\"${CMAKE_CURRENT_SOURCE_DIR}/src/export.msvc\"") 370endif() 371 372include_directories(${CMAKE_SOURCE_DIR}/src) 373include_directories(${CBOR_INCLUDE_DIRS}) 374include_directories(${CRYPTO_INCLUDE_DIRS}) 375 376link_directories(${CBOR_LIBRARY_DIRS}) 377link_directories(${CRYPTO_LIBRARY_DIRS}) 378 379message(STATUS "CMAKE_C_COMPILER: ${CMAKE_C_COMPILER}") 380message(STATUS "CMAKE_C_COMPILER_ID: ${CMAKE_C_COMPILER_ID}") 381message(STATUS "CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}") 382message(STATUS "CMAKE_INSTALL_LIBDIR: ${CMAKE_INSTALL_LIBDIR}") 383message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}") 384message(STATUS "CBOR_INCLUDE_DIRS: ${CBOR_INCLUDE_DIRS}") 385message(STATUS "CBOR_LIBRARY_DIRS: ${CBOR_LIBRARY_DIRS}") 386message(STATUS "CBOR_LIBRARIES: ${CBOR_LIBRARIES}") 387message(STATUS "CRYPTO_INCLUDE_DIRS: ${CRYPTO_INCLUDE_DIRS}") 388message(STATUS "CRYPTO_LIBRARY_DIRS: ${CRYPTO_LIBRARY_DIRS}") 389message(STATUS "CRYPTO_LIBRARIES: ${CRYPTO_LIBRARIES}") 390message(STATUS "BASE_LIBRARIES: ${BASE_LIBRARIES}") 391message(STATUS "HIDAPI_LIBRARIES: ${HIDAPI_LIBRARIES}") 392message(STATUS "VERSION: ${FIDO_VERSION}") 393message(STATUS "LIB_VERSION: ${LIB_VERSION}") 394message(STATUS "LIB_SOVERSION: ${LIB_SOVERSION}") 395message(STATUS "FUZZ: ${FUZZ}") 396message(STATUS "AFL: ${AFL}") 397message(STATUS "LIBFUZZER: ${LIBFUZZER}") 398message(STATUS "ASAN: ${ASAN}") 399message(STATUS "MSAN: ${MSAN}") 400message(STATUS "COVERAGE: ${COVERAGE}") 401message(STATUS "TLS: ${TLS}") 402message(STATUS "USE_HIDAPI: ${USE_HIDAPI}") 403 404if(CMAKE_SYSTEM_NAME STREQUAL "Linux") 405 message(STATUS "UDEV_INCLUDE_DIRS: ${UDEV_INCLUDE_DIRS}") 406 message(STATUS "UDEV_LIBRARY_DIRS: ${UDEV_LIBRARY_DIRS}") 407 message(STATUS "UDEV_LIBRARIES: ${UDEV_LIBRARIES}") 408 message(STATUS "UDEV_RULES_DIR: ${UDEV_RULES_DIR}") 409endif() 410 411subdirs(src) 412subdirs(examples) 413subdirs(tools) 414subdirs(man) 415 416if(NOT WIN32) 417 if(CMAKE_BUILD_TYPE STREQUAL "Debug") 418 if(NOT MSAN AND NOT LIBFUZZER) 419 subdirs(regress) 420 endif() 421 endif() 422 if(FUZZ) 423 subdirs(fuzz) 424 endif() 425 426 if(CMAKE_SYSTEM_NAME STREQUAL "Linux") 427 subdirs(udev) 428 endif() 429endif() 430