[HN Gopher] An opinionated approach to GNU Make
___________________________________________________________________
An opinionated approach to GNU Make
Author : hasheddan
Score : 155 points
Date : 2022-08-21 15:18 UTC (7 hours ago)
(HTM) web link (tech.davis-hansson.com)
(TXT) w3m dump (tech.davis-hansson.com)
| [deleted]
| kardos wrote:
| Assuming that Makefiles aren't going away any time soon, I wonder
| if the situation here calls for a linter/formatter that can parse
| a makefile and optimize it toward "best practices"...
| forrestthewoods wrote:
| Plot Twist: your makefile is wrong because make sucks and is
| utterly miserable to use.
|
| Build systems are hard so I'm not gonna point fingers too hard.
| But reading/writing makefiles is one of my least favorite parts
| of the job.
| andrewmcwatters wrote:
| I hate developers like this. This is the attitude of every weirdo
| developer I've had to work with who thought they were brilliant
| instead of just using the stupid tool as it was intended.
| jrockway wrote:
| I don't know, I can't really argue with .SHELLFLAGS = -euo
| pipefail.
|
| If you want someone to really hate, pick me. I see a Makefile
| and think "welp, strap in for a wild ride that isn't going to
| get me a working binary". If someone has ever made a good
| Makefile, I certainly haven't seen it.
| shepherdjerred wrote:
| Really? I love cloning a project and seeing a Makefile. The
| install instructions are usually something like 'run make
| install'.
|
| mosh is a good example: https://mosh.org/#build-instructions
| CamperBob2 wrote:
| More typically, the install instructions read like the
| bomb-defusal instructions in the classic MASH episode. "Cut
| red wire, then unscrew detonator subassembly. But first..."
| romanows wrote:
| I don't know if it's a well-written makefile, but Python
| builds are straightforward, even with stuff like LTO enabled.
| Also sqlite.
| agumonkey wrote:
| I felt the opposite, I (among many) was winging my makefiles
| due to unfinished learning. I always appreciate high precision
| posts like these (even if some of the points are above the
| top).
| spicybright wrote:
| It's high precision of a flawed view (in my opinion, of
| course) that should only be taken for what they are, an
| opinion.
|
| For any readers that want to learn make, look at the
| makefiles of big projects and see how they set things up.
| There's a huge difference of one person's opinions vs. a
| working system for a real world project.
| falcolas wrote:
| Or RTFM. Make is ridiculously well documented.
|
| https://www.gnu.org/software/make/manual/make.html
|
| It's a peeve of mine that folks refuse to read the actual
| documentation for tools these days, preferring to wing it
| by copying other people's code.
| agumonkey wrote:
| People should be a little more forgiving. Even after
| reading emacs Manual thoroughly 3 times, I still managed
| to miss a ton of nuances and information. Same goes for
| make or other large old tools I guess.
| pessimizer wrote:
| Any specific criticism about any points made in the
| article, or just general shade and a nonspecific
| recommendation?
| agumonkey wrote:
| Hmm in a way it's difficult because either Makefiles are
| small or suddenly part of very large projects with 1000+
| lines nested Makefiles :)
| dataflow wrote:
| Honestly his takes (mostly) aren't wrong or niche (at least not
| all of them; a few like the tabs thing are debatable). Some of
| these you only realize once you've wrestled with Make for a
| while and spent time thinking about the underlying problem,
| which many don't do. Knowing some of these ahead of time can
| save quite a bit of a headache. They're worth considering even
| if you don't follow all of them.
| jart wrote:
| It would have been classier if they'd replaced the tab
| character with an emoji. That's what someone on Lobsters
| recommended, once I told them about .RECIPEPREFIX.
| cpuguy83 wrote:
| That's a strange take on the post. The post only uses built-in
| functionality. Options exist for a reason, and defaults are
| _really_ difficult to change in software used by millions of
| people.
| blueflow wrote:
| The effect is that the Makefile now has a dependency on bash
| and GNU make. What happens to the *BSD or non-GNU linux
| users?
| formerly_proven wrote:
| They usually don't matter (and unseen-untested portability
| is simply wishful thinking), but particularly don't matter
| for projects you're responsible for and decided they don't
| matter. That doesn't mean you must randomly preempt
| portability, of course.
| [deleted]
| blueflow wrote:
| I'm Alpine Linux user.... How would you feel if i said,
| GNU/Linux users don't matter? Why should i bother to
| support your platforms?
| eropple wrote:
| What about them? I don't use Python or Golang, but I
| install the requested versions of each if I need to do
| something that uses them. Folks who don't use GNU Make can
| do likewise. It's not a big deal.
|
| For me, every Mac I touch gets a GNU userland by default
| (and Homebrew comes with shell helpers to switch to GNU
| userland aliases temporarily, it isn't a hard switch
| unless, like me, you lock it on all the time) because it's
| really not worth the time and effort to remember what bits
| are GNU and what bits are BSD. So I picked the one that has
| the most stuff that makes my life easier.
|
| There's also just the more basic thing of "the author
| doesn't care about portability to environments they
| consider out of scope," and that's totally fine, too. In
| 2022, the barriers to entry to installing the necessary
| bits of one flavor or another are very low, and if you
| choose to make them harder for yourself that's mostly on
| you.
| bee_rider wrote:
| It is of course up to the coder, what platforms they want
| to support.
|
| But it isn't _always_ easy to install new software. GNU
| make is so widespread that it probably doesn 't matter.
| But for example, if you are on a shared machine where you
| might not necessarily have root. Or, if somebody requires
| some obscure build system that isn't available in your
| distro repos (of course you can build from source, but
| the need to check the source of the build system is going
| to increase the barrier to entry).
| bee_rider wrote:
| "Don't use tabs" just seems wrong.
|
| "Use a recent bash" seems like a matter of preference.
|
| "Make is all about files (paraphrasing)" seems a little obvious
| hopefully, but definitely the way Make is intended to be used.
|
| "Magic variables" eh... I dunno, I guess sometimes they can get
| obscure but it isn't super hard to look this sort of thing up.
|
| The omission of % seems weird.
| dataflow wrote:
| > "Use a recent bash" seems like a matter of preference.
|
| Unfortunately it's not merely a preference; old Bash versions
| (in particular the one that shipped on macOS for a long time)
| have had at least one nasty behavior (I think multiple, but I
| recall at least definitely one) that have been fixed since
| then, but which cause grief in Makefiles. I don't recall what
| it was or have a link handy, but if anybody knows, please
| leave it here; it's a well-known issue.
| jart wrote:
| If you want to read something good, check out the docs for
| this Landlock Make project I've been working on the past
| week. https://github.com/jart/landlock-make It has many more
| features since it was announced on August 7th.
| bee_rider wrote:
| Make, but protective. Ambitious, but pretty neat!
|
| > .CPU = SECONDS
|
| > .MEMORY = SIZE
|
| I wish the cluster I use sometimes had this built into
| their make system, to prevent people from make-ing on the
| headnode, haha.
| protastus wrote:
| The attitude reminds me of the Nick Burns character from SNL.
| omginternets wrote:
| Tone aside, I agree. The net result is an unreadable mess of
| niche configuration that could probably be avoided by having
| the Makefile simply do less.
| throwaway787544 wrote:
| Please don't tell people "you are wrong / don't do X", especially
| if it's not objectively true. It's negative, rude, judgemental,
| and bossy. Find a kinder way to make your point and people might
| listen to you. (If you don't care if people listen to you, why
| are you speaking?)
| IncRnd wrote:
| 2019: An opinionated approach to GNU Make,
| https://news.ycombinator.com/item?id=21812656
| benreesman wrote:
| This is a really weird thread.
|
| It's an opinionated blog post about relatively minor Makefile
| conventions with a clickbait title, which doesn't look obviously
| self-submitted.
|
| And yet the thread is #1 and has 96 comments, of which like 92
| are trashing the poor guy.
|
| Surely there is someone more worthy of an HN gang-tackle than
| this? It can't be _that_ slow of a news day.
| [deleted]
| pessimizer wrote:
| It's triggering for some people to be told that they are wrong,
| even if the person who said it doesn't actually know them
| specifically, wasn't thinking about them as individuals when
| they wrote the blog, and has no idea that they exist.
|
| The idea that someone could be so presumptuous to assume that
| they had more make knowledge than everyone on the planet makes
| them very angry, because they are someone on the planet, so
| their first instinct is to lash out and prove that person
| wrong. A better instinct would be to humor the idea that the
| author doesn't think they know make better than anyone else in
| the world and isn't trying to hurt their feelings or their
| careers, but instead is trying to give people who don't know
| make as well as the author does a few tips.
|
| edit: basically a gathering of the people who reply to things
| on the internet that upset them with: "That's just your
| opinion." No shit, buddy, I wrote it, who else's opinion would
| it be?
| yjftsjthsd-h wrote:
| > It's triggering for some people to be told that they are
| wrong, even if the person who said it doesn't actually know
| them specifically, wasn't thinking about them as individuals
| when they wrote the blog, and has no idea that they exist.
|
| ...and, of course, when they're not actually wrong.
|
| > No shit, buddy, I wrote it, who else's opinion would it be?
|
| Okay, if OP can have an _opinion_ that "Your Makefiles are
| wrong", then I can have an opinion that " Your article is
| wrong". Fair?
| Joker_vD wrote:
| You see, the very first point of the article not only has a
| really weird opinion (that'd be only half bad), but but this
| weird opinion is being justified/defended with obviously faulty
| reasoning: "in the shell spaces matter, [so don't use tabs].
| Instead, ask make to use > as the block character". Yeah,
| because ">" doesn't matter in shell, and there is absolutely no
| confusion possible as a result. Imagine copypasting a recipe
| from such a Makefile into a shell? The results will be pretty
| hilarious.
|
| Which is a shame because the rest of the post is mostly
| reasonable: turning recipes from a collection of one-liners
| into an actual piece of shell script, deleting output files on
| build errors, using -e and -o pipefail, etc.
| benreesman wrote:
| Oh I also disagree with the ">" thing. I just think we could
| have been like: "the > thing seems bad, good call on the
| pipefail thing. moving on..." rather than like ruin this guys
| day with 100+ negative comments because of the novel horror
| of a clickbait blog title. It's not that big of a deal
| (unless you're the guy who just got clobbered by every HN
| user awake on Sunday morning).
|
| It's just weird.
| throwaway9870 wrote:
| linkdd wrote:
| There are a million other ways to express your opinion without
| ad hominem insults.
|
| Learn how to communicate and chill, no one forced you to read
| the blog post, and you could just have ignored it.
| throwaway9870 wrote:
| When you come at people with the attitude the author has, you
| should expect it right back at you. That is why anyone who
| knows how to give a proper talk or write a professional paper
| does not do that. Leave it to popular culture sites to treat
| people like that, it should have no place in professional
| presentations.
| linkdd wrote:
| > When you come at people with the attitude the author has,
| you should expect it right back at you.
|
| The attitude being: a clickbait title immediately dismissed
| as "an opinion" --> An opinionated approach
| to writing (GNU) Makefiles that I learned [..]
| Use the above as guidelines, not dogma
|
| But maybe you haven't read the article and was just
| offended by the title. Still not a good reason to insult
| people like you did. The author of the article never
| insulted anyone.
|
| > it should have no place in professional presentations
|
| Good thing then that this article is posted on a personal
| website. It's not even the author of the article who posted
| the link on HN.
|
| Still not an excuse to insult people.
| jlg23 wrote:
| I've heavily relied on GNUMake myself in a commercial project.
| But when I encounter a software that does require a GNUMake >= a
| specific version and on top bash instead of Posix SH, I must be
| quite desperate to install this just to build some software. My
| excuse was that I was building against 80 different target
| devices (it was j2me development) on some under-powered machines
| and that there was no budget for cutting down build times by
| several orders of magnitudes compared to ant. What's the author's
| excuse?
| admax88qqq wrote:
| > GNUMake >= a specific version and on top bash instead of
| Posix SH
|
| It's such a shame that this is the attitude though. We're stuck
| with a make and shell frozen in time. Why even add new features
| to make/bash if nobody will run the new versions?
|
| Make is cool, but it's stagnated because people don't think we
| should rely on anything beyond POSIX
| jlg23 wrote:
| My development environment is FreeBSD, OpenBSD and Linux; I
| am deploying to non-linux unixes only. 99% of the patches I
| have to do to build systems are one-liners that explicitly
| spell out what syntactic sugar the newest feature of
| gmake/bash supported or that fixes what a linux-only
| developer considers to be "the standard" (and let's talk
| real, it's not only "linux-only" anymore, one has to say
| "this-specific-linux-distro-only"). And that is on top of the
| fact that it is not about "running the new versions" but
| actually installing non-standard software.
| shepherdjerred wrote:
| > Make has a bunch of cryptic magic variables that refer to
| things like the targets and prerequisites of rules. I mostly
| think these should be avoided, because they are hard to read.
|
| > However, for the sentinel file pattern, the magic variable
| $(@D), which refers to the directory the target should go in, and
| $@, which refers to the target, are common enough that you
| quickly learn to recognize what they mean:
|
| So, avoid using the magic variables, but actually you should use
| them because they're useful and common. Got it.
| nrclark wrote:
| This article has some questionable advice imo.
| SHELL := bash
|
| Bash is a much slower shell than Dash, which is why Debian and
| friends don't use it as /bin/sh. .ONESHELL mitigates the speed
| problem, but you could also just use the default shell and leave
| ONESHELL turned off. Use bash strict mode
| .... .SHELLFLAGS := -eu -o pipefail -c
|
| I wish people would stop cargo-culting the so-called "strict
| mode".
|
| The -e flag is only useful because the author likes .ONESHELL
| mode. If you leave ONESHELL turned off, then you don't need it.
|
| The -u flag is useful sometimes, depending on coding style. I use
| it on complex scripts. Individual Makefile recipes maybe don't
| want that much complexity though. Also the -u flag makes the
| shell's variable-handling behavior inconsistent with Make's.
|
| The pipefail option is Bash-specific, and only works because the
| author likes to set SHELL to Bash in their Makefiles. It's also
| not a good default in my opinion. There are times when it's
| useful, and other times when it's the opposite of what you want.
| Just depends on the pipeline that you're writing.
| jwilk wrote:
| > The -e flag is only useful because the author likes .ONESHELL
| mode
|
| Not really. The most common class of bugs I see in makefiles is
| something like this: for x in foo bar baz; do
| frobnicate $x; done
|
| This ignores errors from frobnicate, unless you set -e.
| jart wrote:
| The fastest shell is to not use shell special characters. For
| example, if you say `foo bar >/dev/null` then Make needs to
| launch your program as `sh -c 'foo bar >/dev/null`. But if you
| say just `foo bar` then Make can pass that directly to
| execve(), bypassing the shell entirely. Sometimes I actually do
| this: SHELL := /bin/false
|
| Just to make sure my Makefile doesn't use shell syntax. If you
| want a `.STRICT` mode, then try Landlock Make.
| nrclark wrote:
| Woah, interesting! I didn't know that Make could launch
| programs directly. Is that specific to GNU Make?
| jwilk wrote:
| At least NetBSD make (also used by FreeBSD, and packaged as
| bmake in some distros) has the same optimization:
|
| https://github.com/NetBSD/src/blob/netbsd-9/usr.bin/make/co
| m...
| jwilk wrote:
| Doesn't work for me: $ make -v | head -n1
| GNU Make 4.3 $ printf 'SHELL :=
| /bin/false\nall:\n\tls\n' > Makefile $ make
| ls make: *** [Makefile:3: all] Error 1
| jart wrote:
| I completely forgot that the GNU Make source code has a
| check to see if the shell is bourne-compatible (it just
| strcmp's with sh, bash, and a hard coded list), and then
| only applies that optimization if it is. I deleted that
| code in my Landlock Make fork so I could use shells like
| /bin/false and still get the optimization. So sorry about
| that! Give it a try with Landlock Make
| https://github.com/jart/landlock-make and
| https://justine.lol/make/
| bigcat12345678 wrote:
| Looking at bazel's complexity, and its popularity, one should see
| that Makefile and its dependents, which forces upon writer a
| centralized model (where one Makefile dictates how to build all
| code files scattered in subdirectories), cute but unreliable
| grammar (tab vs. space), unnecessarily convenience features (for
| god's sake, I never managed to learn any thing beyond simple
| target & deps, and things like PHONY target are just beyond my
| mental capacity).
| Animats wrote:
| The trouble with makefiles is that they're supposed to specify
| dependency relationships, but they're used as a procedural
| scripting language because the dependency system isn't very
| smart.
| zzbn00 wrote:
| A little trick to rebuild targets based on the build options: use
| .VARIABLES and pipe to sha256sum to create an option-dependent
| suffix for all built files:
|
| https://bnikolic.co.uk/blog/sh/make/unix/2021/07/08/makefile
|
| In this way a meaningful change to the makefile triggers rebuild
| automatically like it should
| bee_rider wrote:
| I like parts of it!
|
| The tabs vs spaces thing seems pretty silly to me. If your editor
| is randomly swapping tabs and spaces, get a better editor. Tab is
| the default in a makefile and that seems fine. The suggestion to
| use "> " instead of tab just looks noisier.
|
| The observation about the filesystem is good and hopefully well
| known. The way to think about makefiles is as a tool for creating
| files (it is very oriented toward this), not as a general purpose
| scripting language (it is just a worse version of whatever
| scripting language you are in it, if you use it this way). I do
| wonder if he could structure his tests to have them actually
| generate output files which make could track, and also have his
| tests track dependencies.
|
| Point taken about the magic variables. Sometimes they can get
| obscure (although they are pretty easy to look up). IMO one he's
| missing, though, is the pattern matching % operator. If make
| isn't generating at least some of your recipes for you, then why
| not just make a "build.sh" script?
| zelphirkalt wrote:
| > [...] it is just a worse version of whatever scripting
| language you are in it, if you use it this way [...]
|
| If I may quote this little part: Oh no, it is actually much
| better, than what a huge part of developers in web development
| do: They use package.json of their project, where they add
| under the "scripts" attribute calls to commands, which contain
| again calls of "npm run", which again reference other "scripts"
| ... Of course there is no way to actually specify dependencies
| (previous steps a step depends on) as actual dependencies and
| the whole thing becomes a procedural thing, instead of a more
| declarative thing.
|
| There is also no good way other than writing whole shell
| conditions in there, in a JSON file inside a mere string, if
| the command relies on a file existing. So in effect the logic
| will always run the step, which creates that file.
|
| So this considered, I don't think Makefiles are really doing
| badly. You can do much worse.
|
| EDIT:
|
| > If make isn't generating at least some of your recipes for
| you, then why not just make a "build.sh" script?
|
| Because then you don't get what Make brings to the table: tab
| completion, declarative dependency specification between steps,
| declarative definition of targets.
|
| You would have to write code for these things yourself in that
| "build.sh" script.
| bee_rider wrote:
| >> If make isn't generating at least some of your recipes for
| you, then why not just make a "build.sh" script?
|
| > Because then you don't get what Make brings to the table:
| tab completion, declarative dependency specification between
| steps, declarative definition of targets.
|
| Yeah, that part was a little bit flip. :)
|
| I think neglecting this feature ignores too much of Make's
| power, but it definitely does have other things going for it
| as well.
| jpollock wrote:
| The tabs and spaces thing is targeted at teams. At any point,
| there will be someone editing the makefile with a misconfigured
| editor. Depending on the team's growth rate, and their desire
| to use different tools, this happens a lot.
|
| Avoiding tab vs spaces or tab width arguments is a good thing
| for any team to do. :)
| bee_rider wrote:
| This is good, their builds will fail, notifying them of their
| misconfiguration in the most obvious way possible. Hopefully
| they will have to customize the Makefile a little to build on
| their system, and give it a build before they start
| programming, so they can correct their editor before they do
| any damage to the source code.
| usefulcat wrote:
| > This is good, their builds will fail, notifying them of
| their misconfiguration in the most obvious way possible.
|
| I think it's very funny that you think a build is
| guaranteed to fail in an obvious way due to a tab vs space
| problem.
| bee_rider wrote:
| It may not be obvious _why_ it failed, but it should be
| obvious that it did fail.
| usefulcat wrote:
| If, for example, make fails to update a target that
| should have been updated, that kind of problem will
| frequently not be obvious.
| bee_rider wrote:
| Sure, it also won't catch the misconfiguration for those
| who don't even open the Makefile. It is too optimistic to
| hope that this venerable piece of software will solve all
| out misconfiguration woes, but at least it provides a
| possible red flag sometimes.
| aslilac wrote:
| Yet this has been settled in Makefiles for a long time: use
| tabs.
|
| OP only seeks to sit on a high horse about how tabs are bad
| and to divide an ecosystem which is already pretty
| consistent. I'm so tired of people insisting tabs are evil
| and that using them somehow makes you "wrong."
| bee_rider wrote:
| Tabs are obviously superior. If the tabs vs spaces argument
| must be had, and the correct option somehow loses, then we
| will have a much more annoying followup argument about how
| many spaces (I vote for three spaces and I will
| filibuster).
| benreesman wrote:
| Since we're doing this... ;)
|
| I'm actually coming around on really narrow conventions
| since tiny laptops started getting really good.
|
| I used to think 80-wide columns and 1-2 space indent was
| silly retro stuff in an era of modern displays.
|
| But on an M2 Air you can just barely get 80 + 80 side by
| side if you full screen SFMono at like 12-14pt.
|
| I'll never sell my colleagues on it, but I've been
| playing around with setting the formatters to 1-space
| indent. It's not as heinous as it sounds.
|
| Bring it on! :P
| bee_rider wrote:
| The cool thing about tabs is that you can do that 1-space
| indent without spreading your madness (but yeah, I think
| I got a preference for 3 spaces -- actually tabs with
| tabwidth set to 3 -- while using a little, now old,
| netbook).
|
| One nice advantage of 3 space tabs is that if somebody
| mixes tabs and spaces in Python, leading to mysterious
| IDE-dependent bugs, it immediately sticks out (my example
| is from helping student in an intro to python class,
| hopefully this doesn't occur much in the real world).
| Izkata wrote:
| Holy crap I'm not the only one that likes 3...
| benreesman wrote:
| We've just gone the deterministic code formatter route on
| everything. Right off the top of my head:
|
| - C/C++: `clang-format` is _great_ - Rust: `rustfmt` is
| very good - Python: `yapf` is very good - Java: `google-
| java-formatter` is pretty good - Haskell: `fourmolu` is
| OK, and if you apply it first and then `stylish-haskell`
| it 's good enough - Starlark - `buildifier` is _great_ -
| Shell: `shfmt` is pretty good - Nix: `nixfmt` is pretty
| good
|
| I haven't done any JS or TypeScript or golang in awhile,
| but I'm sure there are great options there too.
|
| By having all the auto-formatters, we can have one golden
| config that's fully deterministic for upstream, but
| everyone can have their own if they want and it just gets
| blasted into the "golden" format before code review.
|
| Finally, a world without brace wars! Everyone tabs and
| spaces and whatever to their hear's content. Everyone's
| happy!
|
| * you do eat the blame getting fucked up the one time.
| it's worth it.
| int_19h wrote:
| You can't meaningfully filibuster rustfmt / go fmt /
| Black / ... - that's the best thing about them.
| yjftsjthsd-h wrote:
| > Point taken about the magic variables. Sometimes they can get
| obscure (although they are pretty easy to look up). IMO one
| he's missing, though, is the pattern matching % operator. If
| make isn't generating at least some of your recipes for you,
| then why not just make a "build.sh" script?
|
| Probably a preference for explicit over implicit, just like
| setting `MAKEFLAGS += --no-builtin-rules`. Of course, promptly
| using a couple of magic variables because they're "common
| enough that you quickly learn to recognize what they mean"
| is... a bit amusing, to me.
| dllthomas wrote:
| And on the topic of "get a better editor", if you (quite
| reasonably) prefer something more visible than a tab... you can
| do something to make tabs more visible in your editor. That way
| it'll work for any Makefile you open, not just those you're
| responsible for.
| bin_bash wrote:
| I think the `.RECIPEPREFIX = >` bit triggered a lot of people
| here in the comments, and I agree. That would make drafting
| newlines a huge pain in any editor. Just enable "Show Whitespace"
| in your editor if you want this.
|
| That said, I'm more concerned about the guidance to not use
| .PHONY and instead do this: # Tests - re-ran if
| any file under src has been changed since tmp/.tests-
| passed.sentinel was last touched tmp/.tests-
| passed.sentinel: $(shell find src -type f) > mkdir -p
| $(@D) > node run test > touch $@
|
| The author is right, that does use make in a more more idiomatic
| way by relying on a real file, but I see 2 major problems:
|
| * That's a lot of logic for something that should just be super
| simple.
|
| * When I say `make test` I want it to run the tests. I don't care
| if they've passed before and the files haven't changed.
|
| Really though, make just isn't a great tool for build scripts.
| The syntax is horrific and it's hard to scale it into something
| readable.
|
| If I started a new project I'd probably consider Just:
| https://github.com/casey/just (though I haven't had a chance to
| use it myself yet).
| brabel wrote:
| > I don't care if they've passed before and the files haven't
| changed.
|
| This is a common interjection from some people... which means
| you think that your tests are not deterministic, otherwise it
| would be completely pointless to run them again without inputs
| changing.
|
| I actually admit that from end-to-end tests, this is usually
| true despite our best efforts to the contrary... but for unit
| tests, I really think tests should be 100% deterministic and
| only ever run when something they rely on changes. The Unison
| programming language goes even further[1] and it NEVER executes
| a test again once the code under test has been "committed" into
| its image.
|
| [1] https://www.unison-lang.org/
| bravetraveler wrote:
| Keep in mind I'm about as ignorant of Make as one can be -- I
| use it to build things, but I've never put things into it
|
| I have a feeling meeting this may scope creep the thing into
| being more environment aware. Interpretation of the things
| it's sourcing [and their paths], and less-than-obvious things
| like environment variables
|
| This just feels like one of those things trying to be too
| helpful that inevitably gets in my way
| marcosdumay wrote:
| > which means you think that your tests are not deterministic
|
| This would be relevant if the command was saving some test
| report somewhere. But then the target would just depend on
| the report, and there would be no need to add guard files.
|
| Looks like that `make test` just does the normal thing that
| is run the tests and print the results to the screen. If so,
| people would want to repeat it any number of times.
| bin_bash wrote:
| > completely pointless to run them again without inputs
| changing
|
| What if I installed some dependency outside of my project?
|
| What if I'm trying to test performance with `time make test`?
|
| What if it failed due to a transitory error--or I'm simply
| trying to discover if it is transitory?
|
| What if I made a change to the way the tests are run in the
| Makefile or a different file not in ./src? Like running `npm
| install`?
|
| What if I want to set an environment variable or pass an
| argument to the test runner?
| tirpen wrote:
| Just run make -B test
|
| to force a rerun?
| bin_bash wrote:
| First, the engineer needs to understand how the makefile
| is written and that it doesn't rerun without changes. Is
| it not rerunning because of npm? because of jest? If the
| engineer isn't the one that wrote the makefile: they
| won't.
|
| Next, you're assuming a JS engineer would know what the
| flag is (or even that such a flag exists) to force
| reruns. I've literally never used this flag in my (JS)
| career so I wouldn't expect anyone to know this.
|
| Don't send engineers down some debugging rabbit hole just
| to save a few seconds when no changes happen. If you want
| this functionality, just use `jest --onlyChanged` in your
| own workflow and don't screw with everyone else's.
| gpderetta wrote:
| On non-toy projects it will save minutes if not much
| more. It also encourage good test discipline l.
|
| The engineer will know because it is their job to know.
|
| (Yes I'm a huge fan of deterministic tests and running
| only what's necessary).
| fn-mote wrote:
| > [...] which means you think that your tests are not
| deterministic, otherwise it would be completely pointless to
| run them again without inputs changing.
|
| Re-running seems reasonable to me. It's make, not Bazel.
|
| In the article I'm looking at targets with a "find" shell
| command on the right hand side. I don't think the
| dependencies of those files are carefully mapped somewhere
| else in the makefile.
| yjftsjthsd-h wrote:
| Title: "Your Makefiles are wrong"
|
| Content: A lot of subjective preferences, with the only thing
| people are probably doing "wrong" being not properly mapping
| files as inputs and outputs (which _could_ be a correctness
| problem but is probably either a mere inefficiency or complete
| non-issue).
|
| If this had been titled, say, "An opinionated approach to writing
| Makefiles", or perhaps "How to use GNU Make in a completely
| unorthodox way that I really like", I wouldn't mind it so much.
| ec965 wrote:
| The purpose of a title is both to summarize content and grab
| the readers attention. It's up the author which one they put
| for emphasis on. You clicked so it worked, even if you don't
| like it.
| yjftsjthsd-h wrote:
| Clickbait _working_ isn 't really a great defense.
| flykespice wrote:
| The user only saw the headline and closed, isn't the author
| aiming visitors to read the content or clicks?
|
| The same analogy could be made to a baker luring customers in
| their bakery with an attractive facade but the very same
| "customers" just give a quick glimpse and leave.
|
| What is the win?
| yjftsjthsd-h wrote:
| In fairness, I did in fact read more or less the whole
| thing. I walked away with a fairly low opinion of the
| article and the author, but I did read it :)
| mkl95 wrote:
| I've never written a non trivial Makefile, because all my non
| trivial Makefiles are generated by CMake. I'm interested in why
| my CMakes are wrong since it's a way more complicated tool.
| kazinator wrote:
| There is a standard way to disable the builtin rules which is
| .SUFFIXES:
|
| https://pubs.opengroup.org/onlinepubs/9699919799/utilities/m...
|
| .SUFFIXES
|
| Prerequisites of .SUFFIXES shall be appended to the list of known
| suffixes and are used in conjunction with the inference rules
| (see Inference Rules). If .SUFFIXES does not have any
| prerequisites, the list of known suffixes shall be cleared.
| teddyh wrote:
| The style he advocates are still technically makefiles, in the
| same way that this is still technically Python:
|
| https://www.reddit.com/r/ProgrammerHumor/comments/uosex4/no_...
| leononame wrote:
| I mostly use make like a package manager agnostic version of the
| "scripts" section in package.json, and some of the
| recommendations here are like a revelation for me. I didn't know
| you could change the tab character to a > for the commands,
| that's such a great improvement imo.
| KindOne wrote:
| Previous discussion (2019) with 194 comments.
|
| https://news.ycombinator.com/item?id=21812656
| WesolyKubeczek wrote:
| I think that this is one of actually nicer articles about using
| Make (and I think that developers should use it in more roles
| than a glorified task runner. It can do more, look at
| buildroot!), but the pontificating headline is quite off putting.
|
| I know that Twitter and Medium popularized this style a lot. I
| wish we used it less.
|
| The tips in the article are interesting, and the text is humbler
| than one would expect from a preamble like this, though. Go read
| it, give it a thought.
| blibble wrote:
| the most common problem in pretty much every Makefile I've ever
| seen is not specifying the dependencies correctly
|
| like nested header files, or forgetting to update them when the
| code is changed
|
| (so everyone runs make clean all instead every time...)
| IncRnd wrote:
| Many people forget to include the makedep utility in their
| makefile.
|
| Makedep creates additinal dependency targets, so that source
| files depend upon the header files they include.
| cpuguy83 wrote:
| How about "your docker builds are wrong", too.
|
| Don't generate some random id and a tag (as in the post). Use
| docker's "-iidfile" flag when building to write the actual id of
| the image to a file which can then be used in a "docker run".
|
| Likewise, you can use "--cidfile" in a "docker run" to output the
| id to a file and use that later for accessing it.
| bin_bash wrote:
| Can you explain this a bit further? I don't think I understand
| the point, but I've been using docker more lately and this
| sounds like it could possibly be something I could use. It
| sounds like I could do something like: docker
| build --iidfile .dockerid && \ docker run -it /bin/bash
| --cidfile .dockerid
|
| Without needing to copy and paste the image ID? Is that right?
| Why wouldn't I just tag the image? docker
| build -t myimage && \ docker run -it myimage /bin/bash
| cpuguy83 wrote:
| Not quite.
|
| --iidfile writes the image id of the build to a file.
|
| --cidfile writes the container id of the container to a file.
|
| To use the output of --iidfile in a "docker run", instead of
| specifying an image name call "$(cat <iidfile>)". As an
| example:
|
| docker build --iidfile out/imageid ...
|
| docker run ... $(cat out/imageid)
|
| --- edit for formatting ---
| jp57 wrote:
| The HN and the blogosphere generally are replete with
| unconvincing "you're doing it wrong" posts. This is one. I use
| make (and have used it off and on for a long long time: since the
| late 80s). I don't do any of these things. If the author is going
| to make a convincing case his way is "right" and other ways are
| "wrong", it's incumbent upon him to clearly state what failures I
| will avoid. Then I can evaluate how often I encounter them, and
| decide how important this advice is. As stated, it doesn't seem
| very important.
|
| I frequently run into similar situations with more junior
| engineers at work. One will insist on dogmatically adopting some
| "best" practice advocated somewhere, and when I ask what failures
| or bad situations we'll avoid, or what good situations we'll
| encourage, they can't answer. In their minds, someone (outside
| our team or the company) said it's better and so it must be.
|
| I think it's important to avoid invoking incantations, and to
| understand the reasons for each choice you make. In this article,
| I don't see that.
| krinchan wrote:
| And I think it's important to read the article before writing
| comments based purely on the title, but here we are.
|
| The author makes several convincing arguments and specifically
| lays out what failure modes are avoided for each
| recommendation. Honestly the title is completely out of step
| with the tone of the argument, which is a critique I can
| support.
| Tainnor wrote:
| I agree that the "you're doing it wrong" tone of the article
| title is off-putting and that if you're just using Make for
| some minor automation once in a while here and there, you
| probably shouldn't worry, but I found most of the tips
| genuinely helpful and the reasons for doing so are stated or
| obvious.
| systemvoltage wrote:
| Should just be titled "I'm doing it this way, adopt what you
| like".
| dwheeler wrote:
| > If the author is going to make a convincing case his way is
| "right" and other ways are "wrong", it's incumbent upon him to
| clearly state what failures I will avoid.
|
| I agree, any claim that you should do XYZ should give a strong
| argument.
|
| The article here _does_ try to give very short arguments, to be
| fair. I leave unconvinced by many of them. For example,
| requiring bash means you can 't use dash; dash is less capable
| but much faster.
|
| I prefer arguments that walk through the key pros and cons.
| Longer, but in long run more useful.
| wk_end wrote:
| > The key message here, of course, is to choose a specific
| shell. If you'd rather use ZSH, or Python or Node for that
| matter, set it to that. Pick a specific language so you can
| stop targeting a lowest common denominator
|
| Seems like dash would be fine for the author.
| [deleted]
| fpoling wrote:
| The article does state the reasons for the rules and gives
| examples how not following them may lead to troubles.
| [deleted]
| avg_dev wrote:
| I feel the same way. I strongly believe that choice of language
| makes a huge difference in your material's reception. Any time
| I am told that something I'm doing is wrong by an article, an
| inanimate piece of text that clearly has no cognition thus no
| idea what I'm doing or not doing, I think that the person who
| wrote it, is, in fact, communicating wrong.
|
| I was on the fence about posting this reply; after all the
| guidelines tell us to stay relevant to the material, but I do
| believe you have done that.
| pessimizer wrote:
| > I strongly believe that choice of language makes a huge
| difference in your material's reception.
|
| Not with me, unless you're talking about the difference
| between _clear_ and _unclear_ language.
|
| I'm not bothered by language that some people seem to class
| as _patronizing_ or _like you know everything_ or whatever.
| When somebody is explaining something to me, I don 't want
| them to explain it to me like I know it already. I want them
| to explain it to me like someone I've hired to explain things
| to me i.e. like they're the expert and I'm not.
|
| If I think I know everything about make, there's no reason
| for me to have clicked on this other than an urge to seek out
| things that confirm my sense of self-worth, or to get upset
| about things that threaten it.
| [deleted]
| dataflow wrote:
| I don't understand your complaints.
|
| > it's incumbent upon him to clearly state what failures I will
| avoid
|
| He does _exactly_ that though? Here 's a list of some of them:
|
| Rule: "Use a strict Bash mode"
|
| Failure(s) avoided: _" your build may keep executing even if
| there was a failure in one of the targets."_
|
| Rule: .ONESHELL
|
| Failure(s) avoided: _assignments failing to take effect on
| subsequent lines_ ( "it lets you do things like loops, variable
| assignments and so on in bash")
|
| Rule: .DELETE_ON_ERROR
|
| Failure(s) avoided: _" ensures the next time you run Make,
| it'll properly re-run the failed rule, and guards against
| broken files"_
|
| Rule: MAKEFLAGS += --warn-undefined-variables
|
| Failure(s) avoided: _avoids silent misbehavior when a variable
| doesn 't exist_ ("if you are referring to Make variables that
| don't exist, that's probably wrong and it's good to get a
| warning")
| mayoff wrote:
| .DELETE_ON_ERROR is not sufficient. Some day your make
| process will be killed (due to a bug, OOM, kernel crash,
| power loss, whatever) while the recipe is running, thus
| having no chance to delete the broken output.
|
| I had this happen often enough (in a quite large system that
| farmed out compile jobs to a cluster) that now I always make
| my recipes write to a temporary file, and then rename the
| temp file to the actual target, e.g.
|
| test.o: test.c > cc -o $@.tmp $< > mv $@.tmp $@
|
| Once you adopt this strategy, .DELETE_ON_ERROR is irrelevant.
| dataflow wrote:
| > .DELETE_ON_ERROR is not sufficient. Some day your make
| process will be killed (due to a bug, OOM, kernel crash,
| power loss, whatever) while the recipe is running, thus
| having no chance to delete the broken output.
|
| I agree, it's one reason Make itself sucks.
|
| > I always make my recipes write to a temporary file, and
| then rename the temp file to the actual target
|
| Then hopefully set the timestamp if you used some tool to
| generate it so it doesn't look out of date to Make. (Again,
| another deficiency of Make. I could list more.)
|
| > Once you adopt this strategy, .DELETE_ON_ERROR is
| irrelevant.
|
| Sure (well actually no, but that's next paragraph), but
| that strategy is only worth it for "serious" Makefiles.
| Ones you use in your work environment and all. For personal
| projects etc. it's not always worth the hassle of polluting
| the Makefile with boilerplate like that; it's much handier
| to put that one line.
|
| But actually no, there's still a benefit: it saves disk
| space to delete incomplete output files. If your files are
| 4KiB you might not care, but if they're 4GiB then you
| might. And sure you can get around that by manually adding
| 'rm' in the beginning of every rule too, but why not use
| this instead while it's already there. It's one line and
| doesn't harm anything.
| mooselaker wrote:
| It literally says at multiple points throughout "this is not
| dogma", including the entire final section.
| bin_bash wrote:
| "Your Makefiles Are Wrong" is an incredibly dogmatic thing to
| say despite that disclaimer.
| cinntaile wrote:
| Some people can't recognize a clickbait title when it hits
| them in the face.
| saulpw wrote:
| Titles are clickbait, not dogma.
| [deleted]
| telez wrote:
| use grouped targets
| https://www.gnu.org/software/make/manual/html_node/Multiple-...
| rather than sentinel.
| morelisp wrote:
| For some reason RECIPEPREFIX has gotten really popular lately.
| Has OS X finally upgraded their version of Make, or are people no
| longer using the default Make on OS X at all?
| chrismorgan wrote:
| > _Make leans heavily on the shell, and in the shell spaces
| matter. Hence, the default behavior in Make of using tabs forces
| you to mix tabs and spaces, and that leads to readability
| issues._
|
| I have written a great many makefiles, simple and complex. I
| can't recall a single time I've needed to mix tabs and spaces in
| one (though I have had to mix them multiple times in both YAML
| and HTML).
|
| (As for anything like accidental mixing, for my part I have a
| sanely-configured text editor and so don't need to worry about
| anything silly like tabs being turned into spaces. Tabs are
| superior to spaces anyway. [?]But I do use spaces for Rust and
| Python where that is customary, I'm not completely antisocial.)
|
| > _.ONESHELL ensures each Make recipe is ran as one single shell
| session, rather than one new shell per line. This both - in my
| opinion - is more intuitive, and it lets you do things like
| loops, variable assignments and so on in bash._
|
| .ONESHELL also means that your makefile will behave differently
| from how anyone that's familiar with makefiles will expect it to.
| But I guess this does explain why you went enabling strict mode,
| since you've basically turned off the near-equivalent default
| functionality from Make.
|
| Note also that you can do loops and such already--you just need
| to use line continuations (put backslashes at the end of each
| line, which Make will consume).
|
| Yeah, the default behaviour is idiosyncratic and will lead to
| surprises in the unwary (though they'll normally observe it
| immediately, when the cd is ineffective on the next line, or when
| the if/for causes a syntax error), but I think Make has generally
| become niche enough that I'd prefer to pander to people that know
| Make than normal people. :-)
|
| > _.DELETE_ON_ERROR_
|
| Two-edged sword: it also means you can't inspect what went wrong
| by looking at the file. You're also making the very dubious
| assumption that merely deleting this _one_ file will fix
| everything. A few times when I've known something to be fallible
| but want to be able to inspect what it created, I've put in
| something like a `... || { touch --date=@0 $@; exit 1; }` suffix
| so it still fails, but first zeroes its mtime so that subsequent
| runs will see that it's out of date, though the file still
| exists.
|
| I'm not saying it's wrong or a bad idea, just that it's worth
| considering the implications fully rather than blindly applying
| it.
| jchw wrote:
| This seems like a lot of work to not just consider ninja, meson,
| CMake, etc. I fully understand that the simplicity and
| portability of Make is alluring, but if you are actually using it
| to build C software it is a catastrophically poor choice and you
| can spend a ton of time and effort trying to come close to what
| you can get out of the box on a modern build system.
|
| If the tradeoff was that Make was easier to use and debug, then
| maybe it could be justified, but in general my experience is that
| it's worse.
|
| There are probably some use cases for Make where it remains
| difficult to replace for one reason or another, but most people
| using it anymore are not in that position. Now, it's usually more
| work to keep using it.
| hedora wrote:
| This is a sadly common corrolarry to "those who do not
| understand make are destined to reimplement it poorly".
|
| I strongly suggest spending an afternoon with "recursive make
| considered harmful" and the gnu make manual.
|
| I've never encountered a cmake proponent that can add trivial
| functionality to a cmake build in less time than it took me to
| learn make.
|
| I can usually port cmake builds to make in less time than such
| people can debug the cmake version of the build I ported.
| jchw wrote:
| I have one question to ask you.
|
| How do I do this in Make:
| find_package(OpenGL) target_link_library(app
| OpenGL::OpenGL)
|
| Goals:
|
| - Support Windows, macOS, *NIX like
|
| - Compile with either MinGW or MSVC on Windows
|
| - Decent error output if GL headers are not found
|
| This SHOULD be possible. All we are doing here is calling the
| compiler with a fairly easy to derive set of options. Yet, in
| Make, there is no ideal way to abstract this. Even detecting
| platforms can be annoying, less trying to abstract the
| differences between them.
|
| I do not find Make hard to use. I do not lack knowledge on
| how to use Make, or not understand the "zen" of Makefiles.
|
| I just know that `-lGL` is a terrible answer to this
| question. And I find Make to be generally bad for compiling
| software.
|
| Out of tree builds and reasonable platform detection
| generally require configure scripts, at which point we've
| thoroughly left any semblence of elegance.
| hedora wrote:
| You should either trust the OS to package GL, or vendor it
| yourself.
|
| If you trust your build environment, then -lGL is the right
| answer. If you do not, then vendoring libGL is the right
| answer. Both approaches are easy to achieve with make.
|
| find_package semantics are frankly weird: "maybe use the OS
| version, or override in nonstandard ways, or maybe download
| some version from somewhere and build it using some
| compiler flags that came from somewhere mysterious. If you
| succeed, have package-dependent side effects on the set of
| global variables in my cmake script".
|
| Does it have a higher chance of producing a binary in dodgy
| environments? Sure. Are those binaries actually
| reproducible or what the developer / distribution tested
| with? Absolutely not.
|
| As for windows with visual studio: Either point make at the
| visual studio compiler, or hand maintain a separate .SLN
| file. The impedance mismatch between Unix and Windows
| builds is too great, and the auto-generated .SLN files that
| tools like cmake produce are low quality.
| WesolyKubeczek wrote:
| Make can do more than compile a bunch of C files. If you can
| express your goals and dependencies as files with meaningful
| creation timestamps, it can be a potent task executor that can
| also skip over steps if they are already done.
|
| Also, your CMake generates Makefiles, so...
|
| CMake and meson/ninja, though, seem to be pretty much tuned to
| compiling C-shaped things, although I'd like to see them
| (ab)used for other things.
| gpderetta wrote:
| Incidentally, is there such a thing as a distributed Make
| that can run and check the dependencies across machines?
|
| Of course Make + ssh and a distributed FS gets you there, but
| you don't always have a distributed FS especially across
| continents.
| gpderetta wrote:
| I tollerate CMake because a bad standard is still better than
| no standard, but I would chose Make everyday if it was my
| decision and just for me.
| pfranz wrote:
| Out of the ones you list CMake is the only one I've authored
| and maintained and I still end up having to understand and
| troubleshoot Makefiles. Depending on the size of the project
| and the needs I try and use the fewest number of abstractions
| since I end up jumping down to troubleshoot anyway.
|
| For toy stuff I'll just compile on the commandline (maybe write
| a bash script). I'll write a Makefile if I need to start
| wrangling too many things. CMake usually comes in if I need to
| go cross-platform or incorporate another build system or
| dependency that needs it. I think most places probably need
| CMake, but quite a few don't. If Make, as is, works then it
| makes sense to come up with opinions and standards that
| streamline authoring and maintenance.
| bin_bash wrote:
| I thought most people use ninja through CMake? Do people
| actually write ninja scripts directly?
| benreesman wrote:
| I'd love to go on an anti CMake rant, because I hate it, but
| @vzverovitch (fmtlib author) is the undisputed God of CMake
| trolling:
| https://mobile.twitter.com/vzverovich/status/138064827250353...
| jchw wrote:
| The point isn't that CMake is good. I don't think anyone is
| arguing that CMake isn't an ugly, weird mess. I can point out
| several annoyances that are frankly disturbingly stupid.
|
| However, it also offers practical answers to real problems
| that even Autoconf don't do a good job with, and that makes
| it valuable. CMake can handle out of tree builds, vendoring,
| cross-compilation, packaging RPMs/debs/even DMGs, library and
| platform detection, test suites, abstracting build systems,
| MSVC/Windows... If you are going to tell me about the "best"
| way to compile software and the answer to this is either "
| _shrug_ " or "Here's a shitty 1000 line Bash script you can
| copy" then I'm going to continue to discard the advice,
| because frankly it sucks.
|
| CMake, also, for all its faults, has improved a fair bit from
| the 2.x days. I'm not saying it will ever not be ugly, at
| least as far as the language itself goes, but they're
| definitely cleaning up a lot of the worst mistakes over time
| and it's making CMake a lot less of a bad proposition. You do
| have to opt-in to some of the new practices, but it is
| nonetheless worthwhile improvements.
| benreesman wrote:
| Oh I agree mostly. CMake is still a practical necessity for
| the time being, and I also agree that from 3.10 or so it
| goes from an NC-17 slasher flick to an R-rated horror film.
| It's so ubiquitous that "I will do nothing, because I can
| do nothing".
|
| _Personally_ I've taken the plunge on Bazel and whoo, the
| first time you run clang-format, save, and hit in the cache
| on the .o, I mean sex is cool but have you tried building
| C++ fast?
|
| But Bazel will probably never be the standard or even
| common, le sigh.
|
| What we might get is something sane that generates CMake,
| so that it can generate Ninja, so that we can be bitching
| about CMakeGen in 10 years.
| jchw wrote:
| Totally fair. I agree. It is a damn shame that things are
| the way they are with build systems.
|
| I like Bazel, but I wish it didn't inherit all of the
| issues that come with large Java software. Also, to be
| honest, I'm less thrilled with how Bazel works outside
| Google than Blaze works within Google; they took out some
| of it's advantages in exchange for better ecosystem
| interoperability, which totally makes sense and yet also
| is a bummer. I wish they could've somehow given the rest
| of the world a generalized taste of how they do it.
|
| Sorta related: I like Bazel's concept of the build
| server. I can't help but think the programming community
| could invent a "build server protocol" not unlike the
| language server protocol, and somehow integrate it with
| LSPs and IDEs. (Obviously it would still be complex, but
| the premise of having a somewhat general way to swap
| build systems in a project and have e.g. clangd or
| tsserver know what flags it would get where seems
| amazing.)
| benreesman wrote:
| That build server protocol is a great idea. There are
| folks who sell Bazel build as a service (e.g. BuildBuddy
| I think it's called), but while it's pretty easy to get a
| remote action cache, it's quite a bit more involved to
| get a true remote farm, and this obviously goes nonlinear
| in complexity as languages/platforms/toolchains start
| their combinatorics routine. If there was a standard and
| it were as successful as LSP (thank god for VSCode and
| whatever hero at Microsoft decided to keep LSP despite
| the JSON) I think it would create a whole new SaaS
| ecosystem and make everyone's life better.
|
| I've never worked at Google, so I'm very curious about
| what Blaze gets you that Bazel doesn't. I have no trouble
| imagining it's a lot: you can do great stuff when you
| control the whole stack and have lots of computers, but
| I'd be intrigued by any details you're at liberty to
| share.
| kennu wrote:
| > .RECIPEPREFIX = >
|
| That seems like a terrible idea. You change the basic syntax of
| the entire Makefile, forcing anybody reading it to get used to
| your custom indentation, where almost every line starts with an
| unnecessary >.
| yjftsjthsd-h wrote:
| Also, the justification seems to be
|
| > And you will never again pull your hair out because some
| editor swapped a tab for four spaces and made Make do insane
| things.
|
| Which... I guess that would be annoying, but maybe fix your
| horribly broken editor rather than mutilating the Makefile?
| Spivak wrote:
| Are you going to fix everyone else's editor too? Software is
| a multiplayer game and eliminating a whole class of error
| that hinges on someone not noticing the difference between
| invisible characters in a diff is a huge win.
| yjftsjthsd-h wrote:
| Are there any major editors that can't handle this? Given
| that python has a very similar kind of formatting I would
| assume any editor that a programmer is using today can
| handle it.
| int_19h wrote:
| In Python, if you save your file with tabs as spaces, the
| code 1) still works, and 2) does the same thing it did
| before. Furthermore, it prohibits mixing tabs and spaces
| up in the same file, on the basis that it's impossible to
| reliably determine indentation levels then. So this isn't
| really a major issue with Python, unlike Make.
| yjftsjthsd-h wrote:
| Sure, I'm happy to agree that the original design of make
| is kind of questionable. My point was that an editor
| which can handle telling you to not mix tabs and spaces
| in python should also be able to tell you to use tabs in
| a Makefile. Or, if you prefer, that if python can say
| "only tabs xor spaces" and be seen as reasonable, then
| make can say "only tabs" and be equally reasonable.
| eropple wrote:
| Just about everyone I know uses VSCode, which handles
| Makefiles correctly out of the box, or I can trust to have
| a correct vim config, so honestly I think I'm okay with it.
| If something breaks, it'll break loud.
|
| There's a lot of other really good advice in this article
| but this one feels unfounded.
| dllthomas wrote:
| > I can trust to have a correct vim config
|
| And this isn't some obscure thing that people need to
| have got around to configuring; vim works properly with
| Makefiles (marking non-tab leading whitespace as an
| error) out of the box on at least Ubuntu and I'd guess
| much more widely than that (all distros and Mac and
| Windows and also when building from source wouldn't
| surprise me, although it also wouldn't surprise me if
| there were a couple of exceptions where things would need
| to be massaged).
| eropple wrote:
| Yeah, the two places I find myself still reaching for vim
| are Git commits and quick shell/Makefile tweaks and both
| are correctly formatted out of the box (shortened Git
| first lines on commits, etc).
|
| I do not think this is actually a problem.
| falcolas wrote:
| Even IntelliJ handles makefile whitespace correctly.
| Folks using Notepad?
| dharmab wrote:
| Autoformatters like gofmt and black let you fix everyone's
| editors at once. Though I haven't seen one for Make.
| bee_rider wrote:
| I'm not 100% certain, but I suspect a Makefile with this
| error will become unusable. So, no need to fix their
| editor, they will fix it themselves after their builds
| fail.
| yakshaving_jgt wrote:
| I'm not convinced.
|
| The advice might be sensible in some way, but if Make isn't anal
| enough for your tastes, why not just use a different build tool?
| blueflow wrote:
| This results in a pretty un-portable Makefile. Portability is a
| desirable feature for a build system, which is supposed to help
| other people on other systems to build your software.
| brabel wrote:
| What do you mean by portability? Are you able to confidently
| write a Makefile that works on any Linux distro, BSDs, MacOS
| and Windows?
|
| Or for you, portability means Linux systems only?
|
| Honestly curious, because I've gone to the trouble of writing
| my own build system just so I can use the same build file on
| any OS whatsoever (which to me, means using a cross platform
| language for everything, not relying on bash or any other
| shell).
| yjftsjthsd-h wrote:
| Given the explicit choice to use GNUisms and promptly
| overriding the SHELL to explicitly use bash, I'm quite
| confident that this author is not concerned with portability
| concerns.
| omginternets wrote:
| Quite, but then the posture of "you're doing it wrong" is
| utterly incomprehensible. It's clear that the author is
| making rather strong assumptions about the runtime
| environment.
| blueflow wrote:
| For the purpose of self-promotion, i guess. Being
| confrontational brings attention.
| orlp wrote:
| > .ONESHELL ensures each Make recipe is ran as one single shell
| session, rather than one new shell per line. This both - in my
| opinion - is more intuitive, and it lets you do things like
| loops, variable assignments and so on in bash.
|
| This will at some point cause a bug that will be a pain to debug.
| Even worse when it depends on execution order/thread grouping
| with -j8. I would not consider introducing state is a good thing.
| eqvinox wrote:
| Wow. This is atrocious.
|
| > You really just need the .RECIPEPREFIX = >
|
| Now I can't copy & paste a block anymore (into the shell, to run
| it), and all my editor indentation settings are broken.
|
| > SHELL := bash
|
| And the Makefile is now non-portable.
|
| > .SHELLFLAGS := -eu -o pipefail -c
|
| If this matters, it's likely you're wedging too complicated
| things into one recipe. But less bad than the other suggestions.
|
| > .ONESHELL
|
| Funnily enough using this is the primary reason the previous item
| becomes important. The subtly changed behavior also turns multi-
| line recipes into a giant footgun if you end up with a non-GNU
| make.
|
| (skipping a few that are not as bad)
|
| > out/image-id: $(shell find src -type f)
|
| Might be OK in a single rule. Otherwise, it's calling find
| more... and more...
|
| > Sentinel files
|
| Actual good practice to end it on.
| dllthomas wrote:
| > Now I can't copy & paste a block anymore (into the shell, to
| run it)
|
| You likely can, actually. Most terminal emulators have a key
| you can hold (ctrl in gnome-terminal, alt in urxvt) to select a
| block of text that doesn't start at the beginning of the line.
| Doesn't work if your lines wrap, of course.
| spicybright wrote:
| But then you can't copy a target and it's steps in one go.
| And the pasted code will only have a single space for
| indentation, if I'm understanding right.
|
| Plus without word wrap you can't copy more than a screen
| width at a time on most terms.
| dllthomas wrote:
| > But then you can't copy a target and it's steps in one
| go.
|
| The parent said they wanted to paste it into the shell to
| run it. In that case, you aren't going to want to copy the
| target, only the steps. It will have a single space
| indentation if you start there, or no indentation if you
| start one character over; either could be what you want,
| depending on your shell settings and whether you want the
| commands in your history.
|
| If you want to copy and paste the target and all of its
| steps in one go, you need to ask yourself where you want to
| paste it, but probably including the > and copying normally
| is the right thing, to be reformatted on the other side as
| desired. In fact, I expect that to break a little less
| often than pasting things with leading tabs.
|
| > Plus without word wrap you can't copy more than a screen
| width at a time on most terms.
|
| Yeah, I was imprecise; "doesn't work if your lines wrap"
| should probably have been "doesn't work if your lines are
| long enough that they would need to wrap".
| jen20 wrote:
| > And the Makefile is now non-portable.
|
| The article calls out GNU Make, so almost everything else in
| there is also non-portable.
| eropple wrote:
| Even beyond that I don't really understand the criticism.
| Like, I don't remember the last machine I had to do serious
| work on that didn't come with GNU Make either out of the box
| or added as part of some very basic bootstrapping scripts. (I
| don't know what a Mac comes with because my bootstrap for
| every new machine has coreutils in it and every project has a
| Brewfile with it too.)
|
| I definitely don't remember the last machine I saw that
| didn't have bash on it.
| dllthomas wrote:
| And in this case we're concerned about computers that do
| have GNU make but don't have bash...
| eqvinox wrote:
| If you write Makefiles for your own personal use -- sure.
|
| If you're working in a team with other people, or are
| publishing things for a broader public to use... no.
| Especially since things like .ONESHELL don't just flat-out
| cause errors, but rather introduce subtle and insidious
| distinctions in behavior.
| eropple wrote:
| Ehh. If I'm writing a Makefile, team context or no, it's
| almost certainly because I don't expect other people to
| be more familiar with Make than I am. If anything, I
| would expect ONESHELL to map to how most programmers
| think Make already works, even though it doesn't. I know
| I have to go look up the various Make-isms whenever I
| need to do anything complex.
|
| And a Make supergenius, should I ever meet one, surely
| will look at the top of the file or derive from
| "incorrect" code that something is nonstandard.
|
| I'd love better tools that take the good parts of Make
| (around file transformations, mostly) and expose them
| more effectively in shells (because doing so in a more
| fully featured programming language often results in
| different and worse hacks--hi, Rake) but using Make to do
| things more people will find predictable seems fine to
| me.
| eqvinox wrote:
| I guess I should've been more clear. My point is other
| people /using/ your Makefile, not editing it. You know
| what you're running. You don't know what everyone else is
| running. I've singled out ONESHELL because it will be
| _silently_ ignored by non-GNU make, and it will behave
| ever so slightly different enough to cause extremely hard
| to find bugs.
|
| Example: .ONESHELL:
| sometarget: someinput BASEDIR=other_expression
| SHELLVAR=complicated_expression rm -rf
| $$BASEDIR/$$SHELLVAR
|
| (obviously extreme to illustrate the point, but you get
| the idea.)
| eqvinox wrote:
| btw. On the BSDs, GNU make is "gmake" while plain "make"
| is POSIX-compliant BSD make. Better hope you never make
| the easy mistake of forgetting that "g"...
|
| (If you use any of these features -- _please_ rename your
| Makefile to GNUmakefile. _Please. I beg you._ )
| eqvinox wrote:
| > The article calls out GNU Make, so almost everything else
| in there is also non-portable.
|
| My brain honestly didn't process that, and it's still
| refusing to. I think it's the braces around (GNU) -- seems
| like I have some neurons wired to push (bracketed) pieces of
| text down into a "detail" stack and eliminate them from high-
| level processing...
|
| P.S./ed.: GNU make looks for GNUmakefile before Makefile, and
| arguably if the Makefile is GNU specific, that feature should
| be used -- and that includes the title of the article ("Your
| GNUmakefiles Are Wrong")
| [deleted]
| asveikau wrote:
| > .ONESHELL ensures each Make recipe is ran as one single shell
| session, rather than one new shell per line. This both - in my
| opinion - is more intuitive, and it lets you do things like
| loops, variable assignments and so on in bash.
|
| You can do things like loops and variable assignments, you just
| have to keep it on one line. You can put that one line on
| multiple lines using newline escaping by ending a line with \
|
| You could argue that making it clumsy to do those things enforces
| that makefile scripts be simpler, while still providing enough of
| an escape hatch should it be necessary.
|
| But probably ONESHELL performs better. The default sounds like a
| lot of wasted repeated fork/execs.
| raggi wrote:
| if you're building C please try to use the built-in rules. I
| often come across reimplementations that miss or disorder one of
| the flag sets and it becomes a pain when porting or integrating.
|
| General reminder: you don't even necessarily need a make file to
| build C: ~ % echo 'void main(){printf("hello");}'
| > example.c ~ % make example
| cc example.c -o example ... 2 warnings
| generated. ~ %
| ./example hello%
| bin_bash wrote:
| This is really cool! I've always worked in interpreted code so
| this isn't that useful to me but I'm surprised that it exists.
|
| I tried it myself though and it complains about not including
| stdio.h and wanting `int main` instead of `void main`. Though
| of course I still get your point.
| coliveira wrote:
| This is bad advice. Changing the default prefix for recipes is
| worse than using tabs, whatever your feelings about tabs are.
| Just use make as it was designed, it will work better this way.
| rcarmo wrote:
| The RECIPEPREFIX was my first clue that I should not go on
| reading. And yet, I did, and lo and behold, came to the comments
| page here to witness most people agreed.
|
| Seriously now I love Makefiles and use them extensively (nothing
| like make serve and make deploy to simplify my day), but there is
| a limit where being too opinionated (rather than just simple,
| easy to understand conventions) just ruins the tool and adds too
| much cognitive overhead.
| ciarand wrote:
| I don't mind sticking to bash, but some of the other choices seem
| overly opinionated. In my experience the best Makefiles just
| invoke other commands, so you're only using make for its
| dependency tracking. That way the Makefile remains fairly simple
| and you can use something more sensible (bash instead of bash-in-
| make, python, whatever) to write your actual build logic.
|
| The Makefile should probably be listed as a dependency for all
| the rules too, otherwise you're gonna end up dealing with stale
| results and adding a "clean" target.
| dataangel wrote:
| Can't believe the number of people s**** on this article who
| obviously don't have enough experience with build systems or the
| problems tab and space mixing cause. Quality has really gone down
| on HN comments in the last few years.
|
| Most of these choices are not really subjective. They are the
| most robust methods that make provides for trying to eliminate
| errors in your make file. If you think "set -e" isn't a good idea
| you're either a rookie or brain damaged. The alternative is your
| scripts silently look like they're working when they actually
| fail and you spend hours trying to debug where things went wrong
| because the system isn't pointing it out to you.
|
| My only fault with the article is that it's putting lipstick on a
| pig. None of this does anything to address the fundamental flaw
| with make that there is no protection against you incorrectly
| specifying building inputs. Every make file I've ever seen at a
| company at scale is buggy. These tips would definitely help but
| would not cure that fundamental issue.
| throwaway787544 wrote:
| No company I have worked for in the past 10 years has used Make
| at all, other than when _I 'm_ using it, and that's because I'm
| just old and used to it. Developers use build tools designed
| for their language, Syseng use ci/cd and shell scripts, very
| large teams standardize on some "modern" overcomplicated
| monstrosity.
| dataangel wrote:
| I agree the new systems are overly complex, but the reason
| they stick is enforcement of dependencies being accurate. If
| someone can bolt that into make it will be a huge
| improvement.
___________________________________________________________________
(page generated 2022-08-21 23:01 UTC)