Most active commenters

    ←back to thread

    Be Aware of the Makefile Effect

    (blog.yossarian.net)
    431 points thunderbong | 18 comments | | HN request time: 1.732s | source | bottom
    1. IgorPartola ◴[] No.42668994[source]
    Make and Makefiles are incredibly simple when they are not autogenerated by autoconf. If they are generated by autoconf, don’t modify them, they are a build artifact. But also, ditch autoconf if you can.

    In the broader sense: yes this effect is very real. You can fall to it or you can exploit it. How I exploit it: write a bit of code (or copy/paste it from somewhere). Use it in a project. Refine as needed. When starting the next project, copy that bit of code in. Modify for the second project. See if changes can be backported to the original project. Once both are running and are in sync, extract the bit of code and make it into a library. Sometimes this takes more projects to distill the thing into what a library should be. In the best case, open source the library so others can use it.

    replies(2): >>42669226 #>>42670018 #
    2. Quekid5 ◴[] No.42669226[source]
    They are simple but very often wrong. It's surprisingly hard to write Makefiles that will actually do the right thing under anything other than "build from scratch" scenarios. (No, I'm not joking. The very existence of the idea of "make clean" is the smoking gun.)
    replies(4): >>42669406 #>>42669421 #>>42669724 #>>42669963 #
    3. IgorPartola ◴[] No.42669406[source]
    That’s why I usually write them from scratch and don’t let them get over 100 lines long at most. Usually they are around 30 with white space.

    make clean makes lots of sense but is not even strictly necessary. In the world where all it does is find all the *.o files and deletes them it’s not a bad thing at all.

    4. mauvehaus ◴[] No.42669421[source]
    The idea that git offers a 'clean' command was revelatory to me. Your build system probably shouldn't need to know how to restore your environment to a clean state because your source control should already know what a clean state is.

    That's sort essential to serving its purpose, after all.

    I haven't yet run into a scenario where there was a clean task that couldn't be accomplished by using flags to git clean, usually -dfx[0]. If someone has an example of something complex enough to require a separate target in the build system, I'm all ears.

    [0] git is my Makefile effect program. I do not know it well, and have not invested the time to learn it. This says something about me, got, or both.

    replies(2): >>42669518 #>>42670840 #
    5. withinboredom ◴[] No.42669518{3}[source]
    The problem with `git clean` is -X vs -x. -x (lowercase) removes EVERYTHING including .env files and other untracked files. -X (uppercase) removes only ignored files, but not untracked files.

    If there is a Makefile with a clean target, usually the first thing I do when I start is make it an alias for `git clean -X`.

    Usually, you want to keep your untracked files (they are usually experiments, debugging hooks, or whatever).

    replies(2): >>42669596 #>>42669732 #
    6. mauvehaus ◴[] No.42669596{4}[source]
    You are almost certainly right that I was using -X. It's been a while since I had to deal with git.
    7. RHSeeger ◴[] No.42669724[source]
    I use makefiles all the time for my projects; projects that are actually built with something else (ex, gradle, maven, whatever). My makefiles have targets for build, clean, dependencies, and a variety of other things. And they also have inputs (like "NOTEST=true") for altering how they run. And then I use make to actually build the project; so I don't need to remember how the specific build tool for _this_ project (or the one of many build tools in a project) happens to work. It works pretty well.
    8. RHSeeger ◴[] No.42669732{4}[source]
    This. I have no urge to have git "clean" my project, because I'll lose a ton of files I have created locally. Rather, I want the project know what it creates when it builds and have the ability to clean/purge them. It's a never ending source of frustration for me that "gradlew clean" only cleans _some_ stuff, and there's no real "gradlew distclean".
    replies(1): >>42669994 #
    9. jandrese ◴[] No.42669963[source]
    I disagree, but I think once a project gets beyond a certain level of complexity you may need to move beyond make. For simple projects though I usually do something like:

        CC=clang
        MODULES=gtk+-3.0 json-glib-1.0
        CFLAGS=-Wall -pedantic --std=gnu17 `pkg-config --cflags $(MODULES)`
        LDLIBS=`pkg-config --libs $(MODULES)`
        HEADERS=*.h
        EXE=app
        
        ALL: $(EXE)
    
        $(EXE): application.o jsonstuff.o otherstuff.o
    
        application.o: application.c $(HEADERS)
    
        jsonstuff.o: jsonstuff.c $(HEADERS)
    
        otherstuff.o: otherstuff.c $(HEADERS)
    
        clean:
                rm -f $(EXE) *.o
    
    
    This isn't perfect as it causes a full project rebuild whenever a header is updated, but I've found it's easier to do this than to try to track header usage in files. Also, failing to rebuild something when a header updates is a quick way to drive yourself crazy in C, it's better to be conservative. It's easy enough that you can write it from memory in a minute or two and pretty flexible. There are no unit tests, no downloading and building of external resources, or anything fancy like that. Just basic make. It does parallelize if you pass -j to make.
    replies(2): >>42672062 #>>42797157 #
    10. Terr_ ◴[] No.42669994{5}[source]
    Hmm, I wonder what's the best way™ to, er "locally backup" those files, in such a way that no git-clean invocation will remove them without promoting.

    All I can think of are things like periodically copying them to another folder, or give them a different ownership needed for edit/delete, etc.

    Unless there's some kind of .gitpreserve feature...

    replies(1): >>42670547 #
    11. stouset ◴[] No.42670018[source]
    They are also extremely limited. Timestamp-based freshness is often broken by modern VCSes. Git doesn’t record timestamps internally, so files can (and often do) have their mtime updated even when their contents are the same, causing unnecessary rebuilds.

    They also are utterly unable to handle many modern tools whose inputs and/or outputs are entire directories or whose output names are not knowable in advance of running the tool.

    I love make. I have put it to good use in spite of its shortcomings and know all the workarounds for them, and the workarounds for the workarounds, and the workarounds for those workarounds. Making a correct Makefile when you end up with tools that don’t perfectly fit into its expectations escalates rapidly in difficulty and complexity.

    replies(1): >>42670371 #
    12. chuckadams ◴[] No.42670371[source]
    I started using ccache to speed up Make, but soon found that allowed me to replace Make entirely with a bash script using a few functions.
    13. gjadi ◴[] No.42670547{6}[source]
    You can have locally ignores files in .git/info/exclude IIRC.
    replies(1): >>42672335 #
    14. rixed ◴[] No.42670840{3}[source]
    make clean is supposed to clean the intermediary files only but keep the actual build targets (typically what you want to install)
    replies(1): >>42672376 #
    15. imtringued ◴[] No.42672062{3}[source]
    Makefile Effect in action...
    16. Terr_ ◴[] No.42672335{7}[source]
    I know there are local-only git settings, but AFAIK ignore-status won't protect files from being removed/overwritten by all possible git commands, it just means they won't be accidentally staged/committed.
    17. computerfriend ◴[] No.42672376{4}[source]
    You might want .INTERMEDIATE in that case.
    18. Quekid5 ◴[] No.42797157{3}[source]
    That's effectively "make clean" just slightly more automated. Btw, what happens if you change CFLAGS? Does anything get compiled if no files have changed?