| # This CMake include file defines utility functions for handling generated files | |
| # that are required in another CMake directory other than the one where it was | |
| # generated. | |
| # | |
| # Key functions: | |
| # | |
| # * ADD_FILE_TARGET - Creates a file target. All source files, whether | |
| # generated or not should call this function. | |
| # * GET_FILE_TARGET - Given a absolute or local source path, what is the target | |
| # that will build this file. | |
| # * GET_REL_TARGET - Given a absolute or local source path and prefix | |
| # generates target name in a form $prefix_$file. | |
| # * GET_FILE_LOCATION - Given a absolute or local source path, what is the | |
| # actual location of the file. | |
| # | |
| # When writing targets that rely on files using these functions, never use a raw | |
| # source path, e.g. ${CMAKE_CURRENT_SOURCE_DIR}/example_dir/example.file or | |
| # example.file. Instead always call GET_FILE_LOCATION on the path. This is | |
| # because the actual source location may not be in the source tree, but instead | |
| # be in the build tree. | |
| # | |
| # When writing targets that rely on files using these functions, always DEPEND | |
| # on both the file location (from GET_FILE_LOCATION) and the file target (from | |
| # GET_FILE_TARGET). If you only DEPEND on the file location, the file will not | |
| # be generated the first time through the build. | |
| # | |
| # Utility functions: | |
| # | |
| # * APPEND_FILE_LOCATION - Appends to a list the file location of specified | |
| # file. | |
| # * APPEND_FILE_DEPENDENCY - Appends to a list both the file location and file | |
| # target of specified file. | |
| function(GET_REL_TARGET var prefix src_file) | |
| if(${src_file} MATCHES "^/") | |
| set(SOURCE_LOCATION ${src_file}) | |
| else() | |
| set(SOURCE_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/${src_file}) | |
| endif() | |
| get_filename_component(CANON_LOCATION ${SOURCE_LOCATION} | |
| ABSOLUTE | |
| BASE_DIR ${f4pga-arch-defs_SOURCE_DIR} | |
| ) | |
| string( | |
| REPLACE | |
| "${f4pga-arch-defs_SOURCE_DIR}" | |
| "" | |
| REL_CANON_LOCATION | |
| ${CANON_LOCATION} | |
| ) | |
| string( | |
| REPLACE | |
| "/" | |
| "_" | |
| TARGET_PATH | |
| ${REL_CANON_LOCATION} | |
| ) | |
| set(${var} ${prefix}${TARGET_PATH} PARENT_SCOPE) | |
| endfunction() | |
| function(GET_FILE_TARGET var src_file) | |
| get_rel_target(TARGET_PATH file ${src_file}) | |
| set(${var} ${TARGET_PATH} PARENT_SCOPE) | |
| endfunction() | |
| function(GET_FILE_LOCATION var src_file) | |
| # Sets var in PARENT_SCOPE to file location for given src_file. | |
| get_file_target(SRC_TARGET ${src_file}) | |
| get_target_property(SRC_LOCATION ${SRC_TARGET} LOCATION) | |
| if("${SRC_LOCATION}" STREQUAL "NOT_FOUND") | |
| message( | |
| FATAL_ERROR | |
| "File ${src_file} is not a valid verilog target, missing LOCATION." | |
| ) | |
| endif() | |
| set(${var} ${SRC_LOCATION} PARENT_SCOPE) | |
| endfunction() | |
| function(APPEND_FILE_LOCATION var src_file) | |
| # Appends to list var in PARENT_SCOPE both file location for | |
| # given src_file. | |
| get_file_target(SRC_TARGET ${src_file}) | |
| get_target_property(SRC_LOCATION ${SRC_TARGET} LOCATION) | |
| if("${SRC_LOCATION}" STREQUAL "NOT_FOUND") | |
| message( | |
| FATAL_ERROR | |
| "File ${src_file} is not a valid verilog target, missing LOCATION." | |
| ) | |
| endif() | |
| list(APPEND ${var} ${SRC_LOCATION}) | |
| set(${var} "${${var}}" PARENT_SCOPE) | |
| endfunction() | |
| function(APPEND_FILE_DEPENDENCY var src_file) | |
| # Appends to list var in PARENT_SCOPE both file location and file target for | |
| # given src_file. | |
| get_file_target(SRC_TARGET ${src_file}) | |
| get_target_property(SRC_LOCATION ${SRC_TARGET} LOCATION) | |
| if("${SRC_LOCATION}" STREQUAL "NOT_FOUND") | |
| message( | |
| FATAL_ERROR | |
| "File ${src_file} is not a valid verilog target, missing LOCATION." | |
| ) | |
| endif() | |
| list(APPEND ${var} ${SRC_TARGET}) | |
| list(APPEND ${var} ${SRC_LOCATION}) | |
| get_target_property(INCLUDE_FILES ${SRC_TARGET} INCLUDE_FILES) | |
| foreach(SRC ${INCLUDE_FILES}) | |
| append_file_dependency(${var} ${SRC}) | |
| endforeach() | |
| set(${var} "${${var}}" PARENT_SCOPE) | |
| endfunction() | |
| function(APPEND_FILE_INCLUDES var src_file) | |
| # Appends to list var in PARENT_SCOPE both includes listed for file target for | |
| # given src_file. | |
| get_file_target(SRC_TARGET ${src_file}) | |
| get_target_property(SRC_INCLUDES ${SRC_TARGET} INCLUDES) | |
| if("${SRC_INCLUDES}" STREQUAL "NOT_FOUND") | |
| message( | |
| FATAL_ERROR | |
| "File ${SRC} is not a valid verilog target, missing INCLUDES list." | |
| ) | |
| endif() | |
| list(APPEND ${var} ${SRC_INCLUDES}) | |
| set(${var} "${${var}}" PARENT_SCOPE) | |
| endfunction() | |
| function(GET_VERILOG_INCLUDES var file) | |
| # Appends to list var in PARENT_SCOPE all verilog source dependency based on | |
| # scanning input at configure time. | |
| # | |
| # Note this function cannot be used at generation time because execute_process | |
| # is called during configure step and generated files don't exist yet. | |
| execute_process( | |
| COMMAND | |
| ${PYTHON_EXECUTABLE} ${f4pga-arch-defs_SOURCE_DIR}/utils/deps_verilog.py | |
| --file_per_line ${CMAKE_CURRENT_SOURCE_DIR}/${file} | |
| WORKING_DIRECTORY ${f4pga-arch-defs_SOURCE_DIR} | |
| OUTPUT_VARIABLE INCLUDES | |
| ) | |
| string( | |
| REPLACE | |
| "\n" | |
| ";" | |
| INCLUDES_LIST | |
| "${INCLUDES}" | |
| ) | |
| foreach(INCLUDE ${INCLUDES_LIST}) | |
| string(STRIP ${INCLUDE} INCLUDE) | |
| if(NOT "${INCLUDE}" STREQUAL "") | |
| get_filename_component( | |
| ABS_PATH_TO_INCLUDE | |
| ${INCLUDE} | |
| ABSOLUTE | |
| BASE_DIR | |
| ${f4pga-arch-defs_SOURCE_DIR} | |
| ) | |
| list(APPEND ${var} ${ABS_PATH_TO_INCLUDE}) | |
| endif() | |
| endforeach() | |
| set(${var} "${${var}}" PARENT_SCOPE) | |
| endfunction() | |
| function(GET_XML_INCLUDES var file) | |
| # Appends to list var in PARENT_SCOPE all xml source dependency based on | |
| # scanning input at configure time. | |
| # | |
| # Note this function cannot be used at generation time because execute_process | |
| # is called during configure step and generated files don't exist yet. | |
| execute_process( | |
| COMMAND | |
| ${PYTHON_EXECUTABLE} ${f4pga-arch-defs_SOURCE_DIR}/utils/deps_xml.py | |
| --file_per_line ${CMAKE_CURRENT_SOURCE_DIR}/${file} | |
| WORKING_DIRECTORY ${f4pga-arch-defs_SOURCE_DIR} | |
| OUTPUT_VARIABLE INCLUDES | |
| ) | |
| string( | |
| REPLACE | |
| "\n" | |
| ";" | |
| INCLUDES_LIST | |
| "${INCLUDES}" | |
| ) | |
| foreach(INCLUDE ${INCLUDES_LIST}) | |
| string(STRIP ${INCLUDE} INCLUDE) | |
| if(NOT "${INCLUDE}" STREQUAL "") | |
| get_filename_component( | |
| ABS_PATH_TO_INCLUDE | |
| ${INCLUDE} | |
| ABSOLUTE | |
| BASE_DIR | |
| ${f4pga-arch-defs_SOURCE_DIR} | |
| ) | |
| list(APPEND ${var} ${ABS_PATH_TO_INCLUDE}) | |
| endif() | |
| endforeach() | |
| set(${var} "${${var}}" PARENT_SCOPE) | |
| endfunction() | |
| function(ADD_FILE_TARGET) | |
| # ~~~ | |
| # ADD_FILE_TARGET( | |
| # FILE <source file location> | |
| # [GENERATED | SCANNER_TYPE <verilog|xml>] | |
| # [ABSOLUTE] | |
| # ) | |
| # ~~~ | |
| # | |
| # Creates new file target for given source location. Even if ADD_FILE_TARGET | |
| # is being called on a file that is located in the binary directory, always | |
| # pass the source location it would have if the source and binary directories | |
| # were the same. This is important for dependency definitions that assume all | |
| # inputs are in one folder. | |
| # | |
| # ADD_FILE_TARGET ensures that all sources are in one folder, because of how | |
| # the verilog include directive is defined. | |
| # | |
| # SCANNER_TYPE argument can be used if GENERATED or ABSOLUTE are not set. Valid | |
| # SCANNER_TYPE are "verilog" and "xml". | |
| # ABSOLUTE parameter must be used to mark passed path is absolute | |
| # | |
| # GENERATED must be passed if the source file is generated and is placed | |
| # within the binary directory. | |
| set(options GENERATED ABSOLUTE) | |
| set(oneValueArgs FILE SCANNER_TYPE) | |
| set(multiValueArgs) | |
| cmake_parse_arguments( | |
| ADD_FILE_TARGET | |
| "${options}" | |
| "${oneValueArgs}" | |
| "${multiValueArgs}" | |
| ${ARGN} | |
| ) | |
| get_file_target(TARGET_NAME ${ADD_FILE_TARGET_FILE}) | |
| set(INCLUDE_FILES "") | |
| if(NOT ${ADD_FILE_TARGET_GENERATED}) | |
| if("${ADD_FILE_TARGET_SCANNER_TYPE}" STREQUAL "") | |
| elseif("${ADD_FILE_TARGET_SCANNER_TYPE}" STREQUAL "verilog") | |
| get_verilog_includes(INCLUDE_FILES ${ADD_FILE_TARGET_FILE}) | |
| elseif("${ADD_FILE_TARGET_SCANNER_TYPE}" STREQUAL "xml") | |
| get_xml_includes(INCLUDE_FILES ${ADD_FILE_TARGET_FILE}) | |
| else() | |
| message( | |
| FATAL_ERROR "Unknown SCANNER_TYPE=${ADD_FILE_TARGET_SCANNER_TYPE}." | |
| ) | |
| endif() | |
| endif() | |
| set(INCLUDE_FILES_TARGETS "") | |
| foreach(INCLUDE ${INCLUDE_FILES}) | |
| append_file_dependency(INCLUDE_FILES_TARGETS ${INCLUDE}) | |
| endforeach() | |
| if(NOT ${ADD_FILE_TARGET_GENERATED} AND NOT ${ADD_FILE_TARGET_ABSOLUTE}) | |
| get_filename_component(DEST_PATH ${CMAKE_CURRENT_BINARY_DIR}/${ADD_FILE_TARGET_FILE} DIRECTORY) | |
| add_custom_command( | |
| OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${ADD_FILE_TARGET_FILE} | |
| COMMAND | |
| ${CMAKE_COMMAND} -E make_directory | |
| ${DEST_PATH} | |
| COMMAND | |
| ${CMAKE_COMMAND} -E create_symlink | |
| ${CMAKE_CURRENT_SOURCE_DIR}/${ADD_FILE_TARGET_FILE} | |
| ${CMAKE_CURRENT_BINARY_DIR}/${ADD_FILE_TARGET_FILE} | |
| ) | |
| endif() | |
| if(${ADD_FILE_TARGET_ABSOLUTE}) | |
| set(FILE_PATH ${ADD_FILE_TARGET_FILE}) | |
| else() | |
| set(FILE_PATH ${CMAKE_CURRENT_BINARY_DIR}/${ADD_FILE_TARGET_FILE}) | |
| endif() | |
| add_custom_target( | |
| ${TARGET_NAME} | |
| DEPENDS | |
| ${FILE_PATH} | |
| ${INCLUDE_FILES_TARGETS} | |
| ) | |
| set_target_properties( | |
| ${TARGET_NAME} | |
| PROPERTIES LOCATION ${FILE_PATH} | |
| ) | |
| set_target_properties(${TARGET_NAME} PROPERTIES INCLUDE_FILES "${INCLUDE_FILES}") | |
| set_target_properties(${TARGET_NAME} PROPERTIES INCLUDES "") | |
| set_target_properties(${TARGET_NAME} PROPERTIES INCLUDE_FILES "${INCLUDE_FILES}") | |
| endfunction(ADD_FILE_TARGET) |