Search code examples
c++clinuxgccm4

Use GNU m4 at compile time for large C/C++ project


Background

I have a large project that I'm currently refactoring. One of the problems is massive abuse of string literals (300+ instances) for common paths used by the product (i.e. references to /opt/dev and sub-paths of this location) all over the place, including:

  • C/C++ source and header files.
  • python scripts.
  • bash scripts.
  • systemd scripts.
  • Binary images (drivers).

Goal

I'd like to use GNU to define a file with a set of common macros so we can "write once, use everywhere", so that if our code is branched (typical for a new product), we can just change the macros in that one file, instead of hunting down the duplicate string literals and debugging them for days. This is easy enough for simple things like scripts, as I just create a copy of the source tree in the build output path, and run M4 directly on the scripts.


Problem

The only downside so far is that it looks like this will be a massive effort for C/C++ projects, because I only want to execute the M4 macro expansion/substitution at compile time. This means that, in order to avoid modifying the source files checked out from git, I'll have to modify my build scripts (lots of Makefiles) to work on a temporary copy of the code rather than the original source files themselves. Otherwise, running M4 directly on the version-controlled source will generate a change to the local working copy, and developers are likely to commit this M4-evaluated copy of the code to version control, breaking the M4 effort.


Question

Is it possible to instruct to evaluate macros/expansions during compilation, either via some external tool or some feature of GCC itself? If not, my build scripts will likely require a massive overhaul to support M4 macros.


Solution

  • Use m4 to generate a project-config.h header for the C and/or C++ code. Use that header in every file that needs to use one of the macros. Make sure that programmers know that's what should be used. Possibly enforce the use with code checks before checkin, or periodical scanning of the code base? Recompile affected files when that header changes. Don't change it unnecessarily.