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).