jart / cosmopolitan

build-once run-anywhere c library
ISC License
18.36k stars 630 forks source link

Compiling all of cosmopolitan on macOS #375

Closed ghaerr closed 1 year ago

ghaerr commented 2 years ago

Hello @jart,

[Edits below: some earlier errors were my misunderstanding of build process]

I'm continuing the discussion from https://github.com/jart/cosmopolitan/issues/227#issuecomment-1077806881, but am opening a new issue, so as not to be off-topic. I hope that's ok, and excuse in advance this long report.

I (finally) now have almost the entire repo compiling (and all .com files produced seemingly working) under macOS. I'd like to help contribute to Cosmopolitan but need to be able to build everything under macOS, since I don't have easy everyday access to Linux. And of course, a huge motivation is to play more with blinkenlights.com, which now is working and compiling from scratch on macOS :)

Rather than immediately produce a PR, I thought to get your input as to various issues found during the port. At present, some of the fixes required hacks, which will want to be fixed differently. I will describe each issue in more detail below using a bullet point.

I installed a pre-compiled homebrew version of Rich Felker's musl-cross-make x86_64-linux-musl-gcc first, which installs the compiler in /usr/local/bin on macOS. Using this version could be helpful, if it were ever decided to build the Linux and macOS compilers from the same source and build scripts.

Second, it was found that macOS (Catalina) is running GNU make 3.81, which silently ignores the $(file ...) function, used to prepare argument lists all over. Installing homebrew version of make 4.3 and then executing export PATH=/usr/local/opt/make/libexec/gnubin:$PATH solved that problem.

These macOS updates then allowed a small diff and a few other changes to compile most of Cosmopolitan.

Here's the entire diff:

diff --git a/build/definitions.mk b/build/definitions.mk
index 7a08e72a7..0d358fb08 100644
--- a/build/definitions.mk
+++ b/build/definitions.mk
@@ -61,6 +61,7 @@ MKDEPS = build/bootstrap/mkdeps.com
 ZIPOBJ = build/bootstrap/zipobj.com
 AS = o/third_party/gcc/bin/x86_64-linux-musl-as
 CC = o/third_party/gcc/bin/x86_64-linux-musl-gcc
+CC = /usr/local/bin/x86_64-linux-musl-gcc
 CXX = o/third_party/gcc/bin/x86_64-linux-musl-g++
 CXXFILT = o/third_party/gcc/bin/x86_64-linux-musl-c++filt
 LD = o/third_party/gcc/bin/x86_64-linux-musl-ld.bfd
diff --git a/build/config.mk b/build/config.mk
index 17827a02e..ee34147f0 100644
--- a/build/config.mk
+++ b/build/config.mk
@@ -308,6 +308,35 @@ OBJDUMP = llvm-objdump
 ADDR2LINE = llvm-addr2line
 endif

+# macOS - options copied from Tiny Metallic Unix Mode
+ifeq ($(MODE), macOS)
+TOOLPREFIX=/usr/local/bin/x86_64-linux-musl-
+AS = $(TOOLPREFIX)as
+CC = ./gcc
+GCC = ./gcc
+CXX = $(TOOLPREFIX)g++
+CXXFILT = $(TOOLPREFIX)llvm-c++filt
+LD = $(TOOLPREFIX)ld.bfd
+NM = $(TOOLPREFIX)nm
+STRIP = $(TOOLPREFIX)strip
+OBJCOPY = $(TOOLPREFIX)objcopy
+OBJDUMP = $(TOOLPREFIX)objdump
+ADDR2LINE = $(TOOLPREFIX)addr2line
+CONFIG_CPPFLAGS +=     \
+   -DTINY          \
+   -DNDEBUG        \
+   -DTRUSTWORTHY       \
+   -DSUPPORT_VECTOR=251
+CONFIG_CCFLAGS +=      \
+   -Os         \
+   -fno-align-functions    \
+   -fno-align-jumps    \
+   -fno-align-labels   \
+   -fno-align-loops
+TARGET_ARCH ?=         \
+   -msse3
+endif
+
 # ANSI Mode
 #
 # These flags cause GCC to predefine __STRICT_ANSI__. Please be warned
diff --git a/build/sanitycheck b/build/sanitycheck
index c2da2d263..235d10af4 100755
--- a/build/sanitycheck
+++ b/build/sanitycheck
@@ -9,7 +9,7 @@
 #   This script is launched at the start of Makefile to detect if
 #   binfmt_misc was tuned to launch 'MZ' shell scripts under WINE

-if [ x`uname -s` != xLinux ]; then
+if [ x`uname -s` != xLinux -a x`uname -s` != xDarwin ]; then
   cat <<'EOF' >&2

 ERROR
diff --git a/test/libc/release/emulate.sh b/test/libc/release/emulate.sh
index cb9152877..eac0ec289 100755
--- a/test/libc/release/emulate.sh
+++ b/test/libc/release/emulate.sh
@@ -8,6 +8,10 @@ if [ "$MODE" = opt ] || [ "$MODE" = optlinux ]; then
   exit
 fi

+if [ "$MODE" = macOS ]; then
+  exit  # TODO
+fi
+
 # smoke test userspace binary emulation
 CMD="o/$MODE/tool/build/blinkenlights.com.dbg o/$MODE/examples/hello.com"
 if OUTPUT="$($CMD)"; then
diff --git a/third_party/mbedtls/mbedtls.mk b/third_party/mbedtls/mbedtls.mk
index 030e78dd5..e8de2d696 100644
--- a/third_party/mbedtls/mbedtls.mk
+++ b/third_party/mbedtls/mbedtls.mk
@@ -74,8 +74,6 @@ o/$(MODE)/third_party/mbedtls/shiftright2-avx.o:          \
 o/$(MODE)/third_party/mbedtls/zeroize.o:               \
            OVERRIDE_CFLAGS +=              \
                -O3                 \
-               -x-no-pg                \
-               -fomit-frame-pointer            \
                -foptimize-sibling-calls

 THIRD_PARTY_MBEDTLS_LIBS = $(foreach x,$(THIRD_PARTY_MBEDTLS_ARTIFACTS),$($(x)))
diff --git a/tool/build/compile.c b/tool/build/compile.c
index a30df1e30..5a4af476b 100644
--- a/tool/build/compile.c
+++ b/tool/build/compile.c
@@ -946,7 +946,7 @@ int main(int argc, char *argv[]) {
       AddArg("-Wno-unused-command-line-argument");
       AddArg("-Wno-incompatible-pointer-types-discards-qualifiers");
     }
-    AddArg("-no-canonical-prefixes");
+    //AddArg("-no-canonical-prefixes");
     if (!__nocolor) {
       AddArg(firstnonnull(colorflag, "-fdiagnostics-color=always"));
     }
diff --git a/build/bootstrap/compile.com b/build/bootstrap/compile.com
index 705f5c5f2..8ce87248f 100755
Binary files a/build/bootstrap/compile.com and b/build/bootstrap/compile.com differ

A problem in definitions.mk is that the "SPAWNER := $(shell build/getcompile) -V$(shell build/getccversion $(CC))" line uses one-time assignment which contains $(CC), which ends up using the definitions.mk value, rather than the config.mk value of $(CC). Thus CC= has to be changed in definitions.mk as well.

I'm not sure the options I've selected for macOS (which are copies of the "MODE=tinynowin" mode) are best for macOS.

With these changes, the cosmopolitan builds all libraries, headers and examples, with all .com files working, up to third_party/chibicc/test/common.chibicc.o, which fails due to chibicc.com.dbg not being executable.

I'd be happy to help get Cosmopolitan firmly building on macOS, if you're willing. You have an amazing project! How would you like to proceed?

Thank you!

jart commented 2 years ago

I support this. It would need to be community maintained for the time being. The biggest thing I recommend doing is creating a shell script in the build folder that rewrites the cc flags so clang is happy. That way you can send PRs quickly. I won't merge PRs that change the binary bootstrap blob for compile.com.

ghaerr commented 2 years ago

I support this. It would need to be community maintained for the time being.

Thank you, I could maintain it, as well as submit an acceptable PR that gets macOS builds fully working.

The biggest thing I recommend doing is creating a shell script in the build folder that rewrites the cc flags so clang is happy.

I did that at first, but then thought it might be better to remove the AddArg("-no-canonical-prefixes") from compile.c. I'll go back to using a shell script.

I won't merge PRs that change the binary bootstrap blob for compile.com.

Ok. Would you consider a PR adding a "build/compiler.mk", to be inserted just before "build/definitions.mk" in the Makefile? This would allow for setting all the CC= etc compiler strings for macOS (and other platforms), and also nicely fixes the problem mentioned above where CC= is used in build/definitions.mk for the SPAWNER := line, which needs the correct CC= definition to come prior.

Seperately, could you comment on the "-x-no-pg" issue seemingly only implemented on your static Linux musl compiler? Was this implemented specially by yourself, as it doesn't work on other builds of Rich Felker's compilers. I don't currently see a workaround for this, we need a way to turn off -no-pg.

Thank you!

jart commented 2 years ago

There's an llvm section in config.mk. Would you be interesting in maintaining that? In other words, you'd put something like make MODE=darwin or make MODE=llvm. We use the -x-no-pg flag because sometimes it's needed to turn that flag off. It's recognized by compile.com. You can do what we used to do. See its predecessor https://github.com/jart/cosmopolitan/blob/c91b3c50068224929cd4d3ddf36c5a10254cbd9c/build/compile

ghaerr commented 2 years ago

Hello @jart,

There's an llvm section in config.mk. Would you be interesting in maintaining that?

Yes, I'd be happy to maintain the macOS port for you. I was thinking that this might be done in two steps: the first, getting Rich Felker's gcc musl-based cross compiler building Cosmopolitan, and then in a second step considering the issues with getting llvm building and linking properly. The advantage of the first step is that the compiled objects should be very close if not identical to the Linux versions, and that the ld.bfd linker can be used, rather than having to deal with Apple's llvm-ld at first.

I have Cosmopolitan building now on macOS, using make MODE=darwin. There are still some small issues when restarting the make, for instance:

make MODE=darwin
♥cosmo
error: "usr/share/zoneinfo/" (o/darwin/libc/time/localtime.o) not defined by direct deps of o/darwin/libc/time/time.a.pkg
    o/darwin/libc/calls/syscalls.a.pkg

After sorting these issues out, I can submit a PR for your consideration.

We use the -x-no-pg flag because sometimes it's needed to turn that flag off. It's recognized by compile.com.

Thanks, I didn't realize the flag was recognized by compile.com. I'm looking into why compile.com isn't turning off the -pg flag in this case, there is some special handling by compile.com looking at the basename of the compiler. In my case, the compiler name is the same, except the path to it is /usr/local/bin, rather than o/thirdparty/gcc/bin.

You can do what we used to do. See its predecessor https://github.com/jart/cosmopolitan/blob/c91b3c50068224929cd4d3ddf36c5a10254cbd9c/build/compile

Got it. I would like to be able to solve this issue without having to resort to using a fancy shell script to run the compiler, since there is already compile.com. There are only couple small issues remaining.

Thank you!

jart commented 2 years ago

We're already using musl-cross-make embedded binaries to build on Linux. If that runs on Darwin then it'll probably help. If you don't want to do the shell script then would you like me to modify compile.com so that it filters the flags appropriately if IsXnu()? I guess what you could do is send me a PR that changes compile.c and then I could submit another change that rebuilds the binary.

ghaerr commented 2 years ago

would you like me to modify compile.com so that it filters the flags appropriately if IsXnu()? I guess what you could do is send me a PR that changes compile.c and then I could submit another change that rebuilds the binary.

That would be great! I will post a minimal PR shortly. I have the darwin build working now.

ghaerr commented 2 years ago

Hello @jart,

Things are looking a lot better regarding using macOS for compilation of Cosmopolitan. In short, the entire repo can be made to compile with just one change to build/definitions.mk (using Rich Felker's x86_64-musl-gcc compiler), although later on the build fails in some of the python tests.

I am going to close #386, as much has been done since April for macOS cross-compilation. Only the following patch is required at this point:

diff --git a/build/definitions.mk b/build/definitions.mk
index 4b4f1cd22..19788da32 100644
--- a/build/definitions.mk
+++ b/build/definitions.mk
@@ -86,6 +86,20 @@ OBJCOPY = o/third_party/gcc/bin/x86_64-pc-linux-gnu-objcopy.exe
 OBJDUMP = o/third_party/gcc/bin/x86_64-pc-linux-gnu-objdump.exe
 ADDR2LINE = $(PWD)/o/third_party/gcc/bin/x86_64-pc-linux-gnu-addr2line.exe
 else
+UNAME := $(shell /usr/bin/uname)
+ifeq ($(UNAME),Darwin)
+AS = x86_64-linux-musl-as
+CC = x86_64-linux-musl-gcc
+CXX = x86_64-linux-musl-g++
+CXXFILT = x86_64-linux-musl-c++filt
+LD = x86_64-linux-musl-ld.bfd
+NM = x86_64-linux-musl-nm
+GCC = x86_64-linux-musl-gcc
+STRIP = x86_64-linux-musl-strip
+OBJCOPY = x86_64-linux-musl-objcopy
+OBJDUMP = x86_64-linux-musl-objdump
+ADDR2LINE = x86_64-linux-musl-addr2line
+else
 IGNORE := $(shell build/bootstrap/unbundle.com)
 AS = o/third_party/gcc/bin/x86_64-linux-musl-as
 CC = o/third_party/gcc/bin/x86_64-linux-musl-gcc
@@ -99,6 +113,7 @@ OBJCOPY = o/third_party/gcc/bin/x86_64-linux-musl-objcopy
 OBJDUMP = o/third_party/gcc/bin/x86_64-linux-musl-objdump
 ADDR2LINE = $(PWD)/o/third_party/gcc/bin/x86_64-linux-musl-addr2line
 endif
+endif

 export ADDR2LINE
 export LC_ALL

Would you like me to post that as a PR?

Other items to note:

====================================================================== ERROR: test_fieldstorage_readline (main.CgiTests)

Traceback (most recent call last): File "/zip/.python/test/test_cgi.py", line 240, in test_fieldstorage_readline f = TestReadlineFile(tempfile.TemporaryFile("wb+")) File "/zip/.python/tempfile.py", line 597, in TemporaryFile fd = _os.open(dir, flags2, 0o600) OverflowError: signed integer is greater than maximum


Ran 23 tests in 0.016s

ghaerr commented 1 year ago

Closing as quite outdated, thanks!