mirror of https://github.com/ARMmbed/mbed-os.git
161 lines
7.3 KiB
CMake
161 lines
7.3 KiB
CMake
# Copyright (c) 2021 ARM Limited. All rights reserved.
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
# This script provides mbed_create_distro(), a function that combines a tree of INTERFACE targets
|
|
# into a single library target, copying properties appropriately.
|
|
|
|
# Append the value of PROPERTY from SOURCE to the value of PROPERTY on DESTINATION
|
|
function(copy_append_property PROPERTY SOURCE DESTINATION)
|
|
get_property(PROP_IS_DEFINED TARGET ${SOURCE} PROPERTY ${PROPERTY} SET)
|
|
if(PROP_IS_DEFINED)
|
|
get_property(PROP_VALUE TARGET ${SOURCE} PROPERTY ${PROPERTY})
|
|
set_property(TARGET ${DESTINATION} APPEND PROPERTY ${PROPERTY} "${PROP_VALUE}")
|
|
endif()
|
|
endfunction(copy_append_property)
|
|
|
|
# Create a "distribution" of Mbed OS containing the base Mbed and certain modules.
|
|
# This distribution only needs to be compiled once and can be referenced in an arbitrary amount of targets.
|
|
function(mbed_create_distro NAME) # ARGN: modules...
|
|
|
|
# Use an OBJECT library so that weak symbol resolution works properly
|
|
add_library(${NAME} OBJECT EXCLUDE_FROM_ALL)
|
|
|
|
# Workaround to ensure that everything that links to this library receives its objects, including other object libraries
|
|
# from here: https://gitlab.kitware.com/cmake/cmake/-/issues/18090#note_1041608
|
|
target_sources(${NAME} INTERFACE $<TARGET_OBJECTS:${NAME}>)
|
|
|
|
# Now copy include dirs, compile defs, and compile options (but NOT interface source files) over
|
|
# to the distribution target so they will be passed into things that link to it.
|
|
# To do this, we need to recursively traverse the tree of dependencies.
|
|
set(REMAINING_MODULES ${ARGN})
|
|
set(COMPLETED_MODULES ${ARGN})
|
|
while(NOT "${REMAINING_MODULES}" STREQUAL "")
|
|
|
|
#message("Distro: ${NAME}. REMAINING_MODULES: ${REMAINING_MODULES}")
|
|
|
|
list(GET REMAINING_MODULES 0 CURR_MODULE)
|
|
list(REMOVE_AT REMAINING_MODULES 0)
|
|
|
|
if(TARGET "${CURR_MODULE}")
|
|
|
|
get_property(CURR_MODULE_TYPE TARGET ${CURR_MODULE} PROPERTY TYPE)
|
|
|
|
# Pass up mbed linker script property, which is used by the top level code to select the linker script
|
|
copy_append_property(INTERFACE_MBED_LINKER_SCRIPT ${CURR_MODULE} ${NAME})
|
|
|
|
if("${CURR_MODULE_TYPE}" STREQUAL "STATIC_LIBRARY")
|
|
# Don't need to do anything other than linking it
|
|
target_link_libraries(${NAME} PUBLIC ${CURR_MODULE})
|
|
else()
|
|
# Make sure that linking to the distro pulls in the compiled code from CURR_MODULE
|
|
target_link_libraries(${NAME} PRIVATE ${CURR_MODULE})
|
|
|
|
copy_append_property(INTERFACE_COMPILE_DEFINITIONS ${CURR_MODULE} ${NAME})
|
|
copy_append_property(INTERFACE_COMPILE_OPTIONS ${CURR_MODULE} ${NAME})
|
|
copy_append_property(INTERFACE_INCLUDE_DIRECTORIES ${CURR_MODULE} ${NAME})
|
|
copy_append_property(INTERFACE_LINK_OPTIONS ${CURR_MODULE} ${NAME})
|
|
|
|
# Additionally, interface libraries can export precompiled .o files as sources.
|
|
# We need to copy these to the interface sources of the distro, because adding a .o
|
|
# to the sources of an object library does nothing.
|
|
get_property(CURR_MODULE_INTERFACE_SOURCES TARGET ${CURR_MODULE} PROPERTY INTERFACE_SOURCES)
|
|
foreach(INTERFACE_SOURCE ${CURR_MODULE_INTERFACE_SOURCES})
|
|
if("${INTERFACE_SOURCE}" MATCHES ".o$" OR "${INTERFACE_SOURCE}" MATCHES ".obj$")
|
|
# Object file found
|
|
target_sources(${NAME} INTERFACE ${INTERFACE_SOURCE})
|
|
endif()
|
|
endforeach()
|
|
|
|
# CMake currently has a limitation that OBJECT libraries cannot link to other OBJECT libraries
|
|
# via the LINK_LIBRARIES property -- CMake will not link the objects in properly :/.
|
|
# see: https://cmake.org/pipermail/cmake/2019-May/069453.html
|
|
# also: https://gitlab.kitware.com/cmake/cmake/-/issues/18090
|
|
|
|
if("${CURR_MODULE_TYPE}" STREQUAL "OBJECT_LIBRARY")
|
|
target_sources(${NAME} INTERFACE $<TARGET_OBJECTS:${CURR_MODULE}>)
|
|
|
|
# Check if this object library has any other libraries exported through its INTERFACE_SOURCES.
|
|
# If it does, we need to propagate those too.
|
|
foreach(INTERFACE_SOURCE ${CURR_MODULE_INTERFACE_SOURCES})
|
|
if(INTERFACE_SOURCE MATCHES "\\$<TARGET_OBJECTS:.*>")
|
|
target_sources(${NAME} INTERFACE ${INTERFACE_SOURCE})
|
|
endif()
|
|
endforeach()
|
|
endif()
|
|
|
|
|
|
list(APPEND COMPLETED_MODULES ${CURR_MODULE})
|
|
|
|
# find sub-modules of this module
|
|
get_property(SUBMODULES TARGET ${CURR_MODULE} PROPERTY INTERFACE_LINK_LIBRARIES)
|
|
foreach(SUBMODULE ${SUBMODULES})
|
|
if(NOT "${SUBMODULE}" MATCHES "::@") # remove CMake internal CMAKE_DIRECTORY_ID_SEP markers
|
|
# Remove LINK_ONLY genexes from target_link_libraries(... PRIVATE). We can ignore things wrapped in these
|
|
# because they will already have been handled by the target_link_libraries earlier on.
|
|
if(NOT "${SUBMODULE}" MATCHES "\\$<LINK_ONLY:.*>")
|
|
if(NOT ${SUBMODULE} IN_LIST COMPLETED_MODULES)
|
|
list(APPEND REMAINING_MODULES ${SUBMODULE})
|
|
endif()
|
|
endif()
|
|
endif()
|
|
endforeach()
|
|
endif()
|
|
else()
|
|
# Module is not a target, it's something else like a linker flag or a generator expression
|
|
# So, just link it to the output.
|
|
target_link_libraries(${NAME} INTERFACE ${CURR_MODULE})
|
|
endif()
|
|
|
|
endwhile()
|
|
|
|
endfunction(mbed_create_distro)
|
|
|
|
# Traverse a tree of targets and create an interface target containing all of the flags (includes/compile options/
|
|
# etc) but none of the source files extracted from those targets.
|
|
# This is mainly used as a shim so that we don't need to edit 100s of target CMake files and separate out the targets
|
|
# containing flags from the targets containing source files.
|
|
function(mbed_extract_flags NAME) # ARGN: modules...
|
|
add_library(${NAME} INTERFACE)
|
|
|
|
# Now copy include dirs, compile defs, and compile options (but NOT interface source files) over
|
|
# to the distribution target so they will be passed into things that link to it.
|
|
# To do this, we need to recursively traverse the tree of dependencies.
|
|
set(REMAINING_MODULES ${ARGN})
|
|
set(COMPLETED_MODULES ${ARGN})
|
|
while(NOT "${REMAINING_MODULES}" STREQUAL "")
|
|
|
|
#message("Flags: ${NAME}. REMAINING_MODULES: ${REMAINING_MODULES}")
|
|
|
|
list(GET REMAINING_MODULES 0 CURR_MODULE)
|
|
list(REMOVE_AT REMAINING_MODULES 0)
|
|
|
|
if(TARGET "${CURR_MODULE}")
|
|
copy_append_property(INTERFACE_COMPILE_DEFINITIONS ${CURR_MODULE} ${NAME})
|
|
copy_append_property(INTERFACE_COMPILE_OPTIONS ${CURR_MODULE} ${NAME})
|
|
copy_append_property(INTERFACE_INCLUDE_DIRECTORIES ${CURR_MODULE} ${NAME})
|
|
copy_append_property(INTERFACE_LINK_OPTIONS ${CURR_MODULE} ${NAME})
|
|
|
|
list(APPEND COMPLETED_MODULES ${CURR_MODULE})
|
|
|
|
# find sub-modules of this module
|
|
get_property(SUBMODULES TARGET ${CURR_MODULE} PROPERTY INTERFACE_LINK_LIBRARIES)
|
|
foreach(SUBMODULE ${SUBMODULES})
|
|
if(NOT "${SUBMODULE}" MATCHES "::@") # remove CMake internal CMAKE_DIRECTORY_ID_SEP markers
|
|
# Remove LINK_ONLY genexes from target_link_libraries(... PRIVATE). We can ignore things wrapped in these
|
|
# because they will already have been handled by the target_link_libraries earlier on.
|
|
if(NOT "${SUBMODULE}" MATCHES "\\$<LINK_ONLY:.*>")
|
|
if(NOT ${SUBMODULE} IN_LIST COMPLETED_MODULES)
|
|
list(APPEND REMAINING_MODULES ${SUBMODULE})
|
|
endif()
|
|
endif()
|
|
endif()
|
|
endforeach()
|
|
else()
|
|
# Module is not a target, it's something else like a linker flag or a generator expression
|
|
# So, just link it to the output.
|
|
target_link_libraries(${NAME} INTERFACE ${CURR_MODULE})
|
|
endif()
|
|
|
|
endwhile()
|
|
|
|
endfunction(mbed_extract_flags) |