Live data from Hacker News

The Language Agnostic, All-Purpose, Incredible, Makefile

blog.mindlessness.life

51–60 of 124 posts

Re: The Language Agnostic, All-Purpose, Incredible, Makefile

#51
post #34

Earlier quoted context omitted.

Yeah, I know about Bazel, but only at a high level--I haven't used it. I generally think the hermetic build concept is a very good one, but IMO Bazel goes about it the wrong way, and is overengineered. Rather than needing custom-built infrastructure for every type of language supported, I'd prefer build systems to use lower level OS facilities for discovering dependencies and controlling nondeterministic behavior. Th…

> Rather than needing custom-built infrastructure for every type of language supported My understanding is that bazel is moving away from this, so that you can define toolchains by saying "here is a binary that serves the job of linking/compiling stuff". The challenge with your idea is that you're basically saying "hey, we should sandbox and introspect to intercept and modify their filesystem and network (at a minimu…

> My understanding is that bazel is moving away from this, so that you can define toolchains by saying "here is a binary that serves the job of linking/compiling stuff".

How do they ensure determinism in that case? Is it just an easy escape hatch so that new languages can be easily supported, with no actual guarantees of hermeticity?

> The challenge with your idea is that you're basically saying "hey, we should sandbox and introspect to intercept and modify their filesystem and network (at a minimum) accesses, across any number of versions and uses".

I think my approach would certainly use a syscall whitelist. Any unsupported syscall would be a build failure, and presumably a bug report if it's a legitimate use. I suspect most build commands can get by with a pretty minimal set of syscalls (mainly basic filesystem access). At some point though, if you start supporting more and more syscalls, you start re-implementing VMs/containers, which sucks. This build system only stays simple if people don't try to do a bunch of wacky things with it :)

Network accesses would probably get whitelisted by the user on a rule-by-rule basis for cases like "download these packages", with the outputs treated as always dirty. The tool would be responsible for running efficiently even if no work actually needs to be done.

One weird/hard thing to support would be soft/hard linking. I'm not sure exactly what should be done there, but that might not be needed for early versions.

> Even just handling conditionally rewriting file writes/reads based on guessing whether something is an input or re-used output isn't that easy in general.

I'm not sure I understand this. One thing I should note is that in my scheme, you still have to specify output files for rules--you only get to skip specifying the inputs.

Re: The Language Agnostic, All-Purpose, Incredible, Makefile

#52
post #47
post #2

Make is great, and I wish more people would use it in place of whatever monstrosity is en vogue this week. However, there is one thing which Make absolutely cannot handle, and that is file names with spaces . If you have any risk of encountering these without any possibility of renaming them, you’ll sadly have to give up on using Make; it just won’t work.

And are we gonna talk about case-insensitive filesystems? cringe

I can't imagine why. I run make on case-insensitive-but-case-preserving HFS+ and APFS-formatted disks all the time.

Re: The Language Agnostic, All-Purpose, Incredible, Makefile

#53
post #7
post #2

Make is great, and I wish more people would use it in place of whatever monstrosity is en vogue this week. However, there is one thing which Make absolutely cannot handle, and that is file names with spaces . If you have any risk of encountering these without any possibility of renaming them, you’ll sadly have to give up on using Make; it just won’t work.

I agree, and the solution to this problem is to forbid filenames with spaces. The convenience of make and similar tools is much more important than spaces in filenames. File names with spaces should not be allowed in modern filesystems. When the user types a filename with spaces, the GUI should encode the space as a non-breaking space character, that does not cause havoc in scripts.

I can't tell if you are being sarcastic.

Re: The Language Agnostic, All-Purpose, Incredible, Makefile

#54
post #51

Earlier quoted context omitted.

> Rather than needing custom-built infrastructure for every type of language supported My understanding is that bazel is moving away from this, so that you can define toolchains by saying "here is a binary that serves the job of linking/compiling stuff". The challenge with your idea is that you're basically saying "hey, we should sandbox and introspect to intercept and modify their filesystem and network (at a minimu…

> My understanding is that bazel is moving away from this, so that you can define toolchains by saying "here is a binary that serves the job of linking/compiling stuff". How do they ensure determinism in that case? Is it just an easy escape hatch so that new languages can be easily supported, with no actual guarantees of hermeticity? > The challenge with your idea is that you're basically saying "hey, we should sandb…

> Is it just an easy escape hatch so that new languages can be easily supported, with no actual guarantees of hermeticity?

Yes, I mean in general some level of compiler hermeticity is assumed. You can verify it by checksumming everything (which bazel does), but you can easily destroy the performance/caching of bazel by modifying clang to have intentionally unpredictable results.

> One weird/hard thing to support would be soft/hard linking. I'm not sure exactly what should be done there, but that might not be needed for early versions.

I think bazels solution here is to just always make fat binaries. Or at least that's how it works if you're using blaze.

> I'm not sure I understand this. One thing I should note is that in my scheme, you still have to specify output files for rules--you only get to skip specifying the inputs.

Ah this helps somewhat, I think there are still potential ambiguities, one thing that bazel can do is statically determine all of the input sources without actually executing the build. You of course can't do this. This has a few nice properties: you get missing input errors before doing any actual building, you have a build graph you can statically analyze (deps queries are magic), and all the sandboxing can be done ahead of time (with symlinks to create a shadow filesystem) instead of ad-hoc, you can parallelize everything, meaning you can saturate all your machines the entire time.

With strace, you have performance issues from the tracing itself, and you can't precompile all the dependencies beforehand you have to discover them as you go (this likely also hurts on memory since you'd need to keep all the partial compiler information in memory).

I also find it easier to reason about stuff with explicit deps, but that's just me.

Re: The Language Agnostic, All-Purpose, Incredible, Makefile

#55
post #9

Make is great as a dependency resolution engine. For everything else, it is absolutely horrible. What I typically do is use make only for what it is good: as a dependency resolution back-end. All the build logic for my projects is written in Python, in an executable file stored in the project root directory and called "make" (I have "." in my PATH). The Python script, when it runs, generates on the fly a clean, lean,…

pyinvoke can be used to define Makefile-like tasks in Python. http://www.pyinvoke.org/ http://fabfile.org allows to execute the commands remotely via ssh

Re: The Language Agnostic, All-Purpose, Incredible, Makefile

#56
post #23
post #2

Make is great, and I wish more people would use it in place of whatever monstrosity is en vogue this week. However, there is one thing which Make absolutely cannot handle, and that is file names with spaces . If you have any risk of encountering these without any possibility of renaming them, you’ll sadly have to give up on using Make; it just won’t work.

Make is useful and the concept is sound. However, the implementation is dated. Just off the top of my head, it could be object oriented (rules could be subclassed), the language could have more sophisticated statements, it could have debugging, etc

Why is old bad? I can't tell you how often one of my team shows me some clever, non-trivial Python script that I solve in a couple of lines of awk/sed/perl. Or a small makefile. Why in the world would I want an OOP make? What do I need 'more sophisticated' in make statements that wouldn't really mean that I needed to be using a different tool that undoubtedly wasn't solving the problem make solves?

OK...debugging could be better. Got me there.

Re: The Language Agnostic, All-Purpose, Incredible, Makefile

#57
post #51

Earlier quoted context omitted.

> My understanding is that bazel is moving away from this, so that you can define toolchains by saying "here is a binary that serves the job of linking/compiling stuff". How do they ensure determinism in that case? Is it just an easy escape hatch so that new languages can be easily supported, with no actual guarantees of hermeticity? > The challenge with your idea is that you're basically saying "hey, we should sandb…

> Is it just an easy escape hatch so that new languages can be easily supported, with no actual guarantees of hermeticity? Yes, I mean in general some level of compiler hermeticity is assumed. You can verify it by checksumming everything (which bazel does), but you can easily destroy the performance/caching of bazel by modifying clang to have intentionally unpredictable results. > One weird/hard thing to support woul…

> I think bazels solution here is to just always make fat binaries. Or at least that's how it works if you're using blaze.

Oh, I should've specified soft/hard filesystem links--they'd make handling a virtual filesystem rather complicated. Dynamic linking is another strange case, but it looks like dylib loading happens in userspace, through an open()/mmap() (at least in Linux), that would be caught through the normal filesystem hooks.

> Ah this helps somewhat, I think there are still potential ambiguities, one thing that bazel can do is statically determine all of the input sources without actually executing the build. You of course can't do this. This has a few nice properties: you get missing input errors before doing any actual building, you have a build graph you can statically analyze (deps queries are magic), and all the sandboxing can be done ahead of time (with symlinks to create a shadow filesystem) instead of ad-hoc, you can parallelize everything, meaning you can saturate all your machines the entire time.

OK, I started out thinking that there would be very little parallelism impact from my scheme, but I realize now the problem that dependencies for a build step are only discovered serially, as each one is built and the dependent process continues.

I could imagine you could work around this with a speculation engine that uses the dependencies from the last run (possibly cancelling the speculated commands mid-flight if the dependent process doesn't end up opening their outputs, and if the speculated commands hasn't started writing files or anything). This would generally work fine, but would waste some work whenever you remove dependencies from a build step (e.g. delete an #include). But it does start to get messy!

Another note: as far as not specifying inputs, I mean inputs beyond the command line (which obviously needs to be specified up front). So you would only need speculation like the above for things like auto-generated headers. The usual cases like "build this executable out of these objects which are each built from these source files" can be parallelized just fine with no speculation.

Static analysis-type queries could be done after a build, but not in a clean tree. Not sure how much of a setback this would be--I'm not generally working in massive projects, and haven't yet felt the need for such queries.

strace performance is a good point (I don't know what sort of overhead it has), and so is memory overhead.

> I also find it easier to reason about stuff with explicit deps, but that's just me.

I could go either way on this one--I generally prefer explicit to implicit, but I don't like repeating the explicit instructions twice (build rules and source code), with the failure mode being unreliable incremental builds. If I'm going to the trouble of explicitly listing dependencies, though, I'll probably go with the ridiculously simple make.py instead of messing with Bazel...

Re: The Language Agnostic, All-Purpose, Incredible, Makefile

#58
post #7

Earlier quoted context omitted.

I agree, and the solution to this problem is to forbid filenames with spaces. The convenience of make and similar tools is much more important than spaces in filenames. File names with spaces should not be allowed in modern filesystems. When the user types a filename with spaces, the GUI should encode the space as a non-breaking space character, that does not cause havoc in scripts.

I can't tell if you are being sarcastic.

i am dead serious about that. Allowing the separator character in filenames is a nightmarish error.

Re: The Language Agnostic, All-Purpose, Incredible, Makefile

#59
It's surprising not to see more examples of implicit rules and dependency resolution in this document. Here's a simple example extracted from http://canonical.org/~kragen/naturaleza/Makefile:

    frames=1-80x160.pgm 2-80x160.pgm 3-80x160.pgm 4-80x160.pgm 5-80x160.pgm 6-80x160.pgm 7-80x160.pgm 8-80x160.pgm 9-80x160.pgm 

    intercalated.pgm: $(frames)
            ./intercalate.py $(frames) > $@

    %.pgm: %.jpg
            convert $
This uses ImageMagick commands to massage the various image files into the desired form without me having to manually invoke the commands image by image. Admittedly, on looking at it, I don't think I got a great deal of dependency-tracking mileage out of make in this case, because the source images weren't actually changing—only the build process was changing, and make doesn't track that (although redo, for example, does.) But in cases where you're dynamically adding new input files, make is super helpful for generating thumbnails or whatever from them. As long as the filenames don't have spaces.

My most immediate work task for the morning is helping a colleague figure out why SCons is failing to build the JNI binding for our project, although the old makefile builds it fine. Sigh.

Re: The Language Agnostic, All-Purpose, Incredible, Makefile

#60
post #3

I like make, but I had a lot more luck with just/justfile, which is similar to make conceptually but with less idiosyncratic syntax/execution.

It doesn't look similar to me at all. It's a tool for running commands, while Make is a build system. Make won't always execute all dependencies.
Post reply on HN