DEV Community

RZM64
RZM64

Posted on Edited on

I was tired of writing CMake. So I built a simpler build system.

I was tired of writing CMake, so I built a simpler build system

The frustration

I didn't start building HelpMake because I was bored. I started because CMake kept breaking on me.

It would not work for me. CMake was bugging, crashing, complex to learn, annoying... At some point I realized I wasn't the only one. Every C++ Discord, every Reddit thread, every "what's wrong with my build" question, it's the same story. People don't hate CMake because it's bad. They hate it because it's a lot, and it breaks in ways that aren't obvious, and every project needs a slightly different incantation to make it work.

The CMakeLists.txt itself isn't really the problem. It's everything around it. The generator step. The out-of-source build requirement. The "why is it building in Debug when I didn't specify". The "why does this work on Linux but not Windows".

I don't build 100,000-file projects. I build 5–20 file projects. Sometimes 50. For that scope, CMake is a lot of machinery for a small job, and the failure modes are worse than the thing it's trying to solve.

So I built a build system where the whole config fits on one screen and you build with one command. Not one command to configure another to build. Just one.

Wait, zero config?

When I released the first version, you still had to write a HelpMake.txt file. But I kept asking myself: "If it's so simple, why do I need to write anything at all?"

So I added auto-detection. Now, you can literally drop hm into any existing C/C++ project directory, run hm -b, and it figures out the rest.

It auto-detects:

  • The compiler (probes g++, clang++, cl, zig, etc.)
  • The standard version (runs -dumpversion)
  • Source files (walks src/, skipping .git and build)
  • Includes, link flags (like -pthread or -lm)
  • Target kind (executable vs static)
  • Output name and extension

Every guess it makes is printed in the terminal so you can see exactly what it inferred.

What if I want control?

If you do want to configure it, the entire config for a small C++ project looks like this:

Compiler: g++
Version: std=c++20
Output: build/app

InputFiles {
    src/**/*.cpp # built-in recursive glob
}

Includes {
    include
}

Flags {
    -Wall
    -O2
}
Enter fullscreen mode Exit fullscreen mode

Run hm -b and you get a binary. No configure step, no generator, no build directory you have to manage.

Wait, another build system?

I know. There are dozens. But every one I tried had the same problem:

  • Make - doable, but you can't see the whole build script on one screen, and it's not cross-platform by design.
  • CMake - powerful, but a lot of ceremony for small projects.
  • Meson - nice, but you still configure before you build.
  • Bazel - for Google-scale monorepos, not side projects.
  • Ninja - a backend, not something you write by hand.

The gap I kept running into: there's a "too much" tier (CMake, Bazel, Meson) and a "too raw" tier (Make, Ninja), but no lightweight tier that's actually simple.

That's the tier I wanted.

What's actually interesting about it

The basic config isn't the interesting part. It's how a build system should work. These three things are why people actually use HelpMake:

1. Cross-platform without duplication

On Windows you want /W4 and /EHsc. On Linux you want -Wall -Wextra -pthread. In CMake that's if(WIN32) ... else() ... endif() blocks. In HelpMake:

Flags {
    -Wall
    win: /W4 /EHsc
    linux: -Wextra -pthread
    mac: -Wextra
    x64: -march=native
}
Enter fullscreen mode Exit fullscreen mode

The win: and linux: prefixes are platform conditionals. Any line can have one. One config for every OS.

2. hm test - a real test runner

Mark configs as tests:

Config: test-core {
    Test: true                  # Save as test
    Output: build/test-core
    InputFiles { tests/core.cpp }
}
Enter fullscreen mode Exit fullscreen mode

hm test builds and runs every marked config. Exit code 1 on failure. That's what CI needs, built in, no separate ctest step.

3. hm -b -w - watch mode

Save a file, rebuild. Save a file, rebuild. hm -b -w -r builds, runs, and rebuilds on save. That's the entire dev loop in one command.

Honest caveats

HelpMake isn't trying to replace CMake. It won't:

  • Generate Visual Studio solutions
  • Auto-detect hundreds of system libraries (you write Dependency: raylib { ... } for external libs)
  • Handle 100,000-file projects
  • Give you CMakeLists.txt compatibility if you need to hand the project to someone using CMake

If you need any of those, use CMake. Seriously.

HelpMake is for the projects where CMake feels like overkill - which, for a solo dev or a small team, is most of them.

What I learned building it

Three things I didn't expect:

  1. C++20 modules are still a mess in build systems. Every compiler handles them differently. Getting GCC and Clang working end-to-end took more time than the rest of the parser combined.
  2. "Just one more flag" is how build configs get to 200 lines. Every feature I added had to justify why the user can't just put it in Flags { }. That constraint kept the file format small.
  3. The hard part isn't the build system. It's the error messages. A build system that fails with "compilation failed" is useless. HelpMake tries to say HelpMake.txt:42: unknown field 'Compilr:' - did you mean 'Compiler:'? Getting those right is most of the work.

Try it

If you've read this far, you probably have a project in mind where CMake feels like too much.

Windows (Scoop):

scoop bucket add helpmake https://github.com/Gag91/scoop-helpmake
scoop install helpmake
Enter fullscreen mode Exit fullscreen mode

Linux / macOS / WSL (Script):

curl -fsSL https://raw.githubusercontent.com/Gag91/Help_Make/main/install.sh | bash
Enter fullscreen mode Exit fullscreen mode

Then just cd into your project and run:

hm -b
Enter fullscreen mode Exit fullscreen mode

MIT licensed. Single binary, no runtime dependencies. If it's useful, a ⭐ on the repo helps other people find it.

If it's not useful - if CMake is the right tool for your project - that's completely fine, and I'd love to hear what your CMake setup looks like. That's the kind of feedback that makes the next version better.

  • Xavi

Top comments (1)

Collapse
 
rzm64_c7017ade827d335e7ea profile image
RZM64 •

I just finished editing the post :)

⌂ 换网址