aboutsummaryrefslogtreecommitdiff
path: root/docs/recommended_practices_for_makefiles.md
blob: 1391ec3b6dbfac784ec8b04b5413e183b3bdc591 (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
165
166
167
168
169
170
171
172
173
174
175
176
# Recommended practices for Makefiles

When authoring a Lua module, especially those containing C code, developers
are always faced with some build and deployment issues: where to find
libraries, where to install modules, which flags to pass when building, and so
on. Looking at the existing modules available in the web, it is clear to see
that there are no _de facto_ standards in Makefiles for Lua modules, and that
many of them are incomplete copies of one another, and many of them share the
same deficiencies. Here is a list of some of those issues we found during the
development of LuaRocks, and how to avoid them. Following the recommendations
below will improve the portability of your Makefiles and make things easier
for writing rocks, other packagers such as Linux distributions, and your
users.

# Do not ask users to edit files "by hand" 

Asking users to hand-edit things is error-prone. Even though systems like
LuaRocks support applying patches -- which is the automated equivalent of
hand-tweaking files -- this adds maintenance burden, as patches have to be
updated on each release if any change happens in the file. Always use
variables, so that they can be overridden by automated processes. Hand-tweaks
in the code can be avoided by propagating C defines from Makefiles as well.

Don't:
```
// Edit this to suit your installation
const char* bla_dir = "/usr/local/share/bla";
```

Do:

```
BLA_DIR=/usr/local/share/bla
# ...
bla.o:
        $(CC) -c bla.c -DBLA_DIR=\"$(BLA_DIR)\"
```

## Do not hardcode any paths 

This is a corollary to the above recommendation, really. Whenever you are
passing any paths, don't write them directly in Makefile rules. Always factor
them out into variables.

# Provide a nice "install" rule 

A large number of Makefiles for Lua modules ship without an "install" rule,
probably due to the long-standing lack of standard install locations for
modules that plagued the Lua world in the past. Nowadays, however, the
convention of using .../lib/lua/5.1/ for C modules and .../share/lua/5.1/ for
Lua modules (relative to the prefix where Lua is installed) is well
established, and there is no reason not to use it. To make things even easier
for your users, you can also factor out the common Lua prefix. /usr/local is a
good default, since it is also the default for the vanilla Lua tarball.

Don't:

```
# no make install rule!
```

Do:

```
LUA_DIR=/usr/local
LUA_LIBDIR=$(LUA_DIR)/lib/lua/5.1
LUA_SHAREDIR=$(LUA_DIR)/share/lua/5.1

# ...

install:
        mkdir -p $(LUA_LIBDIR)/bla
        cp bla/core.so $(LUA_LIBDIR)/bla
        mkdir -p $(LUA_SHAREDIR)/bla
        cp bla.lua $(LUA_SHAREDIR)
        cp bla/extras.lua $(LUA_SHAREDIR)/bla
```

Some packagers recommend prepending an empty `$(DESTDIR)` variable to all target
paths in your install rule, but that's not strictly necessary if your paths
are all set into variables, which can be redefined for the "make install" run,
like in the example above.

# Do not assume libraries are in the system path 

If your program uses LibPNG, adding "-lpng" to your Makefile is not enough.
Your users may have the LibPNG library somewhere else, so let them specify the
locations of both the libraries and headers. The default values you pick are
not really important, as long as they're overridable by the user, but
/usr/local is always a good choice on Unix systems as this is the first
typical "non-system path" that users may want to use.

Of course, use one library per value; don't assume all third-party libraries
can be found in the same place.

Don't:

```
gcc -o bla bla.c -lpng
```

Do:

```
LIBPNG_DIR=/usr/local
LIBPNG_INCDIR=$(LIBPNG_DIR)/include
LIBPNG_LIBDIR=$(LIBPNG_DIR)/lib

# ...
        $(CC) -o bla bla.c -lpng -L$(LIBPNG_LIBDIR) -I$(LIBPNG_INCDIR)
```

# Avoid compiler assumptions 

Even if your code only compiles in GCC and is Unix-only, there are still build portability issues to look out for. The main ones are:

* **Not all GCCs link libraries with the same flags** - for instance, linking
  shared libraries is done with "-shared" on Linux and "-bundle -undefined
  dynamic_lookup -all_load" on Mac OSX. Factoring the flags in a variable is
  a nice gesture for users of other operating systems. (LuaRocks can take
  care of the detection part and set the flag appropriately, but packages of
  other systems will benefit as well.)

* **The compiler is not always called "gcc"** - this one is for the people in
  the embedded world; in their toolchains, their cross-compilers often have
  names like "arm-nofpu-gcc". $(CC) is a standard variable in make. Just use
  that instead of "gcc" and you're good to go.

Don't:

```
bla.so:
        gcc -o bla.so -shared bla.o
```

Do:

```
LIBFLAG=-shared
# ...
bla.so:
        $(CC) -o bla.so $(LIBFLAG) bla.o
```

# Do not "overload" variables 

As mentioned in the topic about third-party libraries above, don't reuse variables just because two conceptually different locations happen to point to the same place. For example, do not assume that the directory you're using to _find_ libraries and the directory you're _installing_ libraries to is the same. That little economy will only cause confusion and trouble to your users.

Don't:

```
LIBDIR=/usr/local/lib
INCDIR=/usr/local/include
# ...
bla.so:
        $(CC) $(LIBFLAG) -o bla.so -lpng -L$(LIBDIR) -I$(INCDIR)
install:
        mkdir -p $(LIBDIR)
        cp bla.so $(LIBDIR)/lua/5.1
```

Do:

```
LIBPNG_DIR=/usr/local
LIBPNG_LIBDIR=$(LIBPNG_DIR)/lib
LIBPNG_INCDIR=$(LIBPNG_DIR)/include
LUA_DIR=/usr/local
LUA_LIBDIR=$(LUA_DIR)/lib/lua/5.1
# ...
bla.so:
        $(CC) $(LIBFLAG) -o bla.so -lpng -L$(LIBPNG_LIBDIR) -I$(LIBPNG_INCDIR)
install:
        mkdir -p $(LUA_LIBDIR)
        cp bla.so $(LUA_LIBDIR)
```