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
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
|
<!-- $NetBSD: chap.types.xml,v 1.1 2015/11/25 16:42:21 rillig Exp $ -->
<chapter id="types">
<title>The &pkglint; type system</title>
<para>One of the most notable additions to &pkglint; is the
introduction of typed variables. Traditionally, in
<filename>Makefile</filename>s, all variables have the type
<type>String</type>. This prevents many useful checks from being
done before executing the code.</para>
<para>Up to 2004, &pkglint; already did some checks based on
the value of the variables, but these checks had no common
structure that could be described easily.</para>
<sect1 id="types.history">
<title>History</title>
<para>In February 2005, initial support for the &pkglint; type
system has been added. Some of the common variables have been
assigned types such as <literal><type>Boolean</type></literal>
or <literal><type>Yes_Or_Undefined</type></literal>, which are
the two common ways to represent boolean variables in pkgsrc.
The list of typed variables has been moved from the &pkglint;
code to an external file, <filename>makevars.map</filename>.
Many more basic types have been added later.</para>
<para>In October 2005, the type system has been extended to
allow <literal><type>List of
<replaceable>simple-type</replaceable></type></literal>, which
allowed to handle variables like <varname>DEPENDS</varname> and
<varname>CFLAGS</varname>. One month later, enumeration types
have been added, allowing the type of
<varname>PTHREAD_OPTS</varname> to be expressed as <literal>List
of { require native }</literal>.</para>
<para>In May 2006, the definition and use of variables has been
further restricted by introducing ACLs, which define the
permitted operations (write, append, default, read, preprocess-read)
depending on the current file.</para>
</sect1>
<sect1 id="types.syntax">
<title>Syntax for defining types</title>
<programlisting>
type ::= (list-type)? simple-type (acls)?
list-type ::= ("List" | "InternalList") "of"
simple-type ::= predefined-type
| enumeration
predefined-type ::= [A-Za-z][0-9A-Z_a-z]*
enumeration ::= "{" (enumeration-item)* "}"
enumeration-item ::= [-0-9A-Z_a-z]+
acls ::= "[" (acl-entry ("," acl-entry)*)? "]"
acl-entry ::= acl-subject ":" acl-perms
acl-subject ::= [.0-9A-Za-z]+ | "_"
acl-perms ::= [adprs]*
</programlisting>
</sect1>
<sect1 id="types.semantics">
<title>Semantics of the types</title>
<para>The <firstterm>simple types</firstterm> in &pkglint; are
either predefined types or enumeration types. A
<firstterm>predefined type</firstterm> is used by its name. See
<xref linkend="types.predefined"/> for the list of predefined
types.</para>
<para>An expression of an enumeration type may have either of
the enumeration-items as a value. It may not reference other
variables.</para>
<para>A list type can be constructed from a predefined type or
an enumeration. It is not possible to construct lists of lists,
since I have never needed that. There are two types of lists,
called <literal>List</literal> and
<literal>InternalList</literal>, which are described in the
<ulink url="&pkgsrc-guide;/makefile.html">pkgsrc guide, the
chapter about <filename>Makefile</filename>s</ulink>.</para>
</sect1>
<sect1 id="types.acls">
<title>Access Control Lists</title>
<para>Additionally to the data type, which specifies
<emphasis>what</emphasis> a variable can contain, the ACLs
define <emphasis>where</emphasis> the variable can be defined or
used (this is called the <firstterm>ACL subject</firstterm>) and
which operations are allowed (these are the <firstterm>ACL
permissions</firstterm>).</para>
<para>The ACL subjects are specified by the filename. For
example, <filename>Makefile</filename> and
<filename>buildlink3.mk</filename> are valid ACL subjects. Since
some names occur over an over in pkgsrc, these can be
abbreviated as shown in <xref linkend="types.acl.subjects.abbr"
/>. The character <literal>*</literal> is a placeholder for zero
or more arbitrary characters, like in the shell. The possible
actions on a variable are shown in <xref
linkend="types.acl.perms" />.</para>
<table id="types.acl.subjects.abbr">
<title>ACL Subjects</title>
<tgroup cols="2">
<thead><row><entry>Subject</entry><entry>Abbreviation</entry></row></thead>
<tbody>
<row><entry><filename>Makefile</filename></entry><entry>m</entry></row>
<row><entry><filename>Makefile.common</filename></entry><entry>c</entry></row>
<row><entry><filename>buildlink3.mk</filename></entry><entry>b</entry></row>
<row><entry><filename>hacks.mk</filename></entry><entry>h</entry></row>
<row><entry><filename>options.mk</filename></entry><entry>o</entry></row>
<row><entry>any file</entry><entry>*</entry></row>
</tbody>
</tgroup>
</table>
<table id="types.acl.perms">
<title>ACL Permissions</title>
<tgroup cols="2">
<thead><row><entry>Permission</entry><entry>Description</entry></row></thead>
<tbody>
<row><entry><filename>a</filename></entry><entry>Append to the
variable using the <literal>+=</literal> operator.</entry></row>
<row><entry><filename>d</filename></entry><entry>Provide a
default value for the variable using the <literal>?=</literal>
operator.</entry></row>
<row><entry><filename>s</filename></entry><entry>Set the
variable unconditionally using the <literal>=</literal>,
<literal>:=</literal> or <literal>!=</literal>
operator.</entry></row>
<row><entry><filename>u</filename></entry><entry>Use the value
of the variable.</entry></row>
<row><entry><filename>p</filename></entry><entry>Use the value
of the variable during preprocessing.</entry></row>
</tbody>
</tgroup>
</table>
<para>If a variable has no ACL definition at all, all operations
are allowed on it. Otherwise exactly those operations of the
first ACL entry whose subject matches the current filename are
allowed. If no entry matches, nothing is allowed.</para>
<para>For determining if a variable is used in the correct
place, the filename is only one part of the whole decision. The
other one is the context in which the variable appears. There
are many factors that influence whether the variable is used
correctly.</para>
<itemizedlist>
<listitem><para>The variable may be either used at preprocessing time
or at runtime. Some variables are defined in
<filename>bsd.pkg.mk</filename> and thus are not available until
that file has been included. As this should always be the very
last thing a package includes, it practically means that these
variables are only available at runtime.</para></listitem>
<listitem><para>The variable may appear as the whole right hand side
of an assignment, as a single word, or even as part of a word.
First, the types on the right and left side should be
compatible. Second, some variables need to be quoted correctly,
depending on whether they are part of a word or not.</para></listitem>
<listitem><para>In shell commands, the variable may also appear as a
whole word or as part of a word. This is similar to the case
above.</para></listitem>
<listitem><para>The variable may appear inside some sort of quotes.
For some variables this is acceptable, as they are assumed to
never contain special characters. For others it
isn't.</para></listitem>
<listitem><para>The various operators in conditional statements like
<literal>.if</literal> may further restrict the valid values.
For example, the <varname>OPSYS</varname> variable should only
be compared to well-known operating system names. The
<varname>exists()</varname> function should only be called on
pathnames. The <varname>defined()</varname> operator only checks
if the variable is defined and does not access its
value.</para></listitem>
</itemizedlist>
<sect2 id="types.acls.future">
<title>Future Directions</title>
<para>Currently the ACLs only cover the <quote>user
space</quote> of pkgsrc. They will be extended later to also
check for valid variable definition and use in the pkgsrc
infrastructure, as well as the user configuration file. For
completeness, those variables that are intended to be specified
on the command line will be added to the
<filename>makevars.map</filename> file.</para>
</sect2>
</sect1>
<sect1 id="types.predefined">
<title>Predefined types</title>
<para>There are many predefined types in &pkglint;, which are
described below.</para>
<!-- reference: pkglint.pl, revision 1.532 -->
<variablelist>
<varlistentry><term><literal><type>AwkCommand</type></literal></term>
<listitem><para>An awk command. Currently nothing is checked
here.</para></listitem></varlistentry>
<varlistentry><term><literal><type>BuildlinkDepmethod</type></literal></term>
<listitem><para>Must be either <literal>build</literal> or
<literal>full</literal>.</para></listitem></varlistentry>
<varlistentry><term><literal><type>BuildlinkDepth</type></literal></term>
<listitem><para>This type is only intended for one variable,
namely <varname>BUILDLINK_DEPTH</varname>, which is only
modified in <filename>buildlink3.mk</filename>
files.</para></listitem></varlistentry>
<varlistentry><term><literal><type>BuildlinkPackages</type></literal></term>
<listitem><para>The type of the variable
<varname>BUILDLINK_PACKAGES</varname>. Like
<literal><type>BuildlinkDepth</type></literal> above, this is
only used in <filename>buildlink3.mk</filename> files. This
variable has two different patterns to be modified. The first is
to remove the current package from itself, and the second is to
append the current package. This prevents a package from showing
up twice in the list.</para></listitem></varlistentry>
<varlistentry><term><literal><type>Category</type></literal></term>
<listitem><para>One of the categories that a package may be
placed in. The list of categories has been assembled manually
when the type was introduced. There is no further agreement on
which valid categories are valid, besides the top level
directory names in pkgsrc.</para></listitem></varlistentry>
<varlistentry><term><literal><type>CFlag</type></literal></term>
<listitem><para>One word in a <varname>CFLAGS</varname> or
<varname>CPPFLAGS</varname> variable. &pkglint; knows the flags
starting with <literal>-D</literal>, <literal>-U</literal>,
<literal>-I</literal>. Flags starting with
<literal>-O</literal>, <literal>-W</literal>,
<literal>-f</literal>, <literal>-g</literal> or
<literal>-m</literal> are silently accepted since they are
commonly used for the GNU compilers. As the pkgsrc framework
does not know how to handle most of these flags, care should be
taken.</para></listitem></varlistentry>
<varlistentry><term><literal><type>Comment</type></literal></term>
<listitem><para>The comment of a package.</para>
</listitem></varlistentry>
<varlistentry><term><literal><type>Dependency</type></literal></term>
<listitem><para>A simple dependency like
<literal>foopkg>=1.0</literal>, <literal>foopkg-[0-9]*</literal>
or <literal>foopkg-1.0</literal>.</para>
</listitem></varlistentry>
<varlistentry><term><literal><type>DependencyWithPath</type></literal></term>
<listitem><para>A dependency (see above), followed by a colon
and a relative directory. For some packages, special variables
like <varname>USE_TOOLS</varname> should be used instead of an
explicit dependency.</para></listitem></varlistentry>
<varlistentry><term><literal><type>DistSuffix</type></literal></term>
<listitem><para>The value of the variable
<varname>EXTRACT_SUFX</varname>. The difference in the name is
intentional here, since <varname>EXTRACT_SUFX</varname> is a
misnomer. <varname>DIST_SUFX</varname> or
<varname>DIST_SUFFIX</varname> would be more appropriate.</para>
</listitem></varlistentry>
<varlistentry><term><literal><type>EmulPlatform</type></literal></term>
<listitem><para>An emulated platform consists of the operating
system (in lowercase, as opposed to <type>PlatformTriple</type>)
and the hardware architecture.</para></listitem></varlistentry>
<varlistentry><term><literal><type>Filename</type></literal></term>
<listitem><para>A filename, as defined in <ulink
url="http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_169">POSIX</ulink>.
This type further restricts the set of allowed characters.
See also <literal><type>Pathname</type></literal>.</para>
</listitem></varlistentry>
<varlistentry><term><literal><type>Filemask</type></literal></term>
<listitem><para>A shell globbing pattern that does not contain a
slash. See also <literal><type>Pathmask</type></literal>.</para>
</listitem></varlistentry>
<varlistentry><term><literal><type>Identifier</type></literal></term>
<listitem><para>In various places in pkgsrc, identifiers are
used. This type collects the most common naming conventions.
When you need a more specific check, you have to write your own
check.</para></listitem></varlistentry>
<varlistentry><term><literal><type>LdFlag</type></literal></term>
<listitem><para>A flag that is passed to the linker. Flags
starting with <literal>-L</literal> or <literal>-l</literal> are
accepted, as well as some others that are assumed to be handled
by the wrapper framework.</para></listitem></varlistentry>
<varlistentry><term><literal><type>Mail_Address</type></literal></term>
<listitem><para>Checks for a very restricted subset of <ulink
url="http://www.ietf.org/rfc/rfc2822.txt">RFC
2822</ulink>.</para></listitem></varlistentry>
<varlistentry><term><literal><type>Message</type></literal></term>
<listitem><para>Messages are printed to the user as status
indicators. <ulink
url="http://www.freebsd.org/cgi/cvsweb.cgi/ports/devel/portlint/src/portlint.pl#rev1.77">As
opposed to FreeBSD</ulink>, they should not be quoted since they
may be used in contexts where quoting should be done
differently.</para></listitem></varlistentry>
<varlistentry><term><literal><type>Option</type></literal></term>
<listitem><para>An option from the
<literal>PKG_OPTIONS</literal> framework. Options should not
contain underscores. They should be documented in
<filename>pkgsrc/mk/defaults/options.description</filename>.</para>
</listitem></varlistentry>
<varlistentry><term><literal><type>Pathlist</type></literal></term>
<listitem><para>A list of directories that are separated by
colons, like the popular environment variable
<varname>PATH</varname>. This type differs from the type
<literal><type>List of Pathname</type></literal> in the
character that is used as a separator.</para>
</listitem></varlistentry>
<varlistentry><term><literal><type>Pathmask</type></literal></term>
<listitem><para>A shell globbing expression that may include
slashes.</para></listitem></varlistentry>
<varlistentry><term><literal><type>Pathname</type></literal></term>
<listitem><para>A pathname, as defined in <ulink
url="http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_266">POSIX</ulink>.
See also <literal><type>Filename</type></literal>.</para>
</listitem></varlistentry>
<varlistentry><term><literal><type>Perl5Packlist</type></literal></term>
<listitem><para>A common error has been to refer to
<varname>INSTALLARCHLIB</varname> in the location of the packing
list. Therefore no references to other variables are
allowed.</para></listitem></varlistentry>
<varlistentry><term><literal><type>PkgName</type></literal></term>
<listitem><para>A package name should conform to some
restrictions, since the filename of the binary package is
created from it, which is then interpreted by pkg_add and the
like.</para></listitem></varlistentry>
<varlistentry><term><literal><type>PkgOptionsVar</type></literal></term>
<listitem><para>I had once made the mistake of referencing
<varname>PKGBASE</varname> in this variable, not knowing that
<varname>PKG_OPTIONS_VAR</varname> is used during preprocessing,
when <varname>PKGBASE</varname> is not yet defined. This type
prevent that mistake from being done again.</para>
</listitem></varlistentry>
<varlistentry><term><literal><type>PkgPath</type></literal></term>
<listitem><para>A directory name that is relative to the
top-level pkgsrc directory. This is only used in specifying
specific packages in bulk builds. Despite its name, this type is
more similar to <type>RelativePkgDir</type> than to
<type>RelativePkgPath</type>.</para></listitem></varlistentry>
<varlistentry><term><literal><type>PkgRevision</type></literal></term>
<listitem><para>The package revision must be a small integer.
The only place where this definition may occur is the package
<filename>Makefile</filename> itself, as this variable says
something about the individual package. There is no mechanism in
pkgsrc for something similar to <varname>PKGREVISION</varname>
that can be used in <filename>Makefile.common</filename>
files.</para></listitem></varlistentry>
<varlistentry><term><literal><type>PlatformTriple</type></literal></term>
<listitem><para>pkgsrc has been ported to many platforms, all of
which are identified using a triple of operating system,
operating system version and hardware
architecture.</para></listitem></varlistentry>
<varlistentry><term><literal><type>Readonly</type></literal></term>
<listitem><para>This type is used to mark a variable as being
read-only to a package author. As this is not really a data type
but an access restriction, it will disappear in the next version
of the type system.</para></listitem></varlistentry>
<varlistentry><term><literal><type>RelativePkgDir</type></literal></term>
<listitem><para>A directory name that is relative to the package
directory. Mostly used for dependencies. See also
<literal><type>RelativePkgPath</type></literal>.</para>
</listitem></varlistentry>
<varlistentry><term><literal><type>RelativePkgPath</type></literal></term>
<listitem><para>A pathname that is relative to the package
directory. It may point to either a regular file or a directory.
See also <literal><type>RelativePkgDir</type></literal>.</para>
</listitem></varlistentry>
<varlistentry><term><literal><type>ShellCommand</type></literal></term>
<listitem><para>A shell command is similar to a
<literal><type>List of ShellWord</type></literal>, except that
additional checks are performed on the direct use of tool names
or certain other deprecated shell commands.</para>
</listitem></varlistentry>
<varlistentry><term><literal><type>ShellWord</type></literal></term>
<listitem><para>A shell word is what the shell would regard as a
single word.</para></listitem></varlistentry>
<varlistentry><term><literal><type>Stage</type></literal></term>
<listitem><para>In pkgsrc, there are phases, stages and steps.
Especially for the <varname>SUBST_STAGE</varname> variable, this
should always be one of the few predefined names, otherwise the
whole substitution group will be ignored.</para>
</listitem></varlistentry>
<varlistentry><term><literal><type>Tool</type></literal></term>
<listitem><para>The pkgsrc tools framework contains very few
plausibility checks. To prevent spelling mistakes, the list of
valid tool names is loaded from the pkgsrc infrastructure files
and compared with the names that are used in the
<varname>USE_TOOLS</varname> variable.</para>
</listitem></varlistentry>
<varlistentry><term><literal><type>URL</type></literal></term>
<listitem><para>URLs appear in <varname>MASTER_SITES</varname>
and the <varname>HOMEPAGE</varname>. If a
<varname>MASTER_SITES</varname> group exists for a given URL, it
should be used instead of listing the URL directly.</para>
</listitem></varlistentry>
<varlistentry><term><literal><type>UserGroupName</type></literal></term>
<listitem><para>User and group names should consist only of
alphanumeric characters and the underscore. This restriction
ensures maximum portability of pkgsrc.</para>
</listitem></varlistentry>
<varlistentry><term><literal><type>Userdefined</type></literal></term>
<listitem><para>Another instance of misuse of the type system.
But it helps to catch some errors in packages. This type will
disappear in the next version of the type system. See also
<literal><type>Readonly</type></literal>.</para>
</listitem></varlistentry>
<varlistentry><term><literal><type>Varname</type></literal></term>
<listitem><para>Variable names are restricted to only uppercase
letters and the underscore in the basename, and arbitrary
characters in the parameterized part, following the dot.</para>
</listitem></varlistentry>
<varlistentry><term><literal><type>WrkdirSubdirectory</type></literal></term>
<listitem><para>The variable <varname>WRKSRC</varname> is
usually defined with reference to <varname>WRKDIR</varname>.
This check currently does nothing, and I don't know if it's
worth to check anything here.</para></listitem></varlistentry>
<varlistentry><term><literal><type>WrksrcSubdirectory</type></literal></term>
<listitem><para>Subdirectories of <varname>WRKSRC</varname> can
be used in <varname>CONFIGURE_DIRS</varname> and some other
variables. For convenience, they are interpreted relative to
<varname>WRKSRC</varname>, so package authors don't have to type
<literal>${WRKSRC}</literal> all the time.</para>
</listitem></varlistentry>
<varlistentry><term><literal><type>Yes</type></literal></term>
<listitem><para>This type is used for variables that are checked
using <literal>defined(VARNAME)</literal>. Their value is
interpreted as <quote>true</quote> if they are defined, no
matter if they are set to <literal>yes</literal> or
<literal>no</literal>.</para></listitem></varlistentry>
<varlistentry><term><literal><type>YesNo</type></literal></term>
<listitem><para>This type is used for variables that are checked
using <literal>defined(VARNAME) &&
!empty(VARNAME:M[Yy][Ee][Ss])</literal>. A value of
<varname>no</varname> means <quote>no</quote> for
them.</para></listitem></varlistentry>
<varlistentry><term><literal><type>YesNoFromCommand</type></literal></term>
<listitem><para>Like <literal><type>YesNo</type></literal>, but
the value may be produced by a shell command using the
<literal>!=</literal> operator.</para></listitem></varlistentry>
</variablelist>
</sect1>
<sect1 id="types.future">
<title>Future directions</title>
<sect2 id="types.kinds">
<title>Different interpretation of the same data types</title>
<para>As explained above, there are internal lists and external
lists in pkgsrc. But that is not the only attribute that a list
can have. They also differ in the way they are defined, which
files may access them, and what it means to append to append a
value to it.</para>
<para>For example, <varname>NOT_FOR_PLATFORM</varname> is a list
that every file may append to without leading to unexpected
behavior. Compare this with
<varname>ONLY_FOR_PLATFORM</varname>, which should only be set
in a single place throughout pkgsrc. Let's say in the package
<filename>Makefile</filename> it is set to
<literal>NetBSD-*-*</literal>, because this file's author knows
for sure that the package is only usable on NetBSD. Now when
some <filename>*.mk</filename> file from a dependency package
adds <literal>DragonFly-*-*</literal> to it, the intent of the
package <filename>Makefile</filename> is undermined by the
dependency package, because now it is possible to build the
package on DragonFly, too.</para>
<para>The same problem arises with the various variables that
can be either <literal>yes</literal> or undefined. They should
always be chosen so that two definitions in different files
don't undermine each other. A good example is
<varname>USE_LIBTOOL</varname>, a bad example is
<varname>NO_BUILD</varname>.</para>
<para>TODO: What are the general properties of
<quote>good</quote> and <quote>bad</quote> variables? How can it
be decided of which kind a certain variable is?</para>
<para>For most lists, the only valid operation is to append
something at the end. Therefore it is good practice to warn if a
list is assigned using another operator that
<literal>+=</literal>. For <varname>SUBST_CLASSES</varname> this
fits perfectly. But for <varname>SUBST_FILES.*</varname> it
doesn't. Usually all occurences of a
<varname>SUBST_FILES.*</varname> variable occur in the same
file, and there should be no other file modifying these
variables. Therefore it is better to use the
<literal>=</literal> operator for the first of the
assignments.</para>
</sect2>
</sect1>
</chapter>
|