3 ms·
I recently discovered unity builds, only applied to C, and I love the quick build times. 10,000 lines of code, included directly into main from other .c files,
by glouwbug 6y ago
I recently discovered unity builds, only applied to C, and I love the quick build times. 10,000 lines of code, included directly into main from other .c files, compiles in 1 second on my machine with -01 optimizations
- moonchild 6y agoUnity builds are a neat idea, but they just don't scale. One of my projects is about 3k loc (for the time being...) Takes 1.6s to build right now, under clang. (Amazingly, it takes 68ms with tcc, but that's a separate issue.) If I switch to a parallel build, that time halves to only 0.8s. You can't do unity builds in parallel, because there's only one translation unit. Most people will probably get much better than 2x performance from parallel builds; I only have 4 cores. You also can't do incremental builds in unity. If I touch just my biggest file (so only that has to be rebuilt), my compile time halves. Touch the next-biggest file, and it halves again. As a project grows, time it takes to do a full rebuild gets bigger, but incremental builds take about the same amount of time. (They may take slightly longer, as your headers grow or as the linking stage takes more time.) You may have slightly better compile times right now, but they won't last. Incremental, parallel builds still have problems (especially when you get to the scale of linux or chromium), but but there's a reason few people use unity builds.
- glouwbug 6y agoFortunatley I've never surpassed 15,000 lines on a personal project!
- moonchild 6y agoStill, though, your incremental builds will be much faster if you avoid unity builds. Full rebuilds are rare (assuming your build system knows about header dependencies, which it should). Unity builds also make it hard to do abstraction or information hiding well. There's a form of polymorphism in c I describe at [1] which requires separation of translation units. 1. https://comp.lang.c.narkive.com/aa5pZoND/polymorphic-oop-hack https://comp.lang.c.narkive.com/aa5pZoND/polymorphic-oop-hac...
- glouwbug 6y agoTrue, but I typically build with link time optimizations (-flto) since I do a lot of software rendering, and this really hurts incremental builds too. I'll checkout your link, but as for polymorphism I've had good luck with doubly linked lists holding void pointers, and routinely writing maps / filters with #define foreach(node, list, ...) for(Node* node = list->head; node; node = node->next) __VA_ARGS__ And using it along the lines of void Move(List* units) { foreach(node, units, { Unit* unit = node->data; unit->position.x += unit->speed.x; unit->position.y += unit->speed.y; } } Or something along the lines of that
- moonchild 6y ago> link time optimizations Ah, fair enough. (Personally, I don't generally find that the performance delta between having lto on|off is worth the compile time. Maybe for release builds. But usually performance is jut not that much of a concern; I don't bother.) void Move(List* units) { foreach(node, units, { Unit* unit = node->data; unit->position.x += unit->speed.x; unit->position.y += unit->speed.y; } } My approach doesn't enable anything fundamentally different from this. But it makes it more ergonomic and safer.
- glouwbug 6y agoI see your point with opaque pointers though. They are great for code obfuscation when shipping libraries, and totally do require a header / source file split making unity builds not an option. It always amazes me how C can reach the height of most modern languages with a bit of (serious) effort.