@@ -19,23 +19,13 @@ func generateGo(src *mkcgo.Source, w io.Writer) {
19
19
// This block outputs C header includes and forward declarations for loader functions.
20
20
fmt .Fprintf (w , "/*\n " )
21
21
fmt .Fprintf (w , "#cgo CFLAGS: -Wno-attributes\n \n " )
22
- if * includeHeader != "" {
23
- fmt .Fprintf (w , "#include \" %s\" \n " , * includeHeader )
24
- }
25
22
for _ , file := range src .Files {
26
23
fmt .Fprintf (w , "#include %q\n " , file )
27
24
}
28
- fmt .Fprintf (w , "\n " )
29
- for _ , tag := range src .Tags () {
30
- fmt .Fprintf (w , "void __mkcgoLoad_%s(void* handle);\n " , tag )
31
- fmt .Fprintf (w , "void __mkcgoUnload_%s();\n " , tag )
32
- }
33
- fmt .Fprintf (w , "\n " )
34
- for _ , fn := range src .Funcs {
35
- if fn .Optional {
36
- fmt .Fprintf (w , "int %s_Available();\n " , fn .ImportName )
37
- }
25
+ if * includeHeader != "" {
26
+ fmt .Fprintf (w , "#include \" %s\" \n " , * includeHeader )
38
27
}
28
+ fmt .Fprintf (w , "#include \" %s\" \n " , autogeneratedFileName (".h" ))
39
29
fmt .Fprintf (w , "*/\n " )
40
30
fmt .Fprintf (w , "import \" C\" \n " )
41
31
fmt .Fprintf (w , "import \" unsafe\" \n \n " )
@@ -56,10 +46,14 @@ func generateGo(src *mkcgo.Source, w io.Writer) {
56
46
fmt .Fprintf (w , "}\n \n " )
57
47
}
58
48
59
- typedefs := make (map [string ]string , len (src .TypeDefs ))
60
- for _ , def := range src .TypeDefs {
61
- typedefs [def .Name ] = def .Type
62
- }
49
+ // Generate error wrapper noescape function, which hides the
50
+ // error state pointer from the Go garbage collector.
51
+ // An instance of https://github.com/golang/go/blob/d704ef76068eb7da15520b08dc7df98f45f85ffa/src/runtime/stubs.go#L194-L201
52
+ fmt .Fprintf (w , "//go:nosplit\n " )
53
+ fmt .Fprintf (w , "func %s(p *C.%s) *C.%s {\n " , mkcgoNoEscape , mkcgoErrState , mkcgoErrState )
54
+ fmt .Fprintf (w , "\t x := uintptr(unsafe.Pointer(p))\n " )
55
+ fmt .Fprintf (w , "\t return (*C.%s)(unsafe.Pointer(x ^ 0))\n " , mkcgoErrState )
56
+ fmt .Fprintf (w , "}\n \n " )
63
57
64
58
// Generate function wrappers.
65
59
for _ , fn := range src .Funcs {
@@ -73,7 +67,7 @@ func generateGo(src *mkcgo.Source, w io.Writer) {
73
67
fmt .Fprintf (w , "\t return C.%s_Available() != 0\n " , fn .ImportName )
74
68
fmt .Fprintf (w , "}\n \n " )
75
69
}
76
- generateGoFn (typedefs , fn , w )
70
+ generateGoFn (fn , w )
77
71
}
78
72
}
79
73
@@ -87,11 +81,15 @@ func generateGo124(src *mkcgo.Source, w io.Writer) {
87
81
// This block outputs C header includes and forward declarations for loader functions.
88
82
fmt .Fprintf (w , "/*\n " )
89
83
for _ , fn := range src .Funcs {
84
+ name := fn .CName
85
+ if fnNeedErrWrapper (fn ) {
86
+ name = fnCErrWrapperName (fn )
87
+ }
90
88
if fn .NoEscape {
91
- fmt .Fprintf (w , "#cgo noescape %s\n " , fn . CName )
89
+ fmt .Fprintf (w , "#cgo noescape %s\n " , name )
92
90
}
93
91
if fn .NoCallback {
94
- fmt .Fprintf (w , "#cgo nocallback %s\n " , fn . CName )
92
+ fmt .Fprintf (w , "#cgo nocallback %s\n " , name )
95
93
}
96
94
}
97
95
fmt .Fprintf (w , "*/\n " )
@@ -148,20 +146,71 @@ func generateGoAliases(funcs []*mkcgo.Func, w io.Writer) {
148
146
}
149
147
}
150
148
151
- // generateC creates the C source file content.
152
- func generateC (src * mkcgo.Source , w io.Writer ) {
149
+ // generateCHeader generates C header file content with
150
+ // the C functions defined in the autogenerated C source file.
151
+ func generateCHeader (src * mkcgo.Source , w io.Writer ) {
153
152
// Header and includes.
154
153
fmt .Fprintf (w , "// Code generated by mkcgo. DO NOT EDIT.\n \n " )
154
+
155
+ fmt .Fprintf (w , "#ifndef MKCGO_H // only include this header once\n " )
156
+ fmt .Fprintf (w , "#define MKCGO_H\n \n " )
157
+
158
+ for _ , file := range src .Files {
159
+ fmt .Fprintf (w , "#include %q\n " , file )
160
+ }
155
161
if * includeHeader != "" {
156
162
fmt .Fprintf (w , "#include \" %s\" \n " , * includeHeader )
157
163
}
158
- for _ , file := range src .Files {
159
- fmt .Fprintf (w , "#include %q\n " , file )
164
+ fmt .Fprintf (w , "\n " )
165
+
166
+ // Custom types
167
+ fmt .Fprintf (w , "typedef void* %s;\n " , mkcgoErrState )
168
+ fmt .Fprintf (w , "%s mkcgo_err_retrieve();\n " , mkcgoErrState )
169
+ fmt .Fprintf (w , "void mkcgo_err_free(%s);\n " , mkcgoErrState )
170
+ fmt .Fprintf (w , "void mkcgo_err_clear();\n \n " )
171
+
172
+ // Add forward declarations for loader functions.
173
+ for _ , tag := range src .Tags () {
174
+ fmt .Fprintf (w , "void __mkcgoLoad_%s(void* handle);\n " , tag )
175
+ fmt .Fprintf (w , "void __mkcgoUnload_%s();\n " , tag )
176
+ }
177
+ fmt .Fprintf (w , "\n " )
178
+
179
+ // Add forward declarations for optional functions.
180
+ for _ , fn := range src .Funcs {
181
+ if fn .Optional {
182
+ fmt .Fprintf (w , "int %s_Available();\n " , fn .ImportName )
183
+ }
184
+ }
185
+ fmt .Fprintf (w , "\n " )
186
+
187
+ // Add forward declarations for function wrappers returning errors.
188
+ for _ , fn := range src .Funcs {
189
+ if ! fnNeedErrWrapper (fn ) {
190
+ continue
191
+ }
192
+ fmt .Fprintf (w , "%s %s(%s);\n " , fn .Ret .Type , fnCErrWrapperName (fn ), fnCErrWrapperParams (fn , false ))
160
193
}
194
+ fmt .Fprintf (w , "\n " )
195
+ fmt .Fprintf (w , "#endif // MKCGO_H\n " )
196
+ }
197
+
198
+ // generateC creates the C source file content.
199
+ func generateC (src * mkcgo.Source , w io.Writer ) {
200
+ // Header and includes.
201
+ fmt .Fprintf (w , "// Code generated by mkcgo. DO NOT EDIT.\n \n " )
202
+
161
203
fmt .Fprintf (w , "#include <stddef.h>\n " )
162
204
fmt .Fprintf (w , "#include <stdlib.h>\n " )
163
205
fmt .Fprintf (w , "#include <stdint.h>\n " )
164
206
fmt .Fprintf (w , "#include <stdio.h>\n " )
207
+ for _ , file := range src .Files {
208
+ fmt .Fprintf (w , "#include %q\n " , file )
209
+ }
210
+ if * includeHeader != "" {
211
+ fmt .Fprintf (w , "#include \" %s\" \n " , * includeHeader )
212
+ }
213
+ fmt .Fprintf (w , "#include \" %s\" \n " , autogeneratedFileName (".h" ))
165
214
fmt .Fprintf (w , "\n " )
166
215
167
216
// Platform-specific includes.
@@ -238,6 +287,10 @@ func generateC(src *mkcgo.Source, w io.Writer) {
238
287
}
239
288
240
289
// Generate C function wrappers.
290
+ typedefs := make (map [string ]string , len (src .TypeDefs ))
291
+ for _ , def := range src .TypeDefs {
292
+ typedefs [def .Name ] = def .Type
293
+ }
241
294
for _ , fn := range src .Funcs {
242
295
if fn .Variadic () {
243
296
// cgo doesn't support variadic functions
@@ -250,11 +303,12 @@ func generateC(src *mkcgo.Source, w io.Writer) {
250
303
fmt .Fprintf (w , "}\n \n " )
251
304
}
252
305
generateCFn (fn , w )
306
+ generateCFnErrorWrapper (typedefs , fn , w )
253
307
}
254
308
}
255
309
256
310
// generateGoFn generates Go function f.
257
- func generateGoFn (typedefs map [ string ] string , fn * mkcgo.Func , w io.Writer ) {
311
+ func generateGoFn (fn * mkcgo.Func , w io.Writer ) {
258
312
fnCall := fmt .Sprintf ("C.%s(%s)" , fn .CName , fnToGoArgs (fn ))
259
313
// Function definition
260
314
fmt .Fprintf (w , "func %s(%s)" , fn .GoName , fnToGoParams (fn ))
@@ -296,21 +350,13 @@ func generateGoFn(typedefs map[string]string, fn *mkcgo.Func, w io.Writer) {
296
350
fmt .Fprintf (w , "}\n \n " )
297
351
return
298
352
}
299
- fmt .Fprintf (w , "\t _ret := C.%s(%s)\n " , fn .CName , fnToGoArgs (fn ))
300
-
301
- // Error handling
302
- errCond := "<= 0"
303
- if fn .ErrCond != "" {
304
- errCond = fn .ErrCond
305
- } else if strings .Contains (goType , "unsafe.Pointer" ) {
306
- errCond = "== nil"
307
- } else if typ , ok := typedefs [goType ]; ok && typ == "void*" {
308
- errCond = "== nil"
353
+ fmt .Fprintf (w , "\t var _err C.%s\n " , mkcgoErrState )
354
+ fmt .Fprintf (w , "\t _ret := C.%s(" , fnCErrWrapperName (fn ))
355
+ args := fnToGoArgs (fn )
356
+ if len (args ) > 0 {
357
+ args += ", "
309
358
}
310
- fmt .Fprintf (w , "\t var _err error\n " )
311
- fmt .Fprintf (w , "\t if _ret %s {\n " , errCond )
312
- fmt .Fprintf (w , "\t \t _err = newOpenSSLError(\" %s\" )\n " , fn .CName )
313
- fmt .Fprintf (w , "\t }\n " )
359
+ fmt .Fprintf (w , "%s%s(&_err))\n " , args , mkcgoNoEscape )
314
360
315
361
// Return the value
316
362
fmt .Fprintf (w , "\t return " )
@@ -322,16 +368,38 @@ func generateGoFn(typedefs map[string]string, fn *mkcgo.Func, w io.Writer) {
322
368
} else {
323
369
fmt .Fprintf (w , "_ret" )
324
370
}
325
- fmt .Fprintf (w , ", _err\n " )
371
+ fmt .Fprintf (w , ", newMkcgoErr(%q, _err) \n " , fn . CName )
326
372
fmt .Fprintf (w , "}\n \n " )
327
373
}
328
374
329
375
func generateCFn (fn * mkcgo.Func , w io.Writer ) {
330
- fmt .Fprintf (w , "%s %s(%s) {\n \t " , fn .Ret .Type , fn .CName , fnToCArgs (fn , true ))
376
+ fmt .Fprintf (w , "%s %s(%s) {\n \t " , fn .Ret .Type , fn .CName , fnToCArgs (fn , true , true ))
331
377
if ! retIsVoid (fn .Ret ) {
332
378
fmt .Fprintf (w , "return " )
333
379
}
334
- fmt .Fprintf (w , "_g_%s(%s);\n " , fn .ImportName , fnToCArgs (fn , false ))
380
+ fmt .Fprintf (w , "_g_%s(%s);\n " , fn .ImportName , fnToCArgs (fn , false , true ))
381
+ fmt .Fprintf (w , "}\n \n " )
382
+ }
383
+
384
+ // generateCFnErrorWrapper generates C function wrapper for function f
385
+ // that returns an error state.
386
+ func generateCFnErrorWrapper (typedefs map [string ]string , fn * mkcgo.Func , w io.Writer ) {
387
+ if ! fnNeedErrWrapper (fn ) {
388
+ return
389
+ }
390
+ fmt .Fprintf (w , "%s %s(%s) {\n " , fn .Ret .Type , fnCErrWrapperName (fn ), fnCErrWrapperParams (fn , true ))
391
+ fmt .Fprintf (w , "\t mkcgo_err_clear();\n " ) // clear any previous error
392
+ fmt .Fprintf (w , "\t %s _ret = _g_%s(%s);\n " , fn .Ret .Type , fn .ImportName , fnToCArgs (fn , false , true ))
393
+ errCond := "<= 0"
394
+ if fn .ErrCond != "" {
395
+ errCond = fn .ErrCond
396
+ } else if strings .Contains (fn .Ret .Type , "*" ) {
397
+ errCond = "== NULL"
398
+ } else if typ , ok := typedefs [fn .Ret .Type ]; ok && typ == "void*" {
399
+ errCond = "== NULL"
400
+ }
401
+ fmt .Fprintf (w , "\t if (_ret %s) *_err_state = mkcgo_err_retrieve();\n " , errCond )
402
+ fmt .Fprintf (w , "\t return _ret;\n " )
335
403
fmt .Fprintf (w , "}\n \n " )
336
404
}
337
405
@@ -436,12 +504,15 @@ func cTypeToGo(t string, cgo bool) (string, bool) {
436
504
}
437
505
438
506
// paramToC returns C source code of parameter p.
439
- func paramToC (i int , p * mkcgo.Param , addType bool ) string {
507
+ func paramToC (i int , p * mkcgo.Param , addType , addName bool ) string {
508
+ if p .Type == "..." {
509
+ return ""
510
+ }
440
511
var s string
441
512
if addType {
442
513
s += p .Type
443
514
}
444
- if p . Type != "void" && p .Type != "... " {
515
+ if addName && p .Type != "void " {
445
516
if len (s ) > 0 {
446
517
s += " "
447
518
}
@@ -470,9 +541,9 @@ func fnToGoArgs(fn *mkcgo.Func) string {
470
541
}
471
542
472
543
// fnToCArgs returns source code for C parameters for function f.
473
- func fnToCArgs (fn * mkcgo.Func , addType bool ) string {
544
+ func fnToCArgs (fn * mkcgo.Func , addType , addName bool ) string {
474
545
return join (fn .Params , func (i int , p * mkcgo.Param ) string {
475
- return paramToC (i , p , addType )
546
+ return paramToC (i , p , addType , addName )
476
547
}, ", " )
477
548
}
478
549
@@ -492,3 +563,34 @@ func join(ps []*mkcgo.Param, fn func(int, *mkcgo.Param) string, sep string) stri
492
563
}
493
564
return strings .Join (params , sep )
494
565
}
566
+
567
+ const mkcgoNoEscape = "mkcgoNoEscape"
568
+ const mkcgoErrState = "mkcgo_err_state"
569
+
570
+ // fnCErrWrapperParams returns source code for C parameters for function f
571
+ // with the error state added as the last parameter.
572
+ func fnCErrWrapperParams (fn * mkcgo.Func , addName bool ) string {
573
+ errArg := mkcgoErrState + " *"
574
+ if addName {
575
+ errArg += "_err_state"
576
+ }
577
+ args := fnToCArgs (fn , true , addName )
578
+ if len (args ) == 0 {
579
+ args = errArg
580
+ } else if args == "void" {
581
+ args = errArg
582
+ } else {
583
+ args += ", " + errArg
584
+ }
585
+ return args
586
+ }
587
+
588
+ // fnCErrWrapperName returns the name of the error wrapper function for function f.
589
+ func fnCErrWrapperName (fn * mkcgo.Func ) string {
590
+ return "_mkcgo_err_" + fn .CName
591
+ }
592
+
593
+ // fnNeedErrWrapper reports whether function fn needs an error wrapper.
594
+ func fnNeedErrWrapper (fn * mkcgo.Func ) bool {
595
+ return ! fn .NoError && ! retIsVoid (fn .Ret )
596
+ }
0 commit comments