| include(GNUInstallDirs) |
| |
| # Create sphinx target |
| if (LLVM_ENABLE_SPHINX) |
| message(STATUS "Sphinx enabled.") |
| find_package(Sphinx REQUIRED) |
| |
| # Sphinx has internal parallelism, so give it a custom job pool. Sphinx tends |
| # not to use all available CPU, so this is not enabled by default. |
| set(LLVM_PARALLEL_SPHINX_JOBS "" CACHE STRING |
| "Define the maximum number of concurrent sphinx-build invocations (Ninja only).") |
| if (LLVM_PARALLEL_SPHINX_JOBS) |
| if (CMAKE_GENERATOR MATCHES "Ninja") |
| get_property(_sphinx_job_pools GLOBAL PROPERTY JOB_POOLS) |
| if (NOT "sphinx_job_pool=${LLVM_PARALLEL_SPHINX_JOBS}" IN_LIST _sphinx_job_pools) |
| set_property(GLOBAL APPEND PROPERTY JOB_POOLS sphinx_job_pool=${LLVM_PARALLEL_SPHINX_JOBS}) |
| endif() |
| set(sphinx_job_pool JOB_POOL sphinx_job_pool) |
| else() |
| message(WARNING "Job pooling is only available with Ninja generators.") |
| endif() |
| endif() |
| |
| if (LLVM_BUILD_DOCS AND NOT TARGET sphinx) |
| add_custom_target(sphinx ALL) |
| set_target_properties(sphinx PROPERTIES FOLDER "LLVM/Docs") |
| endif() |
| else() |
| message(STATUS "Sphinx disabled.") |
| endif() |
| |
| # Create a target that synchronizes checked-in Sphinx inputs into a build-tree |
| # source directory. The synchronization preserves mtimes for unchanged files, |
| # updates changed files, and removes stale .rst/.md files so incremental docs |
| # builds stay correct when documentation is renamed or deleted. The cheap scan |
| # target is always run to notice directory listing changes, but it writes the |
| # file list only when it changes; the sync command depends on that list and on a |
| # depfile of the listed source files. The scan also records the destination |
| # .rst/.md listing so destination-only stale files trigger cleanup. It also |
| # records source files that are missing from the destination so externally |
| # removed copies are restored. The actual copy step can still be skipped when |
| # both trees are unchanged. Use PRESERVE_DOCS for generated .rst/.md files that |
| # live in the destination directory but do not exist in source_dir. Use |
| # IGNORE_MISSING_FILES for files that are copied by the sync step but |
| # intentionally removed by a later build action. |
| function(add_sphinx_source_sync_target target source_dir destination_dir) |
| cmake_parse_arguments(ARG "" "" "PRESERVE_DOCS;IGNORE_MISSING_FILES" ${ARGN}) |
| |
| set(sync_dir "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${target}.sphinx-source-sync") |
| set(file_list "${sync_dir}/files.txt") |
| set(destination_doc_list "${sync_dir}/destination-docs.txt") |
| set(missing_file_list "${sync_dir}/missing-files.txt") |
| set(preserve_file "${sync_dir}/preserve.txt") |
| set(ignore_missing_file "${sync_dir}/ignore-missing.txt") |
| set(manifest_file "${sync_dir}/manifest.txt") |
| set(depfile "${sync_dir}/sync.d") |
| set(stamp_file "${sync_dir}/sync.stamp") |
| set(scan_target "${target}-scan") |
| set(scan_script "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/SphinxSourceScan.cmake") |
| set(sync_script "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/SphinxSourceSync.cmake") |
| set(utils_script "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/SphinxSourceUtils.cmake") |
| |
| file(MAKE_DIRECTORY "${sync_dir}") |
| string(REPLACE ";" "\n" preserve_docs "${ARG_PRESERVE_DOCS}") |
| if (preserve_docs) |
| string(APPEND preserve_docs "\n") |
| endif() |
| if (EXISTS "${preserve_file}") |
| file(READ "${preserve_file}" old_preserve_docs) |
| else() |
| set(old_preserve_docs) |
| endif() |
| if (NOT preserve_docs STREQUAL old_preserve_docs) |
| file(WRITE "${preserve_file}" "${preserve_docs}") |
| endif() |
| string(REPLACE ";" "\n" ignore_missing_files "${ARG_IGNORE_MISSING_FILES}") |
| if (ignore_missing_files) |
| string(APPEND ignore_missing_files "\n") |
| endif() |
| if (EXISTS "${ignore_missing_file}") |
| file(READ "${ignore_missing_file}" old_ignore_missing_files) |
| else() |
| set(old_ignore_missing_files) |
| endif() |
| if (NOT ignore_missing_files STREQUAL old_ignore_missing_files) |
| file(WRITE "${ignore_missing_file}" "${ignore_missing_files}") |
| endif() |
| |
| add_custom_target(${scan_target} |
| COMMAND "${CMAKE_COMMAND}" |
| "-DSOURCE_DIR=${source_dir}" |
| "-DDESTINATION_DIR=${destination_dir}" |
| "-DFILE_LIST=${file_list}" |
| "-DDESTINATION_DOC_LIST=${destination_doc_list}" |
| "-DMISSING_FILE_LIST=${missing_file_list}" |
| "-DIGNORE_MISSING_FILE=${ignore_missing_file}" |
| -P "${scan_script}" |
| BYPRODUCTS "${file_list}" "${destination_doc_list}" |
| "${missing_file_list}" |
| DEPENDS "${scan_script}" "${utils_script}" |
| COMMENT |
| "Scanning Sphinx sources in \"${source_dir}\"" |
| VERBATIM) |
| |
| add_custom_command(OUTPUT "${stamp_file}" |
| COMMAND "${CMAKE_COMMAND}" |
| "-DSOURCE_DIR=${source_dir}" |
| "-DDESTINATION_DIR=${destination_dir}" |
| "-DFILE_LIST=${file_list}" |
| "-DPRESERVE_FILE=${preserve_file}" |
| "-DMANIFEST_FILE=${manifest_file}" |
| "-DDEPFILE=${depfile}" |
| "-DSTAMP_FILE=${stamp_file}" |
| -P "${sync_script}" |
| DEPENDS "${file_list}" "${preserve_file}" |
| "${destination_doc_list}" "${missing_file_list}" |
| "${ignore_missing_file}" "${sync_script}" |
| "${utils_script}" |
| DEPFILE "${depfile}" |
| BYPRODUCTS "${manifest_file}" |
| COMMENT |
| "Copying Sphinx sources from \"${source_dir}\" to \"${destination_dir}\"" |
| VERBATIM) |
| |
| add_custom_target(${target} DEPENDS "${stamp_file}") |
| add_dependencies(${target} ${scan_target}) |
| endfunction() |
| |
| # Handy function for creating the different Sphinx targets. |
| # |
| # ``builder`` should be one of the supported builders used by |
| # the sphinx-build command. |
| # |
| # ``project`` should be the project name |
| # |
| # Named arguments: |
| # ``ENV_VARS`` should be a list of environment variables that should be set when |
| # running Sphinx. Each environment variable should be a string with |
| # the form KEY=VALUE. |
| function (add_sphinx_target builder project) |
| cmake_parse_arguments(ARG "" "SOURCE_DIR" "ENV_VARS" ${ARGN}) |
| set(SPHINX_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/${builder}") |
| set(SPHINX_DOC_TREE_DIR "${CMAKE_CURRENT_BINARY_DIR}/_doctrees-${project}-${builder}") |
| set(SPHINX_TARGET_NAME docs-${project}-${builder}) |
| |
| if (SPHINX_WARNINGS_AS_ERRORS) |
| set(SPHINX_WARNINGS_AS_ERRORS_FLAG "-W") |
| else() |
| set(SPHINX_WARNINGS_AS_ERRORS_FLAG "") |
| endif() |
| |
| if (NOT ARG_SOURCE_DIR) |
| set(ARG_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") |
| endif() |
| |
| # Give Sphinx some internal job parallelism, since it tends to be on the |
| # critical path at the end of the build. This can speed up doc builds by |
| # ~80%. Sphinx rarely consumes all cores available, so it's safe to |
| # overallocate a bit. |
| if (NOT DEFINED LLVM_SPHINX_THREADS) |
| cmake_host_system_information(RESULT number_of_logical_cores |
| QUERY NUMBER_OF_LOGICAL_CORES) |
| math(EXPR LLVM_SPHINX_THREADS |
| "(${number_of_logical_cores} + 1) / 2") |
| endif() |
| set(LLVM_SPHINX_THREADS "${LLVM_SPHINX_THREADS}" |
| CACHE STRING "Define the number of parallel jobs for each Sphinx build.") |
| if (LLVM_SPHINX_THREADS) |
| set(sphinx_jobs_flag -j ${LLVM_SPHINX_THREADS}) |
| endif() |
| |
| if ("${LLVM_VERSION_SUFFIX}" STREQUAL "git") |
| set(PreReleaseTag "-tPreRelease") |
| endif() |
| |
| add_custom_target(${SPHINX_TARGET_NAME} |
| COMMAND ${CMAKE_COMMAND} -E env ${ARG_ENV_VARS} |
| --modify "PYTHONPATH=path_list_append:${LLVM_MAIN_SRC_DIR}/../utils/docs" |
| ${SPHINX_EXECUTABLE} |
| -b ${builder} |
| -d "${SPHINX_DOC_TREE_DIR}" |
| ${sphinx_jobs_flag} |
| -q # Quiet: no output other than errors and warnings. |
| -t builder-${builder} # tag for builder |
| -D version=${LLVM_VERSION_MAJOR} |
| -D release=${PACKAGE_VERSION} |
| ${PreReleaseTag} |
| ${SPHINX_WARNINGS_AS_ERRORS_FLAG} # Treat warnings as errors if requested |
| "${ARG_SOURCE_DIR}" # Source |
| "${SPHINX_BUILD_DIR}" # Output |
| ${sphinx_job_pool} |
| COMMENT |
| "Generating ${builder} Sphinx documentation for ${project} into \"${SPHINX_BUILD_DIR}\"") |
| get_subproject_title(subproject_title) |
| set_target_properties(${SPHINX_TARGET_NAME} PROPERTIES FOLDER "${subproject_title}/Docs") |
| |
| # When "clean" target is run, remove the Sphinx build directory |
| set_property(DIRECTORY APPEND PROPERTY |
| ADDITIONAL_MAKE_CLEAN_FILES |
| "${SPHINX_BUILD_DIR}") |
| |
| # We need to remove ${SPHINX_DOC_TREE_DIR} when make clean is run |
| # but we should only add this path once |
| get_property(_CURRENT_MAKE_CLEAN_FILES |
| DIRECTORY PROPERTY ADDITIONAL_MAKE_CLEAN_FILES) |
| if (NOT "${SPHINX_DOC_TREE_DIR}" IN_LIST _CURRENT_MAKE_CLEAN_FILES) |
| set_property(DIRECTORY APPEND PROPERTY |
| ADDITIONAL_MAKE_CLEAN_FILES |
| "${SPHINX_DOC_TREE_DIR}") |
| endif() |
| |
| if (LLVM_BUILD_DOCS) |
| add_dependencies(sphinx ${SPHINX_TARGET_NAME}) |
| |
| # Handle installation |
| if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY) |
| if (builder STREQUAL man) |
| # FIXME: We might not ship all the tools that these man pages describe |
| install(DIRECTORY "${SPHINX_BUILD_DIR}/" # Slash indicates contents of |
| COMPONENT "${project}-sphinx-man" |
| DESTINATION "${CMAKE_INSTALL_MANDIR}/man1") |
| |
| if(NOT LLVM_ENABLE_IDE) |
| add_llvm_install_targets("install-${SPHINX_TARGET_NAME}" |
| DEPENDS ${SPHINX_TARGET_NAME} |
| COMPONENT "${project}-sphinx-man") |
| endif() |
| elseif (builder STREQUAL html) |
| string(TOUPPER "${project}" project_upper) |
| set(${project_upper}_INSTALL_SPHINX_HTML_DIR "${CMAKE_INSTALL_DOCDIR}/${project}/html" |
| CACHE STRING "HTML documentation install directory for ${project}") |
| |
| # '/.' indicates: copy the contents of the directory directly into |
| # the specified destination, without recreating the last component |
| # of ${SPHINX_BUILD_DIR} implicitly. |
| install(DIRECTORY "${SPHINX_BUILD_DIR}/." |
| COMPONENT "${project}-sphinx-html" |
| DESTINATION "${${project_upper}_INSTALL_SPHINX_HTML_DIR}") |
| |
| if(NOT LLVM_ENABLE_IDE) |
| add_llvm_install_targets("install-${SPHINX_TARGET_NAME}" |
| DEPENDS ${SPHINX_TARGET_NAME} |
| COMPONENT "${project}-sphinx-html") |
| endif() |
| else() |
| message(WARNING Installation of ${builder} not supported) |
| endif() |
| endif() |
| endif() |
| endfunction() |