# # This file is distributed under the MIT License. See LICENSE.md for details. # # Extracts definitions and generates C++ headers and implementations from the # given header files. # The definitions must be embedded as described in the docs for # tuple_tree_generator_extract_definitions_from_headers. function(tuple_tree_generator # Name of the target to generate the code TARGET_NAME # List of C++ headers HEADERS # Delimiter used to mark comments embedding type schemas DELIMITER NAMESPACE # Where the schema will be collected SCHEMA_PATH # Directory where the headers will be generated HEADERS_DIR # Include path prefix INCLUDE_PATH_PREFIX # Variable will be filled with the list of generated C++ headers GENERATED_HEADERS_VARIABLE # Variable will be filled with the list of generated C++ source files GENERATED_IMPLS_VARIABLE # Where the JSON schema will be produced (empty for no schema) JSONSCHEMA_PATH # Type to use as the root of the JSON schema JSONSCHEMA_ROOT_TYPE # Types equivalent to strings STRING_TYPES # Types equivalent to strings which get a separate type definition SEPARATE_STRING_TYPES ) # # Collect all the definitions in a single YAML document # tuple_tree_generator_extract_definitions_from_headers( "${HEADERS}" "${DELIMITER}" "${SCHEMA_PATH}" ) # # C++ headers and implementation generation # tuple_tree_generator_compute_generated_cpp_files( "${HEADERS}" "${HEADERS_DIR}" LOCAL_GENERATED_HEADERS LOCAL_GENERATED_IMPLS ) tuple_tree_generator_generate_cpp( "${SCHEMA_PATH}" "${NAMESPACE}" "${HEADERS_DIR}" "${INCLUDE_PATH_PREFIX}" "${LOCAL_GENERATED_HEADERS}" "${LOCAL_GENERATED_IMPLS}" ) set("${GENERATED_HEADERS_VARIABLE}" ${LOCAL_GENERATED_HEADERS} PARENT_SCOPE) set("${GENERATED_IMPLS_VARIABLE}" ${LOCAL_GENERATED_IMPLS} PARENT_SCOPE) # # Produce JSON schema, if requested # if(NOT "${JSONSCHEMA_PATH}" STREQUAL "") tuple_tree_generator_generate_jsonschema( "${SCHEMA_PATH}" "${NAMESPACE}" "${JSONSCHEMA_ROOT_TYPE}" "${STRING_TYPES}" "${SEPARATE_STRING_TYPES}" "${JSONSCHEMA_PATH}" ) endif() add_custom_target( "${TARGET_NAME}" DEPENDS "${SCHEMA_PATH}" ${LOCAL_GENERATED_HEADERS} ${LOCAL_GENERATED_IMPLS} ${JSONSCHEMA_PATH} ) endfunction() # Extracts tuple_tree_generator YAML definitions from the given header files # # The definitions have to be embedded in a c-style comment marked with the given # delimiter, like so: # # /* DELIMITER # # DELIMITER */ function(tuple_tree_generator_extract_definitions_from_headers HEADERS DELIMITER OUTPUT_FILE) add_custom_command( OUTPUT "${OUTPUT_FILE}" COMMAND "${CMAKE_SOURCE_DIR}/scripts/tuple_tree_generator/extract_yaml.py" --output "${OUTPUT_FILE}" "${DELIMITER}" ${HEADERS} DEPENDS ${HEADERS} ) endfunction() # Computes the list of headers and C++ source files that will be generated by # tuple_tree_generator. # Note: the output variables will be overwritten function(tuple_tree_generator_compute_generated_cpp_files SOURCE_HEADERS HEADERS_DIR GENERATED_HEADERS_VARIABLE GENERATED_IMPLS_VARIABLE ) # Empty output variables set(LOCAL_GENERATED_HEADERS_VARIABLE "${HEADERS_DIR}/ForwardDecls.h") set(LOCAL_GENERATED_IMPLS_VARIABLE) foreach(HEADER ${SOURCE_HEADERS}) # TODO: we should not be generating /Impl/*.cpp files in an include/* directory # TODO: this piece of code is tightly coupled with cppheaders.py get_filename_component(HEADER_FILENAME "${HEADER}" NAME) get_filename_component(HEADER_FILENAME_WE "${HEADER}" NAME_WE) set(EARLY_OUTPUT "${HEADERS_DIR}/Early/${HEADER_FILENAME}") set(LATE_OUTPUT "${HEADERS_DIR}/Late/${HEADER_FILENAME}") set(IMPL_OUTPUT "${HEADERS_DIR}/Impl/${HEADER_FILENAME_WE}.cpp") list(APPEND LOCAL_GENERATED_HEADERS_VARIABLE "${EARLY_OUTPUT}") list(APPEND LOCAL_GENERATED_HEADERS_VARIABLE "${LATE_OUTPUT}") list(APPEND LOCAL_GENERATED_IMPLS_VARIABLE "${IMPL_OUTPUT}") endforeach() set("${GENERATED_HEADERS_VARIABLE}" ${LOCAL_GENERATED_HEADERS_VARIABLE} PARENT_SCOPE) set("${GENERATED_IMPLS_VARIABLE}" ${LOCAL_GENERATED_IMPLS_VARIABLE} PARENT_SCOPE) endfunction() set(TEMPLATES_DIR "${CMAKE_SOURCE_DIR}/scripts/tuple_tree_generator/tuple_tree_generator/templates") set(TEMPLATES "${TEMPLATES_DIR}/class_forward_decls.h.tpl" "${TEMPLATES_DIR}/enum.h.tpl" "${TEMPLATES_DIR}/struct.h.tpl" "${TEMPLATES_DIR}/struct_forward_decls.h.tpl" "${TEMPLATES_DIR}/struct_late.h.tpl" "${TEMPLATES_DIR}/struct_impl.cpp.tpl" ) set(SCRIPTS_ROOT_DIR "${CMAKE_SOURCE_DIR}/scripts/tuple_tree_generator") # The list of Python scripts is build as follows: # # find scripts/tuple_tree_generator -name "*.py" | sort | sed 's|scripts/tuple_tree_generator|"\${SCRIPTS_ROOT_DIR}|; s/$/"/' # # TODO: detect and warn about extra files in those directories set(TUPLE_TREE_GENERATOR_SOURCES "${SCRIPTS_ROOT_DIR}/extract_yaml.py" "${SCRIPTS_ROOT_DIR}/tuple-tree-generate-cpp.py" "${SCRIPTS_ROOT_DIR}/tuple-tree-generate-jsonschema.py" "${SCRIPTS_ROOT_DIR}/tuple_tree_generator/__init__.py" "${SCRIPTS_ROOT_DIR}/tuple_tree_generator/generators/__init__.py" "${SCRIPTS_ROOT_DIR}/tuple_tree_generator/generators/cppheaders.py" "${SCRIPTS_ROOT_DIR}/tuple_tree_generator/generators/jinja_utils.py" "${SCRIPTS_ROOT_DIR}/tuple_tree_generator/generators/jsonschema.py" "${SCRIPTS_ROOT_DIR}/tuple_tree_generator/schema/__init__.py" "${SCRIPTS_ROOT_DIR}/tuple_tree_generator/schema/definition.py" "${SCRIPTS_ROOT_DIR}/tuple_tree_generator/schema/enum.py" "${SCRIPTS_ROOT_DIR}/tuple_tree_generator/schema/schema.py" "${SCRIPTS_ROOT_DIR}/tuple_tree_generator/schema/struct.py" ) # Generates headers and implementation C++ files function(tuple_tree_generator_generate_cpp # Path to the yaml definitions YAML_DEFINITIONS # Base namespace of the generated classes (e.g. model) NAMESPACE # Output directory OUTPUT_DIR # Include path prefix INCLUDE_PATH_PREFIX # List of headers that are expected to be generated EXPECTED_GENERATED_HEADERS # List of implementation files expected to be generated EXPECTED_GENERATED_IMPLS ) add_custom_command( COMMAND "${SCRIPTS_ROOT_DIR}/tuple-tree-generate-cpp.py" --namespace "${NAMESPACE}" --include-path-prefix "${INCLUDE_PATH_PREFIX}" "${YAML_DEFINITIONS}" "${OUTPUT_DIR}" OUTPUT ${EXPECTED_GENERATED_HEADERS} ${EXPECTED_GENERATED_IMPLS} DEPENDS "${YAML_DEFINITIONS}" ${TEMPLATES} "${SCRIPTS_ROOT_DIR}/extract_yaml.py" ${TUPLE_TREE_GENERATOR_SOURCES} ) endfunction() # Generates JSON schema files function(tuple_tree_generator_generate_jsonschema YAML_DEFINITIONS # Path to the yaml definitions NAMESPACE # Base namespace of the generated classes (e.g. model) JSONSCHEMA_ROOT_TYPE # Type to use as the root of the JSON schema STRING_TYPES # Types equivalent to plain strings SEPARATE_STRING_TYPES # Types equivalent to plain strings that get a separate type definition OUTPUT_PATH # Output path ) set(STRING_TYPE_ARGS) foreach(ST ${STRING_TYPES}) list(APPEND STRING_TYPE_ARGS --string-type "${ST}") endforeach() set(SEPARATE_STRING_TYPE_ARGS) foreach(ST ${SEPARATE_STRING_TYPES}) list(APPEND SEPARATE_STRING_TYPE_ARGS --separate-string-type "${ST}") endforeach() add_custom_command( COMMAND "${SCRIPTS_ROOT_DIR}/tuple-tree-generate-jsonschema.py" --namespace "${NAMESPACE}" --root-type "${JSONSCHEMA_ROOT_TYPE}" --output "${OUTPUT_PATH}" ${STRING_TYPE_ARGS} ${SEPARATE_STRING_TYPE_ARGS} "${YAML_DEFINITIONS}" OUTPUT "${OUTPUT_PATH}" DEPENDS "${YAML_DEFINITIONS}" ${TUPLE_TREE_GENERATOR_SOURCES} ) endfunction() function( target_tuple_tree_and_schema_generate HEADER_DIRECTORY NAMESPACE SCHEMA_PATH TARGET_ID JSONSCHEMA_PATH JSONSCHEMA_ROOT_TYPE STRING_TYPES SEPARATE_STRING_TYPES ) # Generate C++ headers from the collected YAML set(OUTPUT_DIR "${CMAKE_BINARY_DIR}/include/revng/${HEADER_DIRECTORY}/Generated") tuple_tree_generator( generate-${TARGET_ID}-tuple-tree-code "${ARGN}" TUPLE-TREE-YAML ${NAMESPACE} "${SCHEMA_PATH}" "${OUTPUT_DIR}" "revng/${HEADER_DIRECTORY}" GENERATED_HEADERS GENERATED_IMPLS "${JSONSCHEMA_PATH}" ${JSONSCHEMA_ROOT_TYPE} "${STRING_TYPES}" "${SEPARATE_STRING_TYPES}" ) install( DIRECTORY ${OUTPUT_DIR} DESTINATION include/revng/${HEADER_DIRECTORY} ) target_sources(${TARGET_ID} PRIVATE ${GENERATED_IMPLS}) add_dependencies(${TARGET_ID} generate-${TARGET_ID}-tuple-tree-code) endfunction() function( target_tuple_tree_generate HEADER_DIRECTORY NAMESPACE SCHEMA_PATH TARGET_ID ) target_tuple_tree_and_schema_generate( ${HEADER_DIRECTORY} ${NAMESPACE} ${SCHEMA_PATH} ${TARGET_ID} "" ${TARGET_ID}_schema "" "" "${ARGN}") endfunction()