| # Copyright 2020 The Dawn & Tint Authors |
| # |
| # Redistribution and use in source and binary forms, with or without |
| # modification, are permitted provided that the following conditions are met: |
| # |
| # 1. Redistributions of source code must retain the above copyright notice, this |
| # list of conditions and the following disclaimer. |
| # |
| # 2. Redistributions in binary form must reproduce the above copyright notice, |
| # this list of conditions and the following disclaimer in the documentation |
| # and/or other materials provided with the distribution. |
| # |
| # 3. Neither the name of the copyright holder nor the names of its |
| # contributors may be used to endorse or promote products derived from |
| # this software without specific prior written permission. |
| # |
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE |
| # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| # Check for Jinja2 |
| if (NOT DAWN_JINJA2_DIR) |
| message(STATUS "Dawn: Using system jinja2") |
| execute_process( |
| COMMAND ${Python3_EXECUTABLE} -c "import jinja2" |
| RESULT_VARIABLE RET |
| ) |
| if (NOT RET EQUAL 0) |
| message(FATAL_ERROR "Dawn: Missing dependencies for code generation, please ensure you have python-jinja2 installed.") |
| endif() |
| else() |
| message(STATUS "Dawn: using jinja2 at ${DAWN_JINJA2_DIR}") |
| message(STATUS "Dawn: using markupsafe at ${DAWN_MARKUPSAFE_DIR}") |
| endif() |
| |
| # Function to invoke a generator_lib.py generator. |
| # - SCRIPT is the name of the script to call |
| # - OUTPUT_HEADERS will be modified to contain the list of header files (*.h, *.hpp) generated by this generator |
| # - OUTPUT_SOURCES will be modified to contain the list of all other files generated by this generator |
| # - ARGS are the extra arguments to pass to the script in addition to the base generator_lib.py arguments |
| # - PRINT_NAME is the name to use when outputting status or errors |
| function(DawnGenerator) |
| cmake_parse_arguments(PARSE_ARGV 0 arg |
| "" |
| "SCRIPT;OUTPUT_HEADERS;OUTPUT_SOURCES;OUTPUT_JSONS;OUTPUT_JS;PRINT_NAME" |
| "EXTRA_PARAMETERS" |
| ) |
| message(STATUS "Dawn: Configuring DawnGenerator for ${arg_PRINT_NAME}.") |
| |
| if (arg_UNPARSED_ARGUMENTS) |
| message(FATAL_ERROR |
| "Unparsed arguments for DawnGenerator: " |
| "${arg_UNPARSED_ARGUMENTS}") |
| endif () |
| |
| # Build the set of args common to all invocation of that generator. |
| set(BASE_ARGS |
| ${Python3_EXECUTABLE} |
| ${arg_SCRIPT} |
| --template-dir |
| "${DAWN_TEMPLATE_DIR}" |
| --root-dir |
| "${Dawn_SOURCE_DIR}" |
| --output-dir |
| "${DAWN_BUILD_GEN_DIR}" |
| ${arg_EXTRA_PARAMETERS} |
| ) |
| if (DAWN_JINJA2_DIR) |
| list(APPEND BASE_ARGS --jinja2-path ${DAWN_JINJA2_DIR}) |
| endif() |
| if (DAWN_MARKUPSAFE_DIR) |
| list(APPEND BASE_ARGS --markupsafe-path ${DAWN_MARKUPSAFE_DIR}) |
| endif() |
| |
| # Call the generator to get the list of its dependencies. |
| execute_process( |
| COMMAND ${BASE_ARGS} --print-cmake-dependencies |
| OUTPUT_VARIABLE DEPENDENCIES |
| RESULT_VARIABLE RET |
| ) |
| if (NOT RET EQUAL 0) |
| message(FATAL_ERROR "Dawn: Failed to get the dependencies for ${arg_PRINT_NAME}. Base args are '${BASE_ARGS}'.") |
| endif() |
| |
| # Ask CMake to re-run if any of the dependencies changed as it might modify the build graph. |
| set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${DEPENDENCIES}) |
| |
| # Call the generator to get the list of its outputs. |
| execute_process( |
| COMMAND ${BASE_ARGS} --print-cmake-outputs |
| OUTPUT_VARIABLE OUTPUTS |
| RESULT_VARIABLE RET |
| ) |
| if (NOT RET EQUAL 0) |
| message(FATAL_ERROR "Dawn: Failed to get the outputs for ${arg_PRINT_NAME}. Base args are '${BASE_ARGS}'.") |
| endif() |
| |
| # Add the custom command that calls the generator. |
| add_custom_command( |
| COMMAND ${BASE_ARGS} |
| DEPENDS ${DEPENDENCIES} |
| OUTPUT ${OUTPUTS} |
| COMMENT "Dawn: Generating files for ${arg_PRINT_NAME}." |
| ) |
| |
| # Populate the list of outputs. |
| set(headers) |
| set(sources) |
| set(jsons) |
| set(js) |
| foreach (filename IN LISTS OUTPUTS) |
| get_filename_component(extension "${filename}" EXT) |
| if (extension MATCHES "(h|hpp)") |
| list(APPEND headers "${filename}") |
| elseif (extension MATCHES "(json)") |
| list(APPEND jsons "${filename}") |
| elseif (extension MATCHES "(js)") |
| list(APPEND js "${filename}") |
| else () |
| list(APPEND sources "${filename}") |
| endif () |
| endforeach () |
| |
| if (sources AND NOT arg_OUTPUT_SOURCES) |
| message(FATAL_ERROR |
| "This function generated source files, although an output variable was not defined!" |
| "Please provide a variable name for OUTPUT_SOURCES.") |
| endif () |
| |
| if (headers AND NOT arg_OUTPUT_HEADERS) |
| message(FATAL_ERROR |
| "This function generated header files, although an output variable was not defined!" |
| "Please provide a variable name for OUTPUT_HEADERS.") |
| endif () |
| |
| if (jsons AND NOT arg_OUTPUT_JSONS) |
| message(FATAL_ERROR |
| "This function generated JSON files, although an output variable was not defined!" |
| "Please provide a variable name for OUTPUT_JSONS.") |
| endif () |
| |
| if (js AND NOT arg_OUTPUT_JS) |
| message(FATAL_ERROR |
| "This function generated JS files, although an output variable was not defined!" |
| "Please provide a variable name for OUTPUT_JS.") |
| endif () |
| |
| set(${arg_OUTPUT_SOURCES} ${sources} PARENT_SCOPE) |
| set(${arg_OUTPUT_HEADERS} ${headers} PARENT_SCOPE) |
| set(${arg_OUTPUT_JSONS} ${jsons} PARENT_SCOPE) |
| set(${arg_OUTPUT_JS} ${js} PARENT_SCOPE) |
| |
| # Prior to CMake 3.20 the GENERATED property is local to a directory which means that putting |
| # generated headers in INTERFACE properties causes dependent targets to complain that they |
| # cannot find the file. (because they don't see it as generated and want to check is is |
| # actually on the filesystem). |
| # Work around this by generating the files once if they aren't present at configuration time. |
| set(needToGenerate OFF) |
| foreach(path ${OUTPUTS}) |
| if (NOT EXISTS ${path}) |
| set(needToGenerate ON) |
| endif() |
| endforeach() |
| |
| if (${needToGenerate}) |
| message(STATUS "Dawn: Generating initial versions of files for ${arg_PRINT_NAME}.") |
| execute_process(COMMAND ${BASE_ARGS} RESULT_VARIABLE RET) |
| if (NOT RET EQUAL 0) |
| message(FATAL_ERROR "Dawn: Failed to generate the initial version of files for ${arg_PRINT_NAME}. Base args are '${BASE_ARGS}'.") |
| endif() |
| endif() |
| endfunction() |
| |
| # Helper function to call dawn_generator.py: |
| # - TARGET is the generator target to build |
| # - OUTPUT_HEADERS, OUTPUT_SOURCES, and PRINT_NAME are like for DawnGenerator |
| function(DawnJSONGenerator) |
| cmake_parse_arguments(PARSE_ARGV 0 arg |
| "" |
| "TARGET;OUTPUT_SOURCES;OUTPUT_HEADERS;OUTPUT_JSONS;OUTPUT_JS;PRINT_NAME" |
| "" |
| ) |
| DawnGenerator( |
| SCRIPT "${Dawn_SOURCE_DIR}/generator/dawn_json_generator.py" |
| PRINT_NAME "${arg_PRINT_NAME}" |
| OUTPUT_HEADERS HEADERS |
| OUTPUT_SOURCES SOURCES |
| OUTPUT_JSONS JSONS |
| OUTPUT_JS JS |
| EXTRA_PARAMETERS |
| --dawn-json |
| "${Dawn_SOURCE_DIR}/src/dawn/dawn.json" |
| --wire-json |
| "${Dawn_SOURCE_DIR}/src/dawn/dawn_wire.json" |
| --kotlin-json |
| "${Dawn_SOURCE_DIR}/src/dawn/dawn_kotlin.json" |
| --targets |
| ${arg_TARGET} |
| ${arg_UNPARSED_ARGUMENTS} |
| ) |
| |
| if (SOURCES AND NOT arg_OUTPUT_SOURCES) |
| message(FATAL_ERROR |
| "This function generated source files, although an output variable was not defined! " |
| "Please provide a variable name for OUTPUT_SOURCES.") |
| elseif (arg_OUTPUT_SOURCES AND NOT SOURCES) |
| message(WARNING |
| "This function did not generate source files. The OUTPUT_SOURCES argument is unnecessary.") |
| endif () |
| |
| if (HEADERS AND NOT arg_OUTPUT_HEADERS) |
| message(FATAL_ERROR |
| "This function generated header files, although an output variable was not defined! " |
| "Please provide a variable name for OUTPUT_HEADERS.") |
| elseif (arg_OUTPUT_HEADERS AND NOT HEADERS) |
| message(WARNING |
| "This function did not generate header files. The OUTPUT_HEADERS argument is unnecessary.") |
| endif () |
| |
| if (JSONS AND NOT arg_OUTPUT_JSONS) |
| message(FATAL_ERROR |
| "This function generated JSON files, although an output variable was not defined! " |
| "Please provide a variable name for OUTPUT_JSONS.") |
| elseif (arg_OUTPUT_JSONS AND NOT JSONS) |
| message(WARNING |
| "This function did not generate JSON files. The OUTPUT_JSONS argument is unnecessary.") |
| endif () |
| |
| if (JS AND NOT arg_OUTPUT_JS) |
| message(FATAL_ERROR |
| "This function generated JS files, although an output variable was not defined! " |
| "Please provide a variable name for OUTPUT_JS.") |
| elseif (arg_OUTPUT_JS AND NOT JS) |
| message(WARNING |
| "This function did not generate JS files. The OUTPUT_JS argument is unnecessary.") |
| endif () |
| |
| # Forward the result up one more scope |
| set(${arg_OUTPUT_SOURCES} ${SOURCES} PARENT_SCOPE) |
| set(${arg_OUTPUT_HEADERS} ${HEADERS} PARENT_SCOPE) |
| set(${arg_OUTPUT_JSONS} ${JSONS} PARENT_SCOPE) |
| set(${arg_OUTPUT_JS} ${JS} PARENT_SCOPE) |
| endfunction() |