diff --git a/cmake/generate_build_env.cmake b/cmake/generate_build_env.cmake new file mode 100644 index 000000000..ea179281e --- /dev/null +++ b/cmake/generate_build_env.cmake @@ -0,0 +1,48 @@ +################################################################## +# +# cFS version metadata collection script +# +# This small script runs at build time (as opposed to prep time) +# and is intended to extract information about the current +# build environment - this may change after initial makefile creation +# +################################################################## + +# All 3 of these may be passed via environment variables to force a particular +# date, user, or hostname i.e. if hoping to reproduce an exact binary of a prior build +# They are free-form strings, will be built/linked into the final CONFIGDATA object. + +# Get the current date and time +set(BUILDDATE $ENV{BUILDDATE}) +if (NOT BUILDDATE) + execute_process( + COMMAND date "+%Y%m%d%H%M" + OUTPUT_VARIABLE BUILDDATE + OUTPUT_STRIP_TRAILING_WHITESPACE + ) +endif(NOT BUILDDATE) + +# Get the build host +set(BUILDHOST $ENV{HOSTNAME}) +if (NOT BUILDHOST) + execute_process( + COMMAND hostname + OUTPUT_VARIABLE BUILDHOST + OUTPUT_STRIP_TRAILING_WHITESPACE + ) +endif (NOT BUILDHOST) + +# Get the user ID +set(BUILDUSER $ENV{USER}) +if (NOT BUILDUSER) + execute_process( + COMMAND whoami + OUTPUT_VARIABLE BUILDUSER + OUTPUT_STRIP_TRAILING_WHITESPACE + ) +endif (NOT BUILDUSER) + +# Use configure_file() command to generate the final output file because this can detect +# and only update it if it changes. +set(CFE_KEYVALUE_TABLE_NAME "CFE_BUILD_ENV_TABLE") +configure_file(${BIN}/cfe_build_env.in ${BIN}/src/cfe_build_env_table.c @ONLY) diff --git a/cmake/generate_git_module_version.cmake b/cmake/generate_git_module_version.cmake new file mode 100644 index 000000000..7a2559324 --- /dev/null +++ b/cmake/generate_git_module_version.cmake @@ -0,0 +1,75 @@ +################################################################## +# +# cFS version metadata collection script +# +# This small script runs at build time (as opposed to prep time) +# and is intended to extract version metadata from the current source +# tree. It is done each time that the code is built, since the +# metadata could change at any time (i.e. a different branch could +# be checked out, or additional changes committed) +# +# Currently only git is supported as a version control source, however +# it could be extended to others by adding the appropriate command +# +################################################################## + +set(GIT_EXECUTABLE git) + +function(get_version DEP) + if (DEP STREQUAL "MISSION") + set(NAME ${MISSION_NAME}) + set(DIR ${MISSION_SOURCE_DIR}) + else() + if(EXISTS ${${DEP}_MISSION_DIR}/version_info.cmake) + include(${${DEP}_MISSION_DIR}/version_info.cmake) + else() + set(NAME ${DEP}) + endif() + set(DIR ${${DEP}_MISSION_DIR}) + endif() + message("inside get_version for ${DEP}") + execute_process( + COMMAND ${GIT_EXECUTABLE} describe --tags --always --dirty + WORKING_DIRECTORY ${DIR} + OUTPUT_VARIABLE GIT_DESC_OUTPUT + RESULT_VARIABLE GIT_RESULT + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + # Export output to parent scope + set(${DEP}_NAME "${NAME}" PARENT_SCOPE) + + # If result was successful, then string-ify it, otherwise use NULL + if (GIT_RESULT EQUAL 0) + set(${DEP}_VERSION "\"git:${GIT_DESC_OUTPUT}\"" PARENT_SCOPE) + else() + set(${DEP}_VERSION "NULL" PARENT_SCOPE) + endif() + +endfunction() + + +# First read in any variables that are passed in from the parent process +# There may be many of these and they may not all be passable via -D options +file(STRINGS "${BIN}/mission_vars.cache" PARENTVARS) +set(VARNAME) +foreach(PV ${PARENTVARS}) + if (VARNAME) + set(${VARNAME} ${PV}) + set(VARNAME) + else() + set(VARNAME ${PV}) + endif() +endforeach(PV ${PARENTVARS}) + +# Get version for all mission apps/dependencies (they may be different) +foreach(DEP "MISSION" ${MISSION_DEPS}) + get_version(${DEP}) +endforeach() + + +# Use configure_file() command to generate the final output file because this can detect +# and only update it if it changes. +set(CFE_KEYVALUE_TABLE_NAME "CFE_MODULE_VERSION_TABLE") +configure_file(${BIN}/cfe_module_version.in ${BIN}/src/cfe_module_version_table.c @ONLY) diff --git a/cmake/mission_build.cmake b/cmake/mission_build.cmake index 66b0d43c1..7920af487 100644 --- a/cmake/mission_build.cmake +++ b/cmake/mission_build.cmake @@ -72,6 +72,95 @@ function(initialize_globals) endfunction(initialize_globals) +################################################################## +# +# FUNCTION: generate_build_version_templates +# +# Generates file templates for use with configure_file() which is +# invoked at build time to get the required information. +# +# Note that some information may change between generation and build +# times, hence why only a template can be generated here, the final +# file content must be generated via a build rule. +# +function(generate_build_version_templates) + + # File header for build info template (tag file as auto-generated) + string(CONCAT GENERATED_FILE_HEADER + "/* This file is auto-generated from CMake build system. Do not manually edit! */\n" + "#include \"target_config.h\"\n" + "const CFE_ConfigKeyValue_t @CFE_KEYVALUE_TABLE_NAME@[] = {\n" + ) + + # File trailer for build info template + string(CONCAT GENERATED_FILE_TRAILER + "{ NULL, NULL } /* End of list */\n" + "};\n" + "/* End of file */\n" + ) + + # These variables are deferred until build time + foreach (VAR BUILDDATE BUILDUSER BUILDHOST) + list (APPEND GENERATED_FILE_CONTENT "{ \"${VAR}\", \"@${VAR}@\" },") + endforeach () + string(REPLACE ";" "\n" GENERATED_FILE_CONTENT "${GENERATED_FILE_CONTENT}") + + # Write a template for build/config information + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/cfe_generated_file.h.in ${CMAKE_BINARY_DIR}/cfe_build_env.in) + + # Content for version info - all are deferred until build time + set(GENERATED_FILE_CONTENT) + foreach(DEP "MISSION" ${MISSION_DEPS}) + list (APPEND GENERATED_FILE_CONTENT "{ \"${DEP}\", @${DEP}_VERSION@ },") + endforeach() + string(REPLACE ";" "\n" GENERATED_FILE_CONTENT "${GENERATED_FILE_CONTENT}") + + # Write a template for version information + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/cfe_generated_file.h.in ${CMAKE_BINARY_DIR}/cfe_module_version.in) + + # The actual version information (to fill out the template above) is obtained at build time + # via a script that is executed as a build target. If this script exists in the mission defs + # directory (user-supplied) then use that. Otherwise a pre-canned "git" version is included + # as a fallback, which should work for source trees assembled via git submodules or subtrees. + if (EXISTS "${MISSION_DEFS}/generate_module_version.cmake") + set(VERSION_SCRIPT "${MISSION_DEFS}/generate_module_version.cmake") + else() + set(VERSION_SCRIPT "${CFE_SOURCE_DIR}/cmake/generate_git_module_version.cmake") + endif() + + add_custom_target(cfe-module-version + COMMAND + ${CMAKE_COMMAND} -D BIN=${CMAKE_BINARY_DIR} + -P "${VERSION_SCRIPT}" + WORKING_DIRECTORY + ${CMAKE_SOURCE_DIR} + VERBATIM + ) + + add_custom_target(cfe-build-env + COMMAND + ${CMAKE_COMMAND} -D BIN=${CMAKE_BINARY_DIR} + -P "${CFE_SOURCE_DIR}/cmake/generate_build_env.cmake" + WORKING_DIRECTORY + ${CMAKE_SOURCE_DIR} + VERBATIM + ) + + # Content for build info - these vars can be evaulated right now, no need to defer + set(GENERATED_FILE_HEADER "/* Automatically generated from CMake build system */") + string(CONCAT GENERATED_FILE_CONTENT + "const char CFE_MISSION_NAME[] = \"${MISSION_NAME}\";\n" + "const char CFE_MISSION_CONFIG[] = \"${MISSIONCONFIG}\";\n" + ) + set(GENERATED_FILE_TRAILER "/* End of file */") + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/cfe_generated_file.h.in ${CMAKE_BINARY_DIR}/src/cfe_mission_strings.c) + + add_custom_target(mission-version + DEPENDS cfe-module-version cfe-build-env + ) + +endfunction(generate_build_version_templates) + ################################################################## # @@ -267,17 +356,8 @@ function(prepare) endif (NOT "${${VARL}}" STREQUAL "") endforeach(VARL ${VARLIST}) file(WRITE "${CMAKE_BINARY_DIR}/mission_vars.cache" "${MISSION_VARCACHE}") - - # Generate version information for the executable file. This is done by executing a small CMAKE - # at _build_ time (not at prep time since it might change between now and then) that collects - # the info out of the version control system in use (git is currently assumed). - add_custom_target(mission-version - COMMAND - ${CMAKE_COMMAND} -D BIN=${CMAKE_BINARY_DIR} - -P ${CFE_SOURCE_DIR}/cmake/version.cmake - WORKING_DIRECTORY - ${CMAKE_SOURCE_DIR} - ) + + generate_build_version_templates() # Generate the tools for the native (host) arch add_subdirectory(${MISSION_SOURCE_DIR}/tools tools) diff --git a/cmake/target/CMakeLists.txt b/cmake/target/CMakeLists.txt index 6ef722b6a..200f6cee7 100644 --- a/cmake/target/CMakeLists.txt +++ b/cmake/target/CMakeLists.txt @@ -21,30 +21,108 @@ if (NOT DEFINED ${TGTNAME}_PROCESSORID) message(FATAL_ERROR "${TGTNAME}_PROCESSORID must be defined to link a final exe") endif (NOT DEFINED ${TGTNAME}_PROCESSORID) -# Create a file for the statically-linked module list for this target -# do this for both PSP and CFS static modules -file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/psp_module_list.inc.tmp" - "/* Automatically generated based on target config */\n") +string(CONCAT GENERATED_FILE_HEADER + "/* This file is auto-generated from CMake build system. Do not manually edit! */\n" + "#include \"target_config.h\"\n" +) + +string(CONCAT GENERATED_FILE_TRAILER + "/* End of file */\n" +) + +# Generate a list of PSP modules along with a pointer to its API structure/entry point +set(GENERATED_EXTERNS) +set(GENERATED_KEYVALS) foreach(PSPMOD ${${TGTNAME}_PSP_MODULELIST}) - file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/psp_module_list.inc.tmp" "LOAD_PSP_MODULE(${PSPMOD})\n") + list(APPEND GENERATED_EXTERNS "extern char CFE_PSP_${PSPMOD}_API;\n") + list(APPEND GENERATED_KEYVALS "{ .Name = \"${PSPMOD}\", .Api = &CFE_PSP_${PSPMOD}_API },\n") endforeach(PSPMOD ${${TGTNAME}_PSP_MODULELIST}) -execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different - "${CMAKE_CURRENT_BINARY_DIR}/psp_module_list.inc.tmp" - "${CMAKE_CURRENT_BINARY_DIR}/psp_module_list.inc") -file (REMOVE "${CMAKE_CURRENT_BINARY_DIR}/psp_module_list.inc.tmp") -file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cfs_static_symbol_list.inc.tmp" - "/* Automatically generated based on target config */\n") +string(CONCAT GENERATED_FILE_CONTENT + ${GENERATED_EXTERNS} + "const CFE_StaticModuleLoadEntry_t CFE_PSP_MODULE_LIST[] = {\n" + ${GENERATED_KEYVALS} + "{ NULL } /* End of list */\n" + "};\n" +) + +configure_file(${CFE_SOURCE_DIR}/cmake/cfe_generated_file.h.in ${CMAKE_CURRENT_BINARY_DIR}/cfe_psp_module_list.c) + +# Generate lists of modules that will be statically linked into this CFE core target +set(GENERATED_ENTRIES_CORE_MODULES) +foreach(DEP ${MISSION_CORE_MODULES}) + list(APPEND GENERATED_ENTRIES_CORE_MODULES "\"{ ${DEP}\" },\n") +endforeach() + +set(GENERATED_ENTRIES_STATIC_APPS) +foreach(DEP ${${TGTNAME}_STATIC_APPLIST}) + list(APPEND GENERATED_ENTRIES_STATIC_APPS "{ \"${DEP}\" },\n") +endforeach() + +string(CONCAT GENERATED_FILE_CONTENT + "CFE_ConfigName_t CFE_CORE_MODULE_LIST[] = {\n" + ${GENERATED_ENTRIES_CORE_MODULES} + "NULL /* End of list */\n" + "};\n" + "CFE_ConfigName_t CFE_STATIC_APP_LIST[] = {\n" + ${GENERATED_ENTRIES_STATIC_APPS} + "NULL /* End of list */\n" + "};\n" +) + +configure_file(${CFE_SOURCE_DIR}/cmake/cfe_generated_file.h.in ${CMAKE_CURRENT_BINARY_DIR}/cfe_static_module_list.c) + +# Generate a list of symbol names that must be known at runtime without OS loader support +set(GENERATED_EXTERNS) +set(GENERATED_KEYVALS) foreach(CFSSYM ${${TGTNAME}_STATIC_SYMLIST}) - file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/cfs_static_symbol_list.inc.tmp" "STATIC_CFS_SYMBOL(${CFSSYM})\n") + string(REPLACE "," ";" CFSSYM "${CFSSYM}") + list(GET CFSSYM 0 SYM_NAME) + list(GET CFSSYM 1 SYM_MODULE) + list(APPEND GENERATED_EXTERNS "extern void ${SYM_NAME} (void);\n") + list(APPEND GENERATED_KEYVALS "{ .Name = \"${SYM_NAME}\", .Address = &{SYM_NAME}, .Module = \"${SYM_MODULE}\" },") endforeach(CFSSYM ${${TGTNAME}_STATIC_SYMLIST}) -execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different - "${CMAKE_CURRENT_BINARY_DIR}/cfs_static_symbol_list.inc.tmp" - "${CMAKE_CURRENT_BINARY_DIR}/cfs_static_symbol_list.inc") -file (REMOVE "${CMAKE_CURRENT_BINARY_DIR}/cfs_static_symbol_list.inc.tmp") + +string(CONCAT GENERATED_FILE_HEADER + "/* This file is auto-generated from CMake build system. Do not manually edit! */\n" + "#include \"osapi-module.h\"\n" +) + +string(CONCAT GENERATED_FILE_CONTENT + ${GENERATED_EXTERNS} + "OS_static_symbol_record_t OS_STATIC_SYMBOL_TABLE[] = {\n" + ${GENERATED_KEYVALS} + "{ NULL } /* End of list */\n" + "};\n" +) + +configure_file(${CFE_SOURCE_DIR}/cmake/cfe_generated_file.h.in ${CMAKE_CURRENT_BINARY_DIR}/cfe_static_symbol_list.c) + +add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/cfe_build_env_table.c + COMMAND ${CMAKE_COMMAND} -E copy + ${MISSION_BINARY_DIR}/src/cfe_build_env_table.c + ${CMAKE_CURRENT_BINARY_DIR}/cfe_build_env_table.c + DEPENDS + ${MISSION_BINARY_DIR}/src/cfe_build_env_table.c +) +add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/cfe_module_version_table.c + COMMAND ${CMAKE_COMMAND} -E copy + ${MISSION_BINARY_DIR}/src/cfe_module_version_table.c + ${CMAKE_CURRENT_BINARY_DIR}/cfe_module_version_table.c + DEPENDS + ${MISSION_BINARY_DIR}/src/cfe_module_version_table.c +) # Target for the final executable -add_executable(core-${TGTNAME} src/target_config.c) +add_executable(core-${TGTNAME} + ${MISSION_BINARY_DIR}/src/cfe_mission_strings.c + ${CMAKE_CURRENT_BINARY_DIR}/cfe_module_version_table.c + ${CMAKE_CURRENT_BINARY_DIR}/cfe_build_env_table.c + ${CMAKE_CURRENT_BINARY_DIR}/cfe_psp_module_list.c + ${CMAKE_CURRENT_BINARY_DIR}/cfe_static_symbol_list.c + ${CMAKE_CURRENT_BINARY_DIR}/cfe_static_module_list.c + src/target_config.c +) target_compile_definitions(core-${TGTNAME} PRIVATE CFE_DEFAULT_MODULE_EXTENSION="${CMAKE_SHARED_MODULE_SUFFIX}" @@ -54,8 +132,7 @@ target_compile_definitions(core-${TGTNAME} PRIVATE CFE_CPU_ID_VALUE=${${TGTNAME}_PROCESSORID} ) -target_include_directories(core-${TGTNAME} PRIVATE - "${CMAKE_CURRENT_BINARY_DIR}" +target_include_directories(core-${TGTNAME} PRIVATE "${CMAKE_BINARY_DIR}/${CFE_CORE_TARGET}/inc" ) diff --git a/cmake/target/inc/target_config.h b/cmake/target/inc/target_config.h index c4af5307f..51935f396 100644 --- a/cmake/target/inc/target_config.h +++ b/cmake/target/inc/target_config.h @@ -76,6 +76,27 @@ typedef const struct CFE_StaticModuleApi_t *Api; } CFE_StaticModuleLoadEntry_t; +/** + * A record containing a configuration name + * This is a single entry in a list of simple strings. + */ +typedef const struct +{ + const char *Name; +} CFE_ConfigName_t; + + +/** + * A record containing a configuration key-value pair + * The data are simple strings defined at compile time, and + * do not change until next build (always const). + */ +typedef const struct +{ + const char *Key; + const void *Value; +} CFE_ConfigKeyValue_t; + /** * Core Flight Executive configuration information. */ @@ -129,12 +150,30 @@ extern Target_CfeConfigData GLOBAL_CFE_CONFIGDATA; */ typedef const struct { - const char *MissionVersion; /**< Version string acquired from version control system at build time */ - const char *CfeVersion; /**< Version string acquired from version control system at build time */ - const char *OsalVersion; /**< Version string acquired from version control system at build time */ + const char *MissionName; /**< The Mission Name from confguration */ + + /* + * Note: the version strings in these fields should reflect the administratively-assigned + * "semantic version" identifiers, typically from a "version.h" header file of + * some type which is manually updated at various points in the development cycle. + * + * This is separate/distinct from the source control based revision + * information, although it may be similar/related. All automatically + * obtained source revision info is in the "ModuleVersionList" below. + */ + const char *MissionVersion; /**< Version string from mission source tree at build time (currently unused/unset) */ + const char *CfeVersion; /**< Version string from CFE source tree at build time */ + const char *OsalVersion; /**< Version string from OSAL source tree at build time */ + const char *Config; /**< Configuration used for build */ - const char *Date; /**< Date and time of build */ - const char *User; /**< User ID and build machine */ + + /* + * Note: date and user info have been moved into the BuildEnvironment below, + * but these members must exist in this structure (for now) for compatibility. + * These pointers will be NULL at runtime. + */ + const char *Date; /**< Not set. Get value from BuildEnvironment instead. */ + const char *User; /**< Not set. Get value from BuildEnvironment instead. */ /* * Default values for CPU ID and CPU Name @@ -150,6 +189,11 @@ typedef const struct Target_PspConfigData *PspConfig; /**< PSP configuration sub-structure */ CFE_StaticModuleLoadEntry_t *PspModuleList; /**< List of PSP modules (API structures) statically linked into the core EXE */ + CFE_ConfigKeyValue_t *BuildEnvironment; /**< Environment details of build system at the last time CFE core was built */ + CFE_ConfigKeyValue_t *ModuleVersionList; /**< List of module versions at the last time CFE core was built */ + CFE_ConfigName_t *CoreModuleList; /**< List of CFE core support module names that are statically linked */ + CFE_ConfigName_t *StaticAppList; /**< List of additional CFS Applications that are statically linked into this binary */ + } Target_ConfigData; diff --git a/cmake/target/src/target_config.c b/cmake/target/src/target_config.c index bbf33104b..ceb7494cd 100644 --- a/cmake/target/src/target_config.c +++ b/cmake/target/src/target_config.c @@ -38,8 +38,8 @@ #include "cfe_es.h" #include "cfe_time.h" #include "private/cfe_es_resetdata_typedef.h" -#include "cfecfs_version_info.h" -#include "cfecfs_build_info.h" +#include "cfe_version.h" /* for CFE_VERSION_STRING */ +#include "osapi-version.h" /* for OS_VERSION_STRING */ #ifndef CFE_CPU_NAME_VALUE @@ -62,6 +62,78 @@ #define CFE_DEFAULT_CORE_FILENAME "" #endif +/* + * Many configdata items are instantiated by the + * build system, where it generates a .c file containing + * the data, which is then compiled and linked with this file. + */ + +extern const char CFE_MISSION_NAME[]; /**< Name of CFE mission */ +extern const char CFE_MISSION_CONFIG[]; /**< Configuration name used for build */ + +/** + * A list of modules which are statically linked into CFE core. + * + * For module names which appear in this list, the code is directly + * linked into the core executable binary file, and therefore means + * several things: + * + * - the module code is guaranteed to be present + * - functions it provides may be used by CFE core apps + * - it cannot be updated/changed without rebuilding CFE core. + */ +extern CFE_ConfigName_t CFE_CORE_MODULE_LIST[]; + +/** + * A list of CFS apps which are also statically linked with this binary. + * + * These apps can be started without dynamically loading any modules, + * however the entry point must be separately provided in order to avoid + * needing any support from the OS dynamic loader subsystem. + */ +extern CFE_ConfigName_t CFE_STATIC_APP_LIST[]; + +/** + * A key-value table containing certain environment information from the build system + * at the time CFE core was built. + * + * This contains basic information such as the time of day, build host, and user. + */ +extern CFE_ConfigKeyValue_t CFE_BUILD_ENV_TABLE[]; + +/** + * Version control (source code) versions of all modules + * + * This list includes all modules known to the build system as determined by the + * version control system in use (e.g. git). It is generated by a post-build step + * to query version control and should change automatically every time code is + * checked in or out. + * + * Notably this includes _all_ modules known to the build system at the time CFE + * core was built, regardless of whether those modules are configured for runtime + * (dynamic) or static linkage. + * + * For dynamic modules, this means the version info can become outdated if/when + * a single module is rebuilt/reloaded after the original CFE build. The keys in + * this table may be be checked against the CFE_STATIC_MODULE_LIST above to + * determine if static or dynamic linkage was used. In the case of dynamic linkage, + * then this table only represents the version of the module that was present at the + * time CFE was built, not necessarily the version on the target filesystem. + */ +extern CFE_ConfigKeyValue_t CFE_MODULE_VERSION_TABLE[]; + +/** + * A list of PSP modules included in this build of CFE core. + * + * These are always statically linked, and this table contains a pointer + * to its API structure, which in turn contains its entry point. + */ +extern CFE_StaticModuleLoadEntry_t CFE_PSP_MODULE_LIST[]; + + +/** + * A structure that encapsulates all the CFE static configuration + */ Target_CfeConfigData GLOBAL_CFE_CONFIGDATA = { /* @@ -88,47 +160,6 @@ Target_CfeConfigData GLOBAL_CFE_CONFIGDATA = .RamDiskTotalSectors = CFE_PLATFORM_ES_RAM_DISK_NUM_SECTORS }; -/* - * PSP Static Module load section - * - * This is in here (the target-specific file) rather than the PSP config data structure - * because it can be different for different targets even those that share the same basic PSP. - * - * For instance, if two boards use the same basic HW hardware but one of them has a special - * timer interrupt for synchronization, only this second target would include a PSP module - * to bind to that special interrupt. - * - * In order to reference the driver from a dynamically generated set, - * two inclusions of the same file are done using different definitions - * of the LOAD_PSP_MODULE() macro. The first pass creates "extern" references - * to the API objects, the second pass generates a table of pointers to them. - */ - -/* - * Definition of LOAD_*_MODULE for the first pass, creates an extern declaration - * for the API object which must be named appropriately. - */ -#define LOAD_PSP_MODULE(name) extern CFE_StaticModuleApi_t CFE_PSP_##name##_API; -#include "psp_module_list.inc" -#undef LOAD_PSP_MODULE - -/* - * Definition of LOAD_PSP_MODULE for the second pass, creates an entry with - * the name and a pointer to the API object. - * - * This is done here in the target file and NOT in the PSP because it is - * configured specifically to each target. The contents of the "psp_module_list.inc" - * file are generated by the build scripts and are different for each target. - */ -#define LOAD_PSP_MODULE(name) { .Name = #name, .Api = &CFE_PSP_##name##_API }, -static CFE_StaticModuleLoadEntry_t GLOBAL_PSP_MODULELIST[] = -{ -#include "psp_module_list.inc" - { .Name = NULL } -}; -#undef LOAD_PSP_MODULE - - /** * Instantiation of global system-wide configuration struct * This contains build info plus pointers to the PSP and CFE @@ -137,12 +168,10 @@ static CFE_StaticModuleLoadEntry_t GLOBAL_PSP_MODULELIST[] = */ Target_ConfigData GLOBAL_CONFIGDATA = { - .MissionVersion = MISSION_VERSION, - .CfeVersion = CFE_VERSION, - .OsalVersion = OSAL_VERSION, - .Config = MISSION_CONFIG, - .Date = MISSION_BUILDDATE, - .User = MISSION_BUILDUSER "@" MISSION_BUILDHOST, + .MissionName = CFE_MISSION_NAME, + .CfeVersion = CFE_SRC_VERSION, + .OsalVersion = OS_VERSION, + .Config = CFE_MISSION_CONFIG, .Default_CpuName = CFE_CPU_NAME_VALUE, .Default_CpuId = CFE_CPU_ID_VALUE, .Default_SpacecraftId = CFE_SPACECRAFT_ID_VALUE, @@ -150,26 +179,10 @@ Target_ConfigData GLOBAL_CONFIGDATA = .Default_CoreFilename = CFE_DEFAULT_CORE_FILENAME, .CfeConfig = &GLOBAL_CFE_CONFIGDATA, .PspConfig = &GLOBAL_PSP_CONFIGDATA, - .PspModuleList = GLOBAL_PSP_MODULELIST, + .PspModuleList = CFE_PSP_MODULE_LIST, + .BuildEnvironment = CFE_BUILD_ENV_TABLE, + .ModuleVersionList = CFE_MODULE_VERSION_TABLE, + .CoreModuleList = CFE_CORE_MODULE_LIST, + .StaticAppList = CFE_STATIC_APP_LIST, }; - - -/* - * Instantiate a list of symbols that should be statically linked into the - * final executable. - * - * This table is in turn used by OSAL if the OS_STATIC_LOADER feature is - * enabled, such that OS_SymbolLookup may return values from this table - * in lieu of an OS/library-provided dynamic lookup function. - */ -#define STATIC_CFS_SYMBOL(n,m) extern void n (void); -#include "cfs_static_symbol_list.inc" -#undef STATIC_CFS_SYMBOL -#define STATIC_CFS_SYMBOL(n,m) { .Name = #n, .Address = n, .Module = #m }, -OS_static_symbol_record_t OS_STATIC_SYMBOL_TABLE[] = -{ -#include "cfs_static_symbol_list.inc" - { NULL, NULL } /* End of list marker */ -}; -#undef STATIC_CFS_SYMBOL diff --git a/cmake/version.cmake b/cmake/version.cmake deleted file mode 100644 index 5a0bdb8c7..000000000 --- a/cmake/version.cmake +++ /dev/null @@ -1,133 +0,0 @@ -################################################################## -# -# cFS version metadata collection script -# -# This small script runs at build time (as opposed to prep time) -# and is intended to extract version metadata from the current source -# tree. It is done each time that the code is built, since the -# metadata could change at any time (i.e. a different branch could -# be checked out, or additional changes committed) -# -# This generates two header files: -# cfecfs_version_info.h -- contains version control metadata -# cfecfs_build_info.h -- contains build information (user,host,etc) -# -# Currently only git is supported as a version control source, however -# it could be extended to others by adding the appropriate command -# -################################################################## - -set(GIT_EXECUTABLE git) - -function(get_version DEP) - if (DEP STREQUAL "MISSION") - set(NAME ${MISSION_NAME}) - set(DIR ${MISSION_SOURCE_DIR}) - else() - if(EXISTS ${${DEP}_MISSION_DIR}/version_info.cmake) - include(${${DEP}_MISSION_DIR}/version_info.cmake) - else() - set(NAME ${DEP}) - endif() - set(DIR ${${DEP}_MISSION_DIR}) - endif() - execute_process( - COMMAND ${GIT_EXECUTABLE} describe --tags --always --dirty - WORKING_DIRECTORY ${DIR} - OUTPUT_VARIABLE GIT_DESC_OUTPUT - RESULT_VARIABLE GIT_RESULT - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - if (NOT GIT_RESULT EQUAL 0) - set(GIT_DESC_OUTPUT "error/unknown") - endif() - set(${DEP}_NAME "${NAME}" PARENT_SCOPE) - set(${DEP}_VERSION "${GIT_DESC_OUTPUT}" PARENT_SCOPE) -endfunction() - - -# First read in any variables that are passed in from the parent process -# There may be many of these and they may not all be passable via -D options -file(STRINGS "${BIN}/mission_vars.cache" PARENTVARS) -set(VARNAME) -foreach(PV ${PARENTVARS}) - if (VARNAME) - set(${VARNAME} ${PV}) - set(VARNAME) - else() - set(VARNAME ${PV}) - endif() -endforeach(PV ${PARENTVARS}) - -# Set other well-known locations -set(OSAL_MISSION_DIR ${MISSION_SOURCE_DIR}/osal) - -# Start the template for configure_file() -- -# see below why it is done this way and not written directly -file(WRITE ${BIN}/cfecfs_version_info.h.in - "/* Auto-generated version information file */\n" - "#define MISSION_CONFIG \"\@MISSIONCONFIG\@\"\n" - "#define MISSION_NAME \"\@MISSION_NAME\@\"\n") - -# Get version for all mission apps/dependencies (they may be different) -foreach(DEP "MISSION" ${MISSION_DEPS}) - get_version(${DEP}) - string(TOUPPER ${${DEP}_NAME} MACRONAME) - string(REGEX REPLACE "[^A-Z0-9_]+" "_" MACRONAME "${MACRONAME}") - file(APPEND ${BIN}/cfecfs_version_info.h.in "#define ${MACRONAME}_VERSION \"\@${DEP}_VERSION\@\"\n") -endforeach() - -string(TOUPPER ${MISSION_NAME} MACRONAME) -file(APPEND ${BIN}/cfecfs_version_info.h.in "\n#define MISSION_VERSION ${MACRONAME}_VERSION\n\n /* end */\n") - -# Same for build information - -# note this is done separately because the build time might change often - -# only the final target EXE should include build.h (nothing else in the mission) to minimize rebuilds -file(WRITE ${BIN}/cfecfs_build_info.h.in - "/* Auto-generated build information file */\n" - "#define MISSION_BUILDDATE \"\@BUILDDATE\@\"\n" - "#define MISSION_BUILDUSER \"\@USERNAME\@\"\n" - "#define MISSION_BUILDHOST \"\@HOSTNAME\@\"\n\n") - -# OVERRIDE NOTE: -# All 3 of these may be passed via environment variables to force a particular -# date, user, or hostname i.e. if hoping to reproduce an exact binary of a prior build -# They are actually free-form strings so they can be anything up to 64 chars. - -# Get the current date and time -set(BUILDDATE $ENV{BUILDDATE}) -if (NOT BUILDDATE) - execute_process( - COMMAND date "+%Y%m%d%H%M" - OUTPUT_VARIABLE BUILDDATE - OUTPUT_STRIP_TRAILING_WHITESPACE - ) -endif(NOT BUILDDATE) - -# Get the build host -set(HOSTNAME $ENV{HOSTNAME}) -if (NOT HOSTNAME) - execute_process( - COMMAND hostname - OUTPUT_VARIABLE HOSTNAME - OUTPUT_STRIP_TRAILING_WHITESPACE - ) -endif (NOT HOSTNAME) - -# Get the user ID -set(USERNAME $ENV{USER}) -if (NOT USERNAME) - execute_process( - COMMAND whoami - OUTPUT_VARIABLE USERNAME - OUTPUT_STRIP_TRAILING_WHITESPACE - ) -endif (NOT USERNAME) - -# Use configure_file() command to generate the final output file because this can detect -# and only update it if it changes. -configure_file(${BIN}/cfecfs_version_info.h.in ${BIN}/inc/cfecfs_version_info.h @ONLY) -configure_file(${BIN}/cfecfs_build_info.h.in ${BIN}/inc/cfecfs_build_info.h @ONLY) - - diff --git a/fsw/cfe-core/src/es/cfe_es_task.c b/fsw/cfe-core/src/es/cfe_es_task.c index 75bae1b7e..b2e84665e 100644 --- a/fsw/cfe-core/src/es/cfe_es_task.c +++ b/fsw/cfe-core/src/es/cfe_es_task.c @@ -184,6 +184,155 @@ void CFE_ES_TaskMain(void) } /* End of CFE_ES_TaskMain() */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/* */ +/* CFE_ES_FindConfigKeyValue() -- Find value for given config key */ +/* */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +const char *CFE_ES_FindConfigKeyValue(const CFE_ConfigKeyValue_t *ConfigList, const char *KeyName) +{ + const char *ValuePtr; + + ValuePtr = NULL; + if (KeyName != NULL && ConfigList != NULL) + { + while (ConfigList->Key != NULL) + { + if (strcmp(KeyName, ConfigList->Key) == 0) + { + ValuePtr = ConfigList->Value; + break; + } + + ++ConfigList; + } + } + + return ValuePtr; +} + +int32 CFE_ES_GenerateSingleVersionEvent(const char *ModuleType, const char *ModuleName) +{ + int32 Status; + const char *VersionString; + + /* The mission version which should appear in the version list under the mission name */ + VersionString = CFE_ES_FindConfigKeyValue(GLOBAL_CONFIGDATA.ModuleVersionList, ModuleName); + + /* If NULL that means the source code was either uncontrolled or there was no way to determine its version */ + if (VersionString == NULL) + { + VersionString = "[unknown]"; + } + + /* + * Advertise the mission version information + */ + Status = CFE_EVS_SendEvent(CFE_ES_VERSION_INF_EID, CFE_EVS_EventType_INFORMATION, + "Version Info: %s %s, version %s", + ModuleType, ModuleName, VersionString); + + return Status; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/* */ +/* CFE_ES_GenerateVersionEvents() -- Send CFE_ES_VERSION_INF_EID's */ +/* */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +void CFE_ES_GenerateVersionEvents(void) +{ + int32 Status; + CFE_ConfigName_t *ModuleNamePtr; + CFE_StaticModuleLoadEntry_t *StaticModulePtr; + + /* + * Advertise the mission version information + */ + Status = CFE_ES_GenerateSingleVersionEvent("Mission", GLOBAL_CONFIGDATA.MissionName); + if ( Status != CFE_SUCCESS ) + { + CFE_ES_WriteToSysLog("ES:Error sending mission version event:RC=0x%08X\n", (unsigned int)Status); + } + + /* + * Also Advertise the version information for all statically-linked core modules. + * Send a separate CFE_ES_VERSION_INF_EID for every component. + */ + ModuleNamePtr = GLOBAL_CONFIGDATA.CoreModuleList; + if (ModuleNamePtr != NULL) + { + while (Status == CFE_SUCCESS && ModuleNamePtr->Name != NULL) + { + Status = CFE_ES_GenerateSingleVersionEvent("Core Module", ModuleNamePtr->Name); + if ( Status != CFE_SUCCESS ) + { + CFE_ES_WriteToSysLog("ES:Error sending core module version event:RC=0x%08X\n", (unsigned int)Status); + } + ++ModuleNamePtr; + } + } + + /* + * Advertise PSP module versions + */ + StaticModulePtr = GLOBAL_CONFIGDATA.PspModuleList; + if (StaticModulePtr != NULL) + { + while (Status == CFE_SUCCESS && StaticModulePtr->Name != NULL) + { + Status = CFE_ES_GenerateSingleVersionEvent("PSP Module", StaticModulePtr->Name); + if ( Status != CFE_SUCCESS ) + { + CFE_ES_WriteToSysLog("ES:Error sending PSP module version event:RC=0x%08X\n", (unsigned int)Status); + } + ++StaticModulePtr; + } + } +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/* */ +/* CFE_ES_GenerateBuildInfoEvents() -- Send CFE_ES_BUILD_INF_EID */ +/* */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +void CFE_ES_GenerateBuildInfoEvents(void) +{ + int32 Status; + const char *BuildDate; + const char *BuildUser; + const char *BuildHost; + + BuildDate = CFE_ES_FindConfigKeyValue(GLOBAL_CONFIGDATA.BuildEnvironment, "BUILDDATE"); + BuildUser = CFE_ES_FindConfigKeyValue(GLOBAL_CONFIGDATA.BuildEnvironment, "BUILDUSER"); + BuildHost = CFE_ES_FindConfigKeyValue(GLOBAL_CONFIGDATA.BuildEnvironment, "BUILDHOST"); + + /* Ensure all strings are set to something non-NULL */ + if (BuildDate == NULL) + { + BuildDate = "[unknown]"; + } + + if (BuildUser == NULL) + { + BuildUser = "[unknown]"; + } + + if (BuildHost == NULL) + { + BuildHost = "[unknown]"; + } + + Status = CFE_EVS_SendEvent(CFE_ES_BUILD_INF_EID, CFE_EVS_EventType_INFORMATION, + "Build %s by %s@%s, config %s", BuildDate, BuildUser, BuildHost, GLOBAL_CONFIGDATA.Config); + if ( Status != CFE_SUCCESS ) + { + CFE_ES_WriteToSysLog("ES:Error sending build info event:RC=0x%08X\n", (unsigned int)Status); + } +} /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* */ @@ -196,9 +345,6 @@ int32 CFE_ES_TaskInit(void) int32 Status; uint32 SizeofCfeSegment; cpuaddr CfeSegmentAddr; - char EventBuffer[CFE_MISSION_EVS_MAX_MESSAGE_LENGTH]; - char VersionBuffer[CFE_MISSION_EVS_MAX_MESSAGE_LENGTH]; - uint32 Remaining; /* ** Register the Application @@ -329,74 +475,21 @@ int32 CFE_ES_TaskInit(void) return(Status); } -#ifdef CFE_PSP_VERSION - - Status = CFE_EVS_SendEvent(CFE_ES_INITSTATS_INF_EID, CFE_EVS_EventType_INFORMATION, - "%s%s. cFE chksm %d", - CFS_VERSIONS, CFE_PSP_VERSION, (int)CFE_ES_TaskData.HkPacket.Payload.CFECoreChecksum); - -#else /* if CFE_PSP_VERSION not defined use integer version macros*/ - Status = CFE_EVS_SendEvent(CFE_ES_INITSTATS_INF_EID, CFE_EVS_EventType_INFORMATION, - "\n%sv%d.%d.%d.%d\n cFE chksm %d", - CFS_VERSIONS, - CFE_PSP_MAJOR_VERSION, CFE_PSP_MINOR_VERSION, CFE_PSP_REVISION, CFE_PSP_MISSION_REV, - (int)CFE_ES_TaskData.HkPacket.Payload.CFECoreChecksum); - -#endif /* CFE_PSP_VERSION */ + Status = CFE_EVS_SendEvent(CFE_ES_INITSTATS_INF_EID, CFE_EVS_EventType_INFORMATION, + "cFS Versions: cfe %s, osal %s, psp %s. cFE chksm %d", + GLOBAL_CONFIGDATA.CfeVersion, GLOBAL_CONFIGDATA.OsalVersion, CFE_PSP_VERSION, (int)CFE_ES_TaskData.HkPacket.Payload.CFECoreChecksum); if ( Status != CFE_SUCCESS ) { - CFE_ES_WriteToSysLog("ES:Error sending version event:RC=0x%08X\n", (unsigned int)Status); + CFE_ES_WriteToSysLog("ES:Error sending init stats event:RC=0x%08X\n", (unsigned int)Status); return(Status); } /* - ** Advertise the build and version information at start up - ** If unique and non-error, reports component information + * Generate all module version and build info events. */ - if (strstr(GLOBAL_CONFIGDATA.MissionVersion, "error")) - { - snprintf(EventBuffer, sizeof(EventBuffer), "Mission %s", GLOBAL_CONFIGDATA.Config); - } - else - { - snprintf(EventBuffer, sizeof(EventBuffer), "Mission %s.%s", - GLOBAL_CONFIGDATA.MissionVersion, GLOBAL_CONFIGDATA.Config); - } - Remaining = sizeof(EventBuffer)-strlen(EventBuffer)-1; - if(Remaining > 0 && strcmp(GLOBAL_CONFIGDATA.MissionVersion, GLOBAL_CONFIGDATA.CfeVersion)) - { - snprintf(VersionBuffer, sizeof(VersionBuffer), ", CFE git version: %s", - GLOBAL_CONFIGDATA.CfeVersion); - VersionBuffer[Remaining] = 0; - strcat(EventBuffer, VersionBuffer); - Remaining = sizeof(EventBuffer)-strlen(EventBuffer)-1; - } - if(Remaining > 0 && strcmp(GLOBAL_CONFIGDATA.MissionVersion, GLOBAL_CONFIGDATA.OsalVersion)) - { - snprintf(VersionBuffer, sizeof(VersionBuffer), ", OSAL git version: %s", - GLOBAL_CONFIGDATA.OsalVersion); - VersionBuffer[Remaining] = 0; - strcat(EventBuffer, VersionBuffer); - } - - Status = CFE_EVS_SendEvent(CFE_ES_VERSION_INF_EID, - CFE_EVS_EventType_INFORMATION, "%s", EventBuffer); - if ( Status != CFE_SUCCESS ) - { - CFE_ES_WriteToSysLog("ES:Error sending version event:RC=0x%08X\n", (unsigned int)Status); - return(Status); - } - - Status = CFE_EVS_SendEvent(CFE_ES_BUILD_INF_EID, - CFE_EVS_EventType_INFORMATION, - "Build %s %s", - GLOBAL_CONFIGDATA.Date, GLOBAL_CONFIGDATA.User); - if ( Status != CFE_SUCCESS ) - { - CFE_ES_WriteToSysLog("ES:Error sending build info event:RC=0x%08X\n", (unsigned int)Status); - return(Status); - } + CFE_ES_GenerateVersionEvents(); + CFE_ES_GenerateBuildInfoEvents(); /* * Initialize the "background task" which is a low priority child task @@ -757,30 +850,17 @@ int32 CFE_ES_NoopCmd(const CFE_ES_NoopCmd_t *Cmd) ** For unit testing purposes, it helps to put this first - the UT ** is checking for the last event sent to be NOOP_INF_EID. */ - CFE_EVS_SendEvent(CFE_ES_BUILD_INF_EID, - CFE_EVS_EventType_INFORMATION, - "Build %s %s", - GLOBAL_CONFIGDATA.Date, GLOBAL_CONFIGDATA.User); + CFE_ES_GenerateBuildInfoEvents(); /* ** This command will always succeed. */ CFE_ES_TaskData.CommandCounter++; - -#ifdef CFE_PSP_VERSION - CFE_EVS_SendEvent(CFE_ES_NOOP_INF_EID, CFE_EVS_EventType_INFORMATION, - "No-op command:\n %s%s", - CFS_VERSIONS, CFE_PSP_VERSION); - -#else /* CFE_PSP_VERSION */ - CFE_EVS_SendEvent(CFE_ES_NOOP_INF_EID, CFE_EVS_EventType_INFORMATION, - "No-op command:\n %sv%d.%d.%d.%d", - CFS_VERSIONS, - CFE_PSP_MAJOR_VERSION, CFE_PSP_MINOR_VERSION, CFE_PSP_REVISION, CFE_PSP_MISSION_REV); + "No-op command:\n cFS Versions: cfe %s, osal %s, psp %s", + GLOBAL_CONFIGDATA.CfeVersion, GLOBAL_CONFIGDATA.OsalVersion, CFE_PSP_VERSION); -#endif /* CFE_PSP_VERSION */ return CFE_SUCCESS; } /* End of CFE_ES_NoopCmd() */ diff --git a/fsw/cfe-core/src/inc/cfe_es_events.h b/fsw/cfe-core/src/inc/cfe_es_events.h index 29cbe4312..1d2d3d93a 100644 --- a/fsw/cfe-core/src/inc/cfe_es_events.h +++ b/fsw/cfe-core/src/inc/cfe_es_events.h @@ -1409,24 +1409,30 @@ #define CFE_ES_TASKINFO_WR_ERR_EID 90 -/** \brief 'Mission %s.%s, %s, %s' -** \event 'Mission %s.%s, %s, %s' +/** \brief 'Version Info: %s, %s' +** \event 'Version Info: %s, %s' ** ** \par Type: INFORMATION ** ** \par Cause: ** ** This event message is always automatically issued when the Executive Services -** Task completes its Initialization +** Task completes its Initialization and as part of the Noop command ** -** The \c Mission field identifies the tagged build identifiers and configuration name. -** If available, this will also indicate the revision control identifiers for CFE and OSAL -** that this binary was built with. +** A separate version info event will be generated for every module which is statically +** linked into the CFE core executable (e.g. OSAL, PSP, MSG, SBR, etc). +** +** The version information reported in this event is derived from the source revision +** control system at build time, as opposed to manually-assigned semantic version numbers. +** It is intendended to uniquely identify the actual source code that is currently running, +** to the extent this is possible. +** +** The \c Mission version information also identifies the build configuration name, if available. **/ #define CFE_ES_VERSION_INF_EID 91 -/** \brief 'Build %s %s' -** \event 'Build %s %s' +/** \brief 'Build %s by %s@%s, config %s' +** \event 'Build %s by %s@%s, config %s' ** ** \par Type: INFORMATION ** @@ -1439,6 +1445,9 @@ ** the build host machine for the current running binary. The first string is the ** build date/time, and the second string is formatted as "user@hostname" ** +** This additionally reports the configuration name that was selected by the user, +** which may affect various platform/mission limits. +** ** By default, if not specified/overridden, the default values of these variables will be: ** BUILDDATE ==> the output of "date +%Y%m%d%H%M" ** HOSTNAME ==> the output of "hostname"