1# 2# Arm SCP/MCP Software 3# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved. 4# 5# SPDX-License-Identifier: BSD-3-Clause 6# 7 8# cmake-lint: disable=C0301 9 10cmake_minimum_required(VERSION 3.18.3) 11 12list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") 13 14# 15# Individual firmware targets are configured based on the 'Firmware.cmake' 16# living in the firmware source directory that the user provides to us, which 17# determines the default set of configuration options we are given, including 18# the toolchain file. 19# 20 21if(SCP_FIRMWARE_SOURCE_DIR) 22 get_filename_component(SCP_FIRMWARE_SOURCE_DIR "${SCP_FIRMWARE_SOURCE_DIR}" 23 ABSOLUTE BASE_DIR "${CMAKE_SOURCE_DIR}/product") 24 25 include("${SCP_FIRMWARE_SOURCE_DIR}/Firmware.cmake") 26 27 if((NOT SCP_FIRMWARE) OR (NOT SCP_FIRMWARE_TARGET)) 28 # cmake-format: off 29 message(FATAL_ERROR 30 "Insufficient firmware metadata provided.\n" 31 32 "Please ensure your 'Firmware.cmake' has set both `SCP_FIRMWARE` " 33 "and `SCP_FIRMWARE_TARGET` to the name of your firmware and the " 34 "firmware's CMake target respectively.") 35 # cmake-format: on 36 endif() 37 38 if(NOT SCP_FIRMWARE_BINARY_DIR) 39 # 40 # Derive the binary directory from the location of the source directory 41 # if it's in-tree. 42 # 43 44 file(RELATIVE_PATH SCP_FIRMWARE_BINARY_DIR "${CMAKE_SOURCE_DIR}" 45 "${SCP_FIRMWARE_SOURCE_DIR}") 46 endif() 47 48 if(SCP_FIRMWARE_BINARY_DIR MATCHES "\\.\\.") 49 # cmake-format: off 50 message(FATAL_ERROR 51 "Invalid firmware binary directory.\n" 52 53 "Please ensure your firmware binary directory is a relative path. " 54 "This path is used as the location within the project binary " 55 "directory that will be used for firmware artifacts.") 56 # cmake-format: on 57 endif() 58endif() 59 60# 61# Handle automatic selection of the toolchain. This only occurs if the user has 62# not explicitly provided the path to a toolchain file and the firmware has 63# given us a default preference. 64# 65 66if(SCP_TOOLCHAIN_INIT AND (NOT CMAKE_TOOLCHAIN_FILE)) 67 # 68 # Let the firmware decide what its default toolchain should be, but allow 69 # the user to override it. 70 # 71 72 if(NOT SCP_TOOLCHAIN) 73 set(SCP_TOOLCHAIN "${SCP_TOOLCHAIN_INIT}") 74 endif() 75 76 set(CMAKE_TOOLCHAIN_FILE 77 "${SCP_FIRMWARE_SOURCE_DIR}/Toolchain-${SCP_TOOLCHAIN}.cmake") 78endif() 79 80if(SCP_TOOLCHAIN STREQUAL "Clang" AND NOT SCP_LLVM_SYSROOT_CC) 81 message( 82 FATAL_ERROR 83 "When Clang is set as toolchain SCP_LLVM_SYSROOT_CC must be defined" 84 ) 85endif() 86 87project( 88 SCP 89 VERSION 2.11.0 90 DESCRIPTION "Arm SCP/MCP Software" 91 HOMEPAGE_URL 92 "https://developer.arm.com/tools-and-software/open-source-software/firmware/scp-firmware" 93 LANGUAGES C ASM) 94 95# 96# Configure the default build type to be "Release". We choose to default to a 97# release build as non-developer consumers will generally want a release build, 98# whereas developers who need a debug build are generally familiar with how to 99# enable it in the build system. 100# 101 102if((NOT CMAKE_BUILD_TYPE) AND (NOT CMAKE_CONFIGURATION_TYPES)) 103 set(CMAKE_BUILD_TYPE 104 "Release" 105 CACHE STRING "Build type." FORCE) 106 107 set_property( 108 CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" 109 "RelWithDebInfo") 110endif() 111 112# 113# Set the default C standard to C11 plus any compiler extensions. 114# 115 116set(CMAKE_C_STANDARD 11) 117set(CMAKE_C_STANDARD_REQUIRED TRUE) 118set(CMAKE_C_EXTENSIONS TRUE) 119 120# 121# We use `__declspec` when available, but Clang needs to explicitly enable 122# support for it before we can use them. 123# 124 125if(CMAKE_C_COMPILER_ID STREQUAL "Clang") 126 string(APPEND CMAKE_C_FLAGS " -fms-extensions") 127endif() 128 129# 130# Enable inter-procedural optimization for all targets if we can. 131# `CheckIPOSupported` doesn't play particularly nicely with toolchains that 132# cannot build executables right off the bat, so we skip this check if we're 133# cross compiling. 134# 135 136include(CheckIPOSupported) 137include(CMakeDependentOption) 138 139check_ipo_supported(RESULT SCP_IPO_SUPPORTED) 140 141cmake_dependent_option( 142 SCP_ENABLE_IPO 143 "Enable the interprocedural optimization (IPO) if supported?" 144 "${SCP_ENABLE_IPO_INIT}" "DEFINED SCP_ENABLE_IPO_INIT" "${SCP_ENABLE_IPO}") 145 146if(CMAKE_CROSSCOMPILING 147 AND (CMAKE_C_COMPILER_ID STREQUAL "GNU") 148 AND SCP_ENABLE_IPO) 149 set(SCP_IPO_SUPPORTED TRUE) 150endif() 151 152cmake_dependent_option( 153 CMAKE_INTERPROCEDURAL_OPTIMIZATION "Enable interprocedural optimization?" 154 TRUE "SCP_IPO_SUPPORTED;SCP_ENABLE_IPO" FALSE) 155 156# 157# Export a `compile_commands.json` file for generators that support it. 158# 159 160set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE) 161 162# 163# Set up Cppcheck if it's available and enabled. 164# 165if(NOT DISABLE_CPPCHECK) 166 find_program(CMAKE_C_CPPCHECK NAMES "cppcheck") 167 168 if(NOT CMAKE_C_CPPCHECK) 169 unset(CMAKE_C_CPPCHECK CACHE) 170 endif() 171 172 if(CMAKE_C_CPPCHECK) 173 # Prepend cppcheck_wrapper.py before binary to perform pre and post 174 # cppcheck operations. 175 set(CPPCHECK_WRAPPER ${CMAKE_SOURCE_DIR}/tools/cppcheck_wrapper.py) 176 # cmake-format: off 177 178 list(PREPEND CMAKE_C_CPPCHECK ${CPPCHECK_WRAPPER}) 179 list(APPEND CMAKE_C_CPPCHECK "--quiet") 180 list(APPEND CMAKE_C_CPPCHECK "--suppressions-list=${CMAKE_CURRENT_SOURCE_DIR}/tools/cppcheck_suppress_list.txt") 181 list(APPEND CMAKE_C_CPPCHECK "--enable=all") 182 list(APPEND CMAKE_C_CPPCHECK "--error-exitcode=1") 183 184 if(SCP_ARCHITECTURE STREQUAL "arm-m") 185 if(CMAKE_SYSTEM_PROCESSOR MATCHES "cortex-m(33|55)") 186 list(APPEND CMAKE_C_CPPCHECK "--library=${CMAKE_CURRENT_SOURCE_DIR}/.armv8m.cppcheck.cfg") 187 elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "cortex-m(3|7)") 188 list(APPEND CMAKE_C_CPPCHECK "--library=${CMAKE_CURRENT_SOURCE_DIR}/.armv7m.cppcheck.cfg") 189 endif() 190 endif() 191 192 if(CMAKE_C_COMPILER_ID STREQUAL "ARMClang") 193 list(APPEND CMAKE_C_CPPCHECK "--library=${CMAKE_CURRENT_SOURCE_DIR}/.armclang.cppcheck.cfg") 194 else() 195 list(APPEND CMAKE_C_CPPCHECK "--library=${CMAKE_CURRENT_SOURCE_DIR}/.gnu.cppcheck.cfg") 196 endif() 197 198 if(COMMAND_OUTPUT_VERBOSE) 199 list(APPEND CMAKE_C_CPPCHECK "verbose") 200 endif() 201 202 # cmake-format: on 203 endif() 204endif() 205 206# 207# Set up Clang-Tidy if it's available and enabled. 208# 209if(ENABLE_CLANG_TIDY) 210 211 find_program( 212 CMAKE_C_CLANG_TIDY 213 NAMES "clang-tidy" 214 "clang-tidy-3.6" 215 "clang-tidy-3.7" 216 "clang-tidy-3.8" 217 "clang-tidy-3.9" 218 "clang-tidy-4.0" 219 "clang-tidy-5.0" 220 "clang-tidy-6.0" 221 "clang-tidy-7" 222 "clang-tidy-8" 223 "clang-tidy-9" 224 "clang-tidy-10" 225 "clang-tidy-11") 226 227 if(NOT CMAKE_C_CLANG_TIDY) 228 unset(CMAKE_C_CLANG_TIDY CACHE) 229 endif() 230 231 if(CMAKE_C_CLANG_TIDY) 232 # cmake-format: off 233 234 if(CMAKE_C_COMPILER_TARGET) 235 list(APPEND CMAKE_C_CLANG_TIDY "--extra-arg=--target=${CMAKE_C_COMPILER_TARGET}") 236 endif() 237 238 foreach(dir IN LISTS CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES) 239 list(APPEND CMAKE_C_CLANG_TIDY "--extra-arg=-isystem") 240 list(APPEND CMAKE_C_CLANG_TIDY "--extra-arg=${dir}") 241 list(APPEND CMAKE_C_CLANG_TIDY "--extra-arg=-fms-extensions") 242 endforeach() 243 244 if(CMAKE_C_COMPILER_ID STREQUAL "ARMClang") 245 list(APPEND CMAKE_C_CLANG_TIDY "--extra-arg=-D__ARM_PROMISE=__builtin_assume") 246 list(APPEND CMAKE_C_CLANG_TIDY "--extra-arg=-D__ARMCC_VERSION=600000") 247 list(APPEND CMAKE_C_CLANG_TIDY "--extra-arg=-D__ESCAPE__(x)=(x)") 248 endif() 249 250 list(APPEND CMAKE_C_CLANG_TIDY "--quiet") 251 252 # cmake-format: on 253 endif() 254 255endif() 256 257# 258# Set up Include What You Use ("IWYU") if it's available and enabled. 259# 260if(ENABLE_IWYU) 261 262 find_program(CMAKE_C_INCLUDE_WHAT_YOU_USE NAMES iwyu include-what-you-use) 263 264 if(NOT CMAKE_C_INCLUDE_WHAT_YOU_USE) 265 unset(CMAKE_C_INCLUDE_WHAT_YOU_USE CACHE) 266 endif() 267 268 if(CMAKE_C_INCLUDE_WHAT_YOU_USE) 269 # cmake-format: off 270 271 if(CMAKE_C_COMPILER_TARGET) 272 list(APPEND CMAKE_C_INCLUDE_WHAT_YOU_USE "--target=${CMAKE_C_COMPILER_TARGET}") 273 endif() 274 275 foreach(dir IN LISTS CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES) 276 list(APPEND CMAKE_C_INCLUDE_WHAT_YOU_USE "-isystem") 277 list(APPEND CMAKE_C_INCLUDE_WHAT_YOU_USE "${dir}") 278 endforeach() 279 280 if(CMAKE_C_COMPILER_ID STREQUAL "ARMClang") 281 list(APPEND CMAKE_C_INCLUDE_WHAT_YOU_USE "-D__ARM_PROMISE=__builtin_assume") 282 list(APPEND CMAKE_C_INCLUDE_WHAT_YOU_USE "-D__ARMCC_VERSION=600000") 283 list(APPEND CMAKE_C_INCLUDE_WHAT_YOU_USE "-D__ESCAPE__(x)=(x)") 284 endif() 285 286 # cmake-format: on 287 endif() 288 289endif() 290 291# 292# Try to locate Arm Compiler's 'fromelf' tool. 293# 294 295if(CMAKE_C_COMPILER_ID MATCHES "ARMClang") 296 get_filename_component(base ${CMAKE_C_COMPILER} DIRECTORY) 297 298 find_program(SCP_FROMELF fromelf ${base}) 299 300 if(SCP_FROMELF) 301 mark_as_advanced(SCP_FROMELF) 302 endif() 303endif() 304 305# 306# Try to identify any standard libraries that require special treatment. 307# 308 309include(CheckSymbolExists) 310 311check_symbol_exists("__NEWLIB__" "sys/features.h" SCP_HAVE_NEWLIB) 312 313# 314# If the user asks for it, we can save them some time by creating a flat binary 315# from the firmware's compiled ELF image. 316# 317 318include(CMakeDependentOption) 319 320cmake_dependent_option( 321 SCP_GENERATE_FLAT_BINARY "Generate a flat binary (.bin) image?" 322 "${SCP_GENERATE_FLAT_BINARY_INIT}" "DEFINED SCP_GENERATE_FLAT_BINARY_INIT" 323 "${SCP_GENERATE_FLAT_BINARY}") 324 325# 326# If the firmware developer has given us initial values for these configuration 327# options, we can expose them to the user. 328# 329 330include(CMakeDependentOption) 331 332# Common build options 333 334if(SCP_ARCHITECTURE STREQUAL "optee") 335 set(SCP_ENABLE_SUB_SYSTEM_MODE_INIT TRUE) 336endif() 337 338set(SCP_ENABLE_OVERRIDE_FIRMWARE_NAME 339 ${SCP_ENABLE_OVERRIDE_FIRMWARE_NAME_INIT} 340 CACHE STRING "Override firmware binary name") 341 342cmake_dependent_option( 343 SCP_ENABLE_SUB_SYSTEM_MODE "Enable the execution as a sub-system?" 344 "${SCP_ENABLE_SUB_SYSTEM_MODE_INIT}" 345 "DEFINED SCP_ENABLE_SUB_SYSTEM_MODE_INIT" 346 "${SCP_ENABLE_SUB_SYSTEM_MODE}") 347 348cmake_dependent_option( 349 SCP_ENABLE_NOTIFICATIONS "Enable the notification subsystem?" 350 "${SCP_ENABLE_NOTIFICATIONS_INIT}" "DEFINED SCP_ENABLE_NOTIFICATIONS_INIT" 351 "${SCP_ENABLE_NOTIFICATIONS}") 352 353cmake_dependent_option( 354 SCP_ENABLE_RESOURCE_PERMISSIONS 355 "Enable the resource permission support?" 356 "${SCP_ENABLE_RESOURCE_PERMISSIONS_INIT}" 357 "DEFINED SCP_ENABLE_RESOURCE_PERMISSIONS_INIT" 358 "${SCP_ENABLE_RESOURCE_PERMISSIONS}") 359 360cmake_dependent_option( 361 SCP_ENABLE_SCMI_NOTIFICATIONS 362 "Enable the SCMI notifications?" 363 "${SCP_ENABLE_SCMI_NOTIFICATIONS_INIT}" 364 "DEFINED SCP_ENABLE_SCMI_NOTIFICATIONS_INIT" 365 "${SCP_ENABLE_SCMI_NOTIFICATIONS}") 366 367cmake_dependent_option( 368 SCP_ENABLE_SCMI_SENSOR_EVENTS 369 "Enable the SCMI sensor events?" 370 "${SCP_ENABLE_SCMI_SENSOR_EVENTS_INIT}" 371 "DEFINED SCP_ENABLE_SCMI_SENSOR_EVENTS_INIT" 372 "${SCP_ENABLE_SCMI_SENSOR_EVENTS}") 373 374cmake_dependent_option( 375 SCP_ENABLE_FAST_CHANNELS 376 "Enable the transport Fast Channels?" 377 "${SCP_ENABLE_FAST_CHANNELS_INIT}" 378 "DEFINED SCP_ENABLE_FAST_CHANNELS_INIT" 379 "${SCP_ENABLE_FAST_CHANNELS}") 380 381# Include firmware specific build options 382include("${SCP_FIRMWARE_SOURCE_DIR}/Buildoptions.cmake" OPTIONAL) 383 384# 385# Wrap `add_executable` in a way that allows us to do some extra processing on 386# the firmware target.(e.g. flat binary generation) This is necessary almost 387# exclusively because `add_custom_command` cannot be used with a target created 388# in a different directory. 389# 390 391# cmake-lint: disable=C0103,C0111 392 393macro(add_executable target) 394 _add_executable(${target} ${ARGN}) 395 396 if("${target}" STREQUAL "${SCP_FIRMWARE_TARGET}") 397 if(SCP_GENERATE_FLAT_BINARY) 398 # 399 # Invoke 'objcopy' or 'fromelf', which we use to generate a flat 400 # binary for the generated firmware image. We make this optional 401 # because some binaries consist of disjoint sections far apart from 402 # one another, which can generate huge binaries. 403 # 404 405 if(SCP_FROMELF) 406 # cmake-format: off 407 add_custom_command( 408 TARGET ${target} POST_BUILD 409 COMMAND ${SCP_FROMELF} 410 ARGS 411 --bin "$<TARGET_FILE:${target}>" 412 --output "$<TARGET_FILE_DIR:${target}>/$<TARGET_PROPERTY:${target},OUTPUT_NAME>.bin" 413 COMMENT "Generating flat binary ${target}.bin") 414 # cmake-format: on 415 elseif(CMAKE_OBJCOPY) 416 # cmake-format: off 417 add_custom_command( 418 TARGET ${target} POST_BUILD 419 COMMAND ${CMAKE_OBJCOPY} 420 ARGS -O binary 421 "$<TARGET_FILE:${target}>" 422 "$<TARGET_FILE_DIR:${target}>/$<TARGET_FILE_BASE_NAME:${target}>.bin" 423 COMMENT "Generating flat binary ${target}.bin") 424 # cmake-format: on 425 endif() 426 endif() 427 endif() 428endmacro() 429 430if(SCP_FIRMWARE) 431 # 432 # Pull in the CMSIS package. 433 # 434 435 add_subdirectory("contrib/cmsis" EXCLUDE_FROM_ALL) 436 437 # 438 # Load in the firmware. We do this now so that the firmware list files can 439 # make adjustments to any modules it wishes to load in, configure the 440 # architecture library, etc. 441 # 442 443 add_subdirectory("${SCP_FIRMWARE_SOURCE_DIR}" "${SCP_FIRMWARE_BINARY_DIR}" 444 EXCLUDE_FROM_ALL) 445 446 # 447 # Generate a map file for the firmware. 448 # 449 450 if(CMAKE_C_COMPILER_ID STREQUAL "ARMClang") 451 target_link_options( 452 ${SCP_FIRMWARE_TARGET} 453 PRIVATE "LINKER:--map" 454 "LINKER:--list=$<TARGET_FILE_DIR:${SCP_FIRMWARE_TARGET}>/$<TARGET_FILE_BASE_NAME:${SCP_FIRMWARE_TARGET}>.map") 455 else() 456 target_link_options( 457 ${SCP_FIRMWARE_TARGET} 458 PRIVATE "LINKER:--cref" 459 "LINKER:-Map=$<TARGET_FILE_DIR:${SCP_FIRMWARE_TARGET}>/$<TARGET_FILE_BASE_NAME:${SCP_FIRMWARE_TARGET}>.map") 460 endif() 461 462 # 463 # Make the firmware target a part of the 'all' pseudo-target and give it a 464 # fixed output binary name so that different toolchains don't generate 465 # different names (which is desirable especially for higher-level build 466 # systems). 467 # 468 469 if("${SCP_ENABLE_OVERRIDE_FIRMWARE_NAME}" STREQUAL "") 470 set(SCP_FIRMWARE_NAME ${SCP_FIRMWARE_TARGET}) 471 else() 472 set(SCP_FIRMWARE_NAME ${SCP_ENABLE_OVERRIDE_FIRMWARE_NAME}) 473 endif() 474 475 set_target_properties( 476 ${SCP_FIRMWARE_TARGET} 477 PROPERTIES EXCLUDE_FROM_ALL FALSE 478 OUTPUT_NAME "${SCP_FIRMWARE_NAME}" 479 RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") 480 481 set_target_properties( 482 ${SCP_FIRMWARE_TARGET} 483 PROPERTIES EXCLUDE_FROM_ALL FALSE 484 SUFFIX ".elf") 485 # 486 # Load in the CLI debugger if it was requested. 487 # 488 489 cmake_dependent_option( 490 SCP_ENABLE_DEBUGGER "Enable the debugger-cli subsystem?" 491 "${SCP_ENABLE_DEBUGGER_INIT}" "DEFINED SCP_ENABLE_DEBUGGER_INIT" 492 "${SCP_ENABLE_DEBUGGER}") 493 494 if(SCP_ENABLE_DEBUGGER) 495 add_subdirectory("debugger" EXCLUDE_FROM_ALL) 496 endif() 497 498 # 499 # Load in the architecture support library. 500 # 501 502 add_subdirectory("arch" EXCLUDE_FROM_ALL) 503 504 # 505 # Load in the modules specified, plus any that need to be included to 506 # support other modules. 507 # 508 509 add_subdirectory("module" EXCLUDE_FROM_ALL) 510 511 # 512 # Load in the framework. This should be the last of the targets we need. 513 # 514 515 add_subdirectory("framework" EXCLUDE_FROM_ALL) 516 517 # 518 # Collect up all the source files used to build the various targets created 519 # above. 520 # 521 522 # cmake-format: off 523 524 string(APPEND scp_sources "$<TARGET_PROPERTY:framework,INTERFACE_SOURCES>$<SEMICOLON>") 525 string(APPEND scp_sources "$<TARGET_PROPERTY:framework,SOURCES>$<SEMICOLON>") 526 string(APPEND scp_sources "$<TARGET_PROPERTY:${SCP_ARCHITECTURE_TARGET},INTERFACE_SOURCES>$<SEMICOLON>") 527 string(APPEND scp_sources "$<TARGET_PROPERTY:${SCP_ARCHITECTURE_TARGET},SOURCES>$<SEMICOLON>") 528 string(APPEND scp_sources "$<TARGET_PROPERTY:${SCP_FIRMWARE_TARGET},INTERFACE_SOURCES>$<SEMICOLON>") 529 string(APPEND scp_sources "$<TARGET_PROPERTY:${SCP_FIRMWARE_TARGET},SOURCES>$<SEMICOLON>") 530 531 string(APPEND scp_includes "$<TARGET_PROPERTY:framework,INTERFACE_INCLUDE_DIRECTORIES>$<SEMICOLON>") 532 string(APPEND scp_includes "$<TARGET_PROPERTY:framework,INCLUDE_DIRECTORIES>$<SEMICOLON>") 533 string(APPEND scp_includes "$<TARGET_PROPERTY:${SCP_ARCHITECTURE_TARGET},INTERFACE_INCLUDE_DIRECTORIES>$<SEMICOLON>") 534 string(APPEND scp_includes "$<TARGET_PROPERTY:${SCP_ARCHITECTURE_TARGET},INCLUDE_DIRECTORIES>$<SEMICOLON>") 535 string(APPEND scp_includes "$<TARGET_PROPERTY:${SCP_FIRMWARE_TARGET},INTERFACE_INCLUDE_DIRECTORIES>$<SEMICOLON>") 536 string(APPEND scp_includes "$<TARGET_PROPERTY:${SCP_FIRMWARE_TARGET},INCLUDE_DIRECTORIES>$<SEMICOLON>") 537 538 string(APPEND scp_defines "$<TARGET_PROPERTY:framework,INTERFACE_COMPILE_DEFINITIONS>$<SEMICOLON>") 539 string(APPEND scp_defines "$<TARGET_PROPERTY:framework,COMPILE_DEFINITIONS>$<SEMICOLON>") 540 string(APPEND scp_defines "$<TARGET_PROPERTY:${SCP_ARCHITECTURE_TARGET},INTERFACE_COMPILE_DEFINITIONS>$<SEMICOLON>") 541 string(APPEND scp_defines "$<TARGET_PROPERTY:${SCP_ARCHITECTURE_TARGET},COMPILE_DEFINITIONS>$<SEMICOLON>" ) 542 string(APPEND scp_defines "$<TARGET_PROPERTY:${SCP_FIRMWARE_TARGET},INTERFACE_COMPILE_DEFINITIONS>$<SEMICOLON>") 543 string(APPEND scp_defines "$<TARGET_PROPERTY:${SCP_FIRMWARE_TARGET},COMPILE_DEFINITIONS>$<SEMICOLON>") 544 545 list(APPEND scp_libraries "$<TARGET_FILE:framework>") 546 list(APPEND scp_libraries "$<TARGET_FILE:${SCP_ARCHITECTURE_TARGET}>") 547 list(APPEND scp_libraries "$<TARGET_FILE:${SCP_FIRMWARE_TARGET}>") 548 549 foreach(module IN LISTS SCP_MODULE_TARGETS) 550 string(APPEND scp_sources "$<TARGET_PROPERTY:${module},INTERFACE_SOURCES>$<SEMICOLON>") 551 string(APPEND scp_sources "$<TARGET_PROPERTY:${module},SOURCES>$<SEMICOLON>") 552 553 string(APPEND scp_includes "$<TARGET_PROPERTY:${module},INTERFACE_INCLUDE_DIRECTORIES>$<SEMICOLON>") 554 string(APPEND scp_includes "$<TARGET_PROPERTY:${module},INCLUDE_DIRECTORIES>$<SEMICOLON>") 555 556 string(APPEND scp_defines "$<TARGET_PROPERTY:${module},INTERFACE_COMPILE_DEFINITIONS>$<SEMICOLON>") 557 string(APPEND scp_defines "$<TARGET_PROPERTY:${module},COMPILE_DEFINITIONS>$<SEMICOLON>") 558 559 list(APPEND scp_libraries "$<TARGET_FILE:${module}>") 560 endforeach() 561 562 set(scp_sources $<REMOVE_DUPLICATES:${scp_sources}>) 563 set(scp_includes $<REMOVE_DUPLICATES:${scp_includes}>) 564 set(scp_defines $<REMOVE_DUPLICATES:${scp_defines}>) 565 566 # cmake-format: on 567 568 # 569 # Load in the documentation generation. 570 # 571 add_subdirectory("doc" EXCLUDE_FROM_ALL) 572endif() 573 574 575set(SCP_FIRMWARE_LIB "${SCP_FIRMWARE_TARGET}-all") 576 577# merged libraries is only built when `make ${SCP_FIRMWARE_LIB}` is issued 578add_custom_target(${SCP_FIRMWARE_LIB} 579 # COMMAND/COMMENT must be upper case 580 COMMAND ${CMAKE_AR} rcT $<TARGET_FILE_DIR:${SCP_FIRMWARE_TARGET}>/lib${SCP_FIRMWARE_LIB}.a ${scp_libraries} 581 COMMENT " Merging all libraries in a single lib${SCP_FIRMWARE_LIB}.a" 582) 583 584add_dependencies(${SCP_FIRMWARE_LIB} ${SCP_FIRMWARE_TARGET}) 585 586# 587# Set up global inclusions and exclusions for source file quality assurance 588# tools. This is intended to filter in external directories (e.g. out-of-tree 589# modules) and filter out third-party directories. 590# 591 592list(APPEND glob_includes "${SCP_SOURCE_DIR}") 593 594list(APPEND glob_excludes "^${SCP_SOURCE_DIR}/contrib/cmsis/git") 595list(APPEND glob_excludes "^${SCP_SOURCE_DIR}/contrib/run-clang-format/git") 596 597list(APPEND cmake_globs "CMakeLists.txt") 598list(APPEND cmake_globs "*.cmake") 599 600list(APPEND markdown_globs "*.md") 601 602list(APPEND yaml_globs "*.yml") 603list(APPEND yaml_globs "*.yaml") 604 605list(APPEND c_globs "*.[ch]") 606list(APPEND c_globs "*.[ch]pp") 607list(APPEND c_globs "*.[ch]xx") 608 609# 610# Glob sources and place them in their respective variables. Globs for source 611# types can be with specified with a `${type}_globs` variable, which should be a 612# list of globs to be fed into `file(GLOB_RECURSE ...)`. 613# 614 615# cmake-lint: disable=C0103 616 617foreach(type cmake markdown yaml c) 618 unset(sources) 619 620 foreach(include IN LISTS glob_includes) 621 foreach(glob IN LISTS ${type}_globs) 622 file(GLOB_RECURSE _sources "${include}/${glob}") 623 list(APPEND sources ${_sources}) 624 endforeach() 625 endforeach() 626 627 foreach(exclude IN LISTS glob_excludes) 628 list(FILTER sources EXCLUDE REGEX "${exclude}") 629 endforeach() 630 631 set(${type}_sources ${sources}) 632endforeach() 633 634# 635# Configure cmake-format. 636# 637 638find_package(CMakeFormat OPTIONAL_COMPONENTS Format Lint) 639 640if(TARGET CMakeFormat::Format) 641 add_custom_target( 642 format-cmake 643 COMMAND CMakeFormat::Format -i "${cmake_sources}" 644 WORKING_DIRECTORY "${SCP_SOURCE_DIR}" 645 COMMENT "Formatting CMake sources..." 646 COMMAND_EXPAND_LISTS) 647 648 list(APPEND format_targets "format-cmake") 649 650 add_custom_target( 651 check-cmake 652 COMMAND CMakeFormat::Format --check "${cmake_sources}" 653 WORKING_DIRECTORY "${SCP_SOURCE_DIR}" 654 COMMENT "Checking CMake sources..." 655 COMMAND_EXPAND_LISTS) 656 657 list(APPEND check_targets "check-cmake") 658endif() 659 660if(TARGET CMakeFormat::Lint) 661 add_custom_target( 662 lint-cmake 663 COMMAND CMakeFormat::Lint --suppress-decorations "${cmake_sources}" 664 WORKING_DIRECTORY "${SCP_SOURCE_DIR}" 665 COMMENT "Linting CMake sources..." 666 COMMAND_EXPAND_LISTS) 667 668 list(APPEND lint_targets "lint-cmake") 669endif() 670 671# 672# Configure markdownlint. 673# 674 675find_package(Markdownlint) 676 677if(Markdownlint_FOUND) 678 add_custom_target( 679 lint-markdown 680 COMMAND Markdownlint "${markdown_sources}" 681 WORKING_DIRECTORY "${SCP_SOURCE_DIR}" 682 COMMENT "Running Markdown sources..." 683 COMMAND_EXPAND_LISTS) 684 685 list(APPEND lint_targets "lint-markdown") 686endif() 687 688# 689# Configure yaml-format. 690# 691 692find_package(Python3 COMPONENTS Interpreter) 693 694if(Python3_Interpreter_FOUND) 695 add_custom_target( 696 format-yaml 697 COMMAND Python3::Interpreter "${SCP_SOURCE_DIR}/tools/yaml-format.py" 698 format -i "${yaml_sources}" 699 WORKING_DIRECTORY "${SCP_SOURCE_DIR}" 700 COMMENT "Formatting YAML sources..." 701 COMMAND_EXPAND_LISTS) 702 703 list(APPEND format_targets "format-yaml") 704 705 add_custom_target( 706 check-yaml 707 COMMAND Python3::Interpreter "${SCP_SOURCE_DIR}/tools/yaml-format.py" 708 diff --check "${yaml_sources}" 709 WORKING_DIRECTORY "${SCP_SOURCE_DIR}" 710 COMMENT "Checking YAML sources..." 711 COMMAND_EXPAND_LISTS) 712 713 list(APPEND check_targets "check-yaml") 714endif() 715 716# 717# Configure yamllint. 718# 719 720find_package(Yamllint) 721 722if(Yamllint_FOUND) 723 add_custom_target( 724 lint-yaml 725 COMMAND Yamllint -s "${yaml_sources}" 726 WORKING_DIRECTORY "${SCP_SOURCE_DIR}" 727 COMMENT "Linting YAML sources..." 728 COMMAND_EXPAND_LISTS) 729 730 list(APPEND lint_targets "lint-yaml") 731endif() 732 733# 734# Configure Clang-Format. 735# 736 737find_package(Clang OPTIONAL_COMPONENTS Format FormatGit) 738 739if(Clang_FormatGit_FOUND) 740 add_custom_target( 741 format-diff-c 742 COMMAND Clang::FormatGit HEAD 743 WORKING_DIRECTORY "${SCP_SOURCE_DIR}" 744 COMMENT "Formatting modified C/C++ sources..." 745 COMMAND_EXPAND_LISTS) 746 747 list(APPEND format_diff_targets "format-diff-c") 748endif() 749 750if(Clang_Format_FOUND) 751 add_custom_target( 752 format-c 753 COMMAND Clang::Format -i "${c_sources}" 754 WORKING_DIRECTORY "${SCP_SOURCE_DIR}" 755 COMMENT "Formatting C/C++ sources..." 756 COMMAND_EXPAND_LISTS) 757 758 list(APPEND format_targets "format-c") 759endif() 760 761# 762# Configure run-clang-format. 763# 764 765find_package(Python3 COMPONENTS Interpreter) 766 767if(Python3_Interpreter_FOUND) 768 add_custom_target( 769 check-c 770 COMMAND 771 Python3::Interpreter 772 "${SCP_SOURCE_DIR}/contrib/run-clang-format/git/run-clang-format.py" 773 --clang-format-executable "${Clang_Format_EXECUTABLE}" 774 "${c_sources}" 775 WORKING_DIRECTORY "${SCP_SOURCE_DIR}" 776 COMMENT "Checking C sources..." 777 COMMAND_EXPAND_LISTS) 778 779 list(APPEND check_targets "check-c") 780endif() 781 782# 783# Create the final check targets. These targets consist of miscellaneous quality 784# assurance tasks like linting and formatting, and act as dummy targets that 785# invoke the various tools we set up above. 786# 787 788add_custom_target( 789 format-diff 790 DEPENDS ${format_diff_targets} 791 COMMENT "Formatting modified sources...") 792 793add_custom_target( 794 format 795 DEPENDS ${format_targets} 796 COMMENT "Formatting all sources...") 797 798add_custom_target( 799 lint 800 DEPENDS ${lint_targets} 801 COMMENT "Linting all sources...") 802 803add_custom_target( 804 check 805 DEPENDS ${check_targets} lint 806 COMMENT "Checking lint...") 807