Our Project

Introduction

The GF2++ project is stored in a git repository the following structure:

GF2
├── .git/...
├── README.adoc
├── LICENSE
├── CMakeLists.txt                      (1)
├── include
│   └── GF2                             (2)
│       ├── GF2.h
│       ├── Matrix.h
│       ├── Vector.h
│       ├── Matrix.h
│       ├── assert.h
│       └── ...
├── examples/...                        (3)
├── docs                                (4)
│   ├── reference-manual/...
│   ├── documentation-strategy/...
│   └── technical-notes/...
└── ...
1 All the library example and test programs are built using CMake which is the defacto standard for C++ projects.
2 This is a header-only library and the principal source code is in the include/GF2/ directory.
3 We provide lots of example programs that exercise various features of the library.
4 There are three documentation modules provided for the library each in its own subdirectory as shown.
The Main Headers

Before we talk in more detail about the documentation we should mention that the library really has just two substantial headers Vector.h and Matrix.h. That assert.h is a short helper file defining macros used do optional assertions such as bounds checking primarily for debug builds. The library ha some headers than this but for the purposes of this discussion we will stick to those.

There is a convenience header GF2.h that just includes all the others. So, assuming your include path allows it, you use the library by just adding one line include <GF2/GF2.h> to the top of your program.

Documentation Layout

As you can see there are three separate modules in the docs/ directory:

  • You are reading content from the documentation-strategy.

  • The technical-notes module is definitely for “extra credit” as it contains some mathematical papers that go into the gory underpinnings of the library and its algorithms.

  • Finally we have reference-manual which is by far the largest and most important module.

The /docs/reference-manual/pages/ directory closely mimics the layout of the library source code in the /include/GF2/ directory. That pages/ directory looks somethings like:

docs/reference-manual
├── nav.adoc
└── pages
    ├── assert
    │   ├── assert.adoc
    ├── Matrix
    │   ├── Matrix.adoc
    │   ├── access.adoc
    │   ├── ...
    │   └── triangle.adoc
    ├── Vector
    │   ├── Vector.adoc
    │   ├── access.adoc
    │   ├── ...
    │   └── to_string.adoc
    ├── assert
    │   └── assert.adoc
    └── overview.adoc

The documentation is in the form of AsciiDoc files stored under the pages/ subdirectory. This layout makes it possible to easily use the static website builder Antora.

The pages/overview.adoc file introduces the library as a whole (this corresponds to the usual index.html for a website). Then each class and macro in GF2++ has a corresponding documentation sub-directory in pages/.

For example, the fairly trivial <GF2/assert.h> header just defines the three related assert style macros and those are all documented in the one assert.adoc file.

In contrast, the GF2::Vector and GF2::Matrix classes have a large number of associated methods and quite a few documentation files. Rather than having one documentation file per method we instead group methods and functions together where it logically makes sense for them to share a single file.

For example, the Vector/access.adoc file documents both GF2::Vector::operator()(i) methods, both GF2::Vector::operator[](i) methods, as well as the GF2::Vector::test(i) method. These are grouped together because each provides access to the individual element at a given index i in a bit-vector. The signature for each of the five is explained, how bounds checking can be enabled for the index, and the access.adoc file includes a short sample code that exercises the methods and the output from that code is shown. The user should be able to copy-paste that snippet, compile, and reproduce the shown results.

The main entry point for documenting the GF2::Vector class is the file Vector/Vector.adoc and for the GF2::Matrix class it is Matrix/Matrix.adoc. Those two files lay out the overall rationale behind the classes as well as providing links to all the other documentation in a nice table format.

The whole effect is quite similar to what you get if say you look up std::vector at CPP Reference/vector.

Repository Structure

Expanding a little on our earlier picture the GF2++ repo now looks something like:

GF2
├── .git/...
├── CMakeLists.txt
├── README.adoc
├── antora/...                          (1)
├── include
│   └── GF2                             (2)
│       ├── GF2.h
│       ├── Matrix.h
│       ├── Vector.h
│       ├── Matrix.h
│       ├── assert.h
│       └── ...
├── examples/...
├── docs                                (3)
│   ├── documentation-strategy/...
│   ├── reference-manual
│   │   ├── nav.adoc
│   │   └── pages                       (4)
│   │       ├── Matrix
│   │       │   ├── Matrix.adoc         (5)
│   │       │   ├── access.adoc
│   │       │   ├── ...
│   │       │   └── triangle.adoc
│   │       ├── Vector
│   │       │   ├── Vector.adoc         (6)
│   │       │   ├── access.adoc
│   │       │   ├── ...
│   │       │   └── to_string.adoc
│   │       ├── assert
│   │       │   └── assert.adoc         (7)
│   │       └── overview.adoc           (8)
│   └── technical-notes/...
│   └── common.adoc                     (9)
└── ...
1 We’ll discuss the antora/ directory in the next section below.
2 The source code for this header-only library is all in include/GF2/.
3 The docs/ subdirectory has the documentation content in three modules discussed above.
4 Inside a module the content is primarily stored in its pages/ subdirectory (there might be an images/ subdirectory also.).
5 The Matrix.adoc file has the overview of the GF2::Matrix class. The many other files in this directory document groups of related class methods and functions.
6 There is a similar structure for the GF2::Vector class.
7 There is a similar structure for the gf2_assert macros.
8 The reference-manual/pages/overview.adoc file introduces the library as a whole.
9 This common.adoc file has some AsciiDoc attributes/settings for all the documentation. Most of the .adoc files in the tree include this at the top.
We make use of common.adoc to set a few attributes for most of our AsciiDoc files. These include the copyright notice and a couple of items that make Antora and a simpler AsciiDoc previewer work nicely together.

We usually write content in an editor that autosaves and simultaneously preview just that one document in a browser with an AsciiDoc plugin installed. This is very fast but the browser based plugin is not as sophisticated as Antora so needs a bit of help to understand what those Antora family directories can be found.

Antora

The top level docs/ directory is organized in a natural manner though we have made an effort to keep it compatible with the way Antora would like things. In particular, we have split the documentation into modules and then under each module stored the actual AsciiDoc content under a pages/ subdirectory, images under an images/ subdirectory and so on.

As we mentioned earlier, adhering to this structure isn’t really much of a constraint. Even if we move away from Antora as our website builder it shouldn’t be hard to map this particular docs/ organization in to whatever is required by the replacement.

It does seem very sensible to keep the Antora specific parameter files, build instructions, needed support tools etc. in their own sandbox. In fact, the Antora documentation suggests having a completely separate repo for all that stuff. For a small library like ours that seems a bit of an overkill so instead we settled for having a dedicated antora/ directory at the top of the repo which looks like:

GF2/antora
├── antora.yml                  (1)
├── modules -> ../docs          (2)
├── UI                          (3)
│   └── supplemental-ui/...
├── antora-playbook.yml         (4)
└── antora-playbook-local.yml   (5)
├── build/...                   (6)
├── Makefile                    (7)
├── package-lock.json
├── package.json                (8)
├── README.adoc                 (9)
├── netlify/...                 (10)
1 This GF2/antora/ directory is an Antora component so has an antora.yml file and a modules/ subdirectory.
2 The modules/ subdirectory is really just a symbolic link to the actual documentation tree at the top of the repo. Antora handles symlinks just fine.
3 The UI/ subdirectory has all the assets that define the look and feel of the website. In our case we are using the default UI to just need to override a few items in UI/supplemental-ui to get that to work.
4 The playbook tells Antora how to build the website. This master antora-playbook.yml file tells Antora to pull the documentation from the remote repo which in our case is hosted on GitLab.
5 This antora-playbook-local.yml version instructs Antora to use the content from the local machine which is handy when you are developing the documentation. It is actually created on the fly from the master playbook so does not need to be checked in to git.
6 No matter which playbook you use Antora will be told to build the website in this local build/ subdirectory.
7 The Makefile can be used to invoke Antora correctly (so make local to invoke it on the local playbook and make remote to invoke it on the remote playbook). It can also be used to keep the two playbooks in sync.
8 We pull in Antora itself and any needed extensions using npm which is configured in package.json.
9 There is a README file to explain all of this.
10 The production version of the Antora built site is hosted by netlify. There is a job set up on netlify to invoke Antora automatically and deploy the site — various configuration parameters for that job are in this subdirectory.
Our antora-playbook.yml file
runtime:                            (1)
  cache_dir: ./.cache/antora
  log:
    failure_level: warn

site:                               (2)
  title: The GF2++ Class Library
  start_page: gf2pp:reference-manual:overview.adoc
  robots: allow
  keys:
    google_analytics: 'G-KMH2PCJ214'  (3)

content:                              (4)
  edit_url: false
  sources:
    - url: https://gitlab.com/nzzn/gf2.git
      start_path: antora

asciidoc:                             (5)
  attributes:
    experimental:

ui:                                   (6)
  bundle:
    url: https://gitlab.com/antora/antora-ui-default/-/jobs/artifacts/HEAD/raw/build/ui-bundle.zip?job=bundle-stable
    snapshot: true
  supplemental_files: ./UI/supplemental-ui

antora:                               (7)
  extensions:
    - "@antora/lunr-extension"

output:                               (8)
  dir: ./build
1 Set up the overall level of logging and get Antora to cache things between builds.
2 Set the documentation site’s title and the landing page. Happy to have the site crawled by search engines.
3 Antora can embed keys/tags in the website pages (see how we use this one below).
4 Repo to pull the documentation component from and its location in that repo.
5 Antora can pass along attributes to AsciiDoc.
6 We are using the default UI and overrode a few things to personalize that.
7 We use lunr to build a search index for the site & use the Antora lunr extension to invoke it.
8 Tell Antora to put the built site into this directory.
This project’s docs are deployed on the free version of netlify which doesn’t give feedback on how busy the site is. However, we can use Google Analytics to get at that data. For obvious reasons Google Analytics requires that you prove a site is yours before they hand over any data about its traffic. They do that by asking you to embed some personalized tags in all the pages. If you give Antora the appropriate key which is public anyway it can do that job for you at build time.