From af375239017c4a392d7232c4c55007dcac4f55ac Mon Sep 17 00:00:00 2001 From: Dennis Klein Date: Thu, 20 May 2021 04:24:01 +0200 Subject: [PATCH] Docs: Add docs target --- .gitignore | 1 + CMakeLists.txt | 9 + README.md | 46 +-- docs/CMakeLists.txt | 20 ++ docs/changelog.rst | 5 + docs/cmake.py | 474 ++++++++++++++++++++++++++ docs/conf.py.in | 72 ++++ docs/development.md | 37 -- docs/development.rst | 76 +++++ docs/index.rst | 30 ++ docs/installation.rst | 58 ++++ docs/issues.rst | 6 + docs/license.rst | 14 + docs/module/FairFindPackage2.rst | 2 + docs/module/FairFormattedOutput.rst | 5 + docs/usage.rst | 5 + src/modules/FairFindPackage2.cmake.in | 139 +++++--- 17 files changed, 880 insertions(+), 119 deletions(-) create mode 100644 .gitignore create mode 100644 docs/CMakeLists.txt create mode 100644 docs/changelog.rst create mode 100644 docs/cmake.py create mode 100644 docs/conf.py.in delete mode 100644 docs/development.md create mode 100644 docs/development.rst create mode 100644 docs/index.rst create mode 100644 docs/installation.rst create mode 100644 docs/issues.rst create mode 100644 docs/license.rst create mode 100644 docs/module/FairFindPackage2.rst create mode 100644 docs/module/FairFormattedOutput.rst create mode 100644 docs/usage.rst diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bee8a64 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +__pycache__ diff --git a/CMakeLists.txt b/CMakeLists.txt index 54bcca9..b438bd2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,10 @@ project(FairCMakeModules VERSION 0.1.0 LANGUAGES CXX HOMEPAGE_URL "https://github.com/FairRootGroup/FairCMakeModules") message(STATUS "${PROJECT_NAME} Version ${PROJECT_VERSION}") +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif() + include(GNUInstallDirs) include(CMakePackageConfigHelpers) include(CTest) @@ -28,6 +32,11 @@ set(PROJECT_INSTALL_MODULESDIR "${PROJECT_INSTALL_DATADIR}/modules") add_subdirectory(src) add_subdirectory(tests) +find_program(SPHINX_EXECUTABLE NAMES sphinx-build) +if(SPHINX_EXECUTABLE) + add_subdirectory(docs) +endif() + configure_package_config_file( "cmake/${PROJECT_NAME}Config.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" diff --git a/README.md b/README.md index 7c0fd0a..cfd937a 100644 --- a/README.md +++ b/README.md @@ -1,47 +1,5 @@ # FairCMakeModules -CMake Modules developed in the context of various FAIR projects +This project maintains CMake Modules developed in the context of various [FAIR](https://www.gsi.de/en/researchaccelerators/fair) software projects. -## Installation - -``` -git clone https://github.com/FairRootGroup/FairCMakeModules -cmake -S FairCMakeModules -B FairCMakeModules_build -DCMAKE_INSTALL_PREFIX=FairCMakeModules_install -cmake --build FairCMakeModules_build --target install -``` - -## Usage - -In your project, discover this package with [`find_package`](https://cmake.org/cmake/help/latest/command/find_package.html#full-signature-and-config-mode) (see the official CMake docs for the full call signature of `find_package`): - -``` -find_package(FairCMakeModules REQUIRED) -``` - -Then [`include`](https://cmake.org/cmake/help/latest/command/include.html) any module you would like to use - -``` -include() -``` - -Available modules are: - -* [FairFindPackage2](src/modules/FairFindPackage2.cmake) - -## License - -``` -################################################################################ -# Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH # -# # -# This software is distributed under the terms of the # -# GNU Lesser General Public Licence (LGPL) version 3, # -# copied verbatim in the file "LICENSE" # -################################################################################ -``` - -## Contributing - -For comments, questions, and bug reports please [open a github issue](https://github.com/FairRootGroup/FairCMakeModules/issues/new). - -For code contributions and bug fixes please create [a github pull request](https://github.com/FairRootGroup/FairCMakeModules/pulls) against the `main` branch. Read our [notes for developers](docs/development.md). +:pushpin: **Get started by visiting the [:closed_book: Documentation](https://fairrootgroup.github.io/FairCMakeModules/index.html)** diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt new file mode 100644 index 0000000..4208452 --- /dev/null +++ b/docs/CMakeLists.txt @@ -0,0 +1,20 @@ +################################################################################ +# Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH # +# # +# This software is distributed under the terms of the # +# GNU Lesser General Public Licence (LGPL) version 3, # +# copied verbatim in the file "LICENSE" # +################################################################################ + +configure_file(conf.py.in + "${CMAKE_CURRENT_BINARY_DIR}/conf.py" @ONLY +) + +set(builder html) +add_custom_target(docs + COMMAND ${SPHINX_EXECUTABLE} -a -E -c "${CMAKE_CURRENT_BINARY_DIR}" -b ${builder} + ${CMAKE_CURRENT_SOURCE_DIR} "${CMAKE_CURRENT_BINARY_DIR}/${builder}" + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Generating documentation" + VERBATIM +) diff --git a/docs/changelog.rst b/docs/changelog.rst new file mode 100644 index 0000000..eb015f2 --- /dev/null +++ b/docs/changelog.rst @@ -0,0 +1,5 @@ +********* +Changelog +********* + +**TODO** diff --git a/docs/cmake.py b/docs/cmake.py new file mode 100644 index 0000000..58db6d6 --- /dev/null +++ b/docs/cmake.py @@ -0,0 +1,474 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +# copied from https://gitlab.kitware.com/cmake/cmake/-/raw/master/Utilities/Sphinx/cmake.py + +import os +import re + +# Override much of pygments' CMakeLexer. +# We need to parse CMake syntax definitions, not CMake code. + +# For hard test cases that use much of the syntax below, see +# - module/FindPkgConfig.html (with "glib-2.0>=2.10 gtk+-2.0" and similar) +# - module/ExternalProject.html (with http:// https:// git@; also has command options -E --build) +# - manual/cmake-buildsystem.7.html (with nested $<..>; relative and absolute paths, "::") + +from pygments.lexers import CMakeLexer +from pygments.token import Name, Operator, Punctuation, String, Text, Comment, Generic, Whitespace, Number +from pygments.lexer import bygroups + +# Notes on regular expressions below: +# - [\.\+-] are needed for string constants like gtk+-2.0 +# - Unix paths are recognized by '/'; support for Windows paths may be added if needed +# - (\\.) allows for \-escapes (used in manual/cmake-language.7) +# - $<..$<..$>..> nested occurrence in cmake-buildsystem +# - Nested variable evaluations are only supported in a limited capacity. Only +# one level of nesting is supported and at most one nested variable can be present. + +CMakeLexer.tokens["root"] = [ + (r'\b(\w+)([ \t]*)(\()', bygroups(Name.Function, Text, Name.Function), '#push'), # fctn( + (r'\(', Name.Function, '#push'), + (r'\)', Name.Function, '#pop'), + (r'\[', Punctuation, '#push'), + (r'\]', Punctuation, '#pop'), + (r'[|;,.=*\-]', Punctuation), + (r'\\\\', Punctuation), # used in commands/source_group + (r'[:]', Operator), + (r'[<>]=', Punctuation), # used in FindPkgConfig.cmake + (r'\$<', Operator, '#push'), # $<...> + (r'<[^<|]+?>(\w*\.\.\.)?', Name.Variable), # + (r'(\$\w*\{)([^\}\$]*)?(?:(\$\w*\{)([^\}]+?)(\}))?([^\}]*?)(\})', # ${..} $ENV{..}, possibly nested + bygroups(Operator, Name.Tag, Operator, Name.Tag, Operator, Name.Tag, Operator)), + (r'([A-Z]+\{)(.+?)(\})', bygroups(Operator, Name.Tag, Operator)), # DATA{ ...} + (r'[a-z]+(@|(://))((\\.)|[\w.+-:/\\])+', Name.Attribute), # URL, git@, ... + (r'/\w[\w\.\+-/\\]*', Name.Attribute), # absolute path + (r'/', Name.Attribute), + (r'\w[\w\.\+-]*/[\w.+-/\\]*', Name.Attribute), # relative path + (r'[A-Z]((\\.)|[\w.+-])*[a-z]((\\.)|[\w.+-])*', Name.Builtin), # initial A-Z, contains a-z + (r'@?[A-Z][A-Z0-9_]*', Name.Constant), + (r'[a-z_]((\\;)|(\\ )|[\w.+-])*', Name.Builtin), + (r'[0-9][0-9\.]*', Number), + (r'(?s)"(\\"|[^"])*"', String), # "string" + (r'\.\.\.', Name.Variable), + (r'<', Operator, '#push'), # <..|..> is different from + (r'>', Operator, '#pop'), + (r'\n', Whitespace), + (r'[ \t]+', Whitespace), + (r'#.*\n', Comment), + # (r'[^<>\])\}\|$"# \t\n]+', Name.Exception), # fallback, for debugging only +] + +from docutils.parsers.rst import Directive, directives +from docutils.transforms import Transform +try: + from docutils.utils.error_reporting import SafeString, ErrorString +except ImportError: + # error_reporting was not in utils before version 0.11: + from docutils.error_reporting import SafeString, ErrorString + +from docutils import io, nodes + +from sphinx.directives import ObjectDescription +from sphinx.domains import Domain, ObjType +from sphinx.roles import XRefRole +from sphinx.util.nodes import make_refnode +from sphinx import addnodes + +sphinx_before_1_4 = False +sphinx_before_1_7_2 = False +try: + from sphinx import version_info + if version_info < (1, 4): + sphinx_before_1_4 = True + if version_info < (1, 7, 2): + sphinx_before_1_7_2 = True +except ImportError: + # The `sphinx.version_info` tuple was added in Sphinx v1.2: + sphinx_before_1_4 = True + sphinx_before_1_7_2 = True + +if sphinx_before_1_7_2: + # Monkey patch for sphinx generating invalid content for qcollectiongenerator + # https://github.com/sphinx-doc/sphinx/issues/1435 + from sphinx.util.pycompat import htmlescape + from sphinx.builders.qthelp import QtHelpBuilder + old_build_keywords = QtHelpBuilder.build_keywords + def new_build_keywords(self, title, refs, subitems): + old_items = old_build_keywords(self, title, refs, subitems) + new_items = [] + for item in old_items: + before, rest = item.split("ref=\"", 1) + ref, after = rest.split("\"") + if ("<" in ref and ">" in ref): + new_items.append(before + "ref=\"" + htmlescape(ref) + "\"" + after) + else: + new_items.append(item) + return new_items + QtHelpBuilder.build_keywords = new_build_keywords + +class CMakeModule(Directive): + required_arguments = 1 + optional_arguments = 0 + final_argument_whitespace = True + option_spec = {'encoding': directives.encoding} + + def __init__(self, *args, **keys): + self.re_start = re.compile(r'^#\[(?P=*)\[\.rst:$') + Directive.__init__(self, *args, **keys) + + def run(self): + settings = self.state.document.settings + if not settings.file_insertion_enabled: + raise self.warning('"%s" directive disabled.' % self.name) + + env = self.state.document.settings.env + rel_path, path = env.relfn2path(self.arguments[0]) + path = os.path.normpath(path) + encoding = self.options.get('encoding', settings.input_encoding) + e_handler = settings.input_encoding_error_handler + try: + settings.record_dependencies.add(path) + f = io.FileInput(source_path=path, encoding=encoding, + error_handler=e_handler) + except UnicodeEncodeError as error: + raise self.severe('Problems with "%s" directive path:\n' + 'Cannot encode input file path "%s" ' + '(wrong locale?).' % + (self.name, SafeString(path))) + except IOError as error: + raise self.severe('Problems with "%s" directive path:\n%s.' % + (self.name, ErrorString(error))) + raw_lines = f.read().splitlines() + f.close() + rst = None + lines = [] + for line in raw_lines: + if rst is not None and rst != '#': + # Bracket mode: check for end bracket + pos = line.find(rst) + if pos >= 0: + if line[0] == '#': + line = '' + else: + line = line[0:pos] + rst = None + else: + # Line mode: check for .rst start (bracket or line) + m = self.re_start.match(line) + if m: + rst = ']%s]' % m.group('eq') + line = '' + elif line == '#.rst:': + rst = '#' + line = '' + elif rst == '#': + if line == '#' or line[:2] == '# ': + line = line[2:] + else: + rst = None + line = '' + elif rst is None: + line = '' + lines.append(line) + if rst is not None and rst != '#': + raise self.warning('"%s" found unclosed bracket "#[%s[.rst:" in %s' % + (self.name, rst[1:-1], path)) + self.state_machine.insert_input(lines, path) + return [] + +class _cmake_index_entry: + def __init__(self, desc): + self.desc = desc + + def __call__(self, title, targetid, main = 'main'): + # See https://github.com/sphinx-doc/sphinx/issues/2673 + if sphinx_before_1_4: + return ('pair', u'%s ; %s' % (self.desc, title), targetid, main) + else: + return ('pair', u'%s ; %s' % (self.desc, title), targetid, main, None) + +_cmake_index_objs = { + 'command': _cmake_index_entry('command'), + 'cpack_gen': _cmake_index_entry('cpack generator'), + 'envvar': _cmake_index_entry('envvar'), + 'generator': _cmake_index_entry('generator'), + 'genex': _cmake_index_entry('genex'), + 'guide': _cmake_index_entry('guide'), + 'manual': _cmake_index_entry('manual'), + 'module': _cmake_index_entry('module'), + 'policy': _cmake_index_entry('policy'), + 'prop_cache': _cmake_index_entry('cache property'), + 'prop_dir': _cmake_index_entry('directory property'), + 'prop_gbl': _cmake_index_entry('global property'), + 'prop_inst': _cmake_index_entry('installed file property'), + 'prop_sf': _cmake_index_entry('source file property'), + 'prop_test': _cmake_index_entry('test property'), + 'prop_tgt': _cmake_index_entry('target property'), + 'variable': _cmake_index_entry('variable'), + } + +def _cmake_object_inventory(env, document, line, objtype, targetid): + inv = env.domaindata['cmake']['objects'] + if targetid in inv: + document.reporter.warning( + 'CMake object "%s" also described in "%s".' % + (targetid, env.doc2path(inv[targetid][0])), line=line) + inv[targetid] = (env.docname, objtype) + +class CMakeTransform(Transform): + + # Run this transform early since we insert nodes we want + # treated as if they were written in the documents. + default_priority = 210 + + def __init__(self, document, startnode): + Transform.__init__(self, document, startnode) + self.titles = {} + + def parse_title(self, docname): + """Parse a document title as the first line starting in [A-Za-z0-9<$] + or fall back to the document basename if no such line exists. + The cmake --help-*-list commands also depend on this convention. + Return the title or False if the document file does not exist. + """ + env = self.document.settings.env + title = self.titles.get(docname) + if title is None: + fname = os.path.join(env.srcdir, docname+'.rst') + try: + f = open(fname, 'r') + except IOError: + title = False + else: + for line in f: + if len(line) > 0 and (line[0].isalnum() or line[0] == '<' or line[0] == '$'): + title = line.rstrip() + break + f.close() + if title is None: + title = os.path.basename(docname) + self.titles[docname] = title + return title + + def apply(self): + env = self.document.settings.env + + # Treat some documents as cmake domain objects. + objtype, sep, tail = env.docname.partition('/') + make_index_entry = _cmake_index_objs.get(objtype) + if make_index_entry: + title = self.parse_title(env.docname) + # Insert the object link target. + if objtype == 'command': + targetname = title.lower() + else: + if objtype == 'genex': + m = CMakeXRefRole._re_genex.match(title) + if m: + title = m.group(1) + targetname = title + targetid = '%s:%s' % (objtype, targetname) + targetnode = nodes.target('', '', ids=[targetid]) + self.document.note_explicit_target(targetnode) + self.document.insert(0, targetnode) + # Insert the object index entry. + indexnode = addnodes.index() + indexnode['entries'] = [make_index_entry(title, targetid)] + self.document.insert(0, indexnode) + # Add to cmake domain object inventory + _cmake_object_inventory(env, self.document, 1, objtype, targetid) + +class CMakeObject(ObjectDescription): + + def handle_signature(self, sig, signode): + # called from sphinx.directives.ObjectDescription.run() + signode += addnodes.desc_name(sig, sig) + if self.objtype == 'genex': + m = CMakeXRefRole._re_genex.match(sig) + if m: + sig = m.group(1) + return sig + + def add_target_and_index(self, name, sig, signode): + if self.objtype == 'command': + targetname = name.lower() + else: + targetname = name + targetid = '%s:%s' % (self.objtype, targetname) + if targetid not in self.state.document.ids: + signode['names'].append(targetid) + signode['ids'].append(targetid) + signode['first'] = (not self.names) + self.state.document.note_explicit_target(signode) + _cmake_object_inventory(self.env, self.state.document, + self.lineno, self.objtype, targetid) + + make_index_entry = _cmake_index_objs.get(self.objtype) + if make_index_entry: + self.indexnode['entries'].append(make_index_entry(name, targetid)) + +class CMakeXRefRole(XRefRole): + + # See sphinx.util.nodes.explicit_title_re; \x00 escapes '<'. + _re = re.compile(r'^(.+?)(\s*)(?$', re.DOTALL) + _re_sub = re.compile(r'^([^()\s]+)\s*\(([^()]*)\)$', re.DOTALL) + _re_genex = re.compile(r'^\$<([^<>:]+)(:[^<>]+)?>$', re.DOTALL) + + def __call__(self, typ, rawtext, text, *args, **keys): + # Translate CMake command cross-references of the form: + # `command_name(SUB_COMMAND)` + # to have an explicit target: + # `command_name(SUB_COMMAND) ` + if typ == 'cmake:command': + m = CMakeXRefRole._re_sub.match(text) + if m: + text = '%s <%s>' % (text, m.group(1)) + elif typ == 'cmake:genex': + m = CMakeXRefRole._re_genex.match(text) + if m: + text = '%s <%s>' % (text, m.group(1)) + # CMake cross-reference targets frequently contain '<' so escape + # any explicit `` with '<' not preceded by whitespace. + while True: + m = CMakeXRefRole._re.match(text) + if m and len(m.group(2)) == 0: + text = '%s\x00<%s>' % (m.group(1), m.group(3)) + else: + break + return XRefRole.__call__(self, typ, rawtext, text, *args, **keys) + + # We cannot insert index nodes using the result_nodes method + # because CMakeXRefRole is processed before substitution_reference + # nodes are evaluated so target nodes (with 'ids' fields) would be + # duplicated in each evaluated substitution replacement. The + # docutils substitution transform does not allow this. Instead we + # use our own CMakeXRefTransform below to add index entries after + # substitutions are completed. + # + # def result_nodes(self, document, env, node, is_ref): + # pass + +class CMakeXRefTransform(Transform): + + # Run this transform early since we insert nodes we want + # treated as if they were written in the documents, but + # after the sphinx (210) and docutils (220) substitutions. + default_priority = 221 + + def apply(self): + env = self.document.settings.env + + # Find CMake cross-reference nodes and add index and target + # nodes for them. + for ref in self.document.traverse(addnodes.pending_xref): + if not ref['refdomain'] == 'cmake': + continue + + objtype = ref['reftype'] + make_index_entry = _cmake_index_objs.get(objtype) + if not make_index_entry: + continue + + objname = ref['reftarget'] + targetnum = env.new_serialno('index-%s:%s' % (objtype, objname)) + + targetid = 'index-%s-%s:%s' % (targetnum, objtype, objname) + targetnode = nodes.target('', '', ids=[targetid]) + self.document.note_explicit_target(targetnode) + + indexnode = addnodes.index() + indexnode['entries'] = [make_index_entry(objname, targetid, '')] + ref.replace_self([indexnode, targetnode, ref]) + +class CMakeDomain(Domain): + """CMake domain.""" + name = 'cmake' + label = 'CMake' + object_types = { + 'command': ObjType('command', 'command'), + 'cpack_gen': ObjType('cpack_gen', 'cpack_gen'), + 'envvar': ObjType('envvar', 'envvar'), + 'generator': ObjType('generator', 'generator'), + 'genex': ObjType('genex', 'genex'), + 'guide': ObjType('guide', 'guide'), + 'variable': ObjType('variable', 'variable'), + 'module': ObjType('module', 'module'), + 'policy': ObjType('policy', 'policy'), + 'prop_cache': ObjType('prop_cache', 'prop_cache'), + 'prop_dir': ObjType('prop_dir', 'prop_dir'), + 'prop_gbl': ObjType('prop_gbl', 'prop_gbl'), + 'prop_inst': ObjType('prop_inst', 'prop_inst'), + 'prop_sf': ObjType('prop_sf', 'prop_sf'), + 'prop_test': ObjType('prop_test', 'prop_test'), + 'prop_tgt': ObjType('prop_tgt', 'prop_tgt'), + 'manual': ObjType('manual', 'manual'), + } + directives = { + 'command': CMakeObject, + 'envvar': CMakeObject, + 'genex': CMakeObject, + 'variable': CMakeObject, + # Other object types cannot be created except by the CMakeTransform + # 'generator': CMakeObject, + # 'module': CMakeObject, + # 'policy': CMakeObject, + # 'prop_cache': CMakeObject, + # 'prop_dir': CMakeObject, + # 'prop_gbl': CMakeObject, + # 'prop_inst': CMakeObject, + # 'prop_sf': CMakeObject, + # 'prop_test': CMakeObject, + # 'prop_tgt': CMakeObject, + # 'manual': CMakeObject, + } + roles = { + 'command': CMakeXRefRole(fix_parens = True, lowercase = True), + 'cpack_gen': CMakeXRefRole(), + 'envvar': CMakeXRefRole(), + 'generator': CMakeXRefRole(), + 'genex': CMakeXRefRole(), + 'guide': CMakeXRefRole(), + 'variable': CMakeXRefRole(), + 'module': CMakeXRefRole(), + 'policy': CMakeXRefRole(), + 'prop_cache': CMakeXRefRole(), + 'prop_dir': CMakeXRefRole(), + 'prop_gbl': CMakeXRefRole(), + 'prop_inst': CMakeXRefRole(), + 'prop_sf': CMakeXRefRole(), + 'prop_test': CMakeXRefRole(), + 'prop_tgt': CMakeXRefRole(), + 'manual': CMakeXRefRole(), + } + initial_data = { + 'objects': {}, # fullname -> docname, objtype + } + + def clear_doc(self, docname): + to_clear = set() + for fullname, (fn, _) in self.data['objects'].items(): + if fn == docname: + to_clear.add(fullname) + for fullname in to_clear: + del self.data['objects'][fullname] + + def resolve_xref(self, env, fromdocname, builder, + typ, target, node, contnode): + targetid = '%s:%s' % (typ, target) + obj = self.data['objects'].get(targetid) + if obj is None: + # TODO: warn somehow? + return None + return make_refnode(builder, fromdocname, obj[0], targetid, + contnode, target) + + def get_objects(self): + for refname, (docname, type) in self.data['objects'].items(): + yield (refname, refname, type, docname, refname, 1) + +def setup(app): + app.add_directive('cmake-module', CMakeModule) + app.add_transform(CMakeTransform) + app.add_transform(CMakeXRefTransform) + app.add_domain(CMakeDomain) diff --git a/docs/conf.py.in b/docs/conf.py.in new file mode 100644 index 0000000..0774ef6 --- /dev/null +++ b/docs/conf.py.in @@ -0,0 +1,72 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import os +import sys +sys.path.insert(0, r'@CMAKE_CURRENT_SOURCE_DIR@') +import sphinx_rtd_theme + +# -- Project information ----------------------------------------------------- + +project = '@PROJECT_NAME@' +copyright = '2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH' + +# The full version, including alpha/beta/rc tags +version = 'latest' +release = 'latest' + + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autosectionlabel', + 'sphinx.ext.extlinks', + 'sphinx_rtd_theme', + 'sphinxemoji.sphinxemoji', + 'cmake' +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = [] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = [] + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'sphinx_rtd_theme' +html_theme_options = { + 'display_version': True, + 'collapse_navigation': False, + 'sticky_navigation': True, + 'navigation_depth': 4, + 'includehidden': True, + 'titles_only': False, +} +html_baseurl = 'https://fairrootgroup.github.io/@PROJECT_NAME@/latest' +html_title = 'FairCMakeModules %s Documentation' % release +html_short_title = '%s Documentation' % release +sphinxemoji_style = 'twemoji' + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +#html_static_path = ['_static'] diff --git a/docs/development.md b/docs/development.md deleted file mode 100644 index cf5447c..0000000 --- a/docs/development.md +++ /dev/null @@ -1,37 +0,0 @@ -# Notes for developers - -## Source Tree Structure - -* [`cmake`](../cmake): Private CMake support files for this package -* [`docs`](../docs): Place for documentation sub-pages -* [`src/modules/`](../src/modules): Modules that are automatically prepended to the `CMAKE_MODULE_PATH`. - Note: Files should be either namespaced as `Fair*` or otherwise be - unique and not conflict with others. -* [`tests`](../tests): Everything related to testing. Every test should be declared as a CTest in [`tests/CMakeLists.txt`](../tests/CMakeLists.txt). - -## Git - -* Commit messages should follow these rules: https://chris.beams.io/posts/git-commit/ -* You may add a prefix to the commit header, e.g. `README: Add new section`, or `Find: Support new version x.y.z` - -## CMake - -* Write function and macro names in lower-case letters and parameter keywords in upper-case, e.g. `list(PREPEND mylist newitem)` -* Make sure that anything you use will work in the supported CMake version range: - * For project CMake code see the top-level [`CMakeLists.txt`](../CMakeLists.txt)). Bump this minimum required version if necessary. - * For installed modules add the following header (Adapt the version as necessary): -```cmake -if(CMAKE_VERSION VERSION_LESS 3.10) - message(FATAL_ERROR "Module FairFindPackage2 requires CMake 3.10 or later!") -endif() - -include_guard(GLOBAL) -``` - -## Changelog and Releases - -* Changelog entries shall be prepared during the pull request process and added to the *Unreleased* section. -* On releases: - 1. Bump the version number adhering to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) - 2. Make a version entry in the [CHANGELOG.md](../CHANGELOG.md) and move entries from the *Unreleased* section. The relaese manager may perform additional changes to the prepared entries in an *editorial* role if it improves readibility. - 3. Create a signed and annotated tag like this: `git tag -s -a "v1.2.3" -m "Release"` diff --git a/docs/development.rst b/docs/development.rst new file mode 100644 index 0000000..9ab33e0 --- /dev/null +++ b/docs/development.rst @@ -0,0 +1,76 @@ +******************** +Notes for developers +******************** + +.. contents:: + :local: + + +Source Tree Structure +===================== + +``cmake/`` + Private CMake support files for this package +``docs/`` + Place for documentation sub-pages +``src/modules/`` + Modules that are automatically prepended to the + :cmake:variable:`CMAKE_MODULE_PATH`. + + .. note:: + + Files and functions should be either namespaced as `Fair*` or otherwise + be unique enough to minimize chances of conflicts. +``tests/`` + Everything related to testing. Every test should be declared as a + CTest in ``tests/CMakeLists.txt``. + + +Git +=== + +* Commit messages should follow these rules: https://chris.beams.io/posts/git-commit/ +* You may add a prefix to the commit header, e.g. + + * ``README: Add new section``, or + * ``Find: Support new version x.y.z`` + + +CMake +===== + +* Write function and macro names in lower-case letters and parameter keywords + in upper-case, e.g. ``list(PREPEND mylist newitem)`` +* Make sure that anything you use will work in the supported CMake version + range: + + * For project CMake code see the top-level ``CMakeLists.txt``. Bump this + minimum required version if necessary. + * For installed modules add the following header (Adapt the version as + necessary): + +.. code-block:: cmake + + if(CMAKE_VERSION VERSION_LESS 3.12) + message(FATAL_ERROR "Module FairFindPackage2 requires CMake 3.12 or later!") + endif() + + include_guard(GLOBAL) + + +Changelog and Releases +====================== + +* Changelog entries shall be prepared during the pull request process and added + to the *Unreleased* section. +* On releases: + + 1. Bump the version number adhering to `Semantic Versioning`_ + 2. Make a version entry in the ``CHANGELOG.rst`` and move entries from the + *Unreleased* section. The release manager may perform additional changes + to the prepared entries in an *editorial* role if it improves readibility. + 3. Create a signed and annotated tag like this: + ``git tag -s -a "v1.2.3" -m "Release"`` + + +.. _`Semantic Versioning`: https://semver.org/spec/v2.0.0.html diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..717ca98 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,30 @@ +**************** +FairCMakeModules +**************** + +This project maintains CMake Modules developed in the context of various `FAIR`_ software projects. + +.. _`FAIR`: https://www.gsi.de/en/researchaccelerators/fair + +.. toctree:: + :caption: General + :maxdepth: 1 + + /installation + /usage + /license + /changelog + +.. toctree:: + :caption: Modules + :maxdepth: 1 + :glob: + + /module/* + +.. toctree:: + :caption: Contributing + :maxdepth: 1 + + /issues + /development diff --git a/docs/installation.rst b/docs/installation.rst new file mode 100644 index 0000000..10e9531 --- /dev/null +++ b/docs/installation.rst @@ -0,0 +1,58 @@ +************ +Installation +************ + +.. toctree:: + :caption: Installation + +.. contents:: + :local: + + +From Source +=========== + +Download the source code with `Git`_ :: + + git clone https://github.com/FairRootGroup/FairCMakeModules + +and install with `CMake`_ :: + + cmake -S FairCMakeModules -B -DCMAKE_INSTALL_PREFIX= + cmake --build --target install + +Replace ```` and ```` with directories of your choice. + + +macOS +===== + +Install `Homebrew for macOS`_ and enable the FairSoft `tap`_ :: + + brew tap fairrootgroup/fairsoft + +and continue with :: + + brew install faircmakemodules + +Find the ``brew`` package formula `here `_. + + +Fedora +====== + +Add the FairSoft RPM repository for Fedora 34 :: + + sudo dnf install https://alfa-ci.gsi.de/packages/rpm/fedora-34-x86_64/fairsoft-release-dev.rpm + +and continue with :: + + sudo dnf install faircmakemodules + +Find the RPM package source `here `_. + + +.. _Git: https://git-scm.com/ +.. _CMake: https://cmake.org/ +.. _Homebrew for macOS: https://brew.sh/ +.. _tap: https://docs.brew.sh/Taps diff --git a/docs/issues.rst b/docs/issues.rst new file mode 100644 index 0000000..72a2133 --- /dev/null +++ b/docs/issues.rst @@ -0,0 +1,6 @@ +********************************* +Bugs, Questions, Feature Requests +********************************* + +Contact us for bug/issue reports, feature requests, and questions by `creating +an issue on github `_. diff --git a/docs/license.rst b/docs/license.rst new file mode 100644 index 0000000..c9ece29 --- /dev/null +++ b/docs/license.rst @@ -0,0 +1,14 @@ +******* +License +******* + +.. toctree:: + :caption: License + + +Copyright (C) 2018-present GSI Helmholtzzentrum fuer Schwerionenforschung GmbH + +This software is distributed under the terms of the GNU Lesser General +Public Licence (LGPL) version 3, copied verbatim in the file `LICENSE`_ + +.. _LICENSE: https://github.com/FairRootGroup/FairCMakeModules/blob/main/LICENSE diff --git a/docs/module/FairFindPackage2.rst b/docs/module/FairFindPackage2.rst new file mode 100644 index 0000000..caae4b7 --- /dev/null +++ b/docs/module/FairFindPackage2.rst @@ -0,0 +1,2 @@ +.. default-domain:: cmake +.. cmake-module:: ../../src/modules/FairFindPackage2.cmake.in diff --git a/docs/module/FairFormattedOutput.rst b/docs/module/FairFormattedOutput.rst new file mode 100644 index 0000000..f66ba0c --- /dev/null +++ b/docs/module/FairFormattedOutput.rst @@ -0,0 +1,5 @@ +******************* +FairFormattedOutput +******************* + +**TODO** diff --git a/docs/usage.rst b/docs/usage.rst new file mode 100644 index 0000000..02743eb --- /dev/null +++ b/docs/usage.rst @@ -0,0 +1,5 @@ +***** +Usage +***** + +**TODO** diff --git a/src/modules/FairFindPackage2.cmake.in b/src/modules/FairFindPackage2.cmake.in index 29b11f1..38546b8 100644 --- a/src/modules/FairFindPackage2.cmake.in +++ b/src/modules/FairFindPackage2.cmake.in @@ -12,29 +12,73 @@ endif() include_guard(GLOBAL) -# -# find_package2(PRIVATE|PUBLIC|INTERFACE|BUNDLED -# [VERSION ] -# [COMPONENTS ] -# [any other option the native find_package supports]...) -# -# Wrapper around CMake's native find_package command to add some features and bookkeeping. -# -# The qualifier (PRIVATE|PUBLIC|INTERFACE|BUNDLED) to the package to populate -# the variables PROJECT_[INTERFACE]__([VERSION]|[COMPONENTS]|PACKAGE_DEPENDENCIES) -# accordingly. This bookkeeping information is used to print our dependency found summary -# table and to generate a part of our CMake package. BUNDLED decays to PUBLIC if the variable -# _BUNDLED is false and to PRIVATE otherwise. -# -# When a dependending package is listed with ADD_REQUIREMENTS_OF the variables -# __VERSION|COMPONENTS are looked up to and added to the native -# VERSION (selected highest version) and COMPONENTS (deduplicated) args. -# -# COMPONENTS and VERSION args are then just passed to the native find_package. -# -# The ADD_REQUIREMENTS_OF argument is now a no-op and only remains for compatibility -# reasons. find_package2 now always merges all known requirements. -# +#[=======================================================================[.rst: +**************** +FairFindPackage2 +**************** +.. versionadded:: 0.1.0 + +Requires CMake 3.12 or later. + +.. contents:: + :local: + +--------- + +On inclusion +============ + +.. versionadded:: 0.2.0 + +Add this module as a ``PRIVATE`` package dependency if included from the +@PROJECT_NAME@ package. + +#]=======================================================================] + +if(@PROJECT_NAME@_FOUND) + list(APPEND PROJECT_PACKAGE_DEPENDENCIES @PROJECT_NAME@) +endif() + +#[=======================================================================[.rst: +--------- + +``find_package2()`` +=================== + +Wrapper around CMake's native :command:`find_package` command to add some +features and bookkeeping. + +.. code-block:: cmake + + find_package2(PRIVATE|PUBLIC|INTERFACE|BUNDLED + [VERSION ] + [COMPONENTS [...]] + [ADD_REQUIREMENTS_OF [...]] + [...]) + + +The qualifier (\ ``PRIVATE|PUBLIC|INTERFACE|BUNDLED``\ ) is used to +populate the variables +:variable:`PROJECT_[INTERFACE]__([VERSION]|[COMPONENTS]|PACKAGE_DEPENDENCIES)` +accordingly. This bookkeeping information is used to print a dependencies +found summary table and in the generation of a CMake package. ``BUNDLED`` +decays to ``PUBLIC`` if the variable `_BUNDLED` is false and to +``PRIVATE`` otherwise. + +When a dependending package is listed with ``ADD_REQUIREMENTS_OF`` the +variables :variable:`__VERSION|COMPONENTS` are looked +up and merged with ``VERSION`` (selected highest version) and ``COMPONENTS`` +(deduplicated) requirements. ``COMPONENTS`` and ``VERSION`` args are then +just passed to :command:`find_package`. + +.. versionchanged:: 0.2.0 + +The ``ADD_REQUIREMENTS_OF`` argument is now a no-op and only remains for +compatibility reasons. :command:`find_package2` now always merges all known +requirements. + +#]=======================================================================] + macro(find_package2 qualifier pkgname) cmake_parse_arguments(ARGS "" "VERSION" "COMPONENTS;ADD_REQUIREMENTS_OF" ${ARGN}) @@ -119,10 +163,25 @@ macro(find_package2 qualifier pkgname) unset(__old_cpp__) endmacro() +#[=======================================================================[.rst: +--------- + +``find_package2_implicit_dependencies()`` +========================================= + +.. versionadded:: 0.2.0 + +Loop over all remaining implicit dependencies and :command:`find_package2` +them. + +.. code-block:: cmake + + find_package2_implicit_dependencies([EXCLUDE [...]]) + +Listed packages with ``EXCLUDE`` are filtered out. + +#]=======================================================================] -# -# Loop over all remaining implicit dependencies and "find_package2" them. -# macro(find_package2_implicit_dependencies) cmake_parse_arguments(ARGS "" "" "EXCLUDE" ${ARGN}) @@ -160,21 +219,25 @@ macro(find_package2_implicit_dependencies) unset(__2_components__) endmacro() +#[=======================================================================[.rst: +--------- -# Add oneself as PRIVATE package if used from the @PROJECT_NAME@ package -if(@PROJECT_NAME@_FOUND) - list(APPEND PROJECT_PACKAGE_DEPENDENCIES @PROJECT_NAME@) -endif() +``fair_generate_package_dependencies()`` +======================================== + +.. versionadded:: 0.2.0 + +.. code-block:: cmake + + find_generate_package_dependencies() + +Populates the variable :variable:`PACKAGE_DEPENDENCIES` with a CMake snippet +from the public dependencies (read from +:variable:`PROJECT_INTERFACE_PACKAGE_DEPENDENCIES`) that can be included in a +CMake package config file to export its package dependencies. +#]=======================================================================] -# -# fair_generate_package_dependencies() -# -# From the public dependencies (marked using find_package2) -# generate a snippet (PACKAGE_DEPENDENCIES) that can be -# included in a cmake package *Config.cmake to export the -# needs of the current package -# function(fair_generate_package_dependencies) list(JOIN PROJECT_INTERFACE_PACKAGE_DEPENDENCIES " " DEPS) set(PACKAGE_DEPENDENCIES "\