Skip to content

Commit

Permalink
Fix #1170, refactor target config objects
Browse files Browse the repository at this point in the history
Rework the dynamic content so it is generated entirely via a
CMake "configure_file()" command into a C source file (.c) that
can be built as normal.

This removes the need for inline `#include` statements to pull
in data fragments to fill in the data.
  • Loading branch information
jphickey committed Mar 3, 2021
1 parent 672b2dc commit 228b914
Show file tree
Hide file tree
Showing 9 changed files with 624 additions and 326 deletions.
48 changes: 48 additions & 0 deletions cmake/generate_build_env.cmake
Original file line number Diff line number Diff line change
@@ -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)
75 changes: 75 additions & 0 deletions cmake/generate_git_module_version.cmake
Original file line number Diff line number Diff line change
@@ -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)
102 changes: 91 additions & 11 deletions cmake/mission_build.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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)


##################################################################
#
Expand Down Expand Up @@ -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)
Expand Down
115 changes: 96 additions & 19 deletions cmake/target/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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}"
Expand All @@ -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"
)

Expand Down
Loading

0 comments on commit 228b914

Please sign in to comment.