http://invisible-island.net/make-tools/
Copyright © 2014,2019 by Thomas E. Dickey


Makefile Archive Rules–An Example

Here are some files from ded in the mid-1990s illustrating how I used the archive rules to keep the makefiles simple.

Sample Makefile

Most of this makefile is lists: CSRC and OBJS. The latter is used for archive rules; the $Z symbol is the name of the archive, while the parentheses around the object filenames tells the make program that those refer to files stored within the archive.

The makefile uses the include feature introduced by augmake, first widely used in AT&T's SVr2 make program in 1984.

The library which I wrote for ded and related programs has several subdirectories containing sources. This particular file is used for the cm_funcs subdirectory.

# $­Id: Makefile,v 12.1 1994/07/02 12:56:29 tom Exp $
# MAKE-file for miscellaneous library routines
 
####### (Environment) ##########################################################
include ../td_defns.mk
 
####### (Standard Lists) #######################################################
CSRC    =\
        cutoff.c \
        newzone.c \
        next_ver.c \
        packdate.c \
        rcs_dir.c \
        rcsargpr.c \
        rcsdebug.c \
        rcsedit.c \
        rcskeys.c \
        rcslast.c \
        rcsload.c \
        rcslocks.c \
        rcsname.c \
        rcspath.c \
        rcsperm.c \
        rcssymbs.c \
        rcstemp.c \
        rcstime.c \
        samebr.c \
        sccs_dir.c \
        sccsdbug.c \
        sccslast.c \
        sccsname.c \
        vcs_file.c \
        vercmp.c
 
SOURCES = Makefile descrip.mms $(CSRC)
 
OBJS    =\
        $Z(cutoff.o) \
        $Z(newzone.o) \
        $Z(next_ver.o) \
        $Z(packdate.o) \
        $Z(rcs_dir.o) \
        $Z(rcsargpr.o) \
        $Z(rcsdebug.o) \
        $Z(rcsedit.o) \
        $Z(rcskeys.o) \
        $Z(rcslast.o) \
        $Z(rcsload.o) \
        $Z(rcslocks.o) \
        $Z(rcsname.o) \
        $Z(rcspath.o) \
        $Z(rcsperm.o) \
        $Z(rcssymbs.o) \
        $Z(rcstemp.o) \
        $Z(rcstime.o) \
        $Z(samebr.o) \
        $Z(sccs_dir.o) \
        $Z(sccsdbug.o) \
        $Z(sccslast.o) \
        $Z(sccsname.o) \
        $Z(vcs_file.o) \
        $Z(vercmp.o)
 
ALL     = $Z
 
####### (Standard Productions) #################################################
include ../td_rules.mk
 
####### (Details of Productions) ###############################################
$Z(rcsargpr.o)\
$Z(rcsedit.o)\
$Z(rcskeys.o)\
$Z(rcslast.o)\
$Z(rcsload.o)\
$Z(rcslocks.o)\
$Z(rcsname.o)\
$Z(rcspath.o)\
$Z(rcsperm.o)\
$Z(rcssymbs.o)\
$Z(rcstime.o)\
$Z(samebr.o)\
$Z(vcs_file.o): $(RCSDEFS_H)
 
$Z(sccsdbug.o)\
$Z(sccslast.o)\
$Z(sccsname.o): $(SCCSDEFS_H)

Common Makefile Definitions

The top-most “include” file contains the suffix rule .c.a, which (because of the way the targets are expressed) is treated as an archive rule. It cleans up after the compile, leaving only an updated archive file.

# $­Id: td_lib.mk,v 12.1 1993/09/22 13:33:35 dickey Exp $
# common definitions for makefiles built over TD_LIB library.
 
####### (Environment) ##########################################################
TD_LIB  = td_lib
# TOP   = ../../.. -- must define
 
B       = ../bin
I       = $(TOP)/$(TD_LIB)/include
L       = $(TOP)/$(TD_LIB)/lib
 
GET     = checkout
COPY    = cp -p
PUT     = rm -f $@$(COPY) $? $@
 
MAKE    = make $(MFLAGS) -k$(MAKEFLAGS) CFLAGS="$(CFLAGS)" COPY="$(COPY)"
 
#CC     = gcc -g -O -Wall -Wshadow -Wconversion -Wstrict-prototypes -Wmissing-prototypes
#LINK   = purify $(CC)
LINK    = $(CC)
 
INSTALL_BIN = $(TOP)/install_bin
INSTALL_LIB = $(TOP)/install_lib
INSTALL_MAN = $(TOP)/install_man
 
####### (Command-line Options) #################################################
INCLUDES= -I. -I$I
CPP_OPTS$(DEFINES) $(INCLUDES)
 
LIBS    = $L/$(TD_LIB).a
DATE    = echo '** '`date` >> $@
 
LINTLIBS= -ltd
LINTOPTS$(CPP_OPTS) $(LINTLIBS)
 
####### (Standard Lists) #######################################################
# don't put .a into CLEAN, because VERDIX-ADA uses that for source!
CLEAN   = *.[oi] *.lint *.bak *.log *.out *.tst .nfs* core
DESTROY =sh -c 'for i in *;do case $$i in RCS);; *) rm -f $$i;;esac;done;exit 0'
RUN_TESTS=sh -c '$@.sh 2>&1 | tee -a $@.out'
 
PTYPES_H =      $I/ptypes.h     $I/td_lib.h
CURSES_H =      $(PTYPES_H)     $I/td_curse.h
QSORT_H =       $(PTYPES_H)     $I/td_qsort.h
RCSDEFS_H =     $(PTYPES_H)     $I/rcsdefs.h    $I/deltree.h
SCCSDEFS_H =    $(PTYPES_H)     $I/sccsdefs.h
 
####### (Development) ##########################################################
CPROTO  = cproto -e -i -fo'\\n\\t\\t' -fp'\\n\\t\\t'
 
LINT_EACH = sh -c 'for i in $?;do echo $$i:; tdlint $(LINTOPTS) $$i >>$@;done'
 
.SUFFIXES: .c .o .a
 
.c.o:           ; $(CC) $(CPP_OPTS) $(CFLAGS) -c $<
.c.a:
        @echo compile $<
        @$(CC) $(CFLAGS) $(CPP_OPTS) -c $*.c
        @ar rv $@ $*.o
        @rm -f $*.o
 
.SUFFIXES: .i .proto .lint .tst
 
.c.i:           ; $(CC) $(CPP_OPTS) -E -C $< >$@
.c.proto:       ; $(CPROTO) $(CPP_OPTS) $< >$@
.c.lint:        ; tdlint $(LINTOPTS) $< >$@
 
.c.tst:         ; $(CC) -o $@ -DTEST $(CFLAGS) $(CPP_OPTS) $< $Z $(LIBS)
 
.SUFFIXES: .man .cat
 
.man.cat:
        rm -f $@
        nroff -man $? >$@

Per-Makefile Definitions

To keep the leaf-directories makefiles simple, they first include this file:

# $­Id: td_defns.mk,v 12.1 1994/07/02 12:56:39 tom Exp $
# Common make-definitions for TD_LIB
 
.SUFFIXES:
.SUFFIXES: .c .o .a
 
####### (Environment) ##########################################################
TOP     = ../../..
include ../../support/td_lib.mk
LINTLIBS = -ltd -lcurses -ltermcap
 
Z       = $L/$(TD_LIB).a
 
SOURCES = Makefile descrip.mms $(CSRC)
 
ALL     = $Z

Makefile Rules

The actual makefile targets are in this complementary file:

# $­Id: td_rules.mk,v 12.1 1994/07/02 12:53:57 tom Exp $
# Common make-rules for TD_LIB
 
####### (Standard Productions) #################################################
all\
run_test\
install:        $(SOURCES) $(ALL)
 
clean:                          ; rm -f $(CLEAN)
clobber:        clean           ; rm -f $(ALL)
destroy:                        ; $(DESTROY)
sources:        $(SOURCES)
 
####### (Details of Productions) ###############################################
$Z:     $(OBJS)
        ranlib $Z
 
.PRECIOUS$Z
 
$(OBJS):        $(PTYPES_H)
 
####### (Development) ##########################################################
$(SOURCES):                     ; $(GET) $@
lint.out:       $(CSRC)         ; $(DATE)$(LINT_EACH)
lincnt.out:     $(CSRC)         ; $(DATE); lincnt $(CSRC) >>$@
tags:           $(CSRC)         ; dotags $(CSRC)