##################################################################
#
# Core Flight System architecture-specific build recipes
#
# This file is invoked by the top-level mission recipe for
# to build cFE/cFS for each target processor
#
# Note that the target CPUs may use different architectures, therefore each
# architecture must be done as a separate sub-build since none of the binaries 
# can be shared.
#
##################################################################


##################################################################
#
# FUNCTION: initialize_globals
#
# Set up global mission configuration variables.
# This function determines the mission configuration directory and 
# also reads any startup state info from file(s) on the disk
# 
# In the CPU (cross) build this only reads a cache file that was
# generated by the mission (top-level) build.  Therefore all 
# architecture-specific cross builds will get the same settings.
#
function(initialize_globals)

  # Sanity check -- the parent build script should have set MISSION_BINARY_DIR
  if (NOT IS_DIRECTORY "${MISSION_BINARY_DIR}")
      message(FATAL_ERROR "BUG -- MISSION_BINARY_DIR not a valid directory in arch_build.cmake")
  endif()

  # Read the variable values from the cache file.
  set(MISSION_IMPORTED_VARS)
  file(READ "${MISSION_BINARY_DIR}/mission_vars.cache" PARENTVARS)
  string(REGEX REPLACE ";" "\\\\;" PARENTVARS "${PARENTVARS}")
  string(REGEX REPLACE "\n" ";" PARENTVARS "${PARENTVARS}")
  foreach(PV ${PARENTVARS})
    if (VARNAME)
      set(${VARNAME} ${PV} PARENT_SCOPE)
      list(APPEND MISSION_IMPORTED_VARS ${VARNAME})
      unset(VARNAME)
    else()
      set(VARNAME ${PV})
    endif()
  endforeach(PV ${PARENTVARS})
  unset(VARNAME)
  unset(PARENTVARS)
  set(MISSION_IMPORTED_VARS ${MISSION_IMPORTED_VARS} PARENT_SCOPE)
    
endfunction(initialize_globals)


##################################################################
#
# FUNCTION: add_psp_module
#
# Simplified routine to add a driver to the PSP in use on this arch
# Called by module listfiles
#
function(add_psp_module MOD_NAME MOD_SRC_FILES)

  # Include the PSP shared directory so it can get to cfe_psp_module.h
  include_directories(${MISSION_SOURCE_DIR}/psp/fsw/shared)
  add_definitions(-D_CFE_PSP_MODULE_)
  
  # Create the module
  add_library(${MOD_NAME} STATIC ${MOD_SRC_FILES} ${ARGN})

endfunction(add_psp_module)

##################################################################
#
# FUNCTION: add_cfe_app
#
# Simplified routine to add a CFS app or lib this arch
# Called by module listfiles
#
function(add_cfe_app APP_NAME APP_SRC_FILES)

  # currently this will build an app with either static linkage or shared/module linkage,
  # but this does not currently support both for a single arch (could be revised if that is needed)
  if (APP_INSTALL_LIST)
     set(APPTYPE "MODULE")
  else()
     set(APPTYPE "STATIC")
  endif()
    
  # Create the app module
  add_library(${APP_NAME} ${APPTYPE} ${APP_SRC_FILES} ${ARGN})
  
  # If using "DYNAMIC" EDS linkage, then link the app with the EDS library here.
  # Note that the linker will only pull in the compilation unit that actually
  # resolves an undefined symbol, which in this case would be the app-specific
  # DATATYPE_DB object if one is referenced at all. 
  #
  # By linking with the respective application like this, the net result is that
  # only the _referenced_ EDS DBs (i.e. those for loaded apps) are held in memory.
  if (CFE_SYSTEM_EDSDB_DYNAMIC_LINK)
    target_link_libraries(${APP_NAME} cfe_edsdb_static)
  endif (CFE_SYSTEM_EDSDB_DYNAMIC_LINK)
    
  if (APP_INSTALL_LIST)
    cfs_app_do_install(${APP_NAME} ${APP_INSTALL_LIST})
  endif (APP_INSTALL_LIST)
  
endfunction(add_cfe_app)

##################################################################
#
# FUNCTION: add_cfe_tables
#
# Simplified routine to add CFS tables to be built with an app
#
function(add_cfe_tables APP_NAME TBL_SRC_FILES)

  # The table source must be compiled using the same "include_directories"
  # as any other target, but it uses the "add_custom_command" so there is
  # no automatic way to do this (at least in the older cmakes)
  set(TBL_CFLAG_PREFIXES "-I" "-D")
  set(TBL_CFLAGS)
  get_current_cflags(TBL_CFLAGS_FULL ${CMAKE_C_FLAGS})
  foreach(TBL_CFLAG ${TBL_CFLAGS_FULL})
    foreach(TBL_CFLAG_PREFIX ${TBL_CFLAG_PREFIXES})
        if(${TBL_CFLAG} MATCHES "^${TBL_CFLAG_PREFIX}([^ ]*)$")
          list(APPEND TBL_CFLAGS ${TBL_CFLAG})
        endif()
    endforeach(TBL_CFLAG_PREFIX ${TBL_CFLAG_PREFIXES})
  endforeach(TBL_CFLAG ${TBL_CFLAGS})

  # Create the intermediate table objects using the target compiler,
  # then use "elf2cfetbl" to convert to a .tbl file
  set(TBL_LIST)
  foreach(TBL ${TBL_SRC_FILES} ${ARGN})
  
    # Get name without extension (NAME_WE) and append to list of tables
    get_filename_component(TBLWE ${TBL} NAME_WE)

    set(TBL_SRC)
    set(TBL_LUA)
    set(TBL_SO_FILE)
    
    foreach(TGT ${APP_INSTALL_LIST})
      set(TABLE_DESTDIR "${CMAKE_CURRENT_BINARY_DIR}/tables_${TGT}")
      file(MAKE_DIRECTORY ${TABLE_DESTDIR})
      list(APPEND TBL_LIST "${TABLE_DESTDIR}/${TBLWE}.tbl")
      
      # Check if an override exists at the mission level (recommended practice)
      # This allows a mission to implement a customized table without modifying
      # the original - this also makes for easier merging/updating if needed.
      if (EXISTS "${MISSION_DEFS}/tables/${TGT}_${TBLWE}.c")
        set(TBL_SRC "${MISSION_DEFS}/tables/${TGT}_${TBLWE}.c")
      elseif (EXISTS "${MISSION_SOURCE_DIR}/tables/${TGT}_${TBLWE}.c")
        set(TBL_SRC "${MISSION_SOURCE_DIR}/tables/${TGT}_${TBLWE}.c")
      elseif (EXISTS "${MISSION_DEFS}/tables/${TBLWE}.c")
        set(TBL_SRC "${MISSION_DEFS}/tables/${TBLWE}.c")
      elseif (EXISTS "${MISSION_SOURCE_DIR}/tables/${TBLWE}.c")
        set(TBL_SRC "${MISSION_SOURCE_DIR}/tables/${TBLWE}.c")
       elseif (EXISTS "${MISSION_DEFS}/${TGT}/tables/${TBLWE}.c")
        set(TBL_SRC "${MISSION_DEFS}/${TGT}/tables/${TBLWE}.c")
      elseif (IS_ABSOLUTE "${TBL}")
        set(TBL_SRC "${TBL}")
      elseif (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${TBL}")
       set(TBL_SRC "${CMAKE_CURRENT_SOURCE_DIR}/${TBL}")
      endif()

      # Check if an lua script exists at the mission level (recommended practice)
      # This allows a mission to implement a customized table without modifying
      # the original - this also makes for easier merging/updating if needed.
      if (EXISTS "${MISSION_DEFS}/tables/${TGT}_${TBLWE}.lua")
        list(APPEND TBL_LUA "${MISSION_DEFS}/tables/${TGT}_${TBLWE}.lua")
      endif()
      if (EXISTS "${MISSION_SOURCE_DIR}/tables/{TGT}_${TBLWE}.lua")
        list(APPEND TBL_LUA "${MISSION_SOURCE_DIR}/tables/${TGT}_${TBLWE}.lua")
      endif()
      if (EXISTS "${MISSION_DEFS}/tables/${TBLWE}.lua")
        list(APPEND TBL_LUA "${MISSION_DEFS}/tables/${TBLWE}.lua")
      endif()
      if (EXISTS "${MISSION_SOURCE_DIR}/tables/${TBLWE}.lua")
        list(APPEND TBL_LUA "${MISSION_SOURCE_DIR}/tables/${TBLWE}.lua")
      endif()
    
      if (TBL_SRC)
      	  message(STATUS "Using ${TBL_SRC} as legacy table definition for ${TBLWE}")
          add_custom_command(
           OUTPUT "${TABLE_DESTDIR}/${TBLWE}.so"
             COMMAND ${CMAKE_NATIVE_C_COMPILER} ${TBL_CFLAGS} -shared -o ${TBLWE}.so ${TBL_SRC}
            DEPENDS ${TBL_SRC}
            WORKING_DIRECTORY ${TABLE_DESTDIR}
          )
          set(TBL_SO_FILE "${TABLE_DESTDIR}/${TBLWE}.so")
      elseif(TBL_LUA)
      	  message(STATUS "Using EDS table definition for ${TBLWE}")
      else()
          # If neither a legacy C source nor a LUA source is found, then
          # this is a mission configuration error. 
      	  message(FATAL_ERROR "No table definition for ${TBLWE} found")
      endif (TBL_SRC)
    
      add_custom_command(
        OUTPUT "${TABLE_DESTDIR}/${TBLWE}.tbl"
        COMMAND eds2cfetbl 
            -e MISSION_DEFS=\"${MISSION_DEFS}\" 
            -e CPUNAME=\"${TGT}\" 
            -e APPNAME=\"${APP}\"
            -e TABLENAME=\"${TBLWE}\"
            ${TBL_SO_FILE} ${TBL_LUA}
        DEPENDS eds2cfetbl ${TBL_SO_FILE} ${TBL_LUA}
        WORKING_DIRECTORY ${TABLE_DESTDIR}
        VERBATIM
      )
      # Create the install targets for all the tables
      install(FILES ${TABLE_DESTDIR}/${TBLWE}.tbl DESTINATION ${TGT}/${INSTALL_SUBDIR})
    endforeach(TGT ${APP_INSTALL_LIST})
    
  endforeach(TBL ${TBL_SRC_FILES} ${ARGN})

  # Make a custom target that depends on all the tables  
  add_custom_target(${APP_NAME}_tables ALL DEPENDS ${TBL_LIST})
  
endfunction(add_cfe_tables)

##################################################################
#
# FUNCTION: add_unit_test_lib
#
# Add a library for unit testing.  This is basically the same as the 
# normal CMake "add_library" but enables the code coverage compiler options.
#
function(add_unit_test_lib UT_NAME UT_SRCS)
    add_library(utl_${UT_NAME} STATIC  ${UT_SRCS} ${ARGN})
    set_target_properties(utl_${UT_NAME} PROPERTIES COMPILE_FLAGS "${CMAKE_C_FLAGS} -pg --coverage")
endfunction(add_unit_test_lib)

##################################################################
#
# FUNCTION: add_unit_test_exe
#
# Create unit test executable.  This links the UT main executive with
# a library that is placed under test (created via add_unit_test_lib)
# It also registers the final executable target with ctest so it will
# be run during the "make test" target or when ctest is run.
#
function(add_unit_test_exe UT_NAME UT_SRCS)
    add_executable(${UT_NAME} ${utexec_MISSION_DIR}/src/utexec.c ${UT_SRCS} ${ARGN})
    
    get_target_property(UTCDEFS ${UT_NAME} COMPILE_DEFINITIONS)
    list(APPEND UTCDEFS "DEFAULT_REF_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}\"")
    
    get_target_property(UTCFLAGS ${UT_NAME} COMPILE_FLAGS)
    if (UTCFLAGS STREQUAL "UTCFLAGS-NOTFOUND")
        set(UTCFLAGS)
    endif()
    set(UTCFLAGS "${UTCFLAGS} -I${utexec_MISSION_DIR}/inc -I${CMAKE_CURRENT_SOURCE_DIR}")
    
    get_target_property(UTLFLAGS ${UT_NAME} LINK_FLAGS)
    if (UTLFLAGS STREQUAL "UTLFLAGS-NOTFOUND")
        set(UTLFLAGS)
    endif()
    set(UTLFLAGS "${UTLFLAGS} -pg --coverage")
    
    set_target_properties(${UT_NAME} PROPERTIES LINK_FLAGS "${UTLFLAGS}" COMPILE_DEFINITIONS "${UTCDEFS}" COMPILE_FLAGS "${UTCFLAGS}")
    target_link_libraries(${UT_NAME} utl_${UT_NAME}) 
    add_test(${UT_NAME} ${UT_NAME})
endfunction(add_unit_test_exe)


##################################################################
#
# FUNCTION: cfe_exec_do_install
#
# Called to install a CFE core executable target to the staging area.
# Some architectures/OS's need special extra steps, and this
# function can be overridden in a custom cmake file for those platforms
#
function(cfe_exec_do_install CPU_NAME)

    # By default just stage it to a directory of the same name
    install(TARGETS core-${CPU_NAME} DESTINATION ${CPU_NAME})
    
endfunction(cfe_exec_do_install)

##################################################################
#
# FUNCTION: cfs_app_do_install
#
# Called to install a CFS application target to the staging area.
# Some architectures/OS's need special extra steps, and this
# function can be overridden in a custom cmake file for those platforms
#
function(cfs_app_do_install APP_NAME)

    # override the default behavior of attaching a "lib" prefix
    set_target_properties(${APP_NAME} PROPERTIES 
        PREFIX "" OUTPUT_NAME "${APP_NAME}")
    
    # Create the install targets for this shared/modular app
    foreach(TGT ${ARGN})
      install(TARGETS ${APP_NAME} DESTINATION ${TGT}/${INSTALL_SUBDIR})
    endforeach()

endfunction(cfs_app_do_install)


##################################################################
#
# FUNCTION: prepare
#
# Called by the top-level CMakeLists.txt to set up prerequisites
#
function(prepare)

  # Create a directory to hold the generated binary objects
  file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/obj")

  # Choose the configuration file to use for OSAL on this system
  set(OSAL_CONFIGURATION_FILE)
  foreach(CONFIG ${BUILD_CONFIG_${TARGETSYSTEM}} ${OSAL_SYSTEM_OSCONFIG})
    if (EXISTS "${MISSION_DEFS}/${CONFIG}_osconfig.cmake")
      list(APPEND OSAL_CONFIGURATION_FILE "${MISSION_DEFS}/${CONFIG}_osconfig.cmake")
    endif()
  endforeach()
  list(REVERSE OSAL_CONFIGURATION_FILE)
  set(OSAL_CONFIGURATION_FILE ${OSAL_CONFIGURATION_FILE} PARENT_SCOPE)

  # Allow sources to "ifdef" certain things if running on simulated hardware
  # This should be used sparingly, typically to fake access to hardware that is not present
  if (SIMULATION)
    add_definitions(-DSIMULATION=${SIMULATION})
  endif (SIMULATION)
  
  # Check that PSPNAME is set properly for this arch
  if (NOT CFE_SYSTEM_PSPNAME)
    if (CMAKE_CROSSCOMPILING)
      message(FATAL_ERROR "Cross-compile toolchain ${CMAKE_TOOLCHAIN_FILE} must define CFE_SYSTEM_PSPNAME")
    elseif ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" OR 
            "${CMAKE_SYSTEM_NAME}" STREQUAL "CYGWIN")
      # Export the variables determined here up to the parent scope
      SET(CFE_SYSTEM_PSPNAME      "pc-linux" PARENT_SCOPE)
    else ()
      # Not cross compiling and host system is not recognized
      message(FATAL_ERROR "Do not know how to set CFE_SYSTEM_PSPNAME on ${CMAKE_SYSTEM_NAME} system")
    endif()
  endif (NOT CFE_SYSTEM_PSPNAME)
  
  # Truncate the global TGTSYS_LIST to be only the target architecture
  set(TGTSYS_LIST ${TARGETSYSTEM} PARENT_SCOPE)

  # set the BUILD_CONFIG variable from the cached data
  set(BUILD_CONFIG ${BUILD_CONFIG_${TARGETSYSTEM}})
  list(REMOVE_AT BUILD_CONFIG 0)
  set(BUILD_CONFIG ${BUILD_CONFIG} PARENT_SCOPE)
  
  # Pull in any application-specific platform-scope configuration
  # This may include user configuration files such as cfe_platform_cfg.h,
  # or any other configuration/preparation that needs to happen at 
  # platform/arch scope.
  foreach(DEP_NAME ${MISSION_DEPS})
    include("${${DEP_NAME}_MISSION_DIR}/arch_build.cmake" OPTIONAL)
  endforeach(DEP_NAME ${MISSION_DEPS})
 
endfunction(prepare)


##################################################################
#
# FUNCTION: process_arch
#
# Called by the top-level CMakeLists.txt to set up targets for this arch
# This is where the real work is done
#
function(process_arch SYSVAR)

  # Check if something actually uses this arch; 
  # if this list is empty then do nothing, skip building osal/psp
  if (NOT DEFINED TGTSYS_${SYSVAR})
    return()
  endif()
  
  # Generate a list of targets that share this system architecture
  set(INSTALL_TARGET_LIST)
  foreach(TGTID ${TGTSYS_${SYSVAR}})
    set(TGTNAME ${TGT${TGTID}_NAME})
    if(NOT TGTNAME)
      set(TGTNAME "cpu${TGTID}")
    endif(NOT TGTNAME)
    list(APPEND INSTALL_TARGET_LIST ${TGTNAME})
  endforeach()
  
  # Assume use of an OSAL BSP of the same name as the CFE PSP
  # This can be overridden by the PSP-specific build_options but normally this is expected.
  set(CFE_PSP_EXPECTED_OSAL_BSPTYPE ${CFE_SYSTEM_PSPNAME})
       
  # Include any specific compiler flags or config from the selected PSP
  include(${MISSION_SOURCE_DIR}/psp/fsw/${CFE_SYSTEM_PSPNAME}/make/build_options.cmake)
  
  if (NOT DEFINED OSAL_SYSTEM_BSPTYPE)
      # Implicitly use the OSAL BSP that corresponds with the CFE PSP
      set(OSAL_SYSTEM_BSPTYPE ${CFE_PSP_EXPECTED_OSAL_BSPTYPE})
  elseif (NOT OSAL_SYSTEM_BSPTYPE STREQUAL CFE_PSP_EXPECTED_OSAL_BSPTYPE)
      # Generate a warning about the BSPTYPE not being expected.
      # Not calling this a fatal error because it could possibly be intended during development
      message(WARNING "Mismatched PSP/BSP: ${CFE_SYSTEM_PSPNAME} implies ${CFE_PSP_EXPECTED_OSAL_BSPTYPE}, but ${OSAL_SYSTEM_BSPTYPE} is configured")
  endif()
    
  # The "inc" directory in the binary dir contains the generated wrappers, if any
  include_directories(${MISSION_BINARY_DIR}/inc)
  include_directories(${CMAKE_BINARY_DIR}/inc)

  # Configure OSAL target first, as it also determines important compiler flags
  add_subdirectory("${osal_MISSION_DIR}" osal)
  
  # The OSAL displays its selected OS, so it is logical to display the selected PSP
  # This can help with debugging if things go wrong.
  message(STATUS "PSP Selection: ${CFE_SYSTEM_PSPNAME}")

  # Add all widely-used public headers to the include path chain
  include_directories(${MISSION_SOURCE_DIR}/osal/src/os/inc)
  include_directories(${MISSION_SOURCE_DIR}/psp/fsw/inc)  
  include_directories(${MISSION_SOURCE_DIR}/cfe/fsw/cfe-core/src/inc)
  include_directories(${MISSION_SOURCE_DIR}/cfe/cmake/target/inc)
    
  # propagate any OSAL interface compile definitions and include directories to this build
  # This is set as a directory property here at the top level so it will apply to all code.
  # This includes MODULE libraries that do not directly/statically link with OSAL but still
  # should be compiled with these flags.
  get_target_property(OSAL_COMPILE_DEFINITIONS osal INTERFACE_COMPILE_DEFINITIONS)
  get_target_property(OSAL_INCLUDE_DIRECTORIES osal INTERFACE_INCLUDE_DIRECTORIES)

  if (OSAL_COMPILE_DEFINITIONS)
    set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS "${OSAL_COMPILE_DEFINITIONS}")
  endif (OSAL_COMPILE_DEFINITIONS)
  if (OSAL_INCLUDE_DIRECTORIES)
    include_directories(${OSAL_INCLUDE_DIRECTORIES})
  endif (OSAL_INCLUDE_DIRECTORIES)

  # Import the eds2cfetbl executable target.
  # This is built by the parent (top-level) build and used here, it is a tool
  # that executes on the native machine so it must NOT be cross compiled.
  add_executable(eds2cfetbl IMPORTED)
  set_target_properties(eds2cfetbl PROPERTIES
    IMPORTED_LOCATION "${MISSION_BINARY_DIR}/eds/cfecfs/eds2cfetbl/eds2cfetbl"
  )

  # Generated EDS files all use a generalized mission name prefix in lowercase
  string(TOLOWER ${MISSION_NAME}_eds EDS_FILE_PREFIX)
  file(RELATIVE_PATH BINARY_SUBDIR ${MISSION_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR})
  
  add_custom_target(${SYSVAR}-eds-db
    COMMAND ${CMAKE_BUILD_TOOL} -j1
        -f ${EDS_FILE_PREFIX}_db_objects.mk 
        O=${BINARY_SUBDIR}/obj 
        CC=${CMAKE_C_COMPILER}
        LD=${CMAKE_LINKER}
        AR=${CMAKE_AR}
        CFLAGS=${CMAKE_C_FLAGS}
	LDFLAGS=${CFE_TOOLCHAIN_LD_FLAGS}
        "${BINARY_SUBDIR}/obj/${EDS_FILE_PREFIX}_db${CMAKE_STATIC_LIBRARY_SUFFIX}"
        "${BINARY_SUBDIR}/obj/${EDS_FILE_PREFIX}_db${CMAKE_SHARED_MODULE_SUFFIX}"
    WORKING_DIRECTORY
        ${MISSION_BINARY_DIR}
    VERBATIM
  )

  add_custom_target(${SYSVAR}-eds-interfacedb
    COMMAND ${CMAKE_BUILD_TOOL} -j1
        -f ${EDS_FILE_PREFIX}_interfacedb_objects.mk 
        O=${BINARY_SUBDIR}/obj 
        CC=${CMAKE_C_COMPILER} 
        LD=${CMAKE_LINKER}
        AR=${CMAKE_AR} 
        CFLAGS=${CMAKE_C_FLAGS} 
	LDFLAGS=${CFE_TOOLCHAIN_LD_FLAGS}
        "${BINARY_SUBDIR}/obj/${EDS_FILE_PREFIX}_interfacedb${CMAKE_STATIC_LIBRARY_SUFFIX}"
        "${BINARY_SUBDIR}/obj/${EDS_FILE_PREFIX}_interfacedb${CMAKE_SHARED_MODULE_SUFFIX}"
    WORKING_DIRECTORY
        ${MISSION_BINARY_DIR}
    VERBATIM
  )

  # on target architecture builds, the "edstool-execute" target
  # will not actually run the tool again.  Instead, it will just build all
  # the generated make targets from the parent build for this processor by
  # supplying the correct CC/AR tool
  add_custom_target(edstool-execute
    DEPENDS
        ${SYSVAR}-eds-db
        ${SYSVAR}-eds-interfacedb
        missionlib-runtime-install
  )
  
  # Append the PSP and OSAL selections to the Doxyfile so it will be included
  # in the generated documentation automatically.
  # Also extract the "-D" options within CFLAGS and inform Doxygen about these
  string(REGEX MATCHALL "-D[A-Za-z0-9_=]+" DOXYGEN_DEFINED_MACROS "${CMAKE_C_FLAGS}")
  string(REGEX REPLACE "-D" " " DOXYGEN_DEFINED_MACROS "${DOXYGEN_DEFINED_MACROS}")
  file(APPEND "${MISSION_BINARY_DIR}/doc/mission-content.doxyfile" 
    "PREDEFINED += ${DOXYGEN_DEFINED_MACROS}\n"
    "INPUT += ${MISSION_SOURCE_DIR}/osal/src/os/${OSAL_SYSTEM_OSTYPE}\n"
    "INPUT += ${MISSION_SOURCE_DIR}/psp/fsw/${CFE_SYSTEM_PSPNAME}\n"
    "INPUT += ${CMAKE_BINARY_DIR}/inc")

  # Append to usersguide.doxyfile
  file(APPEND "${MISSION_BINARY_DIR}/doc/cfe-usersguide.doxyfile" 
    "INPUT += ${MISSION_SOURCE_DIR}/psp/fsw/${CFE_SYSTEM_PSPNAME}/src\n"
    "INPUT += ${CMAKE_BINARY_DIR}/inc")
   
  # The PSP and/or OSAL should have defined where to install the binaries.
  # If not, just install them in /cf as a default (this can be modified 
  # by the packaging script if it is wrong for the target)
  if (NOT INSTALL_SUBDIR)
    set(INSTALL_SUBDIR cf)
  endif (NOT INSTALL_SUBDIR)

  # confirm that all dependencies have a MISSION_DIR defined that indicates the source.
  # This should have been set up by the parent script.  However, if any dir is not set,
  # this may result in "add_subdirectory" of itself which causes a loop.  This can happen
  # if the variables/lists were modified unexpectedly.
  foreach(DEP
        ${MISSION_CORE_MODULES}
        ${TGTSYS_${SYSVAR}_PSPMODULES}
        ${TGTSYS_${SYSVAR}_STATICAPPS}
        ${TGTSYS_${SYSVAR}_APPS})
    if(NOT DEFINED ${DEP}_MISSION_DIR)
      message(FATAL_ERROR "ERROR: core module ${DEP} has no MISSION_DIR defined")
    endif()
  endforeach()


  # Add all core modules
  # The osal is handled explicitly (above) since this has special extra config
  foreach(DEP ${MISSION_CORE_MODULES})
    if(NOT DEP STREQUAL "osal")
      message(STATUS "Building Core Module: ${DEP}")
      add_subdirectory("${${DEP}_MISSION_DIR}" ${DEP})
    endif(NOT DEP STREQUAL "osal")
  endforeach(DEP ${MISSION_CORE_MODULES})
  
  # For the PSP it may define the FSW as either 
  # "psp-${CFE_SYSTEM_PSPNAME}" or just simply "psp"
  if (NOT TARGET psp)
    add_library(psp ALIAS psp-${CFE_SYSTEM_PSPNAME})
  endif (NOT TARGET psp)
    
  # EDS aliases - due to the generic nature of EdsLib the
  # target names do not exactly match CFE expectations.
  add_library(edslib ALIAS edslib_minimal)
  add_library(missionlib ALIAS cfe_missionlib)

    
  # Process each PSP module that is referenced on this system architecture (any cpu)
  foreach(PSPMOD ${TGTSYS_${SYSVAR}_PSPMODULES}) 
    message(STATUS "Building PSP Module: ${PSPMOD}")
    add_subdirectory("${${PSPMOD}_MISSION_DIR}" psp/${PSPMOD})
  endforeach()
  
  # Process each app that is used on this system architecture
  set(APP_INSTALL_LIST)
  foreach(APP ${TGTSYS_${SYSVAR}_STATICAPPS})
    message(STATUS "Building Static App: ${APP}")
    add_subdirectory("${${APP}_MISSION_DIR}" apps/${APP})
  endforeach()

  # Process each target that shares this system architecture
  # First Pass: Assemble the list of apps that should be compiled 
  foreach(APP ${TGTSYS_${SYSVAR}_APPS})
    set(TGTLIST_${APP})
  endforeach()

  foreach(TGTID ${TGTSYS_${SYSVAR}})
      
    set(TGTNAME ${TGT${TGTID}_NAME})
    if(NOT TGTNAME)
      set(TGTNAME "cpu${TGTID}")
      set(TGT${TGTID}_NAME "${TGTNAME}")
    endif(NOT TGTNAME)
       
    # Append to the app install list for this CPU
    foreach(APP ${TGT${TGTID}_APPLIST})
      set(TGTLIST_${APP} ${TGTLIST_${APP}} ${TGTNAME})
    endforeach(APP ${TGT${TGTID}_APPLIST})
      
  endforeach(TGTID ${TGTSYS_${SYSVAR}})
  
  # Process each app that is used on this system architecture
  foreach(APP ${TGTSYS_${SYSVAR}_APPS})
    set(APP_INSTALL_LIST ${TGTLIST_${APP}})
    message(STATUS "Building App: ${APP} install=${APP_INSTALL_LIST}")
    add_subdirectory("${${APP}_MISSION_DIR}" apps/${APP})
  endforeach()
  
  # Process each target that shares this system architecture
  # Second Pass: Build and link final target executable 
  foreach(TGTID ${TGTSYS_${SYSVAR}})
  
    set(TGTNAME ${TGT${TGTID}_NAME})
    
    # Target to generate the actual executable file
    add_subdirectory(cmake/target ${TGTNAME})
    
    foreach(INSTFILE ${TGT${TGTID}_FILELIST})
      if(EXISTS ${MISSION_DEFS}/${TGTNAME}_${INSTFILE})
        set(FILESRC ${MISSION_DEFS}/${TGTNAME}_${INSTFILE})
      elseif(EXISTS ${MISSION_DEFS}/${INSTFILE})
        set(FILESRC ${MISSION_DEFS}/${INSTFILE})
      else()
        set(FILESRC)
      endif()
      if (FILESRC)
        install(FILES ${FILESRC} DESTINATION ${TGTNAME}/${INSTALL_SUBDIR} RENAME ${INSTFILE})
      else(FILESRC)
        message("WARNING: Install file ${INSTFILE} for ${TGTNAME} not found")
      endif (FILESRC)
    endforeach(INSTFILE ${TGT${TGTID}_FILELIST})
  endforeach(TGTID ${TGTSYS_${SYSVAR}})
 
 
endfunction(process_arch SYSVAR)

