svenevs / exhale

Automatic C++ library api documentation generation: breathe doxygen in and exhale it out.
BSD 3-Clause "New" or "Revised" License
219 stars 51 forks source link

Fortran support may be broken #214

Open principis opened 9 months ago

principis commented 9 months ago

On Fedora 39 the CPPFortranMixed.test_hierarchies test fails:

FAILED testing/tests/cpp_fortran_mixed.py::CPPFortranMixed::test_hierarchies - RuntimeError: Matching child for [function] 'conversions::degrees_to_radians_s' with signature 'real(c_float) function conversions::degrees_to_radians_s(degrees_s)' not found!

Complete test results: test_output.txt

Version info: Doxygen version: 1.9.7 Breathe version: 4.35.0 Sphinx version: 6.2.1 Python version: 3.12.1

svenevs commented 9 months ago

Thanks for reporting @principis!

It seems like either the gfortran version or doxygen@1.9.7 are at play here. The underlying problem is the testing framework is dumb / very picky, and wanted to find real(c_float) function conversions::degrees_to_radians_s(real(c_float), intent(in)) (note: the difference is the parameters degrees_s)

I will need to fiddle with things, if this is for a packaging build it might be appropriate to disable the test. I will see what I can dig up, I've had this change behavior in the past too and IIRC it was because doxygen changed how the xml worked.

principis commented 9 months ago

Thanks for your swift response! I'm packaging exhale for Fedora, I'll disable the test for now. :slightly_smiling_face:

svenevs commented 9 months ago

I'll disable the test for now.

TL;DR: I'd say that's probably the right call, not much has changed code-wise for a couple of years, the latest release was really just to fix packaging mistakes that were starting to prevent people from installing the project on RTD using PyPI.


image

Hmmmmm... so after some digging around, it seems like at some point the fortran support broke. Possibly for quite some time. The next thing to check for me / anybody interested would be looking at different combinations of sphinx and breathe versions to see if there is a known point where the function signatures exhale was generating actually worked.

# See tox.ini hack, the variable needs the leadding '=='
# change X.Y.Z / A.B.C to try
SPHINX_VERSION='==X.Y.Z' BREATHE_VERSION='==A.B.C' tox -e py -- -k cpp_fortran_mixed --pdb -s

In this edge case, tests don't actually necessarily fail, it will just render the warning. To keep all of the builds around (warning: -k cpp_fortran_mixed is useful here, actually builds and renders the html for all projects if you run just tox -e py...):

diff --git a/testing/base.py b/testing/base.py
index 3360c81..96a8219 100644
--- a/testing/base.py
+++ b/testing/base.py
@@ -122,7 +122,7 @@ class ExhaleTestCaseMetaclass(type):
                 yield  # the test runs
                 # @no_cleanup sets self.testroot to [self.testroot] as a flag that
                 # cleanup should not transpire
-                if isinstance(self.testroot, six.string_types):
+                if False and isinstance(self.testroot, six.string_types):
                     # This cleanup happens between each test case, do not delete docs/
                     # until all tests for this class are done!
                     containmentFolder = self.getAbsContainmentFolder()
@@ -207,7 +207,7 @@ class ExhaleTestCaseMetaclass(type):
                 # perform cleanup by deleting the docs dir
                 # @no_cleanup sets self.testroot to [self.testroot] as a flag that
                 # cleanup should not transpire
-                if isinstance(self.testroot, six.string_types) and os.path.isdir(self.testroot):
+                if False and isinstance(self.testroot, six.string_types) and os.path.isdir(self.testroot):
                     shutil.rmtree(self.testroot)

                 self.testroot = None
@@ -225,6 +225,9 @@ class ExhaleTestCaseMetaclass(type):
                     self.checkAllFilesGenerated()
                     self.checkAllFilesIncluded()

+                    print("{{{{{ imma building }}}}}")
+                    self.app.build()
+
             attrs["test_common"] = test_common

             # Import the default hierarchy dictionaries from the testing/projects folder

And the place where you can fiddle with the parsing of things is here

diff --git a/exhale/graph.py b/exhale/graph.py
index c0d8e86..99d57ad 100644
--- a/exhale/graph.py
+++ b/exhale/graph.py
@@ -2196,7 +2196,16 @@ class ExhaleRoot(object):
                 # 2. The function parameter list.
                 parameters = []
                 for param in memberdef.find_all("param", recursive=False):
-                    parameters.append(param.type.text)
+                    # if param.type.text is not None and 'real(c_float), intent(in)' == param.type.text:
+                    if func_refid == "namespaceconversions_1af3f7e870092b4986419a4c8c56aaff63":
+                        # import pdb
+                        # pdb.set_trace()
+                        # (pdb) p param <<< that'll show you the function parameters
+                        #         these are the beautiful soup (xml) nodes getting parsed
+                        #         as we're building the {hacky} exhale representation
+                        parameters.append(param.defname.text)
+                    else:
+                        parameters.append(param.type.text)
                 func.parameters = utils.sanitize_all(parameters)
                 # 3. The template parameter list.
                 templateparamlist = memberdef.templateparamlist

Noting that modifying this method directly is also an easy way to hack

https://github.com/svenevs/exhale/blob/c99592533143b5144a69bf685c85cdb63e534b0b/exhale/graph.py#L279

There's other known problems even with C++ functions (overloads specifically, some work, some don't) :no_mouth: While I'd love to be able to fix these things, they're usually in a corner case of "no known solution without making significant changes here and in breathe"...


When running tests against later versions of sphinx and breathe all kinds of other things broke, so it's not clear if this will get solved anytime soon :disappointed: