-
Notifications
You must be signed in to change notification settings - Fork 22
/
PORTABILITY
235 lines (202 loc) · 8.33 KB
/
PORTABILITY
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
Portability guideline
KAME project
$Id: PORTABILITY,v 1.27 2000/01/06 14:48:08 itojun Exp $
Source code in the "kame" directory will be shared among operating systems
and hardware platforms. Here are several guidelines to be portable
across those possibilities.
- Developers MUST compile the code on two or more platforms, before committing
it to the repository (trivial changes or comment typos are okay).
- Do not break paren-match.
Always try to keep paren-match correctly, regardless of #ifdef.
The following is WRONG example:
#if foo
if (foo) {
#else
if (foo && bar) {
#endif
....
}
baz(this, that,
#if foo
something);
#else
something, anything);
#endif
It should be written like follows:
#if foo
if (foo)
#else
if (foo && bar)
#endif
{
....
}
#ifdef foo
baz(this, that, something);
#else
baz(this, that, something, anything);
#endif
/* latter part can also be like follows... */
baz(this, that,
something
#ifndef foo
, anything
#endif
);
It is also advised to add extra comment to help paren match,
if you need to write widow paren in string. For example:
printf("("); /* ) */
- Avoid use of "#if" as much as possible, stick to "#ifdef" or "#ifndef"
if possible (Avoid "#if defined(foo)" if you only have single "foo").
"#if" is relatively new syntax and is not friendly with old tools like
unifdef(1).
- Follow NetBSD KNF.
They are the most strict guys about source code formatting.
If you obey NetBSD KNF, other platforms are happy.
More information on KNF is available at:
http://www.netbsd.org/Documentation/kernel/programming.html
- Pointer can be 64bit (for example, on alpha).
When taking integer from pointer, use u_long, or long.
This is WRONG:
void *p;
/* alignment check */
if ((1 & (int)p) == 0) {
...
}
This is correct (but actually is not future-proven - fail on 128bit arch):
void *p;
/* alignment check */
if ((1 & (u_long)p) == 0) {
...
}
- size_t can be 64bit, and may not be of same size as int.
When doing printf(), cast size_t to u_long and print it as %lu.
size_t siz;
printf("%lu", (u_long)siz);
- tv.tv_sec is not typed as time_t.
If you want time_t, explicitly copy the value.
- Packed structs must be used with care.
Unaligned structure can cause problem on certain architectures.
You'll need to copy the return value to aligned structure before accessing.
Structure returned by SIOCGIFCONF falls into this category.
- 2nd arg to ioctl() must be u_long, not int, on non-FreeBSD2 platforms.
- If you define multi-statement #define, define that like:
#define foobar (x, y) \
do { \
/*something*/ \
/*something*/ \
} while (0)
Without this wrapper nasty mistakes can happen.
- Compiler options need to be configured differently into Makefile.
For NetBSD and OpenBSD, CFLAGS and CPPFLAGS are defined separately:
CPPFLAGS+=-I/usr/local/include
CFLAGS+=-g
For FreeBSD and BSDI, there's no distinction.
CFLAGS+=-I/usr/local/include
CFLAGS+=-g
- To refer objects and machine-generated source code, FreeBSD needs to use
${.OBJDIR}. This is because because FreeBSD completely separates "obj" tree
and "src" tree and has no symlink from ${.CURDIR}/obj to /usr/obj/foobar.
On other platforms, ${.CURDIR}/obj should do.
- On manpage installation and shlib generation in Makefile.
for BSDI3, you need to set MAN[0-9] in Makefile like below. MANDIR must
point to "catN" directory, not "manN", without "N":
MANDIR= /usr/local/v6/man/cat
MAN5= foo.0
MAN8= baz.0
MLINKS= foo.5 bar.5
BSDI4 is much like the same as BSDI3. The only exception is shlib
generation. NODYNAMIC=yes would prevent dynamic library from created:
MANDIR= /usr/local/v6/man/cat
MAN5= foo.0
MAN8= baz.0
MLINKS= foo.5 bar.5
NODYNAMIC=yes # if you do not want shlib, define it
For NetBSD, you need to set MAN (not MAN[0-9]). MANDIR needs to point to
"man" directory right above "catN" or "manN" directory:
MANDIR= /usr/local/v6/man
MAN= foo.5 baz.8
MLINKS= foo.5 bar.5
MKPIC= # if you do not want shlib, make it empty
For OpenBSD, you need to set MAN (not MAN[0-9]). MANDIR needs to point to
"catN" directory, without "N":
MANDIR= /usr/local/v6/man/cat
MAN= foo.5 baz.8
MLINKS= foo.5 bar.5
NOPIC= yes # if you do not want shlib, define it
For FreeBSD, you need to set MAN[0-9] like below. MANDIR needs to point
to "manN" directory, without "N":
MANDIR= /usr/local/v6/man/man
MAN5= foo.5
MAN8= baz.8
MLINKS= foo.5 bar.5
# if you do not want shlib, do not define SHLIB_{MAJOR,MINOR}
- If you use yacc/lex, be aware that FreeBSD bsd.prog.mk behaves very
strange with yacc's -o option (non-trivial .if statement is placed).
You may need to add the following into Makefile for code sharing.
The following fragment will force the build to generate y.tab.h, instead
of foo.h.
SRCS+=y.tab.h
y.tab.h: foo.y
Be sure to include y.tab.h, not foo.h, from *.l.
- BSDI3 /usr/bin/cc is gcc 1.42, and it does not support __FUNCTION__.
If you need to use __FUNCTION__, you need to set CC to "gcc", or "shlicc2"
explicitly.
__FUNCTION__ macro is not included in the ANSI standard, so it is best to
avoid __FUNCTION__, or make it optional, for portability.
- sys/queue.h are very different in each of *BSDs. Most of macros found in
FreeBSD3 are not available in other systems. Simply avoid those, make sure
your code compile on non-FreeBSD3 systems.
Avoid xx_FOREACH(), which is only available in FreeBSD3. Just use
for (x = xx_FIRST(); x; x = xx_NEXT(x))
and do not try to make #if section for FreeBSD3. More #if introduces
more bugs.
- It is better to avoid insque() and rmque(), they are from old VAX days
and some platform now tries to avoid these.
- To identify FreeBSD3, use the following:
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
this is freebsd3.
#endif
- To identify BSDI4, use the following:
#if defined(__bsdi__) && _BSDI_VERSION >= 199802
this is bsdi4.
#endif
- RFC2553 defines sockaddr_storage to have __ss_{family,len} member. During
the discusson for the draft on ipngwg, ss_len was proposed and final result
was not very clear. Therefore, you can see both definition on operating
system platforms. The most portable way of dealing with it is to:
(1) have -Dss_len=__ss_len to unify all occurences (including header file)
into __ss_len, or (2) never touch __ss_len. cast to sockaddr * and use
sa_len.
- Never, never touch the __u6_addr{,8,16,32} member in struct in6_addr
directly. Symbols starting with "__" are NOT supposed to be used.
- RFC2553 defines only s6_addr[16] (array of u_int8_t) as member of struct
in6_addr. KAME strictly follows RFC2553, and does not provide any
extensions like s6_addr{8,16,32} to the userland. For maximum portability
across IPv6 platforms, only s6_addr should be used.
In the future, we may provide s6_addr{8,16,32} to the userland when updates
to RFC2553 defines them. They are, in fact, very convenient and we would
like to see them defined in standard document.
- sysctl(3) support in kernel.
FreeBSD: linker hack #define in sys/sysctl.h, like SYSCTL_INT().
no need to recompile sysctl(8).
SYSCTL_INT(_net_inet6_tcp6, TCP6CTL_SYN_CACHE_INTER,
syn_cache_interval, CTLFLAG_RW, &tcp6_syn_cache_interval, 0, "");
OpenBSD/NetBSD: xx_sysctl() needs to be supplied from inet6sw.
xx_sysctl() should implement switch statement to dispatch to all
possible leaf nodes available. symbols must be defined in header file
for use from sysctl(8).
BSDI: similar to OpenBSD/NetBSD, but sysctl_int_arr() makes xx_sysctl()
code much easier for simple integer leaf nodes.
- Developers are advised to use pedantic compilation options (like -Wall
-Werror). To configure default make settings, /etc/make.conf (freebsd),
/etc/mk.conf (netbsd/openbsd), and/or /usr/share/mk/sys.mk (bsdi) should be
useful. Note, however, that the default compiler of bsdi3 (/usr/ucb/cc)
does not suppport the -Werror option.
Note that the meaning of -Wall is different across *BSD because *BSD uses
different version of gnu cc. Sometimes -Wall raises bogus warning due to
bugs in code generator. Also, since function prototypes are defined
differently in some cases (like ntohl), certain tweaks are needed to
eliminate warnings on all the platforms. Don't worry about it too much,
you can always talk with other developers.
- For portability in kernel networking code, look at kame/sys/net/net_osdep.h.