Use zig cc as a alternative linker (draft version)

This approach was originally verified by @luislavena and first posted here, here and here, big thanks to him for proving this solutin work, and he showed a little bit of this in following videos:

[Building CLIs with Crystal - Quick cross-compilation - Part 1](https://www.youtube.com/watch?v=ij7alYEvfTg)
[Building CLIs with Crystal - Quick cross-compilation - Part 2](https://www.youtube.com/watch?v=LdVNqdf_kBI)

Here are some links explain how zig cc link work:

zig cc: a Powerful Drop-In Replacement for GCC/Clang

How Uber Uses Zig

PR: Add guide: Use zig cc as a alternative linker (draft version) by zw963 · Pull Request #737 · crystal-lang/crystal-book · GitHub


@straight-shoota , we can also discuss here.

HTML version:

@luislavena , because the original gem GitHub - luislavena/magic-haversack: Facilitate Crystal cross-compilation, there is no way to create issue, i just create it here.

As the example code following, A minimal hello world code, if linked to macOS using zig cc, the libiconv is necessary.


╰─ $ echo ‘puts “hello”’ > hello.cr

╰─ $ crystal build hello.cr --release --no-debug --cross-compile --target=x86_64-darwin --link-flags=-s
cc hello.o -o hello -s -rdynamic -L/home/zw963/Crystal/bin/…/lib/crystal -lpcre2-8 -lgc -lpthread -ldl -levent -liconv


But, this library not exists in magic-haversack.

tl;dr: you need macOS SDK to link against their dynamic version of iconv, the one used by Crystal by default when targeting macOS platforms.

You could workaround that by downloading libiconv for macOS (the static library) and forcing the link to it.

See this Crystal PR that covers all the details of iconv on macOS.

Or you can download existing versions of macOS SDK and grab the .tld files necessary for the dynamic linking to work.

I cannot distribute bundled versions of the SDK without breaking Apple’s terms.

Cheers.

How about adding libiconv for macOS (the static library) to magic-haversack? it can be installed use brew anyway.

Add a bash script example make cross link aarch64-linux-musl/x86_64-linux-musl use zig cc automate.

Add a new bash script, it can build and link binary on my AMD64 laptop for x86_64-linux-musl/aarch64-linux-musl/x86_64-darwin/arrch64-darwin now without needs docker.

 ╰─ $ cd ~/Crystal/crystal-lang/shards
 
  ╰─ $ git clean -fdx && shards build --production --static --no-debug --cross-compile --target=aarch64-linux-musl --link-flags=-s
Removing bin/shards
Removing bin/shards.o
Removing lib/
zig cc -target aarch64-linux-musl /home/zw963/Crystal/crystal-lang/shards/bin/shards.o -o /home/zw963/Crystal/crystal-lang/shards/bin/shards -s -rdynamic -static -L/home/zw963/Crystal/static_libraries/aarch64-linux-musl -lyaml -lpcre2-8 -lgc -lpthread -ldl -levent -lunwind
 
 ╰─ $ file bin/shards
bin/shards: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), static-pie linked, stripped

 ╰─ $ git clean -fdx && shards build --production --static --no-debug --cross-compile --target=x86_64-linux-musl --link-flags=-s
Removing bin/shards
Removing bin/shards.o
Removing lib/
zig cc -target x86_64-linux-musl /home/zw963/Crystal/crystal-lang/shards/bin/shards.o -o /home/zw963/Crystal/crystal-lang/shards/bin/shards -s -rdynamic -static -L/home/zw963/Crystal/static_libraries/x86_64-linux-musl -lyaml -lpcre2-8 -lgc -lpthread -ldl -levent -lunwind

 ╰─ $ file bin/shards
bin/shards: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), static-pie linked, stripped

 ╰─ $ git clean -fdx && shards build --production --static --no-debug --cross-compile --target=x86_64-darwin --link-flags=-s
Removing bin/shards
Removing bin/shards.o
Removing lib/
zig cc -target x86_64-macos-none /home/zw963/Crystal/crystal-lang/shards/bin/shards.o -o /home/zw963/Crystal/crystal-lang/shards/bin/shards -s -rdynamic -static -L/home/zw963/Crystal/static_libraries/x86_64-apple-darwin21.0 -lyaml -lpcre2-8 -lgc -lpthread -ldl -levent -liconv -lunwind

 ╰─ $ file bin/shards
bin/shards: Mach-O 64-bit x86_64 executable, flags:<NOUNDEFS|DYLDLINK|TWOLEVEL|PIE|HAS_TLV_DESCRIPTORS>

 ╰─ $ git clean -fdx && shards build --production --static --no-debug --cross-compile --target=aarch64-darwin --link-flags=-s
Removing bin/shards
Removing bin/shards.o
Removing lib/
zig cc -target aarch64-macos-none /home/zw963/Crystal/crystal-lang/shards/bin/shards.o -o /home/zw963/Crystal/crystal-lang/shards/bin/shards -s -rdynamic -static -L/home/zw963/Crystal/static_libraries/aarch64-apple-darwin21.0 -lyaml -lpcre2-8 -lgc -lpthread -ldl -levent -liconv -lunwind

 ╰─ $ file bin/shards
bin/shards: Mach-O 64-bit arm64 executable, flags:<NOUNDEFS|DYLDLINK|TWOLEVEL|PIE|HAS_TLV_DESCRIPTORS>