summaryrefslogtreecommitdiff
path: root/automake.txt
blob: 935af5f5a93c44af18facd2bfb642e4999f3e380 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
Luke's AutoMake
===============

Yo, this document is incomplete.  It describes the magical
automake.{head,tail}.mk Makefiles and how to use them, kinda.

I wrote a "clone" of automake.  I say clone, because it works
differently.  Yeah, I need a new name for it.

High-level overview
-------------------

Now, what this does for you is:

It makes it _easy_ to write non-recursive Makefiles--and ones that are
similar to plain recursive Makefiles, at that! (search for the paper
"Recursive Make Considered Harmful")  As harmful as recursive make is,
it's historically been difficult to to write non-recursive Makefiles.
This makes it easy.

It also makes it easy to follow the GNU standards for your makefiles:
it takes care of this entire table of .PHONY targets for you:

| this | and this         | are aliases for this                                   |
|------+------------------+--------------------------------------------------------|
| all  | build            | $(outdir)/build                                        |
|      | install          | $(outdir)/install                                      |
|      | uninstall        | $(outdir)/uninstall                                    |
|      | mostlyclean      | $(outdir)/mostlyclean                                  |
|      | clean            | $(outdir)/clean                                        |
|      | distclean        | $(outdir)/distclean                                    |
|      | maintainer-clean | $(outdir)/maintainer-clean                             |
|      | check            | $(outdir)/check (not implemented for you)              |
|      | dist             | $(topoutdir)/$(PACKAGE)-$(VERSION).tar.gz (not .PHONY) |

(You are still responsible for implementing the `$(outdir)/check`
target in each of your Makefiles.)

What you have to do is:

In each source directory, you write a `Makefile`, very similarly to if
you were writing for plain GNU Make, with

    topoutdir ?= ...
    topsrcdir ?= ...
    include $(topsrcdir)/automake.head.mk

    # your makefile
    
    include $(topsrcdir)/automake.tail.mk

And in the top-level source directory, Write your own helper makefiles
that get included:
 - `common.once.head.mk`: before parsing any of your Makefiles
 - `common.each.head.mk`: before parsing each of your Makefiles
 - `common.each.tail.mk`: after parsing each of your Makefiles
 - `common.each.tail.mk`: after parsing all of your Makefiles

The `common.*.mk` makefiles are nice for including generic pattern
rules and variables that aren't specific to a directory.

You're probably thinking that this sounds too good to be true!
Unfortunately, there are two major deviations from writing a plain
recursive Makefile:

 1. all targets and prerequisites (including .PHONY targets!) need to
    be prefixed with
    `$(srcdir)`/`$(outdir)`/`$(topsrcdir)`/`$(topoutdir)`.
      * sub-gotcha: this means that if a pattern rule has a
        prerequisite that may be in srcdir or outdir, then it must be
        specified twice, once for each case.
 2. if a prerequisite is in a directory "owned" by another Makefile,
    you must filter the pathname through `am_path`:
    `$(call am_path,YOUR_PATH)`.  Further, that path must NOT contain
    a `..` segment; if you need to refer to a sibling directory, do it
    relative to `$(topoutdir)` or `$(topsrcdir)`.

Telling automake about your program
-----------------------------------

You tell automake what to do for you by setting some variables.  They
are all prefixed with `am_`; this prefix may be changed by editing the
`_am` variable at the top of `automake.head.mk`.

The exception to this is the `am_path` variable, which is a macro that
is used to make a list of filenames relative to the appropriate
directory, because unlike normal GNU (Auto)Make, `$(outdir)` isn't
nescessarily equal to `.`.  See above.

There are several commands that generate files; simply record the list
of files that each command generates as the following variable
variables:

| Variable     | Create Command | Delete Command              | Description                       | Relative to |
|--------------+----------------+-----------------------------+-----------------------------------+-------------|
| am_src_files | emacs          | rm -rf .                    | Files that the developer writes   | srcdir      |
| am_gen_files | ???            | make maintainer-clean       | Files the developer compiles      | srcdir      |
| am_cfg_files | ./configure    | make distclean              | Users' compile-time configuration | outdir      |
| am_out_files | make all       | make mostlyclean/make clean | Files the user compiles           | outdir      |
| am_sys_files | make install   | make uninstall              | Files the user installs           | DESTDIR     |

In addition, there are two more variables that control not how files
are created, but how they are deleted:

| Variable       | Affected command | Description                                    | Relative to |
|----------------+------------------+------------------------------------------------+-------------|
| am_clean_files | make clean       | A list of things to `rm` in addition to the    | outdir      |
|                |                  | files in `$(am_out_files)`.  (Example: `*.o`)  |             |
|----------------+------------------+------------------------------------------------+-------------|
| am_slow_files  | make mostlyclean | A list of things that (as an exception) should | outdir      |
|                |                  | _not_ be deleted.  (otherwise, `mostlyclean`   |             |
|                |                  | is the same as `clean`)                        |             |

Finally, there are two variables that express the relationships
between directories:

| Variable   | Description                                             |
|------------+---------------------------------------------------------|
| am_subdirs | A list of other directories (containing Makefiles) that |
|            | may be considered "children" of this                    |
|            | directory/Makefile; building a phony target in this     |
|            | directory should also build it in the subdirectory.     |
|            | They are not necesarily actually subdirectories of this |
|            | directory in the filesystem.                            |
|------------+---------------------------------------------------------|
| am_depdirs | A list of other directories (containing Makefiles) that |
|            | contain or generate files that are dependencies of      |
|            | targets in this directory.  They are not necesarily     |
|            | actually subdirectories of this directory in the        |
|            | filesystem.  Except for files that are dependencies of  |
|            | files in this directory, things in the dependency       |
|            | directory will not be built.                            |

Tips, notes
-----------

I like to have the first (non-comment) line in a Makefile be:

    include $(dir $(lastword $(MAKEFILE_LIST)))/../../config.mk

(adjusting the number of `../` sequences as nescessary).  Then, my
(user-editable) `config.mk` is of the form:

    ifeq ($(topsrcdir),)
    topoutdir := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))
    topsrcdir := $(topoutdir)

    # your configuration

    endif

If the package has a `./configure` script, then I have it modifiy
topsrcdir as necessary, as well as modifying whatever other parts of
the configuration.  All of the configuration lives in `config.mk`;
`./configure` doesn't modify any `Makefile`s, it just generates
`config.mk`, and copies (or (sym?)link?) every `$(srcdir)/Makefile` to
`$(outdir)/Makefile`.

----
Copyright (C) 2016  Luke Shumaker

This documentation file is placed into the public domain.  If that is
not possible in your legal system, I grant you permission to use it in
absolutely every way that I can legally grant to you.