Skip to content

Commit

Permalink
Fix #2289, implement common search routine for config files
Browse files Browse the repository at this point in the history
  • Loading branch information
dzbaker committed Apr 13, 2023
2 parents eef72cc + 810d203 commit ddddd17
Showing 1 changed file with 101 additions and 39 deletions.
140 changes: 101 additions & 39 deletions cmake/global_functions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,91 @@
# cFS Mission global CMake function definitions
#
# This is included by the top-level script and can define
# common routines and variables that may be referenced in both
# common routines and variables that may be referenced in both
# the mission (non-arch) and arch-specific builds
#
##################################################################

include(CMakeParseArguments)

##################################################################
#
# FUNCTION: cfe_locate_implementation_file
#
# The CFE/CFS build permits users to modify or tune system behavior by
# providing customized versions of configuration files and tables.
#
# This function locates the preferred version of a file to use, by following
# a priority-based search scheme. Users can put their preferred version of
# a file in their MISSION_DEFS directory, based on a file naming convention.
#
# If no version of the file is found there, a default/fallback version can
# be specified as well, which can be part of the module source.
#
function(cfe_locate_implementation_file OUTPUT_VAR FILE_NAME)

cmake_parse_arguments(LOCATEIMPL_ARG "OPTIONAL;ALLOW_LIST" "FALLBACK_FILE" "PREFIX;SUBDIR" ${ARGN})

# Always check for filename matches directly in the MISSION_DEFS dir
set(IMPL_SEARCH_BASEDIRS "${MISSION_DEFS}/")
# The prefix could also be a subdir, but do not repeat the mission name
foreach (PREFIX ${LOCATEIMPL_ARG_PREFIX})
if (NOT "${MISSIONCONFIG}" STREQUAL "${PREFIX}")
list(APPEND IMPL_SEARCH_BASEDIRS "${MISSION_DEFS}/${PREFIX}/")
endif()
endforeach()
set(ADD_SUBDIRS)
foreach (SUBDIR ${LOCATEIMPL_ARG_SUBDIR})
foreach (BASEDIR ${IMPL_SEARCH_BASEDIRS})
list(APPEND ADD_SUBDIRS "${BASEDIR}${SUBDIR}/")
endforeach()
endforeach()
list(APPEND IMPL_SEARCH_BASEDIRS ${ADD_SUBDIRS})

# Build the list of possible locations for this file in REVERSE priority order
set(IMPL_SEARCH_PATH)
if (LOCATEIMPL_ARG_FALLBACK_FILE)
if (IS_ABSOLUTE "${LOCATEIMPL_ARG_FALLBACK_FILE}")
list(APPEND IMPL_SEARCH_PATH "${LOCATEIMPL_ARG_FALLBACK_FILE}")
else()
list(APPEND IMPL_SEARCH_PATH "${CMAKE_CURRENT_LIST_DIR}/${LOCATEIMPL_ARG_FALLBACK_FILE}")
endif()
endif()

# Check for the existence of the file in each of the dirs
foreach(BASEDIR ${IMPL_SEARCH_BASEDIRS})
list(APPEND IMPL_SEARCH_PATH "${BASEDIR}${FILE_NAME}")

# A target-specific prefixed filename gets priority over a direct filename match
# But do not include this variant if the prefix is already part of the basedir
foreach (PREFIX ${LOCATEIMPL_ARG_PREFIX})
if (NOT "${BASEDIR}" MATCHES "/${PREFIX}/")
list(APPEND IMPL_SEARCH_PATH "${BASEDIR}${PREFIX}_${FILE_NAME}")
endif()
endforeach()
endforeach()

set(SELECTED_FILE)
foreach (CHECK_FILE ${IMPL_SEARCH_PATH})
if (EXISTS "${CHECK_FILE}")
list(APPEND SELECTED_FILE ${CHECK_FILE})
endif()
endforeach()

if (SELECTED_FILE)
message(STATUS "Using file: ${SELECTED_FILE} for ${FILE_NAME}")
elseif(NOT LOCATEIMPL_ARG_OPTIONAL)
message(FATAL_ERROR "No implementation for ${FILE_NAME} found")
endif()

# Export the result to the caller
if (NOT LOCATEIMPL_ARG_ALLOW_LIST AND SELECTED_FILE)
list(GET SELECTED_FILE -1 SELECTED_FILE)
endif()
set(${OUTPUT_VAR} ${SELECTED_FILE} PARENT_SCOPE)

endfunction()

##################################################################
#
# FUNCTION: generate_c_headerfile
Expand Down Expand Up @@ -78,48 +156,32 @@ function(generate_config_includefile)
set(GENCONFIG_ARG_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/inc")
endif (NOT GENCONFIG_ARG_OUTPUT_DIRECTORY)

set(WRAPPER_FILE_CONTENT)
set(ITEM_FOUND FALSE)
if (IS_CFS_ARCH_BUILD)
set(ARCH_PREFIXES ${BUILD_CONFIG})
else()
set(ARCH_PREFIXES)
endif()

# Assemble a list of file names to test for
# Check for existence of a file in defs directory with an exact matching name
# Then Check for existence of file(s) with a matching prefix+suffix
set(CHECK_PATH_LIST "${MISSION_DEFS}/${GENCONFIG_ARG_FILE_NAME}")
if (GENCONFIG_ARG_MATCH_SUFFIX)
foreach(PREFIX ${GENCONFIG_ARG_PREFIXES} ${GENCONFIG_ARG_UNPARSED_ARGUMENTS})
list(APPEND CHECK_PATH_LIST "${MISSION_DEFS}/${PREFIX}_${GENCONFIG_ARG_MATCH_SUFFIX}")
endforeach()
endif(GENCONFIG_ARG_MATCH_SUFFIX)

# Check for existence of files, and add to content if present
# Note that all files are appended/concatenated together.
foreach(SRC_LOCAL_PATH ${CHECK_PATH_LIST})
if (EXISTS "${SRC_LOCAL_PATH}")
file(TO_NATIVE_PATH "${SRC_LOCAL_PATH}" SRC_NATIVE_PATH)
list(APPEND WRAPPER_FILE_CONTENT "#include \"${SRC_NATIVE_PATH}\"\n")
set(ITEM_FOUND TRUE)
else()
list(APPEND WRAPPER_FILE_CONTENT "/* ${SRC_LOCAL_PATH} does not exist */\n")
endif (EXISTS "${SRC_LOCAL_PATH}")
endforeach()

# If _no_ files were found in the above loop,
# then check for and use the fallback file.
# (if specified by the caller it should always exist)
# Also produce a message on the console showing whether mission config or fallback was used
if (ITEM_FOUND)
message(STATUS "Generated ${GENCONFIG_ARG_FILE_NAME} from ${MISSION_DEFS} configuration")
elseif (GENCONFIG_ARG_FALLBACK_FILE)
file(TO_NATIVE_PATH "${GENCONFIG_ARG_FALLBACK_FILE}" SRC_NATIVE_PATH)
list(APPEND WRAPPER_FILE_CONTENT
"\n\n/* No configuration for ${GENCONFIG_ARG_FILE_NAME}, using fallback */\n"
"#include \"${GENCONFIG_ARG_FALLBACK_FILE}\"\n")
message(STATUS "Using ${GENCONFIG_ARG_FALLBACK_FILE} for ${GENCONFIG_ARG_FILE_NAME}")
set(TGTFILE ${GENCONFIG_ARG_MATCH_SUFFIX})
else()
message("ERROR: No implementation for ${GENCONFIG_ARG_FILE_NAME} found")
message(FATAL_ERROR "Tested: ${CHECK_PATH_LIST}")
set(TGTFILE ${GENCONFIG_ARG_FILE_NAME})
endif()

# Use the common search function to find the candidate(s)
cfe_locate_implementation_file(SRC_LOCAL_PATH_LIST "${TGTFILE}"
ALLOW_LIST
FALLBACK_FILE "${GENCONFIG_ARG_FALLBACK_FILE}"
PREFIX ${GENCONFIG_ARG_PREFIXES} ${ARCH_PREFIXES}
SUBDIR config
)

set(WRAPPER_FILE_CONTENT)
foreach(SELECTED_FILE ${SRC_LOCAL_PATH_LIST})
file(TO_NATIVE_PATH "${SELECTED_FILE}" SRC_NATIVE_PATH)
list(APPEND WRAPPER_FILE_CONTENT "#include \"${SRC_NATIVE_PATH}\"\n")
endforeach()

# Generate a header file
generate_c_headerfile("${GENCONFIG_ARG_OUTPUT_DIRECTORY}/${GENCONFIG_ARG_FILE_NAME}" ${WRAPPER_FILE_CONTENT})

Expand All @@ -139,7 +201,7 @@ endfunction(generate_config_includefile)
#
# This function then sets up the following variables in the global scope:
# TGTSYS_LIST: list of CPU architectures used in the build. Note this
# will always contain a "native" target (for tools at least) which
# will always contain a "native" target (for tools at least) which
# is forced to be last.
# MISSION_APPS: list of all applications in this build
# MISSION_PSPMODULES: list of all psp modules in this build
Expand Down

0 comments on commit ddddd17

Please sign in to comment.