github.com/gotranspile/cxgo@v0.3.7/examples/README.md (about) 1 # Examples 2 3 - [Converting a single main file](#converting-a-single-main-file) 4 - [Converting a pair of library files (.c and .h)](#converting-a-pair-of-library-files) 5 - [Using a config for larger projects](#using-a-config-file) 6 - [Real-world examples](#real-world-examples) 7 - [Potrace](potrace/README.md) 8 9 ## Converting a single main file 10 11 The simplest possible use case for `cxgo` is to convert a single file. For example, create a file named `main.c`: 12 13 ```c 14 #include <stdio.h> 15 16 void main() { 17 printf("Hello world!\n"); 18 } 19 ``` 20 21 Then convert it to Go with: 22 23 ```bash 24 cxgo file main.c 25 ``` 26 27 It should generate a file `main.go` with content similar to this: 28 29 ```go 30 package main 31 32 import "github.com/gotranspile/cxgo/runtime/stdio" 33 34 func main() { 35 stdio.Printf("Hello world!\n") 36 } 37 ``` 38 39 This single-file mode is useful when testing `cxgo` behavior in comparison with `gcc` and other compilers. 40 41 Note that the file imports `github.com/gotranspile/cxgo/runtime` - this is the C standard library that `cxgo` uses. 42 Although we try to use Go stdlib as much as possible, in some cases it's still necessary to use wrappers to preserve 43 different C semantics. 44 45 The same is true for `stdio.Printf`, as opposed to `fmt.Printf` - C version will accept zero-terminated strings, while 46 native Go version doesn't. 47 48 Also, have you noted that you were not asked to provide a path for a `stdio.h` include (`-I` in `gcc`)? 49 This is because `cxgo` bundles most of the stdlib headers and automatically uses them when needed. 50 51 ## Converting a pair of library files 52 53 Converting a library is similar to converting a main file. For example, given a header `lib.h`: 54 55 ```c 56 #ifndef MYLIB_H 57 #define MYLIB_H 58 59 enum MyEnum { 60 ENUM_ONE, 61 ENUM_TWO 62 }; 63 64 typedef struct { 65 int* ptr; 66 MyEnum val; 67 } my_struct; 68 69 my_struct* new_struct(int v); 70 71 void free_struct(my_struct* p); 72 73 #endif // MYLIB_H 74 ``` 75 76 And a library file `lib.c`: 77 78 ```c 79 #include <stdlib.h> 80 #include "lib.h" 81 82 my_struct* new_struct(int v) { 83 my_struct* p = malloc(sizeof(my_struct)); 84 p->ptr = 0; 85 p->val = v; 86 return p; 87 } 88 89 void free_struct(my_struct* p) { 90 free(p); 91 } 92 ``` 93 94 It can then be converted with: 95 96 ``` 97 cxgo file --pkg mylib lib.c 98 ``` 99 100 Note that you need to specify the `lib.c` file, not `lib.h`. cxgo will use the header automatically. 101 102 The process should generating an output file `lib.go` similar to this: 103 104 ```go 105 package mylib 106 107 type MyEnum int 108 109 const ( 110 ENUM_ONE = MyEnum(iota) 111 ENUM_TWO 112 ) 113 114 type my_struct struct { 115 Ptr *int 116 Val MyEnum 117 } 118 119 func new_struct(v int) *my_struct { 120 var p *my_struct = new(my_struct) 121 p.Ptr = nil 122 p.Val = MyEnum(v) 123 return p 124 } 125 func free_struct(p *my_struct) { 126 p = nil 127 } 128 ``` 129 130 This mode is useful when generating types, constants and functions from a self-contained C libraries. 131 The downside is that it gives no control regarding variable/function names, Go types used, etc. 132 For more control, see [this example](#using-a-config-file). 133 134 Note that the Go code has no references to `github.com/gotranspile/cxgo/runtime` this time, although the original C code 135 did use the `stdlib.h`. cxgo recognizes some common patterns like struct and array allocation and automatically replaces 136 them with Go equivalents. 137 138 Also, note that there are no calls to `free` in the Go version. Go has GC, so it's usually safe to just set the 139 corresponding variable to `nil`. But, as in this case, `free_struct` will only set its own argument to `nil`, 140 instead of setting the caller's variable. This may cause the memory to be kept longer than in the C version. 141 142 ## Using a config file 143 144 `cxgo` also offers a [config file](../docs/config.md) that can help to customize the translation process. 145 146 We can use our previous example (`lib.c` and `lib.h`) and write a `cxgo.yml` config file for it: 147 148 ```yaml 149 # Specifies the root path for C files 150 root: ./ 151 # Specifies the output path for Go files 152 out: ./ 153 # Package name for Go files 154 package: mylib 155 156 # Replace C int with Go int (the default is to use int32/int64) 157 use_go_int: true 158 159 # Allows to control identifier (type/variable/function) names and types 160 idents: 161 - name: my_struct 162 rename: MyStruct 163 164 # List of files to convert. Supports wildcards (*.c). 165 files: 166 - name: lib.c 167 # Allows to skip generating declarations by name 168 skip: 169 - free_struct 170 # The same as a top level 'idents', but only affects a specific file 171 idents: 172 - name: new_struct 173 rename: NewStruct 174 # Allows to replace code in the output Go file (in case cxgo is not smart enough) 175 replace: 176 # simplify declaration, just for an example 177 - old: 'var p *MyStruct =' 178 new: 'p :=' 179 ``` 180 181 You can now generate the Go files with: 182 183 ``` 184 cxgo 185 ``` 186 187 It should create a file `lib.go` as well as `go.mod`. The `lib.go` will now look like this: 188 189 ``` 190 package mylib 191 192 type MyEnum int 193 194 const ( 195 ENUM_ONE = MyEnum(iota) 196 ENUM_TWO 197 ) 198 199 type MyStruct struct { 200 Ptr *int 201 Val MyEnum 202 } 203 204 func NewStruct(v int) *MyStruct { 205 p := new(MyStruct) 206 p.Ptr = nil 207 p.Val = MyEnum(v) 208 return p 209 } 210 ``` 211 212 Note that names are different now, `free_struct` is now gone and the declaration in `NewStruct` is more idiomatic. 213 Let's break down the config file to explain those changes. 214 215 ```yaml 216 # Specifies the root path for C files 217 root: ./ 218 # Specifies the output path for Go files 219 out: ./ 220 # Package name for Go files 221 package: mylib 222 ``` 223 224 The first part is pretty self-explanatory: it sets the input, output paths and the Go package name. 225 226 ```yaml 227 # Replace C int with Go int (the default is to use int32/int64) 228 use_go_int: true 229 ``` 230 231 This option controls how C int types are interpreted. In this case we don't really care about int size, so we can 232 replace all C `int` types with Go `int` types, which is platform-dependant. Sometimes it may be important to keep 233 the original int size. In that case you can omit `use_go_int` and set `int_size` and `ptr_size` manually. 234 235 ```yaml 236 # Allows to control identifier (type/variable/function) names and types 237 idents: 238 - name: my_struct 239 rename: MyStruct 240 ``` 241 242 This section controls different aspects of the type and name conversion. As in the example, you can rename identifiers 243 however you like. It's also possible to [alias](../docs/config.md#identsalias) the type, [promote it](../docs/config.md#identstype) to Go bool or slice. 244 245 ```yaml 246 # List of files to convert. Supports wildcards (*.c). 247 files: 248 - name: lib.c 249 ``` 250 251 This section control which [files](../docs/config.md#files) are converted. Since C compilers operate on a "translation unit" 252 (a single C file with all included files inlined), `cxgo` does the same and allows to selectively translate individual files. 253 It will only translate declarations found in the specified file (or corresponding header). To convert other included files, 254 you need to explicitly add them here. You can also use a regex to convert all C files. 255 256 ```yaml 257 # Allows to skip generating declarations by name 258 skip: 259 - free_struct 260 ``` 261 262 This section controls which declarations are [skipped](../docs/config.md#skip) when generating a specific Go file. 263 You may decide that you don't need certain C functions or type declarations, for example. You may also plan to use 264 manually written Go functions to replace generated ones, and [`skip`](../docs/config.md#skip) might help you avoid the needless declaration. 265 266 ```yaml 267 # The same as a top level 'idents', but only affects a specific file 268 idents: 269 - name: new_struct 270 rename: NewStruct 271 ``` 272 273 There may be cases when two C files declare conflicting functions withs the same name. You can solve this by using 274 per-file [`idents`](../docs/config.md#filesidents) section and rename those problematic identifiers and avoid the name conflict. 275 276 277 ```yaml 278 # Allows to replace code in the output Go file (in case cxgo is not smart enough) 279 replace: 280 # simplify declaration, just for an example 281 - old: 'var p *MyStruct =' 282 new: 'p :=' 283 ``` 284 285 `cxgo` tries to be smart, but sometimes it may fail to generate a good Go code. In this case you may decide to override 286 some parts of it. [`replace`](../docs/config.md#replace) offers a simple find-and-replace mechanism that works as a post-processing 287 step on the output file. As in the example, we replace `var p *MyStruct =` with a more idiomatic `p :=`. Note that the type of 288 variable is written as `NewStruct` - the replacement is run after all other conversions are applied. You may also use 289 `regexp` key instead of `old` to use regular expressions instead of an exact match. 290 291 ## Real-world examples 292 293 Short examples might be good to understand the basics, but there might be a lot of different edge-cases in the wild. 294 295 To make your journey easier, we provide a set of examples that convert real-world C projects to Go. 296 297 - [Potrace](http://potrace.sourceforge.net/) is a vectorization tool written by Peter Selinger. 298 You can convert it to a Go library using [our example](./potrace/README.md).