From 121c95b815923fee57dafd02b021fdf2a6e84628 Mon Sep 17 00:00:00 2001 From: Anna Petrasova Date: Fri, 17 Jul 2026 05:44:46 -0400 Subject: [PATCH 1/2] doc: cmake compilation guide --- CONTRIBUTING.md | 54 +++------ doc/development/building_with_cmake.md | 162 +++++++++++++++++++++++++ man/mkdocs/docs/development_intro.md | 1 + 3 files changed, 180 insertions(+), 37 deletions(-) create mode 100644 doc/development/building_with_cmake.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c264c9850fc..e3224d80cc5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -76,43 +76,23 @@ To contribute effectively, please familiarize yourself with our If you use an AI assistant or agent, see [`AGENTS.md`](./AGENTS.md) for project-specific instructions and conventions. -### Testing changes - -Testing helps to ensure that the changes work well with the rest -of the project. While there are many different ways to test, -usually you will want to compile the source code (see below), -add test code (using _grass.gunittest_ or pytest), and run code -linters (automated code quality checks). - -There is a series of automated checks which will run on your pull request -after you create one. You don't need to run all these -checks locally and, indeed, some of them may fail for your code. This is a part -of the standard iterative process of integrating changes into the main code, -so if that happens, just see the error messages, go back to your code -and try again. If you are not sure what to do, let others know in a pull -request comment. - -Note that there are some steps you can do locally to improve your code. -For Python, run `ruff format` to apply standardized formatting. You can -also run linter tools such as `ruff check` or Pylint which will suggest -different improvements to your code. - -## Compilation - -More often than not, in order to test the changes, you need to create -a runnable binary program from the source code, -using the so-called "compilation step". While the -source code consists of thousands of C and Python files (plus HTML -documentation and other files), the included "makefiles" tell the build system to -generate binaries from the source code in the correct order, render the -manual pages, etc. - -The way to install the compiler tools and Python depends on the operating -system. To make this easier, we have collected copy-paste instructions -to install dependencies and compile GRASS source code for most operating systems. -Please see our dedicated wiki: - -[Compile and install instructions](https://grasswiki.osgeo.org/wiki/Compile_and_Install) +To test your changes, you may need to compile the source code. +For compilation, see [instructions for building with CMake](./doc/development/building_with_cmake.md) +or [instructions for GNU Autoools](./INSTALL.md). +Further notes for various platforms can be found on a dedicated +[wiki page](https://grasswiki.osgeo.org/wiki/Compile_and_Install). + +Before creating a PR, please test your changes. +Refer to [testing README](./testsuite/README.md) for details. +Once you create a PR, a series of automated checks which will run on your pull request. +This is a part of the standard iterative process of integrating +changes into the main code, so if that happens, +just see the error messages, go back to your code and try again. +If you are not sure what to do, let others know in a pull request comment. + +In addition to testing, please use +[pre-commit](doc/development/style_guide.md#using-pre-commit) +to apply standardized formatting. ## About source code diff --git a/doc/development/building_with_cmake.md b/doc/development/building_with_cmake.md new file mode 100644 index 00000000000..542bf8c99d8 --- /dev/null +++ b/doc/development/building_with_cmake.md @@ -0,0 +1,162 @@ +# Building GRASS with CMake + +This guide covers developer workflows for building GRASS with CMake: +configuring and compiling, running GRASS directly from the build +directory, recompiling only modified code, and compiling addons. For +dependencies and general installation instructions, see +[INSTALL.md](../../INSTALL.md). If you are coming from the Autotools +build, see the [comparison table](#comparison-with-autotools) at the +end. + +## Configuring + +Create and configure a build directory with: + +```bash +cmake -B build +``` + +The build is fully out-of-source: all generated files go into the build +directory (here `build`), the source tree stays clean, and you can keep +several independently configured build directories side by side +(e.g. `build-debug`, `build-clang`). + +Optional dependencies are controlled with `WITH_*` options: + +```bash +cmake -B build -DWITH_MYSQL=ON -DWITH_FFTW=OFF +``` + +See the `option(WITH_...)` calls in the top-level `CMakeLists.txt` for +the full list. Note that options enabled by default (PDAL, GEOS, FFTW, +etc.) are treated as required: on a system missing one, configure fails +with a "Could not find ..." error. Either install the dependency or +disable the option explicitly. + +Other frequently used settings: + +```bash +# Custom compiler flags +cmake -B build -DCMAKE_C_FLAGS="-g -Wall" + +# Optimization/debug presets (Debug, Release, RelWithDebInfo) +cmake -B build -DCMAKE_BUILD_TYPE=Debug + +# Installation directory (default /usr/local) +cmake -B build -DCMAKE_INSTALL_PREFIX=/opt/grass +``` + +The install prefix is recorded in the build at configure time, so set it +with `-DCMAKE_INSTALL_PREFIX` here rather than at install time. + +Settings are sticky: they are cached in the build directory, so a later +plain `cmake -B build` or rebuild keeps using them. To change a setting, +pass the new `-D...` value; to reset everything, delete the build +directory. + +If `ccache` is installed, the build uses it automatically to cache +compiler output, so recompiling files that have not changed (e.g. after +deleting the build directory or in a second build directory) is nearly +instant. Pass `-DUSE_CCACHE=OFF` to opt out. + +## Compiling + +```bash +cmake --build build -j$(nproc) +``` + +`cmake --build` drives `make` under the hood; it compiles serially +unless you pass `-j`. + +There is no separate reconfigure step after pulling changes: the build +re-runs CMake automatically when any `CMakeLists.txt` changed. + +## Running GRASS from the build directory + +The runnable tree is staged under `build/output`, so GRASS can be run +without installing: + +```bash +./build/output/bin/grass +``` + +For running tests against the build tree, put `build/output/bin` on +`PATH`: + +```bash +export PATH="$(pwd)/build/output/bin:${PATH}" +``` + +## Recompiling only what you modified + +Every tool is a CMake target named exactly like the tool, and building a +target also rebuilds any libraries it depends on and re-links the result +into `build/output`. So after editing, e.g., `raster/r.slope.aspect/main.c` +or a library it uses: + +```bash +cmake --build build --target r.slope.aspect +``` + +and the updated tool is immediately runnable from `build/output`. +Targets are always built this way from the top level; there is no +per-directory build. + +Other useful target names: + +- C libraries: `grass_` (e.g. `grass_gis`, `grass_raster`, + `grass_vector`) +- Python packages, staged into `build/output`: `python_` + (e.g. `python_script`, `python_tools`, `python_temporal`, + `python_pygrass`); an edited file under `python/grass/` is not visible + in `build/output` until its target is rebuilt +- Python script tools: the tool name, same as C tools (e.g. `r.mask`) + +To list all available targets (with the default Makefile generator): + +```bash +cmake --build build --target help +``` + +## Compiling addons + +Addons are installed with *g.extension*, which downloads the addon +source code, compiles it, and installs it into your user addon +directory. With a CMake-built GRASS, *g.extension* compiles the addon +using CMake automatically; you do not run any CMake commands yourself. + +The requirement is that the GRASS you run *g.extension* from is an +installed one (`cmake --install build`), not the `build/output` tree, +which lacks the addon build machinery. No root is needed: install to a +prefix in your home directory. In the GRASS source directory: + +```bash +cmake -B build -DCMAKE_INSTALL_PREFIX=$HOME/grass-install +cmake --build build -j$(nproc) +cmake --install build +``` + +Then run *g.extension* from the installed GRASS as usual, in a GRASS +session or on the command line with `--exec`: + +```bash +$HOME/grass-install/bin/grass --tmp-project XY --exec \ + g.extension extension=r.example +``` + +## Comparison with Autotools + +For developers used to the Autotools build (`./configure && make`): + +| Task | Autotools | CMake | +| ---- | --------- | ----- | +| Configure | `./configure [options]` | `cmake -B build [options]` | +| Configure with debug flags | `CFLAGS="-g -Wall" ./configure` | `cmake -B build -DCMAKE_C_FLAGS="-g -Wall"` | +| Set install directory | `./configure --prefix=...` | `cmake -B build -DCMAKE_INSTALL_PREFIX=...` | +| Compile everything | `make -j$(nproc)` | `cmake --build build -j$(nproc)` | +| Install | `make install` | `cmake --install build` | +| Run without installing | `bin.$ARCH/grass` | `build/output/bin/grass` | +| Recompile one tool | `cd raster/r.slope.aspect && make` | `cmake --build build --target r.slope.aspect` | +| Clean compiled files | `make clean` | `cmake --build build --target clean` | +| Clean everything incl. configuration | `make distclean` | `rm -rf build` | +| Use ccache | `CC="ccache gcc" ./configure` | automatic if installed | diff --git a/man/mkdocs/docs/development_intro.md b/man/mkdocs/docs/development_intro.md index 87bf5fcb16a..abdbeaef376 100644 --- a/man/mkdocs/docs/development_intro.md +++ b/man/mkdocs/docs/development_intro.md @@ -34,5 +34,6 @@ and are a great way to extend the functionality of GRASS. - [Style guide](style_guide.md) - [GitHub guide](github_guide.md) +- [CMake guide](building_with_cmake.md) - [Investigating code history](investigating_history.md) - [CONTRIBUTING file on GitHub](https://github.com/OSGeo/grass/blob/main/CONTRIBUTING.md) From b1174261d34613a75fb736171b66dc8b0fc0efea Mon Sep 17 00:00:00 2001 From: Anna Petrasova Date: Sat, 18 Jul 2026 13:19:59 -0400 Subject: [PATCH 2/2] address review --- doc/development/building_with_cmake.md | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/doc/development/building_with_cmake.md b/doc/development/building_with_cmake.md index 542bf8c99d8..77c318e6abe 100644 --- a/doc/development/building_with_cmake.md +++ b/doc/development/building_with_cmake.md @@ -54,6 +54,12 @@ plain `cmake -B build` or rebuild keeps using them. To change a setting, pass the new `-D...` value; to reset everything, delete the build directory. +By default the build is driven by `make`. If [Ninja](https://ninja-build.org/) +is installed, you can select it instead with `-G Ninja`; it is faster on +incremental builds and compiles in parallel by default. The build tool +is chosen at configure time and cannot be changed in an existing build +directory. + If `ccache` is installed, the build uses it automatically to cache compiler output, so recompiling files that have not changed (e.g. after deleting the build directory or in a second build directory) is nearly @@ -65,8 +71,10 @@ instant. Pass `-DUSE_CCACHE=OFF` to opt out. cmake --build build -j$(nproc) ``` -`cmake --build` drives `make` under the hood; it compiles serially -unless you pass `-j`. +`cmake --build` is a thin wrapper that runs the actual build tool +selected at configure time: `make` by default, or `ninja` if configured +with `-G Ninja`. With `make` it compiles serially unless you pass `-j`; +Ninja parallelizes by default. There is no separate reconfigure step after pulling changes: the build re-runs CMake automatically when any `CMakeLists.txt` changed. @@ -118,6 +126,20 @@ To list all available targets (with the default Makefile generator): cmake --build build --target help ``` +## Installing + +For everyday development, installing is optional: GRASS runs directly +from `build/output`. To install, run: + +```bash +cmake --install build +``` + +This installs into the prefix recorded at configure time (default +`/usr/local`, which typically requires `sudo`). To install without +root, configure with `-DCMAKE_INSTALL_PREFIX` set to a writable +directory, e.g. `$HOME/grass-install`. + ## Compiling addons Addons are installed with *g.extension*, which downloads the addon