Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Yeah. And it's wildly misunderstood too, so you get random people writing and running `make clean test` stuff that inherently disagrees with itself, which can do all kinds of nonsense if your system isn't normal/clean/running on Thursday.

I do still use it for simple automation, because it's nice to have a language-agnostic way to do simple things. But once it grows beyond about a page of text it tends to become a real nightmare, and is nigh impossible for most people to help maintain... which is not at all helped by its absolute lack of clear best-practices or warnings when misconfigured, and poor meshing with many common systems (like source-modifying tools, e.g. gofmt).

It doesn't help that every guide starts out with

    # so easy!
    thing:
      ./build thing
When in reality you pretty much always need at least how this page ends, to be even slightly stable and maintainable:

    # The final build step.
    $(BUILD_DIR)/$(TARGET_EXEC): $(OBJS)
      $(CXX) $(OBJS) -o $@ $(LDFLAGS)
    
    # Build step for C source
    $(BUILD_DIR)/%.c.o: %.c
      mkdir -p $(dir $@)
      $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
    
    # Build step for C++ source
    $(BUILD_DIR)/%.cpp.o: %.cpp
      mkdir -p $(dir $@)
      $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
It's a horrifying bait-and-switch that a lot of people never fully learn their way through to the end.


That's true of every language, yes?

It always starts with `print 'Hello world'`, but it never stays that simple.


In some ways yes. But there are absolutely differing degrees of inconsistency in a language.

Make is pretty darn far down the "deeply inconsistent and error-prone" side of things when you try to do anything correctly and reliably with it, particularly on multiple systems and across various implementations/versions. It survives because it's ubiquitous and just barely good enough.


In terms of task running specifically it does generally stay that simple for the likes of just.

The only complexity there is getting it installed on everyone's machine, but that's true of most tooling, even the common stuff given versions won't match. I solve that with Nix.


I've pointed out "reboot --halt" elsewhere as one of the common self-contradictory instructions that people like to give to computers.

* http://jdebp.uk/Softwares/nosh/guide/commands/reboot.xml

* https://www.freedesktop.org/software/systemd/man/reboot.html

I suspect that you may have just started a list. (-:


I do not rule out that one exists, but what tool looks simpler (I wanted to say ‘nicer’, but I think we should avoid ‘it looks ugly’ arguments; I think those largely are about familiarity) once you start building something from code written in multiple programming languages?

And what tool is as powerful that doesn’t have the ‘problem’ that a lot of people never learn it fully? (Why would I learn make or any other tool to the full? I browse its manual so that I know what it can do, and (hopefully) remember features exist when I need them, so that I can (often temporarily) learn them then)


Most of Make is quite reasonable. The simple stuff is clear and effective and a lot of the foundations are good (dependency order? only redo changes? great!)

It's the uncountable number of edge cases, lack of versioning/features (you can't declare what you need, you just succeed/fail/misbehave, often silently), massive massive problems dealing with entirely normal things in file paths like spaces, and more useful output than `make -d` for very common cases like "why am I rebuilding every time" / accidentally cyclic dependencies.

For starters.

Make does a lot right, but the amount of inconsistencies and friction to be reliable with it is truly absurd and unnecessary, and you need to go to extreme lengths to correctly handle them (e.g. cmake).


FYI if you care to, you can prevent `make clean test` by looking at `$(MAKECMDGOALS)`.


I have some copypasta that I stick in every makefile that has too many people abusing it blindly, yeah. It works but it's a real pain that there isn't a standard way to do it.

Which is an immediate consequence of make being built to make things, not run tasks. So it goes.


What's the problem with "make clean test"? A test target would have a test-build prerequisite anyways, so

- clean out build artefacts - rebuild test builds - run tests

sounds very much ok to me.


One obvious problem is that that isn't what `make clean test` does.

Order isn't guaranteed, and most clean targets won't have any dependency relationship with test targets, so it could test and then clean. Or interleave them (clean between test dependencies). Or run them both simultaneously if someone has set the -j flag, and then who knows what happens. It does often work out, but it depends on a lot of things.

It's a consequence of make making things, not running tasks. You've told it to make two things that you've said are completely unrelated to each other. Order doesn't matter there, so make is free to do whatever it wants.

---

Other than that, make's behavior when a target updates dependencies of another target which do not share dependencies can get extremely complicated, and often depends on execution order. Clean generally affects many/most, so it's sometimes very problematic to run with any other.

You might also have computed test dependencies at parse time based on what's on disk, which have changed unexpectedly due to clean deleting those files. That can cause `make clean test` vs `make clean` and then `make test` to behave completely differently. The latter is the only consistently safe option, and the only one where your intent will always match what make will do.




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

Search: