Skip to content

Commit

Permalink
add options to sphinx' cmake adapter
Browse files Browse the repository at this point in the history
  • Loading branch information
bkietz committed Oct 28, 2024
1 parent 539e0f4 commit 3f4bd46
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 78 deletions.
20 changes: 20 additions & 0 deletions inject_regenerate.cmake → bootstrapping.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,23 @@ try_compile(
if(NOT success)
message(FATAL_ERROR "try_compile failed: ${errors}")
endif()


# When documenting Maud itself, we need to render the sphinx
# extension template with maud_in2. However we can only get
# the name of the target file with a generator expression,
# but that's enough to copy it to a known location.
set(
_MAUD_IN2
"${MAUD_DIR}/maud_in2"
CACHE INTERNAL
"copied maud_in2 for bootstrapping Maud"
)
add_custom_command(
OUTPUT "${_MAUD_IN2}"
DEPENDS maud_in2
COMMAND
"${CMAKE_COMMAND}" -E create_hardlink
$<TARGET_FILE:maud_in2>
"${_MAUD_IN2}"
)
26 changes: 26 additions & 0 deletions cmake_modules/.maud_sphinx_cmake_adapter.py.in2
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from pathlib import Path

CMAKE_SOURCE_DIR = Path("@CMAKE_SOURCE_DIR@")
CMAKE_BINARY_DIR = Path("@CMAKE_BINARY_DIR@")
STAGE_DIR = CMAKE_BINARY_DIR / "documentation/stage"
APIDOC_DIR = CMAKE_BINARY_DIR / "documentation/apidoc"

project = "@PROJECT_NAME@"

for name, typ, value in [@
foreach(name ${_MAUD_ALL_OPTIONS})
get_property(typ CACHE ${name} PROPERTY TYPE)
string_escape("${${name}}" value)
render("\n ('${name}', '${typ}', \"${value}\"),")
endforeach()
@]:
if typ == "BOOL":
globals()[name] = (value == "ON")
elif "PATH" in typ:
globals()[name] = Path(value)
else:
globals()[name] = value

def setup(app):
print("set up maud extension")

114 changes: 65 additions & 49 deletions cmake_modules/Maud.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,12 @@ function(_maud_cxx_sources)

glob(_MAUD_CXX_SOURCES CONFIGURE_DEPENDS "[.](${ext_regex})$")

# TODO handle this (and other glob exclusions) with a source property
# rather than another glob. Then if a glob is desired, we can write
# glob(CXX_EXCLUDED_SOURCES "cmake_modules/.*[.]cxx")
# foreach(source ${CXX_EXCLUDED_SOURCES})
# # set the excluded property
# endforeach()
if(MAUD_CXX_SOURCE_EXCLUSION_PATTERN)
list(
# This doesn't alter the value in the cache, just the local value
Expand Down Expand Up @@ -849,10 +855,10 @@ function(_maud_load_cache build_dir)
unset(CMAKE_SOURCE_DIR PARENT_SCOPE)
unset(CMAKE_BINARY_DIR PARENT_SCOPE)
file(READ "${build_dir}/CMakeCache.txt" cache)
string(CONCAT pattern "^(.*\n)" [[([^#/].*):.+=]] "([^\n]*)" "\n(.*)$")
string(CONCAT pattern "^(.*\n)" [[([^#/].*):(.+)=]] "([^\n]*)" "\n(.*)$")
while(cache MATCHES "${pattern}")
set(cache "${CMAKE_MATCH_1}")
_maud_set(${CMAKE_MATCH_2} "${CMAKE_MATCH_3}")
set(${CMAKE_MATCH_2} "${CMAKE_MATCH_4}" CACHE ${CMAKE_MATCH_3} "" FORCE)
endwhile()
endif()

Expand Down Expand Up @@ -892,12 +898,14 @@ endfunction()
function(_maud_setup)
_maud_set(CMAKE_SOURCE_DIR "${CMAKE_SOURCE_DIR}")
_maud_set(CMAKE_BINARY_DIR "${CMAKE_BINARY_DIR}")
_maud_set(PROJECT_NAME "${PROJECT_NAME}")
_maud_set(MAUD_DIR "${CMAKE_BINARY_DIR}/_maud")

_maud_set(_MAUD_INCLUDE "SHELL: $<IF:$<CXX_COMPILER_ID:MSVC>,/Fi,-include>")
_maud_set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

_maud_load_cache(CONFIGURING)
unset(_MAUD_ALL_OPTIONS CACHE)
unset(_MAUD_ALL_OPTIONS_RESOLVED CACHE)

if(NOT DEFINED _MAUD_ALL)
Expand Down Expand Up @@ -967,7 +975,6 @@ function(_maud_setup)
)

option(
# TODO document this option
MAUD_CXX_SOURCE_EXCLUSION_PATTERN
STRING "If provided, files matching this pattern will not be scanned as C++ modules."
MARK_AS_ADVANCED
Expand Down Expand Up @@ -1036,28 +1043,42 @@ endfunction()


function(_maud_in2)
glob(_MAUD_IN2 CONFIGURE_DEPENDS EXCLUDE_RENDERED "[.]in2$")
foreach(template ${_MAUD_IN2})
cmake_path(GET template PARENT_PATH dir)
cmake_path(GET template STEM LAST_ONLY RENDER_FILE)

set(compiled "${MAUD_DIR}/compiled_templates/${RENDER_FILE}.in2.cmake")
file(WRITE "${compiled}" "")
if("${_MAUD_IN2}" STREQUAL "")
find_program(_MAUD_IN2 maud_in2 REQUIRED)
endif()

execute_process(
COMMAND maud_in2
INPUT_FILE "${template}"
OUTPUT_FILE "${compiled}"
COMMAND_ERROR_IS_FATAL ANY
glob(_MAUD_IN2_TEMPLATES CONFIGURE_DEPENDS EXCLUDE_RENDERED "[.]in2$")
foreach(template ${_MAUD_IN2_TEMPLATES})
cmake_path(GET template PARENT_PATH dir)
cmake_path(GET template STEM LAST_ONLY stem)
cmake_path(
RELATIVE_PATH dir
BASE_DIRECTORY "${CMAKE_SOURCE_DIR}"
OUTPUT_VARIABLE relative_dir
)

set(RENDER_FILE "${MAUD_DIR}/rendered/${RENDER_FILE}")
file(WRITE "${RENDER_FILE}" "")
include("${compiled}")
set(compiled "${MAUD_DIR}/compiled_templates/${relative_dir}/${stem}.in2.cmake")
set(RENDER_FILE "${MAUD_DIR}/rendered/${relative_dir}/${stem}")
_maud_render_in2()
endforeach()
endfunction()


function(_maud_render_in2)
file(WRITE "${compiled}" "")
file(WRITE "${RENDER_FILE}" "")

execute_process(
COMMAND "${_MAUD_IN2}"
INPUT_FILE "${template}"
OUTPUT_FILE "${compiled}"
COMMAND_ERROR_IS_FATAL ANY
)

include("${compiled}")
endfunction()


function(_maud_setup_doc)
find_package(Python3)

Expand Down Expand Up @@ -1101,7 +1122,7 @@ function(_maud_setup_doc)
file(CREATE_LINK "${CMAKE_SOURCE_DIR}" "${doc}/stage/CMAKE_SOURCE_DIR" SYMBOLIC)

file(
WRITE "${MAUD_DIR}/maud_sphinx_helper/pyproject.toml"
WRITE "${MAUD_DIR}/maud_sphinx_cmake_adapter/pyproject.toml"
[[
[build-system]
requires = ["setuptools"]
Expand All @@ -1112,21 +1133,31 @@ function(_maud_setup_doc)
dependencies = []
]]
)
configure_file(
"${_MAUD_SELF_DIR}/maud_sphinx_helper.py.in"
"${MAUD_DIR}/maud_sphinx_helper/maud/__init__.py"
NO_SOURCE_PERMISSIONS
@ONLY

add_custom_command(
OUTPUT "${MAUD_DIR}/maud_sphinx_cmake_adapter/maud/__init__.py"
DEPENDS "${_MAUD_SELF_DIR}/.maud_sphinx_cmake_adapter.py.in2" "${_MAUD_IN2}"
COMMAND
"${CMAKE_COMMAND}"
-DRENDER_FILE="${MAUD_DIR}/maud_sphinx_cmake_adapter/maud/__init__.py"
-Dcompiled="${MAUD_DIR}/maud_sphinx_cmake_adapter/maud/__init__.py.in2.cmake"
-Dtemplate="${_MAUD_SELF_DIR}/.maud_sphinx_cmake_adapter.py.in2"
-P "${MAUD_DIR}/eval.cmake"
--
[["_maud_render_in2()"]]
COMMENT "Extracting cmake state for sphinx access"
)

add_custom_command(
OUTPUT "${doc}/venv/pip.report.json"
DEPENDS "${_MAUD_SELF_DIR}/sphinx_requirements.txt"
DEPENDS
"${_MAUD_SELF_DIR}/sphinx_requirements.txt"
"${MAUD_DIR}/maud_sphinx_cmake_adapter/maud/__init__.py"
COMMAND
Python3::Interpreter -m venv --clear "${doc}/venv"
COMMAND
"${doc}/venv/bin/pip" install
"${MAUD_DIR}/maud_sphinx_helper"
"${MAUD_DIR}/maud_sphinx_cmake_adapter"
--requirement "${_MAUD_SELF_DIR}/sphinx_requirements.txt"
--isolated
--require-virtualenv
Expand Down Expand Up @@ -1207,36 +1238,22 @@ function(_maud_setup_doc)
foreach(
builder

html
dirhtml
singlehtml
htmlhelp
qthelp
devhelp
epub
applehelp
latex
html dirhtml singlehtml
htmlhelp qthelp devhelp applehelp
epub latex texinfo
man
texinfo
text
gettext
doctest
linkcheck
xml
pseudoxml
text gettext
doctest linkcheck
xml pseudoxml
)
add_custom_command(
OUTPUT "${doc}/${builder}.log"
DEPENDS
"${doc}/venv/pip.report.json"
${all_staged}
${all_apidoc}
# FIXME sphinx doesn't check the mtime of conf.py; it will only rebuild
# if the pickled configuration has changed. That's not great for
# interactive development; it'd be better if modifying conf.py
# invalidated the whole doc build. Maybe add a config value which is
# the mtime of conf.py? Or better, have the command use --write-all --fresh-env
# if any configuration file has changed
# FIXME note all of these with Sphinx.env.note_dependency()
# if they aren't already noted.
"${conf_dir}/conf.py"
WORKING_DIRECTORY "${doc}"
COMMAND
Expand Down Expand Up @@ -1804,7 +1821,6 @@ function(_maud_options_summary)
unset(_MAUD_${prefix}_${name} CACHE)
endforeach()
endforeach()
unset(_MAUD_ALL_OPTIONS CACHE)
endfunction()


Expand Down
11 changes: 0 additions & 11 deletions cmake_modules/maud_sphinx_helper.py.in

This file was deleted.

34 changes: 20 additions & 14 deletions documentation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,24 @@ which defaults to building just ``dirhtml``. To disable building
documentation, set this to an empty string.

Sphinx configuration (minimally, your ``conf.py``) should be put in a directory
named ``sphinx_configuration/`` anywhere in your project.
named ``sphinx_configuration/`` anywhere in your project. In a Maud project,
``conf.py`` has access to all :ref:`options` defined in cmake. For example,
``option(ENABLE_DIAGRAMS)`` might be used in ``conf.py``:

.. code-block:: python
import maud
if maud.ENABLE_DIAGRAMS:
# set up sphinx extension for diagrams
... or ``option(DOCUMENT_EXPERIMENTAL)`` might be used with
`ifconfig <https://www.sphinx-doc.org/en/master/extensions/ifconfig.html>`_:

.. code-block:: rst
.. ifconfig:: maud.DOCUMENT_EXPERIMENTAL
.. experimental features doc
.. TODO talk about import maud, requirements.txt, venv, ...
Expand Down Expand Up @@ -59,16 +76,5 @@ note for those who have used other apidoc systems: cross references from
``///`` comments to labels defined in .rst will just work.


``.in2`` Templates
~~~~~~~~~~~~~~~~~~

ReStructuredText files can also be rendered from ``.in2``
:ref:`templates <in2-templates>`, which allows documentation to have easy
access to arbitrary cmake state. Let's say documentation of experimental
features should be controlled by ``option(DOCUMENT_EXPERIMENTAL)``:

.. code-block:: rst
.. ifconfig:: @DOCUMENT_EXPERIMENTAL | if_else(True False)@
.. experimental features doc
.. TODO if there's an example of ``.rst.in2`` which isn't completely
redundant put that here
2 changes: 1 addition & 1 deletion install.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ install(
"${dir}/cmake_modules/test_.cxx"
"${dir}/cmake_modules/test_.hxx"
"${dir}/cmake_modules/test_main_.cxx"
"${dir}/cmake_modules/maud_sphinx_helper.py.in"
"${dir}/cmake_modules/.maud_sphinx_cmake_adapter.py.in2"
"${dir}/cmake_modules/maud_apidoc.py"
"${dir}/cmake_modules/sphinx_requirements.txt"
DESTINATION
Expand Down
16 changes: 13 additions & 3 deletions project.test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ auto primary interface:
- maud --log-level=VERBOSE


rendered source:
rendered in2 source:
- write: render_foo.cmake
contents: |
file(
Expand Down Expand Up @@ -701,8 +701,18 @@ documentation:
contents: |
.. apidoc:: Foo
:members:
- write: options.cmake
contents: |
option(
SOME_DOC_OPTION
ENUM A B C "Some documentation option"
)
- write: sphinx_configuration/conf.py
contents: ""
contents: |
from maud import SOME_DOC_OPTION, BUILD_TESTING
assert SOME_DOC_OPTION == 'B'
assert type(BUILD_TESTING) == bool
exclude_patterns = ["CMAKE_SOURCE_DIR", "Thumbs.db", ".DS_Store"]
- write: s.cxx
contents: |
export module foo;
Expand All @@ -715,5 +725,5 @@ documentation:
/// metasyntactic variable
int baz;
};
- maud --log-level=VERBOSE
- maud --log-level=VERBOSE -DSOME_DOC_OPTION=B
# TODO abolish exist etc; just provide an inline cmake command for asserting whatever

0 comments on commit 3f4bd46

Please sign in to comment.