From 2b3195268ae1a49d175804a458fc4f823cc3d9ac Mon Sep 17 00:00:00 2001 From: M Starch Date: Thu, 11 Jun 2026 15:29:30 -0700 Subject: [PATCH 1/7] Streamlining the handling of locations and include roots in F Prime CMake --- Fw/Types/CMakeLists.txt | 3 +- cmake/API.cmake | 43 +++++----- cmake/FPrime.cmake | 36 ++------- cmake/autocoder/fpp.cmake | 45 ++++++++--- cmake/autocoder/fpp_ut.cmake | 9 +-- cmake/config_assembler.cmake | 4 +- cmake/global_interface.cmake | 81 +++++++++++++++++++ cmake/sub-build/sub-build-config.cmake | 1 - cmake/target/sub-build/module_info.cmake | 7 +- .../data/cmake/target/test_recursion.cmake | 3 +- cmake/utilities.cmake | 16 +++- 11 files changed, 163 insertions(+), 85 deletions(-) create mode 100644 cmake/global_interface.cmake diff --git a/Fw/Types/CMakeLists.txt b/Fw/Types/CMakeLists.txt index 3698ad4edc6..74bd8c43ff5 100644 --- a/Fw/Types/CMakeLists.txt +++ b/Fw/Types/CMakeLists.txt @@ -1,6 +1,7 @@ #### # F prime CMakeLists.txt: #### +include(global_interface) register_fprime_module( Fw_Types SOURCES @@ -17,7 +18,7 @@ register_fprime_module( AUTOCODER_INPUTS "${CMAKE_CURRENT_LIST_DIR}/Types.fpp" DEPENDS - __fprime_config # Only module that should ever list __fprime_config in DEPENDS. Use Fw_Types instead. + ${FPRIME_GLOBAL_INTERFACE_TARGET} # Most users should prefer Fw_Types instead over the direct global interface. REQUIRES_IMPLEMENTATIONS Fw_StringFormat Fw_StringScan diff --git a/cmake/API.cmake b/cmake/API.cmake index 3d9cb4eeaf3..0396e467a04 100644 --- a/cmake/API.cmake +++ b/cmake/API.cmake @@ -17,14 +17,11 @@ include(module) include(config_assembler) include(sub-build/sub-build) include(fprime-util) +include(global_interface) + set(FPRIME_TARGET_LIST "" CACHE INTERNAL "FPRIME_TARGET_LIST: custom fprime targets" FORCE) set(FPRIME_UT_TARGET_LIST "" CACHE INTERNAL "FPRIME_UT_TARGET_LIST: custom fprime targets" FORCE) set(FPRIME_AUTOCODER_TARGET_LIST "" CACHE INTERNAL "FPRIME_AUTOCODER_TARGET_LIST: custom fprime targets" FORCE) -set(FPRIME_GLOBAL_INTERFACE_TARGET "_fprime_global_interface_target" CACHE INTERNAL "FPRIME_GLOBAL_INTERFACE_TARGETS: global interface targets" FORCE) -# Create a singleton global interface target -if (NOT TARGET "${FPRIME_GLOBAL_INTERFACE_TARGET}") - add_library("${FPRIME_GLOBAL_INTERFACE_TARGET}" INTERFACE) -endif() #### # Macro `skip_on_sub_build`: @@ -106,8 +103,8 @@ endmacro() # directories. This creates a directed acyclic graph of modules, one subgraph of which will be built # for each executable/module/library defined in the system. The subgraph should also be a DAG. # -# This directory is computed based off the closest path in `FPRIME_BUILD_LOCATIONS`. It must be set to -# be used. Otherwise, an error will occur. `EXCLUDE_FROM_ALL` can also be supplied. +# This directory is computed based off the closest path in `FPRIME_LOCATIONS` of the global interface. +# # See: https://cmake.org/cmake/help/latest/command/add_fprime_subdirectory.html # # **Note:** Replaces CMake `add_subdirectory` call in order to automate the [binary_dir] argument. @@ -469,16 +466,19 @@ function(fprime_add_config_build_target) # The new module should include the root configuration directory fprime_target_include_directories("${INTERNAL_MODULE_NAME}" PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/..") - # The configuration target should depend on the new module + # When the configuration is marked as BASE_CONFIG, this implies that the entire build system should have access to + # the configuration. Thus, we link the configuration module into the global interface target allowing any module + # to pull in the dependency. if (INTERNAL_BASE_CONFIG) - target_link_libraries("${FPRIME__INTERNAL_CONFIG_TARGET_NAME}" INTERFACE "${INTERNAL_MODULE_NAME}") + target_link_libraries("${FPRIME_GLOBAL_INTERFACE_TARGET}" INTERFACE "${INTERNAL_MODULE_NAME}") endif() # Set up the new module to be marked as FPRIME_CONFIGURATION append_list_property("${INTERNAL_MODULE_NAME}" GLOBAL PROPERTY "FPRIME_CONFIG_MODULES") set_property(TARGET "${INTERNAL_MODULE_NAME}" PROPERTY FPRIME_CONFIGURATION TRUE) # Targets likely do not exist yet, so just aggregate the complete list of chosen implementations # for processing later - append_list_property("${INTERNAL_CHOOSES_IMPLEMENTATIONS}" TARGET "${FPRIME__INTERNAL_CONFIG_TARGET_NAME}" PROPERTY FPRIME_CHOSEN_IMPLEMENTATIONS) + append_list_property("${INTERNAL_CHOOSES_IMPLEMENTATIONS}" TARGET "${FPRIME_GLOBAL_INTERFACE_TARGET}" PROPERTY + FPRIME_CHOSEN_IMPLEMENTATIONS) # Static libraries must be position independent when building shared libraries get_target_property(CONFIG_LIBRARY_TYPE "${INTERNAL_MODULE_NAME}" TYPE) @@ -734,10 +734,11 @@ endfunction() # Macro `register_fprime_project`: # # Used to register an F Prime project. This will do the following: -# 1. Add the current source directory to the FPRIME_BUILD_LOCATIONS property -# 2. Add the current source directory to the global include directories -# 3. Add the current binary directory to the global include directories -# 4. Add the current source directory to the CMAKE_PATH_PREFIX variable for this module +# 1. Add the current source directory to the FPRIME_LOCATIONS property of the global interface +# 2. Add the current binary directory to the FPRIME_LOCATIONS property of the global interface +# 3. Add the current source directory to the global include directories +# 4. Add the current binary directory to the global include directories +# 5. Add the current source directory to the CMAKE_PATH_PREFIX variable for this module # This allows it to be found and used by other modules in the build system. It ensures that the components are properly # slotted underneath this library for the purposed of include path and target names. # Args: none @@ -750,19 +751,15 @@ macro(register_fprime_project) endif() # Add to the build locations property - append_list_property("${CMAKE_CURRENT_SOURCE_DIR}" GLOBAL PROPERTY FPRIME_PROJECT_LOCATIONS) - # Add source and binaries to the interface includes of our singular global interface target - target_include_directories("${FPRIME_GLOBAL_INTERFACE_TARGET}" INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}") - target_include_directories("${FPRIME_GLOBAL_INTERFACE_TARGET}" INTERFACE "${CMAKE_CURRENT_BINARY_DIR}") + fprime_add_location_pair("${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}") - # Backwards compatibility: update the build locations variable as well - set(FPRIME_BUILD_LOCATIONS "${CMAKE_CURRENT_SOURCE_DIR};${FPRIME_BUILD_LOCATIONS}" CACHE INTERNAL "FPRIME_BUILD_LOCATIONS: list of source directories containing fprime modules" FORCE) # Backwards compatibility: bridge the interface target include directories back into the include_directories directive include_directories("$") - # Update the CMAKE_MODULE_PATH for this particular project - get_property(FPRIME_PROJECT_LOCATIONS GLOBAL PROPERTY FPRIME_PROJECT_LOCATIONS) - foreach (PROJECT_LOCATION IN LISTS FPRIME_PROJECT_LOCATIONS) + # Update the CMAKE_MODULE_PATH for this particular project. This has to be done for each project because + # CMAKE_MODULE_PATH is not a cache variable. + get_property(FPRIME_LOCATIONS TARGET "${FPRIME_GLOBAL_INTERFACE_TARGET}" PROPERTY FPRIME_LOCATIONS) + foreach (PROJECT_LOCATION IN LISTS FPRIME_LOCATIONS) list(APPEND CMAKE_MODULE_PATH "${PROJECT_LOCATION}/cmake") endforeach() set(FPRIME_CURRENT_PROJECT_PATH "${CMAKE_CURRENT_SOURCE_DIR}") diff --git a/cmake/FPrime.cmake b/cmake/FPrime.cmake index 42d1b6a2d62..92b257183a2 100644 --- a/cmake/FPrime.cmake +++ b/cmake/FPrime.cmake @@ -12,6 +12,7 @@ include(utilities) include(options) include(sanitizers) # Enable sanitizers if they are requested include(required) +include(global_interface) include(config_assembler) include(fprime-util) @@ -30,21 +31,9 @@ if (IS_DIRECTORY "${FPRIME_PROJECT_ROOT}/_fprime_packages") endif() endif() -# Setup fprime library locations -list(REMOVE_DUPLICATES FPRIME_LIBRARY_LOCATIONS) +# Adds the historical locations to the global interface target. +fprime_add_historical_locations() -# F Prime build locations represent the root of the module paths in F Prime. This allows us to detect module names from the -# paths to given files. -# Now that modules can build within the build cache, the build cache locations (root, F-Prime) are added to the list of -# locations. This allows for the detection of modules that are built within the build cache. -set(FPRIME_BUILD_LOCATIONS "${FPRIME_FRAMEWORK_PATH}" ${FPRIME_LIBRARY_LOCATIONS} "${FPRIME_PROJECT_ROOT}" - "${CMAKE_BINARY_DIR}/F-Prime" "${CMAKE_BINARY_DIR}" CACHE INTERNAL "List of root locations for F Prime modules" FORCE) -list(REMOVE_DUPLICATES FPRIME_BUILD_LOCATIONS) -resolve_path_variables(FPRIME_BUILD_LOCATIONS) - -# Message describing the fprime setup -fprime_cmake_status("[FPRIME] Module locations: ${FPRIME_BUILD_LOCATIONS}") -fprime_cmake_status("[FPRIME] Installation directory: ${CMAKE_INSTALL_PREFIX}") include(platform/platform) # Now that module locations are known, load platform settings fprime_validate_platform() @@ -66,21 +55,6 @@ include(API) include(sub-build/sub-build) # C and C++ settings for building the framework include(settings) -#### -# Function `fprime_setup_global_includes`: -# -# Adds basic include directories that make fprime work. This ensures that configuration, framework, and project all -# function as expected. This will also include the internal build-cache directories. -#### -function(fprime_setup_global_includes) - # Setup the global include directories that exist outside of the build cache - include_directories("${FPRIME_FRAMEWORK_PATH}") - include_directories("${FPRIME_PROJECT_ROOT}") - - # Setup the include directories that exist within the build-cache - include_directories("${CMAKE_BINARY_DIR}") - include_directories("${CMAKE_BINARY_DIR}/F-Prime") -endfunction(fprime_setup_global_includes) #### # Function `fprime_detect_libraries`: @@ -162,7 +136,6 @@ macro(fprime_initialize_build_system) get_property(_FPRIME_BUILD_SYSTEM_LOADED GLOBAL PROPERTY FPRIME_BUILD_SYSTEM_LOADED) if (NOT _FPRIME_BUILD_SYSTEM_LOADED) cmake_minimum_required(VERSION 3.18) - fprime_setup_global_includes() fprime_detect_libraries() fprime_setup_standard_targets() fprime_setup_override_targets() @@ -178,6 +151,9 @@ macro(fprime_initialize_build_system) run_sub_build(info-cache ${SUB_BUILD_TARGETS}) # Import the pre-computed properties! include("${CMAKE_BINARY_DIR}/fprime_module_info.cmake") + get_property(FPRIME_SUBBUILD_LOCATIONS TARGET ${FPRIME_GLOBAL_INTERFACE_TARGET} PROPERTY FPRIME_SUBBUILD_LOCATIONS) + fprime_cmake_status("[FPRIME] Module locations: ${FPRIME_SUBBUILD_LOCATIONS}") + fprime_cmake_status("[FPRIME] Installation directory: ${CMAKE_INSTALL_PREFIX}") endif() endif() endmacro(fprime_initialize_build_system) diff --git a/cmake/autocoder/fpp.cmake b/cmake/autocoder/fpp.cmake index 53c172d1570..7cf3afa058d 100644 --- a/cmake/autocoder/fpp.cmake +++ b/cmake/autocoder/fpp.cmake @@ -188,6 +188,32 @@ function(fpp_info MODULE_NAME AC_INPUT_FILES) set(FPP_IMPORTS "${STDOUT}" PARENT_SCOPE) endfunction(fpp_info) +function(fpp_autocoder_variables FPP_IMPORTS) + # Resolve the current binary directory. This is necessary because fpp tools run in the JVM. + # The JVM resolves all paths, and thus if a path is passed in unresolved form, fpp would see + # it as a different file. + set(CMAKE_CURRENT_BINARY_DIR_RESOLVED "${CMAKE_CURRENT_BINARY_DIR}") + resolve_path_variables(CMAKE_BINARY_DIR_RESOLVED CMAKE_CURRENT_BINARY_DIR_RESOLVED) + + # Read the locations from the global interface target. These are normalized when set as the property. + # We then convert this list to a comma-separated list for passing to FPP. + get_property(FPRIME_LOCATIONS TARGET "${FPRIME_GLOBAL_INTERFACE_TARGET}" PROPERTY FPRIME_LOCATIONS) + string(REGEX REPLACE ";" "," FPRIME_LOCATIONS_COMMA_SEP "${FPRIME_LOCATIONS}") + # fpp imports also need to be a comma-separated list + string(REGEX REPLACE ";" "," FPP_IMPORTS_COMMA_SEP "${FPP_IMPORTS}") + + # If imports exist, then we need to prepend the -i flag for fpp + set(IMPORT_FLAGS) + if (FPP_IMPORTS_COMMA_SEP) + set(IMPORT_FLAGS "-i" "${FPP_IMPORTS_COMMA_SEP}") + endif() + + # Now set the variables for the FPP autocoder in parent scope + set(FPP_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR_RESOLVED}" PARENT_SCOPE) + set(FPP_LOCATIONS_COMMA_SEP "${FPRIME_LOCATIONS_COMMA_SEP}" PARENT_SCOPE) + set(FPP_IMPORT_FLAGS "${IMPORT_FLAGS}" PARENT_SCOPE) +endfunction(fpp_autocoder_variables) + #### # Function `fpp_setup_autocode`: # @@ -201,16 +227,9 @@ function(fpp_setup_autocode MODULE_NAME AC_INPUT_FILES) message(FATAL_ERROR "fpp tools not found, please install them onto your system path") endif() fpp_info("${MODULE_NAME}" "${AC_INPUT_FILES}") - set(CMAKE_BINARY_DIR_RESOLVED "${CMAKE_BINARY_DIR}") - set(CMAKE_CURRENT_BINARY_DIR_RESOLVED "${CMAKE_CURRENT_BINARY_DIR}") - resolve_path_variables(CMAKE_BINARY_DIR_RESOLVED CMAKE_CURRENT_BINARY_DIR_RESOLVED) - string(REGEX REPLACE ";" "," FPRIME_BUILD_LOCATIONS_COMMA_SEP "${FPRIME_BUILD_LOCATIONS}") - string(REGEX REPLACE ";" "," FPP_IMPORTS_COMMA_SEP "${FPP_IMPORTS}") - set(IMPORTS) - if (FPP_IMPORTS_COMMA_SEP) - set(IMPORTS "-i" "${FPP_IMPORTS_COMMA_SEP}") - endif() - # Separate the source files into the CPP + fpp_autocoder_variables("${FPP_IMPORTS}") + + # Separate the source files into the various types generated by the fpp tools. set(GENERATED_CPP) set(GENERATED_DICT) foreach(GENERATED IN LISTS GENERATED_FILES) @@ -234,8 +253,8 @@ function(fpp_setup_autocode MODULE_NAME AC_INPUT_FILES) if (GENERATED_CPP) add_custom_command( OUTPUT ${GENERATED_CPP} - COMMAND ${FPP_TO_CPP} "-d" "${CMAKE_CURRENT_BINARY_DIR_RESOLVED}" ${IMPORTS} ${AC_INPUT_FILES} - "-p" "${FPRIME_BUILD_LOCATIONS_COMMA_SEP},${CMAKE_BINARY_DIR_RESOLVED}" + COMMAND ${FPP_TO_CPP} "-d" "${FPP_OUTPUT_DIRECTORY}" ${FPP_IMPORT_FLAGS} ${AC_INPUT_FILES} + "-p" "${FPP_LOCATIONS_COMMA_SEP}" DEPENDS ${FILE_DEPENDENCIES} ) endif() @@ -248,7 +267,7 @@ function(fpp_setup_autocode MODULE_NAME AC_INPUT_FILES) "--executable" "${FPP_TO_DICT}" "--cmake-bin-dir" "${CMAKE_CURRENT_BINARY_DIR}" "--jsonVersionFile" "${FPRIME_JSON_VERSION_FILE}" - ${IMPORTS} ${AC_INPUT_FILES} + ${FPP_IMPORT_FLAGS} ${AC_INPUT_FILES} DEPENDS ${FILE_DEPENDENCIES} ${FPRIME_JSON_VERSION_FILE} version_generate diff --git a/cmake/autocoder/fpp_ut.cmake b/cmake/autocoder/fpp_ut.cmake index 615220549aa..9b518f3fb51 100644 --- a/cmake/autocoder/fpp_ut.cmake +++ b/cmake/autocoder/fpp_ut.cmake @@ -32,19 +32,14 @@ function(fpp_ut_setup_autocode MODULE_NAME AC_INPUT_FILES) message(FATAL_ERROR "fpp tools not found, please install them onto your system path") endif() fpp_info("${MODULE_NAME}" "${AC_INPUT_FILES}") - string(REGEX REPLACE ";" "," FPRIME_BUILD_LOCATIONS_COMMA_SEP "${FPRIME_BUILD_LOCATIONS}") - string(REGEX REPLACE ";" "," FPP_IMPORTS_COMMA_SEP "${FPP_IMPORTS}") - set(IMPORTS) - if (FPP_IMPORTS_COMMA_SEP) - set(IMPORTS "-i" "${FPP_IMPORTS_COMMA_SEP}") - endif() + fpp_autocoder_variables("${FPP_IMPORTS}") # Separate the source files into the CPP set(GENERATED_AI) set(GENERATED_CPP) foreach(GENERATED IN LISTS UNITTEST_FILES) list(APPEND GENERATED_CPP "${GENERATED}") endforeach() - set(CLI_ARGS ${FPP_TO_CPP} "-u" "-d" "${CMAKE_CURRENT_BINARY_DIR}" ${IMPORTS} ${AC_INPUT_FILES} "-p" "${FPRIME_BUILD_LOCATIONS_COMMA_SEP},${CMAKE_BINARY_DIR}") + set(CLI_ARGS ${FPP_TO_CPP} "-u" "-d" "${FPP_OUTPUT_DIRECTORY}" ${FPP_IMPORT_FLAGS} ${AC_INPUT_FILES} "-p" "${FPP_LOCATIONS_COMMA_SEP}") get_target_property(UT_AUTO_HELPERS "${MODULE_NAME}" FPRIME_UT_AUTO_HELPERS) if (UT_AUTO_HELPERS) list(APPEND CLI_ARGS "-a") diff --git a/cmake/config_assembler.cmake b/cmake/config_assembler.cmake index 631a141be65..467d7944067 100644 --- a/cmake/config_assembler.cmake +++ b/cmake/config_assembler.cmake @@ -4,9 +4,7 @@ # CMake configuration handling function. #### include_guard() -# Create a target to act as an interface to all fprime configuration modules -set(FPRIME__INTERNAL_CONFIG_TARGET_NAME "__fprime_config" CACHE INTERNAL "Internal name of the config target" FORCE) -add_library(${FPRIME__INTERNAL_CONFIG_TARGET_NAME} INTERFACE) + #### # Function `fprime__internal_process_configuration_sources`: diff --git a/cmake/global_interface.cmake b/cmake/global_interface.cmake new file mode 100644 index 00000000000..bc664c433ae --- /dev/null +++ b/cmake/global_interface.cmake @@ -0,0 +1,81 @@ +#### +# global_interface.cmake: +# +# This file provides an internal global interface target for use in the F Prime build system. Its job is to act as a +# singular target that has all the global properties that the build system requires. These include: +# +# 0. FPRIME_LOCATIONS: list of all "root" locations (source, binary) +# 1. FPRIME_SOURCE_LOCATIONS: list of all "root" locations of the project used for infering target names. +# 2. FPRIME_BINARY_LOCATIONS: list of all binary equivalents of FPRIME_SOURCE_LOCATIONS in the build cache. +# 3. INTERFACE_INCLUDE_DIRECTORIES: list of all include directories that apply to all targets in the build system. +# a. These include all FPRIME_SOURCE_LOCATIONS, FPRIME_BINARY_LOCATIONS, and configuration directories +# 4. FPRIME_CHOSEN_IMPLEMENTATIONS: list of all chosen implementations for selectable build modules. +# +# The global interface target also links to all BASE_CONFIG configuration modules. This allows modules to depend on, +# and receive include directories for all base configurations. +# +# The target's name is stored in the FPRIME_GLOBAL_INTERFACE_TARGET cache variable and is available to all projects. +# Users must include this file to ensure that, should they be the first to need this target, it will be created. +# +# A global target is preferable to global properties as it has several advantages. First, it allows for transitive +# properties for things like include paths. Second, its F Prime properties can be used in generator expressions. +# +# CACHE VARIABLES: +# - FPRIME_GLOBAL_INTERFACE_TARGET: the name of the global interface target. Used when interfacing with the target +# +#### +include_guard() +# Create a target for use as the global interface for cross-build properties. Then create a variable to store the name. +set(FPRIME_GLOBAL_INTERFACE_TARGET "__fprime_global_interface" CACHE INTERNAL "Target name of global interface" FORCE) +add_library(${FPRIME_GLOBAL_INTERFACE_TARGET} INTERFACE) + +#### +# Function `fprime_add_location_pair`: +# +# This function adds a source location and its corresponding binary location to the global interface target. This +# includes adding the SOURCE to FPRIME_SOURCE_LOCATIONS, the BINARY to FPRIME_BINARY_LOCATIONS and updating the +# INTERFACE_INCLUDE_DIRECTORIES and FPRIME_LOCATIONS property with both locations. +# +# Arguments: +# - `SOURCE`: the source location to add +# - `BINARY`: the binary location to add +# Returns: None +#### +function(fprime_add_location_pair SOURCE BINARY) + resolve_path_variables(SOURCE BINARY) + # First update the target properties with the appropriate locations. + append_list_property("${SOURCE}" TARGET "${FPRIME_GLOBAL_INTERFACE_TARGET}" PROPERTY FPRIME_SOURCE_LOCATIONS) + append_list_property("${BINARY}" TARGET "${FPRIME_GLOBAL_INTERFACE_TARGET}" PROPERTY FPRIME_BINARY_LOCATIONS) + append_list_property("${SOURCE}" TARGET "${FPRIME_GLOBAL_INTERFACE_TARGET}" PROPERTY FPRIME_LOCATIONS) + append_list_property("${BINARY}" TARGET "${FPRIME_GLOBAL_INTERFACE_TARGET}" PROPERTY FPRIME_LOCATIONS) + # Add source and binaries to the interface includes of our singular global interface target + target_include_directories("${FPRIME_GLOBAL_INTERFACE_TARGET}" INTERFACE "${SOURCE}") + target_include_directories("${FPRIME_GLOBAL_INTERFACE_TARGET}" INTERFACE "${BINARY}") +endfunction(fprime_add_location_pair) + +#### +# Function `fprime_add_historical_locations`: +# +# This function adds the list of historical locations to the global interface target. This is done for backwards +# compatibility with older versions of F Prime. This includes the following historical locations: +# - FPRIME_PROJECT_ROOT: the root source directory of the project, from settings.ini +# - FPRIME_FRAMEWORK_PATH: the source directory of the F Prime framework, from settings.ini +# - FPRIME_LIBRARY_LOCATIONS: the list of the library locations of the project, from settings.ini +# +# > [!WARNING] +# > This functions and associated variables are deprecated. New projects and code should not use these variables. +# +# Arguments: None +# Returns: None +#### +function(fprime_add_historical_locations) + if (DEFINED FPRIME_PROJECT_ROOT) + fprime_add_location_pair("${FPRIME_PROJECT_ROOT}" "${CMAKE_BINARY_DIR}") + endif() + if (DEFINED FPRIME_FRAMEWORK_PATH) + fprime_add_location_pair("${FPRIME_FRAMEWORK_PATH}" "${CMAKE_BINARY_DIR}/F-Prime") + endif() + foreach(LIBRARY_LOCATION IN LISTS FPRIME_LIBRARY_LOCATIONS) + fprime_add_location_pair("${LIBRARY_LOCATION}" "${CMAKE_BINARY_DIR}") + endforeach() +endfunction(fprime_add_historical_locations) \ No newline at end of file diff --git a/cmake/sub-build/sub-build-config.cmake b/cmake/sub-build/sub-build-config.cmake index 23793c62e6b..b515338f19a 100644 --- a/cmake/sub-build/sub-build-config.cmake +++ b/cmake/sub-build/sub-build-config.cmake @@ -17,7 +17,6 @@ set(FPRIME_SUB_BUILD_EXCLUDED_CACHE_VARIABLES CMAKE_EDIT_COMMAND CMAKE_HOME_DIRECTORY CMAKE_INSTALL_NAME_TOOL - FPRIME_BUILD_LOCATIONS FPRIME_SUB_BUILD FPRIME_VERSION_SCRIPT CMAKE_C_COMPILER_FORCED diff --git a/cmake/target/sub-build/module_info.cmake b/cmake/target/sub-build/module_info.cmake index 472ffa154d2..9e423f464e8 100644 --- a/cmake/target/sub-build/module_info.cmake +++ b/cmake/target/sub-build/module_info.cmake @@ -11,7 +11,6 @@ set(FPRIME__INTERNAL_PROPERTY_WRITER "${PYTHON}" "${CMAKE_CURRENT_LIST_DIR}/../t set(FPRIME__INTERNAL_CAT "${PYTHON}" "${CMAKE_CURRENT_LIST_DIR}/../tools/cat.py" CACHE INTERNAL "Internal helper for module_info to concatenate files" FORCE) - #### # Function `module_info_add_global_target`: # @@ -25,7 +24,11 @@ function(module_info_add_global_target CUSTOM_TARGET_NAME) add_custom_target("module_info" COMMAND "${FPRIME__INTERNAL_PROPERTY_WRITER}" "--file" "${MODULE_INFO_FILE}.part" SET GLOBAL PROPERTY FPRIME_BASE_CHOSEN_IMPLEMENTATIONS - "$" + "$" + COMMAND_EXPAND_LISTS + COMMAND "${FPRIME__INTERNAL_PROPERTY_WRITER}" "--file" "${MODULE_INFO_FILE}.part" "--append" + SET TARGET ${FPRIME_GLOBAL_INTERFACE_TARGET} PROPERTY FPRIME_SUBBUILD_LOCATIONS + "$" COMMAND_EXPAND_LISTS COMMAND "${FPRIME__INTERNAL_CAT}" $ diff --git a/cmake/test/data/cmake/target/test_recursion.cmake b/cmake/test/data/cmake/target/test_recursion.cmake index 4c5acb81ba4..67627fa34a8 100644 --- a/cmake/test/data/cmake/target/test_recursion.cmake +++ b/cmake/test/data/cmake/target/test_recursion.cmake @@ -4,6 +4,7 @@ # This target sets up a test target for checking the right recursive dependencies come in #### include(utilities) +include(global_interface) # Current full dependency list for TestDeployment (mostly via Svc_CmdDispatcher) set(EXPECTED_FULL_DEPENDENCIES Fw @@ -61,7 +62,7 @@ set(EXPECTED_FULL_DEPENDENCIES TestLibrary_TestComponent UnixPlatformTypes Utils_Hash - __fprime_config + ${FPRIME_GLOBAL_INTERFACE_TARGET} default_config ) diff --git a/cmake/utilities.cmake b/cmake/utilities.cmake index 04a70bb24be..1df70bf4e3a 100644 --- a/cmake/utilities.cmake +++ b/cmake/utilities.cmake @@ -252,16 +252,22 @@ endfunction() #### # Function `get_nearest_build_root`: # -# Finds the nearest build root from ${FPRIME_BUILD_LOCATIONS} that is a parent of DIRECTORY_PATH. +# Finds the nearest location in FPRIME_LOCATIONS to the given path. This is used for calculating module names, include +# paths, and relative asserts. FPRIME_LOCATIONS is derrived from the global interface target. +# +# Note: historically these were called "build roots". # # - **DIRECTORY_PATH:** path to detect nearest build root -# Return: nearest parent from ${FPRIME_BUILD_LOCATIONS} +# Return: nearest parent from FPRIME_LOCATIONS as read from the global interface target property FPRIME_LOCATIONS #### function(get_nearest_build_root DIRECTORY_PATH) - get_filename_component(DIRECTORY_PATH "${DIRECTORY_PATH}" ABSOLUTE) + resolve_path_variables(DIRECTORY_PATH) set(FOUND_BUILD_ROOT "${DIRECTORY_PATH}") set(LAST_REL "${DIRECTORY_PATH}") - foreach(FPRIME_BUILD_LOC ${FPRIME_BUILD_LOCATIONS} ${CMAKE_BINARY_DIR}/F-Prime ${CMAKE_BINARY_DIR}) + + # Read the know locations (up to this point) and look for the closest one. + get_property(FPRIME_ALL_LOCATIONS TARGET "${FPRIME_GLOBAL_INTERFACE_TARGET}" PROPERTY FPRIME_LOCATIONS) + foreach(FPRIME_BUILD_LOC IN LISTS FPRIME_ALL_LOCATIONS) get_filename_component(FPRIME_BUILD_LOC "${FPRIME_BUILD_LOC}" ABSOLUTE) file(RELATIVE_PATH TEMP_MODULE ${FPRIME_BUILD_LOC} ${DIRECTORY_PATH}) string(LENGTH "${LAST_REL}" LEN1) @@ -271,11 +277,13 @@ function(get_nearest_build_root DIRECTORY_PATH) set(LAST_REL "${TEMP_MODULE}") endif() endforeach() + # Report when this file is not anchored under any know location. if ("${FOUND_BUILD_ROOT}" STREQUAL "${DIRECTORY_PATH}") message(FATAL_ERROR "No build root found for: ${DIRECTORY_PATH}") endif() set(FPRIME_CLOSEST_BUILD_ROOT "${FOUND_BUILD_ROOT}" PARENT_SCOPE) endfunction() + #### # Function `get_module_name`: # From e187e33a9962f40c094896a31c98818c65db506c Mon Sep 17 00:00:00 2001 From: M Starch Date: Thu, 11 Jun 2026 16:06:20 -0700 Subject: [PATCH 2/7] sp --- cmake/FPrime.cmake | 4 ++-- cmake/global_interface.cmake | 2 +- cmake/target/sub-build/module_info.cmake | 2 +- cmake/utilities.cmake | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cmake/FPrime.cmake b/cmake/FPrime.cmake index 92b257183a2..6a8de88135d 100644 --- a/cmake/FPrime.cmake +++ b/cmake/FPrime.cmake @@ -151,8 +151,8 @@ macro(fprime_initialize_build_system) run_sub_build(info-cache ${SUB_BUILD_TARGETS}) # Import the pre-computed properties! include("${CMAKE_BINARY_DIR}/fprime_module_info.cmake") - get_property(FPRIME_SUBBUILD_LOCATIONS TARGET ${FPRIME_GLOBAL_INTERFACE_TARGET} PROPERTY FPRIME_SUBBUILD_LOCATIONS) - fprime_cmake_status("[FPRIME] Module locations: ${FPRIME_SUBBUILD_LOCATIONS}") + get_property(FPRIME_SUB_BUILD_LOCATIONS TARGET ${FPRIME_GLOBAL_INTERFACE_TARGET} PROPERTY FPRIME_SUB_BUILD_LOCATIONS) + fprime_cmake_status("[FPRIME] Module locations: ${FPRIME_SUB_BUILD_LOCATIONS}") fprime_cmake_status("[FPRIME] Installation directory: ${CMAKE_INSTALL_PREFIX}") endif() endif() diff --git a/cmake/global_interface.cmake b/cmake/global_interface.cmake index bc664c433ae..597f5418d33 100644 --- a/cmake/global_interface.cmake +++ b/cmake/global_interface.cmake @@ -5,7 +5,7 @@ # singular target that has all the global properties that the build system requires. These include: # # 0. FPRIME_LOCATIONS: list of all "root" locations (source, binary) -# 1. FPRIME_SOURCE_LOCATIONS: list of all "root" locations of the project used for infering target names. +# 1. FPRIME_SOURCE_LOCATIONS: list of all "root" locations of the project used for inferring target names. # 2. FPRIME_BINARY_LOCATIONS: list of all binary equivalents of FPRIME_SOURCE_LOCATIONS in the build cache. # 3. INTERFACE_INCLUDE_DIRECTORIES: list of all include directories that apply to all targets in the build system. # a. These include all FPRIME_SOURCE_LOCATIONS, FPRIME_BINARY_LOCATIONS, and configuration directories diff --git a/cmake/target/sub-build/module_info.cmake b/cmake/target/sub-build/module_info.cmake index 9e423f464e8..09d8ec2f9ae 100644 --- a/cmake/target/sub-build/module_info.cmake +++ b/cmake/target/sub-build/module_info.cmake @@ -27,7 +27,7 @@ function(module_info_add_global_target CUSTOM_TARGET_NAME) "$" COMMAND_EXPAND_LISTS COMMAND "${FPRIME__INTERNAL_PROPERTY_WRITER}" "--file" "${MODULE_INFO_FILE}.part" "--append" - SET TARGET ${FPRIME_GLOBAL_INTERFACE_TARGET} PROPERTY FPRIME_SUBBUILD_LOCATIONS + SET TARGET ${FPRIME_GLOBAL_INTERFACE_TARGET} PROPERTY FPRIME_SUB_BUILD_LOCATIONS "$" COMMAND_EXPAND_LISTS COMMAND "${FPRIME__INTERNAL_CAT}" diff --git a/cmake/utilities.cmake b/cmake/utilities.cmake index 1df70bf4e3a..b528440aa41 100644 --- a/cmake/utilities.cmake +++ b/cmake/utilities.cmake @@ -253,7 +253,7 @@ endfunction() # Function `get_nearest_build_root`: # # Finds the nearest location in FPRIME_LOCATIONS to the given path. This is used for calculating module names, include -# paths, and relative asserts. FPRIME_LOCATIONS is derrived from the global interface target. +# paths, and relative asserts. FPRIME_LOCATIONS is derived from the global interface target. # # Note: historically these were called "build roots". # From f4639262af53b2ebc33073244b0c6ab7b6cc09b4 Mon Sep 17 00:00:00 2001 From: M Starch Date: Thu, 11 Jun 2026 16:12:04 -0700 Subject: [PATCH 3/7] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- cmake/global_interface.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/global_interface.cmake b/cmake/global_interface.cmake index 597f5418d33..77a2d0656d6 100644 --- a/cmake/global_interface.cmake +++ b/cmake/global_interface.cmake @@ -63,7 +63,7 @@ endfunction(fprime_add_location_pair) # - FPRIME_LIBRARY_LOCATIONS: the list of the library locations of the project, from settings.ini # # > [!WARNING] -# > This functions and associated variables are deprecated. New projects and code should not use these variables. +# > This function and associated variables are deprecated. New projects and code should not use these variables. # # Arguments: None # Returns: None From 0d7e2c91a29bfd80861021927a3826897df49404 Mon Sep 17 00:00:00 2001 From: M Starch Date: Thu, 11 Jun 2026 16:12:15 -0700 Subject: [PATCH 4/7] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- cmake/API.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/API.cmake b/cmake/API.cmake index 0396e467a04..5eb04bf7014 100644 --- a/cmake/API.cmake +++ b/cmake/API.cmake @@ -740,7 +740,7 @@ endfunction() # 4. Add the current binary directory to the global include directories # 5. Add the current source directory to the CMAKE_PATH_PREFIX variable for this module # This allows it to be found and used by other modules in the build system. It ensures that the components are properly -# slotted underneath this library for the purposed of include path and target names. +# slotted underneath this library for the purpose of include path and target names. # Args: none ##### macro(register_fprime_project) From 92b156663a5cc161c43f1f94cfbfc93ec18f864a Mon Sep 17 00:00:00 2001 From: M Starch Date: Thu, 11 Jun 2026 16:12:42 -0700 Subject: [PATCH 5/7] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- cmake/autocoder/fpp.cmake | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmake/autocoder/fpp.cmake b/cmake/autocoder/fpp.cmake index 7cf3afa058d..3779e812c3a 100644 --- a/cmake/autocoder/fpp.cmake +++ b/cmake/autocoder/fpp.cmake @@ -193,8 +193,7 @@ function(fpp_autocoder_variables FPP_IMPORTS) # The JVM resolves all paths, and thus if a path is passed in unresolved form, fpp would see # it as a different file. set(CMAKE_CURRENT_BINARY_DIR_RESOLVED "${CMAKE_CURRENT_BINARY_DIR}") - resolve_path_variables(CMAKE_BINARY_DIR_RESOLVED CMAKE_CURRENT_BINARY_DIR_RESOLVED) - + resolve_path_variables(CMAKE_CURRENT_BINARY_DIR_RESOLVED) # Read the locations from the global interface target. These are normalized when set as the property. # We then convert this list to a comma-separated list for passing to FPP. get_property(FPRIME_LOCATIONS TARGET "${FPRIME_GLOBAL_INTERFACE_TARGET}" PROPERTY FPRIME_LOCATIONS) From 13b810fdbaa35be009a32da95d7fe9fea8bcca93 Mon Sep 17 00:00:00 2001 From: M Starch Date: Thu, 11 Jun 2026 16:14:19 -0700 Subject: [PATCH 6/7] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- cmake/utilities.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/utilities.cmake b/cmake/utilities.cmake index b528440aa41..edcdaa4557a 100644 --- a/cmake/utilities.cmake +++ b/cmake/utilities.cmake @@ -277,7 +277,7 @@ function(get_nearest_build_root DIRECTORY_PATH) set(LAST_REL "${TEMP_MODULE}") endif() endforeach() - # Report when this file is not anchored under any know location. + # Report when this file is not anchored under any known location. if ("${FOUND_BUILD_ROOT}" STREQUAL "${DIRECTORY_PATH}") message(FATAL_ERROR "No build root found for: ${DIRECTORY_PATH}") endif() From 467db96c2c07a99528f694c8277882e2b09c9d3c Mon Sep 17 00:00:00 2001 From: M Starch Date: Thu, 11 Jun 2026 16:16:17 -0700 Subject: [PATCH 7/7] Fix copilot recommendations --- cmake/global_interface.cmake | 1 + cmake/utilities.cmake | 1 + 2 files changed, 2 insertions(+) diff --git a/cmake/global_interface.cmake b/cmake/global_interface.cmake index 77a2d0656d6..9bfc5d26c03 100644 --- a/cmake/global_interface.cmake +++ b/cmake/global_interface.cmake @@ -25,6 +25,7 @@ # #### include_guard() +include(utilities) # Create a target for use as the global interface for cross-build properties. Then create a variable to store the name. set(FPRIME_GLOBAL_INTERFACE_TARGET "__fprime_global_interface" CACHE INTERNAL "Target name of global interface" FORCE) add_library(${FPRIME_GLOBAL_INTERFACE_TARGET} INTERFACE) diff --git a/cmake/utilities.cmake b/cmake/utilities.cmake index edcdaa4557a..f4d99d400ee 100644 --- a/cmake/utilities.cmake +++ b/cmake/utilities.cmake @@ -4,6 +4,7 @@ # Utility and support functions for the fprime CMake build system. #### include_guard() +include(global_interface) set_property(GLOBAL PROPERTY C_CPP_ASM_REGEX ".*\.(c|cpp|cc|cxx|S|asm)$") ####