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)
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.
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!
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
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:
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.
This seems to be some difference in how zig and GCC behaves when preprocessing assembly, GCC defines __PIC__, whereas zig seems not to (but it does define it when compiling C files).
The following works on Linux as a workaround (where $ZIG is the path to where you installed zig 0.10.0):
./configure CC=“$ZIG cc” ASPP=“$ZIG cc -D__PIC__” --with-pic=yes
You also need this patch:
diff --git a/configure b/configure
index f54df4138..d0ce62355 100755
Binary files a/configure and b/configure differ
diff --git a/yacc/defs.h b/yacc/defs.h
index 16c2c8de6..0eae1b5d7 100644
--- a/yacc/defs.h
+++ b/yacc/defs.h
@@ -16,8 +16,11 @@
/* Based on public-domain code from Berkeley Yacc */
#ifndef DEBUG
+#ifndef NDEBUG
#define NDEBUG
#endif
+#endif
+
#include <assert.h>
#include <ctype.h>
This workaround in configure:
diff --git a/configure b/configure
index f54df4138..d0ce62355 100755
--- a/configure
+++ b/configure
@@ -13541,7 +13541,7 @@ case $ocaml_cv_cc_vendor in #(
*) :
outputobj='-o $(EMPTY)'
warn_error_flag='-Werror'
- cc_warnings='-Wall' ;;
+ cc_warnings='-Wall -Wno-deprecated-non-prototype' ;;
esac
case $enable_warn_error,true in #(