Skip to content

Latest commit

 

History

History
1187 lines (895 loc) · 58.6 KB

README.md

File metadata and controls

1187 lines (895 loc) · 58.6 KB

LVGL for PinePhone (and WebAssembly) with Zig and Apache NuttX RTOS

LVGL for PinePhone (and WebAssembly) with Zig and Apache NuttX RTOS

Read the articles...

Can we build an LVGL App in Zig for PinePhone... That will run on Apache NuttX RTOS?

Can we preview a PinePhone App with Zig, LVGL and WebAssembly in a Web Browser? To make the UI Coding a little easier?

Let's find out!

LVGL Zig App

Let's run this LVGL Zig App on PinePhone...

/// Create the LVGL Widgets that will be rendered on the display. Calls the
/// LVGL API that has been wrapped in Zig. Based on
/// https://docs.lvgl.io/master/widgets/label.html?highlight=lv_label_create#line-wrap-recoloring-and-scrolling
fn createWidgetsWrapped() !void {
debug("createWidgetsWrapped: start", .{});
defer { debug("createWidgetsWrapped: end", .{}); }
// Get the Active Screen
var screen = try lvgl.getActiveScreen();
// Create a Label Widget
var label = try screen.createLabel();
// Wrap long lines in the label text
label.setLongMode(c.LV_LABEL_LONG_WRAP);
// Interpret color codes in the label text
label.setRecolor(true);
// Center align the label text
label.setAlign(c.LV_TEXT_ALIGN_CENTER);
// Set the label text and colors
label.setText(
"#ff0000 HELLO# " ++ // Red Text
"#00aa00 LVGL ON# " ++ // Green Text
"#0000ff PINEPHONE!# " // Blue Text
);
// Set the label width
label.setWidth(200);
// Align the label to the center of the screen, shift 30 pixels up
label.alignObject(c.LV_ALIGN_CENTER, 0, -30);
}

How is createWidgetsWrapped called?

createWidgetsWrapped will be called by the LVGL Widget Demo lv_demo_widgets, which we'll replace by this Zig version...

/// We render an LVGL Screen with LVGL Widgets
pub export fn lv_demo_widgets() void {
// Create the widgets for display (with Zig Wrapper)
createWidgetsWrapped()
catch |e| {
// In case of error, quit
std.log.err("createWidgetsWrapped failed: {}", .{e});
return;
};

Where's the Zig Wrapper for LVGL?

Our Zig Wrapper for LVGL is defined here...

We also have a version of the LVGL Zig Code that doesn't call the Zig Wrapper...

Build LVGL Zig App

NuttX Build runs this GCC Command to compile lv_demo_widgets.c for PinePhone...

$ make --trace
...
cd $HOME/PinePhone/wip-nuttx/apps/graphics/lvgl
aarch64-none-elf-gcc
  -c
  -fno-common
  -Wall
  -Wstrict-prototypes
  -Wshadow
  -Wundef
  -Werror
  -Os
  -fno-strict-aliasing
  -fomit-frame-pointer
  -g
  -march=armv8-a
  -mtune=cortex-a53
  -isystem $HOME/PinePhone/wip-nuttx/nuttx/include
  -D__NuttX__ 
  -pipe
  -I $HOME/PinePhone/wip-nuttx/apps/graphics/lvgl
  -I "$HOME/PinePhone/wip-nuttx/apps/include"
  -Wno-format
  -Wno-unused-variable
  "-I./lvgl/src/core"
  "-I./lvgl/src/draw"
  "-I./lvgl/src/draw/arm2d"
  "-I./lvgl/src/draw/nxp"
  "-I./lvgl/src/draw/nxp/pxp"
  "-I./lvgl/src/draw/nxp/vglite"
  "-I./lvgl/src/draw/sdl"
  "-I./lvgl/src/draw/stm32_dma2d"
  "-I./lvgl/src/draw/sw"
  "-I./lvgl/src/draw/swm341_dma2d"
  "-I./lvgl/src/font"
  "-I./lvgl/src/hal"
  "-I./lvgl/src/misc"
  "-I./lvgl/src/widgets"
  "-DLV_ASSERT_HANDLER=ASSERT(0);"   
  lvgl/demos/widgets/lv_demo_widgets.c
  -o  lvgl/demos/widgets/lv_demo_widgets.c.Users.Luppy.PinePhone.wip-nuttx.apps.graphics.lvgl.o

We'll copy the above GCC Options to the Zig Compiler and build this Zig Program for PinePhone...

Here's the Shell Script...

## Build the LVGL Zig App
function build_zig {

  ## Go to LVGL Zig Folder
  pushd ../pinephone-lvgl-zig
  git pull

  ## Check that NuttX Build has completed and `lv_demo_widgets.*.o` exists
  if [ ! -f ../apps/graphics/lvgl/lvgl/demos/widgets/lv_demo_widgets.*.o ] 
  then
    echo "*** Error: Build NuttX first before building Zig app"
    exit 1
  fi

  ## Compile the Zig App for PinePhone 
  ## (armv8-a with cortex-a53)
  ## TODO: Change ".." to your NuttX Project Directory
  zig build-obj \
    --verbose-cimport \
    -target aarch64-freestanding-none \
    -mcpu cortex_a53 \
    -isystem "../nuttx/include" \
    -I "../apps/include" \
    -I "../apps/graphics/lvgl" \
    -I "../apps/graphics/lvgl/lvgl/src/core" \
    -I "../apps/graphics/lvgl/lvgl/src/draw" \
    -I "../apps/graphics/lvgl/lvgl/src/draw/arm2d" \
    -I "../apps/graphics/lvgl/lvgl/src/draw/nxp" \
    -I "../apps/graphics/lvgl/lvgl/src/draw/nxp/pxp" \
    -I "../apps/graphics/lvgl/lvgl/src/draw/nxp/vglite" \
    -I "../apps/graphics/lvgl/lvgl/src/draw/sdl" \
    -I "../apps/graphics/lvgl/lvgl/src/draw/stm32_dma2d" \
    -I "../apps/graphics/lvgl/lvgl/src/draw/sw" \
    -I "../apps/graphics/lvgl/lvgl/src/draw/swm341_dma2d" \
    -I "../apps/graphics/lvgl/lvgl/src/font" \
    -I "../apps/graphics/lvgl/lvgl/src/hal" \
    -I "../apps/graphics/lvgl/lvgl/src/misc" \
    -I "../apps/graphics/lvgl/lvgl/src/widgets" \
    lvgltest.zig

  ## Copy the compiled app to NuttX and overwrite `lv_demo_widgets.*.o`
  ## TODO: Change ".." to your NuttX Project Directory
  cp lvgltest.o \
    ../apps/graphics/lvgl/lvgl/demos/widgets/lv_demo_widgets.*.o

  ## Return to NuttX Folder
  popd
}

## Download the LVGL Zig App
git clone https://github.com/lupyuen/pinephone-lvgl-zig

## Build NuttX for PinePhone
cd nuttx
make -j

## Build the LVGL Zig App
build_zig

## Link the LVGL Zig App with NuttX
make -j

(Original Build Script)

(Updated Build Script)

And our LVGL Zig App runs OK on PinePhone!

LVGL for PinePhone with Zig and Apache NuttX RTOS

Simulate PinePhone UI with Zig, LVGL and WebAssembly

We're now building a Feature Phone UI for NuttX on PinePhone...

Can we simulate the Feature Phone UI with Zig, LVGL and WebAssembly in a Web Browser? To make the UI Coding a little easier?

We have previously created a simple LVGL App with Zig for PinePhone...

Zig natively supports WebAssembly...

So we might run Zig + JavaScript in a Web Browser like so...

But LVGL doesn't work with JavaScript yet. LVGL runs in a Web Browser by compiling with Emscripten and SDL...

Therefore we shall do this...

  1. Use Zig to compile LVGL from C to WebAssembly (With zig cc)

  2. Use Zig to connect the JavaScript UI (canvas rendering + input events) to LVGL WebAssembly (Like this)

WebAssembly Demo with Zig and JavaScript

We can run Zig (WebAssembly) + JavaScript in a Web Browser like so...

Let's run a simple demo...

To compile Zig to WebAssembly...

git clone --recursive https://github.com/lupyuen/pinephone-lvgl-zig
cd pinephone-lvgl-zig
cd demo
zig build-lib \
  madelbrot.zig \
  -target wasm32-freestanding \
  -dynamic \
  -rdynamic

(According to this)

This produces the Compiled WebAssembly mandelbrot.wasm.

Start a Local Web Server. (Like Web Server for Chrome)

Browse to demo/demo.html. We should see the Mandelbrot Set yay!

Mandelbrot Set rendered with Zig and WebAssembly

Import JavaScript Functions into Zig

How do we import JavaScript Functions into our Zig Program?

This is documented here...

In our Zig Program, this is how we import and call a JavaScript Function: demo/madelbrot.zig

// extern functions refer to the exterior JS namespace
// when importing wasm code, the `print` func must be provided
extern fn print(i32) void;
...
// Test printing to JavaScript Console.
// Warning: This is slow!
if (iterations == 1) { print(iterations); }

We define the JavaScript Function print when loading the WebAssembly Module in our JavaScript: demo/game.js

// On Loading the WebAssembly Module...
request.onload = function() {
  var bytes = request.response;
  WebAssembly.instantiate(bytes, {
    // JavaScript Environment exported to Zig
    env: {
      // JavaScript Print Function exported to Zig
      print: function(x) { console.log(x); }
    }
  }).then(result => {
    // Store references to Zig functions
    Game = result.instance.exports;

    // Start the Main Loop
    main();
  });
};

Will this work for passing Strings and Buffers as parameters?

Nope, the parameter will be passed as a number. (Probably a WebAssembly Data Address)

To pass Strings and Buffers between JavaScript and Zig, see daneelsan/zig-wasm-logger and mitchellh/zig-js

TODO: Change request.onload to fetch (Like this)

Compile Zig LVGL App to WebAssembly

Does our Zig LVGL App lvgltest.zig compile to WebAssembly?

Let's take the earlier steps to compile our Zig LVGL App lvgltest.zig. To compile for WebAssembly, we change...

  • zig build-obj to zig build-lib

  • Target becomes -target wasm32-freestanding

  • Remove -mcpu

  • Add -dynamic and -rdynamic

Like this...

  ## Compile the Zig App for WebAssembly 
  ## TODO: Change ".." to your NuttX Project Directory
  zig build-lib \
    --verbose-cimport \
    -target wasm32-freestanding \
    -dynamic \
    -rdynamic \
    -isystem "../nuttx/include" \
    -I "../apps/include" \
    -I "../apps/graphics/lvgl" \
    -I "../apps/graphics/lvgl/lvgl/src/core" \
    -I "../apps/graphics/lvgl/lvgl/src/draw" \
    -I "../apps/graphics/lvgl/lvgl/src/draw/arm2d" \
    -I "../apps/graphics/lvgl/lvgl/src/draw/nxp" \
    -I "../apps/graphics/lvgl/lvgl/src/draw/nxp/pxp" \
    -I "../apps/graphics/lvgl/lvgl/src/draw/nxp/vglite" \
    -I "../apps/graphics/lvgl/lvgl/src/draw/sdl" \
    -I "../apps/graphics/lvgl/lvgl/src/draw/stm32_dma2d" \
    -I "../apps/graphics/lvgl/lvgl/src/draw/sw" \
    -I "../apps/graphics/lvgl/lvgl/src/draw/swm341_dma2d" \
    -I "../apps/graphics/lvgl/lvgl/src/font" \
    -I "../apps/graphics/lvgl/lvgl/src/hal" \
    -I "../apps/graphics/lvgl/lvgl/src/misc" \
    -I "../apps/graphics/lvgl/lvgl/src/widgets" \
    lvgltest.zig

(According to this)

OK no errors, this produces the Compiled WebAssembly lvgltest.wasm.

Now we tweak lvgltest.zig for WebAssembly, and call it lvglwasm.zig...

  ## Compile the Zig App for WebAssembly 
  ## TODO: Change ".." to your NuttX Project Directory
  zig build-lib \
    --verbose-cimport \
    -target wasm32-freestanding \
    -dynamic \
    -isystem "../nuttx/include" \
    -I "../apps/include" \
    -I "../apps/graphics/lvgl" \
    -I "../apps/graphics/lvgl/lvgl/src/core" \
    -I "../apps/graphics/lvgl/lvgl/src/draw" \
    -I "../apps/graphics/lvgl/lvgl/src/draw/arm2d" \
    -I "../apps/graphics/lvgl/lvgl/src/draw/nxp" \
    -I "../apps/graphics/lvgl/lvgl/src/draw/nxp/pxp" \
    -I "../apps/graphics/lvgl/lvgl/src/draw/nxp/vglite" \
    -I "../apps/graphics/lvgl/lvgl/src/draw/sdl" \
    -I "../apps/graphics/lvgl/lvgl/src/draw/stm32_dma2d" \
    -I "../apps/graphics/lvgl/lvgl/src/draw/sw" \
    -I "../apps/graphics/lvgl/lvgl/src/draw/swm341_dma2d" \
    -I "../apps/graphics/lvgl/lvgl/src/font" \
    -I "../apps/graphics/lvgl/lvgl/src/hal" \
    -I "../apps/graphics/lvgl/lvgl/src/misc" \
    -I "../apps/graphics/lvgl/lvgl/src/widgets" \
    lvglwasm.zig

(According to this)

This produces the Compiled WebAssembly lvglwasm.wasm.

Start a Local Web Server. (Like Web Server for Chrome)

Browse to our HTML lvglwasm.html. Which calls our JavaScript lvglwasm.js to load the Compiled WebAssembly.

Our JavaScript lvglwasm.js calls the Zig Function lv_demo_widgets that's exported to WebAssembly by our Zig App lvglwasm.zig.

But the WebAssembly won't load because we haven't fixed the WebAssembly Imports...

Fix WebAssembly Imports

What happens if we don't fix the WebAssembly Imports in our Zig Program?

Suppose we forgot to import puts(). JavaScript Console will show this error when the Web Browser loads our Zig WebAssembly...

Uncaught (in promise) LinkError:
WebAssembly.instantiate():
Import #0 module="env" function="puts" error:
function import requires a callable

But we haven't compiled the LVGL Library to WebAssembly!

Yep that's why LVGL Functions like lv_label_create are failing when the Web Browser loads our Zig WebAssembly...

Uncaught (in promise) LinkError:
WebAssembly.instantiate():
Import #1 module="env" function="lv_label_create" error:
function import requires a callable

We need to compile the LVGL Library with zig cc and link it in...

Compile LVGL to WebAssembly with Zig Compiler

How to compile LVGL from C to WebAssembly with Zig Compiler?

We'll use zig cc, since Zig can compile C programs to WebAssembly.

In the previous section, we're missing the LVGL Function lv_label_create in our Zig WebAssembly Module.

lv_label_create is defined in this file...

apps/lvgl/src/widgets/lv_label.c

According to make --trace, lv_label.c is compiled with...

## Compile LVGL in C
## TODO: Change "../../.." to your NuttX Project Directory
cd apps/graphics/lvgl
aarch64-none-elf-gcc \
  -c \
  -fno-common \
  -Wall \
  -Wstrict-prototypes \
  -Wshadow \
  -Wundef \
  -Werror \
  -Os \
  -fno-strict-aliasing \
  -fomit-frame-pointer \
  -ffunction-sections \
  -fdata-sections \
  -g \
  -march=armv8-a \
  -mtune=cortex-a53 \
  -isystem ../../../nuttx/include \
  -D__NuttX__  \
  -pipe \
  -I ../../../apps/graphics/lvgl \
  -I "../../../apps/include" \
  -Wno-format \
  -Wno-format-security \
  -Wno-unused-variable \
  "-I./lvgl/src/core" \
  "-I./lvgl/src/draw" \
  "-I./lvgl/src/draw/arm2d" \
  "-I./lvgl/src/draw/nxp" \
  "-I./lvgl/src/draw/nxp/pxp" \
  "-I./lvgl/src/draw/nxp/vglite" \
  "-I./lvgl/src/draw/sdl" \
  "-I./lvgl/src/draw/stm32_dma2d" \
  "-I./lvgl/src/draw/sw" \
  "-I./lvgl/src/draw/swm341_dma2d" \
  "-I./lvgl/src/font" \
  "-I./lvgl/src/hal" \
  "-I./lvgl/src/misc" \
  "-I./lvgl/src/widgets" \
  "-DLV_ASSERT_HANDLER=ASSERT(0);" \
  ./lvgl/src/widgets/lv_label.c \
  -o  lv_label.c.Users.Luppy.PinePhone.wip-nuttx.apps.graphics.lvgl.o

Let's use the Zig Compiler to compile lv_label.c from C to WebAssembly....

  • Change aarch64-none-elf-gcc to zig cc

  • Remove -march, -mtune

  • Add the target -target wasm32-freestanding

  • Add -dynamic and -rdynamic

  • Add -lc (because we're calling C Standard Library)

  • Add -DFAR= (because we won't need Far Pointers)

  • Add -DLV_USE_LOG=1 (to enable logging)

  • Add -DLV_LOG_LEVEL=LV_LOG_LEVEL_TRACE (for detailed logging)

  • Add -DLV_MEM_SIZE=1000000 (for 1,000,000 bytes of dynamically-allocated memory)

  • Change "-DLV_ASSERT_HANDLER..." to...

    "-DLV_ASSERT_HANDLER={void lv_assert_handler(void); lv_assert_handler();}"
    

    (To handle Assertion Failures ourselves)

  • Change the output to...

    -o ../../../pinephone-lvgl-zig/lv_label.o`
    

Like this...

## Compile LVGL from C to WebAssembly
## TODO: Change "../../.." to your NuttX Project Directory
cd apps/graphics/lvgl
zig cc \
  -target wasm32-freestanding \
  -dynamic \
  -rdynamic \
  -lc \
  -DFAR= \
  -DLV_USE_LOG=1 \
  -DLV_LOG_LEVEL=LV_LOG_LEVEL_TRACE \
  -DLV_MEM_SIZE=1000000 \
  "-DLV_ASSERT_HANDLER={void lv_assert_handler(void); lv_assert_handler();}" \
  -c \
  -fno-common \
  -Wall \
  -Wstrict-prototypes \
  -Wshadow \
  -Wundef \
  -Werror \
  -Os \
  -fno-strict-aliasing \
  -fomit-frame-pointer \
  -ffunction-sections \
  -fdata-sections \
  -g \
  -isystem ../../../nuttx/include \
  -D__NuttX__  \
  -pipe \
  -I ../../../apps/graphics/lvgl \
  -I "../../../apps/include" \
  -Wno-format \
  -Wno-format-security \
  -Wno-unused-variable \
  "-I./lvgl/src/core" \
  "-I./lvgl/src/draw" \
  "-I./lvgl/src/draw/arm2d" \
  "-I./lvgl/src/draw/nxp" \
  "-I./lvgl/src/draw/nxp/pxp" \
  "-I./lvgl/src/draw/nxp/vglite" \
  "-I./lvgl/src/draw/sdl" \
  "-I./lvgl/src/draw/stm32_dma2d" \
  "-I./lvgl/src/draw/sw" \
  "-I./lvgl/src/draw/swm341_dma2d" \
  "-I./lvgl/src/font" \
  "-I./lvgl/src/hal" \
  "-I./lvgl/src/misc" \
  "-I./lvgl/src/widgets" \
  ./lvgl/src/widgets/lv_label.c \
  -o ../../../pinephone-lvgl-zig/lv_label.o

This produces the Compiled WebAssembly lv_label.o.

Will Zig Compiler let us link lv_label.o with our Zig LVGL App?

Let's ask Zig Compiler to link lv_label.o with our Zig LVGL App lvglwasm.zig...

  ## Compile the Zig App for WebAssembly 
  ## TODO: Change ".." to your NuttX Project Directory
  zig build-lib \
    --verbose-cimport \
    -target wasm32-freestanding \
    -dynamic \
    -rdynamic \
    -lc \
    -DFAR= \
    -DLV_USE_LOG=1 \
    -DLV_LOG_LEVEL=LV_LOG_LEVEL_TRACE \
    -DLV_MEM_SIZE=1000000 \
    "-DLV_ASSERT_HANDLER={void lv_assert_handler(void); lv_assert_handler();}" \
    -I . \
    -isystem "../nuttx/include" \
    -I "../apps/include" \
    -I "../apps/graphics/lvgl" \
    -I "../apps/graphics/lvgl/lvgl/src/core" \
    -I "../apps/graphics/lvgl/lvgl/src/draw" \
    -I "../apps/graphics/lvgl/lvgl/src/draw/arm2d" \
    -I "../apps/graphics/lvgl/lvgl/src/draw/nxp" \
    -I "../apps/graphics/lvgl/lvgl/src/draw/nxp/pxp" \
    -I "../apps/graphics/lvgl/lvgl/src/draw/nxp/vglite" \
    -I "../apps/graphics/lvgl/lvgl/src/draw/sdl" \
    -I "../apps/graphics/lvgl/lvgl/src/draw/stm32_dma2d" \
    -I "../apps/graphics/lvgl/lvgl/src/draw/sw" \
    -I "../apps/graphics/lvgl/lvgl/src/draw/swm341_dma2d" \
    -I "../apps/graphics/lvgl/lvgl/src/font" \
    -I "../apps/graphics/lvgl/lvgl/src/hal" \
    -I "../apps/graphics/lvgl/lvgl/src/misc" \
    -I "../apps/graphics/lvgl/lvgl/src/widgets" \
    lvglwasm.zig \
    lv_label.o

(Source)

Now we see this error in the Web Browser...

Uncaught (in promise) LinkError: 
WebAssembly.instantiate(): 
Import #0 module="env" function="lv_obj_clear_flag" error:
function import requires a callable

lv_label_create is no longer missing, because Zig Compiler has linked lv_label.o into our Zig LVGL App.

Yep Zig Compiler will happily link WebAssembly Object Files with our Zig App yay!

Now we need to compile lv_obj_clear_flag and the other LVGL Files from C to WebAssembly with Zig Compiler...

Compile Entire LVGL Library to WebAssembly

When we track down lv_obj_clear_flag and the other Missing Functions (by sheer tenacity), we get this trail of LVGL Source Files that need to be compiled from C to WebAssembly...

widgets/lv_label.c
core/lv_obj.c
misc/lv_mem.c
core/lv_event.c
core/lv_obj_style.c
core/lv_obj_pos.c
misc/lv_txt.c
draw/lv_draw_label.c
core/lv_obj_draw.c
misc/lv_area.c
core/lv_obj_scroll.c
font/lv_font.c
core/lv_obj_class.c
(And many more)

(Based on LVGL 8.3.3)

So we wrote a script to compile the above LVGL Source Files from C to WebAssembly with zig cc...

## Build the LVGL App (in Zig) and LVGL Library (in C) for PinePhone and WebAssembly
## TODO: Change ".." to your NuttX Project Directory
function build_zig {
## Check that NuttX Build has completed and `lv_demo_widgets.*.o` exists
if [ ! -f ../apps/graphics/lvgl/lvgl/demos/widgets/lv_demo_widgets.*.o ]
then
echo "*** Error: Build NuttX first before building Zig app"
exit 1
fi
## Compile our LVGL Display Driver from C to WebAssembly with Zig Compiler
compile_lvgl ../../../../../pinephone-lvgl-zig/display.c display.o
## Compile LVGL Library from C to WebAssembly with Zig Compiler
compile_lvgl widgets/lv_label.c lv_label.o
compile_lvgl core/lv_obj.c lv_obj.o
compile_lvgl misc/lv_mem.c lv_mem.o
compile_lvgl core/lv_event.c lv_event.o
compile_lvgl core/lv_obj_style.c lv_obj_style.o
compile_lvgl core/lv_obj_pos.c lv_obj_pos.o
compile_lvgl misc/lv_txt.c lv_txt.o
compile_lvgl draw/lv_draw_label.c lv_draw_label.o
compile_lvgl core/lv_obj_draw.c lv_obj_draw.o
compile_lvgl misc/lv_area.c lv_area.o
compile_lvgl core/lv_obj_scroll.c lv_obj_scroll.o
compile_lvgl font/lv_font.c lv_font.o
compile_lvgl core/lv_obj_class.c lv_obj_class.o
compile_lvgl core/lv_obj_tree.c lv_obj_tree.o
compile_lvgl hal/lv_hal_disp.c lv_hal_disp.o
compile_lvgl misc/lv_anim.c lv_anim.o
compile_lvgl misc/lv_tlsf.c lv_tlsf.o
compile_lvgl core/lv_group.c lv_group.o
compile_lvgl core/lv_indev.c lv_indev.o
compile_lvgl draw/lv_draw_rect.c lv_draw_rect.o
compile_lvgl draw/lv_draw_mask.c lv_draw_mask.o
compile_lvgl misc/lv_style.c lv_style.o
compile_lvgl misc/lv_ll.c lv_ll.o
compile_lvgl core/lv_obj_style_gen.c lv_obj_style_gen.o
compile_lvgl misc/lv_timer.c lv_timer.o
compile_lvgl core/lv_disp.c lv_disp.o
compile_lvgl core/lv_refr.c lv_refr.o
compile_lvgl misc/lv_color.c lv_color.o
compile_lvgl draw/lv_draw_line.c lv_draw_line.o
compile_lvgl draw/lv_draw_img.c lv_draw_img.o
compile_lvgl misc/lv_math.c lv_math.o
compile_lvgl hal/lv_hal_indev.c lv_hal_indev.o
compile_lvgl core/lv_theme.c lv_theme.o
compile_lvgl hal/lv_hal_tick.c lv_hal_tick.o
compile_lvgl misc/lv_log.c lv_log.o
compile_lvgl misc/lv_printf.c lv_printf.o
compile_lvgl misc/lv_fs.c lv_fs.o
compile_lvgl draw/lv_draw.c lv_draw.o
compile_lvgl draw/lv_img_decoder.c lv_img_decoder.o
compile_lvgl extra/lv_extra.c lv_extra.o
compile_lvgl extra/layouts/flex/lv_flex.c lv_flex.o
compile_lvgl extra/layouts/grid/lv_grid.c lv_grid.o
compile_lvgl draw/sw/lv_draw_sw.c lv_draw_sw.o
compile_lvgl draw/sw/lv_draw_sw_rect.c lv_draw_sw_rect.o
compile_lvgl draw/lv_img_cache.c lv_img_cache.o
compile_lvgl draw/lv_img_buf.c lv_img_buf.o
compile_lvgl draw/sw/lv_draw_sw_arc.c lv_draw_sw_arc.o
compile_lvgl draw/sw/lv_draw_sw_letter.c lv_draw_sw_letter.o
compile_lvgl draw/sw/lv_draw_sw_blend.c lv_draw_sw_blend.o
compile_lvgl draw/sw/lv_draw_sw_layer.c lv_draw_sw_layer.o
compile_lvgl draw/sw/lv_draw_sw_transform.c lv_draw_sw_transform.o
compile_lvgl draw/sw/lv_draw_sw_polygon.c lv_draw_sw_polygon.o
compile_lvgl draw/sw/lv_draw_sw_line.c lv_draw_sw_line.o
compile_lvgl draw/sw/lv_draw_sw_img.c lv_draw_sw_img.o
compile_lvgl draw/sw/lv_draw_sw_gradient.c lv_draw_sw_gradient.o
compile_lvgl draw/lv_draw_transform.c lv_draw_transform.o
compile_lvgl extra/themes/default/lv_theme_default.c lv_theme_default.o
compile_lvgl font/lv_font_fmt_txt.c lv_font_fmt_txt.o
compile_lvgl draw/lv_draw_layer.c lv_draw_layer.o
compile_lvgl misc/lv_style_gen.c lv_style_gen.o
## Compile the Zig LVGL App for WebAssembly
## TODO: Change ".." to your NuttX Project Directory
## TODO: Try `zig build-exe` to fix `strlen` missing
zig build-lib \
--verbose-cimport \
-target wasm32-freestanding \
-dynamic \
-rdynamic \
-lc \
-DFAR= \
-DLV_USE_LOG \
-DLV_LOG_LEVEL=LV_LOG_LEVEL_TRACE \
"-DLV_ASSERT_HANDLER={void lv_assert_handler(void); lv_assert_handler();}" \
-I . \
\
-isystem "../nuttx/include" \
-I "../apps/include" \
-I "../apps/graphics/lvgl" \
-I "../apps/graphics/lvgl/lvgl/src/core" \
-I "../apps/graphics/lvgl/lvgl/src/draw" \
-I "../apps/graphics/lvgl/lvgl/src/draw/arm2d" \
-I "../apps/graphics/lvgl/lvgl/src/draw/nxp" \
-I "../apps/graphics/lvgl/lvgl/src/draw/nxp/pxp" \
-I "../apps/graphics/lvgl/lvgl/src/draw/nxp/vglite" \
-I "../apps/graphics/lvgl/lvgl/src/draw/sdl" \
-I "../apps/graphics/lvgl/lvgl/src/draw/stm32_dma2d" \
-I "../apps/graphics/lvgl/lvgl/src/draw/sw" \
-I "../apps/graphics/lvgl/lvgl/src/draw/swm341_dma2d" \
-I "../apps/graphics/lvgl/lvgl/src/font" \
-I "../apps/graphics/lvgl/lvgl/src/hal" \
-I "../apps/graphics/lvgl/lvgl/src/misc" \
-I "../apps/graphics/lvgl/lvgl/src/widgets" \
\
lvglwasm.zig \
display.o \
lv_label.o \
lv_mem.o \
lv_obj.o \
lv_event.o \
lv_obj_style.o \
lv_obj_pos.o \
lv_txt.o \
lv_draw_label.o \
lv_obj_draw.o \
lv_area.o \
lv_obj_scroll.o \
lv_font.o \
lv_obj_class.o \
lv_obj_tree.o \
lv_hal_disp.o \
lv_anim.o \
lv_tlsf.o \
lv_group.o \
lv_indev.o \
lv_draw_rect.o \
lv_draw_mask.o \
lv_style.o \
lv_ll.o \
lv_obj_style_gen.o \
lv_timer.o \
lv_disp.o \
lv_refr.o \
lv_color.o \
lv_draw_line.o \
lv_draw_img.o \
lv_math.o \
lv_hal_indev.o \
lv_theme.o \
lv_hal_tick.o \
lv_log.o \
lv_printf.o \
lv_fs.o \
lv_draw.o \
lv_img_decoder.o \
lv_extra.o \
lv_flex.o \
lv_grid.o \
lv_draw_sw.o \
lv_draw_sw_rect.o \
lv_img_cache.o \
lv_img_buf.o \
lv_draw_sw_arc.o \
lv_draw_sw_letter.o \
lv_draw_sw_blend.o \
lv_draw_sw_layer.o \
lv_draw_sw_transform.o \
lv_draw_sw_polygon.o \
lv_draw_sw_line.o \
lv_draw_sw_img.o \
lv_draw_sw_gradient.o \
lv_draw_transform.o \
lv_theme_default.o \
lv_font_fmt_txt.o \
lv_draw_layer.o \
lv_style_gen.o \

Which calls compile_lvgl to compile a single LVGL Source File from C to WebAssembly with zig cc...

pinephone-lvgl-zig/build.sh

Lines 212 to 267 in 1c7a3fe

## Compile LVGL Library from C to WebAssembly with Zig Compiler
## TODO: Change ".." to your NuttX Project Directory
function compile_lvgl {
local source_file=$1 ## Input Source File (LVGL in C)
local object_file=$2 ## Output Object File (WebAssembly)
pushd ../apps/graphics/lvgl
zig cc \
-target wasm32-freestanding \
-dynamic \
-rdynamic \
-lc \
-DFAR= \
-DLV_USE_LOG \
-DLV_LOG_LEVEL=LV_LOG_LEVEL_TRACE \
"-DLV_ASSERT_HANDLER={void lv_assert_handler(void); lv_assert_handler();}" \
\
-c \
-fno-common \
-Wall \
-Wstrict-prototypes \
-Wshadow \
-Wundef \
-Werror \
-Os \
-fno-strict-aliasing \
-fomit-frame-pointer \
-ffunction-sections \
-fdata-sections \
-g \
-isystem ../../../nuttx/include \
-D__NuttX__ \
-pipe \
-I ../../../apps/graphics/lvgl \
-I "../../../apps/include" \
-Wno-format \
-Wno-format-security \
-Wno-unused-variable \
"-I./lvgl/src/core" \
"-I./lvgl/src/draw" \
"-I./lvgl/src/draw/arm2d" \
"-I./lvgl/src/draw/nxp" \
"-I./lvgl/src/draw/nxp/pxp" \
"-I./lvgl/src/draw/nxp/vglite" \
"-I./lvgl/src/draw/sdl" \
"-I./lvgl/src/draw/stm32_dma2d" \
"-I./lvgl/src/draw/sw" \
"-I./lvgl/src/draw/swm341_dma2d" \
"-I./lvgl/src/font" \
"-I./lvgl/src/hal" \
"-I./lvgl/src/misc" \
"-I./lvgl/src/widgets" \
lvgl/src/$source_file \
-o ../../../pinephone-lvgl-zig/$object_file
popd
}

What happens after we compile the whole bunch of LVGL Source Files from C to WebAssembly?

Now the Web Browser says that strlen is missing...

Uncaught (in promise) LinkError: 
WebAssembly.instantiate(): 
Import #0 module="env" function="strlen" error: 
function import requires a callable

Let's fix strlen...

C Standard Library is Missing

But strlen should come from the C Standard Library! (musl)

Not sure why strlen is missing, but we fixed it temporarily by copying from the Zig Library Source Code...

///////////////////////////////////////////////////////////////////////////////
// C Standard Library
// From zig-macos-x86_64-0.10.0-dev.2351+b64a1d5ab/lib/zig/c.zig
export fn memset(dest: ?[*]u8, c2: u8, len: usize) callconv(.C) ?[*]u8 {
@setRuntimeSafety(false);
if (len != 0) {
var d = dest.?;
var n = len;
while (true) {
d.* = c2;
n -= 1;
if (n == 0) break;
d += 1;
}
}
return dest;
}
export fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, len: usize) callconv(.C) ?[*]u8 {
@setRuntimeSafety(false);
if (len != 0) {
var d = dest.?;
var s = src.?;
var n = len;
while (true) {
d[0] = s[0];
n -= 1;
if (n == 0) break;
d += 1;
s += 1;
}
}
return dest;
}
export fn strcpy(dest: [*:0]u8, src: [*:0]const u8) callconv(.C) [*:0]u8 {
var i: usize = 0;
while (src[i] != 0) : (i += 1) {
dest[i] = src[i];
}
dest[i] = 0;
return dest;
}
export fn strlen(s: [*:0]const u8) callconv(.C) usize {
return std.mem.len(s);
}

This seems to be the same problem mentioned here.

(Referenced by this pull request)

(And this issue)

TODO: Maybe because we didn't export strlen in our Main Program lvglwasm.zig?

TODO: Do we compile C Standard Library ourselves? From musl? Newlib? wasi-libc?

What if we change the target to wasm32-freestanding-musl?

Nope doesn't help, same problem.

What if we use zig build-exe instead of zig build-lib?

Sorry zig build-exe is meant for building WASI Executables. (See this)

zig build-exe is not supposed to work for WebAssembly in the Web Browser. (See this)

LVGL Porting Layer for WebAssembly

LVGL expects us to provide a millis function that returns the number of elapsed milliseconds...

Uncaught (in promise) LinkError: 
WebAssembly.instantiate(): 
Import #0 module="env" function="millis" error: 
function import requires a callable

We implement millis ourselves for WebAssembly...

///////////////////////////////////////////////////////////////////////////////
// LVGL Porting Layer for WebAssembly
/// TODO: Return the number of elapsed milliseconds
export fn millis() u32 {
elapsed_ms += 1;
return elapsed_ms;
}
/// Number of elapsed milliseconds
var elapsed_ms: u32 = 0;
/// On Assertion Failure, print a Stack Trace and halt
export fn lv_assert_handler() void {
@panic("*** lv_assert_handler: ASSERTION FAILED");
}
/// Custom Logger for LVGL that writes to JavaScript Console
export fn custom_logger(buf: [*c]const u8) void {
wasmlog.Console.log("{s}", .{buf});
}

TODO: Fix millis. How would it work in WebAssembly? Using a counter?

WebAssembly Logger for LVGL

Let's trace the LVGL Execution with a WebAssembly Logger.

(Remember: printf won't work in WebAssembly)

We set the Custom Logger for LVGL, so that we can print Log Messages to the JavaScript Console...

///////////////////////////////////////////////////////////////////////////////
// Main Function
/// We render an LVGL Screen with LVGL Widgets
pub export fn lv_demo_widgets() void {
// TODO: Change to `debug`
wasmlog.Console.log("lv_demo_widgets: start", .{});
defer wasmlog.Console.log("lv_demo_widgets: end", .{});
// Set the Custom Logger for LVGL
c.lv_log_register_print_cb(custom_logger);

The Custom Logger is defined in our Zig Program...

/// Custom Logger for LVGL that writes to JavaScript Console
export fn custom_logger(buf: [*c]const u8) void {
wasmlog.Console.log("custom_logger: {s}", .{buf});
}

wasmlog is our Zig Logger for WebAssembly: wasmlog.zig

(Based on daneelsan/zig-wasm-logger)

jsConsoleLogWrite and jsConsoleLogFlush are defined in our JavaScript...

// On Loading the WebAssembly Module...
request.onload = function() {
var bytes = request.response;
WebAssembly.instantiate(bytes, {
// JavaScript Environment exported to Zig
env: {
// JavaScript Print Function exported to Zig
print: function(x) { console.log(x); },
// Write to JavaScript Console from Zig
jsConsoleLogWrite: function (ptr, len) {
console_log_buffer += wasm.getString(ptr, len);
},
// Flush JavaScript Console from Zig
jsConsoleLogFlush: function () {
console.log(console_log_buffer);
console_log_buffer = "";
},
}
}).then(result => {
// Store references to WebAssembly Functions and Memory exported by Zig
Game = result.instance.exports;
wasm.init(result);
// Start the Main Loop
main();
});
};

wasm.getString also comes from our JavaScript...

// Log WebAssembly Messages from Zig to JavaScript Console
const text_decoder = new TextDecoder();
let console_log_buffer = "";
let wasm = {
// WebAssembly Instance
instance: undefined,
// Init the WebAssembly Instance
init: function (obj) {
this.instance = obj.instance;
},
// Fetch the Zig String from a WebAssembly Pointer
getString: function (ptr, len) {
const memory = this.instance.exports.memory;
return text_decoder.decode(
new Uint8Array(memory.buffer, ptr, len)
);
},
};

Now we can see the LVGL Log Messages in the JavaScript Console yay! (Pic below)

custom_logger: [Warn]	(0.001, +1)
lv_disp_get_scr_act:
no display registered to get its active screen
(in lv_disp.c line #54)

Let's initialise the LVGL Display...

WebAssembly Logger for LVGL

Initialise LVGL Display

According to the LVGL Docs, this is how we inititialise and operate LVGL...

  1. Call lv_init()

  2. Register the LVGL Display and LVGL Input Devices

  3. Call lv_tick_inc(x) every x milliseconds in an interrupt to report the elapsed time to LVGL

  4. Call lv_timer_handler() every few milliseconds to handle LVGL related tasks

(Source)

To register the LVGL Display, we should do this...

But we can't do this in Zig...

// Nope! lv_disp_drv_t is an Opaque Type
var disp_drv = c.lv_disp_drv_t{};
c.lv_disp_drv_init(&disp_drv);

Because lv_disp_drv_t is an Opaque Type.

(lv_disp_drv_t contains Bit Fields, hence it's Opaque)

Thus we apply this workaround to create lv_disp_drv_t in C...

And we get this LVGL Display Interface for Zig: display.c

Finally this is how we initialise the LVGL Display in Zig WebAssembly...

pub export fn lv_demo_widgets() void {
debug("lv_demo_widgets: start", .{});
defer debug("lv_demo_widgets: end", .{});
// Set the Custom Logger for LVGL
c.lv_log_register_print_cb(custom_logger);
// Init LVGL
c.lv_init();
// Fetch pointers to Display Driver and Display Buffer
const disp_drv = c.get_disp_drv();
const disp_buf = c.get_disp_buf();
// Init Display Buffer and Display Driver as pointers
c.init_disp_buf(disp_buf);
c.init_disp_drv(disp_drv, // Display Driver
disp_buf, // Display Buffer
flushDisplay, // Callback Function to Flush Display
720, // Horizontal Resolution
1280 // Vertical Resolution
);
// Register the Display Driver
const disp = c.lv_disp_drv_register(disp_drv);
_ = disp;
// Create the widgets for display (with Zig Wrapper)
createWidgetsWrapped() catch |e| {
// In case of error, quit
std.log.err("createWidgetsWrapped failed: {}", .{e});
return;
};

LVGL Memory Allocation

What happens if we don't set -DLV_MEM_SIZE=1000000?

The LVGL Memory Allocation fails...

lv_demo_widgets: start
[Info]	lv_init: begin 	(in lv_obj.c line #102)
[Warn]	lv_init: Log level is set to 'Trace' which makes LVGL much slower 	(in lv_obj.c line #176)
[Error]	block_next: Asserted at expression: !block_is_last(block) 	(in lv_tlsf.c line #458)
lv_assert_handler: assertion failed
[Error]	block_next: Asserted at expression: !block_is_last(block) 	(in lv_tlsf.c line #458)
lv_assert_handler: assertion failed
[Trace]	lv_init: finished 	(in lv_obj.c line #183)

[Info]	lv_mem_alloc: couldn't allocate memory (106824 bytes) 	(in lv_mem.c line #140)
[Info]	lv_mem_alloc: used:   1480 (  3 %), frag:   0 %, biggest free:  64056 	(in lv_mem.c line #146)
[Error]	lv_disp_drv_register: Asserted at expression: disp != NULL (Out of memory) 	(in lv_hal_disp.c line #162)
lv_assert_handler: assertion failed

lv_mem_alloc calls lv_tlsf_malloc and fails to allocate memory.

That's because the Dynamic Memory Pool is too small: We need 106,824 bytes but only 64,056 bytes are available.

Hence we set -DLV_MEM_SIZE=1000000 in the Zig Compiler.

TODO: Why did block_next fail? (lv_tlsf.c line #458)

main: start
loop: start
lv_demo_widgets: start
before lv_init
[Info]	lv_init: begin 	(in lv_obj.c line #102)
[Trace]	lv_mem_alloc: allocating 76 bytes 	(in lv_mem.c line #127)
[Trace]	lv_mem_alloc: allocated at 0x1a700 	(in lv_mem.c line #160)
[Trace]	lv_mem_alloc: allocating 28 bytes 	(in lv_mem.c line #127)
[Trace]	lv_mem_alloc: allocated at 0x1a750 	(in lv_mem.c line #160)
[Warn]	lv_init: Log level is set to 'Trace' which makes LVGL much slower 	(in lv_obj.c line #176)
[Trace]	lv_mem_realloc: reallocating 0x14 with 8 size 	(in lv_mem.c line #196)
[Error]	block_next: Asserted at expression: !block_is_last(block) 	(in lv_tlsf.c line #459)

004a5b4a:0x29ab2 Uncaught (in promise) RuntimeError: unreachable
    at std.builtin.default_panic (004a5b4a:0x29ab2)
    at lv_assert_handler (004a5b4a:0x2ac6c)
    at block_next (004a5b4a:0xd5b3)
    at lv_tlsf_realloc (004a5b4a:0xe226)
    at lv_mem_realloc (004a5b4a:0x20f1)
    at lv_layout_register (004a5b4a:0x75d8)
    at lv_flex_init (004a5b4a:0x16afe)
    at lv_extra_init (004a5b4a:0x16ae5)
    at lv_init (004a5b4a:0x3f28)
    at lv_demo_widgets (004a5b4a:0x29bb9)

Two-Level Segregate Fit (TLSF) Allocator

block_next calls offset_to_block, which calls...

TODO

TODO: Why no screen found in lv_obj_get_disp?

[Trace]	lv_init: finished 	(in lv_obj.c line #183)
[Info]	lv_obj_create: begin 	(in lv_obj.c line #206)
[Warn]	lv_obj_get_disp: No screen found 	(in lv_obj_tree.c line #287)

TODO: Call lv_tick_inc and lv_timer_handler

  1. Call lv_tick_inc(x) every x milliseconds in an interrupt to report the elapsed time to LVGL

  2. Call lv_timer_handler() every few milliseconds to handle LVGL related tasks

(Source)

Render LVGL Display in Web Browser

TODO: Render LVGL Display

TODO: Use Zig to connect the JavaScript UI (canvas rendering + input events) to LVGL WebAssembly (Like this)

https://github.com/daneelsan/minimal-zig-wasm-canvas

https://github.com/daneelsan/Dodgeballz/tree/master/src

https://github.com/daneelsan/zig-wefx/blob/master/wefx/WEFX.zig

Zig with Rancher Desktop

The Official Zig Download for macOS no longer runs on my 10-year-old MacBook Pro that's stuck on macOS 10.15.7. 😢

To run the latest version of Zig Compiler, I use Rancher Desktop and VSCode Remote Containers...

Here's how...

  1. Install Rancher Desktop

  2. In Rancher Desktop, click "Settings"...

    Set "Container Engine" to "dockerd (moby)"

    Under "Kubernetes", uncheck "Enable Kubernetes"

    (To reduce CPU Utilisation)

  3. Restart VSCode to use the new PATH

    Install the VSCode Docker Extension

    In VSCode, click the Docker icon in the Left Bar

  4. Under "Containers", click "+" and "New Dev Container"

    Select "Alpine"

  5. In a while, we'll see VSCode running inside the Alpine Linux Container

    We have finally Linux on macOS!

    $ uname -a
    Linux bc0c45900671 5.15.96-0-virt #1-Alpine SMP Sun, 26 Feb 2023 15:14:12 +0000 x86_64 GNU/Linux
    
  6. Now we can download and run the latest and greatest Zig Compiler for Linux x64 (from here)

    wget https://ziglang.org/builds/zig-linux-x86_64-0.11.0-dev.3283+7cb3a6750.tar.xz
    tar -xvf zig-linux-x86_64-0.11.0-dev.3283+7cb3a6750.tar.xz 
    zig-linux-x86_64-0.11.0-dev.3283+7cb3a6750/zig version
  7. To install the NuttX Toolchain on Alpine Linux...

    "Build Apache NuttX RTOS on Alpine Linux"

  8. To forward Network Ports, click the "Ports" tab beside "Terminal"

    To configure other features in the Alpine Linux Container, edit the file .devcontainer/devcontainer.json

Zig Version

(Here's what happens if we don't run Zig in a Container)

Which version of Zig are we using?

We're using an older version: 0.10.0-dev.2351+b64a1d5ab

Sadly Zig 0.10.1 won't run on my 10-year-old MacBook Pro that's stuck on macOS 10.15.7 😢

→ #  Compile the Zig App for PinePhone
  #  (armv8-a with cortex-a53)
  #  TODO: Change ".." to your NuttX Project Directory
  zig build-obj \
    --verbose-cimport \
    -target aarch64-freestanding-none \
    -mcpu cortex_a53 \
    -isystem "../nuttx/include" \
    -I "../apps/include" \
    lvgltest.zig

dyld: lazy symbol binding faileddyld: lazy symbol binding faileddyld: lazy symbol binding failed: Symbol not found: ___ulock_wai: Symbol not found: ___ulock_wait2
  Referenced from: /Users/Lupt2
  Referenced from: /Users/Lupdyld: lazy symbol binding failedpy/zig-macos-x86_64-0.10.1/zig (py/zig-macos-x86_64-0.10.1/zig (dyld: lazy symbol binding failedwhich was built for Mac OS X 11.: Symbol not found: ___ulock_wai: Symbol not found: ___ulock_waiwhich was built for Mac OS X 11.7)
  Expected in: /usr/lib/libSy: Symbol not found: ___ulock_wai7)
  Expected in: /usr/lib/libSystem.B.dylib

stem.B.dylib

t2
  Referenced from: /Users/Lupt2
  Referenced from: /Users/Lupt2
  Referenced from: /Users/Luppy/zig-macos-x86_64-0.10.1/zig (py/zig-macos-x86_64-0.10.1/zig (py/zig-macos-x86_64-0.10.1/zig (which was built for Mac OS X 11.which was built for Mac OS X 11.which was built for Mac OS X 11.7)
  Expected in: /usr/lib/libSy7)
  Expected in: /usr/lib/libSydyld: Symbol not found: ___ulock7)
  Expected in: /usr/lib/libSystem.B.dylib

stem.B.dylib

_wait2
  Referenced from: /Usersstem.B.dylib

/Luppy/zig-macos-x86_64-0.10.1/zdyld: Symbol not found: ___ulockig (which was built for Mac OS X_wait2
  Referenced from: /Users 11.7)
  Expected in: /usr/lib/ldyld: Symbol not found: ___ulockdyld: Symbol not found: ___ulock/Luppy/zig-macos-x86_64-0.10.1/zibSystem.B.dylib

_wait2
  Referenced from: /Usersig (which was built for Mac OS X_wait2
  Referenced from: /Users/Luppy/zig-macos-x86_64-0.10.1/z 11.7)
  Expected in: /usr/lib/l/Luppy/zig-macos-x86_64-0.10.1/zig (which was built for Mac OS XibSystem.B.dylib

ig (which was built for Mac OS X 11.7)
  Expected in: /usr/lib/l 11.7)
  Expected in: /usr/lib/libSystem.B.dylib

ibSystem.B.dylib

dyld: Symbol not found: ___ulockdyld: lazy symbol binding faileddyld: lazy symbol binding failed[1]    11157 abort      zig build-obj --verbose-cimport -target aarch64-freestanding-none -mcpu    -I

I tried building Zig from source, but it didn't work either...

Build Zig from Source

The Official Zig Download for macOS no longer runs on my 10-year-old MacBook Pro that's stuck on macOS 10.15.7. (See the previous section)

So I tried building Zig from Source according to these instructions...

Here's what I did...

brew install llvm
git clone --recursive https://github.com/ziglang/zig
cd zig

mkdir build
cd build
cmake .. -DZIG_STATIC_LLVM=ON -DCMAKE_PREFIX_PATH="$(brew --prefix llvm);$(brew --prefix zstd)"
make install

brew install llvm failed...

==> cmake -G Unix Makefiles .. -DLLVM_ENABLE_PROJECTS=clang;clang-tools-extra;lld;lldb;mlir;polly -DLLVM_ENABLE_RUNTIMES=compiler-rt;libcxx;libcxxabi;libunwind;
==> cmake --build .
Last 15 lines from /Users/Luppy/Library/Logs/Homebrew/llvm/02.cmake:
[ 51%] Building CXX object lib/Transforms/Utils/CMakeFiles/LLVMTransformUtils.dir/ValueMapper.cpp.o
cd /tmp/llvm-20230523-44290-sxekyo/llvm-project-16.0.4.src/llvm/build/lib/Transforms/Utils && /usr/local/Homebrew/Library/Homebrew/shims/mac/super/clang++ -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/tmp/llvm-20230523-44290-sxekyo/llvm-project-16.0.4.src/llvm/build/lib/Transforms/Utils -I/tmp/llvm-20230523-44290-sxekyo/llvm-project-16.0.4.src/llvm/lib/Transforms/Utils -I/tmp/llvm-20230523-44290-sxekyo/llvm-project-16.0.4.src/llvm/build/include -I/tmp/llvm-20230523-44290-sxekyo/llvm-project-16.0.4.src/llvm/include -stdlib=libc++ -fPIC -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-class-memaccess -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -O3 -DNDEBUG -std=c++17 -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk -MD -MT lib/Transforms/Utils/CMakeFiles/LLVMTransformUtils.dir/ValueMapper.cpp.o -MF CMakeFiles/LLVMTransformUtils.dir/ValueMapper.cpp.o.d -o CMakeFiles/LLVMTransformUtils.dir/ValueMapper.cpp.o -c /tmp/llvm-20230523-44290-sxekyo/llvm-project-16.0.4.src/llvm/lib/Transforms/Utils/ValueMapper.cpp
[ 51%] Building CXX object lib/Transforms/Utils/CMakeFiles/LLVMTransformUtils.dir/VNCoercion.cpp.o
cd /tmp/llvm-20230523-44290-sxekyo/llvm-project-16.0.4.src/llvm/build/lib/Transforms/Utils && /usr/local/Homebrew/Library/Homebrew/shims/mac/super/clang++ -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/tmp/llvm-20230523-44290-sxekyo/llvm-project-16.0.4.src/llvm/build/lib/Transforms/Utils -I/tmp/llvm-20230523-44290-sxekyo/llvm-project-16.0.4.src/llvm/lib/Transforms/Utils -I/tmp/llvm-20230523-44290-sxekyo/llvm-project-16.0.4.src/llvm/build/include -I/tmp/llvm-20230523-44290-sxekyo/llvm-project-16.0.4.src/llvm/include -stdlib=libc++ -fPIC -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-class-memaccess -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -O3 -DNDEBUG -std=c++17 -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk -MD -MT lib/Transforms/Utils/CMakeFiles/LLVMTransformUtils.dir/VNCoercion.cpp.o -MF CMakeFiles/LLVMTransformUtils.dir/VNCoercion.cpp.o.d -o CMakeFiles/LLVMTransformUtils.dir/VNCoercion.cpp.o -c /tmp/llvm-20230523-44290-sxekyo/llvm-project-16.0.4.src/llvm/lib/Transforms/Utils/VNCoercion.cpp
[ 51%] Linking CXX static library ../../libLLVMTransformUtils.a
cd /tmp/llvm-20230523-44290-sxekyo/llvm-project-16.0.4.src/llvm/build/lib/Transforms/Utils && /usr/local/Cellar/cmake/3.26.4/bin/cmake -P CMakeFiles/LLVMTransformUtils.dir/cmake_clean_target.cmake
cd /tmp/llvm-20230523-44290-sxekyo/llvm-project-16.0.4.src/llvm/build/lib/Transforms/Utils && /usr/local/Cellar/cmake/3.26.4/bin/cmake -E cmake_link_script CMakeFiles/LLVMTransformUtils.dir/link.txt --verbose=1
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool" -static -no_warning_for_no_symbols -o ../../libLLVMTransformUtils.a CMakeFiles/LLVMTransformUtils.dir/AddDiscriminators.cpp.o CMakeFiles/LLVMTransformUtils.dir/AMDGPUEmitPrintf.cpp.o CMakeFiles/LLVMTransformUtils.dir/ASanStackFrameLayout.cpp.o CMakeFiles/LLVMTransformUtils.dir/AssumeBundleBuilder.cpp.o CMakeFiles/LLVMTransformUtils.dir/BasicBlockUtils.cpp.o CMakeFiles/LLVMTransformUtils.dir/BreakCriticalEdges.cpp.o CMakeFiles/LLVMTransformUtils.dir/BuildLibCalls.cpp.o CMakeFiles/LLVMTransformUtils.dir/BypassSlowDivision.cpp.o CMakeFiles/LLVMTransformUtils.dir/CallPromotionUtils.cpp.o CMakeFiles/LLVMTransformUtils.dir/CallGraphUpdater.cpp.o CMakeFiles/LLVMTransformUtils.dir/CanonicalizeAliases.cpp.o CMakeFiles/LLVMTransformUtils.dir/CanonicalizeFreezeInLoops.cpp.o CMakeFiles/LLVMTransformUtils.dir/CloneFunction.cpp.o CMakeFiles/LLVMTransformUtils.dir/CloneModule.cpp.o CMakeFiles/LLVMTransformUtils.dir/CodeExtractor.cpp.o CMakeFiles/LLVMTransformUtils.dir/CodeLayout.cpp.o CMakeFiles/LLVMTransformUtils.dir/CodeMoverUtils.cpp.o CMakeFiles/LLVMTransformUtils.dir/CtorUtils.cpp.o CMakeFiles/LLVMTransformUtils.dir/Debugify.cpp.o CMakeFiles/LLVMTransformUtils.dir/DemoteRegToStack.cpp.o CMakeFiles/LLVMTransformUtils.dir/EntryExitInstrumenter.cpp.o CMakeFiles/LLVMTransformUtils.dir/EscapeEnumerator.cpp.o CMakeFiles/LLVMTransformUtils.dir/Evaluator.cpp.o CMakeFiles/LLVMTransformUtils.dir/FixIrreducible.cpp.o CMakeFiles/LLVMTransformUtils.dir/FlattenCFG.cpp.o CMakeFiles/LLVMTransformUtils.dir/FunctionComparator.cpp.o CMakeFiles/LLVMTransformUtils.dir/FunctionImportUtils.cpp.o CMakeFiles/LLVMTransformUtils.dir/GlobalStatus.cpp.o CMakeFiles/LLVMTransformUtils.dir/GuardUtils.cpp.o CMakeFiles/LLVMTransformUtils.dir/HelloWorld.cpp.o CMakeFiles/LLVMTransformUtils.dir/InlineFunction.cpp.o CMakeFiles/LLVMTransformUtils.dir/InjectTLIMappings.cpp.o CMakeFiles/LLVMTransformUtils.dir/InstructionNamer.cpp.o CMakeFiles/LLVMTransformUtils.dir/IntegerDivision.cpp.o CMakeFiles/LLVMTransformUtils.dir/LCSSA.cpp.o CMakeFiles/LLVMTransformUtils.dir/LibCallsShrinkWrap.cpp.o CMakeFiles/LLVMTransformUtils.dir/Local.cpp.o CMakeFiles/LLVMTransformUtils.dir/LoopPeel.cpp.o CMakeFiles/LLVMTransformUtils.dir/LoopRotationUtils.cpp.o CMakeFiles/LLVMTransformUtils.dir/LoopSimplify.cpp.o CMakeFiles/LLVMTransformUtils.dir/LoopUnroll.cpp.o CMakeFiles/LLVMTransformUtils.dir/LoopUnrollAndJam.cpp.o CMakeFiles/LLVMTransformUtils.dir/LoopUnrollRuntime.cpp.o CMakeFiles/LLVMTransformUtils.dir/LoopUtils.cpp.o CMakeFiles/LLVMTransformUtils.dir/LoopVersioning.cpp.o CMakeFiles/LLVMTransformUtils.dir/LowerAtomic.cpp.o CMakeFiles/LLVMTransformUtils.dir/LowerGlobalDtors.cpp.o CMakeFiles/LLVMTransformUtils.dir/LowerIFunc.cpp.o CMakeFiles/LLVMTransformUtils.dir/LowerInvoke.cpp.o CMakeFiles/LLVMTransformUtils.dir/LowerMemIntrinsics.cpp.o CMakeFiles/LLVMTransformUtils.dir/LowerSwitch.cpp.o CMakeFiles/LLVMTransformUtils.dir/MatrixUtils.cpp.o CMakeFiles/LLVMTransformUtils.dir/MemoryOpRemark.cpp.o CMakeFiles/LLVMTransformUtils.dir/MemoryTaggingSupport.cpp.o CMakeFiles/LLVMTransformUtils.dir/Mem2Reg.cpp.o CMakeFiles/LLVMTransformUtils.dir/MetaRenamer.cpp.o CMakeFiles/LLVMTransformUtils.dir/MisExpect.cpp.o CMakeFiles/LLVMTransformUtils.dir/ModuleUtils.cpp.o CMakeFiles/LLVMTransformUtils.dir/NameAnonGlobals.cpp.o CMakeFiles/LLVMTransformUtils.dir/PredicateInfo.cpp.o CMakeFiles/LLVMTransformUtils.dir/PromoteMemoryToRegister.cpp.o CMakeFiles/LLVMTransformUtils.dir/RelLookupTableConverter.cpp.o CMakeFiles/LLVMTransformUtils.dir/ScalarEvolutionExpander.cpp.o CMakeFiles/LLVMTransformUtils.dir/SCCPSolver.cpp.o CMakeFiles/LLVMTransformUtils.dir/StripGCRelocates.cpp.o CMakeFiles/LLVMTransformUtils.dir/SSAUpdater.cpp.o CMakeFiles/LLVMTransformUtils.dir/SSAUpdaterBulk.cpp.o CMakeFiles/LLVMTransformUtils.dir/SampleProfileInference.cpp.o CMakeFiles/LLVMTransformUtils.dir/SampleProfileLoaderBaseUtil.cpp.o CMakeFiles/LLVMTransformUtils.dir/SanitizerStats.cpp.o CMakeFiles/LLVMTransformUtils.dir/SimplifyCFG.cpp.o CMakeFiles/LLVMTransformUtils.dir/SimplifyIndVar.cpp.o CMakeFiles/LLVMTransformUtils.dir/SimplifyLibCalls.cpp.o CMakeFiles/LLVMTransformUtils.dir/SizeOpts.cpp.o CMakeFiles/LLVMTransformUtils.dir/SplitModule.cpp.o CMakeFiles/LLVMTransformUtils.dir/StripNonLineTableDebugInfo.cpp.o CMakeFiles/LLVMTransformUtils.dir/SymbolRewriter.cpp.o CMakeFiles/LLVMTransformUtils.dir/UnifyFunctionExitNodes.cpp.o CMakeFiles/LLVMTransformUtils.dir/UnifyLoopExits.cpp.o CMakeFiles/LLVMTransformUtils.dir/Utils.cpp.o CMakeFiles/LLVMTransformUtils.dir/ValueMapper.cpp.o CMakeFiles/LLVMTransformUtils.dir/VNCoercion.cpp.o
[ 51%] Built target LLVMTransformUtils
[ 51%] Linking CXX static library ../../../libLLVMAMDGPUDisassembler.a
cd /tmp/llvm-20230523-44290-sxekyo/llvm-project-16.0.4.src/llvm/build/lib/Target/AMDGPU/Disassembler && /usr/local/Cellar/cmake/3.26.4/bin/cmake -P CMakeFiles/LLVMAMDGPUDisassembler.dir/cmake_clean_target.cmake
cd /tmp/llvm-20230523-44290-sxekyo/llvm-project-16.0.4.src/llvm/build/lib/Target/AMDGPU/Disassembler && /usr/local/Cellar/cmake/3.26.4/bin/cmake -E cmake_link_script CMakeFiles/LLVMAMDGPUDisassembler.dir/link.txt --verbose=1
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool" -static -no_warning_for_no_symbols -o ../../../libLLVMAMDGPUDisassembler.a CMakeFiles/LLVMAMDGPUDisassembler.dir/AMDGPUDisassembler.cpp.o
[ 51%] Built target LLVMAMDGPUDisassembler
make: *** [all] Error 2

So I tried building LLVM from source (from here)...

cd ~/Downloads
git clone --depth 1 --branch release/16.x https://github.com/llvm/llvm-project llvm-project-16
cd llvm-project-16
git checkout release/16.x

mkdir build-release
cd build-release
cmake ../llvm \
  -DCMAKE_INSTALL_PREFIX=$HOME/local/llvm16-release \
  -DCMAKE_BUILD_TYPE=Release \
  -DLLVM_ENABLE_PROJECTS="lld;clang" \
  -DLLVM_ENABLE_LIBXML2=OFF \
  -DLLVM_ENABLE_TERMINFO=OFF \
  -DLLVM_ENABLE_LIBEDIT=OFF \
  -DLLVM_ENABLE_ASSERTIONS=ON \
  -DLLVM_PARALLEL_LINK_JOBS=1 \
  -G Ninja
ninja install

But LLVM fails to build...

→ ninja install

[1908/4827] Building CXX object lib/Target/AMDGPU/AsmParser/CMakeFiles/LLVMAMDGPUAsmParser.dir/AMDGPUAsmParser.cpp.o
FAILED: lib/Target/AMDGPU/AsmParser/CMakeFiles/LLVMAMDGPUAsmParser.dir/AMDGPUAsmParser.cpp.o
/Applications/Xcode.app/Contents/Developer/usr/bin/g++ -DGTEST_HAS_RTTI=0 -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/Users/Luppy/llvm-project-16/build-release/lib/Target/AMDGPU/AsmParser -I/Users/Luppy/llvm-project-16/llvm/lib/Target/AMDGPU/AsmParser -I/Users/Luppy/llvm-project-16/llvm/lib/Target/AMDGPU -I/Users/Luppy/llvm-project-16/build-release/lib/Target/AMDGPU -I/Users/Luppy/llvm-project-16/build-release/include -I/Users/Luppy/llvm-project-16/llvm/include -isystem /usr/local/include -fPIC -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wstring-conversion -Wctad-maybe-unsupported -fdiagnostics-color -O3 -DNDEBUG -std=c++17 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk  -fno-exceptions -fno-rtti -UNDEBUG -MD -MT lib/Target/AMDGPU/AsmParser/CMakeFiles/LLVMAMDGPUAsmParser.dir/AMDGPUAsmParser.cpp.o -MF lib/Target/AMDGPU/AsmParser/CMakeFiles/LLVMAMDGPUAsmParser.dir/AMDGPUAsmParser.cpp.o.d -o lib/Target/AMDGPU/AsmParser/CMakeFiles/LLVMAMDGPUAsmParser.dir/AMDGPUAsmParser.cpp.o -c /Users/Luppy/llvm-project-16/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp
/Users/Luppy/llvm-project-16/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp:5490:13: error: no viable constructor or deduction guide for deduction of template arguments of 'tuple'
          ? std::tuple(HSAMD::V3::AssemblerDirectiveBegin,
            ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:625:5: note: candidate template ignored: requirement '__lazy_and<std::__1::is_same<std::__1::allocator_arg_t, const char *>, std::__1::__lazy_all<> >::value' was not satisfied [with _Tp = <>, _AllocArgT = const char *, _Alloc = char [21], _Dummy = true]
    tuple(_AllocArgT, _Alloc const& __a)
    ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:641:5: note: candidate template ignored: requirement '_CheckArgsConstructor<true, void>::__enable_implicit()' was not satisfied [with _Tp = <char [17], char [21]>, _Dummy = true]
    tuple(const _Tp& ... __t) _NOEXCEPT_((__all<is_nothrow_copy_constructible<_Tp>::value...>::value))
    ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:659:14: note: candidate template ignored: requirement '_CheckArgsConstructor<true, void>::__enable_explicit()' was not satisfied [with _Tp = <char [17], char [21]>, _Dummy = true]
    explicit tuple(const _Tp& ... __t) _NOEXCEPT_((__all<is_nothrow_copy_constructible<_Tp>::value...>::value))
             ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:677:7: note: candidate template ignored: substitution failure [with _Tp = <>, _Alloc = char [21], _Dummy = true]: cannot reference member of primary template because deduced class template specialization 'tuple<>' is an explicit specialization
      tuple(allocator_arg_t, const _Alloc& __a, const _Tp& ... __t)
      ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:697:7: note: candidate template ignored: substitution failure [with _Tp = <>, _Alloc = char [21], _Dummy = true]: cannot reference member of primary template because deduced class template specialization 'tuple<>' is an explicit specialization
      tuple(allocator_arg_t, const _Alloc& __a, const _Tp& ... __t)
      ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:723:9: note: candidate template ignored: substitution failure [with _Tp = <>, _Up = <char const (&)[17], char const (&)[21]>]: cannot reference member of primary template because deduced class template specialization 'tuple<>' is an explicit specialization
        tuple(_Up&&... __u)
        ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:756:9: note: candidate template ignored: substitution failure [with _Tp = <>, _Up = <char const (&)[17], char const (&)[21]>]: cannot reference member of primary template because deduced class template specialization 'tuple<>' is an explicit specialization
        tuple(_Up&&... __u)
        ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:783:9: note: candidate template ignored: substitution failure [with _Tp = <>, _Alloc = char [21], _Up = <>]: cannot reference member of primary template because deduced class template specialization 'tuple<>' is an explicit specialization
        tuple(allocator_arg_t, const _Alloc& __a, _Up&&... __u)
        ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:803:9: note: candidate template ignored: substitution failure [with _Tp = <>, _Alloc = char [21], _Up = <>]: cannot reference member of primary template because deduced class template specialization 'tuple<>' is an explicit specialization
        tuple(allocator_arg_t, const _Alloc& __a, _Up&&... __u)
        ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:612:23: note: candidate function template not viable: requires 0 arguments, but 2 were provided
    _LIBCPP_CONSTEXPR tuple()
                      ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:615:5: note: candidate function template not viable: requires 1 argument, but 2 were provided
    tuple(tuple const&) = default;
    ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:616:5: note: candidate function template not viable: requires 1 argument, but 2 were provided
    tuple(tuple&&) = default;
    ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:822:9: note: candidate function template not viable: requires single argument '__t', but 2 arguments were provided
        tuple(_Tuple&& __t) _NOEXCEPT_((is_nothrow_constructible<_BaseT, _Tuple>::value))
        ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:837:9: note: candidate function template not viable: requires single argument '__t', but 2 arguments were provided
        tuple(_Tuple&& __t) _NOEXCEPT_((is_nothrow_constructible<_BaseT, _Tuple>::value))
        ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:850:9: note: candidate function template not viable: requires 3 arguments, but 2 were provided
        tuple(allocator_arg_t, const _Alloc& __a, _Tuple&& __t)
        ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:864:9: note: candidate function template not viable: requires 3 arguments, but 2 were provided
        tuple(allocator_arg_t, const _Alloc& __a, _Tuple&& __t)
        ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:469:28: note: candidate function template not viable: requires 1 argument, but 2 were provided
class _LIBCPP_TEMPLATE_VIS tuple
                           ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:932:1: note: candidate function template not viable: requires 3 arguments, but 2 were provided
tuple(allocator_arg_t, const _Alloc&, tuple<_Args...> const&) -> tuple<_Args...>;
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:934:1: note: candidate function template not viable: requires 3 arguments, but 2 were provided
tuple(allocator_arg_t, const _Alloc&, tuple<_Args...>&&) -> tuple<_Args...>;
^
/Users/Luppy/llvm-project-16/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp:5492:13: error: no viable constructor or deduction guide for deduction of template arguments of 'tuple'
          : std::tuple(HSAMD::AssemblerDirectiveBegin,
            ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:625:5: note: candidate template ignored: requirement '__lazy_and<std::__1::is_same<std::__1::allocator_arg_t, const char *>, std::__1::__lazy_all<> >::value' was not satisfied [with _Tp = <>, _AllocArgT = const char *, _Alloc = char [29], _Dummy = true]
    tuple(_AllocArgT, _Alloc const& __a)
    ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:641:5: note: candidate template ignored: requirement '_CheckArgsConstructor<true, void>::__enable_implicit()' was not satisfied [with _Tp = <char [25], char [29]>, _Dummy = true]
    tuple(const _Tp& ... __t) _NOEXCEPT_((__all<is_nothrow_copy_constructible<_Tp>::value...>::value))
    ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:659:14: note: candidate template ignored: requirement '_CheckArgsConstructor<true, void>::__enable_explicit()' was not satisfied [with _Tp = <char [25], char [29]>, _Dummy = true]
    explicit tuple(const _Tp& ... __t) _NOEXCEPT_((__all<is_nothrow_copy_constructible<_Tp>::value...>::value))
             ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:677:7: note: candidate template ignored: substitution failure [with _Tp = <>, _Alloc = char [29], _Dummy = true]: cannot reference member of primary template because deduced class template specialization 'tuple<>' is an explicit specialization
      tuple(allocator_arg_t, const _Alloc& __a, const _Tp& ... __t)
      ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:697:7: note: candidate template ignored: substitution failure [with _Tp = <>, _Alloc = char [29], _Dummy = true]: cannot reference member of primary template because deduced class template specialization 'tuple<>' is an explicit specialization
      tuple(allocator_arg_t, const _Alloc& __a, const _Tp& ... __t)
      ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:723:9: note: candidate template ignored: substitution failure [with _Tp = <>, _Up = <char const (&)[25], char const (&)[29]>]: cannot reference member of primary template because deduced class template specialization 'tuple<>' is an explicit specialization
        tuple(_Up&&... __u)
        ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:756:9: note: candidate template ignored: substitution failure [with _Tp = <>, _Up = <char const (&)[25], char const (&)[29]>]: cannot reference member of primary template because deduced class template specialization 'tuple<>' is an explicit specialization
        tuple(_Up&&... __u)
        ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:783:9: note: candidate template ignored: substitution failure [with _Tp = <>, _Alloc = char [29], _Up = <>]: cannot reference member of primary template because deduced class template specialization 'tuple<>' is an explicit specialization
        tuple(allocator_arg_t, const _Alloc& __a, _Up&&... __u)
        ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:803:9: note: candidate template ignored: substitution failure [with _Tp = <>, _Alloc = char [29], _Up = <>]: cannot reference member of primary template because deduced class template specialization 'tuple<>' is an explicit specialization
        tuple(allocator_arg_t, const _Alloc& __a, _Up&&... __u)
        ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:612:23: note: candidate function template not viable: requires 0 arguments, but 2 were provided
    _LIBCPP_CONSTEXPR tuple()
                      ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:615:5: note: candidate function template not viable: requires 1 argument, but 2 were provided
    tuple(tuple const&) = default;
    ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:616:5: note: candidate function template not viable: requires 1 argument, but 2 were provided
    tuple(tuple&&) = default;
    ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:822:9: note: candidate function template not viable: requires single argument '__t', but 2 arguments were provided
        tuple(_Tuple&& __t) _NOEXCEPT_((is_nothrow_constructible<_BaseT, _Tuple>::value))
        ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:837:9: note: candidate function template not viable: requires single argument '__t', but 2 arguments were provided
        tuple(_Tuple&& __t) _NOEXCEPT_((is_nothrow_constructible<_BaseT, _Tuple>::value))
        ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:850:9: note: candidate function template not viable: requires 3 arguments, but 2 were provided
        tuple(allocator_arg_t, const _Alloc& __a, _Tuple&& __t)
        ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:864:9: note: candidate function template not viable: requires 3 arguments, but 2 were provided
        tuple(allocator_arg_t, const _Alloc& __a, _Tuple&& __t)
        ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:469:28: note: candidate function template not viable: requires 1 argument, but 2 were provided
class _LIBCPP_TEMPLATE_VIS tuple
                           ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:932:1: note: candidate function template not viable: requires 3 arguments, but 2 were provided
tuple(allocator_arg_t, const _Alloc&, tuple<_Args...> const&) -> tuple<_Args...>;
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/tuple:934:1: note: candidate function template not viable: requires 3 arguments, but 2 were provided
tuple(allocator_arg_t, const _Alloc&, tuple<_Args...>&&) -> tuple<_Args...>;
^
2 errors generated.
[1917/4827] Building CXX object lib/Target/AMDGPU/Disassembler/CMakeFiles/LLVMAMDGPUDisassembler.dir/AMDGPUDisassembler.cpp.o
ninja: build stopped: subcommand failed.

So I can't build Zig from source on my 10-year-old MacBook Pro 😢