Make cosmocc capable of cross compilation

This commit is contained in:
Justine Tunney 2023-08-13 14:38:33 -07:00
parent 504a4bbf84
commit d1b937bf1d
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
21 changed files with 439 additions and 132 deletions

View file

@ -11,43 +11,43 @@
# ape-install # optionally install a faster systemwide ape loader
# cosmocc --update # pull and rebuild toolchain artifacts
#
# building open source projects
# getting started synopsis
#
# export CC=cosmocc
# export CXX=cosmoc++
# ./configure --prefix=/opt/cosmos
# make -j
# make install
# cosmocc -o hello.com hello.c
# ./foo.com
# ./foo.com --strace
# ./foo.com --ftrace
#
# cosmopolitan runtime flags
# how to build a project like lua 5.4.6
#
# ./hello.com --strace
# ./hello.com --ftrace
# 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
#
# cosmpolitan runtime libraries
# how to cross compile a project like lua 5.4.6
#
# #include <cosmo.h>
# int main() {
# ShowCrashReports();
# __builtin_trap();
# }
# 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
# (cd /opt/cosmo; make -j8 toolchain)
# cosmocc --update
# cosmocc -Os -o foo.com foo.c
#
# building in tiniest mode (linux only)
#
# export MODE=tinylinux
# (cd /opt/cosmo; make -j8 toolchain)
# cosmocc --update
# cosmocc -Os -o foo.com foo.c
#
# hardening programs with memory safety
#
# export MODE=asan
# (cd /opt/cosmo; make -j8 toolchain)
# cosmocc --update
# cosmocc -o foo.com foo.c
#
# detecting this environment
@ -77,74 +77,134 @@
# for further details, run `man gcc`
PROG=${0##*/}
MODE=${MODE:-$m}
COSMO=${COSMO:-/opt/cosmo}
COSMOS=${COSMOS:-/opt/cosmos}
GCC_VERSION=11.2.0
if [ "$1" = "--version" ]; then
# note: only the underlying gcc compiler binaries are gpl
# our shell script is released with the isc license
# absolutely zero cosmo runtime libraries are gpl'd
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 is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
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 0
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"
CPPFLAGS="-fno-pie -nostdinc -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/public/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=$PAGESZ"
if [ ! -d "$COSMO" ]; then
fatal_error "you need to clone cosmopolitan to your $COSMO directory"
fi
if [ "$1" = "--update" ]; then
cd /opt/cosmo || exit
if GIT=$(command -v git); then
echo "$PROG: running git pull on cosmo..." >&2
echo "running git pull on cosmo..." >&2
"$GIT" pull --quiet || exit
fi
echo "$PROG: building cosmo x86_64 toolchain..." >&2
make --silent -j toolchain MODE="${MODE}" || exit
"$COSMO/tool/scripts/setup-cosmos"
echo "$PROG: successfully updated your cosmo toolchain" >&2
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
CC="$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-gcc"
ORIGINAL="$0 $*"
PLATFORM="-D__COSMOPOLITAN__"
PREDEF="-include libc/integral/normalize.inc"
CCFLAGS="-fno-pie -mno-tls-direct-seg-refs -mno-red-zone -fportcosmo"
CPPFLAGS="-nostdinc -iquote $COSMO -isystem $COSMOS/include -isystem $COSMO/libc/isystem"
LDFLAGS="-static -no-pie -nostdlib -fuse-ld=bfd -Wl,-melf_x86_64 -Wl,-z,common-page-size=4096 -Wl,-z,max-page-size=4096"
APEFLAGS="-L$COSMOS/lib -Wl,--gc-sections -Wl,-T,$COSMO/o/$MODE/ape/public/ape.lds $COSMO/o/$MODE/ape/ape-no-modify-self.o $COSMO/o/$MODE/libc/crt/crt.o"
LDLIBS="$COSMO/o/$MODE/cosmopolitan.a"
if [ x"$0" != x"${0%++}" ]; then
CC="$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-g++"
CCFLAGS="$CCFLAGS -fno-rtti -fno-exceptions -fuse-cxa-atexit"
LDLIBS="$COSMO/o/$MODE/third_party/libcxx/libcxx.a $LDLIBS"
fi
if [ ! -d "$COSMO" ]; then
echo "$PROG: you need to clone cosmopolitan to your $COSMO directory" >&2
exit 1
fi
if [ ! -d "$COSMOS" ] ||
if [ ! -f "$COSMOS/lib/libc.a" ] ||
[ ! -f "$COSMO/o/$MODE/cosmopolitan.a" ]; then
echo "$PROG: you need to run: $PROG --update" >&2
exit 1
fatal_error "you need to run: $PROG --update"
fi
# auto-install some shell libraries
if [ ! -d "$COSMOS/lib" ]; then
mkdir -p "$COSMOS/lib"
fi
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"
fi
done
OPT=
FIRST=1
OUTPUT=
@ -203,7 +263,7 @@ for x; do
elif [ x"$x" = x"-fsanitize=all" ] ||
[ x"$x" = x"-fsanitize=address" ] ||
[ x"$x" = x"-fsanitize=undefined" ]; then
echo "$PROG: use cosmo MODE=dbg rather than passing $x" >&2
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
@ -219,7 +279,11 @@ for x; do
# elevating warnings into errors, should only be done by devs
continue
elif [ x"$x" = x"-march=native" ]; then
set -- "$@" $("$COSMO/o/$MODE/tool/build/march-native.com")
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
@ -229,55 +293,66 @@ for x; do
done
if [ "$GOT_SOME" -eq 0 ]; then
echo "$PROG: fatal error: no input files" >&2
echo "compilation terminated." >&2
exit 1
fatal_error "no input files"
fi
if [ $RELOCATABLE -eq 1 ]; then
APEFLAGS="-r"
LDFLAGS="$LDFLAGS -r"
fi
if [ x"$MODE" = x"nox87" ]; then
CCFLAGS="$CCFLAGS -mlong-double-64"
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)
# support --ftrace unless optimizing for size
CCFLAGS="$CCFLAGS -fpatchable-function-entry=18,16"
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
if [ x"$MODE" = x"dbg" ]; then
set -- \
-fsanitize=address \
-fsanitize=undefined \
"$@"
# 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
if [ x"$OPT" != x"-Os" ] &&
[ x"${MODE#tiny}" != x"${MODE}" ]; then
set -- \
-fno-optimize-sibling-calls \
-mno-omit-leaf-frame-pointer \
"$@"
# 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 $CCFLAGS $CPPFLAGS "$@"
set -- "$CC" $PLATFORM $CPPFLAGS "$@"
elif [ $INTENT = cc ]; then
set -- "$CC" $PLATFORM $PREDEF $CCFLAGS $CPPFLAGS "$@" -fno-omit-frame-pointer
set -- "$CC" $PLATFORM $PREDEF $CFLAGS $CPPFLAGS "$@" $PRECIOUS
else
set -- "$CC" $PLATFORM $PREDEF $CCFLAGS $CPPFLAGS $CPPFLAGS "$@" \
$LDFLAGS $APEFLAGS $LDLIBS -fno-omit-frame-pointer
set -- "$CC" $PLATFORM $PREDEF $CFLAGS $CPPFLAGS $CRT "$@" $LDFLAGS $LDLIBS $PRECIOUS
fi
printf '# %s\n(cd %s; %s)\n' "$ORIGINAL" "$PWD" "$*" >>"${TMPDIR:-/tmp}/build.log"
log_command "$@"
"$@" || exit
if [ -n "$OUTPUT" ] && [ -f "$OUTPUT" ]; then
if [ $INTENT = cc ] || [ $INTENT = ld ]; then
"$COSMO/o/$MODE/tool/build/fixupobj.com" "$OUTPUT" || exit
"$COSMO/o//tool/build/fixupobj.com" \
"$OUTPUT" || exit
fi
if [ $INTENT = ld ]; then
if [ x"$OUTPUT" != x"${OUTPUT%.com}" ] ||
@ -286,10 +361,16 @@ if [ -n "$OUTPUT" ] && [ -f "$OUTPUT" ]; then
# -> foo.com (ape)
# -> foo.com.dbg (elf)
mv -f "$OUTPUT" "$OUTPUT.dbg" || exit
"$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-objcopy" -S -O binary "$OUTPUT.dbg" "$OUTPUT" || exit
"$COSMO/o/$MODE/tool/build/zipcopy.com" "$OUTPUT.dbg" "$OUTPUT" || 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/x86_64-linux-musl-strip" "$OUTPUT" || exit
"$COSMO/o/third_party/gcc/bin/$ARCH-linux-musl-strip" \
"$OUTPUT" || exit
fi
fi
fi