Last active
May 2, 2023 12:20
-
-
Save avih/467b307051bf01bc9c8475221a59513d to your computer and use it in GitHub Desktop.
cosmocc script to simplify usage of the cosmopolitan.zip bundle
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
[ "${COSMOXX-}" ] && set -x || : | |
# name: cosmocc | |
# self-contained replacement for the cc command which uses cosmopolitan libc | |
# see https://justine.lol/cosmopolitan/index.html | |
# home: https://gist.github.com/avih/467b307051bf01bc9c8475221a59513d | |
# based on: https://github.com/jart/cosmopolitan/blob/master/tool/scripts/cosmocc | |
# requires: gcc or clang installed | |
# | |
# how to use: | |
# download a cosmopolitan[-variant].zip bundle of your choice from here | |
# https://justine.lol/cosmopolitan/download.html then extract it to some | |
# dir X, place this file in X, ensure it's executable, link to it from PATH | |
# | |
# or, create a dir X where the cosmopolitan files will be stored, then | |
# copy this script into X, and link to it from someplace at PATH. | |
# this will download the main cosmopolitan.zip bundle on first run. | |
# | |
# or, set COSMO below to an absolute dir path which will hold the files, | |
# and place or link to this file someplace at PATH. the dir will be created | |
# automatically on first run, before downloading the zip. | |
# | |
# E.g., assuming ~/.local/bin is in PATH, and that this file | |
# is ~/cosmocc and executable: | |
# mkdir ~/cosmo && cp ~/cosmocc ~/cosmo/ && ln -s ~/cosmo/cosmocc ~/.local/bin/ | |
# | |
# then use "cosmocc" instead of "cc", e.g: | |
# cosmocc myapp.c -o myapp.com.dbg | |
# or: | |
# cosmocc -c file1.c file2.c && cosmocc file1.o file2.o -o myapp.com.dbg | |
# or: | |
# make CC=cosmocc ... && cosmocc --cosmo2ape path/to/myapp | |
# etc. | |
# | |
# | |
# first run does initial setup - create the dir if needed, | |
# download and extract the cosmopolitan zip if needed, setup some | |
# default include wrappers and shell lib files in that dir. | |
# | |
# when creating binaries, e.g. cosmocc file.c -o myapp | |
# then the resulting file runs on linux but is not actually APE. | |
# it needs an additional step: objcopy -S -O binary myapp myapp.com | |
# if the binary has a .com.dbg extension, then two things will happen: | |
# - the objcopy command is invoked automatically to create a .com APE file | |
# - the .com APE file will use the symbols at the .com.dbg file | |
# when tracing functions, e.g. myapp.com --ftrace ... | |
# (with default or "dbg" cosmopolitan.zip variants, but not "tiny") | |
# for instance: cosmocc file.c -o file.com.dbg | |
# creates file.com too, which can use the debug symbols at file.com.dbg | |
# NOTE: don't use strip on the resulting binaries. | |
# | |
# If the binary was created using a Makefile or some other build system | |
# and the application ends up without .com.dbg suffix, then this command will | |
# rename it and also create the APE file: cosmocc --cosmo2ape path/to/myapp | |
# | |
# ENV vars: | |
# COSMOCC=... set a specific compiler to use. default is gcc or clang or cc | |
# COSMOX=1 trace the compiler commands | |
# COSMOXX=1 trace the whole script | |
# if readlink -f is unavailable, or if this file is outside the cosmo dir | |
# then set COSMO manually to the full path to the dir (without trail /) | |
COSMO=$(dirname -- "$(readlink -f -- "$0")") | |
one_val() { [ "$#" = 1 ] && [ "$1" ]; } | |
one_val $COSMO || | |
{ >&2 echo "$0: \$COSMO must be non-nul, no spaces -- '$COSMO'"; exit 1; } | |
if [ "${1-}" = --cosmo2ape ]; then | |
shift | |
[ "${1-}" != -- ] || shift | |
[ -x "${1-}" ] || | |
{ echo "Usage: $0 --cosmo2ape APP... cosmo binary -> APE"; exit 1; } | |
( set -x | |
for f; do | |
mv -- "$f" "$f.com.dbg" | |
objcopy -S -O binary -- "$f.com.dbg" "$f.com" | |
done | |
); exit | |
fi | |
# download the archive if missing | |
[ -e "$COSMO"/cosmopolitan.a ] || ( | |
# for variants, see: https://justine.lol/cosmopolitan/download.html | |
variant= # <empty> | tiny | tinylinux | rel | asan | dbg | |
f=cosmopolitan${variant:+-$variant}.zip | |
mkdir -p -- "$COSMO" && | |
cd "$COSMO" && | |
{ ! [ -e "$f" ] || mv -- "$f" "prev.$f"; } && | |
wget -- "https://justine.lol/cosmopolitan/$f" && | |
unzip -- "$f" && | |
rm -rf lib include | |
) || exit | |
# ensure shell includes | |
posix_includes=" | |
aio.h arpa/inet.h assert.h complex.h cpio.h ctype.h dirent.h dlfcn.h | |
errno.h fcntl.h fenv.h float.h fmtmsg.h fnmatch.h ftw.h glob.h grp.h | |
iconv.h inttypes.h iso646.h langinfo.h libgen.h limits.h locale.h | |
math.h monetary.h mqueue.h ndbm.h net/if.h netdb.h netinet/in.h | |
netinet/tcp.h nl_types.h poll.h pthread.h pwd.h regex.h sched.h | |
search.h semaphore.h setjmp.h signal.h spawn.h stdarg.h stdbool.h | |
stddef.h stdint.h stdio.h stdlib.h string.h strings.h stropts.h | |
sys/ipc.h sys/mman.h sys/msg.h sys/resource.h sys/select.h sys/sem.h | |
sys/shm.h sys/socket.h sys/stat.h sys/statvfs.h sys/time.h | |
sys/times.h sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h | |
syslog.h tar.h termios.h tgmath.h time.h trace.h ulimit.h unistd.h | |
utime.h utmpx.h wchar.h wctype.h wordexp.h | |
" | |
if ! [ -d "$COSMO/include" ]; then | |
mkdir -p "$COSMO/include" | |
for inc in $posix_includes; do | |
case $inc in */*) mkdir -p $COSMO/include/${inc%/*}; esac | |
ln -s -- "$COSMO/cosmopolitan.h" "$COSMO/include/$inc" 2>/dev/null || | |
printf %s\\n "#include \"$COSMO/cosmopolitan.h\"" >"$COSMO/include/$inc" | |
done | |
fi | |
# the following is adapted from: | |
# https://github.com/jart/cosmopolitan/blob/master/tool/scripts/cosmocc | |
# auto-install some shell libraries | |
if [ ! -d $COSMO/lib ]; then | |
mkdir $COSMO/lib | |
# FIXME: other than libc, which of those actually exist at cosmopolitan.a? | |
for lib in c dl gcc_s m pthread resolv rt z stdc++; do | |
printf '\041\074\141\162\143\150\076\012' >$COSMO/lib/lib$lib.a | |
done | |
fi | |
if [ "$1" = "--version" ]; then | |
cat <<'EOF' | |
x86_64-unknown-cosmo-gcc (GCC) 9.2.0 | |
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. | |
EOF | |
exit 0 | |
fi | |
has_nop_mcount() { | |
echo "int main() {return 0;}" | | |
"$1" -c -xc - -o /dev/null -mnop-mcount 2>/dev/null | |
} | |
: ${COSMOCC:=$(which gcc || which clang || which cc)} | |
has_nop_mcount "$COSMOCC" && NOPMCOUNT=-mnop-mcount || NOPMCOUNT= | |
CFLAGS="-g -O2 -fdata-sections -ffunction-sections -fno-pie -pg $NOPMCOUNT \ | |
-mno-tls-direct-seg-refs" | |
CPPFLAGS="-DNDEBUG -nostdinc -isystem $COSMO/include" | |
LDFLAGS="-static -no-pie -nostdlib -fuse-ld=bfd -Wl,-melf_x86_64 \ | |
-Wl,--gc-sections -Wl,-z,max-page-size=0x1000 \ | |
-L$COSMO/lib -Wl,-T,$COSMO/ape.lds \ | |
$COSMO/ape-no-modify-self.o $COSMO/crt.o" | |
LDLIBS=$COSMO/cosmopolitan.a | |
HAS_C= HAS_E= | |
O= NEXT_IS_O= | |
for x; do shift | |
if [ "$NEXT_IS_O" ]; then | |
O=$x NEXT_IS_O= | |
set -- "$@" "$x" | |
continue | |
fi | |
case $x in | |
-Werror|-pedantic) | |
# this toolchain is intended for building other people's code | |
# elevating warnings into errors, should only be done by devs | |
# we don't need the compiler's assistance to be more portable | |
>&2 printf %s\\n "$0: ignoring $x" | |
continue | |
;; | |
-c) HAS_C=x ;; | |
-E) HAS_E=x ;; | |
-o) NEXT_IS_O=x ;; | |
-o*) O=${x#-o} ;; | |
esac | |
set -- "$@" "$x" | |
done | |
if [ "$HAS_E" ]; then | |
set -- $CPPFLAGS "$@" | |
elif [ "$HAS_C" ]; then | |
set -- $CFLAGS $CPPFLAGS "$@" -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer | |
else # [compile and] link | |
set -- $LDFLAGS $CFLAGS $CPPFLAGS "$@" $LDLIBS -Wl,-z,common-page-size=4096 -Wl,-z,max-page-size=4096 | |
fi | |
set -- "$COSMOCC" "$@" | |
printf '(cd %s; %s)\n' "$PWD" "$*" >>/tmp/$(basename -- "$0").log | |
[ "${COSMOX-}" ] && set -x || : | |
"$@" && { | |
if [ -x "$O" ]; then | |
case $O in *.com.dbg) | |
out=${O%.dbg} | |
>&2 printf %s\\n "[auto: $O --> $out]" | |
objcopy -S -O binary "$O" "$out" | |
esac | |
fi | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment