Hacker News new | past | comments | ask | show | jobs | submit login
[dupe] Makefile Tutorial (makefiletutorial.com)
93 points by hasheddan on Sept 22, 2023 | hide | past | favorite | 57 comments



Learn Makefiles with the Tastiest Examples - https://news.ycombinator.com/item?id=35936665 - May 2023 (95 comments)

Makefile Tutorial by Example - https://news.ycombinator.com/item?id=9979865 - July 2015 (33 comments)


This tutorial is out of date:

    # Search for the "-i" flag. MAKEFLAGS is just a list of single characters, one per flag. So look for "i" in this case.
    ifneq (,$(findstring i, $(MAKEFLAGS)))
     echo "i was passed to MAKEFLAGS"
    endif
As of GNU Make 4.4 (Oct 2022) it gives false positives; from the release notes:

    * WARNING: Backward-incompatibility!
      Previously only simple (one-letter) options were added to the MAKEFLAGS
      variable that was visible while parsing makefiles.  Now, all options are
      available in MAKEFLAGS.  If you want to check MAKEFLAGS for a one-letter
      option, expanding "$(firstword -$(MAKEFLAGS))" is a reliable way to return
      the set of one-letter options which can be examined via findstring, etc.


Honest question: why don’t we see a new version of Make tailored to more modern use cases, and that is available immediately/automatically in the most used Linux distributions (e.g., Ubuntu, Debian, etc.)?

I’ve seen dozens of new libraries, frameworks and prog. languages appeared in the last 20 years… but no one is interested in improving Make? I’m not talking about creating an alternative (e.g., Task), I’m talking about Make 2.0

Same goes for Bash.


Because Make is perfect for 99% of cases. And adding the extra 1% of features would be a mountain of extra work and complexity. Bazel does that, but I don't work on anything that needs its complexity, so for me and most other projects it wouldn't be a step forward.

Make is great. Even has a debugger: https://remake.readthedocs.io/en/latest/debugger.html


plan9 mk⁰ is a simplified and improved make derivative (the same is true for other components, and the entirety of the system, of plan9 in relation to unix).

mk is generally available in modern systems' package repositories through plan9port¹ or 9base².

0. https://9p.io/sys/doc/mk.html

1. https://9fans.github.io/plan9port/

2. https://tools.suckless.org/9base/


I think it comes down to user segmentation and legacy. There are a few tools that I feel could fit into this space but Make has serious legacy that would making moving projects, people, and build systems over a real pain. Same idea with Bash as well. Maybe we'll see it but I don't have a ton of faith.


I fully agree that Bash is trash. It's useful, but every control structure is convoluted crap. That said, there are probably hundred of alternatives. Csh is the most obvious. Why people continue to use sh, I'm not sure beyond historical reasons. Sure it's shipped, but csh is often shipped as well.


I use Bash because it's ubiquitous, it works well enough (even if it has several flaws), and because a lot of other people know how to use it. Find me another language that meets the same criteria while retaining the core syntax for executingprograms, redirection, and pipes, and I'll switch to it.

Csh and Tcsh might be improvements, but I don't know how to use them and none of my coworkers do either.

Powershell is an option at my particular company, but it has a handful of other problems (some of which are gradually being fixed in newer versions) and it's not "portable" to other organizations.

And I personally use Zsh, which I think is an improvement over Bash, but again, none of my coworkers know how to use it, even though it's the default of everyone's Mac.

People have similar complaints about SQL. It's kind of bad, but nothing has replaced it because it's just too hard to accumulate the critical mass of adoption for any one replacement.


there's also nushell and powershell, which i think are an evolution over the shells which only pipe streams of bytes to programs


Powershell is supposed to be good, but I’ve always been confused how it sends objects between programs. Seems like every program would have be modifed to support whatever rich IPC it uses.

Unix’s philosophy that everything is a file, and everything is stream of bytes is Good™. Dumb pipes and smart ends are future proof. The smarter the pipe, the more likely you’re going to run into things just not being possible.


> Dumb pipes and smart ends are future proof

Shell scripts should not live long enough to require being future proof. If you need to rely long term on some code, write it in an actual programming language


Where did you get this from? Who told you that shell scripts must have a lifetime and can't be crucial for production?

There is no such a thing as serious programming vs baby shell programming. There are just tools, that are means to an end, simple as that. If the tool sufficiently and efficiently does the job, there is no need to replace it with an 'actual' programming language.


The PROGRAMS. Who wants to rewrite everything because you can no longer pipe or redirect?


You can still pipe


No shit.

I don’t think you understand what I’m talking about. Powershell isn’t just a shell with some rudimentary flow control, like every Unix shell since thr 1960s. Powershell can hook together apps with a rich IPC objects, not just the old stream of bytes that kicked off this thread. In fact, I specifically mentioned its rich IPC as its nifty feature, and a feature that I did not understand how it worked, especially since it works in a backwards compatible fashion. THAT’S the thing that moves it beyond a stream of random bytes, to something with semantics. Maybe you didn’t know that, but it does. In fact, when it came out that was its marquee feature. That’s why I’m talking about IPC, and and the fucking programs. No one give a shit about a janky ass .sh file. It’s the thing that go in it. If the programs being connected together don’t understand the rich IPC channel, you’re stuck in the 1960s, like every other shell and scripting language, and so Powershell’s benefits are nonexistent.

This thread went from interesting to absolutely infuriating because you keep smuggly chiming in about things you apparently don’t understand.


Try working on your communication/interpersonal skills, man. You're not a good communicator because I had no idea what you were trying to say until this post. You also shouldn't get upset by discussions of shells on the internet. You probably should take some time away from the computer.

This statement:

> The PROGRAMS. Who wants to rewrite everything because you can no longer pipe or redirect?

Is almost unintelligible, aside from the fact that I guess it qualifies as a nearly-correct statement in English


> and so Powershell’s benefits are nonexistent

A world where every program talks via the same IPC is utopia. Claiming that pwsh benefits are nonexistent because of that, is absurd.

Besides, there are ways to mitigate this problem. As an example, many tools now accept and return json output, which means they can be easily hooked to pwsh via ConvertTo/From-Json without any parsing whatsoever.


GNU Make is still being developed. What features are you talking about? IMHO GNU Make is pretty complete, and it shouldn't change drastically.

Also note that ninja exists as an alternative.


Tracking files based on content hash in addition to timestamps would be a very nice feature Make could add in a compatible way. The current timestamp-only tracking is problematic in many environments, especially with Docker.


DVC and Dud do this, but they're more meant for data analysis projects than building software.

https://dvc.org/

https://github.com/kevin-hanselman/dud/


Also an easier way to search subdirectories without having to invoke the shell to enumerate those files. A runtime with filewatxhers for hotswap compiling of .o files at runtime. Basically all the stuff msbuild provides


I see teams using Make to execute commands (e.g., transpile this, rename that, etc.), as a replacement (or enhancement) of npm (in the node world), for compiling Golang binaries, and even for running stuff in the pipeline. Make is quite versatile, indeed, but it feels like modern teams are using it in a way Make was never intended to be used. That’s the reason why alternatives to Make have appeared. My take is: wouldn’t it be possible to update Make so that it fits more modern use cases more naturally? The problems with Make alternatives is that: they are many and they don’t come preinstalled with your usual Linux distribution. Make has that special place to be a greater tool than what it is right now.


Make is not a command runner. That people are abusing it as such doesn't mean make needs to change, it means people need to use the right tool for the job. Shell scripts can do the exact same thing without the wonky syntax or attempted dependency resolution, so why not just write a shell script? Hell, even npm has script running functionality. Is that not sufficient?


> without the wonky syntax

Idk about you but every shell syntax on a unix-like OS is wonky to me


That's fine, you can always use something like Perl or Python then. But at some point, it certainly seems like all people want to do is run shell commands, and a shell script is still the best way to do that.


I think people want a kind of declarative way for the application to pick up their files and build them, often simultaneously


Make is literally a command runner. That’s all it does.


Yes. Thank you. Make is a victim of its own success in many ways.



It seems like most of the effort goes into creating Make replacements (Bezel, etc). I suspect the problem could be that a Make tailored to more modern use cases may end up being incompatible with current Make - or it could be that preserving compatibility with classic Make would make using the proposed added modern features awkward.


I saw this further down in the thread: https://github.com/casey/just

Looks like a version of make optimized for running commands instead of builds.


Can you pass extra args to a Just command?

Lacking a good way to do this was the #1 reason I moved off of Make:

  make test-foo TESTOPTS='-a -b -c'
Yuck.

My team now just adds a "run" script to all of our projects and it works well enough, no extra dependencies and no fussing around with the unfamiliarity of Make macros. Simple example of how this looks:

  #!/usr/bin/env bash

  set -eu

  venv=.venv

  test-coverage() {
    "${venv}"/bin/pytest --cov=src
  }

  coverage-report() {
    "${venv}"/bin/coverage combine || true
    "${venv}"/bin/coverage report
  }

  _run() {
    source "${venv}"/bin/activate
    "$@"
  }

  _run "$@"


I'm also surprised there aren't any linters for Makefiles, at least not any that check more than a handful of rules.


I use make to set up my environment (run conan etc) and to drive cmake. Works great.


But I don't like tabs and don't understand dependencies so I'm going to invent an ad-hoc DSL full of footguns where everything's driven by magical, opaque 'plugins', call it "modern", and tell everyone to use that, instead.

/s

(I'm all for replacing Make with a tool that's more cross-platform, less dependent on the shell, and has nicer syntax for writing functions, etc, but somehow every 'Make replacement' that crashes through here seems to completely completely miss the point of Make, and instead just provides, at best, a badly-defined scripting language with language-specific package management. There's a reason Make keeps going.)


It's because web developers actually just want a command runner, and not a tool originally designed specifically for selectively recompiling parts of C programs. Make still works for what make is good at, and that's not simply running `npm start`.


gnu make manual - https://www.gnu.org/software/make/manual/make.html

one of the best pieces of technical writing i've ever read


It's pretty good, but I think it's hard to figure out which piece of information is on which page and it's insufficiently anchored/crosslinked. However the concept index is excellent and should help you find everything you need: https://www.gnu.org/software/make/manual/make.html#Concept-I...


A bit off-topic, but I think still relevant: I've fallen in love with justfiles for all the non-build-related things I'd have used Makefiles for. Make is incredibly powerful. Sometimes that power makes the simple things a little harder to express. In those cases, Just warms my jaded heart.

In short, I use make when I'm building a C project and want to model build dependencies as a DAG. I use just when I want to write a bunch of convenient entry points for a project like `just build` (e.g. calling `cargo build`), `just test` (running all the tests no matter what language I'm using), and so on.


I use makefiles for my automation. I built some bootstrap functions that reach for a separate git repo (no submodules for ease of update in certain cases), and then in that repo is the real meat, built in an easily extensible way. I have generic targets like `build`, but that build call actually executes all *_build` targets. And its all auto documented help via comments and grepping. Bit over engineered but i love usin and modifying it


Dropping a link here for convenience: https://github.com/casey/just


Thank you. It's not a search-friendly name


Unfortunately, Just is a stupid task runner. It has no dependency tracking, which is the real power of Make.


That’s what makes it beautiful: it’s optimized for running tasks, with options to show all the “recipes” (with docs), accept arguments, etc.


Scanning through this, it's actually a tutorial for GNU make.


What alternatives are there to Make? Popular C/C++ alternative build systems are SCons, CMake, Bazel, and Ninja.

IMHO just bite the bullet and start with CMake. Make is such a pain to learn and is instantly useless once you realize you're going to need CMake at some point in your career anyway.


Make is a language for making build systems. CMake is a build system that uses Make written by people who haven't read the manual. Anybody touching build systems at all needs to do themselves a huge favor: read the GNU Make manual to be able to write a Makefile to support a small project. This isn't difficult, and gives you wonderful perspective about what build systems are great and which aren't. CMake is good if you need to support many different unixes and xcode and visual studio. If you don't, then cmake gives you lots of pain for no benefit.

Make is simple and good-enough for most cases. I use this: https://github.com/dkogan/mrbuild

But it's not special and there are lots like it. And they are all infinitely better than cmake


If you come from a unix background the Meson/Ninja combination (more or less autotools without legacy crud) is probably more approachable than CMake with all of its implicit magic.


Came here to post the same. The answer for How to build software? is Meson[1] for C and C++ and also other languages. Works well on Windows and Mac, too.

I’ve written a small Makefile to learn the basic and backgrounds. Make itself is fine. But the next higher level would have been Autotools. Which is an intimidating and weird set of tools. Most new stuff written in C/C++ use now Meson and it feels sane.

[1] https://mesonbuild.com


I've used Make routinely in my 25 year career as a backend software engineer and data scientist working mostly in Java, C#, Fortran, Python, SQL, and on the command line. So far I've never experienced the need for CMake. Perhaps I just need a few more years under my belt.


The issue is that Make isn't particularly well suited to figure out properties of C / C++ compilers, or how to locate and link dependencies. That's the main reason Autotools and CMake exist.


That's fair. I see now that the parent did in fact make reference to C/C++. I was reacting to the mistaken impression that the parent was making a blanket statement that went beyond C/C++.


yeah, CMake helps if not everyone is running the same compiler/environment as you.

If your code only ever runs with gcc on Linux though, Make works pretty well..


The comment is explicitly targeted toward those working with C or C++.


CMake is too complicated. You can tell it was made by C++ programmers. (I am one, btw.)


make is not very well suited for extremely large projects (Android or some other OS distribution for example). Bazel works best in such scenarios. it is not just for C++, it has support for other languages too, and in IMO it works better than other complex build systems such as Yocto for large projects.

CMake is not a competitor to make, it is just a tool to generate makefiles with cross platform support. More suited for opensource C++ libraries.


<the BSDs have entered the chat>




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: