mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 11:37:35 +00:00
f531acc8f9
- Invent openatemp() API - Invent O_UNLINK open flag - Introduce getenv_secure() API - Remove `git pull` from cosmocc - Fix utimes() when path is NULL - Fix mktemp() to never return NULL - Fix utimensat() UTIME_OMIT on XNU - Improve utimensat() code for RHEL5 - Turn `argv[0]` C:/ to /C/ on Windows - Introduce tmpnam() and tmpnam_r() APIs - Fix more const issues with internal APIs - Permit utimes() on WIN32 in O_RDONLY mode - Fix fdopendir() to check fd is a directory - Fix recent crash regression in landlock make - Fix futimens(AT_FDCWD, NULL) to return EBADF - Use workaround so `make -j` doesn't fork bomb - Rename dontdiscard to __wur (just like glibc) - Fix st_size for WIN32 symlinks containing UTF-8 - Introduce stdio ext APIs needed by GNU coreutils - Fix lstat() on WIN32 for symlinks to directories - Move some constants from normalize.inc to limits.h - Fix segv with memchr() and memcmp() overlapping page - Implement POSIX fflush() behavior for reader streams - Implement AT_SYMLINK_NOFOLLOW for utimensat() on WIN32 - Don't change read-only status of existing files on WIN32 - Correctly handle `0x[^[:xdigit:]]` case in strtol() functions
375 lines
11 KiB
Bash
Executable file
375 lines
11 KiB
Bash
Executable file
#!/bin/sh
|
|
#
|
|
# cosmopolitan c/c++ compiler
|
|
#
|
|
# getting started
|
|
#
|
|
# sudo chmod 1777 /opt # sticky bit isn't required
|
|
# git clone https://github.com/jart/cosmopolitan /opt/cosmo
|
|
# export PATH="/opt/cosmo/bin:/opt/cosmos/bin:$PATH"
|
|
# echo 'export PATH="/opt/cosmo/bin:/opt/cosmos/bin:$PATH"' >>~/.profile
|
|
# ape-install # optionally install a faster systemwide ape loader
|
|
# cosmocc --update # pull and rebuild toolchain artifacts
|
|
#
|
|
# getting started synopsis
|
|
#
|
|
# cosmocc -o hello.com hello.c
|
|
# ./foo.com
|
|
# ./foo.com --strace
|
|
# ./foo.com --ftrace
|
|
#
|
|
# how to build a project like lua 5.4.6
|
|
#
|
|
# make all test CC=cosmocc
|
|
# src/lua -e 'print("hi")'
|
|
# make install INSTALL_TOP=/opt/cosmos
|
|
# apecopy src/lua src/lua.com # convert to portable ape binary
|
|
#
|
|
# how to cross compile a project like lua 5.4.6
|
|
#
|
|
# aarch64-unknown-cosmo-cc --update
|
|
# make clean all test CC=aarch64-unknown-cosmo-cc AR='aarch64-unknown-cosmo-ar rc' -j8
|
|
# qemu-aarch64 src/lua -e 'print("hi")'
|
|
# make install INSTALL_TOP=/opt/cosmos/aarch64
|
|
#
|
|
# building in tiny mode
|
|
#
|
|
# export MODE=tiny
|
|
# cosmocc --update
|
|
# cosmocc -Os -o foo.com foo.c
|
|
#
|
|
# building in tiniest mode (linux only)
|
|
#
|
|
# export MODE=tinylinux
|
|
# cosmocc --update
|
|
# cosmocc -Os -o foo.com foo.c
|
|
#
|
|
# hardening programs with memory safety
|
|
#
|
|
# export MODE=asan
|
|
# cosmocc --update
|
|
# cosmocc -o foo.com foo.c
|
|
#
|
|
# detecting this environment
|
|
#
|
|
# - `__COSMOCC__` is defined when this compiler is in play
|
|
# - `__COSMOPOLITAN__` is always defined by Cosmopolitan Libc
|
|
#
|
|
# some notes on this compiler
|
|
#
|
|
# - the underlying compiler itself is gcc
|
|
# - we use cosmopoiltan libc rather than glibc
|
|
# - we use llvm's compiler-rt and libcxx runtimes
|
|
# - we patched gcc so switch case can have symbols
|
|
# - our scanf() implementation is somewhat troubled
|
|
#
|
|
# compiler flags that aren't supported
|
|
#
|
|
# - `-r` partial linking not implemented yet (todo)
|
|
# - `-S` you need to put your assembly behind #ifdefs instead
|
|
# - `-fexceptions` cosmopolitan doesn't support c++ exceptions yet
|
|
# - `-frtti` cosmopolitan doesn't support c++ runtime reflection yet
|
|
# - `-mred-zone` the system v red zone doesn't exist on windows and metal
|
|
# - `-fpic`, '-fPIC', `-shared`, `-pie`, etc. no shared object support yet
|
|
# - `-fsanitize=thread` cosmopolitan doesn't have thread sanitizer runtime yet
|
|
# - `-fomit-frame-pointer` is partially supported (apple forbids full removal)
|
|
#
|
|
# for further details, run `man gcc`
|
|
|
|
PROG=${0##*/}
|
|
COSMO=${COSMO:-/opt/cosmo}
|
|
GCC_VERSION=11.2.0
|
|
|
|
if [ "$1" = "--version" ]; then
|
|
cat <<EOF
|
|
$PROG (GCC) $GCC_VERSION
|
|
Copyright (c) 2023 Justine Alexandra Roberts Tunney
|
|
Cosmopolitan Libc and LLVM libcxx/compiler-rt are subject to non-GPL
|
|
notice licenses, e.g. ISC, MIT, etc. Your compiled programs must embed
|
|
our copyright notices. This toolchain is configured to do so default.
|
|
Cosmopolitan comes with absolutely NO WARRANTY of any kind.
|
|
For more information, see the Cosmopolitan LICENSE files.
|
|
Copyright (C) 2019 Free Software Foundation, Inc.
|
|
This launches GNU GCC/Binutils subprocesses, which is free software; see
|
|
Cosmopolitan's third_party/gcc/ for source code and copying conditions.
|
|
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
|
|
PARTICULAR PURPOSE.
|
|
EOF
|
|
exit
|
|
fi
|
|
|
|
fatal_error() {
|
|
echo "$PROG: fatal error: $1" >&2
|
|
echo "compilation terminated." >&2
|
|
exit 1
|
|
}
|
|
|
|
log_command() {
|
|
if [ -n "$BUILDLOG" ]; then
|
|
printf '# %s\n(cd %s; %s)\n' "$ORIGINAL" "$PWD" "$*" >>"$BUILDLOG"
|
|
fi
|
|
}
|
|
|
|
ORIGINAL="$0 $*"
|
|
PLATFORM="-D__COSMOPOLITAN__ -D__COSMOCC__"
|
|
PREDEF="-include libc/integral/normalize.inc"
|
|
CFLAGS="-fportcosmo -fno-dwarf2-cfi-asm -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-semantic-interposition"
|
|
CPPFLAGS="-fno-pie -nostdinc -fno-math-errno -iquote $COSMO"
|
|
LDFLAGS="-static -no-pie -nostdlib -fuse-ld=bfd"
|
|
APEFLAGS="-Wl,--gc-sections"
|
|
PRECIOUS="-fno-omit-frame-pointer"
|
|
|
|
CROSS=1
|
|
ARCH=${PROG%%-*} # split(prog, '-')[0]
|
|
if [ x"$ARCH" = x"$PROG" ]; then
|
|
ARCH=x86_64
|
|
CROSS=0
|
|
fi
|
|
|
|
if [ x"$ARCH" = x"x86_64" ]; then
|
|
MODE=${MODE:-$m}
|
|
else
|
|
MODE=${MODE:-${m:-$ARCH}}
|
|
fi
|
|
|
|
if [ $CROSS -eq 0 ]; then
|
|
COSMOS=${COSMOS:-/opt/cosmos}
|
|
else
|
|
COSMOS=${COSMOS:-/opt/cosmos/$ARCH}
|
|
fi
|
|
|
|
CC="$COSMO/o/third_party/gcc/bin/$ARCH-linux-musl-gcc"
|
|
CRT="$COSMO/o/$MODE/libc/crt/crt.o"
|
|
LDLIBS="$COSMO/o/$MODE/cosmopolitan.a"
|
|
CPPFLAGS="$CPPFLAGS -isystem $COSMOS/include -isystem $COSMO/libc/isystem"
|
|
LDFLAGS="$LDFLAGS -L$COSMOS/lib"
|
|
if [ x"$PROG" != x"${PROG%++}" ]; then
|
|
CC="$COSMO/o/third_party/gcc/bin/$ARCH-linux-musl-g++"
|
|
CFLAGS="$CFLAGS -fno-rtti -fno-exceptions -fuse-cxa-atexit"
|
|
LDLIBS="$COSMO/o/$MODE/third_party/libcxx/libcxx.a $LDLIBS"
|
|
fi
|
|
|
|
PAGESZ=4096
|
|
if [ x"$ARCH" = x"x86_64" ]; then
|
|
OBJCOPYFLAGS="-S -O binary"
|
|
CRT="$COSMO/o/$MODE/ape/ape-no-modify-self.o $CRT"
|
|
CPPFLAGS="$CPPFLAGS -mno-red-zone"
|
|
CFLAGS="$CFLAGS -mno-tls-direct-seg-refs"
|
|
LDFLAGS="$LDFLAGS -Wl,-T,$COSMO/o/$MODE/ape/ape.lds"
|
|
if [ x"$MODE" = x"aarch64" ]; then
|
|
fatal_error '$MODE must not be aarch64 when using x86_64 cross compiler'
|
|
elif [ x"$MODE" != x"${MODE#* }" ]; then
|
|
fatal_error '$MODE must not contain hyphens when targeting x86_64'
|
|
fi
|
|
elif [ x"$ARCH" = x"aarch64" ]; then
|
|
OBJCOPYFLAGS="-S"
|
|
PAGESZ=16384
|
|
CFLAGS="$CFLAGS -ffixed-x18 -ffixed-x28 -mno-outline-atomics"
|
|
LDFLAGS="$LDFLAGS -Wl,-T,$COSMO/o/$MODE/ape/aarch64.lds"
|
|
if [ x"$MODE" != x"aarch64" ] && [ x"$MODE" = x"${MODE#aarch64-*}" ]; then
|
|
fatal_error '$MODE must be either "aarch64" or "aarch64-FOO" when using aarch64 cross compiler'
|
|
fi
|
|
else
|
|
fatal_error "$ARCH: unsupported architecture"
|
|
fi
|
|
|
|
LDFLAGS="$LDFLAGS -Wl,-z,common-page-size=$PAGESZ -Wl,-z,max-page-size=16384"
|
|
|
|
if [ ! -d "$COSMO" ]; then
|
|
fatal_error "you need to clone cosmopolitan to your $COSMO directory"
|
|
fi
|
|
|
|
if [ "$1" = "--update" ]; then
|
|
cd $COSMO || exit
|
|
echo "building cosmo host toolchain..." >&2
|
|
make --silent -j toolchain MODE= || exit
|
|
echo "building cosmo target (MODE=$MODE) toolchain..." >&2
|
|
make --silent -j toolchain MODE="$MODE" || exit
|
|
echo "setting up your cosmos..." >&2
|
|
mkdir -p "$COSMOS/lib" || exit
|
|
for lib in c dl gcc_s m pthread resolv rt dl z stdc++; do
|
|
if [ ! -f "$COSMOS/lib/lib${lib}.a" ]; then
|
|
printf '\041\074\141\162\143\150\076\012' >"$COSMOS/lib/lib${lib}.a" || exit
|
|
fi
|
|
done
|
|
echo "successfully updated your cosmo toolchain" >&2
|
|
exit
|
|
fi
|
|
|
|
if [ ! -f "$COSMOS/lib/libc.a" ] ||
|
|
[ ! -f "$COSMO/o/$MODE/cosmopolitan.a" ]; then
|
|
fatal_error "you need to run: $PROG --update"
|
|
fi
|
|
|
|
OPT=
|
|
FIRST=1
|
|
OUTPUT=
|
|
SFLAG=0
|
|
INTENT=ld
|
|
GOT_SOME=0
|
|
NEED_OUTPUT=
|
|
RELOCATABLE=0
|
|
for x; do
|
|
if [ $FIRST -eq 1 ]; then
|
|
set --
|
|
FIRST=0
|
|
fi
|
|
if [ -n "$NEED_OUTPUT" ]; then
|
|
NEED_OUTPUT=
|
|
OUTPUT=$x
|
|
set -- "$@" "$x"
|
|
continue
|
|
fi
|
|
if [ x"$x" = x"-" ] || # is an argument
|
|
[ x"$x" = x"${x#-*}" ]; then # !startswith(x, "-")
|
|
GOT_SOME=1
|
|
elif [ x"$x" = x"-static-libstdc++" ]; then
|
|
continue
|
|
elif [ x"$x" = x"-static-libgcc" ]; then
|
|
continue
|
|
elif [ x"$x" != x"${x#-O}" ]; then
|
|
OPT=$x
|
|
elif [ x"$x" = x"-c" ]; then
|
|
INTENT=cc
|
|
elif [ x"$x" = x"-s" ]; then
|
|
SFLAG=1
|
|
continue
|
|
elif [ x"$x" = x"-r" ]; then
|
|
RELOCATABLE=1
|
|
elif [ x"$x" = x"-E" ]; then
|
|
INTENT=cpp
|
|
elif [ x"$x" = x"-o" ]; then
|
|
NEED_OUTPUT=1
|
|
elif [ x"$x" = x"-mcosmo" ]; then
|
|
CPPFLAGS="$CPPFLAGS -D_COSMO_SOURCE"
|
|
continue
|
|
elif [ x"$x" != x"${x#-o}" ]; then
|
|
OUTPUT=${x#-o}
|
|
elif [ x"$x" = x"-fpic" ]; then
|
|
continue
|
|
elif [ x"$x" = x"-fPIC" ]; then
|
|
continue
|
|
elif [ x"$x" = x"-r" ] ||
|
|
[ x"$x" = x"-pie" ] ||
|
|
[ x"$x" = x"-frtti" ] ||
|
|
[ x"$x" = x"-shared" ] ||
|
|
[ x"$x" = x"-nostdlib" ] ||
|
|
[ x"$x" = x"-mred-zone" ] ||
|
|
[ x"$x" = x"-fexceptions" ] ||
|
|
[ x"$x" = x"-fsanitize=thread" ]; then
|
|
echo "$PROG: $x not supported" >&2
|
|
exit 1
|
|
elif [ x"$x" = x"-fsanitize=all" ] ||
|
|
[ x"$x" = x"-fsanitize=address" ] ||
|
|
[ x"$x" = x"-fsanitize=undefined" ]; then
|
|
echo "$PROG: use cosmo MODE=dbg or MODE=asan rather than passing $x" >&2
|
|
exit 1
|
|
elif [ x"$x" = x"-fomit-frame-pointer" ]; then
|
|
# Quoth Apple "The frame pointer register must always address a
|
|
# valid frame record. Some functions — such as leaf functions or
|
|
# tail calls — may opt not to create an entry in this list. As a
|
|
# result, stack traces are always meaningful, even without debug
|
|
# information."
|
|
set -- "$@" -momit-leaf-frame-pointer -foptimize-sibling-calls
|
|
continue
|
|
elif [ x"$x" != x"${x#-Werror}" ] || \
|
|
[ x"$x" = x"-pedantic-errors" ]; then
|
|
# this toolchain is intended for building other people's code
|
|
# elevating warnings into errors, should only be done by devs
|
|
continue
|
|
elif [ x"$x" = x"-march=native" ]; then
|
|
if [ $CROSS -eq 0 ]; then
|
|
set -- "$@" $("$COSMO/o//tool/build/march-native.com")
|
|
else
|
|
fatal_error "-march=native can't be used when cross compiling"
|
|
fi
|
|
continue
|
|
elif [ x"$x" = x"-dumpversion" ]; then
|
|
echo $GCC_VERSION
|
|
exit 0
|
|
fi
|
|
set -- "$@" "$x"
|
|
done
|
|
|
|
if [ "$GOT_SOME" -eq 0 ]; then
|
|
fatal_error "no input files"
|
|
fi
|
|
|
|
if [ $RELOCATABLE -eq 1 ]; then
|
|
LDFLAGS="$LDFLAGS -r"
|
|
fi
|
|
|
|
if [ x"$MODE" = x"nox87" ]; then
|
|
CPPFLAGS="$CPPFLAGS -mlong-double-64"
|
|
fi
|
|
|
|
# support --ftrace unless optimizing for size
|
|
if [ x"$OPT" != x"-Os" ] && # $OPT != -Os
|
|
[ x"${MODE%tiny}" = x"${MODE}" ]; then # $MODE not in (tiny, aarch64-tiny)
|
|
if [ x"$ARCH" = x"x86_64" ]; then
|
|
CFLAGS="$CFLAGS -fpatchable-function-entry=18,16"
|
|
elif [ x"$ARCH" = x"aarch64" ]; then
|
|
CFLAGS="$CFLAGS -fpatchable-function-entry=7,6"
|
|
fi
|
|
fi
|
|
|
|
# ask compiler to generate sanitization code in debug mode
|
|
if [ x"$MODE" != x"${MODE%*dbg}" ]; then # endswith($MODE, "dbg")
|
|
if [ x"$ARCH" = x"x86_64" ]; then
|
|
CPPFLAGS="$CPPFLAGS -fsanitize=address -fsanitize=undefined"
|
|
else
|
|
CPPFLAGS="$CPPFLAGS -fsanitize=undefined"
|
|
fi
|
|
fi
|
|
|
|
# ask compiler to generate memory safety code in asan mode
|
|
if [ x"$MODE" != x"${MODE%*asan}" ]; then # endswith($MODE, "asan")
|
|
if [ x"$ARCH" = x"x86_64" ]; then
|
|
CPPFLAGS="$CPPFLAGS -fsanitize=address"
|
|
else
|
|
fatal_error "address sanitizer not supported on non-x86 yet"
|
|
fi
|
|
fi
|
|
|
|
# maximize frame pointers unless optimizing for size
|
|
if [ x"$OPT" != x"-Os" ] && # $OPT != "-Os"
|
|
[ x"$MODE" != x"${MODE%tiny}" ]; then # endswith($MODE, "tiny")
|
|
CFLAGS="$CFLAGS -fno-optimize-sibling-calls -mno-omit-leaf-frame-pointer"
|
|
fi
|
|
|
|
if [ $INTENT = cpp ]; then
|
|
set -- "$CC" $PLATFORM $CPPFLAGS "$@"
|
|
elif [ $INTENT = cc ]; then
|
|
set -- "$CC" $PLATFORM $PREDEF $CFLAGS $CPPFLAGS "$@" $PRECIOUS
|
|
else
|
|
set -- "$CC" $PLATFORM $PREDEF $CFLAGS $CPPFLAGS $CRT "$@" $LDFLAGS $LDLIBS $PRECIOUS
|
|
fi
|
|
|
|
log_command "$@"
|
|
"$@" || exit
|
|
|
|
if [ -n "$OUTPUT" ] && [ -f "$OUTPUT" ]; then
|
|
if [ $INTENT = cc ] || [ $INTENT = ld ]; then
|
|
"$COSMO/o//tool/build/fixupobj.com" \
|
|
"$OUTPUT" || exit
|
|
fi
|
|
if [ $INTENT = ld ]; then
|
|
if [ x"$OUTPUT" != x"${OUTPUT%.com}" ] ||
|
|
[ x"$OUTPUT" != x"${OUTPUT%.exe}" ]; then
|
|
# cosmocc -o foo.com ...
|
|
# -> foo.com (ape)
|
|
# -> foo.com.dbg (elf)
|
|
mv -f "$OUTPUT" "$OUTPUT.dbg" || exit
|
|
"$COSMO/o/third_party/gcc/bin/$ARCH-linux-musl-objcopy" \
|
|
$OBJCOPYFLAGS \
|
|
"$OUTPUT.dbg" \
|
|
"$OUTPUT" || exit
|
|
"$COSMO/o//tool/build/zipcopy.com" \
|
|
"$OUTPUT.dbg" \
|
|
"$OUTPUT" || exit
|
|
elif [ $SFLAG -eq 1 ]; then
|
|
"$COSMO/o/third_party/gcc/bin/$ARCH-linux-musl-strip" \
|
|
"$OUTPUT" || exit
|
|
fi
|
|
fi
|
|
fi
|