jsgoller1 / sprawl

2D Game Engine
GNU General Public License v3.0
0 stars 0 forks source link

Optimize build system #8

Closed jsgoller1 closed 1 year ago

jsgoller1 commented 1 year ago

The Problem

Each build takes ~60s, regardless of what changes to source actually occur. This is long enough to be annoying / a serious waste of time, and also to get distracted and take even longer to resume task.

Root cause

The current build system is implemented via a Makefile that does a full project build every time. This is obviously wasteful. Most of the time spent during the build is on the Clang front-end, which doesn't have fine grain metrics. Each compiled source file generates a report like the following (and we have ~60 of them):

===-------------------------------------------------------------------------===
                          Clang front-end time report
===-------------------------------------------------------------------------===
  Total Execution Time: 1.0148 seconds (1.0151 wall clock)

   ---User Time---   --System Time--   --User+System--   ---Wall Time---  --- Name ---
   0.9640 (100.0%)   0.0508 (100.0%)   1.0148 (100.0%)   1.0151 (100.0%)  Clang front-end timer
   0.9640 (100.0%)   0.0508 (100.0%)   1.0148 (100.0%)   1.0151 (100.0%)  Total

This continues to occur even after I depolluted namespaces in #7. So I'd say the root cause here is unnecessary recompilation and parsing.

Approaches

Here are some ideas I have for solving this:

Refactor Makefile

This would involve using Make to implement targets for each individual .o file, compiling them separately, and linking them. The paper Recursive Make Considered Harmful has some good suggestions about how we can do this with include statements so we can have Makefiles in subdirectories but still have fast builds.

Investigate PImpl and precompiled headers

I've seen pointer to implementation proposed as a solution to some situations where slow compilation occurs due to header files, but I don't know if it's relevant here. We also don't currently know the extent to which large system headers are contributing to the parsing slowness. It could be a useful idea to precompile headers like <vector> or <iostream> since they almost never change between Sprawl builds. I should also probably do this with the 3rd party libraries (nlohmann/json is huge).

Switch to a different build system

I need the following from any build system:

Here are some alternatives I've tried/considered, but ultimately rejected in favor of just working with Make:

Bazel

I used Bazel at ATG and in another project. However, the tutorial for modifying the toolchain so I could set Clang flags took ~10 steps, had numerous indirection layers, and a custom DSL. This is way too complex for one person on Mac and Linux.

Meson

I looked at the docs and a couple of other projects using it, but determined it was too complicated as well. It uses a Python-like DSL, and I had to spend a non-trivial time trying to figure out how to specify include directories / header file dependencies for each source file.

CMake

I like CMake and will probably switch to this eventually. However, it has a nontrivial DSL and requires a few tutorials to figure out how to use. Too complicated for now.

Write my own

I briefly considered borrowing by build script from my competitive programming repository and modifying it to check when build artifacts needed to be reproduced, but this boiled down to re-inventing Make.