mirror of
https://gitlab.kitware.com/cmake/cmake.git
synced 2026-09-25 04:09:36 +03:00
FindDoxygen: Create and clean recursive subdirectories for output formats
Teach `doxygen_add_docs()` to recursively create subdirectories for each output format (HTML, XML, ...) and add each subdirectory to the `clean` target. Previously, only the HTML output directory was added to the `clean` target. Fixes: #27970, #22570
This commit is contained in:
+65
-15
@@ -1172,6 +1172,51 @@ function(doxygen_list_to_quoted_strings LIST_VARIABLE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(_doxygen_collect_output_dirs outputDirs)
|
||||
# Collect user-provided output directories for known output formats
|
||||
set(_doxygen_output_formats DOCBOOK HTML LATEX MAN RTF SQLITE3 XML)
|
||||
set(_doxygen_output_dirs "")
|
||||
foreach(_format IN LISTS _doxygen_output_formats)
|
||||
set(_doxygen_generate_format "DOXYGEN_GENERATE_${_format}")
|
||||
if(DEFINED "${_doxygen_generate_format}" AND ${${_doxygen_generate_format}})
|
||||
set(_doxygen_format_output "DOXYGEN_${_format}_OUTPUT")
|
||||
if(DEFINED _doxygen_format_output)
|
||||
list(APPEND _doxygen_output_dirs "${${_doxygen_format_output}}" )
|
||||
endif()
|
||||
unset(_doxygen_format_output)
|
||||
endif()
|
||||
unset(_doxygen_generate_format)
|
||||
endforeach()
|
||||
set(${outputDirs} ${_doxygen_output_dirs} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(_doxygen_resolve_output_dirs parentDir childDirs outputDirs)
|
||||
# Resolve relative and absolute paths for output directories
|
||||
# parentDir: parent directory (e.g., DOXYGEN_OUTPUT_DIRECTORY -> docs)
|
||||
# childDirs: child directories list (e.g., "html;foo/xml")
|
||||
# outputDirs: output list of resolved directories
|
||||
# (e.g., "docs/html;docs/foo/xml")
|
||||
if(NOT DEFINED parentDir)
|
||||
message(FATAL_ERROR "Undefined parent output directory given")
|
||||
endif()
|
||||
if(NOT parentDir)
|
||||
message(FATAL_ERROR "Empty parent output directory given")
|
||||
endif()
|
||||
|
||||
set(_doxygen_output_dirs "")
|
||||
foreach(_dir IN LISTS childDirs)
|
||||
cmake_path(IS_RELATIVE _dir _is_rel)
|
||||
if(_is_rel)
|
||||
cmake_path(ABSOLUTE_PATH _dir
|
||||
BASE_DIRECTORY "${parentDir}"
|
||||
NORMALIZE
|
||||
OUTPUT_VARIABLE _doxygen_resolved_dir)
|
||||
list(APPEND _doxygen_output_dirs "${_doxygen_resolved_dir}")
|
||||
endif()
|
||||
endforeach()
|
||||
set(${outputDirs} "${_doxygen_output_dirs}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(doxygen_add_docs targetName)
|
||||
set(_options ALL USE_STAMP_FILE USES_TERMINAL)
|
||||
set(_one_value_args WORKING_DIRECTORY COMMENT CONFIG_FILE)
|
||||
@@ -1336,19 +1381,6 @@ doxygen_add_docs() for target ${targetName}")
|
||||
# already set and we have not provided above
|
||||
include("${CMAKE_BINARY_DIR}/CMakeDoxygenDefaults.cmake" OPTIONAL)
|
||||
|
||||
# Cleanup built HTMLs on "make clean"
|
||||
# TODO Any other dirs?
|
||||
if(DOXYGEN_GENERATE_HTML)
|
||||
if(IS_ABSOLUTE "${DOXYGEN_HTML_OUTPUT}")
|
||||
set(_args_clean_html_dir "${DOXYGEN_HTML_OUTPUT}")
|
||||
else()
|
||||
set(_args_clean_html_dir
|
||||
"${DOXYGEN_OUTPUT_DIRECTORY}/${DOXYGEN_HTML_OUTPUT}")
|
||||
endif()
|
||||
set_property(DIRECTORY APPEND PROPERTY
|
||||
ADDITIONAL_CLEAN_FILES "${_args_clean_html_dir}")
|
||||
endif()
|
||||
|
||||
# Build up a list of files we can identify from the inputs so we can list
|
||||
# them as DEPENDS and SOURCES in the custom command/target (the latter
|
||||
# makes them display in IDEs). This must be done before we transform the
|
||||
@@ -1470,6 +1502,19 @@ doxygen_add_docs() for target ${targetName}")
|
||||
# later in the custom target's commands.
|
||||
set( _original_doxygen_output_dir ${DOXYGEN_OUTPUT_DIRECTORY} )
|
||||
|
||||
# Collect the output directories for each DOXYGEN_${format}_OUTPUT
|
||||
# if the corresponding DOXYGEN_GENERATE_${format} is YES
|
||||
_doxygen_collect_output_dirs(_doxygen_output_dirs)
|
||||
|
||||
# Resolve the output directories as absolute paths
|
||||
# that can be given to make_directory() and appended to
|
||||
# the ADDITIONAL_CLEAN_FILES target property
|
||||
_doxygen_resolve_output_dirs("${_original_doxygen_output_dir}"
|
||||
"${_doxygen_output_dirs}"
|
||||
_doxygen_resolved_output_dirs)
|
||||
|
||||
unset(_doxygen_output_dirs)
|
||||
|
||||
foreach(_item IN LISTS _doxygen_quoted_options)
|
||||
doxygen_quote_value(DOXYGEN_${_item})
|
||||
endforeach()
|
||||
@@ -1503,7 +1548,7 @@ doxygen_add_docs() for target ${targetName}")
|
||||
add_custom_command(
|
||||
VERBATIM
|
||||
OUTPUT ${__stamp_file}
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${_original_doxygen_output_dir}
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${_doxygen_resolved_output_dirs}
|
||||
COMMAND "${DOXYGEN_EXECUTABLE}" "${_target_doxyfile}"
|
||||
COMMAND ${CMAKE_COMMAND} -E touch ${__stamp_file}
|
||||
WORKING_DIRECTORY "${_args_WORKING_DIRECTORY}"
|
||||
@@ -1522,7 +1567,7 @@ doxygen_add_docs() for target ${targetName}")
|
||||
add_custom_target( ${targetName}
|
||||
${_all}
|
||||
VERBATIM
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${_original_doxygen_output_dir}
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${_doxygen_resolved_output_dirs}
|
||||
COMMAND "${DOXYGEN_EXECUTABLE}" "${_target_doxyfile}"
|
||||
WORKING_DIRECTORY "${_args_WORKING_DIRECTORY}"
|
||||
DEPENDS "${_target_doxyfile}" ${_sources}
|
||||
@@ -1532,4 +1577,9 @@ doxygen_add_docs() for target ${targetName}")
|
||||
)
|
||||
endif()
|
||||
|
||||
# Add the DOXYGEN_${format}_OUTPUT directories as additional clean files
|
||||
# to the Doxygen target (rather than as a directory property)
|
||||
set_property(TARGET ${targetName} APPEND PROPERTY
|
||||
ADDITIONAL_CLEAN_FILES "${_doxygen_resolved_output_dirs}")
|
||||
|
||||
endfunction()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
add_test(NAME FindDoxygen.SimpleTest COMMAND
|
||||
${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
|
||||
${CMAKE_CTEST_COMMAND} -C $<CONFIG>
|
||||
--build-and-test
|
||||
"${CMake_SOURCE_DIR}/Tests/FindDoxygen/SimpleTest"
|
||||
"${CMake_BINARY_DIR}/Tests/FindDoxygen/SimpleTest"
|
||||
@@ -9,7 +9,7 @@ add_test(NAME FindDoxygen.SimpleTest COMMAND
|
||||
)
|
||||
|
||||
add_test(NAME FindDoxygen.QuotingTest COMMAND
|
||||
${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
|
||||
${CMAKE_CTEST_COMMAND} -C $<CONFIG>
|
||||
--build-and-test
|
||||
"${CMake_SOURCE_DIR}/Tests/FindDoxygen/QuotingTest"
|
||||
"${CMake_BINARY_DIR}/Tests/FindDoxygen/QuotingTest"
|
||||
@@ -19,17 +19,27 @@ add_test(NAME FindDoxygen.QuotingTest COMMAND
|
||||
)
|
||||
|
||||
add_test(NAME FindDoxygen.AllTarget COMMAND
|
||||
${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
|
||||
${CMAKE_CTEST_COMMAND} -C $<CONFIG>
|
||||
--build-and-test
|
||||
"${CMake_SOURCE_DIR}/Tests/FindDoxygen/AllTarget"
|
||||
"${CMake_BINARY_DIR}/Tests/FindDoxygen/AllTarget"
|
||||
${build_generator_args}
|
||||
--build-options ${build_options}
|
||||
--test-command ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
|
||||
--test-command ${CMAKE_CTEST_COMMAND} -C $<CONFIG>
|
||||
)
|
||||
|
||||
add_test(NAME FindDoxygen.CleanTarget COMMAND
|
||||
${CMAKE_CTEST_COMMAND} -C $<CONFIG>
|
||||
--build-and-test
|
||||
"${CMake_SOURCE_DIR}/Tests/FindDoxygen/CleanTarget"
|
||||
"${CMake_BINARY_DIR}/Tests/FindDoxygen/CleanTarget"
|
||||
${build_generator_args}
|
||||
--build-options ${build_options}
|
||||
--test-command ${CMAKE_CTEST_COMMAND} -C $<CONFIG>
|
||||
)
|
||||
|
||||
add_test(NAME FindDoxygen.StampFile COMMAND
|
||||
${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
|
||||
${CMAKE_CTEST_COMMAND} -C $<CONFIG>
|
||||
--build-and-test
|
||||
"${CMake_SOURCE_DIR}/Tests/FindDoxygen/StampFile"
|
||||
"${CMake_BINARY_DIR}/Tests/FindDoxygen/StampFile"
|
||||
@@ -40,7 +50,7 @@ add_test(NAME FindDoxygen.StampFile COMMAND
|
||||
|
||||
if(CMake_TEST_FindDoxygen_Dot)
|
||||
add_test(NAME FindDoxygen.DotComponentTest COMMAND
|
||||
${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
|
||||
${CMAKE_CTEST_COMMAND} -C $<CONFIG>
|
||||
--build-and-test
|
||||
"${CMake_SOURCE_DIR}/Tests/FindDoxygen/DotComponentTestTest"
|
||||
"${CMake_BINARY_DIR}/Tests/FindDoxygen/DotComponentTestTest"
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(TestFindDoxygen VERSION 1.0 LANGUAGES NONE)
|
||||
enable_testing()
|
||||
|
||||
#[[
|
||||
The ADDITIONAL_CLEAN_FILES property "only works for the Ninja
|
||||
and the Makefile generators. It is ignored by other generators."
|
||||
|
||||
Therefore, we must skip this test for other generators.
|
||||
|
||||
https://cmake.org/cmake/help/latest/prop_tgt/ADDITIONAL_CLEAN_FILES.html#prop_tgt:ADDITIONAL_CLEAN_FILES
|
||||
]]
|
||||
|
||||
set(DISABLE_THIS_TEST TRUE)
|
||||
|
||||
if(CMAKE_GENERATOR MATCHES "Ninja|Makefile")
|
||||
set(DISABLE_THIS_TEST FALSE)
|
||||
endif()
|
||||
|
||||
# Skip calling Doxygen if the generator does not support the 'clean' target
|
||||
if(NOT DISABLE_THIS_TEST)
|
||||
find_package(Doxygen REQUIRED)
|
||||
|
||||
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/main.cpp
|
||||
[[/**
|
||||
* \file
|
||||
* \brief One C++ file w/ sample Doxygen comment just to produce any docs...
|
||||
*/
|
||||
]])
|
||||
|
||||
set(OUTPUT_FORMATS DOCBOOK HTML LATEX MAN RTF SQLITE3 XML)
|
||||
|
||||
# test one target with direct parent/child directories
|
||||
set(DOXYGEN_OUTPUT_DIRECTORY "docs dir with spaces")
|
||||
set(DOXYGEN_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/${DOXYGEN_OUTPUT_DIRECTORY}")
|
||||
|
||||
file(REMOVE_RECURSE "${DOXYGEN_OUTPUT_DIR}")
|
||||
|
||||
foreach(format IN LISTS OUTPUT_FORMATS)
|
||||
set(DOXYGEN_GENERATE_${format} YES)
|
||||
set(DOXYGEN_${format}_OUTPUT "my ${format} output")
|
||||
cmake_path(ABSOLUTE_PATH DOXYGEN_${format}_OUTPUT
|
||||
BASE_DIRECTORY "${DOXYGEN_OUTPUT_DIR}"
|
||||
NORMALIZE
|
||||
OUTPUT_VARIABLE EXPECTED_${format}_DIR)
|
||||
|
||||
list(APPEND DIRS_TO_CLEAN "${EXPECTED_${format}_DIR}")
|
||||
endforeach()
|
||||
|
||||
doxygen_add_docs(docsClean ALL ${CMAKE_CURRENT_BINARY_DIR}/main.cpp)
|
||||
|
||||
# test another target with relative paths
|
||||
set(DOXYGEN_OUTPUT_DIRECTORY "docs dir/with/subdirs")
|
||||
set(DOXYGEN_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/${DOXYGEN_OUTPUT_DIRECTORY}")
|
||||
|
||||
file(REMOVE_RECURSE "${DOXYGEN_OUTPUT_DIR}")
|
||||
|
||||
SET(DOXYGEN_DOCBOOK_OUTPUT "docbook")
|
||||
SET(DOXYGEN_HTML_OUTPUT "make/this/dir/html")
|
||||
SET(DOXYGEN_LATEX_OUTPUT "../latex")
|
||||
SET(DOXYGEN_MAN_OUTPUT "../r/t/f/m")
|
||||
SET(DOXYGEN_RTF_OUTPUT "../../r t f")
|
||||
SET(DOXYGEN_SQLITE3_OUTPUT "../../../sqlite3")
|
||||
SET(DOXYGEN_XML_OUTPUT "./../xml")
|
||||
|
||||
foreach(format IN LISTS OUTPUT_FORMATS)
|
||||
set(_doxygen_format_output "DOXYGEN_${format}_OUTPUT")
|
||||
cmake_path(ABSOLUTE_PATH DOXYGEN_${format}_OUTPUT
|
||||
BASE_DIRECTORY "${DOXYGEN_OUTPUT_DIR}"
|
||||
NORMALIZE
|
||||
OUTPUT_VARIABLE EXPECTED_${format}_DIR)
|
||||
list(APPEND DIRS_TO_CLEAN "${EXPECTED_${format}_DIR}")
|
||||
endforeach()
|
||||
|
||||
doxygen_add_docs(docsCleanRelative ALL ${CMAKE_CURRENT_BINARY_DIR}/main.cpp)
|
||||
endif()
|
||||
|
||||
add_test(NAME testDocsClean
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-D BUILD_DIR=${CMAKE_CURRENT_BINARY_DIR}
|
||||
-D "OUTPUT_DIRS=${DIRS_TO_CLEAN}"
|
||||
-P "${CMAKE_CURRENT_SOURCE_DIR}/TestClean.cmake"
|
||||
)
|
||||
|
||||
set_tests_properties(testDocsClean PROPERTIES DISABLED ${DISABLE_THIS_TEST})
|
||||
@@ -0,0 +1,48 @@
|
||||
|
||||
message(STATUS "Checking whether Doxygen wrote "
|
||||
"output to expected directories...")
|
||||
|
||||
foreach(DIR IN LISTS OUTPUT_DIRS)
|
||||
file(GLOB DIR_CONTENTS "${DIR}/*")
|
||||
|
||||
list(LENGTH DIR_CONTENTS DIR_SIZE)
|
||||
|
||||
if(DIR_SIZE EQUAL 0)
|
||||
message(FATAL_ERROR "Target directory \"${DIR}\" is empty. "
|
||||
"Doxygen failed to generate output.")
|
||||
else()
|
||||
message(STATUS "Target directory \"${DIR}\" is not empty. "
|
||||
"Doxygen generated output.")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
message(STATUS "Building 'clean' target...")
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} --build ${BUILD_DIR} --target clean
|
||||
RESULT_VARIABLE CLEAN_RESULT
|
||||
ERROR_QUIET
|
||||
)
|
||||
|
||||
if(NOT CLEAN_RESULT EQUAL 0)
|
||||
message(FATAL_ERROR "The 'clean' target failed to build")
|
||||
endif()
|
||||
|
||||
message(STATUS "Successfully built 'clean' target")
|
||||
|
||||
message(STATUS "Checking whether the 'clean' target "
|
||||
"successfully cleaned the Doxygen output...")
|
||||
|
||||
foreach(DIR IN LISTS OUTPUT_DIRS)
|
||||
file(GLOB DIR_CONTENTS "${DIR}/*")
|
||||
|
||||
list(LENGTH DIR_CONTENTS DIR_SIZE)
|
||||
|
||||
if(DIR_SIZE EQUAL 0)
|
||||
message(STATUS "Target directory \"${DIR}\" is empty. "
|
||||
"The 'clean' target succeeded.")
|
||||
else()
|
||||
message(FATAL_ERROR "Target directory \"${DIR}\" is not empty. "
|
||||
"The 'clean' target failed.")
|
||||
endif()
|
||||
endforeach()
|
||||
Reference in New Issue
Block a user