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 #724, implement config-based target builds #728

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
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
2 changes: 1 addition & 1 deletion cmake/Makefile.sample
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
# Establish default values for critical variables. Any of these may be overridden
# on the command line or via the make environment configuration in an IDE
O ?= build
ARCH ?= native
ARCH ?= native/default_cpu1
BUILDTYPE ?= debug
INSTALLPREFIX ?= /exe
DESTDIR ?= $(O)
Expand Down
33 changes: 5 additions & 28 deletions cmake/arch_build.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -411,16 +411,6 @@ function(process_arch SYSVAR)
set(TGTLIST_DRV_${DRV})
endforeach()

# INCLUDE_REFACTOR: apps and the PSP like to #include cfe_platform_cfg.h -- they shouldn't
# This will become unnecessary when dependency refactoring is merged in, but for now
# they need to be able to find it. Remove the next line once refactoring is merged.
# Also do not do this if more than one CPU shares this architecture - this hack can only
# be done if a 1:1 mapping between cpus and architectures (so all apps are rebuilt per-cpu)
list(LENGTH TGTSYS_${SYSVAR} ARCHLEN)
if (ARCHLEN EQUAL 1)
include_directories(${CMAKE_BINARY_DIR}/cfe_core_default_${TGT${TGTSYS_${SYSVAR}}_NAME}/inc)
endif (ARCHLEN EQUAL 1)

# Process each PSP module that is referenced on this system architecture (any cpu)
foreach(PSPMOD ${TGTSYS_${SYSVAR}_PSPMODULES})
message(STATUS "Building PSP Module: ${PSPMOD}")
Expand Down Expand Up @@ -464,6 +454,9 @@ function(process_arch SYSVAR)
add_subdirectory(${${APP}_MISSION_DIR} apps/${APP})
endforeach()

# Actual core library is a subdirectory
add_subdirectory(${MISSION_SOURCE_DIR}/cfe/fsw/cfe-core cfe-core)

# If unit test is enabled, build a generic ut stub library for CFE
if (ENABLE_UNIT_TESTS)
add_subdirectory(${cfe-core_MISSION_DIR}/ut-stubs ut_cfe_core_stubs)
Expand All @@ -473,24 +466,8 @@ function(process_arch SYSVAR)
# Second Pass: Build cfe-core and link final target executable
foreach(TGTID ${TGTSYS_${SYSVAR}})

set(TGTNAME ${TGT${TGTID}_NAME})
set(TGTPLATFORM ${TGT${TGTID}_PLATFORM})
if(NOT TGTPLATFORM)
set(TGTPLATFORM "default" ${TGTNAME})
endif(NOT TGTPLATFORM)

string(REPLACE ";" "_" CFE_CORE_TARGET "cfe_core_${TGTPLATFORM}")
if (NOT TARGET ${CFE_CORE_TARGET})

# Generate wrapper file for the requisite cfe_platform_cfg.h file
generate_config_includefile("${CFE_CORE_TARGET}/inc/cfe_msgids.h" msgids.h ${TGTPLATFORM})
generate_config_includefile("${CFE_CORE_TARGET}/inc/cfe_platform_cfg.h" platform_cfg.h ${TGTPLATFORM})

# Actual core library is a subdirectory
add_subdirectory(${MISSION_SOURCE_DIR}/cfe/fsw/cfe-core ${CFE_CORE_TARGET})

endif (NOT TARGET ${CFE_CORE_TARGET})

set(TGTNAME ${TGT${TGTID}_NAME})

# Target to generate the actual executable file
add_subdirectory(cmake/target ${TGTNAME})

Expand Down
5 changes: 5 additions & 0 deletions cmake/cfe_generated_file.h.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@GENERATED_FILE_HEADER@

@GENERATED_FILE_CONTENT@

@GENERATED_FILE_TRAILER@
156 changes: 102 additions & 54 deletions cmake/global_functions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,49 @@
#
##################################################################

include(CMakeParseArguments)

##################################################################
#
# FUNCTION: generate_c_headerfile
#
# Generates a C header file in the build directory.
# First argument is the file name to write. All remaining arguments will be
# concatenated and written to the file.
#
function(generate_c_headerfile FILE_NAME)

# Determine the absolute location for this wrapper file
# If it is relative path then assume it is relative to ${CMAKE_BINARY_DIR}
# This should not write generated files to ${CMAKE_SOURCE_DIR}
if (NOT IS_ABSOLUTE "${FILE_NAME}")
set(FILE_NAME "${CMAKE_BINARY_DIR}/${FILE_NAME}")
endif (NOT IS_ABSOLUTE "${FILE_NAME}")

# Generate an include guard
get_filename_component(FILE_GUARD "${FILE_NAME}" NAME)
string(REGEX REPLACE "[^A-Za-z0-9]" "_" FILE_GUARD "${FILE_GUARD}")
string(TOUPPER "GENERATED_INCLUDE_${FILE_GUARD}" FILE_GUARD)
set(GENERATED_FILE_HEADER
"/* Generated header file. Do not edit */\n\n"
"#ifndef ${FILE_GUARD}\n"
"#define ${FILE_GUARD}\n\n"
)
set(GENERATED_FILE_TRAILER
"#endif /* ${FILE_GUARD} */\n"
)

# Use configure_file() to write the file, as this automatically
# has the logic to not update the timestamp on the file unless it changes.
string(REPLACE ";" "" GENERATED_FILE_CONTENT "${ARGN}")
string(REPLACE ";" "" GENERATED_FILE_HEADER "${GENERATED_FILE_HEADER}")
string(REPLACE ";" "" GENERATED_FILE_TRAILER "${GENERATED_FILE_TRAILER}")
configure_file(
"${CFE_SOURCE_DIR}/cmake/cfe_generated_file.h.in"
"${FILE_NAME}"
@ONLY)

endfunction(generate_c_headerfile)

##################################################################
#
Expand All @@ -21,58 +64,56 @@
# This also supports "stacking" multiple component files together by specifying more than one
# source file for the wrapper.
#
# In all cases, care must be used when updating such files -- if the timestamp is updated then
# everything that uses it will be rebuilt even if the content did not change. So the file content
# is checked against any pre-existing files, and if the content is the same then the update is
# skipped, preserving the original timestamp.
# This function now accepts named parameters:
# OUTPUT_DIRECTORY - where the generated file will be written
# FILE_NAME - the name of the file to write
# FALLBACK_FILE - if no files are found in "defs" using the name match, this file will be used instead.
# MATCH_SUFFIX - the suffix to match in the "defs" directory (optional)
# PREFIXES - a list of prefixes to match in the "defs" directory (optional)
#
function(generate_config_includefile DESTFILE SUFFIX)
function(generate_config_includefile)

# Determine the absolute location for this wrapper file
if (NOT IS_ABSOLUTE ${DESTFILE})
set(DESTFILE ${CMAKE_BINARY_DIR}/${DESTFILE})
endif (NOT IS_ABSOLUTE ${DESTFILE})

set(INCL_LIST)
set(DEST_CONTENTSTR "/* This is a wrapper file generated by the build system - DO NOT EDIT */\n")
foreach(SRC ${ARGN})
set(SRC_LOCAL_PATH "${MISSION_DEFS}/${SRC}_${SUFFIX}")
# only add this if not already included (prevent double inclusion) */
list(FIND INCL_LIST "${SRC_LOCAL_PATH}" INCL_INDX)
if (INCL_INDX LESS 0)
list(APPEND INCL_LIST "${SRC_LOCAL_PATH}")
if (EXISTS "${SRC_LOCAL_PATH}")
file(TO_NATIVE_PATH "${SRC_LOCAL_PATH}" SRC_NATIVE)
set(DEST_CONTENTSTR "${DEST_CONTENTSTR}#include \"${SRC_NATIVE}\"\n")
else()
set(DEST_CONTENTSTR "${DEST_CONTENTSTR}/* ${SRC_LOCAL_PATH} does not exist */\n")
endif (EXISTS "${SRC_LOCAL_PATH}")
endif (INCL_INDX LESS 0)
endforeach(SRC ${SRCFILES})
if (EXISTS "${DESTFILE}")
file(READ "${DESTFILE}" DEST_EXISTING)
else (EXISTS "${DESTFILE}")
set(DEST_EXISTING)
endif (EXISTS "${DESTFILE}")
if (NOT DEST_CONTENTSTR STREQUAL DEST_EXISTING)
file(WRITE "${DESTFILE}" "${DEST_CONTENTSTR}")
endif (NOT DEST_CONTENTSTR STREQUAL DEST_EXISTING)

# Create a copy of the generated file in a location where it can
# be found by an editor such as Eclipse. The user will still have to
# add the path to the IDEs include search path, but this makes it easier
# by at least putting them all in one spot. This is not used for the build.
get_filename_component(DESTBASENAME "${DESTFILE}" NAME)
if (MISSION_BINARY_DIR)
set(EDITOR_COPY_DIR ${MISSION_BINARY_DIR}/editor_inc)
else()
set(EDITOR_COPY_DIR ${CMAKE_BINARY_DIR}/editor_inc)
endif()

file(MAKE_DIRECTORY ${EDITOR_COPY_DIR})
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different ${DESTFILE} ${EDITOR_COPY_DIR}/${DESTBASENAME})
cmake_parse_arguments(GENCONFIG_ARG "" "OUTPUT_DIRECTORY;FILE_NAME;FALLBACK_FILE;MATCH_SUFFIX" "PREFIXES" ${ARGN} )

set(WRAPPER_FILE_CONTENT)
set(ITEM_FOUND FALSE)

# 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)
if (NOT ITEM_FOUND AND 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")
endif()

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

endfunction(generate_config_includefile DESTFILE SUFFIX)
endfunction(generate_config_includefile)


##################################################################
Expand Down Expand Up @@ -106,21 +147,28 @@ function(read_targetconfig)
endif()
if (NOT DEFINED TGT${TGTID}_SYSTEM)
set(TGT${TGTID}_SYSTEM "cpu${TGTID}")
set(TGT${TGTID}_SYSTEM "${TGT${TGTID}_SYSTEM}" PARENT_SCOPE)
endif()
if (NOT DEFINED TGT${TGTID}_PLATFORM)
set(TGT${TGTID}_PLATFORM "default" "${TGT${TGTID}_NAME}")
set(TGT${TGTID}_PLATFORM "${TGT${TGTID}_PLATFORM}" PARENT_SCOPE)
endif()

if (SIMULATION)
# if simulation use simulation system architecture for all targets
set(CURRSYS "${SIMULATION}")
set(TOOLCHAIN_NAME "${SIMULATION}")
else (SIMULATION)
# get the target system arch identifier string
set(CURRSYS "${TGT${TGTID}_SYSTEM}")
set(TOOLCHAIN_NAME "${TGT${TGTID}_SYSTEM}")
endif (SIMULATION)

# make sure the string is safe for a variable name
string(REGEX REPLACE "[^A-Za-z0-9]" "_" SYSVAR "${CURRSYS}")
set(BUILD_CONFIG ${TOOLCHAIN_NAME} ${TGT${TGTID}_PLATFORM})

# convert to a the string which is safe for a variable name
string(REGEX REPLACE "[^A-Za-z0-9]" "_" SYSVAR "${BUILD_CONFIG}")

# save the unmodified name for future reference
set(SYSID_${SYSVAR} "${CURRSYS}" PARENT_SCOPE)
set(BUILD_CONFIG_${SYSVAR} "${BUILD_CONFIG}" PARENT_SCOPE)

# Append to global lists
list(APPEND TGTSYS_LIST "${SYSVAR}")
Expand Down
Loading