Building `bfs`
==============
Compiling
---------
`bfs` uses [GNU Make](https://www.gnu.org/software/make/) as its build system.
A simple invocation of
$ make config
$ make
should build `bfs` successfully.
As usual with `make`, you can run a [parallel build](https://www.gnu.org/software/make/manual/html_node/Parallel.html) with `-j`.
For example, to use all your cores, run `make -j$(nproc)`.
### Targets
| Command | Description |
|------------------|---------------------------------------------------------------|
| `make config` | Configures the build system |
| `make` | Builds just the `bfs` binary |
| `make all` | Builds everything, including the tests (but doesn't run them) |
| `make check` | Builds everything, and runs the tests |
| `make install` | Installs `bfs` (with man page, shell completions, etc.) |
| `make uninstall` | Uninstalls `bfs` |
| `make clean` | Delete the build products |
| `make distclean` | Delete all generated files, including the build configuration |
### Build profiles
The configuration system provides a few shorthand flags for handy configurations:
| Command | Description |
|-------------------------|-------------------------------------------------------------|
| `make config RELEASE=y` | Build `bfs` with optimizations, LTO, and without assertions |
| `make config ASAN=y` | Enable [AddressSanitizer] |
| `make config LSAN=y` | Enable [LeakSanitizer] |
| `make config MSAN=y` | Enable [MemorySanitizer] |
| `make config TSAN=y` | Enable [ThreadSanitizer] |
| `make config UBSAN=y` | Enable [UndefinedBehaviorSanitizer] |
| `make config GCOV=y` | Enable [code coverage] |
[AddressSanitizer]: https://github.com/google/sanitizers/wiki/AddressSanitizer
[LeakSanitizer]: https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer#stand-alone-mode
[MemorySanitizer]: https://github.com/google/sanitizers/wiki/MemorySanitizer
[ThreadSanitizer]: https://github.com/google/sanitizers/wiki/ThreadSanitizerCppManual
[UndefinedBehaviorSanitizer]: https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html
[code coverage]: https://gcc.gnu.org/onlinedocs/gcc/Gcov.html
You can combine multiple profiles (e.g. `make config ASAN=y UBSAN=y`), but not all of them will work together.
### Flags
Other flags can be specified on the `make config` command line or in the environment.
Here are some of the common ones; check the [`Makefile`](/Makefile) for more.
| Flag | Description |
|-------------------------------------|----------------------------------------------------|
| `CC` | The C compiler to use, e.g. `make config CC=clang` |
| `CFLAGS`
`EXTRA_CFLAGS` | Override/add to the default compiler flags |
| `LDFLAGS`
`EXTRA_LDFLAGS` | Override/add to the linker flags |
| `USE_LIBACL`
`USE_LIBCAP`
... | Enable/disable [optional dependencies] |
| `TEST_FLAGS` | `tests.sh` flags for `make check` |
| `BUILDDIR` | The build output directory (default: `.`) |
| `DESTDIR` | The root directory for `make install` |
| `PREFIX` | The installation prefix (default: `/usr`) |
| `MANDIR` | The man page installation directory |
[optional dependencies]: #dependencies
### Dependencies
`bfs` depends on some system libraries for some of its features.
These dependencies are optional, and can be turned off in `make config` if necessary by setting the appropriate variable to `n` (e.g. `make config USE_ONIGURUMA=n`).
| Dependency | Platforms | `make config` flag |
|--------------|------------|--------------------|
| [libacl] | Linux only | `USE_LIBACL` |
| [libcap] | Linux only | `USE_LIBCAP` |
| [liburing] | Linux only | `USE_LIBURING` |
| [libselinux] | Linux only | `USE_LIBSELINUX` |
| [Oniguruma] | All | `USE_ONIGURUMA` |
[libacl]: https://savannah.nongnu.org/projects/acl
[libcap]: https://sites.google.com/site/fullycapable/
[libselinux]: https://github.com/SELinuxProject/selinux
[liburing]: https://github.com/axboe/liburing
[Oniguruma]: https://github.com/kkos/oniguruma
### Dependency tracking
The build system automatically tracks header dependencies with the `-M` family of compiler options (see `DEPFLAGS` in the [`Makefile`](/Makefile)).
So if you edit a header file, `make` will rebuild the necessary object files ensuring they don't go out of sync.
We also add a dependency on the current configuration, so you can change configurations and rebuild without having to `make clean`.
We go one step further than most build systems by tracking the flags that were used for the previous compilation.
That means you can change configurations without having to `make clean`.
For example,
$ make config
$ make
$ make config RELEASE=y
$ make
will build the project in debug mode and then rebuild it in release mode.
Testing
-------
`bfs` comes with an extensive test suite which can be run with
$ make check
The test harness is implemented in the file [`tests/tests.sh`](/tests/tests.sh).
Individual test cases are found in `tests/*/*.sh`.
Most of them are *snapshot tests* which compare `bfs`'s output to a known-good copy saved under the matching `tests/*/*.out`.
You can pass the name of a particular test case (or a few) to run just those tests.
For example:
$ ./tests/tests.sh posix/basic
If you need to update the reference snapshot, pass `--update`.
It can be handy to generate the snapshot with a different `find` implementation to ensure the output is correct, for example:
$ ./tests/tests.sh posix/basic --bfs=find --update
But keep in mind, other `find` implementations may not be correct.
To my knowledge, no other implementation passes even the POSIX-compatible subset of the tests:
$ ./tests/tests.sh --bfs=find --posix
...
tests passed: 90
tests skipped: 3
tests failed: 6
Run
$ ./tests/tests.sh --help
for more details.
### Validation
A more thorough testsuite is run by the [CI](https://github.com/tavianator/bfs/actions) and to validate releases.
It builds `bfs` in multiple configurations to test for latent bugs, memory leaks, 32-bit compatibility, etc.
You can run it yourself with
$ make distcheck
Some of these tests require `sudo`, and will prompt for your password if necessary.