# # 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 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()