1# 2# Arm SCP/MCP Software 3# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved. 4# 5# SPDX-License-Identifier: BSD-3-Clause 6# 7 8include_guard() 9 10# cmake-lint: disable=C0113,C0301 11 12# .rst: 13# 14# .. command:: scp_preprocess_source 15# 16# Preprocess a file with the C preprocessor. 17# 18# .. cmake:: scp_preprocess_source(<target> <source> <output>) 19# 20# This macro creates a target ``<target>`` which preprocesses a source file 21# ``<source>``, giving the file ``<output>``. 22# 23# You can set properties on the target created by this macro through the 24# standard means. If you wish you to add extra compile definitions or include 25# directories, you can do so by manually adding them to the 26# ``INCLUDE_DIRECTORIES`` and ``COMPILE_DEFINITIONS`` target properties. 27# ``target_include_directories`` and friends cannot be used on the target 28# created by this macro. 29macro(scp_preprocess_source target source output) 30 # 31 # CMake provides the `CMAKE_C_CREATE_PREPROCESSED_SOURCE` variable, which 32 # describes the command line required to preprocess a C source file. This 33 # variable is in a format similar to this: 34 # 35 # <CMAKE_C_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > 36 # <PREPROCESSED_SOURCE> 37 # 38 # We do some processing on this variable to convert these bracket-surrounded 39 # names to variables we set. For example, `<DEFINES>` is replaced with 40 # `${cpp_DEFINES}`. We then need to do some string replacement magic to 41 # expand that string out to the value of the actual variable. 42 # 43 # The values for some of these, namely include directories, definitions and 44 # other compiler options, come from properties set on the target by the 45 # caller. These are typically taken from the target that this preprocessed 46 # source file. 47 # 48 49 set(command ${CMAKE_C_CREATE_PREPROCESSED_SOURCE}) 50 string(REPLACE " " ";" command ${command}) 51 52 string(TOUPPER ${CMAKE_BUILD_TYPE} config) 53 54 set(cpp_SOURCE "${source}") 55 set(cpp_PREPROCESSED_SOURCE "${output}") 56 57 set(cpp_CMAKE_C_COMPILER "${CMAKE_C_COMPILER}") 58 59 unset(cpp_DEFINES) 60 unset(cpp_INCLUDES) 61 62 # cmake-format: off 63 64 separate_arguments(cpp_FLAGS 65 UNIX_COMMAND "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_${config}} -P") 66 67 list(APPEND cpp_FLAGS "$<TARGET_PROPERTY:${target},COMPILE_OPTIONS>") 68 list(APPEND cpp_DEFINES "$<TARGET_PROPERTY:${target},COMPILE_DEFINITIONS>") 69 list(APPEND cpp_INCLUDES "$<TARGET_PROPERTY:${target},INCLUDE_DIRECTORIES>") 70 71 set(cpp_DEFINES "$<$<BOOL:${cpp_DEFINES}>:-D$<JOIN:${cpp_DEFINES},$<SEMICOLON>-D>>") 72 set(cpp_INCLUDES "$<$<BOOL:${cpp_INCLUDES}>:-I$<JOIN:${cpp_INCLUDES},$<SEMICOLON>-I>>") 73 74 # cmake-format: on 75 76 string(REGEX REPLACE "<([[A-Z_]+)>" "\${cpp_\\1}" command "${command}") 77 string(REGEX MATCH "\\\${[^}]*}" match "${command}") 78 79 while(match) 80 string(REGEX REPLACE "\\\${(.*)}" "\\1" variable "${match}") 81 string(REPLACE "\${${variable}}" "${${variable}}" command "${command}") 82 string(REGEX MATCH "\\\${[^}]*}" match "${command}") 83 endwhile() 84 85 add_custom_command( 86 OUTPUT ${output} 87 MAIN_DEPENDENCY ${source} 88 COMMAND "${command}" 89 VERBATIM COMMAND_EXPAND_LISTS) 90 91 add_custom_target(${target} DEPENDS ${output}) 92endmacro() 93