From 0aa3cae285dec62d7b66386449a9be1de87a1ab7 Mon Sep 17 00:00:00 2001 From: leakec Date: Sun, 22 Feb 2026 07:10:49 -0700 Subject: [PATCH 01/17] Adding cmake function. See https://github.com/pybind/pybind11_mkdoc/issues/23 --- share/cmake/pybind11_mkdoc_functions.cmake | 59 ++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 share/cmake/pybind11_mkdoc_functions.cmake diff --git a/share/cmake/pybind11_mkdoc_functions.cmake b/share/cmake/pybind11_mkdoc_functions.cmake new file mode 100644 index 0000000..8ad21cc --- /dev/null +++ b/share/cmake/pybind11_mkdoc_functions.cmake @@ -0,0 +1,59 @@ +# This function is used to run pybind11-mkdoc for the headers of a pybind11 module. +# In addition, this will automatically add the current binary directory to the +# pybind11 module's includes, so it can easily be included when compiling the +# module. +# +# The required parameters are: +# * OUTPUT - The name of the output file. +# * PYBIND11_MODULE - The pybind11 module target that these docs will be used for. +# * HEADERS - The header files to create docs for. These can be absoulte paths or relative to the +# current source directory. +# +# The optional parameters are: +# * EXTRA_ARGS - This string argument will be added verbatim to the pybind11-mkdoc command. +# +# Example usage: +# pybind11_add_module(my_pybind11_module src/my_pybind11_module.cc my_byind11_module_doc.h) +# pybind11_mkdoc( +# OUTPUT my_pybind11_module_doc.h +# PYBIND11_MODULE my_pybind11_module +# HEADERS +# include/my_header_1.h +# /absolute/path/to/header.h +# ) +function (pybind11_mkdoc) + set(options) + set(oneValueArgs OUTPUT PYBIND11_MODULE EXTRA_ARGS) + set(multiValueArgs HEADERS) + cmake_parse_arguments(PARSE_ARGV 0 arg + "${options}" "${oneValueArgs}" "${multiValueArgs}" + ) + + # Include directories for the pybind11 module + set(prop "$") + + # Remove the header file from the list + set(HEADERS "") + # Run through all the other arguments. + foreach(header ${arg_HEADERS}) + if(IS_ABSOLUTE ${header}) + # If it is an absolute path, then add it as is. + list(APPEND HEADERS ${header}) + else() + # Otherwise, assume it is relative to the current source directory. + list(APPEND HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/${header}") + endif() + endforeach() + + # Add a custom command for the full header file location that runs pybind11-mkdoc + # We automatically include the source directory and build/include + add_custom_command( + OUTPUT ${arg_OUTPUT} + COMMAND Python::Interpreter -m pybind11_mkdoc ${arg_EXTRA_ARGS} -o ${arg_OUTPUT} "$<$:-I$>" ${HEADERS} + DEPENDS ${HEADERS} + COMMAND_EXPAND_LISTS + ) + + # Add the current binary directory to the pybind11 module so it can be included easily + target_include_directories(${arg_PYBIND11_MODULE} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) +endfunction() From 1019bb52711f510016bc72c15089413e079e1efc Mon Sep 17 00:00:00 2001 From: leakec Date: Sun, 22 Feb 2026 07:23:18 -0700 Subject: [PATCH 02/17] Adding files to create config and versions. --- share/cmake/CMakeLists.txt | 31 +++++++++++++++++++++++ share/cmake/pybind11_mkdocConfig.cmake.in | 6 +++++ 2 files changed, 37 insertions(+) create mode 100644 share/cmake/CMakeLists.txt create mode 100644 share/cmake/pybind11_mkdocConfig.cmake.in diff --git a/share/cmake/CMakeLists.txt b/share/cmake/CMakeLists.txt new file mode 100644 index 0000000..20761ef --- /dev/null +++ b/share/cmake/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 3.25) +project(pybind11_mkdoc) + +include(CMakePackageConfigHelpers) + +# Generate version file +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/pybind11_mkdocConfigVersion.cmake" + VERSION 2.6.2 + COMPATIBILITY SameMajorVersion +) + +# Create config file +configure_package_config_file( + "${CMAKE_CURRENT_SOURCE_DIR}/pybind11_mkdocConfig.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/pybind11_mkdocConfig.cmake" + INSTALL_DESTINATION pybind11_mkdoc +) + +# Install config + version +install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/pybind11_mkdocConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/pybind11_mkdocConfigVersion.cmake" + DESTINATION pybind11_mkdoc +) + +# Install functions +install(FILES + "${CMAKE_CURRENT_SOURCE_DIR}/pybind11_mkdoc_functions.cmake" + DESTINATION pybind11_mkdoc +) diff --git a/share/cmake/pybind11_mkdocConfig.cmake.in b/share/cmake/pybind11_mkdocConfig.cmake.in new file mode 100644 index 0000000..6f135e7 --- /dev/null +++ b/share/cmake/pybind11_mkdocConfig.cmake.in @@ -0,0 +1,6 @@ +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/pybind11_mkdoc_functions.cmake") + +# If you export targets: +# include("${CMAKE_CURRENT_LIST_DIR}/my_pkgTargets.cmake") From 9e2fd54effd0249689b53180be1d4ca53ad15ba8 Mon Sep 17 00:00:00 2001 From: leakec Date: Sun, 22 Feb 2026 07:30:42 -0700 Subject: [PATCH 03/17] Adding build artifacts to .gitignore. --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 73358ad..919b1d4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# Build artifacts from generating cmake files +share/cmake/build + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] From a66967ef59ac4338c7f9a6389d96fecf01689c61 Mon Sep 17 00:00:00 2001 From: leakec Date: Sun, 22 Feb 2026 07:30:52 -0700 Subject: [PATCH 04/17] Adding makefile to make it easy to re-generate when necessary. --- share/cmake/Makefile | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 share/cmake/Makefile diff --git a/share/cmake/Makefile b/share/cmake/Makefile new file mode 100644 index 0000000..464a1e6 --- /dev/null +++ b/share/cmake/Makefile @@ -0,0 +1,6 @@ +build: CMakeLists.txt + cmake -B build -S . -DCMAKE_INSTALL_PREFIX=. + +pybind11_mkdoc: pybind11_mkdocConfig.cmake.in pybind11_mkdoc_functions.cmake build + cmake --build build + cmake --install build From e1e6dd2fdb3958932141c6691568969029f184a0 Mon Sep 17 00:00:00 2001 From: leakec Date: Sun, 22 Feb 2026 07:45:10 -0700 Subject: [PATCH 05/17] Adding these files to version control, since users will often install directly from GitHub. --- .../pybind11_mkdoc/pybind11_mkdocConfig.cmake | 30 +++++++++ .../pybind11_mkdocConfigVersion.cmake | 65 +++++++++++++++++++ .../pybind11_mkdoc_functions.cmake | 59 +++++++++++++++++ 3 files changed, 154 insertions(+) create mode 100644 share/cmake/pybind11_mkdoc/pybind11_mkdocConfig.cmake create mode 100644 share/cmake/pybind11_mkdoc/pybind11_mkdocConfigVersion.cmake create mode 100644 share/cmake/pybind11_mkdoc/pybind11_mkdoc_functions.cmake diff --git a/share/cmake/pybind11_mkdoc/pybind11_mkdocConfig.cmake b/share/cmake/pybind11_mkdoc/pybind11_mkdocConfig.cmake new file mode 100644 index 0000000..c72741b --- /dev/null +++ b/share/cmake/pybind11_mkdoc/pybind11_mkdocConfig.cmake @@ -0,0 +1,30 @@ + +####### Expanded from @PACKAGE_INIT@ by configure_package_config_file() ####### +####### Any changes to this file will be overwritten by the next CMake run #### +####### The input file was pybind11_mkdocConfig.cmake.in ######## + +get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../" ABSOLUTE) + +macro(set_and_check _var _file) + set(${_var} "${_file}") + if(NOT EXISTS "${_file}") + message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !") + endif() +endmacro() + +macro(check_required_components _NAME) + foreach(comp ${${_NAME}_FIND_COMPONENTS}) + if(NOT ${_NAME}_${comp}_FOUND) + if(${_NAME}_FIND_REQUIRED_${comp}) + set(${_NAME}_FOUND FALSE) + endif() + endif() + endforeach() +endmacro() + +#################################################################################### + +include("${CMAKE_CURRENT_LIST_DIR}/pybind11_mkdoc_functions.cmake") + +# If you export targets: +# include("${CMAKE_CURRENT_LIST_DIR}/my_pkgTargets.cmake") diff --git a/share/cmake/pybind11_mkdoc/pybind11_mkdocConfigVersion.cmake b/share/cmake/pybind11_mkdoc/pybind11_mkdocConfigVersion.cmake new file mode 100644 index 0000000..df97cb6 --- /dev/null +++ b/share/cmake/pybind11_mkdoc/pybind11_mkdocConfigVersion.cmake @@ -0,0 +1,65 @@ +# This is a basic version file for the Config-mode of find_package(). +# It is used by write_basic_package_version_file() as input file for configure_file() +# to create a version-file which can be installed along a config.cmake file. +# +# The created file sets PACKAGE_VERSION_EXACT if the current version string and +# the requested version string are exactly the same and it sets +# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version, +# but only if the requested major version is the same as the current one. +# The variable CVF_VERSION must be set before calling configure_file(). + + +set(PACKAGE_VERSION "2.6.2") + +if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION) + set(PACKAGE_VERSION_COMPATIBLE FALSE) +else() + + if("2.6.2" MATCHES "^([0-9]+)\\.") + set(CVF_VERSION_MAJOR "${CMAKE_MATCH_1}") + if(NOT CVF_VERSION_MAJOR VERSION_EQUAL 0) + string(REGEX REPLACE "^0+" "" CVF_VERSION_MAJOR "${CVF_VERSION_MAJOR}") + endif() + else() + set(CVF_VERSION_MAJOR "2.6.2") + endif() + + if(PACKAGE_FIND_VERSION_RANGE) + # both endpoints of the range must have the expected major version + math (EXPR CVF_VERSION_MAJOR_NEXT "${CVF_VERSION_MAJOR} + 1") + if (NOT PACKAGE_FIND_VERSION_MIN_MAJOR STREQUAL CVF_VERSION_MAJOR + OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND NOT PACKAGE_FIND_VERSION_MAX_MAJOR STREQUAL CVF_VERSION_MAJOR) + OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND NOT PACKAGE_FIND_VERSION_MAX VERSION_LESS_EQUAL CVF_VERSION_MAJOR_NEXT))) + set(PACKAGE_VERSION_COMPATIBLE FALSE) + elseif(PACKAGE_FIND_VERSION_MIN_MAJOR STREQUAL CVF_VERSION_MAJOR + AND ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_LESS_EQUAL PACKAGE_FIND_VERSION_MAX) + OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_MAX))) + set(PACKAGE_VERSION_COMPATIBLE TRUE) + else() + set(PACKAGE_VERSION_COMPATIBLE FALSE) + endif() + else() + if(PACKAGE_FIND_VERSION_MAJOR STREQUAL CVF_VERSION_MAJOR) + set(PACKAGE_VERSION_COMPATIBLE TRUE) + else() + set(PACKAGE_VERSION_COMPATIBLE FALSE) + endif() + + if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION) + set(PACKAGE_VERSION_EXACT TRUE) + endif() + endif() +endif() + + +# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it: +if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "8" STREQUAL "") + return() +endif() + +# check that the installed version has the same 32/64bit-ness as the one which is currently searching: +if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "8") + math(EXPR installedBits "8 * 8") + set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)") + set(PACKAGE_VERSION_UNSUITABLE TRUE) +endif() diff --git a/share/cmake/pybind11_mkdoc/pybind11_mkdoc_functions.cmake b/share/cmake/pybind11_mkdoc/pybind11_mkdoc_functions.cmake new file mode 100644 index 0000000..8ad21cc --- /dev/null +++ b/share/cmake/pybind11_mkdoc/pybind11_mkdoc_functions.cmake @@ -0,0 +1,59 @@ +# This function is used to run pybind11-mkdoc for the headers of a pybind11 module. +# In addition, this will automatically add the current binary directory to the +# pybind11 module's includes, so it can easily be included when compiling the +# module. +# +# The required parameters are: +# * OUTPUT - The name of the output file. +# * PYBIND11_MODULE - The pybind11 module target that these docs will be used for. +# * HEADERS - The header files to create docs for. These can be absoulte paths or relative to the +# current source directory. +# +# The optional parameters are: +# * EXTRA_ARGS - This string argument will be added verbatim to the pybind11-mkdoc command. +# +# Example usage: +# pybind11_add_module(my_pybind11_module src/my_pybind11_module.cc my_byind11_module_doc.h) +# pybind11_mkdoc( +# OUTPUT my_pybind11_module_doc.h +# PYBIND11_MODULE my_pybind11_module +# HEADERS +# include/my_header_1.h +# /absolute/path/to/header.h +# ) +function (pybind11_mkdoc) + set(options) + set(oneValueArgs OUTPUT PYBIND11_MODULE EXTRA_ARGS) + set(multiValueArgs HEADERS) + cmake_parse_arguments(PARSE_ARGV 0 arg + "${options}" "${oneValueArgs}" "${multiValueArgs}" + ) + + # Include directories for the pybind11 module + set(prop "$") + + # Remove the header file from the list + set(HEADERS "") + # Run through all the other arguments. + foreach(header ${arg_HEADERS}) + if(IS_ABSOLUTE ${header}) + # If it is an absolute path, then add it as is. + list(APPEND HEADERS ${header}) + else() + # Otherwise, assume it is relative to the current source directory. + list(APPEND HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/${header}") + endif() + endforeach() + + # Add a custom command for the full header file location that runs pybind11-mkdoc + # We automatically include the source directory and build/include + add_custom_command( + OUTPUT ${arg_OUTPUT} + COMMAND Python::Interpreter -m pybind11_mkdoc ${arg_EXTRA_ARGS} -o ${arg_OUTPUT} "$<$:-I$>" ${HEADERS} + DEPENDS ${HEADERS} + COMMAND_EXPAND_LISTS + ) + + # Add the current binary directory to the pybind11 module so it can be included easily + target_include_directories(${arg_PYBIND11_MODULE} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) +endfunction() From d82c11475d888fbd65decc80312f80efb931f82f Mon Sep 17 00:00:00 2001 From: leakec Date: Sun, 22 Feb 2026 07:53:53 -0700 Subject: [PATCH 06/17] Moving things around to make installing easier. --- .gitignore | 2 +- {share/cmake => cmake}/CMakeLists.txt | 0 cmake/Makefile | 10 ++++++++++ {share/cmake => cmake}/pybind11_mkdocConfig.cmake.in | 0 .../pybind11_mkdoc_functions.cmake | 0 .../cmake/pybind11_mkdoc/pybind11_mkdocConfig.cmake | 0 .../pybind11_mkdoc/pybind11_mkdocConfigVersion.cmake | 0 .../pybind11_mkdoc}/pybind11_mkdoc_functions.cmake | 0 share/cmake/Makefile | 6 ------ 9 files changed, 11 insertions(+), 7 deletions(-) rename {share/cmake => cmake}/CMakeLists.txt (100%) create mode 100644 cmake/Makefile rename {share/cmake => cmake}/pybind11_mkdocConfig.cmake.in (100%) rename {share/cmake/pybind11_mkdoc => cmake}/pybind11_mkdoc_functions.cmake (100%) rename {share => pybind11_mkdoc/share}/cmake/pybind11_mkdoc/pybind11_mkdocConfig.cmake (100%) rename {share => pybind11_mkdoc/share}/cmake/pybind11_mkdoc/pybind11_mkdocConfigVersion.cmake (100%) rename {share/cmake => pybind11_mkdoc/share/cmake/pybind11_mkdoc}/pybind11_mkdoc_functions.cmake (100%) delete mode 100644 share/cmake/Makefile diff --git a/.gitignore b/.gitignore index 919b1d4..623b582 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ # Build artifacts from generating cmake files -share/cmake/build +cmake/build # Byte-compiled / optimized / DLL files __pycache__/ diff --git a/share/cmake/CMakeLists.txt b/cmake/CMakeLists.txt similarity index 100% rename from share/cmake/CMakeLists.txt rename to cmake/CMakeLists.txt diff --git a/cmake/Makefile b/cmake/Makefile new file mode 100644 index 0000000..c630ec2 --- /dev/null +++ b/cmake/Makefile @@ -0,0 +1,10 @@ +.PHONY: all + +all : ../pybind11_mkdoc/share/cmake/pybind11_mkdoc + +build: CMakeLists.txt + cmake -B build -S . -DCMAKE_INSTALL_PREFIX=../pybind11_mkdoc/share/cmake + +../pybind11_mkdoc/share/cmake/pybind11_mkdoc: pybind11_mkdocConfig.cmake.in pybind11_mkdoc_functions.cmake build + cmake --build build + cmake --install build diff --git a/share/cmake/pybind11_mkdocConfig.cmake.in b/cmake/pybind11_mkdocConfig.cmake.in similarity index 100% rename from share/cmake/pybind11_mkdocConfig.cmake.in rename to cmake/pybind11_mkdocConfig.cmake.in diff --git a/share/cmake/pybind11_mkdoc/pybind11_mkdoc_functions.cmake b/cmake/pybind11_mkdoc_functions.cmake similarity index 100% rename from share/cmake/pybind11_mkdoc/pybind11_mkdoc_functions.cmake rename to cmake/pybind11_mkdoc_functions.cmake diff --git a/share/cmake/pybind11_mkdoc/pybind11_mkdocConfig.cmake b/pybind11_mkdoc/share/cmake/pybind11_mkdoc/pybind11_mkdocConfig.cmake similarity index 100% rename from share/cmake/pybind11_mkdoc/pybind11_mkdocConfig.cmake rename to pybind11_mkdoc/share/cmake/pybind11_mkdoc/pybind11_mkdocConfig.cmake diff --git a/share/cmake/pybind11_mkdoc/pybind11_mkdocConfigVersion.cmake b/pybind11_mkdoc/share/cmake/pybind11_mkdoc/pybind11_mkdocConfigVersion.cmake similarity index 100% rename from share/cmake/pybind11_mkdoc/pybind11_mkdocConfigVersion.cmake rename to pybind11_mkdoc/share/cmake/pybind11_mkdoc/pybind11_mkdocConfigVersion.cmake diff --git a/share/cmake/pybind11_mkdoc_functions.cmake b/pybind11_mkdoc/share/cmake/pybind11_mkdoc/pybind11_mkdoc_functions.cmake similarity index 100% rename from share/cmake/pybind11_mkdoc_functions.cmake rename to pybind11_mkdoc/share/cmake/pybind11_mkdoc/pybind11_mkdoc_functions.cmake diff --git a/share/cmake/Makefile b/share/cmake/Makefile deleted file mode 100644 index 464a1e6..0000000 --- a/share/cmake/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -build: CMakeLists.txt - cmake -B build -S . -DCMAKE_INSTALL_PREFIX=. - -pybind11_mkdoc: pybind11_mkdocConfig.cmake.in pybind11_mkdoc_functions.cmake build - cmake --build build - cmake --install build From 57028980c02ab2c390adc325a0a03f5a0b87a82c Mon Sep 17 00:00:00 2001 From: leakec Date: Sun, 22 Feb 2026 07:58:03 -0700 Subject: [PATCH 07/17] Adding method to get the cmake directory. --- pybind11_mkdoc/__init__.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pybind11_mkdoc/__init__.py b/pybind11_mkdoc/__init__.py index 567d266..fc81bad 100644 --- a/pybind11_mkdoc/__init__.py +++ b/pybind11_mkdoc/__init__.py @@ -7,6 +7,7 @@ import argparse import os import re +from pathlib import Path from pybind11_mkdoc.mkdoc_lib import mkdoc @@ -73,6 +74,17 @@ def _append_definition(args: list, definition: str): pass +def get_cmake_dir() -> str: + """ + Return the path to the pybind11 CMake module directory. + """ + cmake_installed_path = Path(__file__).parent / "share" / "cmake" / "pybind11_mkdoc" + if cmake_installed_path.exists(): + return str(cmake_installed_path) + + raise ImportError("pybind11_mkdoc cmake files not found.") + + def main(): """ Entry point for the `pybind11_mkdoc` console script. From baf6322e521ceaac47990ba0d41606730812559f Mon Sep 17 00:00:00 2001 From: leakec Date: Sun, 22 Feb 2026 08:27:22 -0700 Subject: [PATCH 08/17] Some minor tweaks to get this working in more cases. --- cmake/pybind11_mkdoc_functions.cmake | 21 +++++++++++++------ .../pybind11_mkdoc_functions.cmake | 20 ++++++++++++------ 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/cmake/pybind11_mkdoc_functions.cmake b/cmake/pybind11_mkdoc_functions.cmake index 8ad21cc..4cc444c 100644 --- a/cmake/pybind11_mkdoc_functions.cmake +++ b/cmake/pybind11_mkdoc_functions.cmake @@ -1,7 +1,8 @@ # This function is used to run pybind11-mkdoc for the headers of a pybind11 module. -# In addition, this will automatically add the current binary directory to the -# pybind11 module's includes, so it can easily be included when compiling the -# module. +# In addition, this will also add target dependencies so the pybind11-mkdoc header +# file is generated before the pybind11 module. Also, this will automatically add +# the current binary directory to the pybind11 module's includes, so it can +# easily be included when compiling the module. # # The required parameters are: # * OUTPUT - The name of the output file. @@ -13,7 +14,7 @@ # * EXTRA_ARGS - This string argument will be added verbatim to the pybind11-mkdoc command. # # Example usage: -# pybind11_add_module(my_pybind11_module src/my_pybind11_module.cc my_byind11_module_doc.h) +# pybind11_add_module(my_pybind11_module src/my_pybind11_module.cc) # pybind11_mkdoc( # OUTPUT my_pybind11_module_doc.h # PYBIND11_MODULE my_pybind11_module @@ -45,15 +46,23 @@ function (pybind11_mkdoc) endif() endforeach() - # Add a custom command for the full header file location that runs pybind11-mkdoc + # Add a custom target and command for the full header file location that runs pybind11-mkdoc # We automatically include the source directory and build/include + add_custom_target( + pybind11_mkdoc_${arg_OUTPUT} + DEPENDS ${arg_OUTPUT} + ) + add_custom_command( OUTPUT ${arg_OUTPUT} - COMMAND Python::Interpreter -m pybind11_mkdoc ${arg_EXTRA_ARGS} -o ${arg_OUTPUT} "$<$:-I$>" ${HEADERS} + COMMAND ${Python_EXECUTABLE} -m pybind11_mkdoc ${arg_EXTRA_ARGS} -o ${arg_OUTPUT} "$<$:-I$>" ${HEADERS} DEPENDS ${HEADERS} COMMAND_EXPAND_LISTS ) + # Add a dependency so that the pybind11-mkdoc command runs before we try to compile the pybind11 module + add_dependencies(${arg_PYBIND11_MODULE} pybind11_mkdoc_${arg_OUTPUT}) + # Add the current binary directory to the pybind11 module so it can be included easily target_include_directories(${arg_PYBIND11_MODULE} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) endfunction() diff --git a/pybind11_mkdoc/share/cmake/pybind11_mkdoc/pybind11_mkdoc_functions.cmake b/pybind11_mkdoc/share/cmake/pybind11_mkdoc/pybind11_mkdoc_functions.cmake index 8ad21cc..3b6f7b0 100644 --- a/pybind11_mkdoc/share/cmake/pybind11_mkdoc/pybind11_mkdoc_functions.cmake +++ b/pybind11_mkdoc/share/cmake/pybind11_mkdoc/pybind11_mkdoc_functions.cmake @@ -1,7 +1,8 @@ # This function is used to run pybind11-mkdoc for the headers of a pybind11 module. -# In addition, this will automatically add the current binary directory to the -# pybind11 module's includes, so it can easily be included when compiling the -# module. +# In addition, this will also add target dependencies so the pybind11-mkdoc header +# file is generated before the pybind11 module. Also, this will automatically add +# the current binary directory to the pybind11 module's includes, so it can +# easily be included when compiling the module. # # The required parameters are: # * OUTPUT - The name of the output file. @@ -13,7 +14,7 @@ # * EXTRA_ARGS - This string argument will be added verbatim to the pybind11-mkdoc command. # # Example usage: -# pybind11_add_module(my_pybind11_module src/my_pybind11_module.cc my_byind11_module_doc.h) +# pybind11_add_module(my_pybind11_module src/my_pybind11_module.cc) # pybind11_mkdoc( # OUTPUT my_pybind11_module_doc.h # PYBIND11_MODULE my_pybind11_module @@ -45,15 +46,22 @@ function (pybind11_mkdoc) endif() endforeach() - # Add a custom command for the full header file location that runs pybind11-mkdoc + # Add a custom target and command for the full header file location that runs pybind11-mkdoc # We automatically include the source directory and build/include + add_custom_target( + pybind11_mkdoc_${arg_OUTPUT} + DEPENDS ${arg_OUTPUT} + ) + add_custom_command( OUTPUT ${arg_OUTPUT} - COMMAND Python::Interpreter -m pybind11_mkdoc ${arg_EXTRA_ARGS} -o ${arg_OUTPUT} "$<$:-I$>" ${HEADERS} + COMMAND ${Python_EXECUTABLE} -m pybind11_mkdoc ${arg_EXTRA_ARGS} -o ${arg_OUTPUT} "$<$:-I$>" ${HEADERS} DEPENDS ${HEADERS} COMMAND_EXPAND_LISTS ) + add_dependencies(${arg_PYBIND11_MODULE} pybind11_mkdoc_${arg_OUTPUT}) + # Add the current binary directory to the pybind11 module so it can be included easily target_include_directories(${arg_PYBIND11_MODULE} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) endfunction() From 3d83ce00e1135e0e1f17630a9053ba5386133852 Mon Sep 17 00:00:00 2001 From: leakec Date: Sun, 22 Feb 2026 08:33:36 -0700 Subject: [PATCH 09/17] Adding simple unit test to ensure cmake is working. --- tests/cmake_docs/CMakeLists.txt | 34 +++++++++++ tests/cmake_docs/dummy.cc | 13 ++++ tests/cmake_docs/my_module_docs_truth.h | 81 +++++++++++++++++++++++++ tests/cmake_test.py | 20 ++++++ 4 files changed, 148 insertions(+) create mode 100644 tests/cmake_docs/CMakeLists.txt create mode 100644 tests/cmake_docs/dummy.cc create mode 100644 tests/cmake_docs/my_module_docs_truth.h create mode 100644 tests/cmake_test.py diff --git a/tests/cmake_docs/CMakeLists.txt b/tests/cmake_docs/CMakeLists.txt new file mode 100644 index 0000000..0623fa6 --- /dev/null +++ b/tests/cmake_docs/CMakeLists.txt @@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 3.25) +project(sbox) + +# Find Python +find_package(Python REQUIRED COMPONENTS Interpreter Development) + +# Find pybind11 +execute_process( + COMMAND ${Python_EXECUTABLE} -c "import pybind11; print(pybind11.get_cmake_dir())" + OUTPUT_VARIABLE pybind11_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE +) +# This is needed for CMake < 3.27. After Cmake 3.27+, can remove setting PYBIND11_FINDPYTHON. +set(PYBIND11_FINDPYTHON ON) +find_package(pybind11 3.0 REQUIRED CONFIG) + +# Find pybind11-mkdoc +execute_process( + COMMAND ${Python_EXECUTABLE} -c "import pybind11_mkdoc; print(pybind11_mkdoc.get_cmake_dir())" + OUTPUT_VARIABLE pybind11_mkdoc_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE +) +find_package(pybind11_mkdoc REQUIRED CONFIG) + +# Add the pybind11 module +pybind11_add_module(my_pybind11_module dummy.cc) +target_include_directories(my_pybind11_module PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../sample_header_docs) +pybind11_mkdoc( + OUTPUT my_module_docs.h + PYBIND11_MODULE my_pybind11_module + HEADERS + "../sample_header_docs/sample header with spaces.h" + ${CMAKE_CURRENT_SOURCE_DIR}/../sample_header_docs/sample_header_2.h +) diff --git a/tests/cmake_docs/dummy.cc b/tests/cmake_docs/dummy.cc new file mode 100644 index 0000000..96f30e0 --- /dev/null +++ b/tests/cmake_docs/dummy.cc @@ -0,0 +1,13 @@ +#include "sample header with spaces.h" +#include "sample_header_2.h" +#include "my_module_docs.h" +#include + +// This is not a real pybind11 module. It is just some dummy code so we can test out +// running pybind11-mkdoc. + +int method1(std::vector, std::map) {return 0;} + +void method2(int p1, int p2){ + std::cout << DOC(Base, method2) << std::endl; +} diff --git a/tests/cmake_docs/my_module_docs_truth.h b/tests/cmake_docs/my_module_docs_truth.h new file mode 100644 index 0000000..2742075 --- /dev/null +++ b/tests/cmake_docs/my_module_docs_truth.h @@ -0,0 +1,81 @@ +/* + This file contains docstrings for use in the Python bindings. + Do not edit! They were automatically extracted by pybind11_mkdoc. + */ + +#define MKD_EXPAND(x) x +#define MKD_COUNT(_1, _2, _3, _4, _5, _6, _7, COUNT, ...) COUNT +#define MKD_VA_SIZE(...) MKD_EXPAND(MKD_COUNT(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0)) +#define MKD_CAT1(a, b) a ## b +#define MKD_CAT2(a, b) MKD_CAT1(a, b) +#define MKD_DOC1(n1) mkd_doc_##n1 +#define MKD_DOC2(n1, n2) mkd_doc_##n1##_##n2 +#define MKD_DOC3(n1, n2, n3) mkd_doc_##n1##_##n2##_##n3 +#define MKD_DOC4(n1, n2, n3, n4) mkd_doc_##n1##_##n2##_##n3##_##n4 +#define MKD_DOC5(n1, n2, n3, n4, n5) mkd_doc_##n1##_##n2##_##n3##_##n4##_##n5 +#define MKD_DOC6(n1, n2, n3, n4, n5, n6) mkd_doc_##n1##_##n2##_##n3##_##n4##_##n5##_##n6 +#define MKD_DOC7(n1, n2, n3, n4, n5, n6, n7) mkd_doc_##n1##_##n2##_##n3##_##n4##_##n5##_##n6##_##n7 +#define DOC(...) MKD_EXPAND(MKD_EXPAND(MKD_CAT2(MKD_DOC, MKD_VA_SIZE(__VA_ARGS__)))(__VA_ARGS__)) + +#if defined(__GNUG__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-variable" +#endif + + +static const char *mkd_doc_Base = R"doc(A simple base class.)doc"; + +static const char *mkd_doc_Base_method1 = +R"doc(Description for method1. + +This is the extended description for method1. + +Args: + p1: I am the first parameter. + p2: I am the second parameter. + +Returns: + An integer is what I return. + +Raises: + runtime_error: Throws runtime error if p1 is empty.)doc"; + +static const char *mkd_doc_Base_method2 = +R"doc(Description for method1. + +This is the extended description for method1. + +Args: + p1: I am a very long description for parameter 1. Let's ensure + that this gets wrapped properly. + p2: I am a very long description for parameter 2. However, I'm + broken out onto two lines. Will this be parsed correctly? + +Returns: + An integer is what I return. + +Raises: + runtime_error: Throws runtime error if p1 is 0. + invalid_argument: Throws invalid_argument error if p2 is 0.)doc"; + +static const char *mkd_doc_RootLevelSymbol = +R"doc(Root-level symbol. Magna fermentum iaculis eu non diam phasellus +vestibulum.)doc"; + +static const char *mkd_doc_drake_MidLevelSymbol = +R"doc(1. Begin first ordered list element. Rutrum quisque non tellus orci ac + auctor. End first ordered list element. +2. Begin second ordered list element. Ipsum faucibus vitae aliquet + nec. Ligula ullamcorper malesuada proin libero. End second ordered + list element. +3. Begin third ordered list element. Dictum sit amet justo donec enim. + Pharetra convallis posuere morbi leo urna molestie. End third + ordered list element. + +Senectus et netus et malesuada fames ac. Tincidunt lobortis feugiat +vivamus at augue eget arcu dictum varius.)doc"; + +#if defined(__GNUG__) +#pragma GCC diagnostic pop +#endif + diff --git a/tests/cmake_test.py b/tests/cmake_test.py new file mode 100644 index 0000000..b9a9236 --- /dev/null +++ b/tests/cmake_test.py @@ -0,0 +1,20 @@ +import subprocess +from pathlib import Path + +import pytest + +DIR = Path(__file__).resolve().parent + +with open(DIR / "cmake_docs" / "my_module_docs_truth.h") as f: + expected = f.read() + +def test_pybind11_mkdoc_cmake(tmp_path: Path) -> None: + # Run pybind11-mkdoc and put the output in a temp file + build_dir = tmp_path / "build" + subprocess.run(["cmake", "-B", build_dir, "-S", DIR / "cmake_docs"], check=True) + subprocess.run(["cmake", "--build", build_dir], check=True) + + # Ensure the header file matches + res = (build_dir/"my_module_docs.h").read_text(encoding="utf-8") + + assert res == expected From 25a4d66e2f1f43326fa17a327b026f1392e736df Mon Sep 17 00:00:00 2001 From: leakec Date: Sun, 22 Feb 2026 08:40:35 -0700 Subject: [PATCH 10/17] Adding test for EXTRA_ARGS as well. --- tests/cmake_docs/CMakeLists.txt | 1 + tests/cmake_docs/my_module_docs_extra_truth.h | 83 +++++++++++++++++++ tests/cmake_test.py | 23 ++++- tests/sample_header_docs/sample_header_2.h | 7 ++ 4 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 tests/cmake_docs/my_module_docs_extra_truth.h diff --git a/tests/cmake_docs/CMakeLists.txt b/tests/cmake_docs/CMakeLists.txt index 0623fa6..d77e3e6 100644 --- a/tests/cmake_docs/CMakeLists.txt +++ b/tests/cmake_docs/CMakeLists.txt @@ -28,6 +28,7 @@ target_include_directories(my_pybind11_module PRIVATE ${CMAKE_CURRENT_SOURCE_DIR pybind11_mkdoc( OUTPUT my_module_docs.h PYBIND11_MODULE my_pybind11_module + EXTRA_ARGS $ENV{PYBIND11_TEST_EXTRA_ARGS} HEADERS "../sample_header_docs/sample header with spaces.h" ${CMAKE_CURRENT_SOURCE_DIR}/../sample_header_docs/sample_header_2.h diff --git a/tests/cmake_docs/my_module_docs_extra_truth.h b/tests/cmake_docs/my_module_docs_extra_truth.h new file mode 100644 index 0000000..5783880 --- /dev/null +++ b/tests/cmake_docs/my_module_docs_extra_truth.h @@ -0,0 +1,83 @@ +/* + This file contains docstrings for use in the Python bindings. + Do not edit! They were automatically extracted by pybind11_mkdoc. + */ + +#define MKD_EXPAND(x) x +#define MKD_COUNT(_1, _2, _3, _4, _5, _6, _7, COUNT, ...) COUNT +#define MKD_VA_SIZE(...) MKD_EXPAND(MKD_COUNT(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0)) +#define MKD_CAT1(a, b) a ## b +#define MKD_CAT2(a, b) MKD_CAT1(a, b) +#define MKD_DOC1(n1) mkd_doc_##n1 +#define MKD_DOC2(n1, n2) mkd_doc_##n1##_##n2 +#define MKD_DOC3(n1, n2, n3) mkd_doc_##n1##_##n2##_##n3 +#define MKD_DOC4(n1, n2, n3, n4) mkd_doc_##n1##_##n2##_##n3##_##n4 +#define MKD_DOC5(n1, n2, n3, n4, n5) mkd_doc_##n1##_##n2##_##n3##_##n4##_##n5 +#define MKD_DOC6(n1, n2, n3, n4, n5, n6) mkd_doc_##n1##_##n2##_##n3##_##n4##_##n5##_##n6 +#define MKD_DOC7(n1, n2, n3, n4, n5, n6, n7) mkd_doc_##n1##_##n2##_##n3##_##n4##_##n5##_##n6##_##n7 +#define DOC(...) MKD_EXPAND(MKD_EXPAND(MKD_CAT2(MKD_DOC, MKD_VA_SIZE(__VA_ARGS__)))(__VA_ARGS__)) + +#if defined(__GNUG__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-variable" +#endif + + +static const char *mkd_doc_Base = R"doc(A simple base class.)doc"; + +static const char *mkd_doc_Base_method1 = +R"doc(Description for method1. + +This is the extended description for method1. + +Args: + p1: I am the first parameter. + p2: I am the second parameter. + +Returns: + An integer is what I return. + +Raises: + runtime_error: Throws runtime error if p1 is empty.)doc"; + +static const char *mkd_doc_Base_method2 = +R"doc(Description for method1. + +This is the extended description for method1. + +Args: + p1: I am a very long description for parameter 1. Let's ensure + that this gets wrapped properly. + p2: I am a very long description for parameter 2. However, I'm + broken out onto two lines. Will this be parsed correctly? + +Returns: + An integer is what I return. + +Raises: + runtime_error: Throws runtime error if p1 is 0. + invalid_argument: Throws invalid_argument error if p2 is 0.)doc"; + +static const char *mkd_doc_Base_method3 = R"doc(A method that is only included if MY_EXTRA_DEFINE is defined.)doc"; + +static const char *mkd_doc_RootLevelSymbol = +R"doc(Root-level symbol. Magna fermentum iaculis eu non diam phasellus +vestibulum.)doc"; + +static const char *mkd_doc_drake_MidLevelSymbol = +R"doc(1. Begin first ordered list element. Rutrum quisque non tellus orci ac + auctor. End first ordered list element. +2. Begin second ordered list element. Ipsum faucibus vitae aliquet + nec. Ligula ullamcorper malesuada proin libero. End second ordered + list element. +3. Begin third ordered list element. Dictum sit amet justo donec enim. + Pharetra convallis posuere morbi leo urna molestie. End third + ordered list element. + +Senectus et netus et malesuada fames ac. Tincidunt lobortis feugiat +vivamus at augue eget arcu dictum varius.)doc"; + +#if defined(__GNUG__) +#pragma GCC diagnostic pop +#endif + diff --git a/tests/cmake_test.py b/tests/cmake_test.py index b9a9236..cb1cd0e 100644 --- a/tests/cmake_test.py +++ b/tests/cmake_test.py @@ -1,3 +1,4 @@ +import os import subprocess from pathlib import Path @@ -5,8 +6,6 @@ DIR = Path(__file__).resolve().parent -with open(DIR / "cmake_docs" / "my_module_docs_truth.h") as f: - expected = f.read() def test_pybind11_mkdoc_cmake(tmp_path: Path) -> None: # Run pybind11-mkdoc and put the output in a temp file @@ -17,4 +16,24 @@ def test_pybind11_mkdoc_cmake(tmp_path: Path) -> None: # Ensure the header file matches res = (build_dir/"my_module_docs.h").read_text(encoding="utf-8") + with open(DIR / "cmake_docs" / "my_module_docs_truth.h") as f: + expected = f.read() + + assert res == expected + +def test_pybind11_mkdoc_cmake_extra_args(tmp_path: Path) -> None: + # Run pybind11-mkdoc and put the output in a temp file + build_dir = tmp_path / "build" + env = os.environ.copy() + env["PYBIND11_TEST_EXTRA_ARGS"] = "-DMY_EXTRA_DEFINE=1" + + subprocess.run(["cmake", "-B", build_dir, "-S", DIR / "cmake_docs"], check=True, env=env) + subprocess.run(["cmake", "--build", build_dir], check=True, env=env) + + # Ensure the header file matches + res = (build_dir/"my_module_docs.h").read_text(encoding="utf-8") + + with open(DIR / "cmake_docs" / "my_module_docs_extra_truth.h") as f: + expected = f.read() + assert res == expected diff --git a/tests/sample_header_docs/sample_header_2.h b/tests/sample_header_docs/sample_header_2.h index c62cb80..a7e9fab 100644 --- a/tests/sample_header_docs/sample_header_2.h +++ b/tests/sample_header_docs/sample_header_2.h @@ -38,4 +38,11 @@ class Base { * @exception invalid_argument Throws invalid_argument error if p2 is 0. */ void method2(int p1, int p2); + +#ifdef MY_EXTRA_DEFINE + /** + * @brief A method that is only included if MY_EXTRA_DEFINE is defined. + */ + void method3(); +#endif }; From 9e1ae615d05ebbbe4e1ff18aea2d6498eeb9c8dc Mon Sep 17 00:00:00 2001 From: leakec Date: Sun, 22 Feb 2026 08:42:31 -0700 Subject: [PATCH 11/17] Ran ruff and fixed errors. --- pybind11_mkdoc/__init__.py | 3 ++- pybind11_mkdoc/mkdoc_lib.py | 2 +- tests/cmake_test.py | 7 +++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pybind11_mkdoc/__init__.py b/pybind11_mkdoc/__init__.py index fc81bad..631c986 100644 --- a/pybind11_mkdoc/__init__.py +++ b/pybind11_mkdoc/__init__.py @@ -82,7 +82,8 @@ def get_cmake_dir() -> str: if cmake_installed_path.exists(): return str(cmake_installed_path) - raise ImportError("pybind11_mkdoc cmake files not found.") + msg = "pybind11_mkdoc cmake files not found." + raise ImportError(msg) def main(): diff --git a/pybind11_mkdoc/mkdoc_lib.py b/pybind11_mkdoc/mkdoc_lib.py index 6f57054..23c9208 100755 --- a/pybind11_mkdoc/mkdoc_lib.py +++ b/pybind11_mkdoc/mkdoc_lib.py @@ -173,7 +173,7 @@ def process_comment(comment): rm_lines.append(k) add_to = (t_params, name) elif m := return_re.match(line): - text, = m.groups() + (text,) = m.groups() ret.append(text.strip()) add_to = (ret, len(ret) - 1) rm_lines.append(k) diff --git a/tests/cmake_test.py b/tests/cmake_test.py index cb1cd0e..f5854b3 100644 --- a/tests/cmake_test.py +++ b/tests/cmake_test.py @@ -2,8 +2,6 @@ import subprocess from pathlib import Path -import pytest - DIR = Path(__file__).resolve().parent @@ -14,13 +12,14 @@ def test_pybind11_mkdoc_cmake(tmp_path: Path) -> None: subprocess.run(["cmake", "--build", build_dir], check=True) # Ensure the header file matches - res = (build_dir/"my_module_docs.h").read_text(encoding="utf-8") + res = (build_dir / "my_module_docs.h").read_text(encoding="utf-8") with open(DIR / "cmake_docs" / "my_module_docs_truth.h") as f: expected = f.read() assert res == expected + def test_pybind11_mkdoc_cmake_extra_args(tmp_path: Path) -> None: # Run pybind11-mkdoc and put the output in a temp file build_dir = tmp_path / "build" @@ -31,7 +30,7 @@ def test_pybind11_mkdoc_cmake_extra_args(tmp_path: Path) -> None: subprocess.run(["cmake", "--build", build_dir], check=True, env=env) # Ensure the header file matches - res = (build_dir/"my_module_docs.h").read_text(encoding="utf-8") + res = (build_dir / "my_module_docs.h").read_text(encoding="utf-8") with open(DIR / "cmake_docs" / "my_module_docs_extra_truth.h") as f: expected = f.read() From a9188866efab35d9e325586e23b72a4018af75f6 Mon Sep 17 00:00:00 2001 From: leakec Date: Sun, 22 Feb 2026 08:42:58 -0700 Subject: [PATCH 12/17] Fixing name. --- pybind11_mkdoc/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pybind11_mkdoc/__init__.py b/pybind11_mkdoc/__init__.py index 631c986..7dd1475 100644 --- a/pybind11_mkdoc/__init__.py +++ b/pybind11_mkdoc/__init__.py @@ -76,7 +76,7 @@ def _append_definition(args: list, definition: str): def get_cmake_dir() -> str: """ - Return the path to the pybind11 CMake module directory. + Return the path to the pybind11_mkdoc CMake module directory. """ cmake_installed_path = Path(__file__).parent / "share" / "cmake" / "pybind11_mkdoc" if cmake_installed_path.exists(): From c458953b9c72821e42a7edfcd90f64854abdeee2 Mon Sep 17 00:00:00 2001 From: leakec Date: Sun, 22 Feb 2026 08:49:55 -0700 Subject: [PATCH 13/17] Adding docs. --- README.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/README.md b/README.md index 6dfcd1a..5623077 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,43 @@ py::class_(m, "MyClass", DOC(MyClass)) ... ``` +### CMake +The `pybind11_mkdoc` CMake function is included to easily generate header for a pybind11 module when +compiling said module in CMake. The function generates the headers based on the arguments provided. +In addition, it add target dependencies so the pybind11-mkdoc header file is generated before +the pybind11 module. Also, it will automatically add the current binary directory to the pybind11 +module's includes, so it can easily be included when compiling the module. + +The required parameters are: +* OUTPUT - The name of the output file. +* PYBIND11_MODULE - The pybind11 module target that these docs will be used for. +* HEADERS - The header files to create docs for. These can be absoulte paths or relative to the + current source directory. + +The optional parameters are: +* EXTRA_ARGS - This string argument will be added verbatim to the pybind11-mkdoc command. + +Below is an exmaple of how it is used: +```cmake +# Find pybind11-mkdoc +# This assumes you have already run a find_package for Python. +execute_process( + COMMAND ${Python_EXECUTABLE} -c "import pybind11_mkdoc; print(pybind11_mkdoc.get_cmake_dir())" + OUTPUT_VARIABLE pybind11_mkdoc_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE +) +find_package(pybind11_mkdoc REQUIRED CONFIG) + +# Add the pybind11 module +pybind11_add_module(my_pybind11_module my_src_files.cc) +pybind11_mkdoc( + OUTPUT my_pybind11_module_docs.h + PYBIND11_MODULE my_pybind11_module + HEADERS + header_1.h + /absolute/path/to/header_2.h +) +``` ## Limitations This tool supports Linux and macOS for Python versions 3.8 to 3.11. Also, it From b09b362cd4ba258ae5687e3edb82e5e6ddc92840 Mon Sep 17 00:00:00 2001 From: leakec Date: Sun, 22 Feb 2026 09:01:30 -0700 Subject: [PATCH 14/17] Trying to sync test group first to ensure dependencies are installed. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ba9202d..96dc8a4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,7 +38,7 @@ jobs: - uses: astral-sh/setup-uv@v7 - name: Test package - run: uv run --with "clang<19" --group test pytest --forked + run: uv sync --group test && uv run --with "clang<19" --group test pytest --forked # Commented for now -- msys2 Clang (v15) and the clang Python package (v14) are incompatible # From c96a17ccbef1473d96a26399125470a9f6fe40bb Mon Sep 17 00:00:00 2001 From: leakec Date: Sun, 22 Feb 2026 09:04:35 -0700 Subject: [PATCH 15/17] Trying again, but just adding pybind11 to --with. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 96dc8a4..6fec315 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,7 +38,7 @@ jobs: - uses: astral-sh/setup-uv@v7 - name: Test package - run: uv sync --group test && uv run --with "clang<19" --group test pytest --forked + run: uv run --with "clang<19,pybind11" --group test pytest --forked # Commented for now -- msys2 Clang (v15) and the clang Python package (v14) are incompatible # From 8b70ad0a3c9b1b04beb3e788edffee3230c3458a Mon Sep 17 00:00:00 2001 From: leakec Date: Sun, 22 Feb 2026 09:12:45 -0700 Subject: [PATCH 16/17] Trying to pass in Python version directly to help cmake in the runners. --- tests/cmake_test.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/cmake_test.py b/tests/cmake_test.py index f5854b3..5d1d616 100644 --- a/tests/cmake_test.py +++ b/tests/cmake_test.py @@ -1,4 +1,5 @@ import os +import sys import subprocess from pathlib import Path @@ -8,7 +9,7 @@ def test_pybind11_mkdoc_cmake(tmp_path: Path) -> None: # Run pybind11-mkdoc and put the output in a temp file build_dir = tmp_path / "build" - subprocess.run(["cmake", "-B", build_dir, "-S", DIR / "cmake_docs"], check=True) + subprocess.run(["cmake", "-B", build_dir, "-S", DIR / "cmake_docs", f"-DPython_EXECUTABLE={sys.executable}"], check=True) subprocess.run(["cmake", "--build", build_dir], check=True) # Ensure the header file matches @@ -26,7 +27,7 @@ def test_pybind11_mkdoc_cmake_extra_args(tmp_path: Path) -> None: env = os.environ.copy() env["PYBIND11_TEST_EXTRA_ARGS"] = "-DMY_EXTRA_DEFINE=1" - subprocess.run(["cmake", "-B", build_dir, "-S", DIR / "cmake_docs"], check=True, env=env) + subprocess.run(["cmake", "-B", build_dir, "-S", DIR / "cmake_docs", f"-DPython_EXECUTABLE={sys.executable}"], check=True, env=env) subprocess.run(["cmake", "--build", build_dir], check=True, env=env) # Ensure the header file matches From b7184984b8df26d1381caa63179246c8d311fcd1 Mon Sep 17 00:00:00 2001 From: leakec Date: Sun, 22 Feb 2026 09:14:06 -0700 Subject: [PATCH 17/17] Trying removing the --with now that I've got the Python path sorted in the cmake tests. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6fec315..ba9202d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,7 +38,7 @@ jobs: - uses: astral-sh/setup-uv@v7 - name: Test package - run: uv run --with "clang<19,pybind11" --group test pytest --forked + run: uv run --with "clang<19" --group test pytest --forked # Commented for now -- msys2 Clang (v15) and the clang Python package (v14) are incompatible #