breathe-doc / breathe

ReStructuredText and Sphinx bridge to Doxygen
https://breathe-doc.org
Other
735 stars 197 forks source link

Documentation fails to build with Doxygen 1.9.7 #935

Open befeleme opened 11 months ago

befeleme commented 11 months ago

This was originally reported in https://github.com/breathe-doc/breathe/issues/933, but then closed, so let me open another issue on this. With doxygen 1.9.7 Breathe documentation build fails with

> /usr/lib/python3.12/site-packages/sphinx/util/logging.py(427)filter()
-> raise exc
(Pdb) 
make[1]: Leaving directory '/builddir/build/BUILD/breathe-4.35.0/documentation'
RPM build errors:
fatal: not a git repository (or any of the parent directories): .git
Exception occurred while building, starting debugger:
Traceback (most recent call last):
  File "/usr/lib/python3.12/site-packages/sphinx/cmd/build.py", line 284, in build_main
    app.build(args.force_all, args.filenames)
  File "/usr/lib/python3.12/site-packages/sphinx/application.py", line 347, in build
    self.builder.build_update()
  File "/usr/lib/python3.12/site-packages/sphinx/builders/__init__.py", line 311, in build_update
    self.build(to_build,
  File "/usr/lib/python3.12/site-packages/sphinx/builders/__init__.py", line 326, in build
    with logging.pending_warnings():
  File "/usr/lib64/python3.12/contextlib.py", line 144, in __exit__
    next(self.gen)
  File "/usr/lib/python3.12/site-packages/sphinx/util/logging.py", line 222, in pending_warnings
    memhandler.flushTo(logger)
  File "/usr/lib/python3.12/site-packages/sphinx/util/logging.py", line 187, in flushTo
    logger.handle(record)
  File "/usr/lib64/python3.12/logging/__init__.py", line 1700, in handle
    self.callHandlers(record)
  File "/usr/lib64/python3.12/logging/__init__.py", line 1762, in callHandlers
    hdlr.handle(record)
  File "/usr/lib64/python3.12/logging/__init__.py", line 1022, in handle
    rv = self.filter(record)
         ^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.12/logging/__init__.py", line 858, in filter
    result = f.filter(record)
             ^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/sphinx/util/logging.py", line 427, in filter
    raise exc
sphinx.errors.SphinxWarning: /builddir/build/BUILD/breathe-4.35.0/documentation/source/specific.rst:195:Invalid C++ declaration: Expected identifier in nested name. [error at 0]

  ^

specific.rst contains C++ Anonymous Entities around the line where error was detected: https://github.com/breathe-doc/breathe/blob/main/documentation/source/specific.rst?plain=1#L190

There are some doxygen fixes in 1.9.7 that caught my eye, looking at the changelog namely: https://github.com/doxygen/doxygen/commit/a18e4c76ed6415893800c7d77a2f798614fb638b https://github.com/doxygen/doxygen/issues/9668

For the sake of completeness, there is the output of the build with breathe_debug_trace_directives = True for reading specific.rst (I can't make much of it):

reading sources... [ 80%] specific
Running directive: .. cpp:type:: template<typename T, typename U, int N> IsFurry = std::is_furry< T, U, N >
Running directive: .. cpp:type:: template<typename T> IsFuzzy = std::is_fuzzy< T >
Running directive: .. cpp:class::  TestClass
  Running directive: .. cpp:type:: void * MemberTypedef 
  Running directive: .. cpp:type:: void(* MemberTypedefFuncPointer )(int, double)
Running directive: .. cpp:class::  TypeDefTest
Running directive: .. cpp:type:: TypeDefNamespace
  Running directive: .. cpp:type:: char * AnotherTypedef 
Running directive: .. cpp:type:: TypeDefTest(* TypeDefTestFuncPtr )(void)
Running directive: .. cpp:type:: void *(* voidFuncPtr )(float, int)
Running directive: .. cpp:type:: void * voidPointer 
Running directive: .. cpp:type:: float * floatPointer 
Running directive: .. cpp:type:: float floatingPointNumber 
Running directive: .. cpp:type:: int TestTypedef 
Running directive: .. cpp:type::  TypeAlias = int
Running directive: .. cpp:function::  virtual void TestNamespaceClasses::NamespacedClassTest::function () const =0
Running directive: .. cpp:function::  inline void TestNamespaceClasses::ClassTest::function ()
Running directive: .. cpp:function::  inline void TestNamespaceClasses::ClassTest::anotherFunction ()
Running directive: .. cpp:function::  void ClassTest::function (int myParameter)
Running directive: .. cpp:function::  void ClassTest::anotherFunction ()
Running directive: .. cpp:function:: template<typename T> void f0 ()
Running directive: .. cpp:function:: template<> void f0< std::string > ()
Running directive: .. cpp:function:: template<typename T> void NS1::f1 ()
Running directive: .. cpp:function:: template<> void NS1::f1< std::string > ()
Running directive: .. cpp:function:: template<typename T> void NS1::NS2::f2 ()
Running directive: .. cpp:function:: template<> void NS1::NS2::f2< std::string > ()
Running directive: .. c:function::  void cache_tree_free (struct cache_tree **)
Running directive: .. c:struct::  cache_tree
Running directive: .. cpp:class::  Out
  Running directive: .. cpp:function::  inline  Out ()
  Running directive: .. cpp:function::  inline  ~Out ()
Running directive: .. cpp:function::  void f (int, int)
Running directive: .. cpp:function::  void f (double, double)
Running directive: .. cpp:function::  void test::g (int, int)
Running directive: .. cpp:function::  void test::g (double, double)
Running directive: .. cpp:function::  void h (std::string, MyType)
Running directive: .. cpp:function::  void h (std::string, MyOtherType o)
Running directive: .. cpp:function::  void h (std::string, const int myint)
Running directive: .. cpp:function:: template<typename T, typename U> void h (std::string, const T m, const U n)
Running directive: .. cpp:class::  Vector
Running directive: .. cpp:function::  Vector center () const
Running directive: .. cpp:class::  ImageClass
Running directive: .. c:function::  int foo (int a[5])
Running directive: .. c:function::  int bar (int n, int a[])
Running directive: .. c:struct::  ACStruct
  Running directive: .. c:var::  int i  
  Running directive: .. c:struct::  ANestedStruct
    Running directive: .. c:var::  int i  
Running directive: .. c:union:: ACUnion
  Running directive: .. c:var::  int i  
Running directive: .. c:enum:: GSM_BackupFormat
  Running directive: .. c:enumerator:: GSM_Backup_Auto
  Running directive: .. c:enumerator:: GSM_Backup_AutoUnicode
  Running directive: .. c:enumerator:: GSM_Backup_LMB
  Running directive: .. c:enumerator:: GSM_Backup_VCalendar
  Running directive: .. c:enumerator:: GSM_Backup_VCard
  Running directive: .. c:enumerator:: GSM_Backup_LDIF
  Running directive: .. c:enumerator:: GSM_Backup_ICS
  Running directive: .. c:enumerator:: GSM_Backup_Gammu
  Running directive: .. c:enumerator:: GSM_Backup_GammuUCS2
  Running directive: .. c:enumerator:: GSM_Backup_VNote
Running directive: .. c:type:: int(* cTypeDefTestFuncPtr )(void)
Running directive: .. c:type:: void *(* cVoidFuncPtr )(float, int)
Running directive: .. c:type:: void * cVoidPointer 
Running directive: .. c:type:: float * cFloatPointer 
Running directive: .. c:type:: float cFloatingPointNumber 
Running directive: .. c:type:: int cTestTypedef 
Running directive: .. c:macro:: A_C_MACRO
Running directive: .. c:macro:: ANOTHER_C_MACRO(name)
Running directive: .. cpp:macro:: USE_STUFF
Running directive: .. cpp:macro:: MAX_LENGTH
Running directive: .. cpp:macro:: MAXIMUM(A, B)
Running directive: .. cpp:macro:: SWAP(A, B)
Running directive: .. cpp:function:: template<TestClass::Enum E> void TestTemplateFunction ()
Running directive: .. cpp:class::  InterfaceClass
Running directive: .. cpp:struct::  ClassWithAnonEntities
  Running directive: .. cpp:enum:: 
    Running directive: .. cpp:enumerator:: Enumerator
  Running directive: .. cpp:var::  int structMember  
  Running directive: .. cpp:var::  struct ClassWithAnonEntities   
  Running directive: .. cpp:var::  int unionMember  
  Running directive: .. cpp:var::  union ClassWithAnonEntities   
Running directive: .. cpp:union:: Union
  Running directive: .. cpp:var::  int i  
Running directive: .. cpp:struct::  Class
  Running directive: .. cpp:union:: Union
    Running directive: .. cpp:var::  int i  
Running directive: .. cpp:enum:: Unscoped
  Running directive: .. cpp:enumerator:: UnscopedEnumerator
Running directive: .. cpp:enum-class:: ScopedStruct : int
  Running directive: .. cpp:enumerator:: Enumerator
Running directive: .. cpp:enum-class:: ScopedClass : int
  Running directive: .. cpp:enumerator:: Enumerator
Running directive: .. cpp:enum-class:: ScopedClassNoUnderlying
  Running directive: .. cpp:enumerator:: Enumerator
Running directive: .. cpp:struct::  Foo
Running directive: .. cpp:struct::  Class
  Running directive: .. cpp:var::  void(* f_issue_489 )(struct Foo *foo, int value) 
  Running directive: .. cpp:function::  virtual void f1 () const volatile &=0
  Running directive: .. cpp:function::  virtual void f2 () const volatile &&=0
  Running directive: .. cpp:function::  int f_issue_338 () noexcept
  Running directive: .. cpp:function::  static void f3 ()
Running directive: .. cpp:type:: TestNamespaceFunction
  Running directive: .. cpp:function::  void namespaceFunc ()
Running directive: .. cpp:struct::  A
Running directive: .. cpp:struct::  B
Running directive: .. cpp:struct::  C
Running directive: .. cpp:class::  Base
Running directive: .. cpp:class::  A : public Base
Running directive: .. cpp:class::  B : public Base
Running directive: .. cpp:function::  auto f_issue_441 () -> Thingy *
Running directive: .. cpp:class::  Thingy
Running directive: .. cpp:var::  static constexpr int v1   = 42
Running directive: .. cpp:var::  static constexpr int v2   = 42
Running directive: .. cpp:function::  static constexpr auto f1 (std::false_type)
Running directive: .. cpp:function::  static constexpr auto f2 (std::false_type)
Running directive: .. cpp:function::  void fNoexcept () noexcept
Running directive: .. cpp:function::  void fFinal () final
Running directive: .. cpp:function::  void fOverride () override
Running directive: .. cpp:function::  void fAttr ()
Running directive: .. cpp:function::  void fFInit ()=default
Running directive: .. cpp:function::  auto fTrailing () -> int
Running directive: .. cpp:function::  void fInit (int arg=42)
Running directive: .. cpp:function::  void fPlain (int arg)
Running directive: .. cpp:function::  void fPtr (int *arg)
Running directive: .. cpp:function::  void fLRef (int &arg)
Running directive: .. cpp:function::  void fRRef (int &&arg)
Running directive: .. cpp:function:: template<typename ... T> void fParamPack (T ...arg)
Running directive: .. cpp:function::  void fMemPtr (int A::*arg)
Running directive: .. cpp:function::  void fParen (void(*arg)())
Running directive: .. cpp:function::  void fParenPlain (void(*arg)(int argInner))
Running directive: .. cpp:function::  int unimplemented (void)
Running directive: .. cpp:function::  void buggy_function (int param)
Running directive: .. cpp:function::  void old_function (void)
Running directive: .. cpp:function::  void sample_xrefitem_function (void)
Running directive: .. cpp:function:: template<typename T1, typename T2> void f (int a, float b, std::string c)
dcermak commented 9 months ago

This appears to be caused by some sphinx bug. The failure is reproducible with doxygen 1.9.7 and Sphinx 7.0.1 but not with Sphinx 7.1.2 (implemented via https://src.fedoraproject.org/rpms/python-sphinx/pull-request/56) nor with Sphinx 7.2.5 (latest upstream).

roehling commented 9 months ago

I get the same error with Sphinx 7.2.5 and Doxygen 1.9.8

roehling commented 8 months ago

I have looked further into this issue and compared the output of doxygen cpp_anon.cfg (from examples/specific) between Doxygen 1.9.4 and Doxygen 1.9.8.

As it turns out, the older Doxygen used to auto-generate names such as @0, @1, @2,… for anonymous entities, and the newer Doxygen leaves the name tag empty in its XML output, which (I assume) results in broken doxygen*:: directives.