mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
259 lines
9.4 KiB
CMake
259 lines
9.4 KiB
CMake
#
|
|
# 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
|
|
# Path where the python generated code will be produced (empty for skipping
|
|
# python code generation)
|
|
PYTHON_PATH
|
|
# Type to use as the root of the schema
|
|
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)
|
|
set(EXTRA_TARGETS)
|
|
|
|
#
|
|
# Produce JSON schema, if requested
|
|
#
|
|
if(NOT "${JSONSCHEMA_PATH}" STREQUAL "")
|
|
tuple_tree_generator_generate_jsonschema(
|
|
"${SCHEMA_PATH}" "${NAMESPACE}" "${ROOT_TYPE}" "${STRING_TYPES}"
|
|
"${SEPARATE_STRING_TYPES}" "${JSONSCHEMA_PATH}")
|
|
list(APPEND EXTRA_TARGETS ${JSONSCHEMA_PATH})
|
|
endif()
|
|
|
|
#
|
|
# Produce Python code, if requested
|
|
#
|
|
if(NOT "${PYTHON_PATH}" STREQUAL "")
|
|
tuple_tree_generator_generate_python(
|
|
"${SCHEMA_PATH}" "${NAMESPACE}" "${ROOT_TYPE}" "${STRING_TYPES}"
|
|
"${SEPARATE_STRING_TYPES}" "${PYTHON_PATH}")
|
|
list(APPEND EXTRA_TARGETS ${PYTHON_PATH})
|
|
endif()
|
|
|
|
add_custom_target(
|
|
"${TARGET_NAME}" DEPENDS "${SCHEMA_PATH}" ${LOCAL_GENERATED_HEADERS}
|
|
${LOCAL_GENERATED_IMPLS} ${EXTRA_TARGETS})
|
|
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 <definition> 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(CPP_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(PYTHON_TEMPLATES "${TEMPLATES_DIR}/tuple_tree_gen.py.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-generate-python.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/generators/python.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}" ${CPP_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()
|
|
|
|
# Generates python files
|
|
function(
|
|
tuple_tree_generator_generate_python
|
|
# Path to the yaml definitions
|
|
YAML_DEFINITIONS
|
|
# Base namespace of the generated classes (e.g. model)
|
|
NAMESPACE
|
|
# Type to use as the root of the schema
|
|
ROOT_TYPE
|
|
# Types equivalent to plain strings
|
|
STRING_TYPES
|
|
# Types equivalent to plain strings that get a separate type definition
|
|
EXTERNAL_TYPES
|
|
# Output path
|
|
OUTPUT_PATH)
|
|
set(STRING_TYPE_ARGS)
|
|
foreach(ST ${STRING_TYPES})
|
|
list(APPEND STRING_TYPE_ARGS --string-type "${ST}")
|
|
endforeach()
|
|
|
|
set(EXTERNAL_TYPE_ARGS)
|
|
foreach(ET ${EXTERNAL_TYPES})
|
|
list(APPEND EXTERNAL_TYPE_ARGS --external-type "${ET}")
|
|
endforeach()
|
|
|
|
add_custom_command(
|
|
COMMAND
|
|
"${SCRIPTS_ROOT_DIR}/tuple-tree-generate-python.py" --namespace
|
|
"${NAMESPACE}" --root-type "${ROOT_TYPE}" --output "${OUTPUT_PATH}"
|
|
${STRING_TYPE_ARGS} ${EXTERNAL_TYPE_ARGS} "${YAML_DEFINITIONS}"
|
|
OUTPUT "${OUTPUT_PATH}"
|
|
DEPENDS "${YAML_DEFINITIONS}" ${PYTHON_TEMPLATES}
|
|
${TUPLE_TREE_GENERATOR_SOURCES})
|
|
endfunction()
|