Benefit of using zig cc?

Has anyone tried to use zig cc as a C compiler to bootstrap OCaml? It could potentially work really well. Zig is built on LLVM so the zig cc compiler is just clang under the hood.

  • There are cross-platform downloads available so e.g. you can download and immediately start using it as a C compiler on Windows
  • The download is 45 MiB
  • It correctly packages a cross-compilation toolchain so you can cross-compile (as shown in the above post)

Cross-platform binaries available for download here: Download ⚡ Zig Programming Language

Could be a great alternative to needing MinGW gcc or msvc.

6 Likes

I did try some time ago, I believe it was when they released 0.7.0. I could fix a number of the build issues but got stuck on an unsupported set of linker flags (there was an open issue about them on the zig repo at the time). I wonder if it works with the latest release…

I don’t know if I still have the code lying around, but the changes to get there were not complicated as far as I remember. Let me know if you try and get stuck, I may give it another go in 2-3 weeks.

1 Like

Thanks, I’ll give it a go and report back.

Let me know if you hit some roadblock, maybe if you throw me the error I can remember what I did to address it

OK, everything went nicely until:

/Users/yamin/Downloads/zig-macos-x86_64-0.10.0-dev.290+3901b6fb0/zig cc -shared                    -flat_namespace -undefined suppress -Wl,-no_compact_unwind                     -o libcamlrun_shared.so interp.bpic.o misc.bpic.o fix_code.bpic.o startup_aux.bpic.o startup_byt.bpic.o major_gc.bpic.o minor_gc.bpic.o memory.bpic.o alloc.bpic.o roots.bpic.o globroots.bpic.o fail_byt.bpic.o signals.bpic.o printexc.bpic.o backtrace_byt.bpic.o backtrace.bpic.o compare.bpic.o ints.bpic.o eventlog.bpic.o floats.bpic.o str.bpic.o array.bpic.o io.bpic.o extern.bpic.o intern.bpic.o hash.bpic.o sys.bpic.o meta.bpic.o parsing.bpic.o gc_ctrl.bpic.o md5.bpic.o obj.bpic.o lexing.bpic.o callback.bpic.o debugger.bpic.o weak.bpic.o finalise.bpic.o custom.bpic.o dynlink.bpic.o platform.bpic.o fiber.bpic.o shared_heap.bpic.o addrmap.bpic.o afl.bpic.o unix.bpic.o bigarray.bpic.o main.bpic.o memprof.bpic.o domain.bpic.o sync.bpic.o skiplist.bpic.o lf_skiplist.bpic.o codefrag.bpic.o prng.bpic.o -lm  -lpthread
warning: unsupported linker arg: -no_compact_unwind
error(link): undefined reference to symbol '_caml_builtin_cprim'
error(link):   first referenced in '/Users/yamin/Downloads/ocaml-trunk/runtime/dynlink.bpic.o'
error(link): undefined reference to symbol '_caml_names_of_builtin_cprim'
error(link):   first referenced in '/Users/yamin/Downloads/ocaml-trunk/runtime/startup_byt.bpic.o'
error: UndefinedSymbolReference
make[2]: *** [libcamlrun_shared.so] Error 1
make[1]: *** [coldstart] Error 2
make: *** [world.opt] Error 2

Fixed that by deleting the -no_compact_unwind flag from the configure script.

Then got this error:

/Users/yamin/Downloads/zig-macos-x86_64-0.10.0-dev.290+3901b6fb0/zig cc -shared                    -flat_namespace -undefined suppress -Wl                     -o libcamlrun_shared.so interp.bpic.o misc.bpic.o fix_code.bpic.o startup_aux.bpic.o startup_byt.bpic.o major_gc.bpic.o minor_gc.bpic.o memory.bpic.o alloc.bpic.o roots.bpic.o globroots.bpic.o fail_byt.bpic.o signals.bpic.o printexc.bpic.o backtrace_byt.bpic.o backtrace.bpic.o compare.bpic.o ints.bpic.o eventlog.bpic.o floats.bpic.o str.bpic.o array.bpic.o io.bpic.o extern.bpic.o intern.bpic.o hash.bpic.o sys.bpic.o meta.bpic.o parsing.bpic.o gc_ctrl.bpic.o md5.bpic.o obj.bpic.o lexing.bpic.o callback.bpic.o debugger.bpic.o weak.bpic.o finalise.bpic.o custom.bpic.o dynlink.bpic.o platform.bpic.o fiber.bpic.o shared_heap.bpic.o addrmap.bpic.o afl.bpic.o unix.bpic.o bigarray.bpic.o main.bpic.o memprof.bpic.o domain.bpic.o sync.bpic.o skiplist.bpic.o lf_skiplist.bpic.o codefrag.bpic.o prng.bpic.o -lm  -lpthread
error(link): undefined reference to symbol '_caml_builtin_cprim'
error(link):   first referenced in '/Users/yamin/Downloads/ocaml-trunk/runtime/dynlink.bpic.o'
error(link): undefined reference to symbol '_caml_names_of_builtin_cprim'
error(link):   first referenced in '/Users/yamin/Downloads/ocaml-trunk/runtime/startup_byt.bpic.o'
error: UndefinedSymbolReference
make[2]: *** [libcamlrun_shared.so] Error 1
make[1]: *** [coldstart] Error 2
make: *** [world.opt] Error 2

Looks like it needs some more work!

EDIT: I also tried building 4.13.1 and got a slightly different error:

/Users/yamin/Downloads/zig-macos-x86_64-0.10.0-dev.290+3901b6fb0/zig cc -c -O2 -fno-strict-aliasing -fwrapv -pthread -Wall -Wdeclaration-after-statement -fno-common -g  -D_FILE_OFFSET_BITS=64 -DCAML_NAME_SPACE  -DCAMLDLLIMPORT=  -o floats.b.o floats.c
make[2]: *** No rule to make target `caml/camlatomic.h', needed by `str.b.o'.  Stop.
make[1]: *** [coldstart] Error 2
make: *** [world.opt] Error 2

EDIT 2: getting the above error with gcc too, so not sure what’s going on…

Oh interesting, those are definitely much further than how it compiled before on the first attempt: I worked around that error by doing ./configure --disable-shared.

After that I needed to modify some include and, finally, it failed linking with an error about main. That one, I was not able to figure out.

It’s a good replacement for MinGW gcc on Windows since zig cc explicitly bundles MinGW 0.7.0. Of course MinGW is not a good replacement for MSVC in some situations. But that is not the main issue: many OCaml packages still rely on Unix tooling so a Unix environment (Cygwin/MSYS2) is still a basic necessity these days. Given that MinGW is trivial to install in Cygwin/MSYS2, it wouldn’t really improve the Windows situation today.

Having spent wasted a few days building a cross-compiling LLVM/clang/lldb installation from source, and after reading the blog post about how zig cc is implemented, zig cc seems like a huge win for cross-compiling to foreign targets. I would look into zig for “easy” cross-compiling, but since I don’t have the bandwidth I’ll follow along this thread with interest!

3 Likes

I took a few minutes to try. Configuring with --disable-shared works all the way to the same failure I had in the past:

/Users/mseri/Downloads/zig-macos-x86_64-0.10.0-dev.317+f423b5949/zig cc -undefined dynamic_lookup -v -allow-shlib-undefined -O2 -fno-strict-aliasing -fwrapv -Qunused-arguments -pthread -Wall -Wdeclaration-after-statement -fno-common -g    -Wl,-no_compact_unwind -g -o ocamlrund prims.o libcamlrund.a -lm  -lpthread
warning: unsupported linker arg: -no_compact_unwind
zig ld -dynamic -syslibroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.1.sdk prims.o libcamlrund.a /Users/mseri/.cache/zig/o/cd482f908487e2f19eacfc6943ed25ec/libcompiler_rt.a -o /Users/mseri/.cache/zig/o/eb03d0dbe45a2e2bf982aef3f941d082/ocamlrund -lSystem -lc -L/usr/lib -L/usr/local/lib -F/Library/Frameworks -F/System/Library/Frameworks
error(link): '_main' export not found
error: MissingMainEntrypoint

Funnily enough, if you run the standard ld manually it works fine:

> cd runtime
> ld -dynamic -syslibroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.1.sdk prims.o libcamlrund.a /Users/mseri/.cache/zig/o/cd482f908487e2f19eacfc6943ed25ec/libcompiler_rt.a -o /Users/mseri/.cache/zig/o/eb03d0dbe45a2e2bf982aef3f941d082/ocamlrund -lSystem -lc -L/usr/lib -L/usr/local/lib -F/Library/Frameworks -F/System/Library/Frameworks
> ./ocamlrun --help
Usage: ocamlrun [<options>] [--] <executable> [<command-line>]
Options are:
  -b  Set runtime parameter b (detailed exception backtraces)
  -config  Print configuration values and exit
  -I <dir>  Add <dir> to the list of DLL search directories
  -m  Print the magic number of <executable> and exit
  -M  Print the magic number expected by this runtime and exit
  -p  Print the names of the primitives known to this runtime
  -t  Trace the execution of the bytecode interpreter (specify multiple
      times to increase verbosity)
  -v  Set runtime parameter v=61 (GC event information)
  -version  Print version string and exit
  -vnum  Print short version number and exit
  -help  Display this list of options
  --help  Display this list of options

I think something is missing on zig linker still to make it work. Maybe we should open an issue on the zig repository.

EDIT: all this is on macOS 12, and before was on macOS 11. I am going to check if on linux it is the same

1 Like

On linux, the default configure fails with

ld.lld: error: relocation R_X86_64_PC32 cannot be used against symbol caml_program; recompile with -fPIC
>>> defined in amd64_libasmrunpic.o
>>> referenced by amd64_libasmrunpic.o:(caml_start_program)

ld.lld: error: relocation R_X86_64_PC32 cannot be used against symbol caml_exn_Stack_overflow; recompile with -fPIC
>>> defined in fail_nat.npic.o
>>> referenced by amd64_libasmrunpic.o:(caml_stack_overflow)

ld.lld: error: relocation R_X86_64_PC32 cannot be used against symbol caml_apply2; recompile with -fPIC
>>> defined in amd64_libasmrunpic.o
>>> referenced by amd64_libasmrunpic.o:(caml_callback2_asm)

ld.lld: error: relocation R_X86_64_PC32 cannot be used against symbol caml_apply3; recompile with -fPIC
>>> defined in amd64_libasmrunpic.o
>>> referenced by amd64_libasmrunpic.o:(caml_callback3_asm)

ld.lld: error: relocation R_X86_64_PC32 cannot be used against symbol caml_array_bound_error; recompile with -fPIC
>>> defined in fail_nat.npic.o
>>> referenced by amd64_libasmrunpic.o:(caml_ml_array_bound_error)

To be noted here is that it is actually compiled with -fPIC.

So I tried to configure with --disable-shared just to check what happens.
While on macOS zig linker has lots of problems (falls back on lld to avoid requiring xcode but lld is terrible on mac and, indeed, there are tons of issues concerning linking on macos), on linux it should work well, so this was really just out of curiosity… and that actually succeeds!!

I have tried to also run make tests and it looks like tests are mostly passing:

Summary:
  1988 tests passed
   92 tests skipped
  369 tests failed
  586 tests not started (parent test skipped or failed)
    0 unexpected errors
  3035 tests considered
#### Something failed. Exiting with error status.

As far as I could see, those failures are all things like

 ... testing 'sorts.ml' with 1 (native) => failed (The file /home/mseri/ocaml/testsuite/_ocamltest/tests/misc/sorts/ocamlopt.byte/ocamlopt.byte.output was expected to be empty because there is no reference file /home/mseri/ocaml/testsuite/tests/misc/sorts.compilers.reference but it is not:
========================================
zig: warning: argument unused during compilation: '-D __GLIBC_MINOR__=31' [-Wunused-command-line-argument]
zig: warning: argument unused during compilation: '-isystem /usr/local/include' [-Wunused-command-line-argument]
zig: warning: argument unused during compilation: '-isystem /usr/include/x86_64-linux-gnu' [-Wunused-command-line-argument]
zig: warning: argument unused during compilation: '-isystem /usr/include' [-Wunused-command-line-argument]
zig: warning: argument unused during compilation: '-D __GLIBC_MINOR__=31' [-Wunused-command-line-argument]
zig: warning: argument unused during compilation: '-isystem /usr/local/include' [-Wunused-command-line-argument]
zig: warning: argument unused during compilation: '-isystem /usr/include/x86_64-linux-gnu' [-Wunused-command-line-argument]
zig: warning: argument unused during compilation: '-isystem /usr/include' [-Wunused-command-line-argument]
========================================

I have also tried to use ZIG_SYSTEM_LINKER_HACK=1 on macOS, to see if it helps in this case, but it still fails:

env ZIG_SYSTEM_LINKER_HACK=1 /Users/mseri/Downloads/zig-macos-x86_64-0.10.0-dev.317+f423b5949/zig cc -O2 -fno-strict-aliasing -fwrapv -pthread -Wall -Wdeclaration-after-statement -fno-common -g    -Wl,-no_compact_unwind -o ocamlrun prims.o libcamlrun.a -lm  -lpthread
warning: unsupported linker arg: -no_compact_unwind
error(link): '_main' export not found
error: MissingMainEntrypoint
3 Likes

There was a report here with Zig having some issues due to the way Homebrew builds LLVM on MacOSX (though reportedly already fixed), although it shouldn’t have affected the official tarballs: homebrew-provided LLVM/Clang prevents zig from building C files · Issue #8860 · ziglang/zig · GitHub Probably worth checking first whether Zig itself can compile a simple hello world C program, and then try to use it to build OCaml.

Interesting although it did not apply here. For my tests I used once the zig provided by macports and once the official tarballs (in particular for the compilations above). Both did compile correctly simple C programs.

Like i already said, ocaml-compiler should have a flag to specify as backend:clang,gcc,zig.
Because each one has a different flag-list-options to compile/link.
I think gcc is the default.

Would this be a good use of precious developer resources? How many people have need of a zig cc backend ?

2 Likes