How to get cpp Doxygen module list in Sphinx? - python-sphinx

Using the defgroup Doxygen keyword in a Doxygen comment block, it is possible to define a "module". Then, using the ingroup Doxygen keyword in any other Doxygen comment block, even in other source files, it is possible to add cpp classes and enums to the defined module.
Then, running doxygen doxyfile, the documentation is generated, and it has a nice modules tab, where all the defined modules are listed, one per line.
I have a C++ project and I would like to also have this module list that Doxygen generates in Sphinx. I activated the autodoc, breathe and exhale sphinx extensions.
Running make html runs Doxygen and generates the sphinx documentation, but the list of modules generated by Doxygen is missing in sphinx. In conf.py I have
# Setup the `exhale` extension
exhale_args = {
# These arguments are required.
"containmentFolder": "./api",
"rootFileName": "library_root.rst",
"rootFileTitle": "Library API",
the api/library_root.html generated by sphinx/exhale has a nice expandable list of all namespaces, each containing all its classes and enums. It also has another nice expandable list of all directories in the project, each with all its files.
So my question is this - how can I get sphinx to also generate the list of modules which doxygen has no trouble generating? It doesn't matter if in the library_root.html or another HTML file.
I found that if I use the name Doxygen keyword, like this: name module1 in a Doxygen comment (with leading backslash or at symbol) breathe seems to recognize it, whereas it seems to not recognize and ignore defgroup/ingroup.
So, in an rst file, I can then manually say
.. doxygengroup:: module1
:outline:
.. doxygengroup:: module2
:outline:
.. doxygengroup:: module3
:outline:
to get the list of modules, (they are labeled group not module) but I want this to be autogenerated, like in Doxygen, where I just define the modules in Doxygen comments in the source, and then they all appear in the modules tab in the Doxygen output without having to do anything else. I would prefer that they are labeled module, but I can live with group as long as it works.
I also tried adding in index.rst
.. automodule:: My Project
:members:
before .. toctree:: but that has no effect, it probably only works in Python.
I use Linux and have Sphinx 1.6.7 on one machine and 1.8.5 on another, Python 2.7

Related

CMake: Use variables from existing Makefile of 3rdparty library

I'm facing the following scenario:
Existing project which uses cmake
External 3rdparty library which only comes with Makefiles
The difference of my situation compared to existing questions is that I don't need to have cmake to build the 3rdparty library via the Makefile. Instead, the 3rdparty library provides a library.mk Makefile which has variables like LIB_SRCS and LIB_INCS containing all source and header files required to compile the library.
My idea is to include the library.mk into the project's CMakeLists.txt and then adding those $(LIB_SRCS) and $(LIB_INCS) to target_sources().
My question: How can I include library.mk into the existing CMakeLists.txt to get access to the $(LIB_SRCS) and $(LIB_INCS) for adding them to target_sources()? I'm looking for something like this:
include("/path/to/library.mk") # Somehow include the library's `library.mk` to expose variables to cmake.
add_executable(my_app)
target_sources(
my_app
PRIVATE
main.c
$(LIB_SRCS) # Add 3rd-party library source files
$(LIB_INCS) # Add 3rd-party library header files
)
Using include() does not work as the library.mk is not a CMake list/file.
Since you can't be sure that your target system will even have Make on it, the only option is to parse the strings out of the .mk file, which might be easy if the variables are set directly as a list of filenames, or really hard if they are set with expansions of other variables, conditionals, etc. Do this with FILE(STRINGS) cmake doc.
Your plan will only work if the Makefiles are trivial, and do not set important compiler flags, define preprocessor variables, modify the include directory, etc. And if they really are trivial, skip the parsing, and just do something like aux_source_directory(<dir> <variable>) to collect all the sources from the library directory.
You might also consider building and maintaining a CMakeLists.txt for this third-party library. Do the conversion once, and store it as a branch off of the "vendor" main branch in your version control system. Whenever you update, update the vendor branch from upstream, and merge or rebase your modifications. Or just store it in your existing project, referring to the source directory of the 3rd-party stuff.

genindex and modindex footer links don't work in readthedocs.io

I have a Python project using Sphinx for docs. I am building the docs remotely on readthedocs.io service.
I used sphinx-quickstart and it generated an index.rst file with these links in the footer:
Indices and tables
~~~~~~~~~~~~~~~~~~
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
When I push changes to readthedocs.io and build the docs, my build succeeds. Docs that I manually linked via toctree directive all work fine.
The search link works fine.
But the genindex link goes to an empty page, titled "Index"
And the modindex page links to py-modindex.html, which is a 404.
Following this guide: https://samnicholls.net/2016/06/15/how-to-sphinx-readthedocs I had run sphinx-apidoc -o api-docs/ ../myproject to generate the autodoc .rst files.
I linked the resulting api-docs/modules.rst in the toctree section at the top of my index.rst... That link works and if I click through the api-docs have been generated correctly.
Also generated by sphinx-autodoc were files for each package in my project, they contain directives like:
myproject.whatever module
-------------------------
.. automodule:: myproject.whatever
:members:
:undoc-members:
:show-inheritance:
If I browse directly to these pages they have content, but they don't appear in the index (only the tocs they are manually linked in).
I also have some manually authored pages, again linked via toc.
My docs/conf.py looks like:
import os
import sys
sys.path.insert(0, os.path.abspath("../"))
extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.viewcode",
"sphinx.ext.napoleon",
"sphinx_autodoc_typehints",
]
templates_path = ["_templates"]
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
html_theme = "alabaster"
html_static_path = ["_static"]
I believe the fact that html generated from the autodoc .rst stub files are filled with modules and classes extracted from the .py files in my project indicates that the sys path fix and autodoc are basically working.
So my question is:
How to make :ref:`genindex` have some content?
How to fix :ref:`modindex` points to py-modindex.html which does not exist?
genindex and modindex are automatically managed by Sphinx. Two cases should be considered:
Any declaration in a .rst file will be inserted in those indexes. For example, if you declare a function from the Python domain:
Your rst file
-------------
.. py:function:: name(parameters)
It will be inserted in the indexes even if it doesn't have a corresponding function in any .py file.
Using autodoc directives, the same applies with a few more rules. The autodoc extension will substitute domain declarations (like above) depending if the object has a docstring and if you are using the :members: and or :undoc-members: options. So you have to verify you are using the correct option and directive for your case.
Your rst file
-------------
.. autoclass:: Your_Module.Your_Class
:members:
The above example will be substituted by a :py:class:: domain declaration if the corresponding class has a docstring, if not you need to add the :undoc-members: option.
The symptoms you are describing of having empty indexes happens when you haven't declared anything in the .rst files. With the nuance that the autodoc directives may or may not do those declarations for you depending if the objects have docstrings and you used the right options in the directives.
EDIT: You should also run make clean before your builds (e.g.make html) because inconsistencies between builds can break the index.
As I eventually worked out in the comments, thanks to help from #bad_coder, my problem was specific to building the docs in readthedocs.io
Building the docs locally worked fine.
The reason came down to use of sphinx.ext.autodoc, perhaps in conjunction with sphinx_autodoc_typehints, which seems to need to import my actual python code. Checking the logs of my apparently successful readthedocs build showed actually there were warnings like:
WARNING: autodoc: failed to import module 'whatever' from module 'myproject'; the following exception was raised:
No module named 'somelib'
i.e the docs had only partially built, it had skipped the parts it couldn't do.
The build worked locally because I was already in a virtualenv with all my project's dependencies installed.
(IMHO this seems like a bad design of the sphinx.ext.autodoc and/or sphinx_autodoc_typehints ...good static-analysis tools exist for Python which can build an AST or CST and extract structure and docstrings without importing any code.)
Well anyway, this meant that I needed to tell readthedocs.io how to install all my project deps. This is slightly complicated by the fact I'm using Poetry, which is not explicitly supported. This means I don't have a requirements.txt file to point to (and I don't want to manually create one that is a duplicate of everything in my pyproject.toml).
Fortunately the pyproject.toml file is understandable by pip, so we're able to use the pip install method described here for readthedocs.io to install both my project deps, plus extra deps that are only needed for building docs: https://github.com/readthedocs/readthedocs.org/issues/4912#issuecomment-664002569
To summarise:
Deleted my docs/requirements.txt
Added:
[tool.poetry.dependencies]
...
sphinx = {version = "^3.1.1", optional = true}
sphinx-autodoc-typehints ={version = "^1.11.1", optional = true}
and:
[tool.poetry.extras]
docs = [
"sphinx",
"sphinx-autodoc-typehints"
]
to my pyproject.toml
Updated my .readthedocs.yml to:
version: 2
sphinx:
configuration: docs/conf.py
python:
version: 3.8
install:
- method: pip
path: .
extra_requirements:
- docs
Pushed these changes to readthedocs.io ...voilĂ , now it works.

RTD compiles all my docs including foreign docs from git submodules

I'm experimenting with Sphinx and ReadTheDocs (RTD) to compile my documentation on every GitHub push. Unfortunately, RTD found multiple doc/docs folders containing a conf.py file.
My repository uses git sub-modules to embed third party libraries. Some of them are also documented using Sphinx. I assume the biggest (long lasting documentation build) wins and overwrites all static HTML pages in the final RTD view.
How can I exclude or tell RTD to ignore the folders of these sub-modules:
lib/cocotb
lib/osvvm
lib/vunit
docs/source/_themes/sphinx_rtd_theme
My documentation is located here:
docs/source/conf.py
docs/source/index.rst
As far as I have found, RTD does support *.yml files, but there is no entry to define the documentation root folder.
Any ideas to solve my problem?
Inside conf.py, there is a list that looks like this
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = []
You can put the files you want to ignore inside it like
exclude_patterns = ["lib/cocotb", "lib/osvvm", "lib/vunit", "docs/_themes/sphinx_rtd_theme"]
Please note that here the pattern is relative to the source directory, you can put / at the beginning of each file pattern above to make this more clear.
The main documentation folder and its conf.py can be configured in the Advanced Settings tab in the per project settings.
Example value: documentation/conf.py

Sphinx, using automodule to find submodules

When using sphinx's automodule (https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html),
I simply write in a .rst file:
.. automodule:: my_module
:members:
It documents my_module fine, but it doesn't find the inner modules like my_module.inner_module0 and my_module.inner_module1. Is there something that needs to be specified in the __init__.py file besides the __all__ variable?
Also, I'm aware of sphinx-apidoc. But that command documents far too much (exposes every function/folder including undocumented ones).
It sounds like you want to give the automodule directive a package name and have it recurse into the directory and document each Python module. That isn't supported yet. You will ned to specify the full dotted module name for each module you want to document.
For example, given the following directory structure (from the Python documentation). You cannot specify .. automodule:: sound.formats and have it document all the modules in the directory. You will have to specify a automodule command for each module: .. automodule:: sound.formats.waveread, .. automodule:: sound.formats.wavewrite, etc.
sound/ Top-level package
__init__.py Initialize the sound package
formats/ Subpackage for file format conversions
__init__.py
wavread.py
wavwrite.py
aiffread.py
aiffwrite.py
auread.py
auwrite.py
...
effects/ Subpackage for sound effects
__init__.py
echo.py
surround.py
reverse.py
...
It seems to me that using the :imported-members: option (non-direct link, do use search) should now be possible, if __init__.py imports those submodules.
However, I'm personally not able to make this work (yet).
EDIT: Possibly a known bug.

Directory layout for pure Ruby project

I'm starting to learn ruby. I'm also a day-to-day C++ dev.
For C++ projects I usually go with following dir structure
/
-/bin <- built binaries
-/build <- build time temporary object (eg. .obj, cmake intermediates)
-/doc <- manuals and/or Doxygen docs
-/src
--/module-1
--/module-2
-- non module specific sources, like main.cpp
- IDE project files (.sln), etc.
What dir layout for Ruby (non-Rails, non-Merb) would you suggest to keep it clean, simple and maintainable?
As of 2011, it is common to use jeweler instead of newgem as the latter is effectively abandoned.
Bundler includes the necessary infrastructure to generate a gem:
$ bundle gem --coc --mit --test=minitest --exe spider
Creating gem 'spider'...
MIT License enabled in config
Code of conduct enabled in config
create spider/Gemfile
create spider/lib/spider.rb
create spider/lib/spider/version.rb
create spider/spider.gemspec
create spider/Rakefile
create spider/README.md
create spider/bin/console
create spider/bin/setup
create spider/.gitignore
create spider/.travis.yml
create spider/test/test_helper.rb
create spider/test/spider_test.rb
create spider/LICENSE.txt
create spider/CODE_OF_CONDUCT.md
create spider/exe/spider
Initializing git repo in /Users/francois/Projects/spider
Gem 'spider' was successfully created. For more information on making a RubyGem visit https://bundler.io/guides/creating_gem.html
Then, in lib/, you create modules as needed:
lib/
spider/
base.rb
crawler/
base.rb
spider.rb
require "spider/base"
require "crawler/base"
Read the manual page for bundle gem for details on the --coc, --exe and --mit options.
The core structure of a standard Ruby project is basically:
lib/
foo.rb
foo/
share/
foo/
test/
helper.rb
test_foo.rb
HISTORY.md (or CHANGELOG.md)
LICENSE.txt
README.md
foo.gemspec
The share/ is rare and is sometimes called data/ instead. It is for general purpose non-ruby files. Most projects don't need it, but even when they do many times everything is just kept in lib/, though that is probably not best practice.
The test/ directory might be called spec/ if BDD is being used instead of TDD, though you might also see features/ if Cucumber is used, or demo/ if QED is used.
These days foo.gemspec can just be .gemspec --especially if it is not manually maintained.
If your project has command line executables, then add:
bin/
foo
man/
foo.1
foo.1.md or foo.1.ronn
In addition, most Ruby project's have:
Gemfile
Rakefile
The Gemfile is for using Bundler, and the Rakefile is for Rake build tool. But there are other options if you would like to use different tools.
A few other not-so-uncommon files:
VERSION
MANIFEST
The VERSION file just contains the current version number. And the MANIFEST (or Manifest.txt) contains a list of files to be included in the project's package file(s) (e.g. gem package).
What else you might see, but usage is sporadic:
config/
doc/ (or docs/)
script/
log/
pkg/
task/ (or tasks/)
vendor/
web/ (or site/)
Where config/ contains various configuration files; doc/ contains either generated documentation, e.g. RDoc, or sometimes manually maintained documentation; script/ contains shell scripts for use by the project; log/ contains generated project logs, e.g. test coverage reports; pkg/ holds generated package files, e.g. foo-1.0.0.gem; task/ could hold various task files such as foo.rake or foo.watchr; vendor/ contains copies of the other projects, e.g. git submodules; and finally web/ contains the project's website files.
Then some tool specific files that are also relatively common:
.document
.gitignore
.yardopts
.travis.yml
They are fairly self-explanatory.
Finally, I will add that I personally add a .index file and a var/ directory to build that file (search for "Rubyworks Indexer" for more about that) and often have a work directory, something like:
work/
NOTES.md
consider/
reference/
sandbox/
Just sort of a scrapyard for development purposes.
#Dentharg: your "include one to include all sub-parts" is a common pattern. Like anything, it has its advantages (easy to get the things you want) and its disadvantages (the many includes can pollute namespaces and you have no control over them). Your pattern looks like this:
- src/
some_ruby_file.rb:
require 'spider'
Spider.do_something
+ doc/
- lib/
- spider/
spider.rb:
$: << File.expand_path(File.dirname(__FILE__))
module Spider
# anything that needs to be done before including submodules
end
require 'spider/some_helper'
require 'spider/some/other_helper'
...
I might recommend this to allow a little more control:
- src/
some_ruby_file.rb:
require 'spider'
Spider.include_all
Spider.do_something
+ doc/
- lib
- spider/
spider.rb:
$: << File.expand_path(File.dirname(__FILE__))
module Spider
def self.include_all
require 'spider/some_helper'
require 'spider/some/other_helper'
...
end
end
Why not use just the same layout? Normally you won't need build because there's no compilation step, but the rest seems OK to me.
I'm not sure what you mean by a module but if it's just a single class a separate folder wouldn't be necessary and if there's more than one file you normally write a module-1.rb file (at the name level as the module-1 folder) that does nothing more than require everything in module-1/.
Oh, and I would suggest using Rake for the management tasks (instead of make).
I would stick to something similar to what you are familiar with: there's no point being a stranger in your own project directory. :-)
Typical things I always have are lib|src, bin, test.
(I dislike these monster generators: the first thing I want to do with a new project is get some code down, not write a README, docs, etc.!)
So I went with newgem.
I removed all unnecessary RubyForge/gem stuff (hoe, setup, etc.), created git repo, imported project into NetBeans. All took 20 minutes and everything's on green.
That even gave me a basic rake task for spec files.
Thank you all.

Resources