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 specifiy the scope of include 10# directories. That way, a target linking to a library (using the 11# target_link_librairies 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 42# Set the project root directory. 43set(MBEDTLS_DIR ${CMAKE_CURRENT_SOURCE_DIR}) 44 45option(ENABLE_PROGRAMS "Build mbed TLS programs." ON) 46 47option(UNSAFE_BUILD "Allow unsafe builds. These builds ARE NOT SECURE." OFF) 48option(MBEDTLS_FATAL_WARNINGS "Compiler warnings treated as errors" ON) 49if(WIN32) 50 option(GEN_FILES "Generate the auto-generated files as needed" OFF) 51else() 52 option(GEN_FILES "Generate the auto-generated files as needed" ON) 53endif() 54 55string(REGEX MATCH "Clang" CMAKE_COMPILER_IS_CLANG "${CMAKE_C_COMPILER_ID}") 56string(REGEX MATCH "GNU" CMAKE_COMPILER_IS_GNU "${CMAKE_C_COMPILER_ID}") 57string(REGEX MATCH "IAR" CMAKE_COMPILER_IS_IAR "${CMAKE_C_COMPILER_ID}") 58string(REGEX MATCH "MSVC" CMAKE_COMPILER_IS_MSVC "${CMAKE_C_COMPILER_ID}") 59 60# the test suites currently have compile errors with MSVC 61if(CMAKE_COMPILER_IS_MSVC) 62 option(ENABLE_TESTING "Build mbed TLS tests." OFF) 63else() 64 option(ENABLE_TESTING "Build mbed TLS tests." ON) 65endif() 66 67# Warning string - created as a list for compatibility with CMake 2.8 68set(CTR_DRBG_128_BIT_KEY_WARN_L1 "**** WARNING! MBEDTLS_CTR_DRBG_USE_128_BIT_KEY defined!\n") 69set(CTR_DRBG_128_BIT_KEY_WARN_L2 "**** Using 128-bit keys for CTR_DRBG limits the security of generated\n") 70set(CTR_DRBG_128_BIT_KEY_WARN_L3 "**** keys and operations that use random values generated to 128-bit security\n") 71 72set(CTR_DRBG_128_BIT_KEY_WARNING "${WARNING_BORDER}" 73 "${CTR_DRBG_128_BIT_KEY_WARN_L1}" 74 "${CTR_DRBG_128_BIT_KEY_WARN_L2}" 75 "${CTR_DRBG_128_BIT_KEY_WARN_L3}" 76 "${WARNING_BORDER}") 77 78# Python 3 is only needed here to check for configuration warnings. 79if(NOT CMAKE_VERSION VERSION_LESS 3.15.0) 80 set(Python3_FIND_STRATEGY LOCATION) 81 find_package(Python3 COMPONENTS Interpreter) 82 if(Python3_Interpreter_FOUND) 83 set(MBEDTLS_PYTHON_EXECUTABLE ${Python3_EXECUTABLE}) 84 endif() 85else() 86 find_package(PythonInterp 3) 87 if(PYTHONINTERP_FOUND) 88 set(MBEDTLS_PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE}) 89 endif() 90endif() 91if(MBEDTLS_PYTHON_EXECUTABLE) 92 93 # If 128-bit keys are configured for CTR_DRBG, display an appropriate warning 94 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 95 RESULT_VARIABLE result) 96 if(${result} EQUAL 0) 97 message(WARNING ${CTR_DRBG_128_BIT_KEY_WARNING}) 98 endif() 99 100endif() 101 102# If this is the root project add longer list of available CMAKE_BUILD_TYPE values 103if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) 104 set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} 105 CACHE STRING "Choose the type of build: None Debug Release Coverage ASan ASanDbg MemSan MemSanDbg Check CheckFull" 106 FORCE) 107endif() 108 109# Create a symbolic link from ${base_name} in the binary directory 110# to the corresponding path in the source directory. 111function(link_to_source base_name) 112 # Get OS dependent path to use in `execute_process` 113 if (CMAKE_HOST_WIN32) 114 #mklink is an internal command of cmd.exe it can only work with \ 115 string(REPLACE "/" "\\" link "${CMAKE_CURRENT_BINARY_DIR}/${base_name}") 116 string(REPLACE "/" "\\" target "${CMAKE_CURRENT_SOURCE_DIR}/${base_name}") 117 else() 118 set(link "${CMAKE_CURRENT_BINARY_DIR}/${base_name}") 119 set(target "${CMAKE_CURRENT_SOURCE_DIR}/${base_name}") 120 endif() 121 122 if (NOT EXISTS ${link}) 123 if (CMAKE_HOST_UNIX) 124 set(command ln -s ${target} ${link}) 125 else() 126 if (IS_DIRECTORY ${target}) 127 set(command cmd.exe /c mklink /j ${link} ${target}) 128 else() 129 set(command cmd.exe /c mklink /h ${link} ${target}) 130 endif() 131 endif() 132 133 execute_process(COMMAND ${command} 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 endif() 141endfunction(link_to_source) 142 143# Get the filename without the final extension (i.e. convert "a.b.c" to "a.b") 144function(get_name_without_last_ext dest_var full_name) 145 # Split into a list on '.' (but a cmake list is just a ';'-separated string) 146 string(REPLACE "." ";" ext_parts "${full_name}") 147 # Remove the last item if there are more than one 148 list(LENGTH ext_parts ext_parts_len) 149 if (${ext_parts_len} GREATER "1") 150 math(EXPR ext_parts_last_item "${ext_parts_len} - 1") 151 list(REMOVE_AT ext_parts ${ext_parts_last_item}) 152 endif() 153 # Convert back to a string by replacing separators with '.' 154 string(REPLACE ";" "." no_ext_name "${ext_parts}") 155 # Copy into the desired variable 156 set(${dest_var} ${no_ext_name} PARENT_SCOPE) 157endfunction(get_name_without_last_ext) 158 159string(REGEX MATCH "Clang" CMAKE_COMPILER_IS_CLANG "${CMAKE_C_COMPILER_ID}") 160 161include(CheckCCompilerFlag) 162 163if(CMAKE_COMPILER_IS_GNU) 164 # some warnings we want are not available with old GCC versions 165 # note: starting with CMake 2.8 we could use CMAKE_C_COMPILER_VERSION 166 execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion 167 OUTPUT_VARIABLE GCC_VERSION) 168 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wwrite-strings") 169 if (GCC_VERSION VERSION_GREATER 3.0 OR GCC_VERSION VERSION_EQUAL 3.0) 170 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wformat=2 -Wno-format-nonliteral") 171 endif() 172 if (GCC_VERSION VERSION_GREATER 4.3 OR GCC_VERSION VERSION_EQUAL 4.3) 173 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wvla") 174 endif() 175 if (GCC_VERSION VERSION_GREATER 4.5 OR GCC_VERSION VERSION_EQUAL 4.5) 176 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wlogical-op") 177 endif() 178 if (GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8) 179 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wshadow") 180 endif() 181 if (GCC_VERSION VERSION_GREATER 5.0) 182 CHECK_C_COMPILER_FLAG("-Wformat-signedness" C_COMPILER_SUPPORTS_WFORMAT_SIGNEDNESS) 183 if(C_COMPILER_SUPPORTS_WFORMAT_SIGNEDNESS) 184 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wformat-signedness") 185 endif() 186 endif() 187 if (GCC_VERSION VERSION_GREATER 7.0 OR GCC_VERSION VERSION_EQUAL 7.0) 188 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wformat-overflow=2 -Wformat-truncation") 189 endif() 190 set(CMAKE_C_FLAGS_RELEASE "-O2") 191 set(CMAKE_C_FLAGS_DEBUG "-O0 -g3") 192 set(CMAKE_C_FLAGS_COVERAGE "-O0 -g3 --coverage") 193 set(CMAKE_C_FLAGS_ASAN "-fsanitize=address -fno-common -fsanitize=undefined -fno-sanitize-recover=all -O3") 194 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") 195 set(CMAKE_C_FLAGS_CHECK "-Os") 196 set(CMAKE_C_FLAGS_CHECKFULL "${CMAKE_C_FLAGS_CHECK} -Wcast-qual") 197endif(CMAKE_COMPILER_IS_GNU) 198 199if(CMAKE_COMPILER_IS_CLANG) 200 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wwrite-strings -Wpointer-arith -Wimplicit-fallthrough -Wshadow -Wvla -Wformat=2 -Wno-format-nonliteral") 201 set(CMAKE_C_FLAGS_RELEASE "-O2") 202 set(CMAKE_C_FLAGS_DEBUG "-O0 -g3") 203 set(CMAKE_C_FLAGS_COVERAGE "-O0 -g3 --coverage") 204 set(CMAKE_C_FLAGS_ASAN "-fsanitize=address -fno-common -fsanitize=undefined -fno-sanitize-recover=all -O3") 205 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") 206 set(CMAKE_C_FLAGS_MEMSAN "-fsanitize=memory -O3") 207 set(CMAKE_C_FLAGS_MEMSANDBG "-fsanitize=memory -O1 -g3 -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize-memory-track-origins=2") 208 set(CMAKE_C_FLAGS_CHECK "-Os") 209endif(CMAKE_COMPILER_IS_CLANG) 210 211if(CMAKE_COMPILER_IS_IAR) 212 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --warn_about_c_style_casts --warnings_are_errors -Ohz") 213endif(CMAKE_COMPILER_IS_IAR) 214 215if(CMAKE_COMPILER_IS_MSVC) 216 # Strictest warnings 217 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W3") 218endif(CMAKE_COMPILER_IS_MSVC) 219 220if(MBEDTLS_FATAL_WARNINGS) 221 if(CMAKE_COMPILER_IS_MSVC) 222 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX") 223 endif(CMAKE_COMPILER_IS_MSVC) 224 225 if(CMAKE_COMPILER_IS_CLANG OR CMAKE_COMPILER_IS_GNU) 226 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") 227 if(UNSAFE_BUILD) 228 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-error=cpp") 229 set(CMAKE_C_FLAGS_ASAN "${CMAKE_C_FLAGS_ASAN} -Wno-error=cpp") 230 set(CMAKE_C_FLAGS_ASANDBG "${CMAKE_C_FLAGS_ASANDBG} -Wno-error=cpp") 231 endif(UNSAFE_BUILD) 232 endif(CMAKE_COMPILER_IS_CLANG OR CMAKE_COMPILER_IS_GNU) 233endif(MBEDTLS_FATAL_WARNINGS) 234 235if(CMAKE_BUILD_TYPE STREQUAL "Coverage") 236 if(CMAKE_COMPILER_IS_GNU OR CMAKE_COMPILER_IS_CLANG) 237 set(CMAKE_SHARED_LINKER_FLAGS "--coverage") 238 endif(CMAKE_COMPILER_IS_GNU OR CMAKE_COMPILER_IS_CLANG) 239endif(CMAKE_BUILD_TYPE STREQUAL "Coverage") 240 241if(LIB_INSTALL_DIR) 242else() 243 set(LIB_INSTALL_DIR lib) 244endif() 245 246add_subdirectory(include) 247 248add_subdirectory(3rdparty) 249 250add_subdirectory(library) 251 252# 253# The C files in tests/src directory contain test code shared among test suites 254# and programs. This shared test code is compiled and linked to test suites and 255# programs objects as a set of compiled objects. The compiled objects are NOT 256# built into a library that the test suite and program objects would link 257# against as they link against the mbedcrypto, mbedx509 and mbedtls libraries. 258# The reason is that such library is expected to have mutual dependencies with 259# the aforementioned libraries and that there is as of today no portable way of 260# handling such dependencies (only toolchain specific solutions). 261# 262# Thus the below definition of the `mbedtls_test` CMake library of objects 263# target. This library of objects is used by tests and programs CMake files 264# to define the test executables. 265# 266if(ENABLE_TESTING OR ENABLE_PROGRAMS) 267 file(GLOB MBEDTLS_TEST_FILES ${CMAKE_CURRENT_SOURCE_DIR}/tests/src/*.c ${CMAKE_CURRENT_SOURCE_DIR}/tests/src/drivers/*.c) 268 add_library(mbedtls_test OBJECT ${MBEDTLS_TEST_FILES}) 269 target_include_directories(mbedtls_test 270 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/tests/include 271 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include 272 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/library) 273endif() 274 275if(ENABLE_PROGRAMS) 276 add_subdirectory(programs) 277endif() 278 279ADD_CUSTOM_TARGET(${MBEDTLS_TARGET_PREFIX}apidoc 280 COMMAND doxygen mbedtls.doxyfile 281 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/doxygen) 282 283if(ENABLE_TESTING) 284 enable_testing() 285 286 add_subdirectory(tests) 287 288 # additional convenience targets for Unix only 289 if(UNIX) 290 291 ADD_CUSTOM_TARGET(covtest 292 COMMAND make test 293 COMMAND programs/test/selftest 294 COMMAND tests/compat.sh 295 COMMAND tests/ssl-opt.sh 296 ) 297 298 ADD_CUSTOM_TARGET(lcov 299 COMMAND rm -rf Coverage 300 COMMAND lcov --capture --initial --directory library/CMakeFiles/mbedtls.dir -o files.info 301 COMMAND lcov --capture --directory library/CMakeFiles/mbedtls.dir -o tests.info 302 COMMAND lcov --add-tracefile files.info --add-tracefile tests.info -o all.info 303 COMMAND lcov --remove all.info -o final.info '*.h' 304 COMMAND gendesc tests/Descriptions.txt -o descriptions 305 COMMAND genhtml --title "mbed TLS" --description-file descriptions --keep-descriptions --legend --no-branch-coverage -o Coverage final.info 306 COMMAND rm -f files.info tests.info all.info final.info descriptions 307 ) 308 309 ADD_CUSTOM_TARGET(memcheck 310 COMMAND sed -i.bak s+/usr/bin/valgrind+`which valgrind`+ DartConfiguration.tcl 311 COMMAND ctest -O memcheck.log -D ExperimentalMemCheck 312 COMMAND tail -n1 memcheck.log | grep 'Memory checking results:' > /dev/null 313 COMMAND rm -f memcheck.log 314 COMMAND mv DartConfiguration.tcl.bak DartConfiguration.tcl 315 ) 316 endif(UNIX) 317 318 # Make scripts needed for testing available in an out-of-source build. 319 if (NOT ${CMAKE_CURRENT_BINARY_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) 320 link_to_source(scripts) 321 # Copy (don't link) DartConfiguration.tcl, needed for memcheck, to 322 # keep things simple with the sed commands in the memcheck target. 323 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/DartConfiguration.tcl 324 ${CMAKE_CURRENT_BINARY_DIR}/DartConfiguration.tcl COPYONLY) 325 endif() 326endif() 327 328configure_package_config_file( 329 "cmake/MbedTLSConfig.cmake.in" 330 "cmake/MbedTLSConfig.cmake" 331 INSTALL_DESTINATION "cmake") 332 333write_basic_package_version_file( 334 "cmake/MbedTLSConfigVersion.cmake" 335 COMPATIBILITY SameMajorVersion 336 VERSION 3.0.0) 337 338install( 339 FILES "${CMAKE_CURRENT_BINARY_DIR}/cmake/MbedTLSConfig.cmake" 340 "${CMAKE_CURRENT_BINARY_DIR}/cmake/MbedTLSConfigVersion.cmake" 341 DESTINATION "cmake") 342 343export( 344 EXPORT MbedTLSTargets 345 NAMESPACE MbedTLS:: 346 FILE "cmake/MbedTLSTargets.cmake") 347 348install( 349 EXPORT MbedTLSTargets 350 NAMESPACE MbedTLS:: 351 DESTINATION "cmake" 352 FILE "MbedTLSTargets.cmake") 353 354if(CMAKE_VERSION VERSION_GREATER 3.15 OR CMAKE_VERSION VERSION_EQUAL 3.15) 355 # Do not export the package by default 356 cmake_policy(SET CMP0090 NEW) 357 358 # Make this package visible to the system 359 export(PACKAGE MbedTLS) 360endif() 361