Showing posts with label BuildSystem. Show all posts
Showing posts with label BuildSystem. Show all posts

2025-09-20

I don't want a framework, but I do want the convenience

Programming frameworks can be a huge boon in terms of simplifying the provision on desirable features and behavior that aren't the core of your project.1 But they evolve toward someone's ideal of an all-singing, all-dancing, universal tool and that makes them huge and complicated. For a lot of the things I write at home, I don't need most of those facilities and I don't want huge or complicated. But I also don't want to be writing thousands of lines of code just to make my tool ergonomic.

Thankfully the open source community provides hundreds of high quality utility libraries covering all kinds of tasks you might want to do. Usually a handful or more for every feature you might want. Which means you have to choose.

This week, I decided that I wanted a command-line argument processor for a tool I"m dinking on. I've used gengetopt in the past when simple ad hoceries were insufficient, but it needs a two stage build and has a clunky, pure-C interface. Surely I can do better than that!

How to decide?

Well, I have a partial answer: The build system I use for home projects is Meson, which uses a facility it calls "wraps" to support fetching and building projects you depend on.2 Moreover, the tool has a facility to fetching wrap files from a centralized database which makes adding a provisioning library to your project nearly transparent.

So I'm going to restrict my consideration to tools that appear on Awesome C++ and are available from Meson's Wrap DB. There might be other good options out there, but these have had some level of peer review and (critically) are easy for me to get. That gets me down to:

After a cursory reading of the github READMEs it's clear that they all provide the features I need and have a version of the same kind of interface that QT uses.3

But that doesn't mean they're equivalent. One (argparse) uses a Method Chaining (AKA Fluent) interface for the "tell the parse what arguments to expect" step,4 and another (cxxopts) uses method chaining with statically polymorphic calls to operator() which makes a slightly weird syntax that I suspect clang-format is going to balk on. Neither of those is a deal breaker, but they are a little odd. Alas, the third option (CLI11) is a little clunky: requiring you to create two objects and relying on a try-catch for detecting errors (though it provides a c-preprocessor macro to hide the exception handling if you prefer).

Anyone have any relevant experience here?


1They also provide consistency across a set of tools for both users and developers, and you should not neglect that value in that. At work we use Qt, which has all the faults I list above and a swath of legacy issues as well. But the bit where my manager can say "Hey, we like that command line feature you added on your project, put it in Jane's too." And even though I've never worked in Jane's project before I can still dive right in because I know how command-line interactions work in QT. Programming at scale is a team sport and that changes the trade-offs.

2 I already use the doctest wrap in several projects, so I know how this goes.

3 You create a parser object, tell it what arguments you expect, pass it the command line, and then ask it what it found. With convenience facilities for detecting violated expectations, issuing help messages, and so on.

4 I've tried method chaining a few times in my own coding, and found that I only like it in cases where most of the uses of a class are going to be transient. Thankfully, if you declare a named object you don't have to use the fluent syntax if you don't want it.

2023-09-14

Really, Qt?

Qt Creator is poluting my nice clear build results window with a complaint that my build directory is not on the same level of the filesystem as my source directory. It's a new complaint even though I've been using Qt Creator for ages, because I recently had to re-oganize my work a little. I have, for a long time, used a layout where by source, build, and distribution directories for each project are sub-directories of $HOME/source, $HOME/build, and $HOME/dist which actually meets Qt's strange requirement.1 Alas IT issued a new edict concerning the centalized backup system and on windows I've been forced to move my source hierarchy to $HOME/Documents/source on that platform. Which broke QT's little brain.

The policy is, presumably, intended to enfore a prefernce for out-of-source build, which is a good idea (every build should be out of source). But it is also way, way too restrictive a way to enforece that behavior.


1 This lets be share the source directory across the Windows host, several WSL linux installations, and the few VMs I still run while each platform maintains it's own build and distribution locations.

2023-03-22

Don't save!

I do a lot of programming at work in Qt Creator which is a perfectly acceptable IDE,1 and up until recently we used qmake to manage the build for basically the same reason we use Qt Creator: because these are Qt projects and the native tools understand them.

But several things have happened recently2 that collectively have made us move to cmake for most projects. And that means we've bumped into a quirk of the IDE: there is a big time-cost to changing the CMakeLists.txt files. Not I hasten to add because its any slower than anything else in running cmake. It does that just fine. But after it re-configures the build, it re-scans the project to locate files that should be listed in the project tree-view. For more than thirty second in the case of my main project. And for some reason it does this as a synchronous operation: preventing you from taking any other action in the IDE.

Now, most of the time this is a non-issue: I'm working on the code not the build, so it rarely comes up and is a minor annoyance.

But if you are working on the build (as I was this afternoon), it is critical to overrule that "hit the save key-combo everytime you pause to think" reflex that makes so much sense at other times.


1 I mean, it can't refactor template code very well, but you can at least learn how it fails and know how to fix up the results.

2 Qt has deprecated qmake with Qt6, we've started using some of our code (including a underlying library) with third party projects that use cmake, and we have found that cmake is slightly better at parallelizing bigish builds resulting in slighlty but noticiably faster edit-compiler-test cycles.

2020-11-20

Success! Kinda.

So, my efforts to flatpak clang-format have succeeded. If you are willing to interpret 750MB for one program as success.

But hey, the first attempt generated a 17GB package (and took three hours to build on a fast four-core machine compared to 15 minutes for the current iteration), so this looks pretty good by comparison. But I'm still remembering that my first $N$ linux boxes had smaller disks than that. Including the one I analyzed my dissertation data on.

Anyway, this being something I did for work I can't share the actual build manifest with you, but I can offer some pieces of advice:

  • Get the code from the git repository rather than downloading tarbals. You can do this in the source section of the manifest.
  • Don't use buildsystem: cmake (or cmake-ninja) which will just build everything, but instead use buildsystem: simple and issue the build commands yourself. This lets you do ninja clang-format and thereby get the build system to pick out the minimal set for you.
  • To figure out exactly what was needed by way of installation I put some finds amung the build commands and used flatback-builder -v so that I could see all the output. With the build down to a quarter of an hour, several passes through the build process to get it right is cumbersome but tolerable. Remember that you are installing libraries as well as the executable.

I imagine that some size could be saved by a fully static build, but this will do so it's no longer worth my time.


Followup: A simple "static" build of the program occupies between 2.3 and 6.8 MB on the platforms I care about. I think this may be the way to go. I put scare quotes in there because on gcc doesn't like to statically link a number of libraries (glibc for one) so these things are not completely static and accordinagly not cross-platform. But the build is less than fifiteen minutes on my fast test machine, so we can afford to build it as needed while setting up a new repository.

2020-05-09

Chosing a new build system

I've started a couple of little software projects which might evolve into something worth putting out in public. Indeed, if I'm committed to open source approaches I should probably put them out there fairly early on. But even with the bare bones, just-preparing-the-ground state of these projects I'd like potential users and contributors to have a smooth path to seeing what little functionality is actually done. Which means having a well designed and at least somewhat cross-platform build.

Now, I'm a Unix guy. I can write a simple makefile starting from a bare editor without breaking a sweat. I've maintained or extended the make-based build on projects with several hundred-thousand lines of code and many hundreds of source files targeting Unix, Windows, and MacOS. I respect make. But...I've maintained or extended the make-based build on projects with several hundred-thousand lines of code and many hundreds of source files targeting Unix, Windows, and MacOS. So I know how hard it is to get a make-based build to scale up without hiccups and what a pain it is to get it to do cross-platform smoothly and reliably. There ought to be something better.

XKCD Standards
Hat-tip to Randall Monroe
I've started looking into what options are available. If you've asked this question any time in the last fifteen years or so you know exactly what I've found.

Lots and lots of contenders, lots and lots of reviews and comparisons, and lots and lots of opinions. But nothing like a consensus. A great many of the contenders are stagnant or abandoned, while others never seem to have evolved beyond some niche or another. I suppose we can conclude that a lot of people think this issue is a pain point and that the problem is harder than it looks. Certainly building has a lot of inherent complexity and and cross-platform building is more complex still.

I'm tempted by meson (and I really appreciate Evan Martin's philosophical position about separating a fast DAG walking component from a intelligent decision making component), but I'm far from confident that it is the best choice. I'm also tempted by tup simply because I'm impressed by the improved asymptotic performance of the underlying process1 but I think the syntax is a little wonky.

Any thoughts?

Aside: If any one of my handful of occasional readers thinks that cmake is the obvious choice, I'll warn you that you're facing an uphill battle to convince me.2 I've had the dubious pleasure of getting to tweak the build of projects supported by that thing and I like it rather less than qmake (which I don't like much and don't consider a contender for projects not involving Qt).




1 There is an aspect of the linked paper that I really don't like. A couple of times the authors criticize Recursive Make Considered Harmful for insisting that you have to have the full DAG for correct build and they claim that they've proved that this isn't true. Except that they do have and use the full graph (remember that they have to cache the graph). They've found a way to avoid walking the whole thing (by using the change list to select the affected sub-trees), but they have to have it to start with or they have to build it before they begin. This is basically a problem with language and the way they form they claims, but it is also basically wrong. When writing a paper you certainly want to promote your work but you shouldn't over claim which is exactly what they've done there.

2 I've read many claims that the syntax of cmake 3 is so much better than that of earlier editions that people who dismissed the previous version should really look again. I find that scary because I've only ever worked with the "new" syntax and it's more than enough to put me off. Can you get Stockholm syndrome from working with difficult software tools?