root/trunk/docsrc/htomodule.dd

Revision 2201, 8.3 kB (checked in by Don Clugston, 2 years ago)

Bug found by Jens Mueller -- const should not be removed when porting to D2.

  • Property svn:eol-style set to native
Line 
1 Ddoc
2
3 $(D_S Converting C $(TT .h) Files to D Modules,
4
5     While D cannot directly compile C source code, it can easily
6     interface to C code, be linked with C object files, and call
7     C functions in DLLs.
8     The interface to C code is normally found in C $(TT .h) files.
9     So, the trick to connecting with C code is in converting C
10     $(TT .h) files to D modules.
11     This turns out to be difficult to do mechanically since
12     inevitably some human judgement must be applied.
13     This is a guide to doing such conversions.
14
15 <h4>Preprocessor</h4>
16
17     $(TT .h) files can sometimes be a bewildering morass of layers of
18     macros, $(TT #include) files, $(TT #ifdef)'s, etc. D doesn't
19     include a text preprocessor like the C preprocessor,
20     so the first step is to remove the need for
21     it by taking the preprocessed output. For DMC (the Digital
22     Mars C/C++ compiler), the command:
23
24 $(CONSOLE
25 <a href="http://www.digitalmars.com/ctg/sc.html">dmc</a> <a href="http://www.digitalmars.com/ctg/sc.html#dashc">-c</a> program.h <a href="http://www.digitalmars.com/ctg/sc.html#dashe">-e</a> <a href="http://www.digitalmars.com/ctg/sc.html#dashl">-l</a>
26 )
27
28     will create a file $(TT program.lst) which is the source file after
29     all text preprocessing.
30     <p>
31
32     Remove all the $(TT #if), $(TT #ifdef), $(TT #include),
33     etc. statements.
34
35 <h4>Linkage</h4>
36
37     Generally, surround the entire module with:
38
39 ---------------------------
40 extern (C)
41 {
42      /* ...file contents... */
43 }
44 ---------------------------
45
46     to give it C linkage.
47
48 <h4>Types</h4>
49
50     A little global search and replace will take care of renaming
51     the C types to D types. The following table shows a typical mapping
52     for 32 bit C code:
53     <p>
54
55     $(TABLE1
56     <caption>Mapping C type to D type</caption>
57     <tr>
58     <th>C type
59     <th>D type
60     <tr>
61     <td>long double
62     <td>real
63     <tr>
64     <td>unsigned long long
65     <td>ulong
66     <tr>
67     <td>long long
68     <td>long
69     <tr>
70     <td>unsigned long
71     <td>uint
72     <tr>
73     <td>long
74     <td>int
75     <tr>
76     <td>unsigned
77     <td>uint
78     <tr>
79     <td>unsigned short
80     <td>ushort
81     <tr>
82     <td>signed char
83     <td>byte
84     <tr>
85     <td>unsigned char
86     <td>ubyte
87     <tr>
88     <td>wchar_t
89     <td>wchar or dchar
90     <tr>
91     <td>bool
92     <td>bool, byte, int
93     <tr>
94     <td>size_t
95     <td>size_t
96     <tr>
97     <td>ptrdiff_t
98     <td>ptrdiff_t
99     )
100
101 <h4>NULL</h4>
102
103     $(TT NULL) and $(TT ((void*)0)) should be replaced
104     with $(TT null).
105
106 <h4>Numeric Literals</h4>
107
108     Any $(SINGLEQUOTE L) or $(SINGLEQUOTE l) numeric literal suffixes should be removed,
109     as a C $(TT long) is (usually) the same size as a D $(TT int).
110     Similarly, $(SINGLEQUOTE LL) suffixes should be replaced with a
111     single $(SINGLEQUOTE L).
112     Any $(SINGLEQUOTE u) suffix will work the same in D.
113
114 <h4>String Literals</h4>
115
116     In most cases, any $(SINGLEQUOTE L) prefix to a string can just be dropped,
117     as D will implicitly convert strings to wide characters if
118     necessary. However, one can also replace:
119
120 $(CCODE
121 L"string"
122 )
123
124     with:
125
126 ---------------------------
127 "string"w   // for 16 bit wide characters
128 "string"d   // for 32 bit wide characters
129 ---------------------------
130
131 <h4>Macros</h4>
132
133     Lists of macros like:
134
135 $(CCODE
136 #define FOO 1
137 #define BAR 2
138 #define ABC 3
139 #define DEF 40
140 )
141
142     can be replaced with:
143
144 ---------------------------
145 enum
146 {   FOO = 1,
147     BAR = 2,
148     ABC = 3,
149     DEF = 40
150 }
151 ---------------------------
152
153     or with:
154
155 ---------------------------
156 const int FOO = 1;
157 const int BAR = 2;
158 const int ABC = 3;
159 const int DEF = 40;
160 ---------------------------
161
162     Function style macros, such as:
163
164 $(CCODE
165 #define MAX(a,b) ((a) < (b) ? (b) : (a))
166 )
167
168     can be replaced with functions:
169
170 ---------------------------
171 int MAX(int a, int b) { return (a < b) ? b : a; }
172 ---------------------------
173
174     <!-- Thanks to Jarrett Billingsley for the following tip -->
175
176     The functions, however, won't work if they appear inside static
177     initializers that must be evaluated at compile time rather than
178     runtime. To do it at compile time, a template can be used:
179
180 $(CCODE
181 #define GT_DEPTH_SHIFT  (0)
182 #define GT_SIZE_SHIFT   (8)
183 #define GT_SCHEME_SHIFT (24)
184 #define GT_DEPTH_MASK   (0xffU << GT_DEPTH_SHIFT)
185 #define GT_TEXT         ((0x01) << GT_SCHEME_SHIFT)
186
187 /* Macro that constructs a graphtype */
188 #define GT_CONSTRUCT(depth,scheme,size) \
189     ((depth) | (scheme) | ((size) << GT_SIZE_SHIFT))
190
191 /* Common graphtypes */
192 #define GT_TEXT16  GT_CONSTRUCT(4, GT_TEXT, 16)
193 )
194
195     The corresponding D version would be:
196
197 ---------------------------
198 const uint GT_DEPTH_SHIFT  = 0;
199 const uint GT_SIZE_SHIFT   = 8;
200 const uint GT_SCHEME_SHIFT = 24;
201 const uint GT_DEPTH_MASK   = 0xffU << GT_DEPTH_SHIFT;
202 const uint GT_TEXT         = 0x01 << GT_SCHEME_SHIFT;
203
204 // Template that constructs a graphtype
205 template GT_CONSTRUCT(uint depth, uint scheme, uint size)
206 {
207  // notice the name of the const is the same as that of the template
208  const uint GT_CONSTRUCT = (depth | scheme | (size << GT_SIZE_SHIFT));
209 }
210
211 // Common graphtypes
212 const uint GT_TEXT16 = GT_CONSTRUCT!(4, GT_TEXT, 16);
213 ---------------------------
214
215
216 <h4>Declaration Lists</h4>
217
218     D doesn't allow declaration lists to change the type.
219     Hence:
220
221 $(CCODE
222 int *p, q, t[3], *s;
223 )
224
225     should be written as:
226
227 ---------------------------
228 int* p, s;
229 int q;
230 int[3] t;
231 ---------------------------
232
233 <h4>Void Parameter Lists</h4>
234
235     Functions that take no parameters:
236
237 $(CCODE
238 int foo(void);
239 )
240
241     are in D:
242
243 ---------------------------
244 int foo();
245 ---------------------------
246
247 $(V1
248
249 <h4>Const Type Modifiers</h4>
250
251     D has $(TT const) as a storage class, not a type modifier. Hence, just
252     drop any $(TT const) used as a type modifier:
253
254 $(CCODE
255 void foo(const int *p, char *const q);
256 )
257
258     becomes:
259
260 ---------------------------
261 void foo(int* p, char* q);
262 ---------------------------
263 )
264 <h4>Extern Global C Variables</h4>
265
266     Whenever a global variable is declared in D, it is also defined.
267     But if it's also defined by the C object file being linked in,
268     there will be a multiple definition error. To fix this problem,
269     use the extern storage class.
270     For example, given a C header file named
271     $(TT foo.h):
272
273 $(CCODE
274 struct Foo { };
275 struct Foo bar;
276 )
277
278     It can be replaced with the D modules, $(TT foo.d):
279
280 ---------------------------
281 struct Foo { }
282 extern (C)
283 {
284     extern Foo bar;
285 }
286 ---------------------------
287
288
289 <h4>Typedef</h4>
290
291     $(TT alias) is the D equivalent to the C $(TT typedef):
292
293 $(CCODE
294 typedef int foo;
295 )
296
297     becomes:
298
299 ---------------------------
300 alias int foo;
301 ---------------------------
302
303 <h4>Structs</h4>
304
305     Replace declarations like:
306
307 $(CCODE
308 typedef struct Foo
309 {   int a;
310     int b;
311 } Foo, *pFoo, *lpFoo;
312 )
313
314     with:
315
316 ---------------------------
317 struct Foo
318 {   int a;
319     int b;
320 }
321 alias Foo* pFoo, lpFoo;
322 ---------------------------
323
324 <h4>Struct Member Alignment</h4>
325
326     A good D implementation by default will align struct members the
327     same way as the C compiler it was designed to work with. But
328     if the $(TT .h) file has some $(TT #pragma)'s to control alignment, they
329     can be duplicated with the D $(TT align) attribute:
330
331 $(CCODE
332 #pragma pack(1)
333 struct Foo
334 {
335     int a;
336     int b;
337 };
338 #pragma pack()
339 )
340
341     becomes:
342
343 ---------------------------
344 struct Foo
345 {
346   align (1):
347     int a;
348     int b;
349 }
350 ---------------------------
351
352 <h4>Nested Structs</h4>
353
354 $(CCODE
355 struct Foo
356 {
357     int a;
358     struct Bar
359     {
360     int c;
361     } bar;
362 };
363
364 struct Abc
365 {
366     int a;
367     struct
368     {
369     int c;
370     } bar;
371 };
372 )
373
374     becomes:
375
376 ---------------------------
377 struct Foo
378 {
379     int a;
380     struct Bar
381     {
382     int c;
383     }
384     Bar bar;
385 }
386
387 struct Abc
388 {
389     int a;
390     struct
391     {
392     int c;
393     }
394 }
395 ---------------------------
396
397 <h4>$(TT __cdecl), $(TT __pascal), $(TT __stdcall)</h4>
398
399 $(CCODE
400 int __cdecl x;
401 int __cdecl foo(int a);
402 int __pascal bar(int b);
403 int __stdcall abc(int c);
404 )
405
406     becomes:
407
408 ---------------------------
409 extern (C) int x;
410 extern (C) int foo(int a);
411 extern (Pascal) int bar(int b);
412 extern (Windows) int abc(int c);
413 ---------------------------
414
415 <h4>$(TT __declspec(dllimport))</h4>
416
417 $(CCODE
418 __declspec(dllimport) int __stdcall foo(int a);
419 )
420
421     becomes:
422
423 ---------------------------
424 export extern (Windows) int foo(int a);
425 ---------------------------
426
427 <h4>$(TT __fastcall)</h4>
428
429     Unfortunately, D doesn't support the $(TT __fastcall) convention.
430     Therefore, a shim will be needed, either written in C:
431
432 $(CCODE
433 int __fastcall foo(int a);
434
435 int myfoo(int a)
436 {
437     return foo(int a);
438 }
439 )
440
441     and compiled with a C compiler that supports $(TT __fastcall) and
442     linked in, or compile the above, disassemble it with
443     <a href="http://www.digitalmars.com/ctg/obj2asm.html">obj2asm</a>
444     and insert it in a D $(TT myfoo) shim with
445     <a href="iasm.html">inline assembler</a>.
446
447 )
448
449 Macros:
450     TITLE=Converting C .h Files to D Modules
451     WIKI=HToModule
Note: See TracBrowser for help on using the browser.