Cobble Something Together

There are plenty of amazing build systems out there. Make is old and well tested. CMake is newer and is better supported on more platforms. It also has a lot of nifty features that make it more flexible, like standardized way of providing options when building. CMake is very good, and I would highly recommend having at least a passing knowledge of it since it is used in so many popular open source projects.

I personally really like Bazel, even moreso than CMake if given the option. It was actually my goto build system even before working at Google, so you can't tell me I'm just biased :p. Bazel is slightly nicer because builds are faster and more reproducible. The build files are also far more strict -- which is a good thing, trust me. It makes it easier to read and understand than any but the most simple CMake files. I would recommend trying it if starting a new project from scratch, but I understand that it can be a pain when trying to combine with existing libraries and other build systems.

On the other hand, there are two problems that I've had with bazel:

  1. First, it would be really nice if it watched files for changes and automatically rebuilt the target for you. Now, bazel is a build tool designed by Google, for a Google scale code base. It makes sense why it doesn't do this. The number of files that it would have to watch would be too large, and the actual build time can be enormous. This can be solved by using a separate wrapper tool known as ibazel, but I must admit that I haven't actually used it before.
  2. Second, it requires repeating yourself. A lot. The build files have to know about every file that the build could possibly depend on. And every file that those files depend on. Repeat. Again, this makes sense for a Google scale project -- if you are building the target on a server, and the repository is massive so that you don't want to (or simply can't) download the entire codebase at the same time, then it makes sense to explictly define what files, and all files, the build system needs to fetch upfront.

What may or may not be surprising, though, is that most codebases are not at a Google scale.

Lately, I've been wondering what a build system designed for smaller projects or just prototypes might look like. And while we're at it, why don't we try to solve the problems with the build systems mentioned above. I mean, why go through all this effort only to make things worse?

So I started building cobble. I'm not going to push it on anyone -- it's definitely not feature complete or production ready, but I wanted to show off a few of the cool features that I am excited about.

  1. The build system is lightweight; additional functionality can be added using plugins. This one is only subjectively a benefit. But the issue this solves is that the system becomes more useful at building projects that are built in more than one language, like most current web projects. Load the plugins that you need or roll your own if you have a custom file type you want to handle.
  2. The config file is simply JSON. It should be easy to read, and easy to write. I want to be able to throw it together in a hurry, and expressive enough that plugins can support additional features that I may have not even thought of. This is the one feature that is undergoing the most change, as it's all about what feels good to use, so this ends up being mostly a guess and check process.
  3. Dependencies are implicit. You only have to specify the source files that aren't referenced by any other files. So for a C++ project, this means the .cpp files, but not the headers. The source files already reference the headers, so why would we need to repeat ourselves and explicitly specify that we need them? Typescript, sass, and clang are the first language / tool plugins that I created for myself. All had already provided a mechanism for outputting the imported files. Typescript and sass libraries both have callbacks that can be passed to the nodejs APIs to get them, and clang has a special flag (-MM) that can be passed to output the Make files instead of actually compiling the files.
  4. Files are watched for changes. When I save a file, I want to be able to test it immediately. And if it fails to compile, it shouldn't prevent me from running the previous working version. This one is huge for me, as sometimes I'm working on one file knowing that I'll need to go back and edit another file to make corresponding changes (think adding an additional parameter to a function), but then someone walks up behind you and wants to see what you're working on. It's always nice to have the previously working version ready so that you can show it off.

If you're bored and throwing together a small prototype, feel free to give it a shot and try it out. And if you run into any problems, feel free to create an issue on github and I'll try to help you out :)