diff --git a/tools/cmakev2/build.cmake b/tools/cmakev2/build.cmake index 3ed7b3a95ce..f8a8e7307a0 100644 --- a/tools/cmakev2/build.cmake +++ b/tools/cmakev2/build.cmake @@ -88,3 +88,162 @@ function(__dump_build_properties) idf_msg(" ${property}: ${value}") endforeach() endfunction() + +#[[ + __get_library_interface_or_die(LIBRARY + OUTPUT ) + + :LIBRARY[in]: Library interface or alias. + :OUTPUT[out]: Output variable to store the library interface. + + Verify that "LIBRARY" is a known interface created by ``idf_build_library`` + or its alias. If it is, return the library interface; otherwise, terminate + the build process. +#]] +function(__get_library_interface_or_die) + set(options) + set(one_value LIBRARY OUTPUT) + set(multi_value) + cmake_parse_arguments(ARG "${options}" "${one_value}" "${multi_value}" ${ARGN}) + + if(NOT DEFINED ARG_LIBRARY) + idf_die("LIBRARY option is required") + endif() + + if(NOT DEFINED ARG_OUTPUT) + idf_die("OUTPUT option is required") + endif() + + __get_real_target(TARGET ${ARG_LIBRARY} OUTPUT library_interface) + idf_build_get_property(library_interfaces LIBRARY_INTERFACES) + + if(NOT "${library_interface}" IN_LIST library_interfaces) + idf_die("Library interface '${ARG_LIBRARY}' does not exist") + endif() + set(${ARG_OUTPUT} ${library_interface} PARENT_SCOPE) +endfunction() + +#[[api +.. cmakev2:function:: idf_library_set_property + + .. code-block:: cmake + + idf_library_set_property( [APPEND]) + + :library[in]: Library interface target or alias. + :property[in]: Property name. + :value[in]: Property value. + :APPEND: Append the value to the property's current value instead of + replacing it. + + Set the value of the specified library property. The property is also + added to the internal list of library properties if it isn't already + there. +#]] +function(idf_library_set_property library property value) + set(options APPEND) + set(one_value) + set(multi_value) + cmake_parse_arguments(ARG "${options}" "${one_value}" "${multi_value}" ${ARGN}) + + set(append) + if(ARG_APPEND) + set(append APPEND) + endif() + + __get_library_interface_or_die(LIBRARY "${library}" OUTPUT library_interface) + __set_property(TARGET "${library_interface}" + PROPERTY "${property}" + PROPERTIES LIBRARY_PROPERTIES + VALUE "${value}" + ${append}) +endfunction() + +#[[api +.. cmakev2:function:: idf_library_get_property + + .. code-block:: cmake + + idf_library_get_property( [GENERATOR_EXPRESSION]) + + :variable[out]: Variable to store the value in. + :library[in]: Library interface target or alias. + :property[in]: Property name to get the value of. + :GENERATOR_EXPRESSION: Obtain the generator expression for the property + rather than the actual value. + + Retrieve the value of the specified library property. +#]] +function(idf_library_get_property variable library property) + set(options GENERATOR_EXPRESSION) + set(one_value) + set(multi_value) + cmake_parse_arguments(ARG "${options}" "${one_value}" "${multi_value}" ${ARGN}) + + set(genexpr) + if(ARG_GENERATOR_EXPRESSION) + set(genexpr GENERATOR_EXPRESSION) + endif() + + __get_library_interface_or_die(LIBRARY "${library}" OUTPUT library_interface) + __get_property(TARGET "${library_interface}" + PROPERTY "${property}" + OUTPUT value + ${genexpr}) + set(${variable} ${value} PARENT_SCOPE) +endfunction() + +#[[ + __dump_library_properties() + + :libraries: List of library interfaces whose properties should be displayed. + + Dump all properties for the libraries listed in ````. +#]] +function(__dump_library_properties libraries) + foreach(library IN LISTS libraries) + idf_library_get_property(properties "${library}" LIBRARY_PROPERTIES) + idf_msg("library '${library}' properties: ${properties}") + foreach(property IN LISTS properties) + idf_library_get_property(value "${library}" "${property}") + idf_msg(" ${property}: ${value}") + endforeach() + endforeach() +endfunction() + +#[[api +.. cmakev2:function:: idf_build_library + + .. code-block:: cmake + + idf_build_library(INTERFACE + [COMPONENTS ...]) + + :INTERFACE[in,out]: Name of the library interface to be created. + :COMPONENTS[in,opt]: List of component names to add to the library. + + Create a new library interface target with the name specified in the + ``INTERFACE`` option and link component targets to it based on the component + names provided in the ``COMPONENTS`` option. If ``COMPONENTS`` option is not + set, link component targets of all discovered components. +#]] +function(idf_build_library) + set(options) + set(one_value INTERFACE) + set(multi_value COMPONENTS) + cmake_parse_arguments(ARG "${options}" "${one_value}" "${multi_value}" ${ARGN}) + + if(NOT DEFINED ARG_INTERFACE) + idf_die("INTERFACE option is required") + endif() + + if(NOT DEFINED ARG_COMPONENTS) + # The library should include all discovered components. + idf_build_get_property(component_names COMPONENTS_DISCOVERED) + set(ARG_COMPONENTS "${component_names}") + endif() + + add_library("${ARG_INTERFACE}" INTERFACE) + idf_build_set_property(LIBRARY_INTERFACES "${ARG_INTERFACE}" APPEND) + idf_library_set_property("${ARG_INTERFACE}" LIBRARY_COMPONENTS "${ARG_COMPONENTS}") +endfunction() diff --git a/tools/cmakev2/test/CMakeLists.txt b/tools/cmakev2/test/CMakeLists.txt index 681600fbd4d..db296d7a148 100644 --- a/tools/cmakev2/test/CMakeLists.txt +++ b/tools/cmakev2/test/CMakeLists.txt @@ -14,6 +14,8 @@ function(test_dump_properties) __dump_build_properties() idf_build_get_property(component_names COMPONENTS_DISCOVERED) __dump_component_properties("${component_names}") + idf_build_get_property(library_interfaces LIBRARY_INTERFACES) + __dump_library_properties("${library_interfaces}") endfunction() # Test component priority @@ -100,11 +102,49 @@ function(test_toolchain) endif() endfunction() +# Test idf_build_library +function(test_idf_build_library) + # Create idflibtest with specific set of components and test that it + # contains them. + set(components app_trace app_update bootloader bootloader_support bt cmock) + + set(idflib idflibtest) + idf_build_library(INTERFACE "${idflib}" + COMPONENTS "${components}") + + if(NOT TARGET "${idflib}") + idf_die("'${idflib}' not created") + endif() + + idf_library_get_property(lib_components "${idflib}" LIBRARY_COMPONENTS) + if(NOT "${lib_components}" STREQUAL "${components}") + idf_die("Library '${idflib}' components '${lib_components}' do not match " + "expected components '${components}'") + endif() + + # Create idflibtest2 without specifying COMPONENTS and test that it + # contains all discovered components. + set(idflib idflibtest2) + idf_build_library(INTERFACE "${idflib}") + + if(NOT TARGET "${idflib}") + idf_die("'${idflib}' not created") + endif() + + idf_library_get_property(lib_components "${idflib}" LIBRARY_COMPONENTS) + idf_build_get_property(component_names COMPONENTS_DISCOVERED) + if(NOT "${lib_components}" STREQUAL "${component_names}") + idf_die("Library '${idflib}' components '${lib_components}' do not match " + "COMPONENTS_DISCOVERED") + endif() +endfunction() + # Run tests -test_dump_properties() test_component_priority() test_idf_version() test_python() test_toolchain() +test_idf_build_library() +test_dump_properties() message("ALL TESTS PASSED")