Skip to content

Go Quick Start

Get a Go publisher and subscriber running in five minutes.

Prerequisites

  • Go 1.23+
  • An Eclipse Zenoh router — see Networking

No Rust toolchain required when using the pre-built library.

1. Get the library

Download the static library and C header for your platform from the Releases page:

Platform Jazzy / Kilted / Rolling Humble
Linux x86_64 libhiroz-jazzy-x86_64-unknown-linux-gnu.a libhiroz-humble-x86_64-unknown-linux-gnu.a
Linux aarch64 libhiroz-jazzy-aarch64-unknown-linux-gnu.a libhiroz-humble-aarch64-unknown-linux-gnu.a
macOS aarch64 libhiroz-jazzy-aarch64-apple-darwin.a libhiroz-humble-aarch64-apple-darwin.a

Each release also includes hiroz_ffi.h (the C header required for CGO).

# Clone the repo for the Go package source — no Rust build needed
git clone https://github.com/ZettaScaleLabs/hiroz.git
cd hiroz

# Download the pre-built library and header — replace <version> and pick your platform file
curl -Lo crates/hiroz-go/libhiroz.a \
  https://github.com/ZettaScaleLabs/hiroz/releases/download/<version>/libhiroz-jazzy-x86_64-unknown-linux-gnu.a
curl -Lo crates/hiroz-go/hiroz/hiroz_ffi.h \
  https://github.com/ZettaScaleLabs/hiroz/releases/download/<version>/hiroz_ffi.h

Option B — Build from source

Requires Rust 1.85+, cbindgen, and just:

git clone https://github.com/ZettaScaleLabs/hiroz.git
cd hiroz
just -f crates/hiroz-go/justfile quickstart

This generates message types, compiles libhiroz.a, and verifies both are present.

2. Write a publisher

Create hello_pub/main.go:

package main

import (
    "fmt"
    "log"
    "time"

    "github.com/ZettaScaleLabs/hiroz/crates/hiroz-go/hiroz"
    "github.com/ZettaScaleLabs/hiroz/crates/hiroz-go/generated/std_msgs"
)

func main() {
    ctx, err := hiroz.NewContext().WithDomainID(0).Build()
    if err != nil {
        log.Fatal(err)
    }
    defer ctx.Close()

    node, err := ctx.CreateNode("go_talker").Build()
    if err != nil {
        log.Fatal(err)
    }
    defer node.Close()

    pub, err := node.CreatePublisher("chatter").Build(&std_msgs.String{})
    if err != nil {
        log.Fatal(err)
    }
    defer pub.Close()

    for i := 0; ; i++ {
        msg := &std_msgs.String{Data: fmt.Sprintf("Hello #%d", i)}
        if err := pub.Publish(msg); err != nil {
            log.Printf("publish error: %v", err)
        }
        fmt.Printf("Published: %s\n", msg.Data)
        time.Sleep(500 * time.Millisecond)
    }
}

Create hello_pub/go.mod — the replace directive points Go to the local hiroz package:

module hello_pub

go 1.23

require github.com/ZettaScaleLabs/hiroz/crates/hiroz-go v0.0.0

replace github.com/ZettaScaleLabs/hiroz/crates/hiroz-go => /path/to/hiroz/crates/hiroz-go

Replace /path/to/hiroz with the absolute path where you cloned the repo.

3. Write a subscriber

Create hello_sub/main.go:

package main

import (
    "log"

    "github.com/ZettaScaleLabs/hiroz/crates/hiroz-go/hiroz"
    "github.com/ZettaScaleLabs/hiroz/crates/hiroz-go/generated/std_msgs"
)

func main() {
    ctx, err := hiroz.NewContext().WithDomainID(0).Build()
    if err != nil {
        log.Fatal(err)
    }
    defer ctx.Close()

    node, err := ctx.CreateNode("go_listener").Build()
    if err != nil {
        log.Fatal(err)
    }
    defer node.Close()

    _, err = node.CreateSubscriber("chatter").
        BuildWithCallback(&std_msgs.String{}, func(data []byte) {
            msg := &std_msgs.String{}
            if err := msg.DeserializeCDR(data); err != nil {
                log.Printf("deserialize error: %v", err)
                return
            }
            log.Printf("Received: %s", msg.Data)
        })
    if err != nil {
        log.Fatal(err)
    }

    select {} // block forever
}

Create hello_sub/go.mod with the same replace directive as above.

4. Run

You need a Zenoh router running first — it acts as the rendezvous point for all nodes.

Start the router (pick one):

# Option A: download zenohd from https://github.com/eclipse-zenoh/zenoh/releases
./zenohd

# Option B: install via cargo (one-time)
cargo install zenohd && zenohd

Run the subscriber and publisher — set CGO_LDFLAGS to point at the library:

HIROZ=/path/to/hiroz

# Terminal 2: subscriber
cd hello_sub
CGO_LDFLAGS="-L$HIROZ/crates/hiroz-go -lhiroz -lm" \
CGO_CFLAGS="-I$HIROZ/crates/hiroz-go/hiroz" \
go run main.go

# Terminal 3: publisher
cd hello_pub
CGO_LDFLAGS="-L$HIROZ/crates/hiroz-go -lhiroz -lm" \
CGO_CFLAGS="-I$HIROZ/crates/hiroz-go/hiroz" \
go run main.go

You should see the subscriber printing messages from the publisher.

Tip

Set HIROZ in your shell profile to avoid repeating the path.

What's next