diff --git a/Makefile b/Makefile index f0ce482c4..0bf8a9db0 100644 --- a/Makefile +++ b/Makefile @@ -209,7 +209,6 @@ include third_party/chibicc/test/test.mk include third_party/python/python.mk include tool/build/build.mk include tool/curl/curl.mk -include tool/ape/ape.mk include third_party/qemu/qemu.mk include examples/examples.mk include examples/pyapp/pyapp.mk @@ -433,6 +432,7 @@ TOOLCHAIN_ARTIFACTS = \ o/$(MODE)/third_party/libcxx/libcxx.a \ o/$(MODE)/tool/build/march-native.com \ o/$(MODE)/tool/build/ar.com \ + o/$(MODE)/tool/build/mktemper.com \ o/$(MODE)/tool/build/fixupobj.com \ o/$(MODE)/tool/build/zipcopy.com \ o/$(MODE)/tool/build/apelink.com \ diff --git a/ape/ape.lds b/ape/ape.lds index 446cfa396..c45756ca3 100644 --- a/ape/ape.lds +++ b/ape/ape.lds @@ -770,6 +770,8 @@ ASSERT(ape_stack_vaddr % ape_stack_memsz == 0, ASSERT(ALIGNOF(.tdata) <= TLS_ALIGNMENT && ALIGNOF(.tbss) <= TLS_ALIGNMENT, "_Thread_local _Alignof can't exceed TLS_ALIGNMENT"); +ASSERT(DEFINED(main), "main() function not defined"); + /* Let's not be like Knight Capital. */ /* NOCROSSREFS_TO(.test .text) */ diff --git a/bin/cosmocc b/bin/cosmocc index 5f4b801b0..0dc1ac636 100755 --- a/bin/cosmocc +++ b/bin/cosmocc @@ -1,13 +1,14 @@ #!/bin/sh # -# non-fat cosmopolitan c compiler +# cosmopolitan c/c++ compiler # # getting started # -# sudo chmod 1777 /opt +# sudo chmod 1777 /opt # sticky bit isn't required # git clone https://github.com/jart/cosmopolitan /opt/cosmo # export PATH="$PATH:/opt/cosmo/bin:/opt/cosmos/bin" # echo 'export PATH="$PATH:/opt/cosmo/bin:/opt/cosmos/bin"' >>~/.profile +# ape-install # optionally install a faster systemwide ape loader # cosmocc --update # pull and rebuild toolchain artifacts # # building open source projects @@ -49,15 +50,44 @@ # (cd /opt/cosmo; make -j8 toolchain) # 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##*/} 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 <&2 + exit 1 +} + +if [ ! -x "$COSMO/o/$MODE/tool/build/ar.com" ]; then + fatal_error "you need to run: fatcosmocc --update" +fi + +if [ x"$1" = x"rc" ] || + [ x"$1" = x"rcD" ] || + [ x"$1" = x"rcu" ] | + [ x"$1" = x"rcuD" ] || + [ x"$1" = x"rcs" ] || + [ x"$1" = x"rcsD" ] || + [ x"$1" = x"--help" ] || + [ x"$1" = x"--version" ]; then + # binutils ar is accidentally quadratic + # cosmopolitan ar is significantly faster + # it'll also use tricks like copy_file_range + AR_X86_64="$COSMO/o/$MODE/tool/build/ar.com" + AR_AARCH64="$COSMO/o/$MODE/tool/build/ar.com" + if [ "$1" = "--help" ] || + [ "$1" = "--version" ]; then + exec "$AR_X86_64" "$1" + fi +else + AR_X86_64="$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-ar" + AR_AARCH64="$COSMO/o/third_party/gcc/bin/aarch64-linux-musl-ar" + if [ "$1" = "--version" ]; then + # note: only the underlying gnu compiler binaries are gpl + # our shell script is released with the isc license + cat </dev/null || + "$AR_X86_64" --help + exit + fi +fi + +FIRST=1 +STATE=0 +OUTPUT_X86_64= +OUTPUT_AARCH64= +INPUTS= +for x; do + if [ $FIRST -eq 1 ]; then + set -- + FIRST=0 + fi + if [ $STATE -eq 0 ]; then + if [ x"$x" != x"${x#--*}" ]; then # startswith(x, "--") + set -- "$@" "$x" # this is a flag + else + set -- "$@" "$x" # command argument, e.g. rcu, rcsD + STATE=1 + fi + elif [ $STATE -eq 1 ]; then + OUTPUT_X86_64=$x + STATE=2 + elif [ x"$x" != x"${x#* }" ]; then + fatal_error "input arguments containing spaces unsupported" + elif [ x"$x" != x"${x#@}" ]; then + fatal_error "input argument @file not supported yet" + elif [ -z "$INPUTS" ]; then + INPUTS=$x + else + INPUTS="$INPUTS $x" + fi +done +if [ -z "$OUTPUT_X86_64" ]; then + fatal_error "missing output path" +fi + +mangle_object_path() { + path=$1 + arch=$2 + outdir=${path%/*} + outbas=${path##*/} + if [ x"$outdir" = x"$path" ]; then + outdir= + elif [ -n "$outdir" ]; then + outdir="$outdir/" + fi + if [ ! -d "$outdir.$arch" ]; then + mkdir -p "$outdir.$arch" || Exit + fi + mangled_path="${outdir}.$arch/$outbas" +} + +OBJECTS_X86_64= +OBJECTS_AARCH64= +for x in $INPUTS; do + if [ ! -f "$x" ]; then + fatal_error "$x: no such file" + fi + mangle_object_path "$x" aarch64 + if [ ! -f "$mangled_path" ]; then + fatal_error "$x: missing concomitant $mangled_path file" + fi + OBJECTS_X86_64="${OBJECTS_X86_64} $x" + OBJECTS_AARCH64="${OBJECTS_AARCH64} $mangled_path" +done + +mangle_object_path "$OUTPUT_X86_64" aarch64 +OUTPUT_AARCH64="$mangled_path" + +"$AR_X86_64" "$@" "$OUTPUT_X86_64" $OBJECTS_X86_64 & +pid1=$! + +"$AR_AARCH64" "$@" "$OUTPUT_AARCH64" $OBJECTS_AARCH64 & +pid2=$! + +if ! wait $pid1; then + kill $pid2 2>/dev/null + wait + exit 1 +fi +wait $pid2 || exit diff --git a/bin/fatcosmocc b/bin/fatcosmocc index 346970fdc..82f3bcc1a 100755 --- a/bin/fatcosmocc +++ b/bin/fatcosmocc @@ -1,6 +1,6 @@ #!/bin/sh # -# fat cosmopolitan c compiler +# fat cosmopolitan c/c++ compiler # # - this command is a drop-in replacement for the cc or gcc command. # the difference is that (1) your binaries will be linked with the @@ -24,10 +24,11 @@ # # installation # -# sudo chmod 1777 /opt +# sudo chmod 1777 /opt # sticky bit isn't required # git clone https://github.com/jart/cosmopolitan /opt/cosmo # export PATH="$PATH:/opt/cosmo/bin:/opt/cosmos/bin" # echo 'export PATH="$PATH:/opt/cosmo/bin:/opt/cosmos/bin"' >>~/.profile +# ape-install # optionally install a faster systemwide ape loader # fatcosmocc --update # pull and rebuild toolchain artifacts # # getting started @@ -36,27 +37,6 @@ # ./foo.com # ./foo.com.dbg # -# building open source projects -# -# export CC=fatcosmocc -# export CXX=fatcosmoc++ -# ./configure --prefix=/opt/cosmos -# make -j -# make install -# -# cosmopolitan runtime flags -# -# ./hello.com --strace -# ./hello.com --ftrace -# -# cosmpolitan runtime libraries -# -# #include -# int main() { -# ShowCrashReports(); -# __builtin_trap(); -# } -# # building in tiny mode # # export MODE=tiny @@ -69,15 +49,57 @@ # fatcosmocc --update # fatcosmocc -g -o foo.com foo.c # +# building a project like lua 5.4.6 +# +# make all test CC=fatcosmocc AR='fatcosmoar rcu' +# +# detecting this environment +# +# - `__FATCOSMOCC__` 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 +# - you may need to recalibrate `make -jN` as `N/2` +# +# compiler flags that work differently +# +# - `-v` will log fatcosmocc subcommands to stderr +# - `-s` will ask apelink to not embed symbol tables in zip +# - `-E` can't be fat and runs once with x86_64 macros undefined +# - `-save-temps` will prevent deleting your arch-specific executables +# +# compiler flags that aren't supported +# +# - `-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` export PROG=${0##*/} export COSMO=${COSMO:-/opt/cosmo} export COSMOS=${COSMOS:-/opt/cosmos} export ORIGINAL="$0 $*" +export TMPDIR=${TMPDIR:-/tmp} +export BUILDLOG= +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 +# and the apelink.com program is definitely not gpl cat <&2 +} + +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 +} + +if [ x"$TMPDIR" != x"${TMPDIR#* }" ]; then + fatal_error '$TMPDIR containing spaces not supported' +fi +if [ ! -d "$TMPDIR" ]; then + if ! mkdir -p "$TMPDIR" 2>/dev/null; then + fatal_error "$TMPDIR: not a directory" + fi +fi + OPT= +FILES= FIRST=1 OUTPUT= -STRIP=0 INTENT=ld -GOT_SOME=0 -SAVE_TEMPS=0 NEED_OUTPUT= +APELINKFLAGS= FRAME="" for x; do if [ $FIRST -eq 1 ]; then @@ -147,22 +213,47 @@ for x; do OUTPUT=$x continue fi - if [ x"$x" = x"${x#-*}" ]; then - GOT_SOME=1 + if [ x"$x" = x"-" ] || # is an argument + [ x"$x" = x"${x#-*}" ]; then # !startswith(x, "-") + if [ x"$x" != x"${x#* }" ]; then + fatal_error "input arguments containing spaces unsupported" + elif [ x"$x" != x"${x%.s}" ] || + [ x"$x" != x"${x%.S}" ]; then + fatal_error "$x: assembler input files not supported" + elif [ x"$x" != x"${x%.so}" ] || + [ x"$x" != x"${x%.dll}" ] || + [ x"$x" != x"${x%.dylib}" ]; then + fatal_error "$x: dynamic shared object input files not supported" + elif [ x"$x" != x"-" ] && [ ! -f "$x" ]; then + fatal_error "$x: no such file" + fi + if [ -z "$FILES" ]; then + FILES=$x + else + FILES="$FILES $x" + fi + continue elif [ x"$x" = x"-o" ]; then NEED_OUTPUT=1 continue - elif [ x"$x" != x"${x#-o}" ]; then + elif [ x"$x" != x"${x#-o}" ]; then # startswith(x, "-o") OUTPUT=${x#-o} continue - elif [ x"$x" != x"${x#-O}" ]; then + elif [ x"$x" != x"${x#-O}" ]; then # startswith(x, "-O") OPT=$x elif [ x"$x" = x"-c" ]; then INTENT=cc elif [ x"$x" = x"-E" ]; then INTENT=cpp elif [ x"$x" = x"-s" ]; then - STRIP=1 + APELINKFLAGS="$APELINKFLAGS -s" + continue + elif [ x"$x" = x"-v" ]; then + exec 3<&2 # dup2(2, 3) b/c stderr will be redirected later + export BUILDLOG=/dev/fd/3 + continue + elif [ x"$x" = x"-x-save-tmps" ]; then + SAVE_TMPS=1 continue elif [ x"$x" = x"-save-temps" ]; then SAVE_TEMPS=1 @@ -172,8 +263,10 @@ for x; do # tail calls — may opt not to create an entry in this list. As a # result, stack traces are always meaningful, even without debug # information." - x="-momit-leaf-frame-pointer" + set -- "$@" -momit-leaf-frame-pointer -foptimize-sibling-calls + continue elif [ x"$x" = x"-r" ] || + [ x"$x" = x"-S" ] || [ x"$x" = x"-pie" ] || [ x"$x" = x"-frtti" ] || [ x"$x" = x"-shared" ] || @@ -181,13 +274,11 @@ for x; do [ x"$x" = x"-mred-zone" ] || [ x"$x" = x"-fexceptions" ] || [ x"$x" = x"-fsanitize=thread" ]; then - echo "$PROG: $x not supported" >&2 - exit 1 + fatal_error "$x flag not supported" 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 - exit 1 + fatal_error "$x use cosmo MODE=dbg rather than passing $x" elif [ x"$x" = x"-mno-red-zone" ]; then # "Any memory below the stack beyond the red zone is considered # volatile and may be modified by the operating system at any time." @@ -206,105 +297,204 @@ for x; do [ x"$x" = x"-shared-libgcc" ]; then # cosmopolitan.a always has llvm compiler runtime static code continue + elif [ x"$x" = x"-dumpversion" ]; then + echo $GCC_VERSION + Exit 0 fi set -- "$@" "$x" done -if [ x"$MODE" = x"dbg" ]; then - set -- \ - -fsanitize=address \ - -fsanitize=undefined \ - "$@" +if [ -z "$FILES" ]; then + fatal_error "$x: no input files" +elif [ $INTENT != ld ] && [ x"$FILES" != x"${FILES#* }" ]; then + fatal_error "cannot specify '-o' with '-c', or '-E' with multiple files" fi +PLATFORM="-D__COSMOPOLITAN__ -D__FATCOSMOCC__" +PREDEF="-include libc/integral/normalize.inc" +CPPFLAGS="-nostdinc -iquote $COSMO -isystem $COSMOS/include -isystem $COSMO/libc/isystem -fno-pie -fno-math-errno" +CCFLAGS_START="-fportcosmo -fno-dwarf2-cfi-asm -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-semantic-interposition" +CCFLAGS_END="-fno-omit-frame-pointer" +if [ x"$MODE" = x"dbg" ]; then + CPPFLAGS_START="-fsanitize=address -fsanitize=undefined" +fi if [ x"$OPT" != x"-Os" ] && [ x"${MODE#tiny}" != x"${MODE}" ]; then - set -- \ - -fno-optimize-sibling-calls \ - -mno-omit-leaf-frame-pointer \ - "$@" -fi - -set -- \ - -fno-pie \ - -fportcosmo \ - -fno-dwarf2-cfi-asm \ - -fno-unwind-tables \ - -fno-asynchronous-unwind-tables \ - -fno-semantic-interposition \ - -fno-math-errno \ - "$@" \ - -fno-omit-frame-pointer - -PLATFORM="-D__COSMOPOLITAN__" -PREDEF="-include libc/integral/normalize.inc" -CPPFLAGS="-nostdinc -iquote $COSMO -isystem $COSMOS/include -isystem $COSMO/libc/isystem" - -if [ "$GOT_SOME" -eq 0 ]; then - echo "$PROG: fatal error: no input files" >&2 - echo "compilation terminated." >&2 - exit 1 + CCFLAGS_START="${CCFLAGS_START} -fno-optimize-sibling-calls -mno-omit-leaf-frame-pointer" fi if [ $INTENT = cpp ]; then if [ -n "$OUTPUT" ]; then set -- "$@" -o"$OUTPUT" fi - MODE="$MODE" "$COSMO/tool/scripts/fat-x86_64" \ - -U__x86_64__ $PLATFORM $CPPFLAGS "$@" - exit -fi - -if [ -z "$OUTPUT" ]; then - if [ $INTENT = cc ]; then - echo "$PROG: passing -c without -o flag not supported" >&2 - exit 1 + CC="$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-gcc" + if [ x"$PROG" != x"${PROG%++}" ]; then + CC="$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-g++" fi - OUTPUT=a.out + set -- \ + "$CC" \ + -U__k8 \ + -U__k8__ \ + -U__amd64 \ + -U__amd64__ \ + -U__x86_64 \ + -U__x86_64__ \ + -U__SSE__ \ + -U__SSE2__ \ + -U__SSE2_MATH__ \ + -mno-red-zone \ + $PLATFORM \ + $CPPFLAGS \ + "$@" \ + $FILES + log_command "$@" + MODE="$MODE" exec "$@" fi -set -- $PLATFORM $PREDEF $CPPFLAGS "$@" +mangle_object_path() { + path=$1 + arch=$2 + outdir=${path%/*} + outbas=${path##*/} + if [ x"$outdir" = x"$path" ]; then + outdir= + elif [ -n "$outdir" ]; then + outdir="$outdir/" + fi + if [ ! -d "$outdir.$arch" ]; then + mkdir -p "$outdir.$arch" || Exit + fi + mangled_path="${outdir}.$arch/$outbas" +} -out2=$(mktemp "${TMPDIR:-/tmp}/ccc.XXXXXX") || exit +mktemper() { + "$COSMO/o/$MODE/tool/build/mktemper.com" \ + "$TMPDIR/fatcosmocc.XXXXXXXXXXXXX$1" +} +build_object() { + out2=$(mktemper .txt) || Exit + TEMP_FILES="${TEMP_FILES} $out2" + MODE="$MODE" \ + "$COSMO/tool/scripts/fat-x86_64" \ + -c -o"$OUTPUT_X86_64" \ + $PLATFORM \ + $PREDEF \ + $CPPFLAGS \ + $CCFLAGS_START \ + "$@" \ + $CCFLAGS_END & + pid1=$! + MODE="$MODE_AARCH64" \ + "$COSMO/tool/scripts/fat-aarch64" \ + -c -o"$OUTPUT_AARCH64" \ + $PLATFORM \ + $PREDEF \ + $CPPFLAGS \ + $CCFLAGS_START \ + "$@" \ + $CCFLAGS_END \ + 2>"$out2" & + pid2=$! + if ! wait $pid1; then + kill $pid2 2>/dev/null + wait + Exit 1 + fi + if ! wait $pid2; then + echo "$PROG: x86_64 succeeded but failed to build object for aarch64:" >&2 + cat "$out2" >&2 + Exit 1 + fi +} + +# turn source files into objects +OBJECTS_X86_64= +OBJECTS_AARCH64= +for x in $FILES; do + if [ x"$x" != x"${x%.o}" ] || + [ x"$x" != x"${x%.a}" ]; then + if [ $INTENT = cc ]; then + show_warning "$x: linker input file unused because linking not done" + else + mangle_object_path "$x" aarch64 + if [ ! -f "$mangled_path" ]; then + fatal_error "$x: linker input missing concomitant $mangled_path file" + fi + OBJECTS_X86_64="${OBJECTS_X86_64} $x" + OBJECTS_AARCH64="${OBJECTS_AARCH64} $mangled_path" + fi + elif [ $INTENT = cc ]; then + if [ -n "$OUTPUT" ]; then + # e.g. `cc -c -o bar.o foo.c` is specified by user + OUTPUT_X86_64=$OUTPUT + mangle_object_path "$OUTPUT" aarch64 + OUTPUT_AARCH64="$mangled_path" + build_object "$@" "$x" + else + # e.g. `cc -c foo.c` builds foo.o + OUTPUT_X86_64="${x%.*}.o" + mangle_object_path "${x%.*}.o" aarch64 + OUTPUT_AARCH64="$mangled_path" + build_object "$@" "$x" + fi + else + # e.g. `cc -o foo foo.c` should *not* build foo.o + OUTPUT_X86_64=$(mktemper .o) || Exit + OUTPUT_AARCH64=$(mktemper .o) || Exit + TEMP_FILES="${TEMP_FILES} ${OUTPUT_X86_64} ${OUTPUT_AARCH64}" + build_object "$@" "$x" + OBJECTS_X86_64="${OBJECTS_X86_64} ${OUTPUT_X86_64}" + OBJECTS_AARCH64="${OBJECTS_AARCH64} ${OUTPUT_AARCH64}" + fi +done + +if [ $INTENT != ld ]; then + Exit +fi + +OUTPUT_X86_64="$OUTPUT.x86_64" +OUTPUT_AARCH64="$OUTPUT.aarch64" + +out2=$(mktemper .txt) || Exit +TEMP_FILES="${TEMP_FILES} $out2" MODE="$MODE" \ -"$COSMO/tool/scripts/fat-x86_64" -o"$OUTPUT.x86_64" "$@" & +"$COSMO/tool/scripts/fat-x86_64" -o"$OUTPUT_X86_64" "$@" $OBJECTS_X86_64 & pid1=$! - MODE="$MODE_AARCH64" \ -"$COSMO/tool/scripts/fat-aarch64" -o"$OUTPUT.aarch64" "$@" 2>"$out2" & +"$COSMO/tool/scripts/fat-aarch64" -o"$OUTPUT_AARCH64" "$@" $OBJECTS_AARCH64 2>"$out2" & pid2=$! - if ! wait $pid1; then + kill $pid2 2>/dev/null wait - rm -f "$out2" - exit 1 + Exit 1 fi - if ! wait $pid2; then - wait - echo "$PROG: aarch64 compiler failed with:" >&2 + echo "$PROG: x86_64 succeeded but failed to link executable for aarch64:" >&2 cat "$out2" >&2 - rm -f "$out2" - exit 1 + Exit 1 fi -rm -f "$out2" - set -- \ "$COSMO/o/$MODE/tool/build/apelink.com" \ -l "$COSMO/o/$MODE/ape/ape.elf" \ -l "$COSMO/o/$MODE_AARCH64/ape/ape.elf" \ -M "$COSMO/ape/ape-m1.c" \ -o "$OUTPUT" \ - "$OUTPUT.x86_64" \ - "$OUTPUT.aarch64" -printf '# %s\n(cd %s; %s)\n' "$ORIGINAL" "$PWD" "$*" >>"${TMPDIR:-/tmp}/build.log" -"$@" || exit + $APELINKFLAGS \ + "$OUTPUT_X86_64" \ + "$OUTPUT_AARCH64" +log_command "$@" +"$@" || Exit -"$COSMO/o/$MODE/tool/build/pecheck.com" "$OUTPUT" || exit +set -- \ +"$COSMO/o/$MODE/tool/build/pecheck.com" "$OUTPUT" +log_command "$@" +"$@" || Exit -if [ $SAVE_TEMPS -eq 0 ]; then - rm -f "$OUTPUT.x86_64" \ - "$OUTPUT.aarch64" +if [ $INTENT = ld ] && [ $SAVE_TEMPS -eq 0 ]; then + rm -f "$OUTPUT_X86_64" \ + "$OUTPUT_AARCH64" fi + +Exit diff --git a/bin/unknown-unknown-cosmo-ar b/bin/unknown-unknown-cosmo-ar deleted file mode 100755 index 1a2485251..000000000 --- a/bin/unknown-unknown-cosmo-ar +++ /dev/null @@ -1 +0,0 @@ -#!/bin/sh diff --git a/bin/unknown-unknown-cosmo-ar b/bin/unknown-unknown-cosmo-ar new file mode 120000 index 000000000..267779688 --- /dev/null +++ b/bin/unknown-unknown-cosmo-ar @@ -0,0 +1 @@ +fatcosmoar \ No newline at end of file diff --git a/bin/x86_64-unknown-cosmo-ar b/bin/x86_64-unknown-cosmo-ar index a5c44ed65..b43abacf4 100755 --- a/bin/x86_64-unknown-cosmo-ar +++ b/bin/x86_64-unknown-cosmo-ar @@ -1,18 +1,29 @@ #!/bin/sh +PROG=${0##*/} MODE=${MODE:-$m} COSMO=${COSMO:-/opt/cosmo} -COSMOS=${COSMOS:-/opt/cosmos} -if [ x"$1" = x"rcs" ] || [ x"$1" = x"rcsD" ]; then - TOOL="$COSMO/o/$MODE/tool/build/ar.com" -else - TOOL="$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-ar" -fi - -if [ ! -x "$TOOL" ]; then - echo "$0: you need to run: cosmocc --update" >&2 +fatal_error() { + echo "$PROG: $1" >&2 exit 1 +} + +if [ ! -x "$COSMO/o/$MODE/tool/build/ar.com" ]; then + fatal_error "you need to run: cosmocc --update" fi -exec "$TOOL" "$@" +if [ x"$1" = x"rc" ] || + [ x"$1" = x"rcD" ] || + [ x"$1" = x"rcu" ] | + [ x"$1" = x"rcuD" ] || + [ x"$1" = x"rcs" ] || + [ x"$1" = x"rcsD" ] || + [ x"$1" = x"--help" ] || + [ x"$1" = x"--version" ]; then + AR="$COSMO/o/$MODE/tool/build/ar.com" +else + AR="$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-ar" +fi + +exec "$AR" "$@" diff --git a/libc/runtime/cocmd.c b/libc/runtime/cocmd.c index 6115e6eb7..04abacac4 100644 --- a/libc/runtime/cocmd.c +++ b/libc/runtime/cocmd.c @@ -578,20 +578,25 @@ static int Env(void) { return 0; } -static int Exec(void) { +static wontreturn void Exec(void) { Shift(1); - return ShellExec(); + if (!ShellExec()) { + _Exit(0); // can happen for builtins + } else { + perror("exec"); + _Exit(127); // sh exec never returns + } } static int TryBuiltin(void) { if (!n) return exitstatus; if (!strcmp(args[0], "exit")) Exit(); + if (!strcmp(args[0], "exec")) Exec(); if (!strcmp(args[0], "cd")) return Cd(); if (!strcmp(args[0], "rm")) return Rm(); if (!strcmp(args[0], "[")) return Test(); if (!strcmp(args[0], "cat")) return Cat(); if (!strcmp(args[0], "env")) return Env(); - if (!strcmp(args[0], "exec")) return Exec(); if (!strcmp(args[0], "wait")) return Wait(); if (!strcmp(args[0], "echo")) return Echo(); if (!strcmp(args[0], "read")) return Read(); diff --git a/test/libc/mem/test.mk b/test/libc/mem/test.mk index b608814c5..b0bcef5b1 100644 --- a/test/libc/mem/test.mk +++ b/test/libc/mem/test.mk @@ -90,7 +90,7 @@ o/$(MODE)/test/libc/mem/prog/life.elf: \ o/$(MODE)/test/libc/mem/prog/life.elf @$(COMPILE) -wAASSIMILATE -T$@ \ $(VM) \ - o/$(MODE)/tool/build/assimilate.com -f \ + o/$(MODE)/tool/build/assimilate.com -cf \ o/$(MODE)/test/libc/mem/prog/life.elf o/$(MODE)/test/libc/mem/prog/life.elf.zip.o: private \ @@ -117,7 +117,7 @@ o/$(MODE)/test/libc/mem/prog/sock.elf: \ o/$(MODE)/test/libc/mem/prog/sock.elf @$(COMPILE) -wAASSIMILATE -T$@ \ $(VM) \ - o/$(MODE)/tool/build/assimilate.com -f \ + o/$(MODE)/tool/build/assimilate.com -cf \ o/$(MODE)/test/libc/mem/prog/sock.elf o/$(MODE)/test/libc/mem/prog/sock.elf.zip.o: private \ diff --git a/tool/ape/ape.c b/tool/ape/ape.c deleted file mode 100644 index 44f83b604..000000000 --- a/tool/ape/ape.c +++ /dev/null @@ -1,412 +0,0 @@ -/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ -│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ -╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2023 Justine Alexandra Roberts Tunney │ -│ │ -│ Permission to use, copy, modify, and/or distribute this software for │ -│ any purpose with or without fee is hereby granted, provided that the │ -│ above copyright notice and this permission notice appear in all copies. │ -│ │ -│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ -│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ -│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ -│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ -│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ -│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ -│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ -│ PERFORMANCE OF THIS SOFTWARE. │ -╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/assert.h" -#include "libc/calls/calls.h" -#include "libc/calls/struct/iovec.h" -#include "libc/calls/struct/timeval.h" -#include "libc/dns/dns.h" -#include "libc/errno.h" -#include "libc/fmt/itoa.h" -#include "libc/fmt/magnumstrs.internal.h" -#include "libc/intrin/kprintf.h" -#include "libc/macros.internal.h" -#include "libc/mem/gc.internal.h" -#include "libc/mem/mem.h" -#include "libc/runtime/runtime.h" -#include "libc/sock/goodsocket.internal.h" -#include "libc/sock/sock.h" -#include "libc/stdio/append.h" -#include "libc/stdio/rand.h" -#include "libc/stdio/stdio.h" -#include "libc/str/slice.h" -#include "libc/str/str.h" -#include "libc/sysv/consts/af.h" -#include "libc/sysv/consts/ipproto.h" -#include "libc/sysv/consts/sig.h" -#include "libc/sysv/consts/sock.h" -#include "net/http/http.h" -#include "net/http/url.h" -#include "net/https/https.h" -#include "third_party/getopt/getopt.internal.h" -#include "third_party/mbedtls/ctr_drbg.h" -#include "third_party/mbedtls/debug.h" -#include "third_party/mbedtls/error.h" -#include "third_party/mbedtls/iana.h" -#include "third_party/mbedtls/net_sockets.h" -#include "third_party/mbedtls/ssl.h" -#include "third_party/mbedtls/x509.h" - -/** - * @fileoverview Downloads HTTP URL to stdout. - */ - -#define HasHeader(H) (!!msg.headers[H].a) -#define HeaderData(H) (p + msg.headers[H].a) -#define HeaderLength(H) (msg.headers[H].b - msg.headers[H].a) -#define HeaderEqualCase(H, S) \ - SlicesEqualCase(S, strlen(S), HeaderData(H), HeaderLength(H)) - -static int sock; -static int outfd; -static const char *prog; -static const char *outpath; - -static wontreturn void PrintUsage(int fd, int rc) { - tinyprint(fd, "usage: ", prog, " [-iksvV] URL\n", NULL); - exit(rc); -} - -static const char *DescribeErrno(void) { - const char *reason; - if (!(reason = _strerdoc(errno))) reason = "Unknown error"; - return reason; -} - -static int GetSslEntropy(void *c, unsigned char *p, size_t n) { - if (getrandom(p, n, 0) != n) { - perror("getrandom"); - exit(1); - } - return 0; -} - -static void OnSslDebug(void *ctx, int level, const char *file, int line, - const char *message) { - char sline[12]; - char slevel[12]; - FormatInt32(sline, line); - FormatInt32(slevel, level); - tinyprint(2, file, ":", sline, ": (", slevel, ") ", message, "\n", NULL); -} - -static void WriteOutput(const void *p, size_t n) { - if (!outfd) { - if (outpath) { - if ((outfd = creat(outpath, 0644)) <= 0) { - perror(outpath); - exit(1); - } - } else { - outfd = 1; - outpath = ""; - } - } - ssize_t rc; - for (size_t i = 0; i < n; i += rc) { - rc = write(outfd, p, n); - if (rc <= 0) { - perror(outpath); - exit(1); - } - } -} - -static int TlsSend(void *c, const unsigned char *p, size_t n) { - int rc; - if ((rc = write(*(int *)c, p, n)) == -1) { - perror("TlsSend"); - exit(1); - } - return rc; -} - -static int TlsRecv(void *c, unsigned char *p, size_t n, uint32_t o) { - int r; - struct iovec v[2]; - static unsigned a, b; - static unsigned char t[4096]; - if (a < b) { - r = MIN(n, b - a); - memcpy(p, t + a, r); - if ((a += r) == b) { - a = b = 0; - } - return r; - } - v[0].iov_base = p; - v[0].iov_len = n; - v[1].iov_base = t; - v[1].iov_len = sizeof(t); - if ((r = readv(*(int *)c, v, 2)) == -1) { - perror("TlsRecv"); - exit(1); - } - if (r > n) { - b = r - n; - } - return MIN(n, r); -} - -int _curl(int argc, char *argv[]) { - - if (!NoDebug()) { - ShowCrashReports(); - } - - prog = argv[0]; - if (!prog) { - prog = "curl"; - } - - /* - * Read flags. - */ - int opt; - while ((opt = getopt(argc, argv, "hV")) != -1) { - switch (opt) { - case 'V': - ++mbedtls_debug_threshold; - break; - case 'h': - PrintUsage(1, 0); - default: - PrintUsage(2, 1); - } - } - - /* - * Get argument. - */ - const char *urlarg; - if (optind == argc) { - tinyprint(2, prog, ": missing url\n", NULL); - PrintUsage(2, 1); - } - urlarg = argv[optind]; - - /* - * Parse URL. - */ - struct Url url; - char *host, *port; - gc(ParseUrl(urlarg, -1, &url, kUrlPlus)); - gc(url.params.p); - if (url.host.n) { - if (url.scheme.n && - !(url.scheme.n == 5 && !memcasecmp(url.scheme.p, "https", 5))) { - tinyprint(2, prog, ": not an https url: ", urlarg, "\n", NULL); - exit(1); - } - host = gc(strndup(url.host.p, url.host.n)); - if (url.port.n) { - port = gc(strndup(url.port.p, url.port.n)); - } else { - port = "443"; - } - } else { - host = "127.0.0.1"; - port = "443"; - } - if (!IsAcceptableHost(host, -1)) { - tinyprint(2, prog, ": invalid host: ", urlarg, "\n", NULL); - exit(1); - } - url.fragment.p = 0, url.fragment.n = 0; - url.scheme.p = 0, url.scheme.n = 0; - url.user.p = 0, url.user.n = 0; - url.pass.p = 0, url.pass.n = 0; - url.host.p = 0, url.host.n = 0; - url.port.p = 0, url.port.n = 0; - if (!url.path.n || url.path.p[0] != '/') { - char *p = gc(malloc(1 + url.path.n)); - mempcpy(mempcpy(p, "/", 1), url.path.p, url.path.n); - url.path.p = p; - ++url.path.n; - } - - char *request = 0; - appendf(&request, - "GET %s HTTP/1.1\r\n" - "Connection: close\r\n" - "User-Agent: ape/1.1\r\n" - "Host: %s:%d\r\n" - "\r\n", - gc(EncodeUrl(&url, 0)), host, port); - - /* - * Perform DNS lookup. - */ - struct addrinfo *addr; - struct addrinfo hints = {.ai_family = AF_UNSPEC, - .ai_socktype = SOCK_STREAM, - .ai_protocol = IPPROTO_TCP, - .ai_flags = AI_NUMERICSERV}; - if (getaddrinfo(host, port, &hints, &addr) != EAI_SUCCESS) { - tinyprint(2, prog, ": could not resolve host: ", host, "\n", NULL); - exit(1); - } - - /* - * Connect to server. - */ - int ret; - if ((sock = GoodSocket(addr->ai_family, addr->ai_socktype, addr->ai_protocol, - false, &(struct timeval){-60})) == -1) { - perror("socket"); - exit(1); - } - if (connect(sock, addr->ai_addr, addr->ai_addrlen)) { - tinyprint(2, prog, ": failed to connect to ", host, " port ", port, ": ", - DescribeErrno(), "\n", NULL); - exit(1); - } - freeaddrinfo(addr); - - /* - * Setup crypto. - */ - mbedtls_ssl_config conf; - mbedtls_ssl_context ssl; - mbedtls_ctr_drbg_context drbg; - mbedtls_ssl_init(&ssl); - mbedtls_ctr_drbg_init(&drbg); - mbedtls_ssl_config_init(&conf); - unassert(!mbedtls_ctr_drbg_seed(&drbg, GetSslEntropy, 0, "justine", 7)); - unassert(!mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT, - MBEDTLS_SSL_TRANSPORT_STREAM, - MBEDTLS_SSL_PRESET_DEFAULT)); - mbedtls_ssl_conf_ca_chain(&conf, GetSslRoots(), 0); - mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &drbg); -#ifndef NDEBUG - mbedtls_ssl_conf_dbg(&conf, OnSslDebug, 0); -#endif - unassert(!mbedtls_ssl_setup(&ssl, &conf)); - unassert(!mbedtls_ssl_set_hostname(&ssl, host)); - mbedtls_ssl_set_bio(&ssl, &sock, TlsSend, 0, TlsRecv); - if ((ret = mbedtls_ssl_handshake(&ssl))) { - tinyprint(2, prog, ": ssl negotiation with ", host, - " failed: ", DescribeSslClientHandshakeError(&ssl, ret), "\n", - NULL); - exit(1); - } - - /* - * Send HTTP Message. - */ - ssize_t rc; - size_t i, n; - n = appendz(request).i; - for (i = 0; i < n; i += rc) { - rc = mbedtls_ssl_write(&ssl, request + i, n - i); - if (rc <= 0) { - tinyprint(2, prog, ": ssl send failed: ", DescribeMbedtlsErrorCode(rc), - "\n", NULL); - exit(1); - } - } - - /* - * Handle response. - */ - int t; - char *p; - ssize_t paylen; - size_t g, hdrlen; - struct HttpMessage msg; - struct HttpUnchunker u; - InitHttpMessage(&msg, kHttpResponse); - for (p = 0, hdrlen = paylen = t = i = n = 0;;) { - if (i == n) { - n += 1000; - n += n >> 1; - p = realloc(p, n); - } - if ((rc = mbedtls_ssl_read(&ssl, p + i, n - i)) < 0) { - if (rc == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { - rc = 0; - } else { - tinyprint(2, prog, ": recv failed: ", DescribeMbedtlsErrorCode(rc), - "\n", NULL); - exit(1); - } - } - g = rc; - i += g; - switch (t) { - case kHttpClientStateHeaders: - unassert(g); - if ((rc = ParseHttpMessage(&msg, p, i)) == -1) { - tinyprint(2, prog, ": ", host, " sent bad http message\n", NULL); - exit(1); - } - if (rc) { - hdrlen = rc; - if (100 <= msg.status && msg.status <= 199) { - DestroyHttpMessage(&msg); - InitHttpMessage(&msg, kHttpResponse); - memmove(p, p + hdrlen, i - hdrlen); - i -= hdrlen; - break; - } - if (msg.status == 204 || msg.status == 304) { - goto Finished; - } - if (!HasHeader(kHttpContentLength) || - (paylen = ParseContentLength(HeaderData(kHttpContentLength), - HeaderLength(kHttpContentLength))) == - -1 || - (HasHeader(kHttpTransferEncoding) && - !HeaderEqualCase(kHttpTransferEncoding, "identity"))) { - tinyprint(2, prog, ": ", host, " sent bad transfer\n", NULL); - exit(1); - } - t = kHttpClientStateBodyLengthed; - if (paylen > i - hdrlen) { - WriteOutput(p + hdrlen, i - hdrlen); - } else { - WriteOutput(p + hdrlen, paylen); - goto Finished; - } - } - break; - case kHttpClientStateBodyLengthed: - unassert(g); - if (i - hdrlen > paylen) { - g = hdrlen + paylen - (i - g); - } - WriteOutput(p + i - g, g); - if (i - hdrlen >= paylen) { - goto Finished; - } - break; - default: - abort(); - } - } - -/* - * Close connection. - */ -Finished: - if (close(sock)) { - tinyprint(2, prog, ": close failed: ", DescribeErrno(), "\n", NULL); - exit(1); - } - - /* - * Free memory. - */ - mbedtls_ssl_free(&ssl); - mbedtls_ctr_drbg_free(&drbg); - mbedtls_ssl_config_free(&conf); - mbedtls_ctr_drbg_free(&drbg); - free(p); - - return 0; -} diff --git a/tool/ape/ape.mk b/tool/ape/ape.mk deleted file mode 100644 index 2a0203e71..000000000 --- a/tool/ape/ape.mk +++ /dev/null @@ -1,66 +0,0 @@ -#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ -#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘ - -PKGS += TOOL_APE - -TOOL_APE_ARTIFACTS += TOOL_APE_A -TOOL_APE = $(TOOL_APE_DEPS) $(TOOL_APE_A) -TOOL_APE_A = o/$(MODE)/tool/ape/ape.a -TOOL_APE_FILES := $(wildcard tool/ape/*) -TOOL_APE_HDRS = $(filter %.h,$(TOOL_APE_FILES)) -TOOL_APE_INCS = $(filter %.inc,$(TOOL_APE_FILES)) -TOOL_APE_SRCS = $(filter %.c,$(TOOL_APE_FILES)) -TOOL_APE_OBJS = $(TOOL_APE_SRCS:%.c=o/$(MODE)/%.o) - -TOOL_APE_DIRECTDEPS = \ - LIBC_CALLS \ - LIBC_DNS \ - LIBC_FMT \ - LIBC_INTRIN \ - LIBC_LOG \ - LIBC_MEM \ - LIBC_NEXGEN32E \ - LIBC_RUNTIME \ - LIBC_SOCK \ - LIBC_STDIO \ - LIBC_STR \ - LIBC_SYSV \ - LIBC_TIME \ - LIBC_X \ - NET_HTTP \ - NET_HTTPS \ - THIRD_PARTY_GETOPT \ - THIRD_PARTY_MBEDTLS - -TOOL_APE_DEPS := \ - $(call uniq,$(foreach x,$(TOOL_APE_DIRECTDEPS),$($(x)))) - -TOOL_APE_CHECKS = \ - $(TOOL_APE_A).pkg \ - $(TOOL_APE_HDRS:%=o/$(MODE)/%.ok) - -$(TOOL_APE_A): \ - tool/ape/ \ - $(TOOL_APE_A).pkg \ - $(TOOL_APE_OBJS) - -$(TOOL_APE_A).pkg: \ - $(TOOL_APE_OBJS) \ - $(foreach x,$(TOOL_APE_DIRECTDEPS),$($(x)_A).pkg) - -o/$(MODE)/tool/ape/ape.com.dbg: \ - $(TOOL_APE) \ - o/$(MODE)/tool/ape/ape.o \ - $(CRT) \ - $(APE_NO_MODIFY_SELF) - @$(APELINK) - -TOOL_APE_LIBS = $(TOOL_APE_A) -TOOL_APE_BINS = $(TOOL_APE_COMS) $(TOOL_APE_COMS:%=%.dbg) -TOOL_APE_COMS = o/$(MODE)/tool/ape/ape.com -$(TOOL_APE_OBJS): $(BUILD_FILES) tool/ape/ape.mk - -.PHONY: o/$(MODE)/tool/ape -o/$(MODE)/tool/ape: \ - $(TOOL_APE_BINS) \ - $(TOOL_APE_CHECKS) diff --git a/tool/ape/zstd.sh b/tool/ape/zstd.sh deleted file mode 100755 index 9bda5eebc..000000000 --- a/tool/ape/zstd.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash -set -ex -rm -rf o/samples -make -j16 o//third_party/zstd/zstd.com -o//third_party/zstd/zstd.com --maxdict=524288 -9 -T0 -B4096 --train $(find o//{examples,tool,third_party} -name \*.com) -o//third_party/zstd/zstd.com -9 --ultra -fz o//tool/curl/curl.com -o//third_party/zstd/zstd.com -D dictionary -9 --ultra -fz o//tool/curl/curl.com -o//third_party/zstd/zstd.com -9 --ultra -fz o//examples/hello.com -o//third_party/zstd/zstd.com -D dictionary -9 --ultra -fz o//examples/hello.com -o//third_party/zstd/zstd.com -9 --ultra -fz o//examples/hello2.com -o//third_party/zstd/zstd.com -D dictionary -9 --ultra -fz o//examples/hello2.com -o//third_party/zstd/zstd.com -9 --ultra -fz o//examples/hello3.com -o//third_party/zstd/zstd.com -D dictionary -9 --ultra -fz o//examples/hello3.com diff --git a/tool/build/ar.c b/tool/build/ar.c index 149697eea..7ba14e854 100644 --- a/tool/build/ar.c +++ b/tool/build/ar.c @@ -327,8 +327,11 @@ int main(int argc, char *argv[]) { // on modern systems that it isn't worth supporting the byzantine // standard posix ar flags intended to improve cassette tape perf SortChars(flags, strlen(flags)); - if (!IsEqual(flags, "crs") && // - !IsEqual(flags, "Dcrs")) { + if (*flags == 'D') ++flags; + if (!IsEqual(flags, "cr") && // + !IsEqual(flags, "cru") && // + !IsEqual(flags, "crsu") && // + !IsEqual(flags, "crs")) { tinyprint(2, program_invocation_name, ": flags should be rcsD\n", NULL); ShowUsage(1, 2); } diff --git a/tool/build/mktemper.c b/tool/build/mktemper.c new file mode 100644 index 000000000..2c295e266 --- /dev/null +++ b/tool/build/mktemper.c @@ -0,0 +1,66 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2023 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/dce.h" +#include "libc/runtime/runtime.h" +#include "libc/stdio/rand.h" +#include "libc/stdio/stdio.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/o.h" + +/** + * @fileoverview stronger mktemp for shell scripts, e.g. + * + * o//tool/build/mktemper.com ${TMPDIR:-/tmp}/fooXXXXXXXXXXXXX.o + * + * Is a good way to name an intermediate object file. + */ + +static wontreturn void Die(const char *thing, const char *reason) { + tinyprint(2, thing, ": ", reason, "\n", NULL); + exit(1); +} + +static wontreturn void DieSys(const char *thing) { + perror(thing); + exit(1); +} + +int main(int argc, char *argv[]) { + const char *prog = program_invocation_short_name; + if (argc == 1) Die(prog, "missing argument"); + if (argc != 2) Die(prog, "too many arguments"); + char *template = argv[1]; + char *substring = strstr(template, "XXXXXXXXXXXXX"); + if (!substring) Die(prog, "template missing XXXXXXXXXXXXX substring"); + uint64_t w; + if (getrandom(&w, 8, 0) != 8) DieSys("getrandom"); + for (int i = 0; i < 13; ++i) { + substring[i] = "0123456789abcdefghijklmnopqrstuvwxyz"[w % 36]; + w /= 36; + } + int fd; + if ((fd = open(template, + O_RDWR | O_CREAT | O_EXCL | (IsWindows() ? 0x00410000 : 0), + 0600)) == -1) { + DieSys(template); + } + close(fd); + tinyprint(1, template, "\n", NULL); +} diff --git a/tool/scripts/fat-aarch64 b/tool/scripts/fat-aarch64 index 082861a26..2538eb51c 100755 --- a/tool/scripts/fat-aarch64 +++ b/tool/scripts/fat-aarch64 @@ -13,6 +13,12 @@ if [ x"$PROG" != x"${PROG%++}" ]; then LDLIBS="$COSMO/o/$MODE/third_party/libcxx/libcxx.a $LDLIBS" fi +log_command() { + if [ -n "$BUILDLOG" ]; then + printf '# %s\n(cd %s; %s)\n' "$ORIGINAL" "$PWD" "$*" >>"$BUILDLOG" + fi +} + OPT= FIRST=1 OUTPUT= @@ -40,12 +46,21 @@ if [ x"$OPT" != x"-Os" ] && [ x"${MODE#aarch64-tiny}" != x"${MODE}" ]; then fi if [ $INTENT = cc ]; then - set -- "$CC" $CCFLAGS "$@" + set -- \ + "$CC" \ + $CCFLAGS \ + "$@" else - set -- "$CC" $CCFLAGS $LDFLAGS $APEFLAGS $CPPFLAGS "$@" \ - $LDLIBS -Wl,-z,common-page-size=16384 -Wl,-z,max-page-size=16384 + set -- \ + "$CC" \ + $LDFLAGS \ + $APEFLAGS \ + "$@" \ + $LDLIBS \ + -Wl,-z,common-page-size=16384 \ + -Wl,-z,max-page-size=16384 fi -printf '# %s\n(cd %s; %s)\n' "$ORIGINAL" "$PWD" "$*" >>"${TMPDIR:-/tmp}/build.log" +log_command "$@" "$@" || exit "$FIXUPOBJ" "$OUTPUT" || exit diff --git a/tool/scripts/fat-x86_64 b/tool/scripts/fat-x86_64 index 0f36e0c17..6ddc34f04 100755 --- a/tool/scripts/fat-x86_64 +++ b/tool/scripts/fat-x86_64 @@ -2,17 +2,23 @@ # amd64 backend compiler for fatcosmocc CC="$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-gcc" -CCFLAGS="-mno-tls-direct-seg-refs -mno-red-zone" +CFLAGS="-mno-tls-direct-seg-refs -mno-red-zone" LDFLAGS="-static -nostdlib -no-pie -Wl,-melf_x86_64" APEFLAGS="-L$COSMOS/lib -Wl,--gc-sections -Wl,-T,$COSMO/o/$MODE/ape/public/ape.lds $COSMO/o/$MODE/ape/ape.o $COSMO/o/$MODE/libc/crt/crt.o" LDLIBS="$COSMO/o/$MODE/cosmopolitan.a" if [ x"$PROG" != x"${PROG%++}" ]; then CC="$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-g++" - CCFLAGS="$CCFLAGS -fno-rtti -fno-exceptions -fuse-cxa-atexit" + CFLAGS="$CFLAGS -fno-rtti -fno-exceptions -fuse-cxa-atexit" LDLIBS="$COSMO/o/$MODE/third_party/libcxx/libcxx.a $LDLIBS" fi +log_command() { + if [ -n "$BUILDLOG" ]; then + printf '# %s\n(cd %s; %s)\n' "$ORIGINAL" "$PWD" "$*" >>"$BUILDLOG" + fi +} + OPT= FIRST=1 OUTPUT= @@ -35,22 +41,31 @@ for x; do done if [ x"$MODE" = x"nox87" ]; then - CCFLAGS="$CCFLAGS -mlong-double-64" + CFLAGS="$CFLAGS -mlong-double-64" fi if [ x"$OPT" != x"-Os" ] && [ x"${MODE#tiny}" != x"${MODE}" ]; then # support --ftrace unless optimizing for size - CCFLAGS="$CCFLAGS -fpatchable-function-entry=18,16" + CFLAGS="$CFLAGS -fpatchable-function-entry=18,16" fi if [ $INTENT = cc ]; then - set -- "$CC" $CCFLAGS "$@" + set -- \ + "$CC" \ + $CFLAGS \ + "$@" else - set -- "$CC" $CCFLAGS $LDFLAGS $APEFLAGS $CPPFLAGS "$@" \ - $LDLIBS -Wl,-z,common-page-size=4096 -Wl,-z,max-page-size=4096 \ - -fuse-ld=bfd + set -- \ + "$CC" \ + $LDFLAGS \ + $APEFLAGS \ + "$@" \ + $LDLIBS \ + -Wl,-z,common-page-size=4096 \ + -Wl,-z,max-page-size=4096 \ + -fuse-ld=bfd fi -printf '# %s\n(cd %s; %s)\n' "$ORIGINAL" "$PWD" "$*" >>"${TMPDIR:-/tmp}/build.log" +log_command "$@" "$@" || exit "$FIXUPOBJ" "$OUTPUT" || exit diff --git a/tool/tool.mk b/tool/tool.mk index 22df104d1..f23e92388 100644 --- a/tool/tool.mk +++ b/tool/tool.mk @@ -3,7 +3,6 @@ .PHONY: o/$(MODE)/tool o/$(MODE)/tool: \ - o/$(MODE)/tool/ape \ o/$(MODE)/tool/args \ o/$(MODE)/tool/build \ o/$(MODE)/tool/curl \