 58b20109cf
			
		
	
	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/)
 | ||
| 
 |