Skip to content

AntonHakansson/cbuild

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

57 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

cbuild: Makefile on steroids in C.

Opinionated proof-of-concept build system/library using C. Describe how to build your project in C instead of a Domain Specific Language (DSL). No need to install, learn, or debug tools such as Makefiles, CMake, Ninja, etc. The build tool(e.g. gnumake, cmake) and describing how to build targets(e.g. Makefiles, CMakelists.txt) are consolidated into one program (cbuild).

Highlights:

  • Single header library with no external dependencies except libc and a compiler(gcc, clang).
  • Not limited by DSL. Use C to do whatever you want at build time!
  • Debug your build process using tools available for C (gdb, sanitizers, etc.)
  • [WIP] Suitable for cross-platform builds (only linux for now)
  • Reuse cbuild.h for scaffolding your C program with arena memory management, dynamic arrays, string-builder/slices, and small platform abstraction.

Quickstart

cc -o cbuild cbuild.c # only once!
./cbuild

On subsequent changes to cbuild.c you do not have to recompile manually. Run ./cbuild and the build tool re-compiles itself.

Future ideas

Some ideas that will probably never come to fruition.

Rebuild target when hash of build function changed

Right now we rebuild targets(including cbuild itself) when the last modified timestamp of source files are newer than the target output file. A more granular approach is to compute a hash for functions that describe how to build a target and recompile both cbuild and the target when the hash is updated.

#define CBUILD_HASH

CBUILD_HASH CB_b32 build_foo(...) { ... }

cb_compute_hashes("./cbuild.c");
char *old_hash = ...; // read from disk
CB_b32 foo_needs_rebuild = cb_changed(build_foo, old_hash)

A drawback of this approach is that we have to store the hashes on disk - maybe introduce build/cbuild.cache. Another wild idea would be to embed the hashes into the cbuild executable itself.

Export minimally viable CMake for compatibility

Export the most basic cmake project for distribution. All Package Maintainers probably know how to make CMake work.

To do this we need to build a tree of dependencies between targets that clashes with our current immediate mode design. I think it’s possible to keep the immediate paradigm and defer compiling the targets to the end.

Metaprogramming

Make it easy to introspect C code and metaprogram (i.e. parse C and output C). Get access to compile time type info, or seamlessly implement custom language features etc. Also, compared to preprocessor macros, the metaprogram, and its output, is typesafe and debuggable.

// foo.c
#ifdef CBUILD_METAPROGRAM
struct Slice {
  $T *items;
  size len;
};
#else
// The output of the metaprogram could be commited in the source tree
// to guarantee the program compiles without cbuild.
#include "foo.meta.c" // output of the metaprogram would go in here
/* foo.meta.c:
  typedef struct { char **items; size len;  } SLice_Char;
  // .. typeinfo about Slice_Char
  typedef struct { i32 *items; size len;  } SLice_I32;
  // .. typeinfo about Slice_I32
 */
#endif

References / Influences

tsoding
nob, REBUILD_YOURSELF macro
nullprogram
dynamic arrays, string builder and more
ryanjfleury
arena memory management

About

Makefile on steroids

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages