feat: add ziglang

This commit is contained in:
AJ ONeal
2022-03-27 09:38:12 +00:00
parent 0864a0a0f8
commit 1c20c6d8ce
8 changed files with 453 additions and 0 deletions

213
zig/README.md Normal file
View File

@@ -0,0 +1,213 @@
---
title: Zig
homepage: https://ziglang.org/
tagline: |
zig: write and cross-compile maintainable robust, optimal, and reusable software.
---
To update or switch versions, run `webi zig@stable` (or `@v0.9`, `@beta`, etc).
### Files
These are the files / directories that are created and/or modified with this
install:
```txt
~/.config/envman/PATH.env
~/.local/opt/zig
```
## Cheat Sheet
> `zig` is two things:
>
> 1. A drop-in cross-compiling toolchain for C and C++ (and Rust and CGo for
> that matter).
>
> 2. A general purpose systems programming language, like C, but intentional,
> and with benefit of hindsight.
>
> (and also a nod to
> [Zero Wing](<https://hero.fandom.com/wiki/ZIG_(Zero_Wing)>))
Philosophy:
- [The Road to Zig 1.0](https://www.youtube.com/watch?v=Gv2I7qTux7g)
- [The Zen of Zig](https://ziglang.org/documentation/master/#Zen)
### The Zen of Zig
- Communicate intent precisely.
- Edge cases matter.
- Favor reading code over writing code.
- Only one obvious way to do things.
- Runtime crashes are better than bugs.
- Compile errors are better than runtime crashes.
- Incremental improvements.
- Avoid local maximums.
- Reduce the amount one must remember.
- Focus on code rather than style.
- Resource allocation may fail; resource deallocation must succeed.
- Memory is a resource.
- Together we serve the users.
### How to compile C/C++ with Zig
You can use
[Zig as a drop-in C compiler](https://andrewkelley.me/post/zig-cc-powerful-drop-in-replacement-gcc-clang.html).
```bash
zig cc -o ./hello main.c
zig c++ -o ./hello++ main.cpp
```
And you can cross-compile effortlessly:
```bash
zig cc -o ./hello.exe main.c -target x86_64-windows-gnu
zig c++ -o ./hello.exe main.cpp -target x86_64-windows-gnu
```
### How to create and compile Zig programs
1. Create a new project directory:
```bash
mkdir -p ./zig-hello/
pushd ./zig-hello/
```
2. Initialize the project with a new `build.zig`
```bash
zig init-exe
```
3. Build `hello.exe` for Windows from MacOS or Linux
```bash
zig build-exe src/main.zig --name hello -target x86_64-windows-gnu
zig build-exe src/main.zig --name hello -target x86_64-linux-musl
zig build-exe src/main.zig --name hello-arm -target aarch64-linux-musl
zig build-exe src/main.zig --name hello-macos -target x86_64-macos-gnu
zig build-exe src/main.zig --name hello-m1 -target aarch64-macos-gnu
```
### How to list and use Zig's cross-compile targets
```bash
zig targets | jq -r '.libc[]'
```
Here's a few of the common targets:
```txt
aarch64-linux-musl
aarch64-windows-gnu
aarch64-macos-gnu
thumb-linux-musleabihf
wasm32-wasi-musl
x86_64-linux-musl
x86_64-windows-gnu
x86_64-macos-gnu
```
### How to cross-compile Rust with Zig
1. Create a `zig-cc-{ARCH-OS}` and `zig-cpp-{ARCH-OS}` wrappers:
```bash
cat << EOF >> ~/.local/bin/zig-cc-x86_64-windows-gnu
#!/bin/sh
set -e
set -u
"\${HOME}/.local/opt/zig/zig" cc -target x86_64-windows-gnu \$@
EOF
chmod a+x ~/.local/bin/zig-cc
```
```bash
cat << EOF >> ~/.local/bin/zig-cpp-x86_64-windows-gnu
#!/bin/sh
set -e
set -u
"\${HOME}/.local/opt/zig/zig" c++ -target x86_64-windows-gnu \$@
EOF
chmod a+x ~/.local/bin/zig-cpp
```
2. Set the `CC`, `CPP` and `ZIGTARGET` ENVs. For example:
```bash
#export ZIGTARGET="x86_64-windows-gnu"
export CC="zig-cc-x86_64-windows-gnu"
export CPP="zig-cpp-x86_64-windows-gnu"
```
3. Install the correpsonding Rust toolchains:
```bash
rustup target install x86_64-apple-darwin
rustup target install x86_64-unknown-linux-musl
rustup target install aarch64-unknown-linux-musl
rustup target install x86_64-pc-windows-gnu
```
4. You may need to also specifically set the linker. For example, with Rust's
`~/.cargo/config.toml`:
```bash
[target.x86_64-apple-darwin]
linker = "zig-cc-x86_64-macos-gnu"
[target.x86_64-unknown-linux-musl]
linker = "zig-cc-x86_64-unknown-linux-musl"
[target.aarch64-unknown-linux-musl]
linker = "zig-cc-aarch64-unknown-linux-musl"
[target.x86_64-pc-windows-gnu]
linker = "zig-cc-x86_64-windows-gnu"
```
`~/.local/bin/zig-create-crossies`:
```bash
#!/bin/bash
set -e
set -u
my_targets="$(zig targets | jq -r '.libc[]' | sort -u)"
for my_target in $my_targets; do
cat << EOF >> "${HOME}/.local/bin/zig-cc-${my_target}"
#!/bin/sh
set -e
set -u
"\${HOME}/.local/opt/zig/zig" cc -target ${my_target} \$@
EOF
chmod a+x "${HOME}/.local/bin/zig-cc-${my_target}"
done
for my_target in $my_targets; do
cat << EOF >> "${HOME}/.local/bin/zig-cpp-${my_target}"
#!/bin/sh
set -e
set -u
"\${HOME}/.local/opt/zig/zig" c++ -target ${my_target} \$@
EOF
chmod a+x "${HOME}/.local/bin/zig-cpp-${my_target}"
done
```
See also:
- <https://actually.fyi/posts/zig-makes-rust-cross-compilation-just-work/>
### How to cross-compile CGo (Golang) with Zig
See the section above about Rust.
It's almost exactly the same.
See also:
- <https://github.com/dosgo/zigtool>
- <https://www.reddit.com/r/Zig/comments/k8o0y0/how_to_crosscompile_a_library_with_buildzig/>

60
zig/install.ps1 Normal file
View File

@@ -0,0 +1,60 @@
#!/usr/bin/env pwsh
###################
# Install ziglang #
###################
# Every package should define these variables
$pkg_cmd_name = "zig"
$pkg_dst_cmd = "$Env:USERPROFILE\.local\opt\zig\zig.exe"
$pkg_dst_bin = "$Env:USERPROFILE\.local\opt\zig"
$pkg_dst_dir = "$Env:USERPROFILE\.local\opt\zig"
$pkg_dst = "$pkg_dst_dir"
$pkg_src_cmd = "$Env:USERPROFILE\.local\opt\zig-v$Env:WEBI_VERSION\zig.exe"
$pkg_src_bin = "$Env:USERPROFILE\.local\opt\zig-v$Env:WEBI_VERSION"
$pkg_src_dir = "$Env:USERPROFILE\.local\opt\zig-v$Env:WEBI_VERSION"
$pkg_src = "$pkg_src_dir"
New-Item "$Env:USERPROFILE\Downloads\webi" -ItemType Directory -Force | out-null
$pkg_download = "$Env:USERPROFILE\Downloads\webi\$Env:WEBI_PKG_FILE"
# Fetch archive
IF (!(Test-Path -Path "$Env:USERPROFILE\Downloads\webi\$Env:WEBI_PKG_FILE"))
{
echo "Downloading ziglang from $Env:WEBI_PKG_URL to $pkg_download"
& curl.exe -A "$Env:WEBI_UA" -fsSL "$Env:WEBI_PKG_URL" -o "$pkg_download.part"
& move "$pkg_download.part" "$pkg_download"
}
IF (!(Test-Path -Path "$pkg_src_cmd"))
{
echo "Installing ziglang"
# TODO: create package-specific temp directory
# Enter tmp
pushd .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\zig-*" -Recurse -ErrorAction Ignore
# Unpack archive file into this temporary directory
# Windows BSD-tar handles zip. Imagine that.
echo "Unpacking $pkg_download"
& tar xf "$pkg_download"
# Settle unpacked archive into place
echo "Install Location: $pkg_src_cmd"
Move-Item -Path ".\zig-*" -Destination "$pkg_src"
# Exit tmp
popd
}
echo "Copying into '$pkg_dst' from '$pkg_src'"
Remove-Item -Path "$pkg_dst" -Recurse -ErrorAction Ignore | out-null
Copy-Item -Path "$pkg_src" -Destination "$pkg_dst" -Recurse
# Add to Windows PATH
& "$Env:USERPROFILE\.local\bin\pathman.exe" add ~/.local/opt/zig

43
zig/install.sh Normal file
View File

@@ -0,0 +1,43 @@
#!/bin/bash
# shellcheck disable=SC2034
# "'pkg_cmd_name' appears unused. Verify it or export it."
function __init_ziglang() {
set -e
set -u
###################
# Install ziglang #
###################
# Every package should define these 6 variables
pkg_cmd_name="zig"
pkg_dst_cmd="$HOME/.local/opt/zig/zig"
pkg_dst_dir="$HOME/.local/opt/zig"
pkg_dst="$pkg_dst_dir"
pkg_src_cmd="$HOME/.local/opt/zig-v$WEBI_VERSION/zig"
pkg_src_dir="$HOME/.local/opt/zig-v$WEBI_VERSION"
pkg_src="$pkg_src_dir"
# pkg_install must be defined by every package
pkg_install() {
# mv ./zig-* ~/.local/opt/zig-v0.9.1
mv ./zig-* "${pkg_src}"
}
# pkg_get_current_version is recommended, but not required
pkg_get_current_version() {
# 'zig version' has output in this format:
# 0.9.1
# We're just doing a little future-proofing to keep it that way
zig version 2> /dev/null |
head -n 1 |
cut -d ' ' -f 1
}
}
__init_ziglang

81
zig/releases.js Normal file
View File

@@ -0,0 +1,81 @@
'use strict';
module.exports = function (request) {
return request({
url: 'https://ziglang.org/download/index.json',
json: true
}).then(function (resp) {
let versions = resp.body;
let releases = [];
let refs = Object.keys(versions);
refs.forEach(function (ref) {
let pkgs = versions[ref];
// "platform" = arch + os combo
let platforms = Object.keys(pkgs);
platforms.forEach(function (platform) {
let pkg = pkgs[platform];
// don't grab 'date' or 'notes', which are (confusingly)
// at the same level as platform releases
let isNotPackage = !pkg || 'object' !== typeof pkg || !pkg.tarball;
if (isNotPackage) {
return;
}
// Ex: aarch64-macos => ['aarch64', 'macos']
let parts = platform.split('-');
let arch = parts[0];
let os = parts[1];
if (parts.length > 2) {
console.warn(
`unexpected platform name with multiple '-': ${platform}`
);
return;
}
let p = {
version: ref,
date: pkgs.date,
channel: 'stable',
// linux, macos, windows
os: os,
// TODO map explicitly (rather than normalization auto-detect)
//arch: arch,
download: pkg.tarball,
hash: pkg.shasum,
size: pkg.size
// TODO docs + release notes?
//docs: 'https://ziglang.org/documentation/0.9.1/',
//stdDocs: 'https://ziglang.org/documentation/0.9.1/std/',
//notes: 'https://ziglang.org/download/0.9.1/release-notes.html'
};
// Mark branches or tags as beta (for now)
// Ex: 'master'
// Also mark prereleases (with build tags) as beta
// Ex: 0.10.0-dev.1606+97a53bb8a
let isNotStable = !/\./.test(ref) || /\+|-/.test(p.version);
if (isNotStable) {
p.channel = 'beta';
}
releases.push(p);
});
});
return {
releases: releases
};
});
};
if (module === require.main) {
module.exports(require('@root/request')).then(function (all) {
all = require('../_webi/normalize.js')(all);
// just select the first 5 for demonstration
all.releases = all.releases.slice(0, 5);
console.info(JSON.stringify(all, null, 2));
});
}

29
zig/zig-create-crossies.sh Executable file
View File

@@ -0,0 +1,29 @@
#!/bin/bash
set -e
set -u
my_targets="$(zig targets | jq -r '.libc[]' | sort -u)"
for my_target in $my_targets; do
cat << EOF >> "${HOME}/.local/bin/zig-cc-${my_target}"
#!/bin/sh
set -e
set -u
"\${HOME}/.local/opt/zig/zig" cc -target ${my_target} \$@
EOF
chmod a+x "${HOME}/.local/bin/zig-cc-${my_target}"
done
for my_target in $my_targets; do
cat << EOF >> "${HOME}/.local/bin/zig-cpp-${my_target}"
#!/bin/sh
set -e
set -u
"\${HOME}/.local/opt/zig/zig" c++ -target ${my_target} \$@
EOF
chmod a+x "${HOME}/.local/bin/zig-cpp-${my_target}"
done

11
ziglang/README.md Normal file
View File

@@ -0,0 +1,11 @@
---
title: ziglang (zig alias)
homepage: https://webinstall.dev/zig
tagline: |
Alias for https://webinstall.dev/zig
alias: zig
description: |
See https://webinstall.dev/zig
---
Alias for https://webinstall.dev/zig

5
ziglang/install.ps1 Normal file
View File

@@ -0,0 +1,5 @@
#!/bin/pwsh
echo "'ziglang@$Env:WEBI_TAG' is an alias for 'zig@$Env:WEBI_VERSION'"
IF ($Env:WEBI_HOST -eq $null -or $Env:WEBI_HOST -eq "") { $Env:WEBI_HOST = "https://webinstall.dev" }
curl.exe -fsSL "$Env:WEBI_HOST/zig@$Env:WEBI_VERSION" | powershell

11
ziglang/install.sh Normal file
View File

@@ -0,0 +1,11 @@
#!/bin/bash
set -e
set -u
function __redirect_alias_zig() {
echo "'ziglang@${WEBI_TAG:-stable}' is an alias for 'zig@${WEBI_VERSION:-}'"
WEBI_HOST=${WEBI_HOST:-"https://webinstall.dev"}
curl -fsSL "$WEBI_HOST/zig@${WEBI_VERSION:-}" | bash
}
__redirect_alias_zig