1# Contributing to Boost.GIL 2 3Boost.GIL is a member of [Boost](https://www.boost.org) libraries. 4 5If you wish to contribute a new feature or a bug fix, 6please follow the workflow explained in this document. 7 8## Table of Content 9 10- [Prerequisites](#prerequisites) 11- [Pull Requests](#pull-requests) 12- [Getting started with Git workflow](#getting-started-with-git-workflow) 13 - [1. Clone Boost super-project](#1-clone-boost-super-project) 14 - [2. Checkout Boost.GIL development branch](#2-checkout-boostgil-development-branch) 15 - [3. Fork Boost.GIL repository on GitHub](#3-fork-boostgil-repository-on-github) 16 - [4. Submit a pull request](#4-submit-a-pull-request) 17 - [5. Update your pull request](#5-update-your-pull-request) 18- [Development](#development) 19 - [Install dependencies](#install-dependencies) 20 - [Using Boost.Build](#using-boostbuild) 21 - [Using CMake](#using-cmake) 22 - [Running clang-tidy](#running-clang-tidy) 23- [Guidelines](#guidelines) 24 25## Prerequisites 26 27- C++11 compiler 28- Build and run-time dependencies for tests and examples: 29 - Boost.Filesystem 30 - Boost.Test 31 - Headers and libraries of libjpeg, libpng, libtiff, libraw for the I/O extension. 32- Experience with `git` command line basics. 33- Familiarity with build toolset and development environment of your choice. 34- Although this document tries to present all commands with necessary options, 35 it may be a good idea to skim through the 36 [Boost Getting Started](https://www.boost.org/more/getting_started/index.html) 37 chapters, especially if you are going to use 38 [Boost.Build](https://boostorg.github.io/build/) for the first time. 39 40## Pull Requests 41 42- **DO** base your work against the `develop` branch, not the `master`. 43- **DO** submit all major changes to code via pull requests (PRs) rather than through 44 a direct commit. PRs will be CI-checked first, then reviewed and potentially merged 45 by the repo maintainers after a peer review that includes at least one maintainer. 46 Contributors with commit access may submit trivial patches or changes to the project 47 infrastructure configuration via direct commits (CAUTION!) 48- **DO NOT** mix independent, unrelated changes in one PR. 49 Separate unrelated fixes into separate PRs, especially if they are in different components 50 (e.g. core headers versus extensions). 51 Separate real product/test code changes from larger code formatting/dead code removal changes, 52 unless the former are extensive enough to justify such refactoring, then also mention it. 53- **DO** start PR subject with "WIP:" tag if you submit it as "work in progress". 54 A PR should preferably be submitted when it is considered ready for review and subsequent 55 merging by the contributor. Otherwise, clearly indicate it is not yet ready. 56 The "WIP:" tag will also help maintainers to label your PR with [status/work-in-progress]. 57- **DO** give PRs short-but-descriptive names (e.g. "Add test for algorithm XXX", not "Fix #1234"). 58- **DO** [refer] to any relevant issues, and include the [keywords] that automatically 59 close issues when the PR is merged. 60- **DO** [mention] any users that should know about and/or review the change. 61- **DO** ensure each commit successfully builds. The entire PR must pass all tests in 62 the Continuous Integration (CI) system before it'll be merged. 63- **DO** ensure any new features or changes to existing behaviours are covered with test cases. 64- **DO** address PR feedback in an additional commit(s) rather than amending the existing 65 commits, and only rebase/squash them when necessary. This makes it easier for reviewers 66 to track changes. 67- **DO** assume that the [Squash and Merge] will be used to merge your commit unless you 68 request otherwise in the PR. 69- **DO** NOT fix merge conflicts using a merge commit. Prefer git rebase. 70- **DO** NOT submit changes to the original legacy tests, see 71 [test/legacy/README.md](test/legacy/README.md). 72 73### Merging Pull Requests (for maintainers with write access) 74 75- **DO** use [Squash and Merge] by default for individual contributions unless requested 76 by the PR author. Do so, even if the PR contains only one commit. It creates a simpler 77 history than [Create a Merge Commit]. Reasons that PR authors may request the true 78 merge recording a merge commit may include (but are not limited to): 79 - The change is easier to understand as a series of focused commits. 80 Each commit in the series must be buildable so as not to break git bisect. 81 - Contributor is using an e-mail address other than the primary GitHub address 82 and wants that preserved in the history. 83 Contributor must be willing to squash the commits manually before acceptance. 84 85## Getting started with Git workflow 86 87First, you need learn some minimal basics of the 88[modular Boost](https://svn.boost.org/trac/boost/wiki/ModularBoost) 89super-project workflow. 90 91The following steps are based on the official Boost 92[Getting Started](https://github.com/boostorg/boost/wiki/Getting-Started). 93 94**NOTE:** For brevity, commands below use notation for POSIX-like operating 95systems and you may need to tweak them for Windows systems. 96 97### 1. Clone Boost super-project 98 99The preparation involves the following steps: 100 1011. Clone the Boost super-project 102 103 ```shell 104 git clone --recurse-submodules --jobs 8 https://github.com/boostorg/boost.git 105 ``` 106 1072. Switch the Boost super-project to desired branch, `master` or `develop` 108 109 ```shell 110 cd boost 111 git checkout master 112 ``` 113 114 **TIP:** [Modular Boost Library Maintenance](https://svn.boost.org/trac10/wiki/StartModMaint) 115 guide, for more realistic test environment, recommends to develop and test 116 individual Boost library against other Boost libraries as defined by 117 the Boost super-project `master` branch: 118 119 ```shell 120 cd boost 121 git checkout master 122 git pull 123 git submodule update --init --recursive --jobs 8 124 ``` 125 1263. Build the `b2` driver program for Boost.Build engine. 127 128 ```shell 129 ./bootstrap.sh 130 ./b2 --version 131 ``` 132 133 **TIP:** For more convenient path-less invocation, you can copy the `b2` 134 program to a location in your `PATH`. 135 1364. Create full content of `/boost` virtual directory with 137all Boost headers linked from the individual modular Boost libraries. 138If you skip this step, executing `b2` to run tests will automatically 139create the directory with all headers required by Boost.GIL and tests. 140 141 ```shell 142 ./b2 headers 143 ``` 144 145**TIP:** If something goes wrong, you end up with incomplete or accidentally 146modified files in your clone of the super-project repository, or you simply 147wish to start fresh, then you can clean and reset the whole repository and 148its modules: 149 150```shell 151git clean -xfd 152git submodule foreach --recursive git clean -xfd 153git reset --hard 154git submodule foreach --recursive git reset --hard 155git submodule update --init --recursive --jobs 8 156``` 157 158### 2. Checkout Boost.GIL development branch 159 160Regardless if you decide to develop again `master` (recommended) or `develop` 161branch of the Boost super-project, you should *always* base your contributions 162(i.e. topic branches) on Boost.GIL `develop` branch. 163 1641. Go to the Boost.GIL library submodule. 165 166 ```shell 167 cd libs/gil 168 ``` 169 1702. Checkout the `develop` branch and bring it up to date 171 172 ```shell 173 git checkout develop 174 git branch -vv 175 git pull origin develop 176 ``` 177 178### 3. Fork Boost.GIL repository on GitHub 179 180Follow [Forking Projects](https://guides.github.com/activities/forking/) guide 181to get personal copy of [boostorg/gil](https://github.com/boostorg/gil) 182repository from where you will be able to submit new contributions as 183[pull requests](https://help.github.com/articles/about-pull-requests/). 184 185Add your fork as git remote to the Boost.GIL submodule: 186 187```shell 188cd libs/gil 189git remote add <username> https://github.com/<username>/gil.git 190``` 191 192or, if you cloned from your fork already, add the upstream as `origin` remote: 193 194```shell 195git remote add upstream https://github.com/boostorg/gil.git 196# or 197git remote rename origin <username> 198git remote add origin https://github.com/boostorg/gil.git 199``` 200 201### 4. Submit a pull request 202 203All Boost.GIL contributions should be developed inside a topic branch created by 204branching off the `develop` branch of [boostorg/gil](https://github.com/boostorg/gil). 205 206**IMPORTANT:** Pull Requests *must* come from a branch based on `develop`, 207and *never* on `master`. 208 209**NOTE:** The branching workflow model 210[Boost recommends](https://svn.boost.org/trac10/wiki/StartModWorkflow) 211is called Git Flow. 212 213For example: 214 215```shell 216cd libs/gil 217git checkout develop 218git checkout -b feature/foo 219``` 220 221Now, you are set to to develop a new feature for Boost.GIL, 222then [git add](https://git-scm.com/docs/git-add) and 223[git commit](https://git-scm.com/docs/git-commit) your changes. 224 225Once it's finished, you can submit it as pull request for review: 226 227```shell 228cd libs/gil 229git checkout feature/foo 230git push <username> feature/foo 231``` 232 233Finally, sign in to your GitHub account and 234[create a pull request](https://help.github.com/articles/creating-a-pull-request/). 235 236Your pull request will be automatically built and tests will run on Travis CI 237and AppVeyor (see [README](README.md) for builds status). Please, keep an eye 238on those CI builds and correct any problems detected in your contribution 239by updating your pull request. 240 241### 5. Update your pull request 242 243Depending on actual purpose of the update, you can follow a different 244strategy to update your pull request: 245 246- Use `git commit --amend`, `git rebase` and `git push --force` when your 247 pull request is still *work-in-progress* and not ready for review yet. 248- Use `git commit`, `git merge` and `git push` to update your pull request 249 during review, in response to requests from reviewers. 250 251**NOTE:** Once review of your work has started, you should not rebase your work. 252You should create new commits and update your topic branch. This helps with 253traceability in the pull request and prevents the accidental history breakage. 254Those who review your work may be fetching it into their fork for local review. 255 256#### Synchronise pull request branch 257 258Keep your topic branch up to date and synchronized with the upstream `develop` branch: 259 260```shell 261cd libs/gil 262git checkout develop 263git pull origin develop 264git checkout feature/foo 265``` 266 267If review of your work has not started, *prefer* to merge: 268 269```shell 270git merge develop 271git push <username> feature/foo 272``` 273 274If your PR is still *work-in-progress*, you may rebase if you like: 275 276```shell 277git rebase develop 278git push --force <username> feature/foo 279``` 280 281#### Amend last commit of pull request 282 283If your pull request is a *work-in-progress* and has not been reviewed yet, 284you may amend your commit or rebase onto the `develop` branch: 285 286```shell 287cd libs/gil 288git checkout feature/foo 289git add -A 290git commit --amend 291git push --force <username> feature/foo 292``` 293 294#### Add new commits to pull request 295 296In order to update your pull request, for example in response to a change 297request from reviewer, just add new commits: 298 299```shell 300cd libs/gil 301git checkout feature/foo 302git add -A 303git commit -m "Fix build Travis CI failures" 304git push <username> feature/foo 305``` 306 307## Development 308 309Boost.GIL is a [header-only library](https://en.wikipedia.org/wiki/Header-only) 310which does not require sources compilation. Only test runners and 311[example](example/README.md) programs have to be compiled. 312 313By default, Boost.GIL uses Boost.Build to build all the executables. 314 315We also provide configuration for two alternative build systems: 316 317- [CMake](https://cmake.org) 318 319**NOTE:** The CMake is optional and the corresponding build configurations 320for Boost.GIL do not offer equivalents for all Boost.Build features. 321Most important difference to recognise is that Boost.Build will automatically 322build any other Boost libraries required by Boost.GIL as dependencies. 323 324### Install dependencies 325 326Boost.GIL tests and examples use the GIL I/O extension which depends on 327third-party libraries for read and write support of specific image formats: 328 329```shell 330sudo apt-get install libjpeg-dev libpng-dev libtiff5-dev libraw-dev 331``` 332 333**TIP:** On Windows, use vcpkg with `user-config.jam` configuration provided in [example/b2/user-config-windows-vcpkg.jam](example/b2/). 334 335### Using Boost.Build 336 337The [b2 invocation](https://boostorg.github.io/build/manual/develop/index.html#bbv2.overview.invocation) 338explains available options like `toolset`, `variant` and others. 339 340Simply, just execute `b2` to run all tests built using default 341`variant=debug` and default `toolset` determined for your 342development environment. 343 344**TIP:** Pass `b2` option `-d 2` to output complete action text and commands, 345as they are executed. It is useful to inspect compilation flags. 346 347If no target or directory is specified, everything in the current directory 348is built. For example, all Boost.GIL tests can be built and run using: 349 350```shell 351cd libs/gil 352../../b2 353``` 354 355Run core tests only specifying location of directory with tests: 356 357```shell 358cd libs/gil 359../../b2 cxxstd=11 test/core 360``` 361 362Run all tests for selected extension (from Boost root directory, as alternative): 363 364```shell 365./b2 cxxstd=11 libs/gil/test/io 366./b2 cxxstd=11 libs/gil/test/numeric 367./b2 cxxstd=11 libs/gil/test/toolbox 368``` 369 370Run I/O extension tests bundled in target called `simple`: 371 372```shell 373./b2 cxxstd=11 libs/gil/test/io//simple 374``` 375 376**TIP:** Pass `b2` feature `cxxstd=11,14,17,2a` to request compilation for 377multiple C++ standard versions in single build run. 378 379### Using CMake 380 381Maintainer: [@mloskot](https://github.com/mloskot) 382 383**WARNING:** The CMake configuration is only provided for convenience 384of contributors. It does not export or install any targets, deploy 385config files or support subproject workflow. 386 387**NOTE:** CMake configuration does not build any dependencies required by 388Boost.GIL like Boost.Test and Boost.Filesystem libraries or any 389third-party image format libraries used by the I/O extension. 390 391The provided CMake configuration allows a couple of ways to develop Boost.GIL: 392 3931. Using Boost installed from binary packages in default system-wide location. 3942. Using Boost installed from sources in arbitrary location (CMake may need 395 `-DBOOST_ROOT=/path/to/boost/root`, see 396 [FindBoost](https://cmake.org/cmake/help/latest/module/FindBoost.html) 397 documentation for details). 3983. Using [cloned Boost super-project](#cloned-boost-super-project), inside modular 399 `libs/gil`. This mode requires prior deployment of `boost` virtual directory 400 with headers and stage build of required libraries, for example: 401 402For CMake, you only need to build Boost libraries required by Boost.Test library 403which is used to run GIL tests. Since the `CMAKE_CXX_STANDARD` option in the current 404[CMakeLists.txt](CMakeLists.txt) defaults to C++11, pass the default `cxxstd=11` to `b2`: 405 406 ```shell 407 ./b2 headers 408 ./b2 variant=debug,release cxxstd=11 --with-filesystem stage 409 ``` 410 411 or, depending on specific requirements, more complete build: 412 413 ```shell 414 ./b2 variant=debug,release address-model=32,64 cxxstd=11 --layout=versioned --with-filesystem stage 415 ``` 416 417If you wish to build tests using different C++ standard version, then adjust the `cxxstd` accordingly. 418 419Using the installed Boost enables a lightweight mode for the library development, 420inside a stand-alone clone Boost.GIL repository and without any need to clone the 421whole Boost super-project. 422 423**TIP:** For the lightweight setup, prefer latest release of Boost. 424 425For available custom CMake options, open the top-level `CMakeLists.txt` and search for `option`. 426 427Here is an example of such lightweight workflow in Linux environment (Debian-based): 428 429- Install required Boost libraries 430 431 ```shell 432 sudo apt-get update 433 sudo apt-get install libboost-dev libboost-test-dev libboost-filesystem-dev 434 ``` 435 436- Clone Boost.GIL repository 437 438 ```shell 439 git clone https://github.com/boostorg/gil.git 440 cd gil 441 ``` 442 443- Configure build with CMake 444 445 ```shell 446 mkdir _build 447 cd _build/ 448 cmake .. 449 ``` 450 451 **TIP:** By default, tests and [examples](example/README.md) are compiled using 452 the minimum required C++11. 453 Specify `-DCMAKE_CXX_STANDARD=14|17|20` to use newer version. 454 For more CMake options available for GIL, check `option`-s defined 455 in the top-level `CMakeLists.txt`. 456 457 **TIP:** If CMake is failing to find Boost libraries, especially built 458 with `--layout=versioned`, you can try a few hacks: 459 - option `-DBoost_ARCHITECTURE=-x64` to help CMake find Boost 1.66 and above 460 add an architecture tag to the library file names in versioned build 461 The option added in CMake 3.13.0. 462 - option `-DBoost_COMPILER=-gcc5` or `-DBoost_COMPILER=-vc141` to help CMake earlier 463 than 3.13 match your compiler with toolset used in the Boost library file names 464 (i.e. `libboost_filesystem-gcc5-mt-x64-1_69` and not `-gcc55-`). 465 Fixed in CMake 3.13.0. 466 - if CMake is still failing to find Boost, you may try `-DBoost_DEBUG=ON` to 467 get detailed diagnostics output from `FindBoost.cmake` module. 468 469- List available CMake targets 470 471 ```shell 472 cmake --build . --target help 473 ``` 474 475- Build selected target with CMake 476 477 ```shell 478 cmake --build . --target gil_test_pixel 479 ``` 480 481- List available CTest targets 482 483 ```shell 484 ctest --show-only | grep Test 485 ``` 486 487- Run selected test with CTest 488 489 ```shell 490 ctest -R gil.tests.core.pixel 491 ``` 492 493#### CMake configuration for Visual Studio 494 495We provide [example/cmake/CMakeSettings.json](https://github.com/boostorg/gil/blob/develop/example/cmake/CMakeSettings.json) 496with reasonable default settings for the [CMake support in Visual Studio](https://go.microsoft.com//fwlink//?linkid=834763). 497See [example/cmake/README.md](example/cmake/README.md) for more details. 498 499#### CMake configuration for Visual Studio Code 500 501We provide [example/cmake/cmake-variants.yaml](https://github.com/boostorg/gil/blob/develop/example/cmake/cmake-variants.yaml) 502with reasonable default settings for the [CMake Tools](https://github.com/vector-of-bool/vscode-cmake-tools) extension. 503See [example/cmake/README.md](example/cmake/README.md) for more details. 504 505### Running clang-tidy 506 507[clang-tidy](http://clang.llvm.org/extra/clang-tidy/) can be run on demand to 508diagnose or diagnose and fix or refactor source code issues. 509 510Since the CMake configuration is provided for building tests and [examples](example/README.md), 511it is easy to run `clang-tidy` using either the integration built-in CMake 3.6+ 512as target property `CXX_CLANG_TIDY` or the compile command database which 513can be easily generated. 514 515#### Linting 516 517This mode uses the CMake built-in integration and runs `clang-tidy` checks configured 518in [.clang-tidy](https://github.com/boostorg/gil/blob/develop/.clang-tidy). 519All custom compilation warning levels (e.g. `-Wall`) are disabled and 520compiler defaults are used. 521 522```shell 523cd libs/gil 524cmake -S . -B _build -DGIL_USE_CLANG_TIDY=ON 525 526# all targets 527cmake --build _build 528 529# selected target 530cmake --build _build --target test_headers_all_in_one 531``` 532 533#### Refactoring 534 535**WARNING:** This is advanced processing and depending on checks, it may fail to deliver 536expected results, especially if run against all configured translation units at ones. 537 5381. Generate `compile_commands.json` database 539 540 ```shell 541 cd libs/gil 542 cmake -S . -B _build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON 543 ``` 544 5452. Edit `compile_commands.json` and remove entries of commands for all but the `.cpp` 546 files you wish to refactor. For example, keep `test_headers_all_in_one.cpp` only 547 to refactor all headers. 548 5493. Run the parallel `clang-tidy` runner script to apply the desired checks (and fixes) 550 across the library source code: 551 552 ```shell 553 run-clang-tidy.py -p=_build -header-filter='boost\/gil\/.*' -checks='-*,modernize-use-using' -fix > cl.log 2>&1 554 ``` 555 556## Guidelines 557 558Boost.GIL is a more than a decade old mature library maintained by several 559developers with help from a couple of dozens contributors. 560It is important to maintain consistent design, look and feel. 561Thus, below a few basic guidelines are listed. 562 563First and foremost, make sure you are familiar with the official 564[Boost Library Requirements and Guidelines](https://www.boost.org/development/requirements.html). 565 566Second, strive for writing idiomatic C++11, clean and elegant code. 567 568**NOTE:** *The Boost.GIL source code does not necessary represent clean and elegant 569code to look up to. The library has recently entered the transition to C++11. 570Major refactoring overhaul is ongoing.* 571 572Maintain structure your source code files according to the following guidelines: 573 574- Name files in meaningful way. 575- Put copyright and license information in every file 576- If your changes [meet a certain threshold of originality](https://www.boost.org/users/license.html), 577 add yourself to the copyright notice. Do not put any additional authorship or 578 file comments (eg. no `\file` for Doxygen), revision information, etc. 579- In header, put `#include` guard based on header path and file name 580 581 ```cpp 582 #ifndef BOOST_GIL_<DIR1>_<DIR2>_<FILE>_HPP 583 #define BOOST_GIL_<DIR1>_<DIR2>_<FILE>_HPP 584 ... 585 #endif 586 ``` 587 588- Make sure each [header is self-contained](https://github.com/boostorg/gil/wiki/Include-Directives-Order), i.e. that they include all headers they need. 589- All public headers should be placed in `boost/gil/` or `boost/gil/<component>/`. 590- All non-public headers should be placed `boost/gil/detail` or `boost/gil/<component>/detail`. 591- All public definitions should reside in scope of `namespace boost { namespace gil {...}}`. 592- All non-public definitions should reside in scope of `namespace boost { namespace gil { namespace detail {...}}}`. 593- Write your code to fit within **100** columns of text. 594- Use [EditorConfig](https://editorconfig.org) for your editor and enable [.editorconfig](https://github.com/boostorg/gil/blob/develop/.editorconfig) to: 595 - Indent with **4 spaces** and no tabs. 596 - Trim any trailing whitespaces. 597- Do not increases the indentation level within namespace. 598 599[status/work-in-progress]: https://github.com/boostorg/gil/labels/status%2Fwork-in-progress 600[refer]: https://help.github.com/articles/autolinked-references-and-urls/ 601[keywords]: https://help.github.com/articles/closing-issues-using-keywords/ 602[mention]: https://help.github.com/articles/basic-writing-and-formatting-syntax/#mentioning-people-and-teams 603[squash and merge]: https://help.github.com/articles/merging-a-pull-request/ 604[create a merge commit]: https://help.github.com/articles/merging-a-pull-request/ 605