summaryrefslogtreecommitdiffstats
path: root/docs/BUILDING.md
blob: f61c11e27dec3c74f78d6a243c3d229c6433c5d2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
Building `bfs`
==============

Compiling
---------

`bfs` uses [GNU Make](https://www.gnu.org/software/make/) as its build system.
A simple invocation of

    $ make

should build `bfs` successfully, with no additional steps necessary.
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`           | 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`                                              |

### Flag-like targets

The build system provides a few shorthand targets for handy configurations:

| Command        | Description                                                 |
|----------------|-------------------------------------------------------------|
| `make release` | Build `bfs` with optimizations, LTO, and without assertions |
| `make asan`    | Enable [AddressSanitizer]                                   |
| `make lsan`    | Enable [LeakSanitizer]                                      |
| `make msan`    | Enable [MemorySanitizer]                                    |
| `make tsan`    | Enable [ThreadSanitizer]                                    |
| `make ubsan`   | Enable [UndefinedBehaviorSanitizer]                         |
| `make gcov`    | 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 flags and other targets (e.g. `make asan ubsan check`), but not all of them will work together.

### Flags

Other flags are controlled with `make` variables and/or environment variables.
Here are some of the common ones; check the [`Makefile`](/Makefile) for more.

| Flag                             | Description                                 |
|----------------------------------|---------------------------------------------|
| `CC`                             | The C compiler to use, e.g. `make CC=clang` |
| `CFLAGS`<br>`EXTRA_CFLAGS`       | Override/add to the default compiler flags  |
| `LDFLAGS`<br>`EXTRA_LDFLAGS`     | Override/add to the linker flags            |
| `WITH_ACL`<br>`WITH_ATTR`<br>... | Enable/disable optional dependencies        |
| `TEST_FLAGS`                     | `tests.sh` flags for `make check`           |
| `DESTDIR`                        | The root directory for `make install`       |
| `PREFIX`                         | The installation prefix (default: `/usr`)   |
| `MANDIR`                         | The man page installation directory         |

### 

### 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 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
    $ make release

will build the project in debug mode and then rebuild it in release mode.

A side effect of this may be surprising: `make check` by itself will rebuild the project in the default configuration.
To test a different configuration, you'll have to repeat it (e.g. `make release check`).


Testing
-------

`bfs` comes with an extensive test suite which can be run with

    $ make check

Most of the testsuite is implemented in the file [`tests.sh`](/tests.sh).
This script contains hundreds of separate test cases.
Most of them are *snapshot tests* which compare `bfs`'s output to a known-good copy saved under [`tests`](/tests).

You can pass the name of a particular test case (or a few) to run just those tests.
For example:

    $ ./tests.sh test_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.sh test_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.sh --bfs=find --posix
    ...
    tests passed: 89
    tests failed: 5

Run

    $ ./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.