Develop with Go
This guide shows you how to create and build Go applications using the TEN Framework's Go language binding.
This guide shows you how to create and build Go applications using the TEN Framework's Go language binding.
Create a TEN Go application
Create a new TEN application using Go with the following steps:
Generate the application
Use TEN Manager to create a new Go application from the default template:
Install dependencies
Install the required TEN packages and extensions:
Install a default TEN extension
To install a default Go TEN extension:
Configure auto-start graph
Configure your application to automatically start the installed extensions by adding a predefined graph to the property.json
file:
Build the application
TEN Go applications require CGO integration, which needs specific environment variables and build configuration. Use the build script provided in the TEN runtime to handle these requirements automatically:
The build process creates a compiled binary named main
in the bin/
directory.
Run the application
Use the provided start script to launch your application with the correct environment variables:
The start script automatically configures the necessary library paths and environment settings for the TEN runtime.
Debug your application
Set up debugging configurations for Visual Studio Code to debug both Go and C code in your TEN application.
Go code debugging
Add this configuration to your .vscode/launch.json
file to debug the Go portions of your application:
C code debugging
Add this configuration to your .vscode/launch.json
file to debug the C/CGO portions of your application:
CGO integration
Understand generated code
The TEN Framework's Go binding relies on CGO to interface between Go and C code. When you call C functions from Go, the cgo
tool automatically converts your Go source files into multiple output files containing both Go and C code. These generated C files are then compiled using standard C compilers like gcc
or clang
.
You can manually generate and examine these intermediate files using:
This creates several generated files that bridge Go and C:
The CGO generation process creates several key files that enable Go-C interoperability:
Key generated files
-
_cgo_export.h
: Enables C code to call Go functions
Contains declarations for Go functions exported with the//export
directive, plus C type definitions that correspond to Go types: -
_cgo_gotypes.go
: Contains Go representations of C types
When you use C types likeC.ten_go_error_t
in Go, this file provides the corresponding Go struct definitions: -
cmd.cgo1.go
: Go wrapper for C function calls
Replaces direct C function calls with CGO-generated wrappers that handle type conversion and memory management: -
cmd.cgo2.c
: C wrapper for the actual C function
Provides the bridge between Go's calling convention and the native C function:
Call sequence
When calling C.ten_go_cmd_create_cmd()
from Go, the execution follows this path:
Work with incomplete types
The cgo
tool generates corresponding Go types based on C header files imported via import "C"
. When a C struct is opaque (only declared, not defined), CGO creates an incomplete type in Go.
Example of an opaque C struct:
Generated incomplete type in Go:
Incomplete types have the following limitations:
-
Cannot be allocated directly
Go's garbage collector cannot manage incomplete types, so standard allocation fails: -
Cannot pass pointers directly to C
CGO rules require pointers to incomplete types to be "pinned" for garbage collector safety, making direct pointer passing impossible.
Workaround: Use C.uintptr_t
Instead of working with pointers to incomplete types, use C.uintptr_t
to represent C pointers as integers.
This approach has the following benefits:
- No allocation overhead:
uintptr
values can be passed directly between Go and C - GC-safe: No pointer tracking required since it's an integer value
- Direct conversion: Represents the exact memory address as an integer
Important limitations
- No pointer arithmetic:
uintptr
is just an integer representing an address - Cannot dereference: Converting to
unsafe.Pointer
can break GC assumptions - Use
0
for null: Sinceuintptr
is an integer, use0
instead ofnil
for null pointers