Skip to content

Commit

Permalink
Merge pull request #2483 from jphickey:fix-2483-tblbuild
Browse files Browse the repository at this point in the history
Fix #2483, clean up and move table build scripts
  • Loading branch information
dzbaker committed Jan 17, 2024
2 parents 5a8bbc4 + dd43aaf commit af07f5f
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 af07f5f

Please sign in to comment.