Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 170 additions & 0 deletions .github/workflows/build-binaries.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
# Copyright 2023 LiveKit, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

name: Build binaries

on:
workflow_call:
inputs:
output_dir:
type: string
default: bin
upload_release:
type: boolean
default: false

jobs:
build:
strategy:
fail-fast: false
matrix:
include:
- os: macos-latest
suffix: darwin_arm64
- os: ubuntu-latest
suffix: linux_amd64
zig_target: x86_64-linux-gnu.2.28
alsa_arch: amd64
alsa_triple: x86_64-linux-gnu
- os: ubuntu-latest
suffix: linux_arm64
zig_target: aarch64-linux-gnu.2.28
alsa_arch: arm64
alsa_triple: aarch64-linux-gnu
goarch: arm64
- os: ubuntu-latest
suffix: linux_arm
zig_target: arm-linux-gnueabihf.2.28
alsa_arch: armhf
alsa_triple: arm-linux-gnueabihf
goarch: arm
goarm: "7"
- os: ubuntu-latest
suffix: windows_amd64
zig_target: x86_64-windows-gnu
goos: windows
goarch: amd64
- os: ubuntu-latest
suffix: windows_arm64
zig_target: aarch64-windows-gnu
goos: windows
goarch: arm64
- os: ubuntu-latest
suffix: windows_arm
goos: windows
goarch: arm
goarm: "7"
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v6
with:
lfs: 'true'
submodules: true

- run: git lfs pull

- name: Set up Go
uses: actions/setup-go@v6
with:
go-version: "1.25"

- name: Install Zig
if: matrix.zig_target
uses: mlugg/setup-zig@v2
with:
version: 0.14.1

- name: Install ALSA headers
if: matrix.alsa_arch
run: |
sudo dpkg --add-architecture ${{ matrix.alsa_arch }}
if [ "${{ matrix.alsa_arch }}" != "amd64" ]; then
CODENAME=$(lsb_release -cs)
# Restrict existing sources to amd64 to avoid 404s for foreign arch
for f in /etc/apt/sources.list.d/*.sources; do
grep -q '^Architectures:' "$f" || sudo sed -i '/^Types:/a Architectures: amd64 i386' "$f"
done
# Add ports.ubuntu.com for the foreign architecture
printf 'Types: deb\nURIs: http://ports.ubuntu.com/ubuntu-ports\nSuites: %s %s-updates\nComponents: main universe\nArchitectures: %s\nSigned-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg\n' \
"$CODENAME" "$CODENAME" "${{ matrix.alsa_arch }}" | sudo tee /etc/apt/sources.list.d/ports.sources
fi
sudo apt-get update
sudo apt-get install -y libasound2-dev:${{ matrix.alsa_arch }}

- name: Generate Windows import libraries
if: matrix.goos == 'windows' && matrix.zig_target
run: |
ZIG_LIB=$(zig env | jq -r '.lib_dir')
echo "ZIG_LIB=${ZIG_LIB}" >> "$GITHUB_ENV"
LIB_DIR="${ZIG_LIB}/libc/mingw/lib-common"
# Zig bundles MinGW .def files but lld needs .a import libraries.
# Go's compiled objects embed COFF /DEFAULTLIB directives (e.g. dbghelp,
# bcrypt) that lld resolves directly, bypassing Zig's lazy .def→.a
# generation. Pre-generate all import libraries so lld can find them.
MACHINE=${{ matrix.goarch == 'amd64' && 'i386:x86-64' || 'arm64' }}
for def in "${LIB_DIR}"/*.def; do
lib=$(basename "$def" .def)
[ -f "${LIB_DIR}/lib${lib}.a" ] && continue
zig dlltool -d "$def" -l "${LIB_DIR}/lib${lib}.a" -m "$MACHINE" 2>/dev/null || true
done

- name: Build
env:
CGO_ENABLED: ${{ (matrix.goos && !matrix.zig_target) && '0' || '1' }}
CC: ${{ matrix.zig_target && format('zig cc -target {0}', matrix.zig_target) || '' }}
CXX: ${{ matrix.zig_target && format('zig c++ -target {0}', matrix.zig_target) || '' }}
# Zig uses its own sysroot; point it at the system ALSA headers and libraries
CGO_CFLAGS: ${{ matrix.alsa_triple && format('-isystem /usr/include -isystem /usr/include/{0}', matrix.alsa_triple) || '' }}
CGO_LDFLAGS: ${{ matrix.alsa_triple && format('-L/usr/lib/{0}', matrix.alsa_triple) || '' }}
# -fms-extensions: enable __try/__except (SEH) used by WebRTC
# -DNTDDI_VERSION: target Windows 10 base to skip WinRT includes absent from MinGW
CGO_CXXFLAGS: ${{ matrix.goos == 'windows' && '-fms-extensions -DNTDDI_VERSION=0x0A000000' || '' }}
GOOS: ${{ matrix.goos || '' }}
GOARCH: ${{ matrix.goarch || '' }}
GOARM: ${{ matrix.goarm || '' }}
shell: bash
run: |
EXT=""; if [ "${GOOS:-}" = "windows" ]; then EXT=".exe"; fi
TAGS=""
if [ "$CGO_ENABLED" = "1" ]; then TAGS="-tags console"; fi
# Force external linking for Windows so Go uses zig cc (CC) as the linker,
# and add Zig's MinGW lib path so lld can find the generated import libraries.
EXTLD=""
if [ "${GOOS:-}" = "windows" ] && [ "$CGO_ENABLED" = "1" ]; then
EXTLD="-linkmode=external -extldflags '-L${ZIG_LIB}/libc/mingw/lib-common'"
fi
go build $TAGS -ldflags "-w -s $EXTLD" -o "${{ inputs.output_dir }}/lk${EXT}" ./cmd/lk

- name: Verify binary
if: "!matrix.goos && !matrix.goarch"
run: ${{ inputs.output_dir }}/lk --help > /dev/null

- name: Package and upload
if: inputs.upload_release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: bash
run: |
TAG="${GITHUB_REF#refs/tags/}"
VERSION="${TAG#v}"
NAME="lk_${VERSION}_${{ matrix.suffix }}"
cp LICENSE ${{ inputs.output_dir }}/
cp -r autocomplete ${{ inputs.output_dir }}/
if [[ "${{ matrix.suffix }}" == windows_* ]]; then
cd ${{ inputs.output_dir }} && zip -r "../${NAME}.zip" lk.exe LICENSE autocomplete && cd ..
gh release upload "$TAG" "${NAME}.zip" --clobber
else
tar -czf "${NAME}.tar.gz" -C ${{ inputs.output_dir }} lk LICENSE autocomplete
gh release upload "$TAG" "${NAME}.tar.gz" --clobber
fi
139 changes: 128 additions & 11 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,32 +20,149 @@ on:
pull_request:
branches: [ main ]

permissions:
contents: read

jobs:
build:
lint-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/cache@v5
with:
path: |
~/go/pkg/mod
~/go/bin
~/.cache
key: livekit-cli
submodules: true

- name: Set up Go
uses: actions/setup-go@v6
with:
go-version: "1.25"

- name: Download Go modules
run: go mod download

- name: Static Check
uses: dominikh/staticcheck-action@v1.4.0
with:
version: "latest"
install-go: false

- name: Run Go tests
- name: Test
run: go test -v ./...

build:
strategy:
fail-fast: false
matrix:
include:
- os: macos-latest
suffix: darwin_arm64
- os: ubuntu-latest
suffix: linux_amd64
zig_target: x86_64-linux-gnu.2.28
alsa_arch: amd64
alsa_triple: x86_64-linux-gnu
- os: ubuntu-latest
suffix: linux_arm64
zig_target: aarch64-linux-gnu.2.28
alsa_arch: arm64
alsa_triple: aarch64-linux-gnu
goarch: arm64
- os: ubuntu-latest
suffix: linux_arm
zig_target: arm-linux-gnueabihf.2.28
alsa_arch: armhf
alsa_triple: arm-linux-gnueabihf
goarch: arm
goarm: "7"
- os: ubuntu-latest
suffix: windows_amd64
zig_target: x86_64-windows-gnu
goos: windows
goarch: amd64
- os: ubuntu-latest
suffix: windows_arm64
zig_target: aarch64-windows-gnu
goos: windows
goarch: arm64
- os: ubuntu-latest
suffix: windows_arm
goos: windows
goarch: arm
goarm: "7"
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v6
with:
submodules: true

- name: Set up Go
uses: actions/setup-go@v6
with:
go-version: "1.25"

- name: Install Zig
if: matrix.zig_target
uses: mlugg/setup-zig@v2
with:
version: 0.14.1

- name: Install ALSA headers
if: matrix.alsa_arch
run: |
sudo dpkg --add-architecture ${{ matrix.alsa_arch }}
if [ "${{ matrix.alsa_arch }}" != "amd64" ]; then
CODENAME=$(lsb_release -cs)
# Restrict existing sources to amd64 to avoid 404s for foreign arch
for f in /etc/apt/sources.list.d/*.sources; do
grep -q '^Architectures:' "$f" || sudo sed -i '/^Types:/a Architectures: amd64 i386' "$f"
done
# Add ports.ubuntu.com for the foreign architecture
printf 'Types: deb\nURIs: http://ports.ubuntu.com/ubuntu-ports\nSuites: %s %s-updates\nComponents: main universe\nArchitectures: %s\nSigned-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg\n' \
"$CODENAME" "$CODENAME" "${{ matrix.alsa_arch }}" | sudo tee /etc/apt/sources.list.d/ports.sources
fi
sudo apt-get update
sudo apt-get install -y libasound2-dev:${{ matrix.alsa_arch }}

- name: Generate Windows import libraries
if: matrix.goos == 'windows' && matrix.zig_target
run: |
ZIG_LIB=$(zig env | jq -r '.lib_dir')
echo "ZIG_LIB=${ZIG_LIB}" >> "$GITHUB_ENV"
LIB_DIR="${ZIG_LIB}/libc/mingw/lib-common"
# Zig bundles MinGW .def files but lld needs .a import libraries.
# Go's compiled objects embed COFF /DEFAULTLIB directives (e.g. dbghelp,
# bcrypt) that lld resolves directly, bypassing Zig's lazy .def→.a
# generation. Pre-generate all import libraries so lld can find them.
MACHINE=${{ matrix.goarch == 'amd64' && 'i386:x86-64' || 'arm64' }}
for def in "${LIB_DIR}"/*.def; do
lib=$(basename "$def" .def)
[ -f "${LIB_DIR}/lib${lib}.a" ] && continue
zig dlltool -d "$def" -l "${LIB_DIR}/lib${lib}.a" -m "$MACHINE" 2>/dev/null || true
done

- name: Build
env:
CGO_ENABLED: ${{ (matrix.goos && !matrix.zig_target) && '0' || '1' }}
CC: ${{ matrix.zig_target && format('zig cc -target {0}', matrix.zig_target) || '' }}
CXX: ${{ matrix.zig_target && format('zig c++ -target {0}', matrix.zig_target) || '' }}
# Zig uses its own sysroot; point it at the system ALSA headers and libraries
CGO_CFLAGS: ${{ matrix.alsa_triple && format('-isystem /usr/include -isystem /usr/include/{0}', matrix.alsa_triple) || '' }}
CGO_LDFLAGS: ${{ matrix.alsa_triple && format('-L/usr/lib/{0}', matrix.alsa_triple) || '' }}
# -fms-extensions: enable __try/__except (SEH) used by WebRTC
# -DNTDDI_VERSION: target Windows 10 base to skip WinRT includes absent from MinGW
CGO_CXXFLAGS: ${{ matrix.goos == 'windows' && '-fms-extensions -DNTDDI_VERSION=0x0A000000' || '' }}
GOOS: ${{ matrix.goos || '' }}
GOARCH: ${{ matrix.goarch || '' }}
GOARM: ${{ matrix.goarm || '' }}
shell: bash
run: |
EXT=""; if [ "${GOOS:-}" = "windows" ]; then EXT=".exe"; fi
TAGS=""
if [ "$CGO_ENABLED" = "1" ]; then TAGS="-tags console"; fi
# Force external linking for Windows so Go uses zig cc (CC) as the linker,
# and add Zig's MinGW lib path so lld can find the generated import libraries.
EXTLD=""
if [ "${GOOS:-}" = "windows" ] && [ "$CGO_ENABLED" = "1" ]; then
EXTLD="-linkmode=external -extldflags '-L${ZIG_LIB}/libc/mingw/lib-common'"
fi
go build $TAGS -ldflags "-w -s $EXTLD" -o "bin/lk${EXT}" ./cmd/lk

- name: Verify binary
if: "!matrix.goos && !matrix.goarch"
run: bin/lk --help > /dev/null
2 changes: 2 additions & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ jobs:

steps:
- uses: actions/checkout@v6
with:
submodules: true

- name: Set up Go
uses: actions/setup-go@v6
Expand Down
47 changes: 47 additions & 0 deletions Formula/lk.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# typed: false
# frozen_string_literal: true

# This formula is meant for a custom Homebrew tap (e.g. livekit/homebrew-livekit).
# It installs a prebuilt binary with console support (PortAudio + WebRTC AEC).
# Usage: brew install livekit/livekit/lk
class Lk < Formula
desc "Command-line interface to LiveKit (with console support)"
homepage "https://livekit.io"
license "Apache-2.0"
version "VERSION"

on_macos do
if Hardware::CPU.arm?
url "https://github.com/livekit/livekit-cli/releases/download/vVERSION/lk_VERSION_darwin_arm64.tar.gz"
sha256 "SHA256_DARWIN_ARM64"
end
end

on_linux do
if Hardware::CPU.arm? && Hardware::CPU.is_64_bit?
url "https://github.com/livekit/livekit-cli/releases/download/vVERSION/lk_VERSION_linux_arm64.tar.gz"
sha256 "SHA256_LINUX_ARM64"
elsif Hardware::CPU.arm?
url "https://github.com/livekit/livekit-cli/releases/download/vVERSION/lk_VERSION_linux_arm.tar.gz"
sha256 "SHA256_LINUX_ARM"
else
url "https://github.com/livekit/livekit-cli/releases/download/vVERSION/lk_VERSION_linux_amd64.tar.gz"
sha256 "SHA256_LINUX_AMD64"
end
end

def install
bin.install "lk"
bin.install_symlink "lk" => "livekit-cli"

bash_completion.install "autocomplete/bash_autocomplete" => "lk"
fish_completion.install "autocomplete/fish_autocomplete" => "lk.fish"
zsh_completion.install "autocomplete/zsh_autocomplete" => "_lk"
end

test do
output = shell_output("#{bin}/lk token create --list --api-key key --api-secret secret")
assert_match "valid for (mins): 5", output
assert_match "lk version #{version}", shell_output("#{bin}/lk --version")
end
end
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ cli: check_lfs
GOOS=windows GOARCH=amd64 go build -ldflags "-w -s" -o bin/lk.exe ./cmd/lk


console:
CGO_ENABLED=1 go build -tags console -ldflags "-w -s" -o bin/lk ./cmd/lk

install: cli
ifeq ($(DETECTED_OS),Windows)
cp bin/lk.exe $(GOBIN)/lk.exe
Expand Down
Loading