Skip to content

Commit

Permalink
Merge pull request #2299 from jphickey/fix-2284-add_cfe_tbl
Browse files Browse the repository at this point in the history
Fix #2284, improve add_cfe_tables function
  • Loading branch information
dzbaker committed Apr 25, 2023
2 parents 8ea2307 + efb8551 commit 67faef0
Show file tree
Hide file tree
Showing 7 changed files with 272 additions and 133 deletions.
255 changes: 172 additions & 83 deletions cmake/arch_build.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,30 @@ function(add_cfe_app APP_NAME APP_SRC_FILES)
cfs_app_do_install(${APP_NAME} ${APP_DYNAMIC_TARGET_LIST})
endif (APP_DYNAMIC_TARGET_LIST)

# Add an interface target is added with a ".table" suffix,
# this should reflect all the INCLUDE_DIRECTORIES and COMPILE_DEFINITIONS that
# were used when compiling the app itself, such that tables (and other items) can be
# added later and reference the same set.
add_library(${APP_NAME}.table INTERFACE)
get_directory_property(CURRENT_INCLUDE_DIRS INCLUDE_DIRECTORIES)
if (NOT CURRENT_INCLUDE_DIRS)
set(CURRENT_INCLUDE_DIRS) # make it empty, not -NOTFOUND
endif()
get_directory_property(CURRENT_COMPILE_DEFS COMPILE_DEFINITIONS)
if (NOT CURRENT_COMPILE_DEFS)
set(CURRENT_COMPILE_DEFS) # make it empty, not -NOTFOUND
endif()
list (APPEND CURRENT_INCLUDE_DIRS
$<TARGET_PROPERTY:${APP_NAME},INCLUDE_DIRECTORIES>
$<TARGET_PROPERTY:core_api,INTERFACE_INCLUDE_DIRECTORIES>
)
list (APPEND CURRENT_COMPILE_DEFS
$<TARGET_PROPERTY:${APP_NAME},COMPILE_DEFINITIONS>
$<TARGET_PROPERTY:core_api,INTERFACE_COMPILE_DEFINITIONS>
)
target_include_directories(${APP_NAME}.table INTERFACE ${CURRENT_INCLUDE_DIRS})
target_compile_definitions(${APP_NAME}.table INTERFACE ${CURRENT_COMPILE_DEFS} CFE_APP_NAME="${APP_NAME}")

endfunction(add_cfe_app)

##################################################################
Expand Down Expand Up @@ -146,99 +170,160 @@ endfunction(add_cfe_app_dependency)
#
# Simplified routine to add CFS tables to be built with an app
#
function(add_cfe_tables APP_NAME TBL_SRC_FILES)
# For apps with just a single table, the TABLE_FQNAME may be the
# same as the app name, which is simple.
#
# For apps with multiple tables, the TABLE_FQNAME may be of the
# form "${APP_NAME}.${TABLE_NAME}" where ${APP_NAME} refers to an
# app target that was registered via the "add_cfe_app" function.
#
# Note that for backward compatibility, any name will be accepted
# for TABLE_FQNAME. However if this function cannot determine which
# app the table is associated with, it will only have a default set
# of INCLUDE_DIRECTORIES when building the C source file(s). By
# associating a table with an app using the conventions above, the
# INCLUDE_DIRECTORIES from the parent app will be used when building the
# tables.
#
# This function produces one or more library targets in CMake, using names
# of the form: "tblobj_${TGT}_{TABLE_FQNAME}" where TGT reflects the name
# of the target from targets.cmake and TABLE_FQNAME reflects the first
# parameter to this function.
#
function(add_cfe_tables TABLE_FQNAME TBL_DEFAULT_SRC_FILES)

get_filename_component(APP_NAME ${TABLE_FQNAME} NAME_WE)

if (TGTNAME)
set (TABLE_TGTLIST ${TGTNAME})
elseif (TARGET ${APP_NAME})
# 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
# are used for include directories and compile definitions, this is needed
# to compile tables with the same include path/definitions as the app has.
# However historically this could have been any string, which still works
# if directory-scope properties are used for includes, so this is not
# an error.
message("NOTE: \"${APP_NAME}\" passed to add_cfe_tables is not a previously-defined application target")
# The first parameter should match the name of an app that was
# previously defined using "add_cfe_app". If target-scope properties
# are used for include directories and compile definitions, this is needed
# to compile tables with the same include path/definitions as the app has.
# However historically this could have been any string, which still works
# if directory-scope properties are used for includes, so this is not
# an error.
message("NOTE: \"${APP_NAME}\" passed to add_cfe_tables is not a previously-defined application target")
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}"
)

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}"
-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}"
)
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 ${TABLE_SELECTED_SRCS})
target_compile_definitions(${TABLE_LIBNAME} PRIVATE
CFE_CPU_NAME=${TGT}
)
target_link_libraries(${TABLE_LIBNAME} ${TABLE_PARENT_TGT})
endif()

# Create the intermediate table objects using the target compiler,
# then use "elf2cfetbl" to convert to a .tbl file
foreach(TBL ${TBL_SRC_FILES} ${ARGN})

# Get name without extension (NAME_WE) and append to list of tables
get_filename_component(TBLWE ${TBL} NAME_WE)

foreach(TGT ${TABLE_TGTLIST})
set(TABLE_LIBNAME "${TGT}_${APP_NAME}_${TBLWE}")
set(TABLE_DESTDIR "${CMAKE_CURRENT_BINARY_DIR}/${TABLE_LIBNAME}")
set(TABLE_BINARY "${TABLE_DESTDIR}/${TBLWE}.tbl")
file(MAKE_DIRECTORY ${TABLE_DESTDIR})

# 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.
if (EXISTS "${MISSION_DEFS}/tables/${TGT}_${TBLWE}.c")
set(TBL_SRC "${MISSION_DEFS}/tables/${TGT}_${TBLWE}.c")
elseif (EXISTS "${MISSION_SOURCE_DIR}/tables/${TGT}_${TBLWE}.c")
set(TBL_SRC "${MISSION_SOURCE_DIR}/tables/${TGT}_${TBLWE}.c")
elseif (EXISTS "${MISSION_DEFS}/${TGT}/tables/${TBLWE}.c")
set(TBL_SRC "${MISSION_DEFS}/${TGT}/tables/${TBLWE}.c")
elseif (EXISTS "${MISSION_DEFS}/tables/${TBLWE}.c")
set(TBL_SRC "${MISSION_DEFS}/tables/${TBLWE}.c")
elseif (EXISTS "${MISSION_SOURCE_DIR}/tables/${TBLWE}.c")
set(TBL_SRC "${MISSION_SOURCE_DIR}/tables/${TBLWE}.c")
elseif (IS_ABSOLUTE "${TBL}")
set(TBL_SRC "${TBL}")
else()
set(TBL_SRC "${CMAKE_CURRENT_SOURCE_DIR}/${TBL}")
endif()

if (NOT EXISTS "${TBL_SRC}")
message(FATAL_ERROR "ERROR: No source file for table ${TBLWE}")
else()
message("NOTE: Selected ${TBL_SRC} as source for ${APP_NAME}.${TBLWE} on ${TGT}")

# 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 ${TBL_SRC})
target_link_libraries(${TABLE_LIBNAME} PRIVATE core_api)
if (TARGET ${APP_NAME})
target_include_directories(${TABLE_LIBNAME} PRIVATE $<TARGET_PROPERTY:${APP_NAME},INCLUDE_DIRECTORIES>)
target_compile_definitions(${TABLE_LIBNAME} PRIVATE $<TARGET_PROPERTY:${APP_NAME},COMPILE_DEFINITIONS>)
endif()

# IMPORTANT: This rule assumes that the output filename of elf2cfetbl matches
# the input file name but with a different extension (.o -> .tbl)
# The actual output filename is embedded in the source file (.c), however
# this must match and if it does not the build will break. That's just the
# way it is, because NO make system supports changing rules based on the
# current content of a dependency (rightfully so).
add_custom_command(
OUTPUT ${TABLE_BINARY}
COMMAND ${CMAKE_COMMAND}
-DCMAKE_AR=${CMAKE_AR}
-DTBLTOOL=${MISSION_BINARY_DIR}/tools/elf2cfetbl/elf2cfetbl
-DLIB=$<TARGET_FILE:${TABLE_LIBNAME}>
-P ${CFE_SOURCE_DIR}/cmake/generate_table.cmake
DEPENDS ${MISSION_BINARY_DIR}/tools/elf2cfetbl/elf2cfetbl ${TABLE_LIBNAME}
WORKING_DIRECTORY ${TABLE_DESTDIR}
)

# Add a custom target to invoke the elf2cfetbl tool to generate the tbl file,
# and install that binary file to the staging area.
add_custom_target(${TABLE_LIBNAME}_tbl ALL DEPENDS ${TABLE_BINARY})
install(FILES ${TABLE_BINARY} DESTINATION ${TGT}/${INSTALL_SUBDIR})
endif()
endforeach()
endforeach()


Expand Down Expand Up @@ -513,6 +598,10 @@ endfunction(cfs_app_check_intf)
#
function(prepare)

# "cfetables" is a top level target to build all table files
# all generated table files will be added as dependencies to this target
add_custom_target(cfetables)

# 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
49 changes: 0 additions & 49 deletions cmake/generate_table.cmake

This file was deleted.

Loading

0 comments on commit 67faef0

Please sign in to comment.