3
votes

I am attempting to exclude certain files from my doxygen generated documentation. I am using version 1.8.14.

My files come in this naming convention:

/Path2/OtherFile.cs
/Path/DAL.Entity/Source.cs
/Path/DAL.Entity/SourceBase.generated.cs

I want to exclude all files that do NOT end in Base.generated.cs, and are located inside of /Path/.

Since it appears doxygen claims to use regex for the exclude_patterns variable, I eventually came up with this:

.*\\Path\\DAL\..{4,15}\\((?<!Base\.generated).)*

Needless to say, it did not work. Nor did multiple other variations. So far a simple wildcard * is the only regex character I have gotten to actually work.

doxygen uses QRegExp for a lot of things, so I assumed that was the library used for this variable as well, but even several variations of a pattern that that library claims to support did not work; granted apparently that library is full of bugs, but I would expect some things to work.

Does doxygen actually use a regex library for this variable? If so, which library is it? In either case, is there a method of achieving my goal?

1
I'm having a similar problem... There doesn't seem to be any relevant documentation about how regex would be used either... A bit ironic since it's a tool for creating documentation. - mattsson

1 Answers

0
votes

My conclusion is; No... Doxygen Doxyfile does not support real regex. Even though they claim that it do. It's just standard wildcards that work.

We ended up with a really awkward solution to work around this.

What we did is that we added a macro in our CMakeLists.txt that creates a string with everything we want to include in INPUT instead. Manually excluding the parts we don't want.

The sad part is that CMakes regex also is crippled. So we couldn't use advanced regex such as negative lookahead in LIST(FILTER EXLUDE) similar to LIST(FILTER children EXCLUDE REGEX "^((?!autogen/public).)*$")... So even this solution is not really what we wanted.

Our CMakeLists.txt ended up looking something like this

cmake_minimum_required(VERSION 3.9)

project(documentation_html LANGUAGES CXX)

find_package(Doxygen REQUIRED dot)

# Custom macros
## Macro for getting all relevant directories when creating HTML documentain.
## This was created cause the regex matching in Doxygen and CMake are lacking support for more
## advanced syntax.
MACRO(SUBDIRS result current_dir include_regex)
  FILE(GLOB_RECURSE children ${current_dir} ${current_dir}/*)
  LIST(FILTER children INCLUDE REGEX "${include_regex}")
  SET(dir_list "")
  FOREACH(child ${children})
    get_filename_component(path ${child} DIRECTORY)
    IF(${path} MATCHES ".*autogen/public.*$" OR NOT ${path} MATCHES ".*build.*$") # If we have the /source/build/autogen/public folder available we create the doxygen for those interfaces also.
        LIST(APPEND dir_list ${path})
    ENDIF()
  ENDFOREACH()
  LIST(REMOVE_DUPLICATES dir_list)
  string(REPLACE ";" " " dirs "${dir_list}")
  SET(${result} ${dirs})
ENDMACRO()

SUBDIRS(DOCSDIRS "${CMAKE_SOURCE_DIR}/docs" ".*.plantuml$|.*.puml$|.*.md$|.*.txt$|.*.sty$|.*.tex$|")
SUBDIRS(SOURCEDIRS "${CMAKE_SOURCE_DIR}/source" ".*.cpp$|.*.hpp$|.*.h$|.*.md$")

# Common config
set(DOXYGEN_CONFIG_PATH ${CMAKE_SOURCE_DIR}/docs/doxy_config)
set(DOXYGEN_IN ${DOXYGEN_CONFIG_PATH}/Doxyfile.in)
set(DOXYGEN_IMAGE_PATH ${CMAKE_SOURCE_DIR}/docs)
set(DOXYGEN_PLANTUML_INCLUDE_PATH ${CMAKE_SOURCE_DIR}/docs)
set(DOXYGEN_OUTPUT_DIRECTORY docs)

# HTML config
set(DOXYGEN_INPUT "${DOCSDIRS} ${SOURCEDIRS}")
set(DOXYGEN_EXCLUDE_PATTERNS "*/tests/* */.*/*")
set(DOXYGEN_FILE_PATTERNS "*.cpp *.hpp *.h *.md")
set(DOXYGEN_RECURSIVE NO)
set(DOXYGEN_GENERATE_LATEX NO)
set(DOXYGEN_GENERATE_HTML YES)
set(DOXYGEN_HTML_DYNAMIC_MENUS NO)
configure_file(${DOXYGEN_IN} ${CMAKE_BINARY_DIR}/DoxyHTML @ONLY)

add_custom_target(docs
    COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_BINARY_DIR}/DoxyHTML -d Markdown
    WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
    COMMENT "Generating documentation"
    VERBATIM)

and in the Doxyfile we added the environment variables for those fields

OUTPUT_DIRECTORY       = @DOXYGEN_OUTPUT_DIRECTORY@
INPUT                  = @DOXYGEN_INPUT@
FILE_PATTERNS          = @DOXYGEN_FILE_PATTERNS@
RECURSIVE              = @DOXYGEN_RECURSIVE@
EXCLUDE_PATTERNS       = @DOXYGEN_EXCLUDE_PATTERNS@
IMAGE_PATH             = @DOXYGEN_IMAGE_PATH@
GENERATE_HTML          = @DOXYGEN_GENERATE_HTML@
HTML_DYNAMIC_MENUS     = @DOXYGEN_HTML_DYNAMIC_MENUS@
GENERATE_LATEX         = @DOXYGEN_GENERATE_LATEX@
PLANTUML_INCLUDE_PATH  = @DOXYGEN_PLANTUML_INCLUDE_PATH@

After this we can run cd ./build && cmake ../ && make docs to create our html documentation and have it include the autogenerated interfaces in our source folder without including all the other directories in the build folder.

Quick description of what actually happens in the CMakeLists.txt

# Macro that gets all directories from current_dir recursively and returns the result to result as a space separated string 
MACRO(SUBDIRS result current_dir include_regex)

  # Gets all files recursively from current_dir
  FILE(GLOB_RECURSE children ${current_dir} ${current_dir}/*)
  
  # Filter files so we only keep the files that match the include_regex (can't be to advanced regex)
  LIST(FILTER children INCLUDE REGEX "${include_regex}")
  SET(dir_list "")
  
  # Let us act on all files... :)
  FOREACH(child ${children})

    # We're only interested in the path. So we get the path part from the file
    get_filename_component(path ${child} DIRECTORY)
    
    # Since CMakes regex also is crippled we can't do nice things such as LIST(FILTER children EXCLUDE REGEX "^((?!autogen/public).)*$") which would have been preferred (CMake regex does not understand negative lookahead/lookbehind)... So we ended up with this ugly thing instead... Adding all build/autogen/public paths and not adding any other paths inside build. I guess it would be possible to write this expression in regex without negative lookahead. But I'm both not really fluent in regex (who are... right?) and a bit lazy in this case. We just needed to get this one pointer task done... :P
    IF(${path} MATCHES ".*autogen/public.*$" OR NOT ${path} MATCHES ".*build.*$") 
        LIST(APPEND dir_list ${path})
    ENDIF()
  ENDFOREACH()

  # Remove all duplicates... Since we GLOBed all files there are a lot of them. So this is important or Doxygen INPUT will overflow... I know... I tested... 
  LIST(REMOVE_DUPLICATES dir_list)

  # Convert the dir_list to a space seperated string
  string(REPLACE ";" " " dirs "${dir_list}")

  # Return the result! Coffee and cinnamon buns for everyone!
  SET(${result} ${dirs})
ENDMACRO()

# Get all the pathes that we want to include in our documentation ... this is also where the build folders for the different applications are going to be... with our autogenerated interfaces which we want to keep.
SUBDIRS(SOURCEDIRS "${CMAKE_SOURCE_DIR}/source" ".*.cpp$|.*.hpp$|.*.h$|.*.md$")

# Add the dirs we want to the Doxygen INPUT
set(DOXYGEN_INPUT "${SOURCEDIRS}")

# Normal exlude patterns for stuff we don't want to add. This thing does not support regex... even though it should.
set(DOXYGEN_EXCLUDE_PATTERNS "*/tests/* */.*/*")

# Normal use of the file patterns that we want to keep in the documentation
set(DOXYGEN_FILE_PATTERNS "*.cpp *.hpp *.h *.md")

# IMPORTANT! Since we are creating all the INPUT paths our self we don't want Doxygen to do any recursion for us
set(DOXYGEN_RECURSIVE NO)

# Write the config
configure_file(${DOXYGEN_IN} ${CMAKE_BINARY_DIR}/DoxyHTML @ONLY)

# Create the target that will use that config to create the html documentation
add_custom_target(docs
    COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_BINARY_DIR}/DoxyHTML -d Markdown
    WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
    COMMENT "Generating documentation"
    VERBATIM)

I know this isn't the answer anyone who stumbles in on this question wants... unfortunately it seems to be the only reasonable solution... ... you all have my deepest condolences...