URI: 
       english_knight - english_knight - A ninja replacement.
  HTML git clone git://bitreich.org/english_knight git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/english_knight
   DIR Log
   DIR Files
   DIR Refs
   DIR Tags
   DIR README
   DIR LICENSE
       ---
       english_knight (10124B)
       ---
            1 #!/bin/sh
            2 
            3 if [ -f Makefile -o -f makefile -o -f GNUmakefile ];
            4 then
            5         make "$@"
            6         exit $?
            7 fi
            8 
            9 cat <<EOF
           10 #[1]Seninha's notes
           11 
           12                   A Template for Portable Idiomatic Makefiles
           13 
           14 [2]seninha.org
           15 2022-04-07
           16 
           17 In this post, I present the template I use to write portable, idiomatic
           18 Makefiles for building C programs.
           19 
           20 I use ${MYVAR}, with curly braces, rather than $(MYVAR), with parentheses, but
           21 both notations are supported. In this document I identify two different people:
           22 the developer or Makefile author, who writes the Makefile; and the user or
           23 package maintainer, who defines the proper variables and run make(1).
           24 
           25 The Project Files
           26 
           27 There are several files involved in the building process: the target files to be
           28 built, the source files, and the intermediate files. They may be referenced
           29 several times by different rules, so it is a good practice to name them with
           30 variables. Suppose we're building a program called myprog composed of three
           31 modules. These are the variables to be defined:
           32 PROG = myprog
           33 SRCS = main.c parse.c util.c
           34 OBJS = main.o parse.o util.o
           35 
           36 The varialbe PROG is the final file; SRCS lists the source files; and OBJS lists
           37 the intermediate, object files. Note that both the list of source files and of
           38 object files are almost equal, differing only by the extension of the files.
           39 POSIX make(1) has a notation for changing the ending of each word in a variable.
           40 In order to avoid repeating ourselves, we can use this notation to define
           41 ${OBJS}.
           42 PROG = myprog
           43 SRCS = main.c parse.c util.c
           44 OBJS = ${SRCS:.c=.o}
           45 
           46 We want to build our program when we call make without any arguments. To do
           47 this, the first target should be ${PROG} itself. However, it is a common
           48 practice to use the target all to build the final files. So the first target is
           49 all, which just has ${PROG} as prerequisite.
           50 all: ${PROG}
           51 
           52 Next we need to declare the dependencies between the program modules. This is
           53 done with rules without commands.
           54 main.o: parse.h util.h
           55 parse.o: parse.h util.h
           56 util.o: util.h
           57 
           58 The Compilation Rules
           59 
           60 The compilation process is split in two parts: generate the object files from
           61 the source files, and generate the program from the object files. So we need two
           62 rules.
           63 
           64 The following rule builds object files (.o) from source files (.c). The .c.o is
           65 a inference rule that declare each .c file to be the prerequisite of a
           66 homonymous .o file. This notation is defined by POSIX and is, therefore,
           67 portable (different from the %.o: %.c rule, which is a GNU extension). In the
           68 command of an inference rule (and only in the command of an inference rule), the
           69 $< variable evaluates to the prerequisite file.
           70 .c.o:
           71         ${CC} -I/usr/X11R6/include ${CFLAGS} ${CPPFLAGS} -c $<
           72 
           73 We use the variable ${CC} to expand to the proper C compiler command. This
           74 variable is set by default to the proper command. We should use this variable
           75 rather than hardcoding it to gcc, for example.
           76 
           77 The variables ${CFLAGS} and ${CPPFLAGS} contains options that the user or
           78 package maintainer wants to pass to the compiler or preprocessor. It is a bad
           79 practice to define those variables in a Makefile; let the user (or package
           80 maintainer) define them. Any option that must be passed to the compiler (such as
           81 -I/usr/X11R6/include above) should be passed before those variables. If the
           82 Makefile author, for example, define ${CFLAGS} to -I/usr/X11R6/include, either
           83 this value may override the values set by the user, or the values set by the
           84 user may shadow the option set by the Makefile author.
           85 
           86 The following rule links all object files into the program. We define ${OBJS} to
           87 be the prerequisites of ${PROG}. The $@ variable evaluates to the target file
           88 (${PROG} in our case). Since this is not an inference rule, the $< variable
           89 cannot be used; we must write ${OBJS} both in the rule and in the command.
           90 ${PROG}: ${OBJS}
           91         ${CC} -o $@ ${OBJS} -L/usr/X11R6/lib -lX11 ${LDFLAGS}
           92 
           93 The variable ${LDFLAGS} contains options that the user or package maintainer
           94 wants to pass to the linker. Again, it is a bad practice to define it in the
           95 Makefile. The options -L/usr/X11R6/lib and -lX11 are passed before this variable
           96 (so the user can override or increment them if necessary).
           97 
           98 The Installation rules
           99 
          100 Your Makefile may include rules for installing the final files in the system. In
          101 this example, two files are installed, ${PROG} (the final, compiled program),
          102 and ${PROG}.1 (the manpage, named as the program followed by .1). The following
          103 rule performs the installation.
          104 PREFIX    = /usr/local
          105 MANPREFIX = ${PREFIX}/share/man
          106 
          107 install: all
          108         mkdir -p ${DESTDIR}${PREFIX}/bin
          109         mkdir -p ${DESTDIR}${MANPREFIX}/man1
          110         install -m 755 ${PROG} ${DESTDIR}${PREFIX}/bin/${PROG}
          111         install -m 644 ${PROG}.1 ${DESTDIR}${MANPREFIX}/man1/${PROG}.1
          112 
          113 Before installing, the program should have been built; therefore all must be a
          114 prerequisite for install.
          115 
          116 The user or package maintainer can set the variable ${DESTDIR} to specify a
          117 different installation destination. This variable must be prepended to each
          118 installation path; and the Makefile author should not define it (it is left to
          119 the user or package maintainer to define it). Note that there is no bar
          120 separating ${DESTDIR} from what follows, because the ${PREFIX} and ${MANPREFIX}
          121 variables should already begin with a bar.
          122 
          123 The Makefile author, however, is expected to define two variables pointing to
          124 installation prefixes: ${PREFIX}, pointing to the general installation prefix;
          125 and ${MANPREFIX}, pointing to the manual page installation prefix. There are
          126 other commonly defined prefixes, such as ${bindir}, set to ${PREFIX}/bin. The
          127 user or package maintainer can then invoke make(1) with those variables assigned
          128 to different prefixes. On most GNU/Linux systems, for example, ${PREFIX} is
          129 assigned to /usr; and on OpenBSD, ${MANPREFIX} is assigned to ${PREFIX}/man
          130 (without the share/ part).
          131 
          132 The variables ${PREFIX} and ${MANPREFIX} are not automatically assigned, but
          133 they can be changed by the user or package maintainer. These variables are
          134 commonly assigned in the Makefile by the Makefile author with the ?= operator,
          135 which assign them only if not already defined, rather than with the common =
          136 operator. Thus, the values of these variables can be inherited from the
          137 environment, and the user need not have to assign them on each invocation. This
          138 operator is a non-POSIX extension, however, although supported by both GNU and
          139 BSD make implementations.
          140 
          141 Looking back at the installation commands, we first use mkdir(1) to create the
          142 destination directories, and then use install(1) to install them. We could
          143 simply call install with the -D flag, which automatically creates the
          144 destination directories if necessary. However, this option is an extension and
          145 is not supported by some implementations (such as FreeBSD's). Remember to
          146 install each file with its proper permission modes with the -m option.
          147 
          148 The Makefile author can also create a uninstallation rule, which simply remove
          149 the files from their destination directories.
          150 uninstall:
          151         rm ${DESTDIR}${PREFIX}/bin/${PROG}
          152         rm ${DESTDIR}${MANPREFIX}/man1/${PROG}.1
          153 
          154 The Cleaning Rule
          155 
          156 The Makefile author can define a rule to clean the build directory and revert it
          157 to its original state. Such rule is commonly called clean. It removes the
          158 intermediate object files and the final files. As convenience, for the developer
          159 to clean the build directory from core files that may be created by the system
          160 during the development, the clean rule can also delete .core files.
          161 clean:
          162         -rm -f ${OBJS} ${PROG} ${PROG:=.core}
          163 
          164 Note that the command of this rule begins with an hyphen -. This causes make to
          165 not return error (non-zero) exit status when the command fails. This is handy,
          166 for cleaning an already cleaned build directory to not print errors.
          167 
          168 The Phony Targets
          169 
          170 In a Makefile, some rules specify “virtual” targets which do not correspond to
          171 any file to be created. These are the “phony” targets. The .PHONY special target
          172 is used to mark its prerequisites as phony targets. In our Makefile, we have
          173 four phony targets: all, install, uninstall, and clean.
          174 .PHONY: all clean install uninstall
          175 
          176 The Makefile
          177 
          178 In the end, our Makefile should look like this:
          179 PROG = myprog
          180 SRCS = main.c util.c
          181 OBJS = ${SRCS:.c=.o}
          182 
          183 PREFIX    = /usr/local
          184 MANPREFIX = ${PREFIX}/share/man
          185 
          186 all: ${PROG}
          187 
          188 main.o: parse.h util.h
          189 parse.o: parse.h util.h
          190 util.o: util.h
          191 
          192 .c.o:
          193         ${CC} -I/usr/X11R6/include ${CFLAGS} ${CPPFLAGS} -c $<
          194 
          195 ${PROG}: ${OBJS}
          196         ${CC} -o $@ ${OBJS} -L/usr/X11R6/lib -lX11 ${LDFLAGS}
          197 
          198 install: all
          199         mkdir -p ${DESTDIR}${PREFIX}/bin
          200         mkdir -p ${DESTDIR}${MANPREFIX}/man1
          201         install -m 755 ${PROG} ${DESTDIR}${PREFIX}/bin/${PROG}
          202         install -m 644 ${PROG}.1 ${DESTDIR}${MANPREFIX}/man1/${PROG}.1
          203 
          204 uninstall:
          205         rm ${DESTDIR}${PREFIX}/bin/${PROG}
          206         rm ${DESTDIR}${MANPREFIX}/man1/${PROG}.1
          207 
          208 clean:
          209         -rm -f ${OBJS} ${PROG} ${PROG:=.core}
          210 
          211 .PHONY: all clean install uninstall
          212 
          213 tl;dr
          214 
          215   * Define variables for the final files to be built, the source files, and the
          216 intermediate object files created by the building process. Those are commonly
          217 named ${PROG}, ${SRCS} and ${OBJS}, respectively.
          218   * Include in the Makefile, but do not assign them, the variables ${CFLAGS},
          219 ${CPPFLAGS}, ${LDFLAGS} and ${DESTDIR}. They should be assigned by the user or
          220 package maintainer.
          221   * Evaluate the flag variables (${CFLAGS}, ${CPPFLAGS}, and ${LDFLAGS}) after
          222 any hardcoded flag, so the user or package maintainer can override it.
          223   * Include the all and clean phony targets. Optionally include install and
          224 uninstall phony targets. Always mark them as .PHONY.
          225   * Do not use $< on anything but on the command of inference rules.
          226   * Do not use -D with install(1).
          227   * Do not call c99 or gcc manually. Call the command set in ${CC} instead.
          228   * Assign ${PREFIX} and ${MANPREFIX} to the proper installation prefixes. You
          229 can assign them with the ?= operator for the user convenience, but this
          230 assignment operatior is not portable, although commonly supported.
          231 
          232 References
          233 
          234    1. file:///feed.xml
          235    2. https://seninha.org/
          236 EOF
          237