1. 34
  1.  

  2. 6

    You don’t need to specify the compile line if it’s a C or C++ file:

    foo : $(OBJS)
    

    is enough. Here’s the Makefile (GNUMake, excluding dependencies) for a 150,000+ line project I have:

    %.a :
    	$(AR) $(ARFLAGS) $@ $?
    
    all: viola/viola
    
    libIMG/libIMG.a     : $(patsubst %.c,%.o,$(wildcard libIMG/*.c))
    libXPA/src/libxpa.a : $(patsubst %.c,%.o,$(wildcard libXPA/src/*.c))
    libStyle/libStyle.a : $(patsubst %.c,%.o,$(wildcard libStyle/*.c))
    libWWW/libWWW.a     : $(patsubst %.c,%.o,$(wildcard libWWW/*.c))
    viola/viola         : $(patsubst %.c,%.o,$(wildcard viola/*.c))	\
    		libIMG/libIMG.a		\
    		libXPA/src/libxpa.a	\
    		libStyle/libStyle.a	\
    		libWWW/libWWW.a
    

    I have a rule to automatically make the dependencies.

    1. 3

      foo: $(OBJS) with no command is not enough for non-GNU make.

      1. 9

        Ah. I haven’t used a non-GNUMake in … 20 years?

        1. 2

          indeed ! it is way better to use a portable make, rather than write portable makefiles :)

          1. 3

            In that case I’ll use NetBSD make ;)

      2. 1

        for < 10k line projects i tend to just do ‘cc *.c’ :P usually it is fast enough

        1. 1

          Meanwhile, I have a 2.5kloc project where a full recompile takes 30 seconds, so incremental compilation is kind of necessary :p C++ is slooow.

        2. 1

          Is this a revived ViolaWWW?

          1. 1

            Somewhat. It’s one of those “I want to do something but I don’t know what” type projects where I clean up the code to get a clean compile (no warnings—I still have a ways to go). It works on a 32-bit system, but crashes horribly on 64-bit systems because of the systemic belief that sizeof(int)==sizeof(long)==sizeof(void *).

        3. 4

          That textfile blog style is absolutely beautiful. @causal_agent, thanks for putting in the notice on how you created it!

          1. 1

            Apart from the repo (https://code.causal.agency/june/text.causal.agency), where can I find more info on the creation by the author? Love it.

            1. 2

              Hi! What would you like to know?

              1. 2

                I am not yet a *nix nor BSD + manpage pro, but I love the idea of tech posts as man pages / .txt files. Are the .7 source files used for a specific reason? The script for building is so simple, as well.

                I’m really keen on simplicity these days, especially when it comes to the bloat of the web, so I try to set a good example, and this is something I can learn from for sure.

                1. 4

                  I’m really keen on simplicity these days, especially when it comes to the bloat of the web, so I try to set a good example, and this is something I can learn from for sure.

                  I’d be the first person to say, “Yeah, make things simpler!” but a plaintext page using spaces for indentation is actually a degraded experience online. The sweet spot for the web is probably a tasteful use of HTML with no Javascript, and a pinch of CSS.

                  Look, even the OpenBSD man pages are rendered online with HTML rather than text. https://man.openbsd.org/mdoc.7 Try resizing the page width and watch how it adjusts to stay readable. Now try different widths with text.casual.agency and look how you get jagged line wrap.

                  Perhaps you’ll argue, “Resize the width, what you do you mean? I’m on lynx!” But even lynx takes cues from HTML tags to render the page better.

                  Finally, you can probably have mdoc output to HTML rather than text and not have to change your page description. Mandoc has a “-Thtml” flag for this, and maybe mdoc has something similar.

                  1. 1

                    Fair points, and that’s exactly what I was hoping I’d find (when it comes to HTML). Being able to build for .txt and .html files is something I’d like to explore, and you’ve helped. And thanks for the -Thtml lead.

                  2. 2

                    The extension used for man pages is the digit corresponding to the manual section they’re for. 7 is the “Miscellaneous Information” section which is the only one that fits. You can read about mandoc and mdoc at http://mandoc.bsd.lv, in particular the mdoc(7) page for authors http://mandoc.bsd.lv/man/mdoc.7.html. I might write a little about what I like about mdoc soon.

                    There’s some interesting background on the build command, mandoc | sed $'s/.\b//g'. When man pages are formatted for display as text, bold text is output as “A\bA” (where “\b” is ASCII backspace) and underlined text is output as “_\bA”, because that was how you achieved those on a teletypewriter. Print A, move back, print A again over it, print underscore, move back, print A over it. Nowadays it’s actually the pager less(1) which interprets those sequences and renders them in your terminal’s bold and underline modes. If you just print the output of mandoc to the terminal, it will look like plain text with no formatting, because the terminal interprets the backspaces and just deletes the first “A” or “_”. The sed command removes those sequences to create a plain text file.

                    1. 1

                      Thank you for the detailed response; I had no idea about that background nor why the extension was .7. So interesting! I’ll read up on mandoc & mdoc, and I look forward to your writeup.

                      Thanks again

            2. 1

              Note that declaring multiple files on the left side of the colon might cause the rule to be run several times when using parallel make. You should declare just one and then declare the others as dependent on the first, like this:

              foo.o: foo.h
              bar.o baz.o qux.o: foo.o
              

              Or consider only using a single witness file instead.

              1. 1

                I’m not sure I get this. bar.o doesn’t depend on foo.o. Wouldn’t this needlessly serialize building foo.o before the others?

                1. 1

                  Sorry, got confused. I wanted to say that make doesn’t deal that well with commands that output more than one file, which is where my hack is useful.

                  1. 1

                    The intention with listing several files left of the colon isn’t to have one command produce several files, but to have the same command produce each file. In the header file dependency case, the .c.o suffix rule is still used to create each .o file.

              2. 1

                Nice! I’ll have to make an Emacs template for when I first open a Makefile to insert that boilerplate. I’d also add the code to generate the header file dependency tree using the correct g++ flags.

                1. 5

                  Here’s the rule I use (GNUMake) to do the dependencies:

                  depend:
                  	makedepend -Y -- $(CFLAGS) -- $(shell find . -name '*.c') 2>/dev/null
                  

                  This will exclude the system header files, but include all local headerfiles. Remove the -Y to include system headers.

                  1. 2

                    On BSD:

                    depend:
                    	mkdep $(CFLAGS) $(SRCS)
                    
                    1. 1

                      Better than this crufty make command I’ve been carrying around for probably 20 years!

                      MAKEDEPS=@echo Making $*.d; \ 
                          set -e; rm -f $@; \ 
                          $(CXX) -MM $(CXXFLAGS) $< > $@.$$$$; \ 
                          sed 's,\(.*$(*F)\)\.o[ :]*,$(*D)/\1.o $@ : ,g' < $@.$$$$ > $@; \ 
                          rm -f $@.$$$$ 
                      
                      %.d: %.cpp 
                          $(MAKEDEPS)
                      
                      1. 2

                        Make already gets such overwhelmingly negative press so let’s not leave this as-is lest others think this is how things have to be. Here is mine:

                        %.d: %.cpp
                            $(CXX) -MM -MT "$(basename $@).d $(basename $@).o" $< > $@
                        
                        1. 1

                          Nice! I’m not even sure where I got mine, just a case of “leave it alone it works”.