Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CMake Implementation Selection #2384

Merged
merged 10 commits into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/actions/spelling/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -686,6 +686,7 @@ ORhex
origfile
origstatinfo
ortega
osal
OSAL
osaves
osets
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/build-test-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:
push:
branches: [ master, devel ]
pull_request:
branches: [ master, devel, release/v3.0.0 ]
branches: [ master, devel ]
paths-ignore:
- 'docs/**'
- '**.md'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/build-test-rpi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:
push:
branches: [ master, devel ]
pull_request:
branches: [ master, devel, release/v3.0.0 ]
branches: [ master, devel ]
paths-ignore:
- 'docs/**'
- '**.md'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:
push:
branches: [ master, devel ]
pull_request:
branches: [ master, devel, release/v3.0.0 ]
branches: [ master, devel ]
paths-ignore:
- 'docs/**'
- '**.md'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/cpplint-scan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on:
branches: [master, devel]
pull_request:
# The branches below must be a subset of the branches above
branches: [master, devel]
branches: [master, devel ]
paths-ignore:
- 'docs/**'
- '**.md'
Expand Down
2 changes: 1 addition & 1 deletion Svc/GroundInterface/test/ut/GroundInterfaceTester.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
#ifndef TESTER_HPP
#define TESTER_HPP

#include <ComPacket.hpp>
#include <Fw/Com/ComPacket.hpp>
#include "GroundInterfaceGTestBase.hpp"
#include "Svc/GroundInterface/GroundInterface.hpp"

Expand Down
71 changes: 68 additions & 3 deletions cmake/API.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#
####
include_guard()
include(utilities)
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)
Expand Down Expand Up @@ -96,6 +97,10 @@ function(add_fprime_subdirectory FP_SOURCE_DIR)
get_module_name("${FP_SOURCE_DIR}")
set(FPRIME_CURRENT_MODULE "${MODULE_NAME}")

# Unset all variables that carry special meaning as it is dangerous to pass them through
init_variables(SOURCE_FILES MOD_DEPS UT_SOURCE_FILES UT_MOD_DEPS EXECUTABLE_NAME)


# Check if the binary and source directory are in agreement. If they agree, then normally add
# the directory, as no adjustments need be made.
get_filename_component(CBD_NAME "${CMAKE_CURRENT_BINARY_DIR}" NAME)
Expand Down Expand Up @@ -545,7 +550,7 @@ endmacro(register_fprime_list_helper)
# the same thing. Note: make sure the directory is on the CMake include path to use the second form.
#
# **TARGET_FILE_PATH:** include path or file path file defining above functions
###
####
macro(register_fprime_build_autocoder TARGET_FILE_PATH)
# Normal registered targets don't run in prescan
if (CMAKE_DEBUG_OUTPUT)
Expand All @@ -554,12 +559,72 @@ macro(register_fprime_build_autocoder TARGET_FILE_PATH)
register_fprime_list_helper("${TARGET_FILE_PATH}" FPRIME_AUTOCODER_TARGET_LIST)
endmacro(register_fprime_build_autocoder)


####
# Function `require_fprime_implementation`:
#
# Designates that the current module requires a separate implementation in order for it to function properly. As an
# example, Os requires an implementation of `Os_Task`. These implementations must be set via
# `choose_fprime_implementation` in the platform and may be overridden in in the executable/deployment.
#
# **IMPLEMENTATION:** implementation module name that must be covered
####
function(require_fprime_implementation IMPLEMENTATION)
resolve_dependencies(IMPLEMENTATION "${IMPLEMENTATION}")
append_list_property("${IMPLEMENTATION}" GLOBAL PROPERTY "REQUIRED_IMPLEMENTATIONS")
append_list_property("${FPRIME_CURRENT_MODULE}" GLOBAL PROPERTY "${IMPLEMENTATION}_REQUESTERS")
endfunction()

####
# Function `register_fprime_implementation`:
#
# Designates that the given implementor implements the required implementation. As an example Os_Task_Posix implements
# Os_Task. These implementations must be set via
## `choose_fprime_implementation` in the platform and may be overridden in in the executable/deployment.
#
# **IMPLEMENTATION:** implementation module name that is implemented by IMPLEMENTOR
# **IMPLEMENTOR:** implementor of IMPLEMENTATION
####
function(register_fprime_implementation IMPLEMENTATION IMPLEMENTOR)
resolve_dependencies(IMPLEMENTATION "${IMPLEMENTATION}")
resolve_dependencies(IMPLEMENTOR "${IMPLEMENTOR}")
append_list_property("${IMPLEMENTOR}" GLOBAL PROPERTY "${IMPLEMENTATION}_IMPLEMENTORS")
endfunction()
####
# Function `choose_fprime_implementation`:
#
# Designates that the given implementor is the selected implementor for the needed implementation. Platforms must call
# this function once for each defined IMPLEMENTATION. An executable/deployment/unit-test may call this function to set
# a specific implementor for any needed implementation
#
# **IMPLEMENTATION:** implementation module name that is implemented by IMPLEMENTOR
# **IMPLEMENTOR:** implementor of IMPLEMENTATION
####
function(choose_fprime_implementation IMPLEMENTATION IMPLEMENTOR)
resolve_dependencies(IMPLEMENTATION "${IMPLEMENTATION}")
resolve_dependencies(IMPLEMENTOR "${IMPLEMENTOR}")
# Check for passed in module name
if (ARGC EQUAL 3)
set(ACTIVE_MODULE "${ARGV2}")
elseif (FPRIME_CURRENT_MODULE)
set(ACTIVE_MODULE "${FPRIME_CURRENT_MODULE}")
elseif(FPRIME_PLATFORM)
set(ACTIVE_MODULE "${FPRIME_PLATFORM}")
else()
message(FATAL_ERROR "Cannot call 'choose_fprime_implementation' outside an fprime module or platform CMake file")
endif()
set_property(GLOBAL PROPERTY "${IMPLEMENTATION}_${ACTIVE_MODULE}" "${IMPLEMENTOR}")
append_list_property("${IMPLEMENTATION}" GLOBAL PROPERTY "REQUIRED_IMPLEMENTATIONS")
append_list_property("${IMPLEMENTOR}" GLOBAL PROPERTY "${IMPLEMENTATION}_IMPLEMENTORS")
endfunction()

#### Documentation links
# Next Topics:
# - Setting Options: [Options](Options.md) are used to vary a CMake build.
# - Adding Deployment: [Deployments](deployment.md) create fprime builds.
# - Adding Module: [Modules](module.md) register fprime Ports, Components, etc.
# - Adding Deployments: [Deployments](deployment.md) create fprime builds.
# - Adding Modules: [Modules](module.md) register fprime Ports, Components, etc.
# - Creating Toolchains: [Toolchains](toolchain.md) setup standard CMake Cross-Compiling.
# - Adding Platforms: [Platforms](platform.md) help fprime set Cross-Compiling specific items.
# - Adding Targets: [Targets](targets.md) for help defining custom build targets
# - Implementation Packages Design: [Implementation Packages](/Design/package-implementor.md)
####
103 changes: 103 additions & 0 deletions cmake/implementation.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
####
# implementation.cmake:
#
# Functions used to handle different registered implementations of various cmake packages within F´. The process breaks
# down as follows:
# 1. A module will "require" an implementation X
# 2. A number of modules will "register" as an implementation of X
# 3. A platform package will "choose" a single implementation for X
# 4. Linked modules (executable, deployment, unit-test) may override and "choose" an alternate implementation for X
#
# For example: Os requires an implementation of Os_File. Os_File_Posix implements Os_File. The Linux platform chooses
# Os_File_Posix as the implementation of Os_File. This applies to all linked modules in the system. Os_Baremetal_ut may
# then override this choose using Os_File_MicroFs instead.
#
# > All required implementations apply system-wide. Platforms specifically disallowing use of a given package should
# > "choose" the special implementation "None" to bypass the check.
#
# Internally this uses several properties. Each of these properties are GLOBAL such that these may be set before the
# various targets have been explicitly created. These pro
#
#
####
include_guard()

####
# Function `remap_implementation_choices`:
#
# When a target is declared with a different name than the module name, we need to pull the implementation choices into
# a property for the declared target instead of the inferred target. This is done by reading each implementation choice
# and setting the new property.
#
# Args:
# INFERRED: inferred target name (FPRIME_CURRENT_MODULE)
# DECLARED: real target name
####
function(remap_implementation_choices INFERRED DECLARED)
# Check and setup implementors
get_property(LOCAL_REQUIRED GLOBAL PROPERTY "REQUIRED_IMPLEMENTATIONS")
if (LOCAL_REQUIRED)
foreach (IMPLEMENTATION IN LISTS LOCAL_REQUIRED)
get_property(IMPLEMENTOR GLOBAL PROPERTY "${IMPLEMENTATION}_${INFERRED}")
if (IMPLEMENTOR)
set_property(GLOBAL PROPERTY "${IMPLEMENTATION}_${DECLARED}" "${IMPLEMENTOR}")
endif()
endforeach()
endif ()
endfunction()

####
# Function `setup_executable_implementations`:
#
# Sets up all the needed implementations for the supplied module. This looks up the global set of required
# implementations and delegates each to `setup_executable_implementation` for final setup.
#
# Args:
# MODULE: module to setup implementation choices for
#####
function(setup_executable_implementations MODULE)
# Check and setup implementors
get_property(LOCAL_REQUIRED GLOBAL PROPERTY "REQUIRED_IMPLEMENTATIONS")
if (LOCAL_REQUIRED)
foreach (IMPLEMENTATION IN LISTS LOCAL_REQUIRED)
setup_executable_implementation("${IMPLEMENTATION}" "${MODULE}")
endforeach ()
endif ()
endfunction()

####
# Function `setup_executable_implementation`:
#
# Sets up the given implementation for the given module. Ensures that choices have been made and linking is setup
# without causing global link dependencies.
#
# Args:
# MODULE: module to setup implementation choices for
#####
function(setup_executable_implementation IMPLEMENTATION MODULE)
# Get the chosen implementor and fallback to the platform choice
get_property(IMPLEMENTOR GLOBAL PROPERTY "${IMPLEMENTATION}_${MODULE}")
if (NOT IMPLEMENTOR)
get_property(IMPLEMENTOR GLOBAL PROPERTY "${IMPLEMENTATION}_${FPRIME_PLATFORM}")
endif()
# Handle a failure to choose anything
get_property(REQUESTERS GLOBAL PROPERTY "${IMPLEMENTATION}_REQUESTERS")
if (NOT REQUESTERS)
set(REQUESTERS)
endif ()
string(REPLACE ";" ", " REQUESTERS_STRING "${REQUESTERS}")
if (NOT IMPLEMENTOR)
get_property(LOCAL_IMPLEMENTATIONS GLOBAL PROPERTY "${IMPLEMENTATION}_IMPLEMENTORS")
if (NOT LOCAL_IMPLEMENTATIONS)
set(LOCAL_IMPLEMENTATIONS "")
endif ()
string(REPLACE ";" ", " POSSIBLE "${LOCAL_IMPLEMENTATIONS}")
message(FATAL_ERROR "An implementation of ${IMPLEMENTATION} is required. Choose from: ${POSSIBLE}")
endif ()
if (CMAKE_DEBUG_OUTPUT)
message(STATUS "Using Implementation: ${IMPLEMENTOR} for ${IMPLEMENTATION}")
endif()
# Replicated order to solve the circular dependency issue without causing a hard-dependency
target_link_libraries("${MODULE}" PUBLIC ${REQUESTERS} "${IMPLEMENTOR}" ${REQUESTERS})
add_dependencies("${MODULE}" "${IMPLEMENTOR}")
endfunction()
13 changes: 10 additions & 3 deletions cmake/module.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
####
include_guard()
include(target/target)
include(implementation)
set(EMPTY "${FPRIME_FRAMEWORK_PATH}/cmake/empty.cpp")

####
Expand All @@ -27,11 +28,17 @@ function(generate_base_module_properties TARGET_TYPE TARGET_NAME SOURCE_FILES DE
if (TARGET_TYPE STREQUAL "Executable" OR TARGET_TYPE STREQUAL "Deployment")
add_executable("${TARGET_NAME}" "${EMPTY}")
elseif(TARGET_TYPE STREQUAL "Unit Test")
add_executable("${UT_EXE_NAME}" "${EMPTY}")
add_executable("${TARGET_NAME}" "${EMPTY}")
elseif(TARGET_TYPE STREQUAL "Library")
add_library("${TARGET_NAME}" "${EMPTY}")
else()
message(FATAL_ERROR "Module ${TARGET_NAME} cannot register object of type ${TARGET_TYPE}")
message(FATAL_ERROR "Module ${FPRIME_CURRENT_MODULE} cannot register object of type ${TARGET_TYPE}")
endif()

# Handle updates when the types have diverged
if (NOT TARGET_NAME STREQUAL "${FPRIME_CURRENT_MODULE}")
# Update implementation choices
remap_implementation_choices("${FPRIME_CURRENT_MODULE}" "${TARGET_NAME}")
endif()

# Modules properties for posterity
Expand Down Expand Up @@ -96,7 +103,7 @@ function(generate_ut UT_EXE_NAME UT_SOURCES_FILE UT_DEPENDENCIES)
# Only for BUILD_TESTING
if (BUILD_TESTING)
get_module_name("${CMAKE_CURRENT_LIST_DIR}")
generate_base_module_properties("Unit Test" "${MODULE_NAME}" "${UT_SOURCES_FILE}" "${UT_DEPENDENCIES}")
generate_base_module_properties("Unit Test" "${UT_EXE_NAME}" "${UT_SOURCES_FILE}" "${UT_DEPENDENCIES}")
endif()
endfunction(generate_ut)

22 changes: 17 additions & 5 deletions cmake/platform/platform.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,27 @@
#
####
include_guard()
include(API)
# Basic definitions
get_filename_component(TOOLCHAIN_NAME "${CMAKE_TOOLCHAIN_FILE}" NAME_WE)
# Setup fallback toolchain name
if ("${TOOLCHAIN_NAME}" STREQUAL "")
# Native toolchains use the system name for the toolchain and FPRIME_PLATFORM
if (NOT TOOLCHAIN_NAME)
set(TOOLCHAIN_NAME "${CMAKE_SYSTEM_NAME}")
set(FPRIME_PLATFORM "${CMAKE_SYSTEM_NAME}")
# It is an error to use a "Generic" toolchain without setting FPRIME_PLATFORM correctly
elseif (CMAKE_SYSTEM_NAME STREQUAL "Generic" AND NOT FPRIME_PLATFORM)
message(FATAL_ERROR "Toolchain '${TOOLCHAIN_NAME}' set CMAKE_SYSTEM_NAME to 'Generic' without setting FPRIME_PLATFORM")
# It is an error to set neither of CMAKE_SYSTEM_NAME and FPRIME_PLATFORM
elseif (NOT CMAKE_SYSTEM_NAME AND NOT FPRIME_PLATFORM)
message(FATAL_ERROR "Toolchain '${TOOLCHAIN_NAME}' should set CMAKE_SYSTEM_NAME to 'Generic' and set FPRIME_PLATFORM")
# Fallback to CMAKE_SYSTEM_NAME when only CMAKE_SYSTEM_NAME is set
elseif (NOT FPRIME_PLATFORM)
message(WARNING "Toolchain '${TOOLCHAIN_NAME}' should set CMAKE_SYSTEM_NAME to 'Generic' and set FPRIME_PLATFORM")
set(FPRIME_PLATFORM "${CMAKE_SYSTEM_NAME}")
endif()

# Include platform file based on system name
message(STATUS "Target build toolchain/platform: ${TOOLCHAIN_NAME}/${CMAKE_SYSTEM_NAME}")
message(STATUS "Target build toolchain/platform: ${TOOLCHAIN_NAME}/${FPRIME_PLATFORM}")

# Output directories
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib/${TOOLCHAIN_NAME}")
Expand All @@ -25,7 +37,7 @@ set(EXPECTED_PLATFORM_FILE "")

# Loop over locations of platform files in order: project, libraries, then framework
foreach(ROOT ${FPRIME_PROJECT_ROOT};${FPRIME_LIBRARY_LOCATIONS};${FPRIME_FRAMEWORK_PATH} )
set(EXPECTED_PLATFORM_FILE "${ROOT}/cmake/platform/${CMAKE_SYSTEM_NAME}.cmake")
set(EXPECTED_PLATFORM_FILE "${ROOT}/cmake/platform/${FPRIME_PLATFORM}.cmake")
# Include host machine settings
if (EXISTS "${EXPECTED_PLATFORM_FILE}")
message(STATUS "Including ${EXPECTED_PLATFORM_FILE}")
Expand All @@ -35,5 +47,5 @@ foreach(ROOT ${FPRIME_PROJECT_ROOT};${FPRIME_LIBRARY_LOCATIONS};${FPRIME_FRAMEWO
endforeach()
# Ensure the last attempt for the platform file was successful, otherwise error.
if (NOT EXISTS "${EXPECTED_PLATFORM_FILE}")
message(FATAL_ERROR "\n[F-PRIME] No platform config for '${CMAKE_SYSTEM_NAME}'. Please create: '${CMAKE_SYSTEM_NAME}.cmake'\n")
message(FATAL_ERROR "\n[F-PRIME] No platform config for '${FPRIME_PLATFORM}'. Please create: '${FPRIME_PLATFORM}.cmake'\n")
endif()
15 changes: 14 additions & 1 deletion cmake/target/build.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
include_guard()
include(autocoder/autocoder)
include(utilities)
include(implementation)

# Flags used when BUILD_TESTING is enabled
set(FPRIME_TESTING_REQUIRED_COMPILE_FLAGS)
Expand Down Expand Up @@ -62,7 +63,14 @@ function(build_setup_build_module MODULE SOURCES GENERATED DEPENDENCIES)
endforeach()
endif()
# Includes the source, so that the Ac files can include source headers
target_include_directories("${MODULE}" PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
#target_include_directories("${MODULE}" PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})


# Handle executable items' need for determined package implementation choices
is_target_library(IS_LIB "${MODULE}")
if (NOT IS_LIB)
setup_executable_implementations("${MODULE}")
endif ()

# For every detected dependency, add them to the supplied module. This enforces build order.
# Also set the link dependencies on this module. CMake rolls-up link dependencies, and thus
Expand Down Expand Up @@ -93,6 +101,11 @@ function(build_setup_build_module MODULE SOURCES GENERATED DEPENDENCIES)
endif()
endfunction()






####
# Function `add_deployment_target`:
#
Expand Down
Loading
Loading