Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #2289, implement common search routine for config files #2290

Merged
merged 1 commit into from
Apr 13, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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