makefile-guideline.txt - bitreich-style - Style guide for programmers.
 (HTM) git clone git://bitreich.org/bitreich-style
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Tags
 (DIR) README
 (DIR) LICENSE
       ---
       makefile-guideline.txt (8924B)
       ---
            1 Title: Guidelines for writing simple portable Makefiles
            2 
            3 
            4 This page describes some guidelines and good practices for writing simple,
            5 portable POSIX Makefiles. It assumes a basic level of understanding in
            6 writing Makefiles and focuses on projects that use the C programming
            7 language.
            8 
            9 make is used because it has been around for a long time, is available
           10 on many systems, is a POSIX standard and has been proven to work well
           11 for most projects.
           12 
           13 
           14 Targets
           15 -------
           16 
           17 The following targets should be defined in the Makefile:
           18 
           19 * all or the "default": build the project.
           20 * clean: clean files used by compilation, such as: object files, compiled
           21   binaries.
           22 * install: install the built project.
           23 * uninstall (optional): uninstall the project.
           24 * dist (optional): create a source tarball of the project intended as
           25   redistribution for source packages.
           26 * tests (optional): run unit tests.
           27 
           28 
           29 Portability
           30 -----------
           31 
           32 Do not use GNUisms in Makefiles. Testing with different make
           33 implementations, such as BSD make, which mostly respects POSIX, is very
           34 useful. Use POSIX Makefile rules:
           35 https://pubs.opengroup.org/onlinepubs/9699919799/utilities/make.html
           36 
           37 Try to place yourself in the shoes of a package maintainer / porter. This
           38 helps make sure that the package is easy to maintain:
           39 
           40 * https://www.openbsd.org/faq/ports/
           41 * https://www.netbsd.org/docs/pkgsrc/
           42 * https://www.freebsd.org/doc/en_US.ISO8859-1/books/porters-handbook/book.html
           43 * https://wiki.voidlinux.org/A_General_Introduction_To_Package_Creation
           44 
           45 
           46 Variables
           47 ---------
           48 
           49 It is recommended to respect the following commonly-used variables.
           50 
           51 * $DESTDIR: make use of the $DESTDIR variable for the install targets. This
           52   makes it simpler to install the package to another location and make binary
           53   packages. It is the prefix destination directory to install to (before $PREFIX).
           54   It should be unset by default.
           55 
           56 * $PREFIX: this variable specifies the prefix location to install to, it should be
           57   "/usr/local" by default since this is most commonly used for ports.
           58 
           59 * $MANPREFIX or $MANDIR:
           60   * Distributions can use different locations for man pages for ports or in general.
           61   * Some distributions package documentation in a separate package (project-doc).
           62 
           63 Specifying compiler and linker flags:
           64 
           65 * $CC, $CFLAGS, $LDFLAGS, $CPPFLAGS: make sure to respect the default set flags
           66   as specified in POSIX:
           67   https://pubs.opengroup.org/onlinepubs/9699919799/utilities/make.html under the
           68   section "Default rules". This make it easier for the ports build system to use
           69   the set variables and not having to patch the Makefile in some way.
           70 
           71 * $CFLAGS: do not hard-code optimization flags like (-O2) or diagnostic flags
           72   such as -Wall, -Wextra, -pedantic. Even more importantly, do not
           73   specify unportable compiler flags.
           74 
           75 * $LDFLAGS: do not hard-code linker flags like -s (symbol stripping) or -g,
           76   -static or such flags.
           77 
           78 * Libraries: using separate variables for compile and link per library (for
           79   example libpng, libjpeg) can be useful for building in ports.
           80   For example a variable LIBPNG_CFLAGS, LIBPNG_LDFLAGS for the header files or
           81   library location.
           82 
           83 
           84 Considerations
           85 --------------
           86 
           87 * It is not recommended to suppress compilation output with the @ prefix (for
           88   example to make output look nicer aligned). The verbose output is very useful
           89   for debugging and suppressing it only adds debugging abstractions.
           90 
           91 * Try to use a single-file Makefile, at least for small projects.  If needed some
           92   configuration could be included from the Makefile: config.mk.  Keep in mind
           93   that reducing abstractions will increase readability and debugability.  Package
           94   maintainers/porters do not want to have to relearn a new system for each
           95   software package.
           96 
           97 * As specified above, different systems can use different locations for certain
           98   things like man pages, X11 header files and libraries and ports installation.
           99 
          100   Examples:
          101   * X11: commonly uses /usr/X11R6 on BSD-like platforms.
          102   * Man page directories: on OpenBSD: /usr/local/man.
          103 
          104 Testing on many different systems is useful! For example: Linux, OpenBSD, NetBSD.
          105 
          106 
          107 Examples
          108 --------
          109 
          110 Below is an example of a Makefile from the json2tsv project. It is
          111 line-numbered and annotated with remarks on why things are done the way
          112 they are.
          113 
          114      1        .POSIX:
          115 
          116 Specify POSIX compatibility: "To receive exactly the behavior described in this
          117 section, the user shall ensure that a portable makefile shall: Include the
          118 special target .POSIX"
          119 
          120      2        
          121      3        NAME = json2tsv
          122      4        VERSION = 0.5
          123      5        
          124 
          125 Define a name and version variable of the project which can be reused, for
          126 example for the dist tarball.
          127 
          128      6        # paths
          129      7        PREFIX = /usr/local
          130      8        MANPREFIX = ${PREFIX}/man
          131      9        DOCPREFIX = ${PREFIX}/share/doc/${NAME}
          132     10        
          133 
          134 Specify default sane paths.
          135 
          136     11        RANLIB = ranlib
          137     12        
          138 
          139 This variable is not specified by default in POSIX. It is commonly "ranlib",
          140 but can be overwritten.
          141 
          142     13        BIN = ${NAME}
          143 
          144 In this case it's simple: the binary is the program name.
          145 
          146     14        SRC = ${BIN:=.c}
          147 
          148 C source files, so just json2tsv.c here.
          149 
          150     15        HDR = json.h
          151 
          152 Header files.
          153 
          154     16        MAN1 = ${BIN:=.1}
          155 
          156 Man section 1 pages.
          157 
          158     17        DOC = \
          159     18                LICENSE\
          160     19                README
          161     20        
          162 
          163 Other documentation and license files.
          164 
          165     21        LIBJSON = libjson.a
          166     22        LIBJSONSRC = json.c
          167     23        LIBJSONOBJ = ${LIBJSONSRC:.c=.o}
          168     24        
          169     25        LIB = ${LIBJSON}
          170     26        
          171 
          172 Build the json.c file as a local reusable linkable library (libjson.a).
          173 
          174     27        all: ${BIN}
          175     28        
          176 
          177 The default build rule: build the binary.
          178 
          179     29        ${BIN}: ${LIB} ${BIN:=.o}
          180     30        
          181 
          182 The binary depends on the libjson library and its own object file.
          183 
          184     31        OBJ = ${SRC:.c=.o} ${LIBJSONOBJ}
          185     32        
          186 
          187 The object files are all C source-code substituted to from .c to .o and the
          188 local libjson library files, so: json2tsv.o json.o
          189 
          190     33        ${OBJ}: ${HDR}
          191     34        
          192 
          193 Ensure the object files are recompiled if the header file contents change.
          194 
          195     35        .o:
          196     36                ${CC} ${LDFLAGS} -o $@ $< ${LIB}
          197 
          198 Linking, use the system specified LDFLAGS.
          199 
          200     37        
          201     38        .c.o:
          202     39                ${CC} ${CFLAGS} ${CPPFLAGS} -c $<
          203 
          204 Compiling, use the system specified CFLAGS and CPPFLAGS.
          205 
          206     40        
          207     41        ${LIBJSON}: ${LIBJSONOBJ}
          208     42                ${AR} -rc $@ $?
          209     43                ${RANLIB} $@
          210     44        
          211 
          212 Create an archive of the libjson object files. Note that ar -s is an extension
          213 so ranlib is called as a separate command. It is also useful to be specified
          214 separately for cross-compiling.
          215 
          216     45        dist:
          217     46                rm -rf "${NAME}-${VERSION}"
          218     47                mkdir -p "${NAME}-${VERSION}"
          219     48                cp -f ${MAN1} ${DOC} ${HDR} \
          220     49                        ${SRC} ${LIBJSONSRC} Makefile "${NAME}-${VERSION}"
          221 
          222 Use the -f (force) options for rm ensures make does not return an error
          223 on failure. For cp it ensures to overwrite the file even if it is busy. For
          224 mkdir the -p flag is used to create all intermediary directories and to not
          225 return an error if the directory already exists.
          226 
          227     50                # make tarball
          228     51                tar cf - "${NAME}-${VERSION}" | gzip -c > "${NAME}-${VERSION}.tar.gz"
          229 
          230 Make a tarball. gzip from stdin is used for portability (tar z is non-POSIX).
          231 https://pubs.opengroup.org/onlinepubs/007908799/xcu/tar.html
          232 
          233     52                rm -rf "${NAME}-${VERSION}"
          234     53        
          235 
          236     54        clean:
          237     55                rm -f ${BIN} ${OBJ} ${LIB}
          238 
          239 Remove the binary, object files and the local archive library (.a) file.
          240 
          241     56        
          242     57        install: all
          243     58                # installing executable files.
          244     59                mkdir -p "${DESTDIR}${PREFIX}/bin"
          245     60                cp -f ${BIN} "${DESTDIR}${PREFIX}/bin"
          246 
          247 cp's -f flag ensures overwriting the file even if it is busy.
          248 
          249     61                for f in ${BIN}; do chmod 755 "${DESTDIR}${PREFIX}/bin/$$f"; done
          250     62                # installing example files.
          251     63                mkdir -p "${DESTDIR}${DOCPREFIX}"
          252     64                cp -f ${DOC} "${DESTDIR}${DOCPREFIX}"
          253     65                for d in ${DOC}; do chmod 644 "${DESTDIR}${DOCPREFIX}/$$d"; done
          254     66                # installing manual pages for general commands: section 1.
          255     67                mkdir -p "${DESTDIR}${MANPREFIX}/man1"
          256     68                cp -f ${MAN1} "${DESTDIR}${MANPREFIX}/man1"
          257     69                for m in ${MAN1}; do chmod 644 "${DESTDIR}${MANPREFIX}/man1/$$m"; done
          258     70        
          259 
          260 Explicitly set permissions for executable files and for documentation.
          261 
          262     71        uninstall:
          263     72                # removing executable files.
          264     73                for f in ${BIN}; do rm -f "${DESTDIR}${PREFIX}/bin/$$f"; done
          265     74                # removing example files.
          266     75                for d in ${DOC}; do rm -f "${DESTDIR}${DOCPREFIX}/$$d"; done
          267 
          268     76                -rmdir "${DESTDIR}${DOCPREFIX}"
          269 
          270 Try to remove the doc directory, but if it is shared by other packages and
          271 rmdir returns an error code then that is ok and make still proceeds.
          272 
          273     77                # removing manual pages.
          274     78                for m in ${MAN1}; do rm -f "${DESTDIR}${MANPREFIX}/man1/$$m"; done
          275     79        
          276     80        .PHONY: all clean dist install uninstall
          277 
          278 
          279 References
          280 ----------
          281 
          282 - https://www.gnu.org/prep/standards/standards.html#DESTDIR
          283 - https://nullprogram.com/blog/2017/08/20/
          284 - https://pubs.opengroup.org/onlinepubs/9699919799/utilities/make.html
          285 - https://pubs.opengroup.org/onlinepubs/9699919799/