From f7f02c791bcbee44597f1fe24570ebdf352ec648 Mon Sep 17 00:00:00 2001 From: Alexandru Croitor Date: Fri, 6 Sep 2024 13:54:24 +0200 Subject: [PATCH] CMake: Add a script to build qdoc and friends from qttools/dev/HEAD A new QtBuildStaticDocToolsScript.cmake script is added which: - clones qt5.git - initializes required submodules for building doc tools - checks out qttools/dev/HEAD - syncs the dependency SHA1s as specified in qttools' dependencies.yaml file - configures qt5 as a top-level static build - builds qdoc and other tools required for documentation generation - installs them into a custom prefix under a subdirectory of the repo's root build dir. The script is intended to be used as part of qtbase's CI build instructions. See the follow-up coin change for reasons on why we want to do that and how to configure optional ref pinning, instead of using dev branch always. Pick-to: 6.8 Task-number: QTBUG-128730 Change-Id: I836fc2f1b47c07171d2a2bd54a85bc2145212e46 Reviewed-by: Joerg Bornemann --- cmake/QtBuildHelpers.cmake | 1 + cmake/QtBuildStaticDocToolsScript.cmake | 252 ++++++++++++++++++++++++ 2 files changed, 253 insertions(+) create mode 100644 cmake/QtBuildStaticDocToolsScript.cmake diff --git a/cmake/QtBuildHelpers.cmake b/cmake/QtBuildHelpers.cmake index 738debeb27c..e7cd9885adc 100644 --- a/cmake/QtBuildHelpers.cmake +++ b/cmake/QtBuildHelpers.cmake @@ -229,6 +229,7 @@ function(qt_internal_get_qt_build_private_files_to_install out_var) QtBaseTopLevelHelpers.cmake QtBuild.cmake QtBuildHelpers.cmake + QtBuildStaticDocToolsScript.cmake QtCMakePackageVersionFile.cmake.in QtCompilerFlags.cmake QtCompilerOptimization.cmake diff --git a/cmake/QtBuildStaticDocToolsScript.cmake b/cmake/QtBuildStaticDocToolsScript.cmake new file mode 100644 index 00000000000..9703790e6a3 --- /dev/null +++ b/cmake/QtBuildStaticDocToolsScript.cmake @@ -0,0 +1,252 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.16) + +# Query the var name from the CMake cache or the environment or use a default value. +function(qt_internal_get_cmake_or_env_or_default out_var var_name_to_check default_value) + if(${var_name_to_check}) + set(value "${var_name_to_check}") + elseif(DEFINED ENV{${var_name_to_check}}) + set(value "$ENV{${var_name_to_check}}") + else() + set(value "${default_value}") + endif() + set(${out_var} "${value}" PARENT_SCOPE) +endfunction() + +# Prepares paths for the cloning of the sources, the build and the installation. +function(qt_internal_prepare_build_paths) + set(current_dir "${CMAKE_CURRENT_BINARY_DIR}") + + qt_internal_get_cmake_or_env_or_default(working_dir + QT_CI_DOC_TOOLS_WORKING_DIR "${current_dir}/qdoc_build") + + qt_internal_get_cmake_or_env_or_default(qt_src_dir + QT_CI_DOC_TOOLS_SRC_DIR "${working_dir}/qt5") + + qt_internal_get_cmake_or_env_or_default(qt_build_dir + QT_CI_DOC_TOOLS_BUILD__DIR "${working_dir}/build") + + qt_internal_get_cmake_or_env_or_default(qt_installed_dir + QT_CI_DOC_TOOLS_INSTALL_DIR "${working_dir}/install") + + set(QT_DOC_TOOLS_WORKING_DIR "${working_dir}" PARENT_SCOPE) + set(QT_DOC_TOOLS_SRC_DIR "${qt_src_dir}" PARENT_SCOPE) + set(QT_DOC_TOOLS_BUILD_DIR "${qt_build_dir}" PARENT_SCOPE) + set(QT_DOC_TOOLS_INSTALL_DIR "${qt_installed_dir}" PARENT_SCOPE) +endfunction() + +# Gets the remote git base URL for qt repositories. +function(qt_internal_get_repo_base_url out_var) + # This Coin CI git daemon IP is set in all CI jobs. + # Prefer using it when available, to avoid general network issues. + # Sample value: QT_COIN_GIT_DAEMON=10.215.0.212:9418 + qt_internal_get_cmake_or_env_or_default(coin_git_ip_port QT_COIN_GIT_DAEMON "") + + # Allow opting out of using the coin git daemon. + qt_internal_get_cmake_or_env_or_default(skip_coin_git QT_DOC_TOOLS_SKIP_COIN_GIT_DAEMON FALSE) + + # Allow override of the default remote. + qt_internal_get_cmake_or_env_or_default(git_remote QT_CI_DOC_TOOLS_GIT_REMOTE "") + + if(coin_git_ip_port AND NOT skip_coin_git) + set(value "git://${coin_git_ip_port}/qt-project") + elseif(git_remote) + set(value "${git_remote}") + else() + set(value "https://code.qt.io") + endif() + + set(${out_var} "${value}" PARENT_SCOPE) +endfunction() + +# Clones qt5.git into the specified src directory. +function(qt_internal_clone_qt5) + file(MAKE_DIRECTORY "${QT_DOC_TOOLS_SRC_DIR}") + + qt_internal_get_repo_base_url(remote_url) + execute_process( + COMMAND git clone "${remote_url}/qt/qt5.git" "${QT_DOC_TOOLS_SRC_DIR}" + COMMAND_ECHO STDOUT + WORKING_DIRECTORY "${QT_DOC_TOOLS_WORKING_DIR}" + RESULT_VARIABLE result + ERROR_VARIABLE proc_err + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(result) + message(WARNING "Cloning qt5.git sources failed. Output: ${result}") + endif() + + # Allow pinning the qt5.git sha1 or any other git ref, based on a cmake var or env var. + qt_internal_get_cmake_or_env_or_default(super_repo_ref + QT_CI_DOC_TOOLS_TOP_LEVEL_PIN_GIT_REF "dev") + + # Allow using the branch that the Coin CI sets, as an opt-in. + qt_internal_get_cmake_or_env_or_default(use_ci_branch + QT_CI_DOC_TOOLS_USE_CI_TOP_LEVEL_BRANCH "OFF") + qt_internal_get_cmake_or_env_or_default(ci_branch + TESTED_MODULE_BRANCH_COIN "") + + if(use_ci_branch AND ci_branch) + set(super_repo_ref "${ci_branch}") + endif() + + execute_process( + COMMAND git checkout "${super_repo_ref}" + COMMAND_ECHO STDOUT + WORKING_DIRECTORY "${QT_DOC_TOOLS_SRC_DIR}" + RESULT_VARIABLE result + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(result) + message(FATAL_ERROR + "Checking out qt5.git '${super_repo_ref}' ref failed. Output: ${result}") + endif() +endfunction() + +# Checks out qttools to the dev branch (or other specified ref) and syncs its submodule +# dependencies according to qttools dependencies.yaml file. +function(qt_internal_sync_to_qttools) + execute_process( + COMMAND + git submodule update + --init + --recursive + --progress + --depth 1 + qttools + + # TODO: Remove these once the sync-to script is taught to automatically clone these. + qtbase + qtshadertools + qtdeclarative + qtsvg + qtimageformats + qtactiveqt + qtlanguageserver + + COMMAND_ECHO STDOUT + WORKING_DIRECTORY "${QT_DOC_TOOLS_SRC_DIR}" + RESULT_VARIABLE result + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(result) + message(FATAL_ERROR "Cloning qttools submodule failed. Output: ${result}") + endif() + + # Allow pinning the qttools sha1 or any other git ref, based on a cmake var or env var. + qt_internal_get_cmake_or_env_or_default(qttools_sync_to_ref QT_CI_DOC_TOOLS_PIN_GIT_REF "dev") + + execute_process( + COMMAND + ${CMAKE_COMMAND} + -DSYNC_TO_MODULE=qttools + "-DSYNC_TO_BRANCH=${qttools_sync_to_ref}" + -DSHOW_PROGRESS=1 + -DVERBOSE=1 + -P cmake/QtSynchronizeRepo.cmake + --log-level=DEBUG + COMMAND_ECHO STDOUT + WORKING_DIRECTORY "${QT_DOC_TOOLS_SRC_DIR}" + RESULT_VARIABLE result + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(result) + message(FATAL_ERROR "Syncing qttools submodule dependencies failed: Output: ${result}") + endif() +endfunction() + +# Configures a top-level static qt build for the checked out qt5.git sources. +function(qt_internal_configure_qt) + file(MAKE_DIRECTORY "${QT_DOC_TOOLS_BUILD_DIR}") + file(MAKE_DIRECTORY "${QT_DOC_TOOLS_INSTALL_DIR}") + + # Get the common CI args, to set the sccache args, etc. + qt_internal_get_cmake_or_env_or_default(ci_common_cmake_args COMMON_CMAKE_ARGS "") + if(ci_common_cmake_args) + separate_arguments(ci_common_cmake_args NATIVE_COMMAND ${ci_common_cmake_args}) + endif() + + execute_process( + COMMAND + "${QT_DOC_TOOLS_SRC_DIR}/configure" + -release + -static + -prefix "${QT_DOC_TOOLS_INSTALL_DIR}" + # Skip optional dependencies we don't need to build. + -skip qtactiveqt,qtimageformats,qtlanguageserver,qtsvg + -- + -DWARNINGS_ARE_ERRORS=OFF + --log-level STATUS + --fresh + -GNinja + ${ci_common_cmake_args} + + COMMAND_ECHO STDOUT + WORKING_DIRECTORY "${QT_DOC_TOOLS_BUILD_DIR}" + RESULT_VARIABLE result + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(result) + message(FATAL_ERROR "Configuring top-level qt5.git build failed. Output: ${result}") + endif() +endfunction() + +# Builds the main doc tools in a configured qt5.git build. +function(qt_internal_build_tools) + execute_process( + COMMAND + cmake + --build . + --verbose + --parallel + --target + qdoc + qtattributionsscanner + qdbusxml2cpp + qdbuscpp2xml + qvkgen + COMMAND_ECHO STDOUT + WORKING_DIRECTORY "${QT_DOC_TOOLS_BUILD_DIR}" + RESULT_VARIABLE result + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(result) + message(FATAL_ERROR "Failed to build doc tools. Output: ${result}") + endif() +endfunction() + +# Installs the built doc tools. +function(qt_internal_install_tools) + execute_process( + COMMAND + cmake + --build . + --target + # TODO: Replace with ninja install_doc_tools_stripped once it lands. + qttools/src/qdoc/qdoc/install/strip + qttools/src/qtattributionsscanner/install/strip + qtbase/src/tools/qdbusxml2cpp/install/strip + qtbase/src/tools/qdbuscpp2xml/install/strip + qtbase/src/tools/qvkgen/install/strip + COMMAND_ECHO STDOUT + WORKING_DIRECTORY "${QT_DOC_TOOLS_BUILD_DIR}" + RESULT_VARIABLE result + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(result) + message(FATAL_ERROR "Failed to install doc tools. Output: ${result}") + endif() +endfunction() + +function(qt_internal_run_script) + qt_internal_prepare_build_paths() + qt_internal_clone_qt5() + qt_internal_sync_to_qttools() + qt_internal_configure_qt() + qt_internal_build_tools() + qt_internal_install_tools() +endfunction() + +qt_internal_run_script()