Skip to content

Commit

Permalink
Fix #142, move scripts for table building to elf2cfetbl tool
Browse files Browse the repository at this point in the history
The scripts and logic used to invoke elf2cfetbl should be version
controlled with the tool itself, allowing it to evolve/change
without affecting CFE
  • Loading branch information
jphickey committed Dec 19, 2023
1 parent 15314d6 commit e67b220
Show file tree
Hide file tree
Showing 6 changed files with 218 additions and 4 deletions.
29 changes: 25 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,32 @@
# CMake snippet for building elf2cfetbl
#
include_directories(${MISSION_BINARY_DIR}/inc)
include_directories(${osal_MISSION_DIR}/src/os/inc)
include_directories(${cfe-core_MISSION_DIR}/src/inc)

project(CFS_TABLETOOL C)

add_executable(elf2cfetbl elf2cfetbl.c)

install(TARGETS elf2cfetbl DESTINATION host)
# Export relevant information so the parent script can invoke the tool
set(CFS_TABLETOOL_SCRIPT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/scripts" CACHE INTERNAL "CFS table tool script directory")

add_custom_target(tabletool-execute
COMMAND $(MAKE)
CC="${CMAKE_C_COMPILER}"
CFLAGS="${CMAKE_C_FLAGS}"
AR="${CMAKE_AR}"
TBLTOOL="$<TARGET_FILE:elf2cfetbl>"
cfetables
WORKING_DIRECTORY
"${MISSION_BINARY_DIR}/tables"
DEPENDS
mission-cfetables
elf2cfetbl
)

add_dependencies(mission-all tabletool-execute)
add_dependencies(mission-install tabletool-execute)
add_dependencies(mission-prebuild elf2cfetbl)

install(DIRECTORY ${CMAKE_BINARY_DIR}/tables/staging/ DESTINATION .)


install(TARGETS elf2cfetbl DESTINATION host)
124 changes: 124 additions & 0 deletions scripts/add_cfe_tables_impl.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
##################################################################
#
# FUNCTION: do_add_cfe_tables_impl
#
# Simplified routine to add CFS tables to be built with an app
#
# 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 "${ADDTBL_ARG_APP_NAME}.${TABLE_NAME}" where ${ADDTBL_ARG_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_${ADDTBL_ARG_TARGET_NAME}_{TABLE_FQNAME}" where TGT reflects the name
# of the target from targets.cmake and TABLE_FQNAME reflects the first
# parameter to this function.
#
function(do_add_cfe_tables_impl TABLE_FQNAME)

cmake_parse_arguments(ADDTBL_ARG "" "APP_NAME;TARGET_NAME;INSTALL_SUBDIR" "" ${ARGN})

set(TEMPLATE_FILE "${CFS_TABLETOOL_SCRIPT_DIR}/table_rule_template.d.in")
set(TABLE_GENSCRIPT "${CFS_TABLETOOL_SCRIPT_DIR}/generate_elf_table_rules.cmake")
set(TABLE_LIBNAME "tblobj_${ADDTBL_ARG_TARGET_NAME}_${TABLE_FQNAME}")

set(TABLE_CMD_OPTS
-DTEMPLATE_FILE="${TEMPLATE_FILE}"
-DAPP_NAME="${ADDTBL_ARG_APP_NAME}"
-DTARGET_NAME="${ADDTBL_ARG_TARGET_NAME}"
-DARCHIVE_FILE="\"$<TARGET_FILE:${TABLE_LIBNAME}>\""
)

if (ADDTBL_ARG_INSTALL_SUBDIR)
list(APPEND TABLE_CMD_OPTS
-DINSTALL_SUBDIR="${ADDTBL_ARG_INSTALL_SUBDIR}"
)
endif()

# If there is an ${ADDTBL_ARG_APP_NAME}.table target defined, make
# things depend on that. Otherwise just depend on core_api.
set(TABLE_DEPENDENCIES core_api)
if (TARGET ${ADDTBL_ARG_APP_NAME}.table)
list(APPEND TABLE_DEPENDENCIES ${ADDTBL_ARG_APP_NAME}.table)
endif()

# Note that the file list passed in are 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 ${ADDTBL_ARG_UNPARSED_ARGUMENTS})

# 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)
set(TABLE_RULEFILE "${MISSION_BINARY_DIR}/tables/${ADDTBL_ARG_TARGET_NAME}_${TABLE_FQNAME}.${TABLE_BASENAME}.d")


# 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}"
FALLBACK_FILE "${CMAKE_CURRENT_SOURCE_DIR}/${TBL}"
PREFIX "${ADDTBL_ARG_TARGET_NAME}"
SUBDIR tables
)

list(APPEND TABLE_SELECTED_SRCS ${TBL_SRC})

set_property(SOURCE "${TBL_SRC}" APPEND PROPERTY COMPILE_DEFINITIONS
CFE_TABLE_NAME=${TABLE_BASENAME}
)

# Note the table is not generated directly here, as it may require the native system compiler, so
# the call to the table tool (elf2cfetbl 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.
add_custom_command(
OUTPUT "${TABLE_RULEFILE}"
COMMAND ${CMAKE_COMMAND}
${TABLE_CMD_OPTS}
-DOUTPUT_FILE="${TABLE_RULEFILE}"
-DTABLE_NAME="${TABLE_BASENAME}"
-DSOURCES="${TBL_SRC}"
-DOBJEXT="${CMAKE_C_OUTPUT_EXTENSION}"
-P "${TABLE_GENSCRIPT}"
WORKING_DIRECTORY
${MISSION_BINARY_DIR}/tables
DEPENDS
${TABLE_TEMPLATE}
${TABLE_GENSCRIPT}
${TABLE_DEPENDENCIES}
)

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

endforeach(TBL ${TBL_DEFAULT_SRC_FILES} ${ARGN})

# 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=${ADDTBL_ARG_TARGET_NAME}
)
target_link_libraries(${TABLE_LIBNAME} ${TABLE_DEPENDENCIES})


endfunction(do_add_cfe_tables_impl)
10 changes: 10 additions & 0 deletions scripts/elf2cfetbl_rules.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Rule for traditional CFE table generation via elf2cfetbl

# The dependency of this target should always be an absolute pathname to
# the intermediate library file as it is generated by a CMake script via
# the TARGET_FILE property. Therefore, the same path should still work
# after the "cd" command. The "cd" is so the ar tool writes the object file
# into a separate dir, in case of similarly-named files on different cpus.
elf/%:
@mkdir -pv "$(dir $(@))"
cd "$(dir $(@))" && $(AR) x "$(<)" "$(notdir $(@))"
34 changes: 34 additions & 0 deletions scripts/generate_elf_table_rules.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
##################################################################
#
# Sub-script to capture the table compile/generation environment
#
# This small script runs at build time (as opposed to prep time)
# which captures a set of environment metadata
#
# It must be done this way such that generator expressions will
# be evaluated now, during the arch build process, rather than
# deferring the evaluation to the parent build where they may
# have different values.
#
##################################################################

set(STAGING_DIR staging ${TARGET_NAME} ${INSTALL_SUBDIR})
string(REPLACE ";" "/" STAGING_DIR "${STAGING_DIR}")

set(TABLE_BINARY "${STAGING_DIR}/${TABLE_NAME}.tbl")
set(TMP_DIR "elf/${TARGET_NAME}")
set(TABLE_RULES)

foreach(TBL_SRC ${SOURCES})

get_filename_component(DEP_FILE ${TBL_SRC} NAME)
set(DEP_FILE "${TMP_DIR}/${DEP_FILE}${OBJEXT}")
string(APPEND TABLE_RULES
"${DEP_FILE}: ${ARCHIVE_FILE}\n"
"${TABLE_BINARY}: ${DEP_FILE}\n"
"\n"
)

endforeach()

configure_file(${TEMPLATE_FILE} ${OUTPUT_FILE})
10 changes: 10 additions & 0 deletions scripts/table_rule_template.d.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Template for table configuration

cfetables: ${TABLE_BINARY}

${TABLE_BINARY}: CFE_TABLE_CPUNAME := ${TARGET_NAME}
${TABLE_BINARY}: CFE_TABLE_APPNAME := ${APP_NAME}
${TABLE_BINARY}: CFE_TABLE_BASENAME := ${TABLE_NAME}

# Rules to build ${TABLE_BINARY}
${TABLE_RULES}
15 changes: 15 additions & 0 deletions scripts/tabletool_rule.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Makefile for EDS-based CFE table generation
.PHONY: cfetables

cfetables:
@echo "Table build completed"

# The dependency of this rule should always be a relative path starting with elf/,
# at least with the current rule generator script, so it matches the elf/% pattern rule.
# But because elf2cfetbl only writes its output to the current working dir, it has to be run
# after changing dirs into the staging area. Thus the path to the elf file needs to be adjusted.
# Ideally this chould be done with the $(abspath f...) function but this doesn't exist in older versions.
# As a workaround, $CURDIR is used.
staging/%.tbl:
@mkdir -pv "$(dir $(@))"
cd "$(dir $(@))" && $(TBLTOOL) $(TBLTOOL_FLAGS) "$(CURDIR)/$(<)"

0 comments on commit e67b220

Please sign in to comment.