Commit 59834db472101b3577f530c7fb3f991d28518b80
1 parent
ece6b6fe
Add documentation for code formatting and contribution guidelines
Showing
6 changed files
with
208 additions
and
55 deletions
README-maintainer
| ... | ... | @@ -119,6 +119,10 @@ GOOGLE OSS-FUZZ |
| 119 | 119 | |
| 120 | 120 | CODING RULES |
| 121 | 121 | |
| 122 | +* Code is formatted with clang-format >= 15. See .clang-format and the | |
| 123 | + "Code Formatting" section in manual/contributing.rst for details. | |
| 124 | + See also "CODE FORMATTING" below. | |
| 125 | + | |
| 122 | 126 | * In a source file, include the header file that declares the source |
| 123 | 127 | class first followed by a blank line. If a config file is needed |
| 124 | 128 | first, put a blank line between that and the header followed by |
| ... | ... | @@ -562,3 +566,36 @@ The check_abi script is responsible for performing many of these |
| 562 | 566 | steps. See comments in check_abi for additional notes. Running |
| 563 | 567 | "check_abi check-sizes" is run by ctest on Linux when CHECK_SIZES is |
| 564 | 568 | on. |
| 569 | + | |
| 570 | + | |
| 571 | +CODE FORMATTING | |
| 572 | + | |
| 573 | +* Emacs doesn't indent breaking strings concatenated with + over | |
| 574 | + lines but clang-format does. It's clearer with clang-format. To | |
| 575 | + get emacs and clang-format to agree, parenthesize the expression | |
| 576 | + that builds the concatenated string. | |
| 577 | + | |
| 578 | +* With | |
| 579 | + | |
| 580 | + long_function(long_function( | |
| 581 | + args) | |
| 582 | + | |
| 583 | + clang-format anchors relative to the first function, and emacs | |
| 584 | + anchors relative to the second function. Use | |
| 585 | + | |
| 586 | + long_function( | |
| 587 | + // line-break | |
| 588 | + long_function( | |
| 589 | + args) | |
| 590 | + | |
| 591 | + to resolve. | |
| 592 | + | |
| 593 | +In the revision control history, there is a commit around April 3, | |
| 594 | +2022 with the title "Update some code manually to get better | |
| 595 | +formatting results" that shows several examples of changing code so | |
| 596 | +that clang-format produces several results. (In git this is commit | |
| 597 | +77e889495f7c513ba8677df5fe662f08053709eb.) | |
| 598 | + | |
| 599 | +The commit that has the bulk of the automatic reformatting is | |
| 600 | +12f1eb15ca3fed6310402847559a7c99d3c77847. This could go in a | |
| 601 | +blame.ignoreRevsFile file for `git blame` if needed. | ... | ... |
TODO
| ... | ... | @@ -6,7 +6,6 @@ Next |
| 6 | 6 | |
| 7 | 7 | In order: |
| 8 | 8 | * cmake |
| 9 | -* code formatting | |
| 10 | 9 | * PointerHolder -> shared_ptr |
| 11 | 10 | * ABI including --json default is latest |
| 12 | 11 | * json v2 |
| ... | ... | @@ -38,60 +37,6 @@ Misc |
| 38 | 37 | |
| 39 | 38 | Soon: Break ground on "Document-level work" |
| 40 | 39 | |
| 41 | -Code Formatting | |
| 42 | -=============== | |
| 43 | - | |
| 44 | -Document about code formatting: | |
| 45 | - | |
| 46 | -* Use clang-format-15. | |
| 47 | -* Update README-maintainer about formatting. Mention | |
| 48 | - | |
| 49 | - // clang-format off | |
| 50 | - // clang-format on | |
| 51 | - | |
| 52 | - as well as the use of a comment to force a line break. Convention: | |
| 53 | - // line-break | |
| 54 | - | |
| 55 | -* .dir-locals.el -- most of the time, emacs's formatting agrees with | |
| 56 | - clang-format. When they differ, clang-format is authoritative. | |
| 57 | - Significant differences: | |
| 58 | - * clang-format-15 bug that when | |
| 59 | - | |
| 60 | - type function(args) | |
| 61 | - | |
| 62 | - is longer than 80 characters, the continuation line rule takes | |
| 63 | - precedence over the break after type rule and the function ends | |
| 64 | - getting intended. (Find an example and report.) | |
| 65 | - * Emacs doesn't indent breaking strings concatenated with + over | |
| 66 | - lines but clang-format does. It's clearer with clang-format. To | |
| 67 | - get emacs and clang-format to agree, parenthesize the expression | |
| 68 | - that builds the concatenated string. | |
| 69 | - * With | |
| 70 | - | |
| 71 | - long_function(long_function( | |
| 72 | - args) | |
| 73 | - | |
| 74 | - clang-format anchors relative to the first function, and emacs | |
| 75 | - anchors relative to the second function. Use | |
| 76 | - | |
| 77 | - long_function( | |
| 78 | - // line-break | |
| 79 | - long_function( | |
| 80 | - args) | |
| 81 | - | |
| 82 | - to resolve. | |
| 83 | -* Consider blame.ignoreRevsFile if it seems to help | |
| 84 | -* Add a script to format the code. | |
| 85 | - | |
| 86 | - for i in **/*.cc **/*.c **/*.h **/*.hh; do | |
| 87 | - clang-format < $i >| $i.new && mv $i.new $i | |
| 88 | - done | |
| 89 | - | |
| 90 | -* Consider a github action to check formatting. I don't want | |
| 91 | - formatting failures to prevent all the tests from being run. | |
| 92 | - Alternatively, add running the format script as a release | |
| 93 | - preparation check like running the spell checker. | |
| 94 | - | |
| 95 | 40 | cmake |
| 96 | 41 | ===== |
| 97 | 42 | ... | ... |
libqpdf/sph/sph_types.h.new
0 โ 100644
manual/CMakeLists.txt
manual/contributing.rst
0 โ 100644
| 1 | +.. _contributing: | |
| 2 | + | |
| 3 | +Contributing to qpdf | |
| 4 | +==================== | |
| 5 | + | |
| 6 | +.. _source-repository: | |
| 7 | + | |
| 8 | +Source Repository | |
| 9 | +----------------- | |
| 10 | + | |
| 11 | +The qpdf source code lives at https://github.com/qpdf/qpdf. | |
| 12 | + | |
| 13 | +Create issues (bug reports, feature requests) at | |
| 14 | +https://github.com/qpdf/qpdf/issues. If you have a general question or | |
| 15 | +topic for discussion, you can create a discussion at | |
| 16 | +https://github.com/qpdf/qpdf/discussions. | |
| 17 | + | |
| 18 | +.. _code-formatting: | |
| 19 | + | |
| 20 | +Code Formatting | |
| 21 | +--------------- | |
| 22 | + | |
| 23 | +The qpdf source code is formatting using clang-format โฅ version 15 | |
| 24 | +with a :file:`.clang-format` file at the top of the source tree. The | |
| 25 | +:file:`format-code` script reformats all the source code in the | |
| 26 | +repository. You must have ``clang-format`` in your path, and it must be | |
| 27 | +at least version 15. | |
| 28 | + | |
| 29 | +For emacs users, the :file:`.dir-locals.el` file configures emacs | |
| 30 | +``cc-mode`` for an indentation style that is similar to but not | |
| 31 | +exactly like what ``clang-format`` produces. When there are | |
| 32 | +differences, ``clang-format`` is authoritative. It is not possible to | |
| 33 | +make ``cc-mode`` and ``clang-format`` exactly match since the syntax | |
| 34 | +parser in emacs is not as sophisticated. | |
| 35 | + | |
| 36 | +Blocks of code that should not be formatted can be surrouned by the | |
| 37 | +comments ``// clang-format off`` and ``// clang-format on``. Sometimes | |
| 38 | +clang-format tries to combine lines in ways that are undesirable. In | |
| 39 | +this case, we follow a convention of adding a comment ``// | |
| 40 | +line-break`` on its own line. | |
| 41 | + | |
| 42 | +For exact details, consult :file:`.clang-format`. Here is a broad, | |
| 43 | +partial summary of the formatting rules: | |
| 44 | + | |
| 45 | +- Use spaces, not tabs. | |
| 46 | + | |
| 47 | +- Keep lines to 80 columns when possible. | |
| 48 | + | |
| 49 | +- Braces are on their own lines after classes and functions (and | |
| 50 | + similar top-level constructs) and are compact otherwise. | |
| 51 | + | |
| 52 | +- Closing parentheses are attached to the previous material, not not | |
| 53 | + their own lines. | |
| 54 | + | |
| 55 | +The :file:`README-maintainer` file has a few additional notes that are | |
| 56 | +probably not important to anyone who is not making deep changes to | |
| 57 | +qpdf. | |
| 58 | + | |
| 59 | +.. _automated-testing: | |
| 60 | + | |
| 61 | +Automated Tests | |
| 62 | +--------------- | |
| 63 | + | |
| 64 | +The testing style of qpdf has evolved over time. More recent tests | |
| 65 | +call ``assert()``. Older tests print stuff to standard output and | |
| 66 | +compare the output against reference files. Many tests are a mixture | |
| 67 | +of these techniques. | |
| 68 | + | |
| 69 | +The `qtest <https://qtest.sourceforge.io>`__ style of testing is to | |
| 70 | +test everything through the application. So effectively most testing | |
| 71 | +is "integration testing" or "end-to-end testing". | |
| 72 | + | |
| 73 | +For details about ``qtest``, consult the `QTest Manual | |
| 74 | +<https://qtest.sourceforge.io/doc/qtest-manual.html>`__. As you read | |
| 75 | +it, keep in mind that, in spite of the recent date on the file, the | |
| 76 | +vast majority of that documentation is from before 2007 and predates | |
| 77 | +many test frameworks and approaches that are in use today. | |
| 78 | + | |
| 79 | +Notes on testing: | |
| 80 | + | |
| 81 | +- In most cases, things in the code are tested through integration | |
| 82 | + tests, though the test suite is very thorough. Many tests are driven | |
| 83 | + through the ``qpdf`` CLI. Others are driven through other files in | |
| 84 | + the ``qpdf`` directory, especially ``test_driver.cc`` and | |
| 85 | + ``qpdf-ctest.c``. These programs only use the public API. | |
| 86 | + | |
| 87 | +- In some cases, there are true "unit tests", but they are exercised | |
| 88 | + through various stand-alone programs that exercise the library in | |
| 89 | + particular ways, including some that have access to library | |
| 90 | + internals. These are in the ``libtests`` directory. | |
| 91 | + | |
| 92 | +Coverage | |
| 93 | +~~~~~~~~ | |
| 94 | + | |
| 95 | +You wil see calls to ``QTC::TC`` throughout the code. This is a | |
| 96 | +"manual coverage" system described in depth in the qtest documentation | |
| 97 | +linked above. It works by ensuring that ``QTC::TC`` is called sometime | |
| 98 | +during the test in each configured way. In brief: | |
| 99 | + | |
| 100 | +- ``QTC::TC`` takes two mandatory options and an optional one: | |
| 101 | + | |
| 102 | + - The first two arguments must be *string literals*. This is because | |
| 103 | + ``qtest`` finds coverage cases lexically. | |
| 104 | + | |
| 105 | + - The first argument is the scope name, usually ``qpdf``. This means | |
| 106 | + there is a ``qpdf.testcov`` file in the source directory. | |
| 107 | + | |
| 108 | + - The second argument is a case name. Each case name appears in | |
| 109 | + ``qpdf.testcov`` with a number after it, usually ``0``. | |
| 110 | + | |
| 111 | + - If the third argument is present, it is a number. ``qtest`` | |
| 112 | + ensures that the ``QTC::TC`` is called for that scope and case at | |
| 113 | + least once with the third argument set to every value from ``0`` | |
| 114 | + to ``n`` inclusive, where ``n`` is the number after the coverage | |
| 115 | + call. | |
| 116 | + | |
| 117 | +- ``QTC::TC`` does nothing unless certain environment variables are | |
| 118 | + set. Therefore, ``QTC:TC`` calls should have no side effects. (In | |
| 119 | + some languages, they may be disabled at compile-time, though qpdf | |
| 120 | + does not actually do this.) | |
| 121 | + | |
| 122 | +So, for example, if you have this code: | |
| 123 | + | |
| 124 | +.. code-block:: C++ | |
| 125 | + | |
| 126 | + QTC::TC("qpdf", "QPDF eof skipping spaces before xref", | |
| 127 | + skipped_space ? 0 : 1); | |
| 128 | + | |
| 129 | + | |
| 130 | +and this line in `qpdf.testcov`: | |
| 131 | + | |
| 132 | +:: | |
| 133 | + | |
| 134 | + QPDF eof skipping spaces before xref 1 | |
| 135 | + | |
| 136 | +the test suite will only pass if that line of code was called at least | |
| 137 | +once with ``skipped_space == 0`` and at least once with ``skipped_space | |
| 138 | +== 1``. | |
| 139 | + | |
| 140 | +The manual coverage approach ensures the reader that certain | |
| 141 | +conditions were covered in testing. Use of ``QTC::TC`` is only part of | |
| 142 | +the overall strategy. | |
| 143 | + | |
| 144 | +I do not require testing on pull requests, but they are appreciated, | |
| 145 | +and I will not merge any code that is not tested. Often someone will | |
| 146 | +submit a pull request that is not adequately tested but is a good | |
| 147 | +contribution. In those cases, I will often take the code, add it with | |
| 148 | +tests, and accept the changes that way rather than merging the pull | |
| 149 | +request as submitted. | |
| 150 | + | |
| 151 | +Personal Comments | |
| 152 | +----------------- | |
| 153 | + | |
| 154 | +QPDF started as a work project in 2002. The first open source release | |
| 155 | +was in 2008. While there have been a handful of contributors, the vast | |
| 156 | +majority of the code was written by one person over many years as a | |
| 157 | +side project. | |
| 158 | + | |
| 159 | +I maintain a very strong commitment to backward compatibility. As | |
| 160 | +such, there are many aspects of the code that are showing their age. | |
| 161 | +While I believe the codebase to have high quality, there are things | |
| 162 | +that I would do differently if I were doing them from scratch today. | |
| 163 | +Sometimes people will suggest changes that I like but can't accept for | |
| 164 | +backward compatibility reasons. | |
| 165 | + | |
| 166 | +While I welcome contributions and am eager to collaborate with | |
| 167 | +contributors, I have a high bar. I only accept things I'm willing to | |
| 168 | +maintain over the long haul, and I am happy to help people get | |
| 169 | +submissions into that state. | ... | ... |