I skimmed the paper. I use Make, extensively, but in a way I generally don’t see in the wild (for C/++):
1. I convert all paths to abspaths;
2. All intermediate products go into a temp dir;
3. All recipes are functions;
4. The set of objects are defined by a “find . -name ‘…’” for C sources;
5. Every C file depends on every header file in the repo;
6. Use ccache; and,
7. Deterministic build.
My big work project is ~20mm loc, including ~65 FW images (embedded OSes). Incremental compilation is ~300ms. Clean rebuilds are 30-40s; scratch builds are 8m. (All of this on ~4 year old MBP.)
Obviously, there are some design tricks to get raw compilation speed up — naive C++ only compiles at ~3kloc/s; it’s possible to get that up to 100kloc/s.
> Every C file depends on every header file in the repo.
So change in single header file always becomes a full build? Do you use pimpl or other tricks to avoid frequent changes to h-files, otherwise class members usually end up in the headers for simplicity and to avoid incomplete type problems on non-pointers unfortunately. Was this C or C++?
What's the difference between a clean rebuild and a scratch build?
Yes: touching any header file causes a full rebuild. Remember that ccache is "under the hood" doing memoization. So, a clean rebuild could still hit ccache, whereas a scratch build starts from an emoty ccache.
1. I convert all paths to abspaths;
2. All intermediate products go into a temp dir;
3. All recipes are functions;
4. The set of objects are defined by a “find . -name ‘…’” for C sources;
5. Every C file depends on every header file in the repo;
6. Use ccache; and,
7. Deterministic build.
My big work project is ~20mm loc, including ~65 FW images (embedded OSes). Incremental compilation is ~300ms. Clean rebuilds are 30-40s; scratch builds are 8m. (All of this on ~4 year old MBP.)
Obviously, there are some design tricks to get raw compilation speed up — naive C++ only compiles at ~3kloc/s; it’s possible to get that up to 100kloc/s.