diff --git a/camkes_vm_helpers.cmake b/camkes_vm_helpers.cmake index f991351f..db90d529 100644 --- a/camkes_vm_helpers.cmake +++ b/camkes_vm_helpers.cmake @@ -63,22 +63,160 @@ function(DeclareCAmkESVM init_component) ) endfunction(DeclareCAmkESVM) +# # Function defines a CAmkESVMFileServer using the declared fileserver images # and fileserver dependencies. These images are placed into a CPIO archive. +# +# Parameters: +# +# TYPE +# Type of the file server CAmkES component. +# Optional, defaults to "FileServer" +# +# INSTANCE +# Instance name of the file server CAmkES component. +# Optional, defaults to "fserv" +# +# FILES [ [...]] +# The files to be added. Each item has the form [:], where +# the optional allows using a different name for the file in the +# archive than on the disk. The build will abort if is not found. +# Each item can either be a single file item or a CMake list of items (such a +# CMake list is basically a string with elements separated by ';'). This +# allows building lists of files in advance, which may contain different files +# for different configurations. An empty string as item is also explicitly +# allowed for convenience reasons. Thus supports cases where a an item does +# not exist in every configuration and the respective CMake variable used for +# the item is just left empty. +# +# DEPENDS [ [...]] +# Any additional dependencies for the file/image the caller is adding to the +# file server +# +# function(DefineCAmkESVMFileServer) - # Retrieve defined kernel images, rootfs images and extraction dependencies - get_target_property(fileserver_images vm_fserver_config FILES) - get_target_property(fileserver_deps vm_fserver_config DEPS) - # Build CPIO archive given the defined kernel and rootfs images - set(CPIO_ARCHIVE "file_server_archive.o") + + cmake_parse_arguments( + PARSE_ARGV + 0 + PARAM # variable prefix + "" # option arguments + "TYPE;INSTANCE" # optional single value arguments + "FILES;DEPENDS" # optional multi value arguments + ) + + if(PARAM_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unknown arguments: ${PARAM_UNPARSED_ARGUMENTS}") + endif() + + if(NOT PARAM_TYPE) + set(PARAM_TYPE "FileServer") + endif() + + if(NOT PARAM_INSTANCE) + set(PARAM_INSTANCE "fserv") + endif() + + if(PARAM_DEPENDS) + set_property( + TARGET vm_fserver_config + APPEND + PROPERTY DEPS_${PARAM_INSTANCE} ${PARAM_DEPENDS} + ) + endif() + + foreach(element IN LISTS PARAM_FILES) + foreach(item IN LISTS element) # [:] + if(NOT item) + continue() + endif() + string( + REGEX + MATCH + "^([^:]+)(:([^:]+))?$" + cpio_item + "${item}" + ) + if(NOT cpio_item) + message(FATAL_ERROR "invalid paramete format: '${item}'") + endif() + if(CMAKE_MATCH_3) + set(CPIO_NAME "${CMAKE_MATCH_1}") + set(FILE_NAME "${CMAKE_MATCH_3}") + else() + set(FILE_NAME "${CMAKE_MATCH_1}") + get_filename_component(CPIO_NAME "${FILE_NAME}" NAME) + endif() + # For legacy reasons, we still call AddToFileServer() here. It will + # simplify things a lot, if this function is removed completely. It + # is no longer needed, because we accept lists of files now., which + # the caller is supposed to build then. For now, AddToFileServer() + # is just a light wrapper that build such a list. Thus, there is no + # need to pass dependencies from PARAM_DEPENDS here, have added them + # above already. + AddToFileServer("${CPIO_NAME}" "${FILE_NAME}" INSTANCE "${PARAM_INSTANCE}") + endforeach() + endforeach() + + # now process the file/deps list + get_target_property(files vm_fserver_config FILES_${PARAM_INSTANCE}) + if(NOT files) # this also catches "files-NOTFOUND" if property is not set + set(files "") + endif() + get_target_property(deps vm_fserver_config DEPS_${PARAM_INSTANCE}) + if(NOT deps) # this also catches "deps-NOTFOUND" if property is not set + set(deps "") + endif() + + set(INST_BIN_DIR "${CMAKE_CURRENT_BINARY_DIR}/${PARAM_INSTANCE}") + + set(CPIO_FILES "") + foreach(item IN LISTS files) # : + string( + REGEX + MATCH + "^([^:]+):([^:]+)$" + cpio_item + "${item}" + ) + if(NOT cpio_item) + message(FATAL_ERROR "invalid CPIO file format: '${item}'") + endif() + set(CPIO_NAME "${CMAKE_MATCH_1}") + set(FILE_NAME "${CMAKE_MATCH_2}") + set(CPIO_FILE "${INST_BIN_DIR}/files/${CPIO_NAME}") + add_custom_command( + OUTPUT "${CPIO_FILE}" + COMMENT "copy: ${FILE_NAME} -> ${CPIO_FILE}" + COMMAND + ${CMAKE_COMMAND} -E copy "${FILE_NAME}" "${CPIO_FILE}" + VERBATIM + DEPENDS ${FILE_NAME} ${deps} + ) + # There is no need to create an explicit target for the command above, + # the archive creation depends on all files in CPIO_FILES, where the + # command above is the creation rule for each one. + list(APPEND CPIO_FILES "${CPIO_FILE}") + endforeach() + + # Build CPIO archive. It implicitly depends on all files in CPIO_FILES, + # which have their own dependencies each from above. So we don't have any + # additional explicit dependencies here. + # Unfortunately MakeCPIO() support plain file names only and does not + # support paths. Thus, the archive will be created in the built output root + # folder, where using INST_BIN_DIR would be a bit cleaner actually. + set(CPIO_ARCHIVE "${PARAM_INSTANCE}_cpio_archive.o") include(cpio) - MakeCPIO("${CPIO_ARCHIVE}" "${fileserver_images}" DEPENDS "${fileserver_deps}") - # Build a library from the CPIO archive - set(FILESERVER_LIB "fileserver_cpio") + MakeCPIO("${CPIO_ARCHIVE}" "${CPIO_FILES}") + + # Build a library from the CPIO archive. Ensure the lib has a unique name + # within the project, as there could be more than one file server. + set(FILESERVER_LIB "${PARAM_INSTANCE}_file_archive_cpio") add_library("${FILESERVER_LIB}" STATIC EXCLUDE_FROM_ALL "${CPIO_ARCHIVE}") set_property(TARGET "${FILESERVER_LIB}" PROPERTY LINKER_LANGUAGE C) # Add the CPIO-library to the FileServer component - ExtendCAmkESComponentInstance(FileServer fserv LIBS "${FILESERVER_LIB}") + ExtendCAmkESComponentInstance("${PARAM_TYPE}" "${PARAM_INSTANCE}" LIBS "${FILESERVER_LIB}") + endfunction(DefineCAmkESVMFileServer) # Function for declaring the CAmkESVM root server. Taking the camkes application @@ -105,40 +243,58 @@ function(DeclareCAmkESVMRootServer camkes_config) endfunction(DeclareCAmkESVMRootServer) # Function for adding a file/image to the vm file server. -# filename_pref: The name the caller wishes to use to reference the file in the CPIO archive. This -# corresponds with the name set in the 'kernel_image' camkes variable for a given instance vm. -# file_dest: The location of the file/image the caller is adding to the file server -# DEPENDS: Any additional dependencies for the file/image the caller is adding to the -# file server +# +# Parameters: +# +# +# The name the caller wishes to use to reference the file in the CPIO archive. +# This corresponds with the name set in the 'kernel_image' camkes variable for +# a given instance vm. +# +# +# The location of the file/image the caller is adding to the file server +# +# INSTANCE +# Instance name of the file server CAmkES component. +# Optional, defaults to "fserv" +# +# DEPENDS [ [...]] +# Any additional dependencies for the file/image the caller is adding to the +# file server +# function(AddToFileServer filename_pref file_dest) - # Get any existing dependencies when adding the image into the file server archive - cmake_parse_arguments(PARSE_ARGV 2 CAMKES_FILESERVER "" "" "DEPENDS") - if(NOT "${CAMKES_FILESERVER_UNPARSED_ARGUMENTS}" STREQUAL "") - message(FATAL_ERROR "Unknown arguments to AddToFileServer") - endif() - # Create a copy of the file in the binary directory to the callers - # preferred name - add_custom_command( - OUTPUT file_server/${filename_pref} - COMMAND - ${CMAKE_COMMAND} -E copy "${file_dest}" - "${CMAKE_CURRENT_BINARY_DIR}/file_server/${filename_pref}" - VERBATIM - DEPENDS ${file_dest} ${CAMKES_FILESERVER_DEPENDS} - ) - #Create custom target for copy command - add_custom_target( - copy_${filename_pref} - DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/file_server/${filename_pref}" + + cmake_parse_arguments( + PARSE_ARGV + 2 + PARAM # variable prefix + "" # option arguments + "INSTANCE" # optional single value arguments + "DEPENDS" # optional multi value arguments ) - # Store the rootfs file location. Used when building the CPIO at a later stage + + if(PARAM_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unknown arguments: ${PARAM_UNPARSED_ARGUMENTS}") + endif() + + if(NOT PARAM_INSTANCE) + set(PARAM_INSTANCE "fserv") + endif() + set_property( TARGET vm_fserver_config APPEND - PROPERTY FILES "${CMAKE_CURRENT_BINARY_DIR}/file_server/${filename_pref}" + PROPERTY FILES_${PARAM_INSTANCE} "${filename_pref}:${file_dest}" ) - # Append soft link dependency - set_property(TARGET vm_fserver_config APPEND PROPERTY DEPS "copy_${filename_pref}") + + if(PARAM_DEPENDS) + set_property( + TARGET vm_fserver_config + APPEND + PROPERTY DEPS_${PARAM_INSTANCE} ${PARAM_DEPENDS} + ) + endif() + endfunction(AddToFileServer) # Function for decompressing/extracting a vmlinux file from a given kernel image