Live data from Hacker News

Everything you never wanted to know about CMake (redux)

izzys.casa

41–50 of 58 posts

Re: Everything you never wanted to know about CMake (redux)

#41

Earlier quoted context omitted.

Deadly serious. My goal is to make a build system that the majority of people don't hate. I understand your concerns about a fully-powerful system. I know that's why Bazel is a favorite. But Nix has the same reliability with a full Turing-complete language, and I feel like I can recover the performance by using C instead of Java. In addition, I understand the purpose of limited languages in build systems. I really do…

What advantages does this system provide? Could you give a motivating example? Bazel’s BUILD.bazel scripts are restricted, but that part is the middle of a “sandwich” which handles the 90% use cases. If you want unfettered execution, you get that in the repository rule phase and the actual build actions (the two slices of bread in our sandwich). This allows you to define build rules dynamically (as long as you can do…

Good questions.

To be frank, Bazel is the build system that comes closest. The biggest selling point of mine against Bazel would be usability (I hope). So really, I would suggest people stay on Bazel if they already are.

(In fact, I would suggest that CMake users stay on CMake. I only want to capture new projects to start. If my build system then proves itself, people who need to will switch by themselves.)

About dynamic capabilities, that's not quite what I mean by defining build rules dynamically. Your qualification ("as long as you can do it before the main part of the build runs") throws out everything I meant. In addition, CMake can do that too.

However, it does sound like Bazel can otherwise run arbitrary code in build actions. Those restrictions you mention are fundamental to sandboxed build systems, so I don't include those.

Yes, my build system will be able to be hermetic and do sandboxing. It will do it in two ways, one of which will be like Bazel. The other will be a sandbox in the interpreter itself.

These will be per build rule and global. There will be no downloading stuff from the Internet if you don't allow it, and build rules will only be able to use outside commands that you allow. (For example, you could allow only the C compiler for a C project.) The sandbox could be even tighter and will be runtime-based: actions could be rejected at runtime based on runtime values.

So if there's a smaller selling point, I hope it would be better protection against malicious build scripts.

A motivating example: headers in C and C++.

What headers a file may use can depend on the build configuration (through preprocessor defines and such).

Yes, you can make a rule to run the preprocessor on the file, then make a separate rule to run the compiler on the preprocessed file. But there is no way to make the preprocessed file depend on the headers because its dependencies must be defined before the build and the list of included files is generated during the build.

"Okay, but why can't you just generate the list of files on an initial build and just use that in later builds?"

You can, and that is what DJB's redo does. But say that you change a file a header A included by a header B included by a file C. C knows it depends on B. It may know that it actually depends on header A too, but if it doesn't, it won't get rebuilt.

Motivating example 2: say you have a language with packages, like Python, except that it's compiled.

You have the main program that imports packages. It can dynamically generate targets for imported packages and dynamically depend on them. And do this recursively.

You are hard at work doing development. You already have done several builds. You change one file to import a new package you just created. Do you need to change the build file or do a clean build? Nope. The task recognizes the new dependency, suspends itself to build the new package, and then resumes. You are none the wiser.

Even better, your dependency information is contained in the actual source, not your build system. There is no duplication. And it "just works."

Re: Everything you never wanted to know about CMake (redux)

#42

Earlier quoted context omitted.

I beg to disagree. Sure, when you want to have a small project that only uses crates.io d'EPS, Cargo is simple and gets the job done. But once you want to do something a bit more complex, (like getting a dependency of something not written in rust, or picking features based on some system configuration), you quickly get to the limitations and there is not much you can do. Cmake on the other hand is very powerful and…

> like getting a dependency of something not written in rust, or picking features based on some system configuration I've found that things like this are pretty straightforward with a build.rs and you aren't context switching between a configuration language and your target language since build.rs is just a Rust program that outputs configuration values via println. > ... very complex applications That's not always a…

> I've found that things like this are pretty straightforward with a build.rs

- build.rs can't change the feature set.

- what they usually do to bring dependency is vendor the C files within the crates, but when it comes to configuring to use an installed library and passing the right linker flags, this becomes really tricky.

Re: Everything you never wanted to know about CMake (redux)

#43

Earlier quoted context omitted.

Quite a lot of "Could be worse. Could be Autotools." for me.

from the perspective of someone who spends 100x more time trying to compile other people’s software than writing my own build scripts, they don’t really feel that different. CMake seems to offer more features/builtins, but without doing much to actually tame complexity. which isn’t necessarily a good thing because then the people who think it’s a good idea to shove complexity into their build system just do more of t…

Yeah, at some point I feel like certain things have an irreducible amount of complexity that ends up getting moved around like an air bubble stuck under plastic laminate. Sometimes moving the complexity helms, sometimes it feels like it’s more trouble than it’s worth. CMake seems to be a net positive, but it’s not without substantial pain at time.

Re: Everything you never wanted to know about CMake (redux)

#44

Earlier quoted context omitted.

> like getting a dependency of something not written in rust, or picking features based on some system configuration I've found that things like this are pretty straightforward with a build.rs and you aren't context switching between a configuration language and your target language since build.rs is just a Rust program that outputs configuration values via println. > ... very complex applications That's not always a…

> I've found that things like this are pretty straightforward with a build.rs - build.rs can't change the feature set. - what they usually do to bring dependency is vendor the C files within the crates, but when it comes to configuring to use an installed library and passing the right linker flags, this becomes really tricky.

> build.rs can't change the feature set.

Can you be more specific here? You can totally do that based on OS, environment vars or even direct feature flags in the Cargo.toml. I've got a number of projects that do this and let downstream consumers decide what features they want. At the end of the day it's just a Rust program that runs ahead of the build and can do anything that you would be able to do in a normal command line program.

> ... but when it comes to configuring to use an installed library and passing the right linker flags, this becomes really tricky.

pkg-config[1] does all of that including returning linker flags. I can't think of a single case where I wasn't able to integrate with an existing library.

I'm not saying there are zero issues(I.E. passing some linker flags as a dependent crate gets annoying) but my experience having used C++ across a number of platforms(Win32, Linux, proprietary systems) before CMake existed and after it started getting wider adoption is that CMake has a significantly higher hurdle and is just harder to get things working correctly, especially under cross-compilation configurations.

[1] https://crates.io/crates/pkg-config

Re: Everything you never wanted to know about CMake (redux)

#45

I cannot overemphasize how enjoyable it is to work with cargo when I'm coding in Rust; I think it's one of the major reasons why Rust took off. As complicated as Rust is, it's a breeze to not only build projects but also add existing projects as dependencies.

I beg to disagree. Sure, when you want to have a small project that only uses crates.io d'EPS, Cargo is simple and gets the job done. But once you want to do something a bit more complex, (like getting a dependency of something not written in rust, or picking features based on some system configuration), you quickly get to the limitations and there is not much you can do. Cmake on the other hand is very powerful and…

Ok, but do you actually enjoy using CMake, or do you accept how horribly complex it is because it lets you do some esoteric thing you want to do?

Every tool has limitations, sure. But I think you're disagreeing about something I didn't even say. I didn't say cargo can replace CMake. I said that cargo is really a pleasure to use when it's the tool you need. If you had the choice to either build with CMake or cargo, I promise you that you'd rather use cargo if possible.

Building most C/C++ projects seems pretty miserable no matter what build process you're using. CMake seems like a huge mental burden in itself. Cargo just does its job and gets out of the way.

Re: Everything you never wanted to know about CMake (redux)

#46

Earlier quoted context omitted.

from the perspective of someone who spends 100x more time trying to compile other people’s software than writing my own build scripts, they don’t really feel that different. CMake seems to offer more features/builtins, but without doing much to actually tame complexity. which isn’t necessarily a good thing because then the people who think it’s a good idea to shove complexity into their build system just do more of t…

Yeah, at some point I feel like certain things have an irreducible amount of complexity that ends up getting moved around like an air bubble stuck under plastic laminate. Sometimes moving the complexity helms, sometimes it feels like it’s more trouble than it’s worth. CMake seems to be a net positive, but it’s not without substantial pain at time.

that’s a really fun metaphor — and it does capture a lot of my day to day experience. but a lot of these bubbles can also be split apart or joined, and doing that skillfully has pretty huge social implications in open source.

i’ve been toying around recently with [sxmo]. at the top level, it’s a collection of shell scripts. when any script would become too complex, it’s factored out into some library-like abstraction and lifted into a different repo, language, etc.

i’m coming at this from phosh, after i hit a bug in it, opened the code base to debug it, and realized “i have no clue where to even start”. desktops already split the bubbles of complexity into components like compositors, window managers, service managers. sxmo shows that you can be even more extreme in this: any time a single bubble of complexity grows too large, break it up into smaller bubbles. do this rigorously and it means any time the software doesn’t behave as i want, i can pretty confidently plot a path to fixing/improving it (and know how long it’ll take and therefore if it’s worth the time).

there’s complexity inherent in anything, but there’s a lot of different ways you can arrange it. my experience with CMake is that the complexity sort of just pervades the whole stack, rather than being isolated into manageable bubbles at all.

sxmo: https://sxmo.org/

Re: Everything you never wanted to know about CMake (redux)

#47
A good chunk of my day job is beating sense into CMakeLists.txt files. It's exhausting in every meaningful dimension. In my literal decades of working with cmake, no amount of familiarity has ever brought me contentment. Rather, with each passing release, the contortions grow ever more torturous.

At one point, on one project, in a moment of supreme frustration, I replaced cmake with GNU Make and a single Makefile. I'm not proud, but for that one instance, it was a good decision because It Just Worked.

Re: Everything you never wanted to know about CMake (redux)

#48

All these CMake improvements are the best example of optimising into a local minimum I have ever seen in SWE

That's the most insightful description of cmake featurism I've ever read. Kitware seems to work tirelessly to reach technical mediocrity.

Re: Everything you never wanted to know about CMake (redux)

#49

All these CMake improvements are the best example of optimising into a local minimum I have ever seen in SWE

Good phrasing! I’m just a hobbyist so I don’t get very involved but what would you suggest as an alternative maximum?

Use whatever your chosen platform supports "natively". If you're on Linux like me, then use GNU Make or even a Bash script. I'm sure Windows users have something different.

Here's the important part: move to a more powerful tool after you decide to support other platforms --- and before circumstances force your hand.

Re: Everything you never wanted to know about CMake (redux)

#50

Earlier quoted context omitted.

What advantages does this system provide? Could you give a motivating example? Bazel’s BUILD.bazel scripts are restricted, but that part is the middle of a “sandwich” which handles the 90% use cases. If you want unfettered execution, you get that in the repository rule phase and the actual build actions (the two slices of bread in our sandwich). This allows you to define build rules dynamically (as long as you can do…

Good questions. To be frank, Bazel is the build system that comes closest. The biggest selling point of mine against Bazel would be usability (I hope). So really, I would suggest people stay on Bazel if they already are. (In fact, I would suggest that CMake users stay on CMake. I only want to capture new projects to start. If my build system then proves itself, people who need to will switch by themselves.) About dyn…

> But there is no way to make the preprocessed file depend on the headers because its dependencies must be defined before the build and the list of included files is generated during the build.

The actual dependencies of a build action in Bazel are defined at build-time, dynamically, after the action runs. So you do not need to know the exact dependencies ahead of time, you just need a superset—not something you can really avoid, as far as I can tell, because the way that #include will search multiple paths.

For languages like Go, where I can just import packages, the build file will be updated automatically to match the source files. This is done using a tool called Gazelle. I know this is possible in other languages as well, such as C++, I just don’t use those tools.

“Dependency information in the actual source” is what you get with Gazelle. There is some duplication in the build files, but I like this and find it useful—you can redirect dependencies to be fulfilled by other targets than what would be the default, for example.

Post reply on HN