58b20109cf
import sys import yaml with open(sys.argv[1]) as fp: data = fp.read() if not data.find("---") == 0: # no head print("NO YAML HEAD FOUND") sys.exit(-1) data = data[3:] head_end = data.find("---") head = data[0:head_end] data = data[head_end+3:] metadata = yaml.safe_load(head) cats = metadata.pop('categories', None) if cats != None: if type(cats) == list: tags = cats elif type(cats) == str: tags = cats.split() tags = list(map(lambda t: t.lower(), tags)) metadata["tags"] = ", ".join(tags) new_data = f"---\n{yaml.dump(metadata, default_flow_style=False)}---{data}" # write it print(f"coverted: categories to tags: {tags} - {sys.argv[1]}") with open(sys.argv[1], "w") as fp: fp.write(new_data) sys.exit(0) if not metadata.get("tags", None): metadata["tags"] = "untagged" new_data = f"---\n{yaml.dump(metadata, default_flow_style=False)}---{data}" print(f"untagged: {sys.argv[1]}") # write it with open(sys.argv[1], "w") as fp: fp.write(new_data) sys.exit(0) print("No changes needed")
129 lines
3.2 KiB
Markdown
129 lines
3.2 KiB
Markdown
---
|
||
comments: true
|
||
date: 2015-03-29 00:28
|
||
layout: post
|
||
tags: golang, c
|
||
title: Notes on cgo
|
||
---
|
||
|
||
## Referencing c from go.
|
||
|
||
### Basic operation
|
||
|
||
import "C" imports the C namespace into go, the comment just above this statement is treated as C.
|
||
|
||
```c
|
||
/*
|
||
#include "add.h"
|
||
*/
|
||
import "C"
|
||
```
|
||
Everything you exported from c library is available in the C namespace.
|
||
|
||
```go
|
||
func main() {
|
||
fmt.Println(
|
||
C.add_two_numbers(3,4)
|
||
)
|
||
}
|
||
```
|
||
|
||
Building code is as easy as `go build`
|
||
|
||
Accessing standard types are easy as `C.char`, `C.int`. For complex types, prepend the type name with an underscore at end – e.g `C.struct_stat`.
|
||
|
||
### Pointers and memory operations
|
||
|
||
Go provides an `unsafe` module. Go’s GC cannot manage the memory allocated in C code, you should call `C.free(unsafe.Pointer)` (`free` is defined in `<stdlib.h>` ensure that this library is imported) to deallocate.
|
||
There are some special functions which convert Go types to C types and vice versa. (lifted from cgo documentation)
|
||
```go
|
||
// Go string to C string
|
||
// The C string is allocated in the C heap using malloc.
|
||
// It is the caller's responsibility to arrange for it to be
|
||
// freed, such as by calling C.free (be sure to include stdlib.h
|
||
// if C.free is needed).
|
||
func C.CString(string) *C.char
|
||
|
||
// C string to Go string
|
||
func C.GoString(*C.char) string
|
||
|
||
// C string, length to Go string
|
||
func C.GoStringN(*C.char, C.int) string
|
||
|
||
// C pointer, length to Go []byte
|
||
func C.GoBytes(unsafe.Pointer, C.int) []byte
|
||
```
|
||
|
||
### Accessing complex objects
|
||
|
||
Accessing structs from Go
|
||
```go
|
||
/*
|
||
struct person {
|
||
int age;
|
||
*/
|
||
// this can be used in go as
|
||
var p C.struct_person
|
||
p.age = 23
|
||
```
|
||
|
||
You can also pass pointers
|
||
|
||
```go
|
||
C.function_accepts_ptr_to_struct(&p)
|
||
```
|
||
|
||
Accessing Unions : No native counterpart, instead of converting it to a type, go treats them as a block of memory represented as byte array. Accessing data is done by casting unsafe.Pointer
|
||
|
||
```go
|
||
/*
|
||
union quant {
|
||
float weight;
|
||
int count;
|
||
};
|
||
*/
|
||
|
||
var q C.union_quant
|
||
ptr := (*float32)(unsafe.Pointer(&q))
|
||
*ptr = 3.14
|
||
```
|
||
|
||
## Extra goodies
|
||
|
||
### Compiler Flags
|
||
Compiler flags can be set using the `#cgo` directive. (`CFLAGS`, `LDFLAGS` etc)
|
||
|
||
```go
|
||
/*
|
||
#cgo: LDFLAGS: -lmath
|
||
#include <math.h>
|
||
*/
|
||
import "C"
|
||
```
|
||
|
||
### Restricting building
|
||
In many cases using cgo breaks the portability of your app, use build constraints to specify compatibility in source. Build constraints are comments which begin with
|
||
|
||
```go
|
||
// +build
|
||
```
|
||
Now, build comment must appear before package clause and should be followed by a blank line To restrict building just to Linux with cgo,
|
||
|
||
```go
|
||
// +build linux,cgo !darwin
|
||
|
||
package main
|
||
```
|
||
|
||
These are evaluated as `OR` of each constraint so the above line becomes `(linux AND cgo) OR (NOT darwin)`, also multiple build tags can be embedded in file.
|
||
|
||
There are other methods to restrict builds, see references.
|
||
|
||
## Reference
|
||
|
||
- [Link to example code gist](https://gist.github.com/dbalan/ace29f0c43638ee4f81d)
|
||
- [cgo Talk by Rajesh Ramachandran (Gophercon India)](https://www.youtube.com/watch?v=oeEVtyypYPg)
|
||
- [Conditional compilation with go build](http://dave.cheney.net/2013/10/12/how-to-use-conditional-compilation-with-the-go-build-tool)
|
||
- [cgo compiler directives](http://golang.org/cmd/cgo/)
|
||
|