From e67b22085870971d063fce3b8771a435702810e7 Mon Sep 17 00:00:00 2001 From: Joseph Hickey Date: Tue, 19 Dec 2023 10:48:28 -0500 Subject: [PATCH] Fix #142, move scripts for table building to elf2cfetbl tool The scripts and logic used to invoke elf2cfetbl should be version controlled with the tool itself, allowing it to evolve/change without affecting CFE --- CMakeLists.txt | 29 +++++- scripts/add_cfe_tables_impl.cmake | 124 +++++++++++++++++++++++++ scripts/elf2cfetbl_rules.mk | 10 ++ scripts/generate_elf_table_rules.cmake | 34 +++++++ scripts/table_rule_template.d.in | 10 ++ scripts/tabletool_rule.mk | 15 +++ 6 files changed, 218 insertions(+), 4 deletions(-) create mode 100644 scripts/add_cfe_tables_impl.cmake create mode 100644 scripts/elf2cfetbl_rules.mk create mode 100644 scripts/generate_elf_table_rules.cmake create mode 100644 scripts/table_rule_template.d.in create mode 100644 scripts/tabletool_rule.mk diff --git a/CMakeLists.txt b/CMakeLists.txt index a4e2fea..818065d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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="$" + 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) diff --git a/scripts/add_cfe_tables_impl.cmake b/scripts/add_cfe_tables_impl.cmake new file mode 100644 index 0000000..845e203 --- /dev/null +++ b/scripts/add_cfe_tables_impl.cmake @@ -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="\"$\"" + ) + + 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) diff --git a/scripts/elf2cfetbl_rules.mk b/scripts/elf2cfetbl_rules.mk new file mode 100644 index 0000000..c174435 --- /dev/null +++ b/scripts/elf2cfetbl_rules.mk @@ -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 $(@))" diff --git a/scripts/generate_elf_table_rules.cmake b/scripts/generate_elf_table_rules.cmake new file mode 100644 index 0000000..12da18b --- /dev/null +++ b/scripts/generate_elf_table_rules.cmake @@ -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}) diff --git a/scripts/table_rule_template.d.in b/scripts/table_rule_template.d.in new file mode 100644 index 0000000..4fa6648 --- /dev/null +++ b/scripts/table_rule_template.d.in @@ -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} diff --git a/scripts/tabletool_rule.mk b/scripts/tabletool_rule.mk new file mode 100644 index 0000000..6b34c75 --- /dev/null +++ b/scripts/tabletool_rule.mk @@ -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)/$(<)"