File: include.so

package info (click to toggle)
cook 2.5-1
  • links: PTS
  • area: main
  • in suites: slink
  • size: 5,860 kB
  • ctags: 3,247
  • sloc: ansic: 41,260; sh: 10,022; yacc: 3,397; makefile: 3,244; awk: 136
file content (280 lines) | stat: -rw-r--r-- 12,366 bytes parent folder | download
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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
.\"
.\"	cook - file construction tool
.\"	Copyright (C) 1997 Peter Miller;
.\"	All rights reserved.
.\"
.\"	This program is free software; you can redistribute it and/or modify
.\"	it under the terms of the GNU General Public License as published by
.\"	the Free Software Foundation; either version 2 of the License, or
.\"	(at your option) any later version.
.\"
.\"	This program is distributed in the hope that it will be useful,
.\"	but WITHOUT ANY WARRANTY; without even the implied warranty of
.\"	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
.\"	GNU General Public License for more details.
.\"
.\"	You should have received a copy of the GNU General Public License
.\"	along with this program; if not, write to the Free Software
.\"	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
.\"
.\" MANIFEST: User Guide, Include File Dependencies
.\"
.H 1 "Include File Dependencies"
A significant factor in a cookbook accurately describing the dependencies
in a program are the include file dependencies.  There are
three
methods
for doing this in Cook.  The first is easily understandable but is too
slow to use on large projects, the second is a little harder to
understand, but works well for large projects.
The third method is rather convoluted, but works well for projects with
many thousands of source files and multiple simultaneous architectures
built within the same source tree.
.P
The recipes here are merely examples and starting points; you will almost
certainly need to enhance them to suit the needs of your projects.
Areas you will need to address include
(a) the existence of \f[CW]cc -I\fP\fIpath\fP options,
(b) the use of \f[CW]search_list\fP variable and the \f[CW][resolve]\fP
function, and
(c) heterogeneous development.
The techniques also apply to other languages,
such as Fortran, Pascal and Roff,
but each requires a language-specific include scanning program\*F.
.FS
The \fIc_incl\fP program understands Roff, you just need to use the
\f[CW]\-r\fP option.
.FE
.H 2 "The Manual Method"
Well, actually there are
four
methods, if you count maintaining the
dependencies manually.  This has the serious defect that humans tend to
\fIforget\fP to update the cookbook.  On a large project not all
developers are familiar with the workings of Cook, and so they shy away
from updating the cookbook.  By finding ways to automate include
dependency processing, we reduce the risk that a developer will forget
to update the cookbook, and we reduce the risk that the cookbook's
dependency information is out-of-date.
.P
Automatic include dependency methods described below have flaws, and can
never replace a human for flexibility and domain knowledge.  On the
other hand, humans have better things to do with their time than grope
files for include file dependencies (like write neat software).
.H 2 "Tools"
All of the automated include file dependency methods described below use the
\fIc_incl\fP(1) program included in the Cook distribution.  It has a
number of options tailored for use with Cook.  For exact information
about the \fIc_incl\fP command, consult the on-line \fIman\fP(1) system
(it should have been installed) or the Cook Reference Manual.
.P
Other tools are available.  The commonest is to use the \f[CW]gcc\|-M\fP
option, which produces a list of include files on the standard output.
Because the \f[CW]gcc\|-M\fP output is aimed at GNU Make, you will need an
\fIawk\fP(1) or \fIsed\fP(1) script to massage the output into a format
suitable for Cook.
.H 2 "The Small Method"
The easiest way to determine a file's include file determine the
include dependencies within the recipe's ingredients.
.eB
%.o: %.c: [collect c_incl -api %.c]
{
	cc -c %.c;
}
.eE
.P
Note the second colon \- the \fIsecond\fP set of dependencies are only
evaluated after Cook has chosen to activate the recipe.
This does not guarantee that the file exists yet
(it may have to be generated by \fIlex\fP or \fIyacc\fP),
which is why the \f[CW]--Absent-Program-Ignore\fP option is required.
.P
This method has the advantage of simplicity.
It uses a single recipe which reads the way recipes usually read,
and does not contain any unusual constructs.
.P
There are two problems with this method.  The first is that it doesn't
scale well.  When there are only a few source files, the processing
burden of running \fIc_incl\fP for every \fB\&.c\fP file every time Cook
is invoked is hardly noticeable.  The \fIc_incl\fP program caches the
results of its scans, so that is can minimize the length of time taken,
and this does help a little.  However projects with hundreds or
thousands of files find even the cached performance an unreasonable
burden; it is constantly re-calculating something which has not changed
from one run to the next.
.P
The second problem is that the \fIc_incl\fP program is run when the
dependency graph is being built, not when it is being walked.  This
means that the \fB\&.c\fP file (or a subordinate \fB\&.h\fP file) may
have been out-of-date at the time.  When the graph is walked, it will
have been regenerated, and the two sets of include files, those
determined by \fIc_incl\fP at graph building time, and those seen by
\fIcc\fP at graph walking time, may not agree \- which may result in
compile-time errors.
.H 2 "The Large Method"
For projects with large numbers of files, hundreds or even thousands,
it is necessary to re-calculate the include
file dependencies only when a \fB\&.c\fP file changes, or a subordinate
\fB\&.h\fP file.  Ideally, Cook should access this information directly,
rather than running a program to determine it or to fetch it.
.P
The first task is to move the information which \fIc_incl\fP caches into
a format that Cook can access directly; Cook can then read in this
information as it scans the cookbook.  By making a separate
``dependency'' file for each \fB\&.c\fP file, we can using existing Cook
mechanisms to describe how to keep this file up-to-date.
.P
The dependency file is generated and maintained as follows:
.eB
%.c.d: %.c
{
	c_incl --no-cache %.c
		"--prefix='%.o "[target]": %.c'"
		"--suffix='set nodefault;'"
		-o [target];
}
.eE
.P
This recipe generates a file which contains a mini-cookbook describing
the ingredients of the \fIobject\fP file.  The dependencies are in terms
of the object file because if any of the \fB\&.h\fP files change, it is
the object file which is out-of-date, not the \fB\&.c\fP file.
The mini-cookbook itself is also described, so that if any of the
source files change, the mini-cookbook can be brought up-to-date again.
.P
The recipe for the object file is less complicated than in the previous
section, because the mini-cookbooks supplement it:
.eB
%.o: %.c
{
	cc -c %.c;
}
.eE
.P
The only thing missing is how to get the information in the
mini-cookbooks into the main cookbook.  This is done with an include
directive in the cookbook itself, but a special form of it.  The names
of the mini-cookbooks can be determined the same way as the names of the
object files, and this allows the cookbook fragments such as the
following to be written:
.eB
object_files = [fromto %.c %.o [source_files]];
dependency_files = [fromto %.c %.c.d [source_files]];

#include-cooked [dependency_files]
.eE
.P
The \f[CW]#include-cooked\fP directive says to include the named files
(there may be more than one) if the file exist.  Once the cookbook (and
its includes) have been read in, the files included with this directive
are checked to see if they are up-to-date.  If they are not, then they
are re-cooked, and then Cook starts over again; this time with
up-to-date include dependencies.
.P
The advantage of the method is
that if the source files don't change, the dependency information is not
recalculated, this can result in significant savings.  Also, no
processes are invoked if nothing has changed, Cook reads the information
directly.  Because file opens are significantly cheaper than process
invocations, this results in a significant performance improvement.
.P
The disadvantage of this method is
that it is harder to describe and harder to implement.
To the uninitiated the cookbook looks incomplete and overly complex.
.P
Another problem is that if you delete an include file, Cook will
complain that it is unable to derive the dependency file because the
include file is not present.  Simply delete the dependency file and
start again.  To avoid the problem, remove references to include files,
and re-build, before deleting the include files.  This problem is seen
from time to time, but does not present a huge problem in normal practice.
.H 2 "The Cascade Method"
When large numbers of files are involved, it becomes clear that the
more popular include files are being scanned repeatedly.  This can be
un-necessarily time-consuming when a popular include file is touched,
as the dependency files of all \f(CW.c\fP files which reference it,
even indirectly, must be re-calculated.
.P
There is also a problem when you are attempting to perform heterogenous
builds for multiple architectures out of the same sources.  This is
typically done by inserting the architecture name into the object file
path as a directory.  This presents another problem: nominating all of the
architectures on the left-hand-side of the regerated dependency recipes.
Especially if you add another one after the fact - now all the existing
dependency files must be recalculated, merely to add the new architecture.
.P
An alternative is to scan each of the source files and include files
once, and request cook to combine them together at build time, rather than
at dependance scan time.  This is done using \f(CWcascade-for\fP recipes.
These recipes notimate additional ingredients (on their right-hand-size)
if any of the files on their left-hand-size appears in an ingredients list.
.eB
cascade-for foo.c = bar.h;
.eE
This recipe says that any recipe which has \fIfoo.c\fP for an ingredient,
also has \fIbar.h\fP for an ingredient.
.P
This takes care of the heterogeneous case, because while the recipes
remain specified in a simple manner, \fIviz:\fP
.eB
%1/%0%.o: %0%.c
{
	%1-gcc -o [target] -c %0%.c;
}
.eE
Any and all of them which compile \fIfoo.c\fP will depend on \fIbar.h\fP
from the \f(CWcascade-for\fP recipe.  (This example assumes that you are
using \fIgcc\fP(10 in the usual way, and that your architecture names
match the GNU target names.)
.P
The dependency files are generated and maintained in much the same way
as before, except that you need two: one for \f(CW.c\fP files and one
for \f(CW.h\fP files:
.eB
%0%.c.d: %0%.c
	set no-cascade
{
	c_incl --no-cache %0%.c
		"--prefix='cascade-for %0%.c ='"
		"--suffix=';'"
		-o [target];
}
.eE
.eB
%0%.h.d: %0%.h
	set no-cascade
{
	c_incl --no-cache %0%.h
		"--prefix='cascade-for %0%.h ='"
		"--suffix=';'"
		-o [target];
}
.eE
You will also need to add the \f(CW.h.d\fP files to the
\f(CW#include-cooked\fP lines, to ensure they are generated.  If there are
any generated \f(CW.c\fP or \f(CW.h\fP files, you will need to mention
these, too.
.H 2 "Dependencies on Derived Files"
If the relationship between a target and a derived ingredient appears
only in a derived cookbook, it is likely that a clean build (solely
from primary source files) will fail.  It is recommended that
relationships such as this be placed in a primary source cookbook.
Cook looks for such dependencies, and will warn you about them.
.P
An example of this is commonly seen when using the \f[CW]-d\fP option
with \fIyacc\fP(1).  If you have a separate lexical analyzer (the usual
reason for using \f[CW]-d\fP) it will need to include the generated
token definition file.
.P
When you first add the \fIyacc\fP(1) grammar definition, Cook will
generate both the \f[CW].c\fP and \f[CW].h\fP file from the usual yacc
recipes.  It is only later, when you have cleaned out all derived files
(including the dependency files) that you may have problems.  Where is
it recorded that Cook needs to regenerate the token definition file
before it can determine the include dependencies of the lexical
analyzer?  (They were in a \f[CW].d\fP file which as ``cleaned'' away.)
.P
Cook will detect this situation at the first possible moment, and warn
you.  But placing the dependency in a non-derived cookbook (\fIe.g.\fP
\f[CW]Howto.cook\fP) the warning will go away, and you will be able to
do reliable clean builds.