1# 2# CMake build system design considerations: 3# 4# - Include directories: 5# + Do not define include directories globally using the include_directories 6# command but rather at the target level using the 7# target_include_directories command. That way, it is easier to guarantee 8# that targets are built using the proper list of include directories. 9# + Use the PUBLIC and PRIVATE keywords to specify the scope of include 10# directories. That way, a target linking to a library (using the 11# target_link_libraries command) inherits from the library PUBLIC include 12# directories and not from the PRIVATE ones. 13# - MBEDTLS_TARGET_PREFIX: CMake targets are designed to be alterable by calling 14# CMake in order to avoid target name clashes, via the use of 15# MBEDTLS_TARGET_PREFIX. The value of this variable is prefixed to the 16# mbedtls, mbedx509, mbedcrypto and apidoc targets. 17# 18 19# We specify a minimum requirement of 3.10.2, but for now use 3.5.1 here 20# until our infrastructure catches up. 21cmake_minimum_required(VERSION 3.5.1) 22 23include(CMakePackageConfigHelpers) 24 25# https://cmake.org/cmake/help/latest/policy/CMP0011.html 26# Setting this policy is required in CMake >= 3.18.0, otherwise a warning is generated. The OLD 27# policy setting is deprecated, and will be removed in future versions. 28cmake_policy(SET CMP0011 NEW) 29# https://cmake.org/cmake/help/latest/policy/CMP0012.html 30# Setting the CMP0012 policy to NEW is required for FindPython3 to work with CMake 3.18.2 31# (there is a bug in this particular version), otherwise, setting the CMP0012 policy is required 32# for CMake versions >= 3.18.3 otherwise a deprecated warning is generated. The OLD policy setting 33# is deprecated and will be removed in future versions. 34cmake_policy(SET CMP0012 NEW) 35 36if(TEST_CPP) 37 project("mbed TLS" C CXX) 38else() 39 project("mbed TLS" C) 40endif() 41 42include(GNUInstallDirs) 43 44# Determine if mbed TLS is being built as a subproject using add_subdirectory() 45if(NOT DEFINED MBEDTLS_AS_SUBPROJECT) 46 set(MBEDTLS_AS_SUBPROJECT ON) 47 if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) 48 set(MBEDTLS_AS_SUBPROJECT OFF) 49 endif() 50endif() 51 52# Set the project root directory. 53set(MBEDTLS_DIR ${CMAKE_CURRENT_SOURCE_DIR}) 54 55option(ENABLE_PROGRAMS "Build mbed TLS programs." ON) 56 57option(UNSAFE_BUILD "Allow unsafe builds. These builds ARE NOT SECURE." OFF) 58option(MBEDTLS_FATAL_WARNINGS "Compiler warnings treated as errors" ON) 59if(CMAKE_HOST_WIN32) 60 option(GEN_FILES "Generate the auto-generated files as needed" OFF) 61else() 62 option(GEN_FILES "Generate the auto-generated files as needed" OFF) 63endif() 64 65option(DISABLE_PACKAGE_CONFIG_AND_INSTALL "Disable package configuration, target export and installation" ${MBEDTLS_AS_SUBPROJECT}) 66 67string(REGEX MATCH "Clang" CMAKE_COMPILER_IS_CLANG "${CMAKE_C_COMPILER_ID}") 68string(REGEX MATCH "GNU" CMAKE_COMPILER_IS_GNU "${CMAKE_C_COMPILER_ID}") 69string(REGEX MATCH "IAR" CMAKE_COMPILER_IS_IAR "${CMAKE_C_COMPILER_ID}") 70string(REGEX MATCH "MSVC" CMAKE_COMPILER_IS_MSVC "${CMAKE_C_COMPILER_ID}") 71 72# the test suites currently have compile errors with MSVC 73if(CMAKE_COMPILER_IS_MSVC) 74 option(ENABLE_TESTING "Build mbed TLS tests." OFF) 75else() 76 option(ENABLE_TESTING "Build mbed TLS tests." ON) 77endif() 78 79# Warning string - created as a list for compatibility with CMake 2.8 80set(CTR_DRBG_128_BIT_KEY_WARN_L1 "**** WARNING! MBEDTLS_CTR_DRBG_USE_128_BIT_KEY defined!\n") 81set(CTR_DRBG_128_BIT_KEY_WARN_L2 "**** Using 128-bit keys for CTR_DRBG limits the security of generated\n") 82set(CTR_DRBG_128_BIT_KEY_WARN_L3 "**** keys and operations that use random values generated to 128-bit security\n") 83 84set(CTR_DRBG_128_BIT_KEY_WARNING "${WARNING_BORDER}" 85 "${CTR_DRBG_128_BIT_KEY_WARN_L1}" 86 "${CTR_DRBG_128_BIT_KEY_WARN_L2}" 87 "${CTR_DRBG_128_BIT_KEY_WARN_L3}" 88 "${WARNING_BORDER}") 89 90# Python 3 is only needed here to check for configuration warnings. 91if(NOT CMAKE_VERSION VERSION_LESS 3.15.0) 92 set(Python3_FIND_STRATEGY LOCATION) 93 find_package(Python3 COMPONENTS Interpreter) 94 if(Python3_Interpreter_FOUND) 95 set(MBEDTLS_PYTHON_EXECUTABLE ${Python3_EXECUTABLE}) 96 endif() 97else() 98 find_package(PythonInterp 3) 99 if(PYTHONINTERP_FOUND) 100 set(MBEDTLS_PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE}) 101 endif() 102endif() 103if(MBEDTLS_PYTHON_EXECUTABLE) 104 105 # If 128-bit keys are configured for CTR_DRBG, display an appropriate warning 106 execute_process(COMMAND ${MBEDTLS_PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/scripts/config.py -f ${CMAKE_CURRENT_SOURCE_DIR}/include/mbedtls/mbedtls_config.h get MBEDTLS_CTR_DRBG_USE_128_BIT_KEY 107 RESULT_VARIABLE result) 108 if(${result} EQUAL 0) 109 message(WARNING ${CTR_DRBG_128_BIT_KEY_WARNING}) 110 endif() 111 112endif() 113 114# If this is the root project add longer list of available CMAKE_BUILD_TYPE values 115if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) 116 set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} 117 CACHE STRING "Choose the type of build: None Debug Release Coverage ASan ASanDbg MemSan MemSanDbg Check CheckFull" 118 FORCE) 119endif() 120 121# Create a symbolic link from ${base_name} in the binary directory 122# to the corresponding path in the source directory. 123# Note: Copies the file(s) on Windows. 124function(link_to_source base_name) 125 set(link "${CMAKE_CURRENT_BINARY_DIR}/${base_name}") 126 set(target "${CMAKE_CURRENT_SOURCE_DIR}/${base_name}") 127 128 # Linking to non-existent file is not desirable. At best you will have a 129 # dangling link, but when building in tree, this can create a symbolic link 130 # to itself. 131 if (EXISTS ${target} AND NOT EXISTS ${link}) 132 if (CMAKE_HOST_UNIX) 133 execute_process(COMMAND ln -s ${target} ${link} 134 RESULT_VARIABLE result 135 ERROR_VARIABLE output) 136 137 if (NOT ${result} EQUAL 0) 138 message(FATAL_ERROR "Could not create symbolic link for: ${target} --> ${output}") 139 endif() 140 else() 141 if (IS_DIRECTORY ${target}) 142 file(GLOB_RECURSE files FOLLOW_SYMLINKS LIST_DIRECTORIES false RELATIVE ${target} "${target}/*") 143 foreach(file IN LISTS files) 144 configure_file("${target}/${file}" "${link}/${file}" COPYONLY) 145 endforeach(file) 146 else() 147 configure_file(${target} ${link} COPYONLY) 148 endif() 149 endif() 150 endif() 151endfunction(link_to_source) 152 153# Get the filename without the final extension (i.e. convert "a.b.c" to "a.b") 154function(get_name_without_last_ext dest_var full_name) 155 # Split into a list on '.' (but a cmake list is just a ';'-separated string) 156 string(REPLACE "." ";" ext_parts "${full_name}") 157 # Remove the last item if there are more than one 158 list(LENGTH ext_parts ext_parts_len) 159 if (${ext_parts_len} GREATER "1") 160 math(EXPR ext_parts_last_item "${ext_parts_len} - 1") 161 list(REMOVE_AT ext_parts ${ext_parts_last_item}) 162 endif() 163 # Convert back to a string by replacing separators with '.' 164 string(REPLACE ";" "." no_ext_name "${ext_parts}") 165 # Copy into the desired variable 166 set(${dest_var} ${no_ext_name} PARENT_SCOPE) 167endfunction(get_name_without_last_ext) 168 169string(REGEX MATCH "Clang" CMAKE_COMPILER_IS_CLANG "${CMAKE_C_COMPILER_ID}") 170 171include(CheckCCompilerFlag) 172 173set(CMAKE_C_EXTENSIONS OFF) 174set(CMAKE_C_STANDARD 99) 175 176if(CMAKE_COMPILER_IS_GNU) 177 # some warnings we want are not available with old GCC versions 178 # note: starting with CMake 2.8 we could use CMAKE_C_COMPILER_VERSION 179 execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion 180 OUTPUT_VARIABLE GCC_VERSION) 181 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wwrite-strings") 182 if (GCC_VERSION VERSION_GREATER 3.0 OR GCC_VERSION VERSION_EQUAL 3.0) 183 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wformat=2 -Wno-format-nonliteral") 184 endif() 185 if (GCC_VERSION VERSION_GREATER 4.3 OR GCC_VERSION VERSION_EQUAL 4.3) 186 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wvla") 187 endif() 188 if (GCC_VERSION VERSION_GREATER 4.5 OR GCC_VERSION VERSION_EQUAL 4.5) 189 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wlogical-op") 190 endif() 191 if (GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8) 192 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wshadow") 193 endif() 194 if (GCC_VERSION VERSION_GREATER 5.0) 195 CHECK_C_COMPILER_FLAG("-Wformat-signedness" C_COMPILER_SUPPORTS_WFORMAT_SIGNEDNESS) 196 if(C_COMPILER_SUPPORTS_WFORMAT_SIGNEDNESS) 197 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wformat-signedness") 198 endif() 199 endif() 200 if (GCC_VERSION VERSION_GREATER 7.0 OR GCC_VERSION VERSION_EQUAL 7.0) 201 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wformat-overflow=2 -Wformat-truncation") 202 endif() 203 set(CMAKE_C_FLAGS_RELEASE "-O2") 204 set(CMAKE_C_FLAGS_DEBUG "-O0 -g3") 205 set(CMAKE_C_FLAGS_COVERAGE "-O0 -g3 --coverage") 206 set(CMAKE_C_FLAGS_ASAN "-fsanitize=address -fno-common -fsanitize=undefined -fno-sanitize-recover=all -O3") 207 set(CMAKE_C_FLAGS_ASANDBG "-fsanitize=address -fno-common -fsanitize=undefined -fno-sanitize-recover=all -O1 -g3 -fno-omit-frame-pointer -fno-optimize-sibling-calls") 208 set(CMAKE_C_FLAGS_CHECK "-Os") 209 set(CMAKE_C_FLAGS_CHECKFULL "${CMAKE_C_FLAGS_CHECK} -Wcast-qual") 210endif(CMAKE_COMPILER_IS_GNU) 211 212if(CMAKE_COMPILER_IS_CLANG) 213 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wwrite-strings -Wpointer-arith -Wimplicit-fallthrough -Wshadow -Wvla -Wformat=2 -Wno-format-nonliteral") 214 set(CMAKE_C_FLAGS_RELEASE "-O2") 215 set(CMAKE_C_FLAGS_DEBUG "-O0 -g3") 216 set(CMAKE_C_FLAGS_COVERAGE "-O0 -g3 --coverage") 217 set(CMAKE_C_FLAGS_ASAN "-fsanitize=address -fno-common -fsanitize=undefined -fno-sanitize-recover=all -O3") 218 set(CMAKE_C_FLAGS_ASANDBG "-fsanitize=address -fno-common -fsanitize=undefined -fno-sanitize-recover=all -O1 -g3 -fno-omit-frame-pointer -fno-optimize-sibling-calls") 219 set(CMAKE_C_FLAGS_MEMSAN "-fsanitize=memory -O3") 220 set(CMAKE_C_FLAGS_MEMSANDBG "-fsanitize=memory -O1 -g3 -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize-memory-track-origins=2") 221 set(CMAKE_C_FLAGS_CHECK "-Os") 222endif(CMAKE_COMPILER_IS_CLANG) 223 224if(CMAKE_COMPILER_IS_IAR) 225 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --warn_about_c_style_casts") 226 set(CMAKE_C_FLAGS_RELEASE "-Ohz") 227 set(CMAKE_C_FLAGS_DEBUG "--debug -On") 228endif(CMAKE_COMPILER_IS_IAR) 229 230if(CMAKE_COMPILER_IS_MSVC) 231 # Strictest warnings, UTF-8 source and execution charset 232 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W3 /utf-8") 233endif(CMAKE_COMPILER_IS_MSVC) 234 235if(MBEDTLS_FATAL_WARNINGS) 236 if(CMAKE_COMPILER_IS_MSVC) 237 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX") 238 endif(CMAKE_COMPILER_IS_MSVC) 239 240 if(CMAKE_COMPILER_IS_CLANG OR CMAKE_COMPILER_IS_GNU) 241 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") 242 if(UNSAFE_BUILD) 243 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-error=cpp") 244 set(CMAKE_C_FLAGS_ASAN "${CMAKE_C_FLAGS_ASAN} -Wno-error=cpp") 245 set(CMAKE_C_FLAGS_ASANDBG "${CMAKE_C_FLAGS_ASANDBG} -Wno-error=cpp") 246 endif(UNSAFE_BUILD) 247 endif(CMAKE_COMPILER_IS_CLANG OR CMAKE_COMPILER_IS_GNU) 248 249 if (CMAKE_COMPILER_IS_IAR) 250 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --warning_are_errors") 251 endif(CMAKE_COMPILER_IS_IAR) 252endif(MBEDTLS_FATAL_WARNINGS) 253 254if(CMAKE_BUILD_TYPE STREQUAL "Coverage") 255 if(CMAKE_COMPILER_IS_GNU OR CMAKE_COMPILER_IS_CLANG) 256 set(CMAKE_SHARED_LINKER_FLAGS "--coverage") 257 endif(CMAKE_COMPILER_IS_GNU OR CMAKE_COMPILER_IS_CLANG) 258endif(CMAKE_BUILD_TYPE STREQUAL "Coverage") 259 260if(LIB_INSTALL_DIR) 261 set(CMAKE_INSTALL_LIBDIR "${LIB_INSTALL_DIR}") 262endif() 263 264add_subdirectory(include) 265 266add_subdirectory(3rdparty) 267 268add_subdirectory(library) 269 270# 271# The C files in tests/src directory contain test code shared among test suites 272# and programs. This shared test code is compiled and linked to test suites and 273# programs objects as a set of compiled objects. The compiled objects are NOT 274# built into a library that the test suite and program objects would link 275# against as they link against the mbedcrypto, mbedx509 and mbedtls libraries. 276# The reason is that such library is expected to have mutual dependencies with 277# the aforementioned libraries and that there is as of today no portable way of 278# handling such dependencies (only toolchain specific solutions). 279# 280# Thus the below definition of the `mbedtls_test` CMake library of objects 281# target. This library of objects is used by tests and programs CMake files 282# to define the test executables. 283# 284if(ENABLE_TESTING OR ENABLE_PROGRAMS) 285 file(GLOB MBEDTLS_TEST_FILES 286 ${CMAKE_CURRENT_SOURCE_DIR}/tests/src/*.c 287 ${CMAKE_CURRENT_SOURCE_DIR}/tests/src/drivers/*.c) 288 add_library(mbedtls_test OBJECT ${MBEDTLS_TEST_FILES}) 289 target_include_directories(mbedtls_test 290 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/tests/include 291 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include 292 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/library) 293 294 file(GLOB MBEDTLS_TEST_HELPER_FILES 295 ${CMAKE_CURRENT_SOURCE_DIR}/tests/src/test_helpers/*.c) 296 add_library(mbedtls_test_helpers OBJECT ${MBEDTLS_TEST_HELPER_FILES}) 297 target_include_directories(mbedtls_test_helpers 298 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/tests/include 299 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include 300 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/library 301 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/everest/include) 302endif() 303 304if(ENABLE_PROGRAMS) 305 add_subdirectory(programs) 306endif() 307 308ADD_CUSTOM_TARGET(${MBEDTLS_TARGET_PREFIX}apidoc 309 COMMAND doxygen mbedtls.doxyfile 310 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/doxygen) 311 312if(ENABLE_TESTING) 313 enable_testing() 314 315 add_subdirectory(tests) 316 317 # additional convenience targets for Unix only 318 if(UNIX) 319 320 # For coverage testing: 321 # 1. Build with: 322 # cmake -D CMAKE_BUILD_TYPE=Coverage /path/to/source && make 323 # 2. Run the relevant tests for the part of the code you're interested in. 324 # For the reference coverage measurement, see 325 # tests/scripts/basic-build-test.sh 326 # 3. Run scripts/lcov.sh to generate an HTML report. 327 ADD_CUSTOM_TARGET(lcov 328 COMMAND scripts/lcov.sh 329 ) 330 331 ADD_CUSTOM_TARGET(memcheck 332 COMMAND sed -i.bak s+/usr/bin/valgrind+`which valgrind`+ DartConfiguration.tcl 333 COMMAND ctest -O memcheck.log -D ExperimentalMemCheck 334 COMMAND tail -n1 memcheck.log | grep 'Memory checking results:' > /dev/null 335 COMMAND rm -f memcheck.log 336 COMMAND mv DartConfiguration.tcl.bak DartConfiguration.tcl 337 ) 338 endif(UNIX) 339 340 # Make scripts needed for testing available in an out-of-source build. 341 if (NOT ${CMAKE_CURRENT_BINARY_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) 342 link_to_source(scripts) 343 # Copy (don't link) DartConfiguration.tcl, needed for memcheck, to 344 # keep things simple with the sed commands in the memcheck target. 345 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/DartConfiguration.tcl 346 ${CMAKE_CURRENT_BINARY_DIR}/DartConfiguration.tcl COPYONLY) 347 endif() 348endif() 349 350if(NOT DISABLE_PACKAGE_CONFIG_AND_INSTALL) 351 configure_package_config_file( 352 "cmake/MbedTLSConfig.cmake.in" 353 "cmake/MbedTLSConfig.cmake" 354 INSTALL_DESTINATION "cmake") 355 356 write_basic_package_version_file( 357 "cmake/MbedTLSConfigVersion.cmake" 358 COMPATIBILITY SameMajorVersion 359 VERSION 3.4.0) 360 361 install( 362 FILES "${CMAKE_CURRENT_BINARY_DIR}/cmake/MbedTLSConfig.cmake" 363 "${CMAKE_CURRENT_BINARY_DIR}/cmake/MbedTLSConfigVersion.cmake" 364 DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/MbedTLS") 365 366 export( 367 EXPORT MbedTLSTargets 368 NAMESPACE MbedTLS:: 369 FILE "cmake/MbedTLSTargets.cmake") 370 371 install( 372 EXPORT MbedTLSTargets 373 NAMESPACE MbedTLS:: 374 DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/MbedTLS" 375 FILE "MbedTLSTargets.cmake") 376 377 if(CMAKE_VERSION VERSION_GREATER 3.15 OR CMAKE_VERSION VERSION_EQUAL 3.15) 378 # Do not export the package by default 379 cmake_policy(SET CMP0090 NEW) 380 381 # Make this package visible to the system 382 export(PACKAGE MbedTLS) 383 endif() 384endif() 385