Skip to content

Commit

Permalink
Fix nasa#2483, clean up and move table build scripts
Browse files Browse the repository at this point in the history
Clean up the logic associated with building tables.  In particular,
the real function that sets up the intermediate library and targets
is moved to be part of the table tool itself (elf2cfetbl) rather
than part of CFE.  This way, its implementation can change based
on the way the tool works, rather than trying to make everything
work like elf2cfetbl does.
  • Loading branch information
jphickey committed Dec 19, 2023
1 parent 7f5ebcd commit dd43aaf
Show file tree
Hide file tree
Showing 9 changed files with 782 additions and 235 deletions.
124 changes: 18 additions & 106 deletions cmake/arch_build.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,14 @@ endfunction(add_cfe_app_dependency)
# of the target from targets.cmake and TABLE_FQNAME reflects the first
# parameter to this function.
#
# The table tool must provide an implementation to use with add_cfe_tables().
#
function(add_cfe_tables TABLE_FQNAME TBL_DEFAULT_SRC_FILES)

if (NOT TBL_DEFAULT_SRC_FILES)
message(FATAL_ERROR "Table source file list is empty")
endif()

get_filename_component(APP_NAME ${TABLE_FQNAME} NAME_WE)

# The passed-in name allows for a qualifier (in the form of APP_NAME.QUALIFIER) to get
Expand All @@ -213,23 +219,11 @@ function(add_cfe_tables TABLE_FQNAME TBL_DEFAULT_SRC_FILES)

# If "TGTNAME" is set, then use it directly
set(TABLE_TGTLIST ${TGTNAME})
set(TABLE_TEMPLATE "${CFE_SOURCE_DIR}/cmake/tables/table_rule_template.d.in")
set(TABLE_CMD_BASIC_OPTS
-DTEMPLATE_FILE="${TABLE_TEMPLATE}"
-DAPP_NAME="${APP_NAME}"
)

if (INSTALL_SUBDIR)
list(APPEND TABLE_CMD_BASIC_OPTS
-DINSTALL_SUBDIR="${INSTALL_SUBDIR}"
)
endif()

if (TARGET ${APP_NAME}.table)
if (NOT TABLE_TGTLIST)
set (TABLE_TGTLIST ${TGTLIST_${APP_NAME}})
endif()
set(TABLE_PARENT_TGT ${APP_NAME}.table)
else()
# The first parameter should match the name of an app that was
# previously defined using "add_cfe_app". If target-scope properties
Expand All @@ -242,108 +236,21 @@ function(add_cfe_tables TABLE_FQNAME TBL_DEFAULT_SRC_FILES)
if (NOT TABLE_TGTLIST)
set (TABLE_TGTLIST ${APP_STATIC_TARGET_LIST} ${APP_DYNAMIC_TARGET_LIST})
endif()
# No (known) parent app, just use core_api in this case. It will only get global-scope includes and defines.
set(TABLE_PARENT_TGT core_api)
endif()

set(TABLE_GENSCRIPT "${CFE_SOURCE_DIR}/cmake/tables/generate_elf_table_rules.cmake")

# The table source must be compiled using the same "include_directories"
# as any other target, but it uses the "add_custom_command" so there is
# no automatic way to do this (at least in the older cmakes)
foreach(TGT ${TABLE_TGTLIST})

set(TABLE_CMD_TGT_OPTS
-DTARGET_NAME="${TGT}"
do_add_cfe_tables_impl("${TABLE_FQNAME}"
APP_NAME "${APP_NAME}"
TARGET_NAME "${TGT}"
INSTALL_SUBDIR "${INSTALL_SUBDIR}"
${TBL_DEFAULT_SRC_FILES} ${ARGN}
)

set(TABLE_LIBNAME "tblobj_${TGT}_${TABLE_FQNAME}")
list(APPEND TABLE_CMD_TGT_OPTS "-DARCHIVE_FILE=\"$<TARGET_FILE:${TABLE_LIBNAME}>\"")

# Note that the TBL_DEFAULT_SRC_FILES is just a default - we now need
# to find the active source, which typically comes from the MISSION_DEFS dir.
# The TABLE_SELECTED_SRCS will become this list of active/selected source files
set(TABLE_SELECTED_SRCS)
foreach(TBL ${TBL_DEFAULT_SRC_FILES} ${ARGN})

# The file source basename (without directory or ext) should be the same as the table
# binary filename with a ".tbl" extension (this is the convention assumed by elf2cfetbl)
get_filename_component(TABLE_SRC_NEEDED ${TBL} NAME)
get_filename_component(TABLE_BASENAME ${TBL} NAME_WE)


# Check if an override exists at the mission level (recommended practice)
# This allows a mission to implement a customized table without modifying
# the original - this also makes for easier merging/updating if needed.
# Note this path list is in reverse-priority order, and only a single file
# will be end up being selected.
cfe_locate_implementation_file(TBL_SRC "${TABLE_SRC_NEEDED}"
OPTIONAL
FALLBACK_FILE "${CMAKE_CURRENT_SOURCE_DIR}/${TBL}"
PREFIX ${TGT}
SUBDIR tables
)

list(APPEND TABLE_SELECTED_SRCS ${TBL_SRC})

if (TBL_SRC)
message(STATUS "Using ${TBL_SRC} as table definition for ${TABLE_BASENAME} on ${TGT}")
else()
message(FATAL_ERROR "No table definition for ${APP_NAME}.${TABLE_BASENAME} on ${TGT} found")
endif()

# Set a preprocessor macro so when the .c file is compiled it knows what its
# input and (by convention) output name is supposed to be.
if (TABLE_LIBNAME)
set_property(SOURCE "${TBL_SRC}" APPEND PROPERTY COMPILE_DEFINITIONS
CFE_TABLE_NAME=${TABLE_BASENAME}
)
endif()

# Note the table is not generated directly here, as it may require the native system compiler, so
# the call to the table tool (eds2cfetbl in this build) is deferred to the parent scope. Instead, this
# generates a file that captures the state (include dirs, source files, targets) for use in a future step.
set(TABLE_RULEFILE "${MISSION_BINARY_DIR}/tables/${TGT}_${TABLE_FQNAME}.${TABLE_BASENAME}.d")
add_custom_command(
OUTPUT "${TABLE_RULEFILE}"
COMMAND ${CMAKE_COMMAND}
${TABLE_CMD_BASIC_OPTS}
${TABLE_CMD_TGT_OPTS}
-DOUTPUT_FILE="${TABLE_RULEFILE}"
-DTABLE_NAME="${TABLE_BASENAME}"
-DSOURCES="${TBL_SRC}"
-DOBJEXT="${CMAKE_C_OUTPUT_EXTENSION}"
-P "${TABLE_GENSCRIPT}"
WORKING_DIRECTORY
${WORKING_DIRECTORY}
DEPENDS
${TABLE_TEMPLATE}
${TABLE_GENSCRIPT}
${TABLE_PARENT_TGT}
)

# Add a custom target to generate the config file
add_custom_target(generate_table_${TGT}_${APP_NAME}_${TABLE_BASENAME}
DEPENDS "${TABLE_RULEFILE}" ${TABLE_LIBNAME}
)
add_dependencies(cfetables generate_table_${TGT}_${APP_NAME}_${TABLE_BASENAME})

endforeach()

if (TABLE_LIBNAME)
# NOTE: On newer CMake versions this should become an OBJECT library which makes this simpler.
# On older versions one may not reference the TARGET_OBJECTS property from the custom command.
# As a workaround this is built into a static library, and then the desired object is extracted
# before passing to elf2cfetbl. It is roundabout but it works.
add_library(${TABLE_LIBNAME} STATIC EXCLUDE_FROM_ALL ${TABLE_SELECTED_SRCS})
target_compile_definitions(${TABLE_LIBNAME} PRIVATE
CFE_CPU_NAME=${TGT}
)
target_link_libraries(${TABLE_LIBNAME} ${TABLE_PARENT_TGT})
endif()

endforeach()

endforeach(TGT ${TABLE_TGTLIST})

endfunction(add_cfe_tables)

Expand Down Expand Up @@ -673,7 +580,6 @@ function(setup_platform_msgids)

# This is the actual export to parent scope
foreach(VAR_NAME ${OUTPUT_VAR_LIST})
message("${VAR_NAME}=${PLATFORM_MSGID_HEADERFILE}")
set(${VAR_NAME} ${PLATFORM_MSGID_HEADERFILE} PARENT_SCOPE)
endforeach(VAR_NAME ${OUTPUT_VAR_LIST})

Expand All @@ -695,6 +601,12 @@ function(prepare)
# all generated table files will be added as dependencies to this target
add_custom_target(cfetables)

# The table tool must provide an implementation to use with add_cfe_tables().
# this is determined by the CFS_TABLETOOL_SCRIPT_DIR that must be exported
# from the parent build.
#
include(${CFS_TABLETOOL_SCRIPT_DIR}/add_cfe_tables_impl.cmake)

# Choose the configuration file to use for OSAL on this system
set(OSAL_CONFIGURATION_FILE)
foreach(CONFIG ${BUILD_CONFIG_${TARGETSYSTEM}} ${OSAL_SYSTEM_OSCONFIG})
Expand Down
6 changes: 5 additions & 1 deletion cmake/generate_git_module_version.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ function(get_version DEP)
endif()
set(DIR ${${DEP}_MISSION_DIR})
endif()
message("inside get_version for ${DEP}")

if ($ENV{VERBOSE})
message("inside get_version for ${DEP}")
endif()

execute_process(
COMMAND ${GIT_EXECUTABLE} describe --tags --always --dirty
WORKING_DIRECTORY ${DIR}
Expand Down
140 changes: 81 additions & 59 deletions cmake/mission_build.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,53 @@ function(setup_global_topicids)

endfunction(setup_global_topicids)

##################################################################
#
# FUNCTION: export_variable_cache
#
# Export variables to a "mission_vars.cache" file so they can be
# referenced by the target-specific builds. This list is ingested
# during the startup phase of all the subordinate cmake invocations.
#
# The passed-in USER_VARLIST should be the names of additional variables
# to export. These can be cache vars or normal vars.
#
function(export_variable_cache USER_VARLIST)

# The set of variables that should always be exported
set(FIXED_VARLIST
"MISSION_NAME"
"SIMULATION"
"MISSION_DEFS"
"MISSION_SOURCE_DIR"
"MISSION_BINARY_DIR"
"MISSIONCONFIG"
"MISSION_APPS"
"MISSION_PSPMODULES"
"MISSION_DEPS"
"MISSION_EDS_FILELIST"
"MISSION_EDS_SCRIPTLIST"
"ENABLE_UNIT_TESTS"
)

set(MISSION_VARCACHE)
foreach(VARL ${FIXED_VARLIST} ${USER_VARLIST} ${ARGN})
# It is important to avoid putting any blank lines in the output,
# This will cause the reader to misinterpret the data
if (NOT "${${VARL}}" STREQUAL "")
string(APPEND MISSION_VARCACHE "${VARL}\n${${VARL}}\n")
endif (NOT "${${VARL}}" STREQUAL "")
endforeach()

# Write the file -- the subprocess will read this file and re-create
# variables out of them. The alternative to this is to specify many "-D"
# parameters to the subordinate build but that would not scale well to many vars,
# and it would go through the shell meaning quoting/escaping for safety becomes
# very difficult. Using the file method avoids shell interpretation.
file(WRITE "${CMAKE_BINARY_DIR}/mission_vars.cache" "${MISSION_VARCACHE}")

endfunction(export_variable_cache)

##################################################################
#
# FUNCTION: prepare
Expand All @@ -246,15 +293,16 @@ function(prepare)
add_definitions(-DSIMULATION=${SIMULATION})
endif (SIMULATION)

# Prepare the table makefile - Ensure the list of tables is initially empty
file(MAKE_DIRECTORY "${MISSION_BINARY_DIR}/tables")
file(WRITE "${MISSION_BINARY_DIR}/tables/Makefile"
"MISSION_BINARY_DIR := ${MISSION_BINARY_DIR}\n"
"TABLE_BINARY_DIR := ${MISSION_BINARY_DIR}/tables\n"
"MISSION_SOURCE_DIR := ${MISSION_SOURCE_DIR}\n"
"MISSION_DEFS := ${MISSION_DEFS}\n\n"
"include \$(wildcard ${CFE_SOURCE_DIR}/cmake/tables/*.mk) \$(wildcard *.d)\n"
)
# Create directories to hold generated files/wrappers
file(MAKE_DIRECTORY "${MISSION_BINARY_DIR}/eds")
file(MAKE_DIRECTORY "${MISSION_BINARY_DIR}/obj")
file(MAKE_DIRECTORY "${MISSION_BINARY_DIR}/inc")
file(MAKE_DIRECTORY "${MISSION_BINARY_DIR}/src")

# Certain runtime variables need to be "exported" to the subordinate build, such as
# the specific arch settings and the location of all the apps. This list is collected
# during this function execution and exported at the end.
set(EXPORT_VARLIST)

# Create custom targets for building and cleaning all architectures
# This is required particularly for doing extra stuff in the clean step
Expand Down Expand Up @@ -428,76 +476,46 @@ function(prepare)
# msgid definitions, or any other configuration/preparation that needs to
# happen at mission/global scope.
foreach(DEP_NAME ${MISSION_DEPS})
list(APPEND EXPORT_VARLIST "${DEP_NAME}_MISSION_DIR")
include("${${DEP_NAME}_MISSION_DIR}/mission_build.cmake" OPTIONAL)
endforeach(DEP_NAME ${MISSION_DEPS})

# Certain runtime variables need to be "exported" to the subordinate build, such as
# the specific arch settings and the location of all the apps. This is done by creating
# a temporary file within the dir and then the subprocess will read that file and re-create
# variables out of them. The alternative to this is to specify many "-D" parameters to the
# subordinate build but that would not scale well to many vars.
set(VARLIST
"MISSION_NAME"
"SIMULATION"
"MISSION_DEFS"
"MISSION_SOURCE_DIR"
"MISSION_BINARY_DIR"
"MISSIONCONFIG"
"MISSION_APPS"
"MISSION_PSPMODULES"
"MISSION_DEPS"
"ENABLE_UNIT_TESTS"
)
foreach(APP ${MISSION_DEPS})
list(APPEND VARLIST "${APP}_MISSION_DIR")
endforeach()

foreach(SYSVAR ${TGTSYS_LIST})
list(APPEND VARLIST "BUILD_CONFIG_${SYSVAR}")
list(APPEND EXPORT_VARLIST "BUILD_CONFIG_${SYSVAR}")
endforeach(SYSVAR ${TGTSYS_LIST})

set(MISSION_VARCACHE)
foreach(VARL ${VARLIST})
# It is important to avoid putting any blank lines in the output,
# This will cause the reader to misinterpret the data
if (NOT "${${VARL}}" STREQUAL "")
set(MISSION_VARCACHE "${MISSION_VARCACHE}${VARL}\n${${VARL}}\n")
endif (NOT "${${VARL}}" STREQUAL "")
endforeach(VARL ${VARLIST})
file(WRITE "${CMAKE_BINARY_DIR}/mission_vars.cache" "${MISSION_VARCACHE}")

generate_build_version_templates()

# Generate the tools for the native (host) arch
# Add all public include dirs for core components to include path for tools
include_directories(
${MISSION_BINARY_DIR}/inc
${core_api_MISSION_DIR}/fsw/inc
${osal_MISSION_DIR}/src/os/inc
${psp_MISSION_DIR}/fsw/inc
)
add_subdirectory(${MISSION_SOURCE_DIR}/tools tools)

# Add a dependency on the table generator tool as this is required for table builds
# The "elf2cfetbl" target should have been added by the "tools" above
add_dependencies(mission-prebuild elf2cfetbl)
set(TABLETOOL_EXEC $<TARGET_FILE:elf2cfetbl>)

add_custom_target(tabletool-execute
COMMAND $(MAKE)
CC="${CMAKE_C_COMPILER}"
CFLAGS="${CMAKE_C_FLAGS}"
AR="${CMAKE_AR}"
TBLTOOL="${TABLETOOL_EXEC}"
cfetables
WORKING_DIRECTORY
"${CMAKE_BINARY_DIR}/tables"
DEPENDS
mission-cfetables
# The table tool target should have been added by the "tools" above
if (NOT DEFINED CFS_TABLETOOL_SCRIPT_DIR)
message(FATAL_ERROR "Table Tool missing: CFS_TABLETOOL_SCRIPT_DIR must be defined by the tools")
endif()
list(APPEND EXPORT_VARLIST CFS_TABLETOOL_SCRIPT_DIR)

# Prepare the table makefile - Ensure the list of tables is initially empty
file(REMOVE_RECURSE "${MISSION_BINARY_DIR}/tables")
file(MAKE_DIRECTORY "${MISSION_BINARY_DIR}/tables")
file(WRITE "${MISSION_BINARY_DIR}/tables/Makefile"
"MISSION_BINARY_DIR := ${MISSION_BINARY_DIR}\n"
"TABLE_BINARY_DIR := ${MISSION_BINARY_DIR}/tables\n"
"TABLETOOL_SCRIPT_DIR := ${CFS_TABLETOOL_SCRIPT_DIR}\n"
"MISSION_SOURCE_DIR := ${MISSION_SOURCE_DIR}\n"
"MISSION_DEFS := ${MISSION_DEFS}\n\n"
"include \$(wildcard $(TABLETOOL_SCRIPT_DIR)/*.mk) \$(wildcard *.d)\n"
)
add_dependencies(mission-all tabletool-execute)
add_dependencies(mission-install tabletool-execute)

add_dependencies(mission-cfetables mission-prebuild)
install(DIRECTORY ${CMAKE_BINARY_DIR}/tables/staging/ DESTINATION .)

# Build version information should be generated as part of the pre-build process
add_dependencies(mission-prebuild mission-version)
Expand All @@ -507,6 +525,10 @@ function(prepare)
install(DIRECTORY ${MISSION_DEFS}/functional-test/ DESTINATION ${FT_INSTALL_SUBDIR})
endif()

# Export the important state variables collected during this function.
# This is done last such that everything should have its correct value
export_variable_cache(${EXPORT_VARLIST})

endfunction(prepare)

##################################################################
Expand Down
Loading

0 comments on commit dd43aaf

Please sign in to comment.