From 9a69167e854a3c77e6d737ff55df56c5860e9e33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 09:40:33 +0700 Subject: [PATCH 01/36] Update run_admin.sh --- .admin/run_admin.sh | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/.admin/run_admin.sh b/.admin/run_admin.sh index e31dd54e5..45b0c6f32 100644 --- a/.admin/run_admin.sh +++ b/.admin/run_admin.sh @@ -4,21 +4,20 @@ ARCH=x86_64-w64-mingw32 WORKDIR="$(cd "$(dirname "$0")" && pwd)" -BINUTILS_VERSION=2.41 -BUSYBOX_VERSION=FRP-5236-g7dff7f376 -CPPCHECK_VERSION=2.10 +BINUTILS_VERSION=2.42 +BUSYBOX_VERSION=FRP-5467-g9376eebd8 CTAGS_VERSION=6.0.0 -EXPAT_VERSION=2.5.0 -GCC_VERSION=13.2.0 -GDB_VERSION=13.1 +EXPAT_VERSION=2.6.2 +GCC_VERSION=14.2.0 +GDB_VERSION=15.1 GMP_VERSION=6.3.0 LIBICONV_VERSION=1.17 MAKE_VERSION=4.4.1 -MINGW_VERSION=11.0.1 +MINGW_VERSION=12.0.0 MPC_VERSION=1.3.1 MPFR_VERSION=4.2.1 -NASM_VERSION=2.15.05 PDCURSES_VERSION=3.9 VIM_VERSION=9.0 +Z7_VERSION=2301 VERSION=1.0.0-hf1 From e2f37f35a16f89c47dd1d961545bd6768c59d1e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 09:41:14 +0700 Subject: [PATCH 02/36] Update .gitmodules --- .gitmodules | 45 --------------------------------------------- 1 file changed, 45 deletions(-) diff --git a/.gitmodules b/.gitmodules index 2286b18a3..e69de29bb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,45 +0,0 @@ -[submodule "PDCurses"] - path = PDCurses - url = https://github.com/wmcbrine/PDCurses.git -[submodule "binutils-gdb"] - path = binutils-gdb - url = https://sourceware.org/git/binutils-gdb.git -[submodule "busybox-w32"] - path = busybox-w32 - url = git://git.frippery.org/busybox-w32 -[submodule "cppcheck"] - path = cppcheck - url = https://github.com/danmar/cppcheck.git -[submodule "ctags"] - path = ctags - url = https://github.com/universal-ctags/ctags.git -[submodule "libexpat"] - path = libexpat - url = https://github.com/libexpat/libexpat.git -[submodule "gcc"] - path = gcc - url = https://gcc.gnu.org/git/gcc.git -[submodule "gmp"] - path = gmp - url = https://github.com/gmp-mirror/gmp.git -[submodule "libiconv"] - path = libiconv - url = https://git.savannah.gnu.org/git/libiconv.git -[submodule "make"] - path = make - url = https://git.savannah.gnu.org/git/make.git -[submodule "mingw-w64"] - path = mingw-w64 - url = https://github.com/mingw-w64/mingw-w64.git -[submodule "libmpc"] - path = libmpc - url = https://github.com/nicolapiccinelli/libmpc.git -[submodule "mpfr"] - path = mpfr - url = https://gitlab.inria.fr/mpfr/mpfr.git -[submodule "nasm"] - path = nasm - url = https://github.com/netwide-assembler/nasm.git -[submodule "vim"] - path = vim - url = https://github.com/vim/vim.git \ No newline at end of file From da57a7382019d7783225c705f5d5858c0138d646 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 09:42:33 +0700 Subject: [PATCH 03/36] update binutils --- .gitmodules | 3 +++ binutils | 1 + 2 files changed, 4 insertions(+) create mode 160000 binutils diff --git a/.gitmodules b/.gitmodules index e69de29bb..02ea34f31 100644 --- a/.gitmodules +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "binutils"] + path = binutils + url = https://github.com/tfslabs/binutils.git diff --git a/binutils b/binutils new file mode 160000 index 000000000..218f8f3a6 --- /dev/null +++ b/binutils @@ -0,0 +1 @@ +Subproject commit 218f8f3a61eaf7387ed803504a7993b31776e1a3 From 45b90c2913f5178ffc3271239121ad6568ce74de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 09:43:34 +0700 Subject: [PATCH 04/36] busybox-w32 --- .gitmodules | 3 +++ busybox-w32 | 1 + 2 files changed, 4 insertions(+) create mode 160000 busybox-w32 diff --git a/.gitmodules b/.gitmodules index 02ea34f31..90809f36d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "binutils"] path = binutils url = https://github.com/tfslabs/binutils.git +[submodule "busybox-w32"] + path = busybox-w32 + url = https://github.com/tfslabs/busybox-w32.git diff --git a/busybox-w32 b/busybox-w32 new file mode 160000 index 000000000..97be75c05 --- /dev/null +++ b/busybox-w32 @@ -0,0 +1 @@ +Subproject commit 97be75c055259baadb6c1ad50d4f0bca94ebb680 From ad0c5a6b521a90f4cb51eb8e8d7d2afeb7bb960e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 09:44:52 +0700 Subject: [PATCH 05/36] ctags --- .gitmodules | 3 +++ ctags | 1 + 2 files changed, 4 insertions(+) create mode 160000 ctags diff --git a/.gitmodules b/.gitmodules index 90809f36d..cc5e94855 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "busybox-w32"] path = busybox-w32 url = https://github.com/tfslabs/busybox-w32.git +[submodule "ctags"] + path = ctags + url = https://github.com/tfslabs/ctags.git diff --git a/ctags b/ctags new file mode 160000 index 000000000..6a12b33aa --- /dev/null +++ b/ctags @@ -0,0 +1 @@ +Subproject commit 6a12b33aaf089b3dea5095117ae673e8d8b94e75 From b116a3a57895ee697557e5dfa0a2d0fc5394eec4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 09:45:33 +0700 Subject: [PATCH 06/36] update expat --- .gitmodules | 3 +++ expat | 1 + 2 files changed, 4 insertions(+) create mode 160000 expat diff --git a/.gitmodules b/.gitmodules index cc5e94855..46a5d2481 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "ctags"] path = ctags url = https://github.com/tfslabs/ctags.git +[submodule "expat"] + path = expat + url = https://github.com/tfslabs/expat.git diff --git a/expat b/expat new file mode 160000 index 000000000..c2d123f19 --- /dev/null +++ b/expat @@ -0,0 +1 @@ +Subproject commit c2d123f19e613c391d70accb2d371bbce332e62e From 14d0fd9933079fb8fbe084c3c39caa86005dcdde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 09:48:30 +0700 Subject: [PATCH 07/36] update gcc --- .gitmodules | 3 +++ gcc | 1 + 2 files changed, 4 insertions(+) create mode 160000 gcc diff --git a/.gitmodules b/.gitmodules index 46a5d2481..1788c2cb2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,6 @@ [submodule "expat"] path = expat url = https://github.com/tfslabs/expat.git +[submodule "gcc"] + path = gcc + url = https://github.com/tfslabs/gcc.git diff --git a/gcc b/gcc new file mode 160000 index 000000000..abcb615be --- /dev/null +++ b/gcc @@ -0,0 +1 @@ +Subproject commit abcb615be03807e2289d41cf382eee52c7d8ff07 From 60618453197486c9d888946e51db49cb7a4a5d6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 10:16:44 +0700 Subject: [PATCH 08/36] update gdb --- .gitmodules | 3 +++ gdb | 1 + 2 files changed, 4 insertions(+) create mode 160000 gdb diff --git a/.gitmodules b/.gitmodules index 1788c2cb2..e4ef7f642 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,3 +13,6 @@ [submodule "gcc"] path = gcc url = https://github.com/tfslabs/gcc.git +[submodule "gdb"] + path = gdb + url = https://github.com/tfslabs/gdb.git diff --git a/gdb b/gdb new file mode 160000 index 000000000..209e4a336 --- /dev/null +++ b/gdb @@ -0,0 +1 @@ +Subproject commit 209e4a336eea6b906eb967e496bfa16c85a150a2 From 3abc1463664b8062281a5577099b750a3e2fffba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 10:20:37 +0700 Subject: [PATCH 09/36] gmp --- .gitmodules | 3 +++ gmp | 1 + 2 files changed, 4 insertions(+) create mode 160000 gmp diff --git a/.gitmodules b/.gitmodules index e4ef7f642..d24243faa 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,3 +16,6 @@ [submodule "gdb"] path = gdb url = https://github.com/tfslabs/gdb.git +[submodule "gmp"] + path = gmp + url = https://github.com/tfslabs/gmp.git diff --git a/gmp b/gmp new file mode 160000 index 000000000..aa8ab164c --- /dev/null +++ b/gmp @@ -0,0 +1 @@ +Subproject commit aa8ab164cb050aeaec81f16c4b0183351f7c71f9 From 18e3d8294aceca3b94d1e8a96a53fe38e9afab39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 10:21:18 +0700 Subject: [PATCH 10/36] update libiconv --- .gitmodules | 3 +++ libiconv | 1 + 2 files changed, 4 insertions(+) create mode 160000 libiconv diff --git a/.gitmodules b/.gitmodules index d24243faa..621ed27f4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -19,3 +19,6 @@ [submodule "gmp"] path = gmp url = https://github.com/tfslabs/gmp.git +[submodule "libiconv"] + path = libiconv + url = https://github.com/tfslabs/libiconv.git diff --git a/libiconv b/libiconv new file mode 160000 index 000000000..d32635728 --- /dev/null +++ b/libiconv @@ -0,0 +1 @@ +Subproject commit d326357280adf935726abaae2189a26ac64c9cb0 From 8cc3f259483b1b9f119fb50ca01a9ec0ce7e74bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 10:28:49 +0700 Subject: [PATCH 11/36] make --- .gitmodules | 3 +++ make | 1 + 2 files changed, 4 insertions(+) create mode 160000 make diff --git a/.gitmodules b/.gitmodules index 621ed27f4..3090d0de7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,3 +22,6 @@ [submodule "libiconv"] path = libiconv url = https://github.com/tfslabs/libiconv.git +[submodule "make"] + path = make + url = https://github.com/tfslabs/make.git diff --git a/make b/make new file mode 160000 index 000000000..1a8f02951 --- /dev/null +++ b/make @@ -0,0 +1 @@ +Subproject commit 1a8f02951acafb2d4c7ea5fb764ee82d74b3481b From fb3d1efcea762306dfc0ffc1be66fefecf7009dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 10:41:05 +0700 Subject: [PATCH 12/36] update mingw-w64 --- .gitmodules | 3 +++ mingw-w64 | 1 + 2 files changed, 4 insertions(+) create mode 160000 mingw-w64 diff --git a/.gitmodules b/.gitmodules index 3090d0de7..8436e04a2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -25,3 +25,6 @@ [submodule "make"] path = make url = https://github.com/tfslabs/make.git +[submodule "mingw-w64"] + path = mingw-w64 + url = https://github.com/tfslabs/mingw-w64.git diff --git a/mingw-w64 b/mingw-w64 new file mode 160000 index 000000000..287ef494f --- /dev/null +++ b/mingw-w64 @@ -0,0 +1 @@ +Subproject commit 287ef494fe79da7862d2ad936e05e3f8a7b9f920 From 37e228aae352e44a656a7626ba7af7ac6a358569 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 10:57:07 +0700 Subject: [PATCH 13/36] mpc --- .gitmodules | 3 +++ mpc | 1 + 2 files changed, 4 insertions(+) create mode 160000 mpc diff --git a/.gitmodules b/.gitmodules index 8436e04a2..f01dca7cd 100644 --- a/.gitmodules +++ b/.gitmodules @@ -28,3 +28,6 @@ [submodule "mingw-w64"] path = mingw-w64 url = https://github.com/tfslabs/mingw-w64.git +[submodule "mpc"] + path = mpc + url = https://github.com/tfslabs/mpc.git diff --git a/mpc b/mpc new file mode 160000 index 000000000..4c90e51e9 --- /dev/null +++ b/mpc @@ -0,0 +1 @@ +Subproject commit 4c90e51e992ce8943e9c2500036cf5e93bde5355 From fef76aeacc88254e24d315c678b823c383c9df15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 10:58:53 +0700 Subject: [PATCH 14/36] mpfr --- .gitmodules | 3 +++ mpfr | 1 + 2 files changed, 4 insertions(+) create mode 160000 mpfr diff --git a/.gitmodules b/.gitmodules index f01dca7cd..0b3f33c7f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -31,3 +31,6 @@ [submodule "mpc"] path = mpc url = https://github.com/tfslabs/mpc.git +[submodule "mpfr"] + path = mpfr + url = https://github.com/tfslabs/mpfr.git diff --git a/mpfr b/mpfr new file mode 160000 index 000000000..a52285994 --- /dev/null +++ b/mpfr @@ -0,0 +1 @@ +Subproject commit a52285994d300e8c53cf81b6046b4f6b5d17c331 From b4348bcbd0f2bd199bf5445fdcdc649ce5443fed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 11:05:31 +0700 Subject: [PATCH 15/36] update pdcurses --- .gitmodules | 3 +++ pdcurses | 1 + 2 files changed, 4 insertions(+) create mode 160000 pdcurses diff --git a/.gitmodules b/.gitmodules index 0b3f33c7f..78496f6a5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -34,3 +34,6 @@ [submodule "mpfr"] path = mpfr url = https://github.com/tfslabs/mpfr.git +[submodule "pdcurses"] + path = pdcurses + url = https://github.com/tfslabs/pdcurses.git diff --git a/pdcurses b/pdcurses new file mode 160000 index 000000000..e70146eca --- /dev/null +++ b/pdcurses @@ -0,0 +1 @@ +Subproject commit e70146eca863e34f750e1d08bf8cf9a01572299b From f0268ff4426b21be1f7f3308d9a03e2820086511 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 11:24:21 +0700 Subject: [PATCH 16/36] update vim --- .gitmodules | 3 +++ vim | 1 + 2 files changed, 4 insertions(+) create mode 160000 vim diff --git a/.gitmodules b/.gitmodules index 78496f6a5..2a11dad57 100644 --- a/.gitmodules +++ b/.gitmodules @@ -37,3 +37,6 @@ [submodule "pdcurses"] path = pdcurses url = https://github.com/tfslabs/pdcurses.git +[submodule "vim"] + path = vim + url = https://github.com/tfslabs/vim.git diff --git a/vim b/vim new file mode 160000 index 000000000..8599c27d2 --- /dev/null +++ b/vim @@ -0,0 +1 @@ +Subproject commit 8599c27d2b0a72a661a4e195e295362fdc265c25 From d9d95fb0ffa2cedc2d9a60a40c8c5d3a2f157116 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 11:32:51 +0700 Subject: [PATCH 17/36] 7z --- .gitmodules | 3 +++ 7z | 1 + 2 files changed, 4 insertions(+) create mode 160000 7z diff --git a/.gitmodules b/.gitmodules index 2a11dad57..7028a1832 100644 --- a/.gitmodules +++ b/.gitmodules @@ -40,3 +40,6 @@ [submodule "vim"] path = vim url = https://github.com/tfslabs/vim.git +[submodule "7z"] + path = 7z + url = https://github.com/tfslabs/7z.git diff --git a/7z b/7z new file mode 160000 index 000000000..5d5fd260e --- /dev/null +++ b/7z @@ -0,0 +1 @@ +Subproject commit 5d5fd260e97971dba5f30440b493406f2fb7956e From db2547ca97fe753cbafda130908b5e80b1ca5848 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 12:21:41 +0700 Subject: [PATCH 18/36] Update dockerfile --- dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dockerfile b/dockerfile index e0299dfac..c1ba923d3 100644 --- a/dockerfile +++ b/dockerfile @@ -1,4 +1,4 @@ -# Use an official Ubuntu image as base +# Use an official Debian image as base FROM debian:latest # Install git and any other dependencies needed for your build script @@ -15,4 +15,4 @@ RUN apt update && \ libx265-199 libxau6 libxcb1 libxdmcp6 libxml2 libxpm4 libyuv0 linux-libc-dev manpages-dev patch \ publicsuffix rpcsvc-proto unzip autoconf automake bison build-essential cmake curl dpkg-dev flex \ g++ gcc libfl-dev libgmp-dev libmpc-dev libmpfr-dev m4 make wget zip texinfo pkg-config python3 \ - python3-pip python3-venv file + python3-pip python3-venv python3-build file p7zip-full zstd tar mingw-w64 libtool \ No newline at end of file From 6ba63edeaff442bf7c0008ec92fa935d1d08156d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 14:20:15 +0700 Subject: [PATCH 19/36] update sources --- .gnu-windows/src/.dirstamp | 0 .gnu-windows/src/7z.mak | 132 + .gnu-windows/src/SHA256SUMS | 15 +- .gnu-windows/src/alias.c | 13 +- .../src/binutils-dlltool-zero-ordinals.patch | 19 + .../src/busybox-000-disable-beep.patch | 6 +- .../src/busybox-002-default-noiconify.patch | 8 + .../src/busybox-004-system-profile.patch | 7 + .../src/busybox-005-disable-utf8-check.patch | 8 + .gnu-windows/src/busybox-alias.c | 13 +- .gnu-windows/src/cppcheck-gcc13.patch | 18 - .gnu-windows/src/cppcheck-quiet.patch | 7 - .gnu-windows/src/cppcheck.mak | 8 - .gnu-windows/src/gcc-stdcall-align.patch | 33 + .gnu-windows/src/gdb-000-alternate-main.patch | 8 +- .gnu-windows/src/gdb-001-confirm-off.patch | 2 +- .gnu-windows/src/gnu-windows.ico | Bin 28283 -> 0 bytes .gnu-windows/src/libchkstk.S | 17 +- .gnu-windows/src/peports.c | 790 +++++ .gnu-windows/src/pkg-config.c | 2760 +++++++++-------- .gnu-windows/src/profile | 6 + .gnu-windows/src/variant-fortran.patch | 17 - .../{variant-i686.patch => variant-x86.patch} | 29 +- .../src/{gnu-windows.c => w64devkit.c} | 325 +- .gnu-windows/src/w64devkit.ico | Bin 0 -> 16131 bytes .../src/{gnu-windows.ini => w64devkit.ini} | 10 +- 26 files changed, 2684 insertions(+), 1567 deletions(-) delete mode 100644 .gnu-windows/src/.dirstamp create mode 100644 .gnu-windows/src/7z.mak create mode 100644 .gnu-windows/src/binutils-dlltool-zero-ordinals.patch create mode 100644 .gnu-windows/src/busybox-002-default-noiconify.patch create mode 100644 .gnu-windows/src/busybox-004-system-profile.patch create mode 100644 .gnu-windows/src/busybox-005-disable-utf8-check.patch delete mode 100644 .gnu-windows/src/cppcheck-gcc13.patch delete mode 100644 .gnu-windows/src/cppcheck-quiet.patch delete mode 100644 .gnu-windows/src/cppcheck.mak create mode 100644 .gnu-windows/src/gcc-stdcall-align.patch delete mode 100644 .gnu-windows/src/gnu-windows.ico create mode 100644 .gnu-windows/src/peports.c create mode 100644 .gnu-windows/src/profile delete mode 100644 .gnu-windows/src/variant-fortran.patch rename .gnu-windows/src/{variant-i686.patch => variant-x86.patch} (56%) rename .gnu-windows/src/{gnu-windows.c => w64devkit.c} (61%) create mode 100644 .gnu-windows/src/w64devkit.ico rename .gnu-windows/src/{gnu-windows.ini => w64devkit.ini} (65%) diff --git a/.gnu-windows/src/.dirstamp b/.gnu-windows/src/.dirstamp deleted file mode 100644 index e69de29bb..000000000 diff --git a/.gnu-windows/src/7z.mak b/.gnu-windows/src/7z.mak new file mode 100644 index 000000000..149b8cf29 --- /dev/null +++ b/.gnu-windows/src/7z.mak @@ -0,0 +1,132 @@ +CROSS = x86_64-w64-mingw32- +CC = $(CROSS)gcc +CXX = $(CROSS)g++ +WINDRES = $(CROSS)windres +LDFLAGS = -mwindows -s -Wl,--gc-sections +LDLIBS = -lcomdlg32 -lole32 -loleaut32 -luuid +CFLAGS = -fno-ident -Oz \ + -DZ7_SFX \ + -DZ7_EXTRACT_ONLY \ + -DZ7_NO_CRYPTO \ + -DZ7_NO_REGISTRY \ + -DZ7_NO_READ_FROM_CODER \ + +obj = \ + CPP/7zip/Bundles/SFXWin/resource.o \ + CPP/7zip/Bundles/SFXWin/SfxWin.o \ + CPP/7zip/UI/GUI/ExtractDialog.o \ + CPP/7zip/UI/GUI/ExtractGUI.o \ + CPP/Common/CRC.o \ + CPP/Common/CommandLineParser.o \ + CPP/Common/IntToString.o \ + CPP/Common/NewHandler.o \ + CPP/Common/MyString.o \ + CPP/Common/StringConvert.o \ + CPP/Common/MyVector.o \ + CPP/Common/Wildcard.o \ + CPP/Windows/Clipboard.o \ + CPP/Windows/CommonDialog.o \ + CPP/Windows/DLL.o \ + CPP/Windows/ErrorMsg.o \ + CPP/Windows/FileDir.o \ + CPP/Windows/FileFind.o \ + CPP/Windows/FileIO.o \ + CPP/Windows/FileName.o \ + CPP/Windows/MemoryGlobal.o \ + CPP/Windows/PropVariant.o \ + CPP/Windows/PropVariantConv.o \ + CPP/Windows/ResourceString.o \ + CPP/Windows/Shell.o \ + CPP/Windows/Synchronization.o \ + CPP/Windows/System.o \ + CPP/Windows/Window.o \ + CPP/Windows/Control/ComboBox.o \ + CPP/Windows/Control/Dialog.o \ + CPP/Windows/Control/ListView.o \ + CPP/7zip/Common/CreateCoder.o \ + CPP/7zip/Common/CWrappers.o \ + CPP/7zip/Common/FilePathAutoRename.o \ + CPP/7zip/Common/FileStreams.o \ + CPP/7zip/Common/InBuffer.o \ + CPP/7zip/Common/FilterCoder.o \ + CPP/7zip/Common/LimitedStreams.o \ + CPP/7zip/Common/OutBuffer.o \ + CPP/7zip/Common/ProgressUtils.o \ + CPP/7zip/Common/PropId.o \ + CPP/7zip/Common/StreamBinder.o \ + CPP/7zip/Common/StreamObjects.o \ + CPP/7zip/Common/StreamUtils.o \ + CPP/7zip/Common/VirtThread.o \ + CPP/7zip/UI/Common/ArchiveExtractCallback.o \ + CPP/7zip/UI/Common/ArchiveOpenCallback.o \ + CPP/7zip/UI/Common/DefaultName.o \ + CPP/7zip/UI/Common/Extract.o \ + CPP/7zip/UI/Common/ExtractingFilePath.o \ + CPP/7zip/UI/Common/LoadCodecs.o \ + CPP/7zip/UI/Common/OpenArchive.o \ + CPP/7zip/UI/Explorer/MyMessages.o \ + CPP/7zip/UI/FileManager/BrowseDialog.o \ + CPP/7zip/UI/FileManager/ComboDialog.o \ + CPP/7zip/UI/FileManager/ExtractCallback.o \ + CPP/7zip/UI/FileManager/FormatUtils.o \ + CPP/7zip/UI/FileManager/OverwriteDialog.o \ + CPP/7zip/UI/FileManager/PasswordDialog.o \ + CPP/7zip/UI/FileManager/ProgressDialog2.o \ + CPP/7zip/UI/FileManager/PropertyName.o \ + CPP/7zip/UI/FileManager/SysIconUtils.o \ + CPP/7zip/Archive/SplitHandler.o \ + CPP/7zip/Archive/Common/CoderMixer2.o \ + CPP/7zip/Archive/Common/ItemNameUtils.o \ + CPP/7zip/Archive/Common/MultiStream.o \ + CPP/7zip/Archive/Common/OutStreamWithCRC.o \ + CPP/7zip/Archive/7z/7zDecode.o \ + CPP/7zip/Archive/7z/7zExtract.o \ + CPP/7zip/Archive/7z/7zHandler.o \ + CPP/7zip/Archive/7z/7zIn.o \ + CPP/7zip/Archive/7z/7zRegister.o \ + CPP/7zip/Compress/Bcj2Coder.o \ + CPP/7zip/Compress/Bcj2Register.o \ + CPP/7zip/Compress/BcjCoder.o \ + CPP/7zip/Compress/BcjRegister.o \ + CPP/7zip/Compress/BranchMisc.o \ + CPP/7zip/Compress/BranchRegister.o \ + CPP/7zip/Compress/CopyCoder.o \ + CPP/7zip/Compress/CopyRegister.o \ + CPP/7zip/Compress/DeltaFilter.o \ + CPP/7zip/Compress/Lzma2Decoder.o \ + CPP/7zip/Compress/Lzma2Register.o \ + CPP/7zip/Compress/LzmaDecoder.o \ + CPP/7zip/Compress/LzmaRegister.o \ + CPP/7zip/Compress/PpmdDecoder.o \ + CPP/7zip/Compress/PpmdRegister.o \ + C/7zCrc.o \ + C/7zCrcOpt.o \ + C/7zStream.o \ + C/Alloc.o \ + C/Bcj2.o \ + C/Bra.o \ + C/Bra86.o \ + C/BraIA64.o \ + C/CpuArch.o \ + C/Delta.o \ + C/DllSecur.o \ + C/Lzma2Dec.o \ + C/Lzma2DecMt.o \ + C/LzmaDec.o \ + C/MtDec.o \ + C/Ppmd7.o \ + C/Ppmd7Dec.o \ + C/Sha256.o \ + C/Sha256Opt.o \ + C/Threads.o \ + +7z.sfx: $(obj) + $(CXX) $(LDFLAGS) -o $@ $(obj) $(LDLIBS) +clean: + rm -f 7z.sfx $(obj) +%.o: %.cpp + $(CXX) -c $(CFLAGS) -o $@ $^ +%.o: %.c + $(CC) -c $(CFLAGS) -o $@ $^ +%.o: %.rc + $(WINDRES) -o $@ $^ diff --git a/.gnu-windows/src/SHA256SUMS b/.gnu-windows/src/SHA256SUMS index 3503e1690..025ee2100 100644 --- a/.gnu-windows/src/SHA256SUMS +++ b/.gnu-windows/src/SHA256SUMS @@ -1,16 +1,15 @@ -ae9a5789e23459e59606e6714723f2d3ffc31c03174191ef0d015bdf06007450 binutils-2.41.tar.xz -e9376e8848200ca085bd74804861f2904e12916e836a23d53bb41d166d38ac0d busybox-w32-FRP-5236-g7dff7f376.tgz -785dcbf711048dfe43ae920b6eff2eeebb4a096e88188a40e173ca4c030f57c3 cppcheck-2.10.tar.gz +356071007360e5a1824d9904993e8b2480b51b570e8c9faf7c0f58ebe4bf9f74 7z2301-src.tar.xz +b53606f443ac8f01d1d5fc9c39497f2af322d99e14cea5c0b4b124d630379365 binutils-2.43.tar.xz +4b3a8ad7a1a6a95b1e8437d2b6ac7d18c9443a9c3d984ef64154d2a4a6558cb0 busybox-w32-FRP-5467-g9376eebd8.tgz 71229a73f25529c9e3dabb2cb7310c55405d31caee8e8a9ab5c71b2406d4005a ctags-6.0.0.tar.gz -ef2420f0232c087801abf705e89ae65f6257df6b7931d37846a193ef2e8cdcbe expat-2.5.0.tar.xz -e275e76442a6067341a27f04c5c6b83d8613144004c0413528863dc6b5c743da gcc-13.2.0.tar.xz -115ad5c18d69a6be2ab15882d365dda2a2211c14f480b3502c6eba576e2e95a0 gdb-13.1.tar.xz +ee14b4c5d8908b1bec37ad937607eab183d4d9806a08adee472c3c3121d27364 expat-2.6.2.tar.xz +a7b39bc69cbf9e25826c5a60ab26477001f7c08d85cec04bc0e29cabed6f3cc9 gcc-14.2.0.tar.xz +83350ccd35b5b5a0cba6b334c41294ea968158c573940904f00b92f76345314d gdb-15.2.tar.xz a3c2b80201b89e68616f4ad30bc66aee4927c3ce50e33929ca819d5c43538898 gmp-6.3.0.tar.xz 8f74213b56238c85a50a5329f77e06198771e70dd9a739779f4c02f65d971313 libiconv-1.17.tar.gz dd16fb1d67bfab79a72f5e8390735c49e3e8e70b4945a15ab1f81ddb78658fb3 make-4.4.1.tar.gz -3f66bce069ee8bed7439a1a13da7cb91a5e67ea6170f21317ac7f5794625ee10 mingw-w64-v11.0.1.tar.bz2 +cc41898aac4b6e8dd5cffd7331b9d9515b912df4420a3a612b5ea2955bbeed2f mingw-w64-v12.0.0.tar.bz2 ab642492f5cf882b74aa0cb730cd410a81edcdbec895183ce930e706c1c759b8 mpc-1.3.1.tar.gz 277807353a6726978996945af13e52829e3abd7a9a5b7fb2793894e18f1fcbb2 mpfr-4.2.1.tar.xz -3caf6729c1073bf96629b57cee31eeb54f4f8129b01902c73428836550b30a3f nasm-2.15.05.tar.xz 590dbe0f5835f66992df096d3602d0271103f90cf8557a5d124f693c2b40d7ec PDCurses-3.9.tar.gz a6456bc154999d83d0c20d968ac7ba6e7df0d02f3cb6427fb248660bacfb336e vim-9.0.tar.bz2 diff --git a/.gnu-windows/src/alias.c b/.gnu-windows/src/alias.c index 91fc7b802..995ec3e2e 100644 --- a/.gnu-windows/src/alias.c +++ b/.gnu-windows/src/alias.c @@ -1,4 +1,4 @@ -// Well-behaved command line aliases for gnu-windows +// Well-behaved command line aliases for w64devkit // // Unlike batch script aliases, this program will not produce an annoying // and useless "Terminate batch job (Y/N)" prompt. When compiling, define @@ -38,6 +38,8 @@ typedef char16_t c16; typedef struct {} *handle; +typedef b32 __stdcall handler(i32); + typedef struct { u32 cb; uptr a, b, c; @@ -61,6 +63,7 @@ W32 i32 GetExitCodeProcess(handle, u32 *); W32 u32 GetFullPathNameW(c16 *, u32, c16 *, c16 *); W32 u32 GetModuleFileNameW(handle, c16 *, u32); W32 handle GetStdHandle(u32); +W32 b32 SetConsoleCtrlHandler(handler, b32); W32 byte *VirtualAlloc(byte *, usize, u32, u32); W32 b32 VirtualFree(byte *, usize, u32); W32 u32 WaitForSingleObject(handle, u32); @@ -68,7 +71,7 @@ W32 b32 WriteFile(handle, u8 *, u32, u32 *, void *); // Application -#define ERR(s) "gnu-windows (alias): " s "\n" +#define ERR(s) "w64devkit (alias): " s "\n" #define new(h, t, n) (t *)alloc(h, sizeof(t), alignof(t), n) __attribute((malloc)) @@ -156,6 +159,11 @@ static si *newstartupinfo(byte **heap) return s; } +static b32 __stdcall ignorectrlc(i32) +{ + return 1; +} + static i32 aliasmain(void) { byte *heap_start = VirtualAlloc(0, 1<<18, 0x3000, 4); @@ -204,6 +212,7 @@ static i32 aliasmain(void) si *si = newstartupinfo(&heap); pi pi; + SetConsoleCtrlHandler(ignorectrlc, 1); // NOTE: set as late a possible if (!CreateProcessW(exe->buf, cmd->buf, 0, 0, 1, 0, 0, 0, si, &pi)) { static const u8 msg[] = ERR("could not start process\n"); return fatal((u8 *)msg, lengthof(msg)); diff --git a/.gnu-windows/src/binutils-dlltool-zero-ordinals.patch b/.gnu-windows/src/binutils-dlltool-zero-ordinals.patch new file mode 100644 index 000000000..594c12370 --- /dev/null +++ b/.gnu-windows/src/binutils-dlltool-zero-ordinals.patch @@ -0,0 +1,19 @@ +If the .def author does not pick an ordinal then it has no meaningful +ordinal. It never makes sense to invent unique hints. That populates +binaries with noise and inhibits reproducible builds. Instead zero out +all ordinal hints to indicate "no data." In Mingw-w64 import libraries +virtually every implicit ordinal hint is nonsense. + +The singular exception might be ordinal-only, NONAME entries without an +explicit ordinal, which instead relies on implicit, undocumented ordinal +numbering. In that case it's not merely a hint. However, this is unsound +and ought to be a syntax error, as it is with MSVC lib.exe. (This patch +should probably make it so.) I could find no examples of this situation +in the wild. + +--- a/binutils/dlltool.c ++++ b/binutils/dlltool.c +@@ -3690,2 +3690,3 @@ fill_ordinals (export_type **d_export_vec) + done:; ++ d_export_vec[i]->ordinal = 0; + } diff --git a/.gnu-windows/src/busybox-000-disable-beep.patch b/.gnu-windows/src/busybox-000-disable-beep.patch index 9c6a17bae..39465842f 100644 --- a/.gnu-windows/src/busybox-000-disable-beep.patch +++ b/.gnu-windows/src/busybox-000-disable-beep.patch @@ -1,10 +1,8 @@ --- a/libbb/lineedit.c +++ b/libbb/lineedit.c -@@ -488,7 +488,6 @@ - +@@ -537,5 +537,4 @@ static void beep(void) { -- bb_putchar('\007'); +- bb_putchar_stderr('\007'); } - /* Full or last/sole prompt line, reset edit cursor, calculate terminal cursor. diff --git a/.gnu-windows/src/busybox-002-default-noiconify.patch b/.gnu-windows/src/busybox-002-default-noiconify.patch new file mode 100644 index 000000000..72166cdea --- /dev/null +++ b/.gnu-windows/src/busybox-002-default-noiconify.patch @@ -0,0 +1,8 @@ +--- a/shell/ash.c ++++ b/shell/ash.c +@@ -12686,4 +12686,5 @@ + #if ENABLE_ASH_NOCONSOLE + noconsole = console_state(); ++ noiconify = 1; + #endif + if (login_sh != NULL) { /* if we came from startup code */ diff --git a/.gnu-windows/src/busybox-004-system-profile.patch b/.gnu-windows/src/busybox-004-system-profile.patch new file mode 100644 index 000000000..0b930f926 --- /dev/null +++ b/.gnu-windows/src/busybox-004-system-profile.patch @@ -0,0 +1,7 @@ +--- a/shell/ash.c ++++ b/shell/ash.c +@@ -16349,3 +16349,3 @@ + +- hp = exe_relative_path("/etc/profile"); ++ hp = exe_relative_path("../src/profile"); + read_profile(hp); diff --git a/.gnu-windows/src/busybox-005-disable-utf8-check.patch b/.gnu-windows/src/busybox-005-disable-utf8-check.patch new file mode 100644 index 000000000..266c47e6c --- /dev/null +++ b/.gnu-windows/src/busybox-005-disable-utf8-check.patch @@ -0,0 +1,8 @@ +Allow it to run without UTF-8 support, such as on Windows 7. +--- a/libbb/appletlib.c ++++ b/libbb/appletlib.c +@@ -1331,3 +1331,3 @@ + #if ENABLE_PLATFORM_MINGW32 +-# if ENABLE_FEATURE_UTF8_MANIFEST ++# if ENABLE_FEATURE_UTF8_MANIFEST && 0 + if (GetACP() != CP_UTF8) { diff --git a/.gnu-windows/src/busybox-alias.c b/.gnu-windows/src/busybox-alias.c index 60ed0ad02..5c23fd895 100644 --- a/.gnu-windows/src/busybox-alias.c +++ b/.gnu-windows/src/busybox-alias.c @@ -19,6 +19,8 @@ typedef char16_t c16; typedef struct {} *handle; +typedef b32 __stdcall handler(i32); + typedef struct { u32 cb; void *a, *b, *c; @@ -41,6 +43,7 @@ W32 c16 *GetCommandLineW(void); W32 i32 GetExitCodeProcess(handle, u32 *); W32 u32 GetModuleFileNameW(handle, c16 *, u32); W32 handle GetStdHandle(u32); +W32 b32 SetConsoleCtrlHandler(handler, b32); W32 u32 WaitForSingleObject(handle, u32); W32 b32 WriteFile(handle, u8 *, u32, u32 *, void *); @@ -84,6 +87,11 @@ static u32 fatal(u8 *msg, i32 len) return 0x17e; } +static b32 __stdcall ignorectrlc(i32) +{ + return 1; +} + static u32 run(void) { c16 buf[MAX_PATH]; @@ -95,7 +103,7 @@ static u32 run(void) c16 busybox[] = u"\\busybox.exe"; append(&exe, busybox, countof(busybox)); if (exe.err) { - static u8 msg[] = "gnu-windows: busybox.exe path too long\n"; + static u8 msg[] = "w64devkit: busybox.exe path too long\n"; return fatal(msg, lengthof(msg)); } @@ -103,8 +111,9 @@ static u32 run(void) si.cb = sizeof(si); pi pi; c16 *cmdline = GetCommandLineW(); + SetConsoleCtrlHandler(ignorectrlc, 1); // NOTE: set as late a possible if (!CreateProcessW(exe.buf, cmdline, 0, 0, 1, 0, 0, 0, &si, &pi)) { - static u8 msg[] = "gnu-windows: could not start busybox.exe\n"; + static u8 msg[] = "w64devkit: could not start busybox.exe\n"; return fatal(msg, lengthof(msg)); } diff --git a/.gnu-windows/src/cppcheck-gcc13.patch b/.gnu-windows/src/cppcheck-gcc13.patch deleted file mode 100644 index 4e4953a9b..000000000 --- a/.gnu-windows/src/cppcheck-gcc13.patch +++ /dev/null @@ -1,18 +0,0 @@ -GCC 13 has stricter allocator checks: -https://gcc.gnu.org/gcc-13/porting_to.html - -Also, libstdc++ no longer leaks stdint.h definitions. ---- a/lib/mathlib.cpp -+++ b/lib/mathlib.cpp -@@ -25,2 +25,3 @@ - #include -+#include - #include ---- a/lib/smallvector.h -+++ b/lib/smallvector.h -@@ -43,2 +43,5 @@ - {} -+ -+ template TaggedAllocator(const TaggedAllocator); -+ template struct rebind { using other = TaggedAllocator; }; - }; diff --git a/.gnu-windows/src/cppcheck-quiet.patch b/.gnu-windows/src/cppcheck-quiet.patch deleted file mode 100644 index b47189911..000000000 --- a/.gnu-windows/src/cppcheck-quiet.patch +++ /dev/null @@ -1,7 +0,0 @@ ---- a/cli/cmdlineparser.cpp -+++ b/cli/cmdlineparser.cpp -@@ -131,3 +131,3 @@ - #if defined(_WIN64) || defined(_WIN32) --bool CmdLineParser::SHOW_DEF_PLATFORM_MSG = true; -+bool CmdLineParser::SHOW_DEF_PLATFORM_MSG = false; - #endif diff --git a/.gnu-windows/src/cppcheck.mak b/.gnu-windows/src/cppcheck.mak deleted file mode 100644 index e7ae46b47..000000000 --- a/.gnu-windows/src/cppcheck.mak +++ /dev/null @@ -1,8 +0,0 @@ -ext := $(shell find externals -mindepth 1 -type d) -src := $(shell find cli lib externals -name '*.cpp') -obj := $(src:.cpp=.o) -CXXFLAGS := -w -Os -Ilib $(addprefix -I,$(ext)) -cppcheck.exe: $(obj) - $(CXX) -s -o $@ $(obj) -lshlwapi -cppcheck: $(obj) - $(CXX) -pthread -s -o $@ $(obj) diff --git a/.gnu-windows/src/gcc-stdcall-align.patch b/.gnu-windows/src/gcc-stdcall-align.patch new file mode 100644 index 000000000..e69fe8337 --- /dev/null +++ b/.gnu-windows/src/gcc-stdcall-align.patch @@ -0,0 +1,33 @@ +GCC requires 16-byte stack alignment on function entry, but x86 calling +conventions only provide 4-byte alignment. Entry points, such as thread +procedures, callbacks, and process entry points, are likely called on a +stack not aligned to GCC's expectations. Since these functions are also +typically __stdcall, silently add the force_align_arg_pointer attribute +to such functions so that GCC re-aligns the stack. + +Note: main, wmain, WinMain, and wWinMain are special cases which the CRT +calls with 16-byte alignment. + +--- a/gcc/config/i386/i386-options.cc ++++ b/gcc/config/i386/i386-options.cc +@@ -3689,7 +3689,7 @@ + arguments as in struct attribute_spec.handler. */ + + static tree +-ix86_handle_cconv_attribute (tree *node, tree name, tree args, int, ++ix86_handle_cconv_attribute (tree *node, tree name, tree args, int flags, + bool *no_add_attrs) + { + if (TREE_CODE (*node) != FUNCTION_TYPE +@@ -3773,6 +3773,11 @@ + sseregparm. */ + else if (is_attribute_p ("stdcall", name)) + { ++ if (!TARGET_64BIT) ++ { ++ tree attr = tree_cons (get_identifier ("force_align_arg_pointer"), NULL_TREE, NULL_TREE); ++ decl_attributes (node, attr, flags); ++ } + if (lookup_attribute ("cdecl", TYPE_ATTRIBUTES (*node))) + { + error ("stdcall and cdecl attributes are not compatible"); diff --git a/.gnu-windows/src/gdb-000-alternate-main.patch b/.gnu-windows/src/gdb-000-alternate-main.patch index c7b1c5da6..402b07b06 100644 --- a/.gnu-windows/src/gdb-000-alternate-main.patch +++ b/.gnu-windows/src/gdb-000-alternate-main.patch @@ -1,10 +1,10 @@ --- a/gdb/symtab.c +++ b/gdb/symtab.c -@@ -6300,6 +6300,23 @@ +@@ -6537,6 +6537,23 @@ if (symbol_found_p) return; -+ if (gdbarch_osabi (target_gdbarch ()) == GDB_OSABI_WINDOWS) ++ if (gdbarch_osabi (current_inferior ()->arch ()) == GDB_OSABI_WINDOWS) + { + static const char *const mains[] = { + "WinMain", "wWinMain", "main", "wmain", "WinMainCRTStartup", "mainCRTStartup" @@ -15,12 +15,12 @@ + msym = lookup_minimal_symbol (main, NULL, NULL); + if (msym.minsym != NULL) + { -+ set_main_name (main, language_unknown); ++ set_main_name (pspace, main, language_unknown); + return; + } + } + } + - set_main_name ("main", language_unknown); + set_main_name (pspace, "main", language_unknown); } diff --git a/.gnu-windows/src/gdb-001-confirm-off.patch b/.gnu-windows/src/gdb-001-confirm-off.patch index 48328481e..9bb9f2197 100644 --- a/.gnu-windows/src/gdb-001-confirm-off.patch +++ b/.gnu-windows/src/gdb-001-confirm-off.patch @@ -3,7 +3,7 @@ creates substantial friction and should be off by default. --- a/gdb/top.c +++ b/gdb/top.c -@@ -132,3 +132,3 @@ +@@ -133,3 +133,3 @@ -bool confirm = true; +bool confirm = false; diff --git a/.gnu-windows/src/gnu-windows.ico b/.gnu-windows/src/gnu-windows.ico deleted file mode 100644 index 6de3a36f51e0d40d10a73d64704a3725853d1f93..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28283 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 VwX5jC48I?TxT%3rFHp4%{y+7QH?{x( diff --git a/.gnu-windows/src/libchkstk.S b/.gnu-windows/src/libchkstk.S index 55be31f18..5016c82ae 100644 --- a/.gnu-windows/src/libchkstk.S +++ b/.gnu-windows/src/libchkstk.S @@ -29,10 +29,11 @@ __chkstk: # endif push %rax push %rcx + mov %gs:(0x10), %rcx // rcx = stack low address neg %rax // rax = frame low address add %rsp, %rax // " - mov %gs:(0x10), %rcx // rcx = stack low address - jmp 1f + jb 1f // frame low address overflow? + xor %eax, %eax // overflowed: frame low address = null 0: sub $0x1000, %rcx // extend stack into guard page test %eax, (%rcx) // commit page (two instruction bytes) 1: cmp %rax, %rcx @@ -49,15 +50,15 @@ __chkstk: ___chkstk_ms: push %eax push %ecx + mov %fs:(0x08), %ecx // ecx = stack low address neg %eax // eax = frame low address add %esp, %eax // " - mov %fs:(0x08), %ecx // ecx = stack low address - jmp 1f + jb 1f // frame low address overflow? + xor %eax, %eax // overflowed: frame low address = null 0: sub $0x1000, %ecx // extend stack into guard page test %eax, (%ecx) // commit page (two instruction bytes) 1: cmp %eax, %ecx ja 0b - sub %esp, %eax pop %ecx pop %eax ret @@ -67,10 +68,12 @@ ___chkstk_ms: .globl __chkstk __chkstk: push %ecx // preserve ecx + mov %fs:(0x08), %ecx // ecx = stack low address neg %eax // eax = frame low address lea 8(%esp,%eax), %eax // " - mov %fs:(0x08), %ecx // ecx = stack low address - jmp 1f + cmp %esp, %eax // frame low address overflow? + jb 1f // " + xor %eax, %eax // overflowed: frame low address = null 0: sub $0x1000, %ecx // extend stack into guard page test %eax, (%ecx) // commit page (two instruction bytes) 1: cmp %eax, %ecx diff --git a/.gnu-windows/src/peports.c b/.gnu-windows/src/peports.c new file mode 100644 index 000000000..36995e38b --- /dev/null +++ b/.gnu-windows/src/peports.c @@ -0,0 +1,790 @@ +// PE export/import table listing +// +// $ peports c:/windows/system32/kernel32.dll +// $ peports -i main.exe >imports.txt +// $ peports -e library.dll >exports.txt +// +// Compilation requires GCC or Clang. Behaves like "dumpbin /exports" +// and "dumpbin /imports" from MSVC, but open source, standalone, and +// much faster. For C++ symbols, consider piping output through c++filt +// or vc++filt. +// +// Dynamic linking only permits ASCII for module and symbol names, and +// both the MSVC and GNU toolchains sometimes choke on non-ASCII names. +// Therefore wide console output is unnecessary. All standard output is +// ASCII, and non-ASCII name bytes are escape-printed. Angle brackets +// in names are escaped, so brackets appearing in output are delimiters. +// Command line argument paths may be wide, though, since these are not +// so restricted. +// +// THIS IS NOT A SECURITY TOOL! While this program does not misbehave +// given arbitrary, untrusted input, its interpretation of PE data may +// not precisely match the Windows loader, which is itself inconsistent +// between releases. For specially-crafted inputs, outputs may differ +// from Windows' parsing of the same input. This is first and foremost a +// debugging tool. +// +// Porting note: The platform layer implements osload and oswrite. To +// run the application, it calls peports with command line arguments and +// a scratch arena. The application calls osload and oswrite as needed +// for reading file and writing output. +// +// Roadmap: +// * Alternate format options? (e.g. DEF, a better gendef) +// * A recursive option, to behave like a dependency walker? +// * An option to automatically demangle C++ symbols? +// +// This is free and unencumbered software released into the public domain. + +#define assert(c) while (!(c)) __builtin_unreachable() +#define countof(a) (iz)(sizeof(a) / sizeof(*(a))) +#define new(a, n, t) (t *)alloc(a, n, sizeof(t), _Alignof(t)) +#define s8(s) (s8){(u8 *)s, countof(s)-1} +#define catch(e) __builtin_setjmp((e)->jmp) + +typedef unsigned char u8; +typedef unsigned short u16; +typedef signed int b32; +typedef signed int i32; +typedef unsigned int u32; +typedef unsigned short char16_t; +typedef char16_t c16; +typedef __PTRDIFF_TYPE__ iz; +typedef __SIZE_TYPE__ uz; +typedef char byte; + +typedef struct { + u8 *data; + iz len; +} s8; + +typedef struct { + void *jmp[5]; + s8 err; +} escape; + +__attribute((noreturn)) +static void throw(escape *e, s8 reason) +{ + e->err = reason; + __builtin_longjmp(e->jmp, 1); +} + +typedef struct { + byte *beg; + byte *end; + escape *esc; +} arena; + +// Read an entire file into memory. Returns a null string on error. The +// information we care about is probably at the very beginning of the +// file, so this function does not fill the whole arena but truncates as +// necessary to leave an 8th or so of the remaining space for parsing. +// Truncation is not an error. The special path "-" is standard input. +static s8 osload(arena *, s8); + +// Write some bytes to standard output (1) or standard error (2). +static b32 oswrite(i32, u8 *, i32); + +static byte *alloc(arena *a, iz count, iz size, iz align) +{ + assert(count >= 0); + iz pad = -(uz)a->beg & (align - 1); + if (count >= (a->end - a->beg - pad)/size) { + throw(a->esc, s8("out of memory")); + } + byte *r = a->beg + pad; + a->beg += pad + count*size; + return __builtin_memset(r, 0, count*size); +} + +static s8 span(u8 *beg, u8 *end) +{ + assert(beg <= end); + s8 r = {0}; + r.data = beg; + r.len = end - beg; + return r; +} + +static b32 equals(s8 a, s8 b) +{ + if (a.len != b.len) { + return 0; + } + for (iz i = 0; i < a.len; i++) { + if (a.data[i] != b.data[i]) { + return 0; + } + } + return 1; +} + +static s8 slice3(s8 s, iz beg, iz end, escape *e) +{ + if (beg<0 || beg>end || end>s.len) { + throw(e, s8("unexpected end of input (slice)")); + } + s.data += beg; + s.len = end - beg; + return s; +} + +static s8 slice2(s8 s, iz beg, escape *e) +{ + return slice3(s, beg, s.len, e); +} + +static u16 readu16(s8 s, iz off, escape *e) +{ + if (off > s.len-2) { + throw(e, s8("unexpected end of input (uint16)")); + } + u8 *p = s.data + off; + return (u16)((u16)p[1]<<8 | p[0]); +} + +static u32 readu32(s8 s, iz off, escape *e) +{ + if (off > s.len-4) { + throw(e, s8("unexpected end of input (uint32)")); + } + u8 *p = s.data + off; + return (u32)p[3]<<24 | (u32)p[2]<<16 | (u32)p[1]<<8 | p[0]; +} + +static s8 nullterm(s8 s) +{ + if (!s.data) return s; + iz len = 0; + for (; lenerr && b->len) { + b->err |= !oswrite(b->fd, b->buf, b->len); + b->len = 0; + } +} + +static void print(u8buf *b, s8 s) +{ + for (iz off = 0; !b->err && offcap - b->len; + i32 count = availbuf+b->len, s.data+off, count); + off += count; + b->len += count; + if (b->len == b->cap) { + flush(b); + } + } +} + +static void printu32(u8buf *b, u32 x) +{ + u8 buf[16]; + u8 *end = buf + countof(buf); + u8 *beg = end; + do { + *--beg = (u8)(x%10) + '0'; + } while (x /= 10); + return print(b, span(beg, end)); +} + +// Escape-print a module or symbol name. +static void printname(u8buf *b, s8 s) +{ + if (!s.len) { + print(b, s8("<>")); // signify empty using brackets + } else { + for (iz i = 0; i < s.len; i++) { + u8 c = s.data[i]; + if (c<0x20 || c>0x7f || c=='<' || c=='>' || c=='\\') { + u8 encode[4] = "\\x.."; + encode[2] = "0123456789abcdef"[c>>4]; + encode[3] = "0123456789abcdef"[c&15]; + print(b, span(encode, encode+countof(encode))); + } else { + print(b, span(&c, &c+1)); + } + } + } +} + +typedef struct { + u32 beg; + u32 end; + s8 mem; +} region; + +typedef struct { + region *regions; + i32 len; +} vm; + +// Parsing a PE means simulating a loader. A virtual memory (vm) object +// represents sections mapped into a virtual address space, and this +// function reads regions out of that address space. +static s8 loadrva(vm m, u32 vaddr, escape *e) +{ + s8 r = {0}; + for (i32 i = 0; i < m.len; i++) { + region s = m.regions[i]; + if (vaddr>=s.beg && vaddr 0xffffffff-b) { + throw(e, s8("overflow computing 32-bit offset")); + } + return a + b; +} + +static void usage(u8buf *b) +{ + print(b, s8( + "usage: peports [-ehi] [files...]\n" + " -e print the export table\n" + " -h print this message\n" + " -i print the import table\n" + "Prints export and import tables of EXEs and DLLs.\n" + "Given no arguments, reads data from standard input.\n" + )); +} + +typedef struct { + u8buf *out; + u8buf *err; + i32 optind; + b32 exports; + b32 imports; +} config; + +enum {OPT_OK, OPT_EXIT, OPT_ERR}; + +static i32 parseopts(config *c, i32 argc, s8 *argv) +{ + for (c->optind = !!argc; c->optind < argc; c->optind++) { + s8 arg = argv[c->optind]; + if (!arg.len || arg.data[0]!='-') break; + for (iz i = 1; i < arg.len; i++) { + u8 x = arg.data[i]; + switch (x) { + case 'e': + c->exports = 1; + break; + case 'h': + usage(c->out); + flush(c->out); + return c->out->err ? OPT_ERR : OPT_EXIT; + case 'i': + c->imports = 1; + break; + default: + print(c->err, s8("peports: unknown option: -")); + print(c->err, span(&x, &x+1)); + print(c->err, s8("\n")); + usage(c->err); + flush(c->err); + return OPT_ERR; + } + } + } + + if (!c->imports && !c->exports) { + c->imports = c->exports = 1; + } + return OPT_OK; +} + +static void processpe(s8 dll, config conf, arena scratch) +{ + u8buf *out = conf.out; + escape *esc = scratch.esc; + + u32 peoff = readu32(dll, 0x3c, esc); + s8 pe = slice2(dll, peoff, esc); + s8 pehdr = slice3(pe, 0, 4, esc); + if (!equals(s8("PE\0\0"), pehdr)) { + throw(esc, s8("not a PE file")); + } + + u16 nsections = readu16(pe, 4+ 2, esc); + u16 hdrsize = readu16(pe, 4+16, esc); + + enum { PE32, PE64 }; + u16 magic = readu16(pe, 4+20, esc); + i32 type = -1; + switch (magic) { + default: throw(esc, s8("unknown PE magic")); + case 0x010b: type = PE32; break; + case 0x020b: type = PE64; break; + } + + vm map = {0}; + i32 loadlen = nsections>96 ? 96 : nsections; + map.regions = new(&scratch, loadlen, region); + s8 sections = slice2(pe, 4+20+hdrsize, esc); + for (i32 i = 0; i < loadlen; i++) { + u32 vsize = readu32(sections, 40*i+ 8, esc); + u32 vaddr = readu32(sections, 40*i+12, esc); + u32 rsize = readu32(sections, 40*i+16, esc); + u32 raddr = readu32(sections, 40*i+20, esc); + + i32 r = map.len++; + map.regions[r].beg = vaddr; + map.regions[r].end = checkadd(vaddr, vsize, esc); + if (r) { + region prev = map.regions[r-1]; + if (prev.beg>=vaddr || prev.end>vaddr) { + throw(esc, s8("invalid section order")); + } + } + + u32 rend = checkadd(raddr, rsize, esc); + map.regions[r].mem = slice3(dll, raddr, rend, esc); + if (vsize > rsize) { + // Padded sections (e.g. .bss) unlikely interesting: discard + map.len--; + } else if (vsize < rsize) { + // Truncated sections *are* usually interesting. Go figure. + map.regions[r].mem.len = vsize; + } + } + + u32 edataoff = readu32(pe, 24+(type==PE32 ? 96 : 112), esc); + u32 edatalen = readu32(pe, 24+(type==PE32 ? 100 : 116), esc); + u32 edataend = checkadd(edataoff, edatalen, esc); + s8 edata = loadrva(map, edataoff, esc); + + if (conf.exports && edatalen) { + print(out, s8("EXPORTS\n")); + + u32 ordbase = readu32(edata, 4*4, esc); + i32 naddrs = readu32(edata, 5*4, esc); + i32 nnames = readu32(edata, 6*4, esc); + if (naddrs<0 || nnames<0) { + throw(esc, s8("invalid export count")); + } + + // If naddrs is huge, this will fail here with OOM + u8 *seen = new(&scratch, naddrs, u8); + + u32 addrsoff = readu32(edata, 7*4, esc); + s8 addrs = loadrva(map, addrsoff, esc); + u32 namesoff = readu32(edata, 8*4, esc); + s8 names = loadrva(map, namesoff, esc); + u32 ordsoff = readu32(edata, 9*4, esc); + s8 ordinals = loadrva(map, ordsoff, esc); + + // If nnames is huge, the loop will EOF before overflow + for (i32 i = 0; i < nnames; i++) { + u16 ordinal = readu16(ordinals, i*2, esc); + if (ordinal >= naddrs) { + throw(esc, s8("invalid export ordinal")); + } + seen[ordinal] = 1; + + // If RVA points in .edata it's a forwarder name + s8 module = {0}; + u32 addr = readu32(addrs, ordinal*4, esc); + if (addr>=edataoff && addr")); + } + print(out, s8("\n")); + } + + for (i32 i = 0; i < naddrs; i++) { + if (!seen[i]) { + print(out, s8("\t")); + printu32(out, checkadd(i, ordbase, esc)); + print(out, s8("\t\n")); + } + } + } + + u32 idataoff = readu32(pe, 24+(type==PE32 ? 104 : 120), esc); + u32 idatalen = readu32(pe, 24+(type==PE32 ? 108 : 124), esc); + s8 idata = loadrva(map, idataoff, esc); + + if (conf.imports && idatalen) { + // The PE specification says the last import directory table + // entry is all zeros, indicating the directory end. However, + // MSVC link.exe is buggy and does not reliably produce this + // null entry. Instead the directory runs into import lookup + // tables and string table, causing the directory to read as + // garbage. We have two workarounds: + // + // 1. Track the earliest import lookup table RVA, and stop + // reading if the directory would overlap it. + // 2. Don't treat garbage RVA fields as errors, just stop + // reading the table (Binutils strategy). + // + // This issue was crashing objdump back in 2005. See Binutils + // commit a50b216054a4. + u32 firsttable = -1; + + for (i32 i = 0;; i++) { + if (idataoff + i*20 == firsttable) { + // Probably the link.exe bug. We're now overlapping an + // import lookup table, so stop reading the import + // directory. The left-side sum might overflow, but + // that's fine. This is just a heuristic. + break; + } + + u32 tableoff = readu32(idata, i*20+ 0, esc); + u32 nameoff = readu32(idata, i*20+12, esc); + if (!tableoff || !nameoff) break; + + s8 name = nullterm(loadrva(map, nameoff, esc)); + if (!name.data) break; // ignore link.exe bug + + printname(out, name); + print(out, s8("\n")); + + s8 table = loadrva(map, tableoff, esc); + if (!table.data) break; // ignore link.exe bug + firsttable = firsttable>31) { + printu32(out, addr&0x7fffffff); + print(out, s8("\t")); + } else { + s8 entry = loadrva(map, addr, esc); + u16 hint = readu16(entry, 0, esc); + printu32(out, hint); + print(out, s8("\t")); + s8 name = nullterm(slice2(entry, 2, esc)); + printname(out, name); + } + print(out, s8("\n")); + } + } + } +} + +static void processpath(s8 path, config conf, arena scratch) +{ + s8 dll = osload(&scratch, path); + if (!dll.data) { + throw(scratch.esc, s8("could not load file")); + } + processpe(dll, conf, scratch); +} + +static b32 peports(i32 argc, s8 *argv, arena scratch) +{ + b32 ok = 1; + u8buf out[1] = {newu8buf(&scratch, 1)}; + u8buf err[1] = {newu8buf(&scratch, 2)}; + + config conf = {0}; + conf.out = out; + conf.err = err; + switch (parseopts(&conf, argc, argv)) { + case OPT_OK: break; + case OPT_EXIT: return 1; + case OPT_ERR: return 0; + } + + if (conf.optind == argc) { + static s8 fakeargv[] = {s8("peports"), s8("-")}; + argc = countof(fakeargv); + argv = fakeargv; + conf.optind = 1; + } + + escape esc = {0}; + scratch.esc = &esc; + for (i32 i = conf.optind; i < argc; i++) { + if (catch(&esc)) { + flush(out); + print(err, s8("peports: ")); + print(err, esc.err); + print(err, s8(": ")); + print(err, argv[i]); // NOTE: UTF-8 + print(err, s8("\n")); + flush(err); + ok &= 1; + continue; + } + processpath(argv[i], conf, scratch); + } + + flush(out); + ok &= !out->err; + return ok; +} + + +#if _WIN32 +// $ gcc -nostartfiles -o peports.exe peports.c +// $ clang-cl peports.c /link /subsystem:console +// kernel32.lib shell32.lib libvcruntime.lib + +#define W32(r) __declspec(dllimport) r __stdcall +W32(b32) CloseHandle(uz); +W32(c16 **) CommandLineToArgvW(c16 *, i32 *); +W32(b32) CreateFileW(c16 *, i32, i32, uz, i32, i32, uz); +W32(void) ExitProcess(i32) __attribute((noreturn)); +W32(c16 *) GetCommandLineW(void); +W32(uz) GetStdHandle(i32); +W32(i32) MultiByteToWideChar(i32, i32, u8 *, i32, c16 *, i32); +W32(b32) ReadFile(uz, u8 *, i32, i32 *, uz); +W32(i32) WideCharToMultiByte(i32, i32, c16 *, i32, u8 *, i32, uz, uz); +W32(b32) WriteFile(uz, u8 *, i32, i32 *, uz); + +static i32 truncsize(iz len, i32 max) +{ + return maxbeg; + iz avail = a->end - a->beg; + avail -= avail / 8; // don't fill the arena to the brim + for (;;) { + i32 max = 1<<21; + i32 len; + ReadFile(handle, r.data+r.len, truncsize(avail-r.len, max), &len, 0); + if (len < 1) break; + r.len += len; + } + a->beg += r.len; + + if (close) CloseHandle(handle); + return r; +} + +static b32 oswrite(i32 fd, u8 *buf, i32 len) +{ + uz h = GetStdHandle(-10 - fd); + return WriteFile(h, buf, len, &len, 0); +} + +__attribute((force_align_arg_pointer)) +void mainCRTStartup(void) +{ + static byte mem[sizeof(uz)<<26]; // 256/512 MiB + arena scratch = {0}; + scratch.beg = mem; + asm ("" : "+r"(scratch.beg)); // launder the pointer + scratch.end = scratch.beg + countof(mem); + + c16 *cmd = GetCommandLineW(); + i32 argc = 0; + c16 **argvw = CommandLineToArgvW(cmd, &argc); + s8 *argv = new(&scratch, argc, s8); + for (i32 i = 0; i < argc; i++) { + i32 len = WideCharToMultiByte(65001, 0, argvw[i], -1, 0, 0, 0, 0); + argv[i].data = new(&scratch, len, u8); + argv[i].len = len ? len-1 : len; + WideCharToMultiByte(65001, 0, argvw[i], -1, argv[i].data, len, 0, 0); + } + + b32 ok = peports(argc, argv, scratch); + ExitProcess(!ok); +} + + +#elif __AFL_COMPILER +// $ afl-gcc-fast -g3 -fsanitize=undefined peports.c +// $ mkdir i +// $ cp corpus.dll i/ +// $ afl-fuzz -ii -oo ./a.out +#include +#include + +__AFL_FUZZ_INIT(); + +static b32 oswrite(i32, u8 *, i32) { return 1; } +static s8 osload(arena *, s8) { __builtin_trap(); } + +int main(void) +{ + __AFL_INIT(); + + iz cap = 1<<20; + arena a = {0}; + a.beg = malloc(cap); + a.end = a.beg + cap; + + config c = {0}; + c.exports = 1; + c.imports = 1; + c.out = new(&a, 1, u8buf); + *c.out = newu8buf(&a, 1); + c.err = new(&a, 1, u8buf); + *c.err = newu8buf(&a, 2); + + s8 dll = {0}; + dll.data = __AFL_FUZZ_TESTCASE_BUF; + while (__AFL_LOOP(10000)) { + dll.len = __AFL_FUZZ_TESTCASE_LEN; + a.esc = &(escape){0}; + if (!catch(a.esc)) { + processpe(dll, c, a); + } + } +} + + +#else // POSIX-ish? +// $ cc -o peports peports.c +#include +#include +#include + +static s8 osload(arena *a, s8 path) +{ + s8 r = {0}; + int fd = 0; + b32 closeit = 1; + + if (equals(path, s8("-"))) { + closeit = 0; + } else { + // NOTE: Assume the path is null-terminated because it came + // straight from argv. This program does not construct paths. + char *cpath = (char *)path.data; + fd = open(cpath, O_RDONLY); + if (fd == -1) return r; + } + + r.data = (u8 *)a->beg; + iz avail = a->end - a->beg; + avail -= avail / 8; // don't fill the arena to the brim + while (r.len < avail) { + iz len = read(fd, r.data+r.len, avail-r.len); + if (len < 1) break; + r.len += len; + } + a->beg += r.len; + + if (closeit) close(fd); + return r; +} + +static b32 oswrite(i32 fd, u8 *buf, i32 len) +{ + for (i32 off = 0; off < len;) { + i32 r = (i32)write(fd, buf+off, len-off); + if (r < 1) return 0; + off += r; + } + return 1; +} + +int main(int argc, char **argv) +{ + static byte mem[sizeof(uz)<<26]; // 256/512 MiB + arena scratch = {0}; + scratch.beg = mem; + asm ("" : "+r"(scratch.beg)); // launder the pointer + scratch.end = scratch.beg + countof(mem); + + s8 *args = new(&scratch, argc, s8); + for (int i = 0; i < argc; i++) { + args[i].data = (u8 *)argv[i]; + args[i].len = strlen(argv[i]); + } + b32 ok = peports(argc, args, scratch); + return !ok; +} +#endif diff --git a/.gnu-windows/src/pkg-config.c b/.gnu-windows/src/pkg-config.c index e3036af42..1f7f356e7 100644 --- a/.gnu-windows/src/pkg-config.c +++ b/.gnu-windows/src/pkg-config.c @@ -1,73 +1,46 @@ // u-config: a small, simple, portable pkg-config clone // https://github.com/skeeto/u-config // $ cc -nostartfiles -o pkg-config.exe pkg-config.c -// $ cl pkg-config.c // This is free and unencumbered software released into the public domain. +#define VERSION "0.33.1" -// Fundamental definitions +typedef unsigned char u8; +typedef signed int b32; +typedef signed int i32; +typedef unsigned int u32; +typedef __PTRDIFF_TYPE__ size; +typedef char byte; -#define VERSION "0.31.1" - -typedef int Size; -#define Size_MASK ((unsigned)-1) -#define Size_MAX ((Size)(Size_MASK >> 1)) - -#define SIZEOF(x) (Size)(sizeof(x)) -#define COUNTOF(a) (SIZEOF(a)/SIZEOF(a[0])) - -typedef int Bool; -typedef unsigned char Byte; - -#if __GNUC__ - #define TRAP __builtin_trap() - #define NORETURN __attribute__((noreturn)) -#elif _MSC_VER - #define TRAP __debugbreak() - #define NORETURN __declspec(noreturn) -#else - #define TRAP *(volatile int *)0 = 0 - #define NORETURN -#endif - -#ifdef DEBUG - #define ASSERT(c) if (!(c)) TRAP -#else - #define ASSERT(c) -#endif +#define assert(c) while (!(c)) __builtin_unreachable() +#define countof(a) (size)(sizeof(a) / sizeof(*(a))) +#define new(a, t, n) (t *)alloc(a, sizeof(t), n) +#define s8(s) {(u8 *)s, countof(s)-1} +#define S(s) (s8)s8(s) typedef struct { - Byte *s; - Size len; -} Str; - -#ifdef __cplusplus - #define S(s) makestr((Byte *)s, SIZEOF(s)-1) - static inline Str makestr(Byte *s, Size len) - { - Str r = {s, len}; - return r; - } -#else - #define S(s) (Str){(Byte *)s, SIZEOF(s)-1} -#endif + u8 *s; + size len; +} s8; typedef struct { - Str mem; - Size off; -} Arena; + byte *beg; + byte *end; +} arena; typedef struct { - Arena arena; - Str *args; - Size nargs; - Str envpath; // $PKG_CONFIG_PATH or empty - Str fixedpath; // $PKG_CONFIG_LIBDIR or default - Str top_builddir; // $PKG_CONFIG_TOP_BUILD_DIR or default - Str sys_incpath; // $PKG_CONFIG_SYSTEM_INCLUDE_PATH or default - Str sys_libpath; // $PKG_CONFIG_SYSTEM_LIBRARY_PATH or default - Bool define_prefix; - Byte delim; -} Config; + arena perm; + s8 *args; + size nargs; + s8 envpath; // $PKG_CONFIG_PATH or empty + s8 fixedpath; // $PKG_CONFIG_LIBDIR or default + s8 top_builddir; // $PKG_CONFIG_TOP_BUILD_DIR or default + s8 sys_incpath; // $PKG_CONFIG_SYSTEM_INCLUDE_PATH or default + s8 sys_libpath; // $PKG_CONFIG_SYSTEM_LIBRARY_PATH or default + s8 print_sysinc; // $PKG_CONFIG_ALLOW_SYSTEM_CFLAGS or empty + s8 print_syslib; // $PKG_CONFIG_ALLOW_SYSTEM_LIBS or empty + b32 define_prefix; + u8 delim; +} config; // Platform API @@ -75,510 +48,485 @@ typedef struct { // Application entry point. Returning from this function indicates the // application itself completed successfully. However, an os_write error // may result in a non-zero exit. -static void appmain(Config); +static void uconfig(config *); -typedef enum {MapFile_OK, MapFile_NOTFOUND, MapFile_READERR} MapFileStatus; +enum { filemap_OK, filemap_NOTFOUND, filemap_READERR }; typedef struct { - Str contents; - MapFileStatus status; -} MapFileResult; + s8 data; + i32 status; +} filemap; // Load a file into memory, maybe using the arena. The path must include // a null terminator since it may be passed directly to the OS interface. -static MapFileResult os_mapfile(Arena *, Str path); +static filemap os_mapfile(arena *, s8 path); // Write buffer to stdout (1) or stderr (2). The platform must detect // write errors and arrange for an eventual non-zero exit status. -static void os_write(int fd, Str); +static void os_write(i32 fd, s8); // Immediately exit the program with a non-zero status. -NORETURN static void os_fail(void); +static void os_fail(void) __attribute((noreturn)); // Application -NORETURN static void oom(void) +static void oom(void) { os_write(2, S("pkg-config: out of memory\n")); os_fail(); } -static Bool digit(Byte c) +static b32 digit(u8 c) { return c>='0' && c<='9'; } -static Bool whitespace(Byte c) +static b32 whitespace(u8 c) { switch (c) { - case '\t': case '\n': case '\b': case '\f': case '\r': case ' ': + case '\t': case '\n': case '\r': case ' ': return 1; } return 0; } -static Bool pathsep(Byte c) +static byte *fillbytes(byte *dst, byte c, size len) { - return c=='/' || c=='\\'; -} - -static Str fillstr(Str s, Byte b) -{ - for (Size i = 0; i < s.len; i++) { - s.s[i] = b; + byte *r = dst; + for (; len; len--) { + *dst++ = c; } - return s; + return r; } -static void *alloc(Arena *a, Size size) +static void u8copy(u8 *dst, u8 *src, size n) { - ASSERT(size >= 0); - Size align = -size & (SIZEOF(void *) - 1); - Size avail = a->mem.len - a->off; - if (avail-align < size) { - oom(); + assert(n >= 0); + for (; n; n--) { + *dst++ = *src++; } - Byte *p = a->mem.s + a->off; - a->off += size + align; - return p; } -static void *allocarray(Arena *a, Size size, Size count) +static i32 u8compare(u8 *a, u8 *b, size n) { - ASSERT(size > 0); - ASSERT(count >= 0); - if (count > Size_MAX/size) { - oom(); + for (; n; n--) { + i32 d = *a++ - *b++; + if (d) return d; } - return alloc(a, size*count); -} - -static Str newstr(Arena *a, Size len) -{ - Str r = {(Byte *)alloc(a, len), len}; - return r; + return 0; } -static void *zalloc(Arena *a, Size size) +static b32 pathsep(u8 c) { - Str r = newstr(a, size); - return fillstr(r, 0).s; + return c=='/' || c=='\\'; } -static Str maxstr(Arena *a) +__attribute((malloc, alloc_size(3, 2))) +static byte *alloc(arena *a, size objsize, size count) { - Size len = a->mem.len - a->off; - return newstr(a, len); + assert(objsize > 0); + assert(count >= 0); + size alignment = -((u32)objsize * (u32)count) & 7; + size available = a->end - a->beg - alignment; + if (count > available/objsize) { + oom(); + } + size total = objsize * count; + return fillbytes(a->end -= total + alignment, 0, total); } -// Fill free space with garbage when debugging. -static void shredfree(Arena *a) +static s8 news8(arena *perm, size len) { - (void)a; - #ifdef DEBUG - Arena temp = *a; - fillstr(maxstr(&temp), 0xa5); - #endif + s8 r = {0}; + r.s = new(perm, u8, len); + r.len = len; + return r; } -static Str fromptrs(Byte *beg, Byte *end) +static s8 s8span(u8 *beg, u8 *end) { - ASSERT(beg); - ASSERT(end); - ASSERT(end >= beg); - Str s = {beg, (Size)(end - beg)}; + assert(beg); + assert(end); + assert(end >= beg); + s8 s = {0}; + s.s = beg; + s.len = end - beg; return s; } // Copy src into dst returning the remaining portion of dst. -static Str copy(Str dst, Str src) -{ - ASSERT(dst.len >= src.len); - for (Size i = 0; i < src.len; i++) { - dst.s[i] = src.s[i]; - } - Str r = {dst.s+src.len, dst.len-src.len}; - return r; -} - -// Compare strings, returning -1, 0, or +1. -static int orderstr(Str a, Str b) +static s8 s8copy(s8 dst, s8 src) { - // NOTE: "null" strings are still valid strings - Size len = a.len= src.len); + u8copy(dst.s, src.s, src.len); + dst.s += src.len; + dst.len -= src.len; + return dst; } -static Bool equals(Str a, Str b) +static b32 s8equals(s8 a, s8 b) { - return 0 == orderstr(a, b); + return a.len==b.len && !u8compare(a.s, b.s, a.len); } -static Str cuthead(Str s, Size off) +static s8 cuthead(s8 s, size off) { - ASSERT(off >= 0); - ASSERT(off <= s.len); + assert(off >= 0); + assert(off <= s.len); s.s += off; s.len -= off; return s; } -static Str takehead(Str s, Size len) +static s8 takehead(s8 s, size len) { - ASSERT(len >= 0); - ASSERT(len <= s.len); + assert(len >= 0); + assert(len <= s.len); s.len = len; return s; } -static Str cuttail(Str s, Size len) +static s8 cuttail(s8 s, size len) { - ASSERT(len >= 0); - ASSERT(len <= s.len); - Str r = {s.s, s.len-len}; - return r; + assert(len >= 0); + assert(len <= s.len); + s.len -= len; + return s; } -static Str taketail(Str s, Size len) +static s8 taketail(s8 s, size len) { return cuthead(s, s.len-len); } -static Bool startswith(Str s, Str prefix) +static b32 startswith(s8 s, s8 prefix) { - return s.len>=prefix.len && equals(takehead(s, prefix.len), prefix); + return s.len>=prefix.len && s8equals(takehead(s, prefix.len), prefix); } -static Size hash(Str s) +static u32 s8hash(s8 s) { - unsigned long long h = 257; - for (Size i = 0; i < s.len; i++) { + u32 h = 0x811c9dc5; + for (size i = 0; i < s.len; i++) { h ^= s.s[i]; - h *= 1111111111111111111; + h *= 0x01000193; } - h ^= h >> 33; - return (Size)(h & Size_MASK); + return h; } typedef struct { - Str head; - Str tail; -} StrPair; + s8 head; + s8 tail; +} s8pair; -static StrPair digits(Str s) +static s8pair digits(s8 s) { - Size i = 0; - for (; ikey)) { - case -1: target = parent->child + 0; break; - case 0: return parent; - case +1: target = parent->child + 1; break; - } +// Encode paths with illegal UTF-8 bytes. Reversible. Allows white space +// and meta characters in paths to behave differently. Encode paths +// before variable assignment. Reversed by dequote() when printed. +static u8 pathencode(u8 c) +{ + // NOTE: space classification must agree with whitespace() + switch (c) { + case '\t': return 0xf8; + case '\n': return 0xf9; + case '\r': return 0xfa; + case ' ' : return 0xfb; + case '$' : return 0xfc; + case '(' : return 0xfd; + case ')' : return 0xfe; } + return c; +} - // None found, insert a new leaf - if (!a) { - return 0; // "only browsing, thanks" +static u8 pathdecode(u8 c) +{ + switch (c) { + case 0xf8: return '\t'; + case 0xf9: return '\n'; + case 0xfa: return '\r'; + case 0xfb: return ' ' ; + case 0xfc: return '$' ; + case 0xfd: return '(' ; + case 0xfe: return ')' ; } - Treap *node = (Treap *)zalloc(a, size); - node->key = key; - node->parent = parent; - *target = node; - - // Randomly rotate the tree according to the hash - Size keyhash = hash(key); - while (node->parent && hash(node->parent->key)parent; + return c; +} - // Swap places with parent, also updating grandparent - node->parent = parent->parent; - parent->parent = node; - if (node->parent) { - int i = node->parent->child[0] == parent; - node->parent->child[!i] = node; - } else { - *t = node; - } +static s8 s8pathencode(s8 s, arena *perm) +{ + b32 encode = 0; + for (size i = 0; ichild[0] == node; - parent->child[!i] = node->child[i]; - if (node->child[i]) { - node->child[i]->parent = parent; - } - node->child[i] = parent; + s8 r = news8(perm, s.len); + for (size i = 0; i < s.len; i++) { + r.s[i] = pathencode(s.s[i]); } - return node; + return r; } typedef struct { - Str buf; - Str avail; - Arena *a; - int fd; -} Out; + u8 *buf; + size cap; + size len; + arena *perm; + i32 fd; +} u8buf; // Buffered output for os_write(). -static Out newoutput(Arena *a, int fd, Size len) +static u8buf *newfdbuf(arena *perm, i32 fd, size cap) { - Str buf = newstr(a, len); - Out out = {buf, buf, 0, fd}; - return out; + u8buf *b = new(perm, u8buf, 1); + b->cap = cap; + b->buf = new(perm, u8, cap); + b->fd = fd; + return b; } -static Out newnullout(void) +static u8buf *newnullout(arena *perm) { - Out out = {0}; - out.fd = -1; - return out; + u8buf *b = new(perm, u8buf, 1); + b->fd = -1; + return b; } // Output to a dynamically-grown arena buffer. The arena cannot be used // again until this buffer is finalized. -static Out newmembuf(Arena *a) +static u8buf newmembuf(arena *perm) { - Str max = maxstr(a); - Out out = {max, max, a, 0}; - return out; + u8buf b = {0}; + b.buf = (u8 *)perm->beg; + b.cap = perm->end - perm->beg; + b.perm = perm; + return b; +} + +static s8 gets8(u8buf *b) +{ + s8 s = {0}; + s.s = b->buf; + s.len = b->len; + return s; } // Close the stream and release the arena, returning the result buffer. -static Str finalize(Out *out) +static s8 finalize(u8buf *b) { - ASSERT(!out->fd); - Size len = out->buf.len - out->avail.len; - out->a->off -= out->buf.len; - return newstr(out->a, len); + assert(!b->fd); + b->perm->beg += b->len; + return gets8(b); } -static void flush(Out *out) +static void flush(u8buf *b) { - ASSERT(out->fd); - if (out->buf.len != out->avail.len) { - Str fill = {out->buf.s, out->buf.len-out->avail.len}; - os_write(out->fd, fill); - out->avail = out->buf; + switch (b->fd) { + case -1: break; // /dev/null + case 0: oom(); + break; + default: if (b->len) { + os_write(b->fd, gets8(b)); + } } + b->len = 0; } -static void outstr(Out *out, Str s) +static void prints8(u8buf *b, s8 s) { - if (out->fd == -1) { + if (b->fd == -1) { return; // /dev/null } - - if (out->fd == 0) { - // Output to a memory buffer, not a stream - if (out->avail.len < s.len) { - oom(); - } - out->avail = copy(out->avail, s); - return; - } - - // Copy into the stream buffer - while (s.len) { - if (out->avail.len >= s.len) { - out->avail = copy(out->avail, s); - s.len = 0; - } else if (out->buf.len==out->avail.len && s.len>=out->buf.len) { - os_write(out->fd, s); - s.len = 0; - } else { - Size len = out->avail.len; - Str head = takehead(s, len); - s = cuthead(s, len); - out->avail = copy(out->avail, head); - flush(out); + for (size off = 0; off < s.len;) { + size avail = b->cap - b->len; + size count = availbuf+b->len, s.s+off, count); + b->len += count; + off += count; + if (b->len == b->cap) { + flush(b); } } } -static void outbyte(Out *out, Byte b) +static void printu8(u8buf *b, u8 c) { - Str s = {&b, 1}; - outstr(out, s); + prints8(b, s8span(&c, &c+1)); } -typedef struct Var { - Treap node; - Str value; -} Var; +typedef struct env env; +struct env { + env *child[4]; + s8 name; + s8 value; +}; -typedef struct { - Treap *vars; -} Env; - -// Return a pointer to the binding so that the caller can choose to fill -// it. The arena is optional. If given, the binding will be created and -// set to a null string. An unallocated, zero-initialized environment is -// a valid empty environment. -static Str *insert(Arena *a, Env *e, Str name) +// Return a pointer to the binding so that the caller can bind it. The +// arena is optional. If given, the binding will be created and set to a +// null string. A null pointer is a valid empty environment. +static s8 *insert(env **e, s8 name, arena *perm) { - Var *var = (Var *)treapinsert(a, &e->vars, name, SIZEOF(*var)); - return var ? &var->value : 0; + for (u32 h = s8hash(name); *e; h <<= 2) { + if (s8equals((*e)->name, name)) { + return &(*e)->value; + } + e = &(*e)->child[h>>30]; + } + if (!perm) { + return 0; + } + *e = new(perm, env, 1); + (*e)->name = name; + return &(*e)->value; } // Try to find the binding in the global environment, then failing that, // the second environment. Returns a null string if no entry was found. -// An unallocated, zero-initialized environment is valid for lookups. -static Str lookup(Env *global, Env *env, Str name) +// A null pointer is valid for lookups. +static s8 lookup(env *global, env *env, s8 name) { - Str *s = insert(0, global, name); - if (s) { - return *s; - } - s = insert(0, env, name); - if (s) { - return *s; - } - Str r = {0}; - return r; + s8 *s = 0; + s8 null = {0}; + s = s ? s : insert(&global, name, 0); + s = s ? s : insert(&env, name, 0); + s = s ? s : &null; + return *s; } -static Str dirname(Str path) +static s8 dirname(s8 path) { - Size len = path.len; + size len = path.len; while (len>0 && !pathsep(path.s[--len])) {} return takehead(path, len); } -static Str basename(Str path) +static s8 basename(s8 path) { - Size len = path.len; + size len = path.len; for (; len>0 && !pathsep(path.s[len-1]); len--) {} return taketail(path, path.len-len); } -static Str buildpath(Arena *a, Str dir, Str pc) +static s8 buildpath(s8 dir, s8 pc, arena *perm) { - Str sep = S("/"); - Str suffix = S(".pc\0"); - Size pathlen = dir.len + sep.len + pc.len + suffix.len; - Str path = newstr(a, pathlen); - Str p = path; - p = copy(p, dir); - p = copy(p, sep); - p = copy(p, pc); - copy(p, suffix); + s8 sep = S("/"); + s8 suffix = S(".pc\0"); + size pathlen = dir.len + sep.len + pc.len + suffix.len; + s8 path = news8(perm, pathlen); + s8 p = path; + p = s8copy(p, dir); + p = s8copy(p, sep); + p = s8copy(p, pc); + s8copy(p, suffix); return path; } -typedef enum {Pkg_DIRECT=1<<0, Pkg_PUBLIC=1<<1} PkgFlags; +enum { pkg_DIRECT=1<<0, pkg_PUBLIC=1<<1 }; -typedef struct Pkg { - Treap node; - struct Pkg *list; // total load order list - Str path; - Str realname; - Str contents; - Env env; - int flags; +typedef struct pkg pkg; +struct pkg { + pkg *child[4]; + pkg *list; // total load order list + s8 path; + s8 realname; + s8 contents; + env *env; + i32 flags; #define PKG_NFIELDS 10 - Str name; - Str description; - Str url; - Str version; - Str requires; - Str requiresprivate; - Str conflicts; - Str libs; - Str libsprivate; - Str cflags; -} Pkg; - -static Str *fieldbyid(Pkg *p, int id) -{ - ASSERT(id >= 0); - ASSERT(id < PKG_NFIELDS); + s8 name; + s8 description; + s8 url; + s8 version; + s8 requires; + s8 requiresprivate; + s8 conflicts; + s8 libs; + s8 libsprivate; + s8 cflags; +}; + +static s8 *fieldbyid(pkg *p, i32 id) +{ + assert(id >= 0); + assert(id < PKG_NFIELDS); return &p->name + id; } -static Str *fieldbyname(Pkg *p, Str name) -{ - static const unsigned char offs[] = {0,4,15,18,25,25,41,50,50,62}; - static const unsigned char lens[] = {4,11,3,7,8,16,9,4,12,6}; - static const Byte fields[] = - "Name" "Description" "URL" "Version" "Requires.private" - "Conflicts" "Libs.private" "Cflags"; - for (int i = 0; i < COUNTOF(offs); i++) { - Str field = {(Byte *)fields+offs[i], lens[i]}; - if (equals(field, name)) { +static s8 *fieldbyname(pkg *p, s8 name) +{ + static const s8 fields[] = { + s8("Name"), + s8("Description"), + s8("URL"), + s8("Version"), + s8("Requires"), + s8("Requires.private"), + s8("Conflicts"), + s8("Libs"), + s8("Libs.private"), + s8("Cflags") + }; + for (i32 i = 0; i < countof(fields); i++) { + if (s8equals(fields[i], name)) { return fieldbyid(p, i); } } @@ -586,43 +534,49 @@ static Str *fieldbyname(Pkg *p, Str name) } typedef struct { - Treap *pkgs; - Pkg *head, *tail; - Size count; -} Pkgs; + pkg *pkgs; + pkg *head; + pkg **tail; + size count; +} pkgs; + +static pkgs *newpkgs(arena *perm) +{ + pkgs *p = new(perm, pkgs, 1); + p->tail = &p->head; + return p; +} // Locate a previously-loaded package, or allocate zero-initialized // space in the set for a new package. -static Pkg *locate(Arena *a, Pkgs *t, Str realname) -{ - Pkg *p = (Pkg *)treapinsert(a, &t->pkgs, realname, SIZEOF(*p)); - if (!p->realname.s) { - t->count++; - p->realname = realname; - if (!t->head) { - t->head = t->tail = p; - } else { - t->tail->list = p; - t->tail = p; +static pkg *locate(pkgs *t, s8 realname, arena *perm) +{ + pkg **p = &t->pkgs; + for (u32 h = s8hash(realname); *p; h <<= 2) { + if (s8equals((*p)->realname, realname)) { + return *p; } + p = &(*p)->child[h>>30]; } - return p; + + *p = new(perm, pkg, 1); + (*p)->realname = realname; + t->count++; + *t->tail = *p; + t->tail = &(*p)->list; + return *p; } -typedef enum { - Parse_OK, - Parse_DUPFIELD, - Parse_DUPVARABLE -} ParseStatus; +enum { parse_OK, parse_DUPFIELD, parse_DUPVARABLE }; typedef struct { - Pkg pkg; - Str dupname; - ParseStatus status; -} ParseResult; + pkg pkg; + s8 dupname; + i32 err; +} parseresult; // Return the number of escape bytes at the beginning of the input. -static Size escaped(Str s) +static size escaped(s8 s) { if (startswith(s, S("\\\n"))) { return 2; @@ -634,14 +588,14 @@ static Size escaped(Str s) } // Return a copy of the input with the escapes squashed out. -static Str stripescapes(Arena *a, Str s) +static s8 stripescapes(arena *perm, s8 s) { - Size len = 0; - Str c = newstr(a, s.len); - for (Size i = 0; i < s.len; i++) { - Byte b = s.s[i]; + size len = 0; + s8 c = news8(perm, s.len); + for (size i = 0; i < s.len; i++) { + u8 b = s.s[i]; if (b == '\\') { - Size r = escaped(cuthead(s, i)); + size r = escaped(cuthead(s, i)); if (r) { i += r - 1; } else if (is) { - ParseResult dup = {0}; + parseresult dup = {0}; dup.dupname = name; - dup.status = Parse_DUPFIELD; + dup.err = parse_DUPFIELD; return dup; } break; @@ -712,7 +666,7 @@ static ParseResult parsepackage(Arena *a, Str src) // Skip leading space; newlines may be escaped with a backslash while (p < e) { if (*p == '\\') { - Size r = escaped(fromptrs(p, e)); + size r = escaped(s8span(p, e)); if (r) { p += r; } else { @@ -725,7 +679,7 @@ static ParseResult parsepackage(Arena *a, Str src) } } - Bool cleanup = 0; + b32 cleanup = 0; end = beg = p; for (; pindex == p->nargs) { - OptionResult r = {0}; return r; } for (;;) { - Str arg = p->args[p->index++]; + s8 arg = p->args[p->index++]; if (p->dashdash || arg.len<2 || arg.s[0]!='-') { - OptionResult r = {0}; r.arg = arg; r.ok = 1; return r; } - if (!p->dashdash && equals(arg, S("--"))) { + if (!p->dashdash && s8equals(arg, S("--"))) { p->dashdash = 1; continue; } - OptionResult r = {0}; r.isoption = 1; r.ok = 1; arg = cuthead(arg, 1); - Cut c = cut(arg, '='); + cut c = s8cut(arg, '='); if (c.ok) { r.arg = c.head; r.value = c.tail; @@ -829,7 +784,7 @@ static OptionResult nextoption(OptionParser *p) } } -static Str getargopt(Out *err, OptionParser *p, Str option) +static s8 getargopt(u8buf *err, options *p, s8 option) { if (p->index == p->nargs) { missing(err, option); @@ -837,9 +792,9 @@ static Str getargopt(Out *err, OptionParser *p, Str option) return p->args[p->index++]; } -static void usage(Out *out) +static void usage(u8buf *b) { - static const char usage[] = + static const u8 usage[] = "u-config " VERSION " https://github.com/skeeto/u-config\n" "free and unencumbered software released into the public domain\n" "usage: pkg-config [OPTIONS...] [PACKAGES...]\n" @@ -863,97 +818,96 @@ static void usage(Out *out) " PKG_CONFIG_LIBDIR\n" " PKG_CONFIG_TOP_BUILD_DIR\n" " PKG_CONFIG_SYSTEM_INCLUDE_PATH\n" - " PKG_CONFIG_SYSTEM_LIBRARY_PATH\n"; - outstr(out, S(usage)); + " PKG_CONFIG_SYSTEM_LIBRARY_PATH\n" + " PKG_CONFIG_ALLOW_SYSTEM_CFLAGS\n" + " PKG_CONFIG_ALLOW_SYSTEM_LIBS\n"; + prints8(b, S(usage)); } -typedef struct StrListNode { - struct StrListNode *next; - Str entry; -} StrListNode; +typedef struct s8node s8node; +struct s8node { + s8node *next; + s8 str; +}; typedef struct { - StrListNode *head; - StrListNode *tail; -} StrList; - -static void append(Arena *a, StrList *list, Str str) -{ - StrListNode *node = (StrListNode *)alloc(a, SIZEOF(*node)); - node->next = 0; - node->entry = str; - if (list->tail) { - ASSERT(list->head); - list->tail->next = node; - } else { - ASSERT(!list->tail); - list->head = node; + s8node *head; + s8node **tail; +} s8list; + +static void append(s8list *list, s8 str, arena *perm) +{ + if (!list->tail) { + list->tail = &list->head; } - list->tail = node; + s8node *node = new(perm, s8node, 1); + node->str = str; + *list->tail = node; + list->tail = &node->next; } typedef struct { - StrList list; - Byte delim; -} Search; + s8list list; + u8 delim; +} search; -static Search newsearch(Byte delim) +static search newsearch(u8 delim) { - Search r = {0}; + search r = {0}; r.delim = delim; return r; } -static void appendpath(Arena *a, Search *dirs, Str path) +static void appendpath(search *dirs, s8 path, arena *perm) { while (path.len) { - Cut c = cut(path, dirs->delim); - Str dir = c.head; + cut c = s8cut(path, dirs->delim); + s8 dir = c.head; if (dir.len) { - append(a, &dirs->list, dir); + append(&dirs->list, dir, perm); } path = c.tail; } } -static void prependpath(Arena *a, Search *dirs, Str path) +static void prependpath(search *dirs, s8 path, arena *perm) { if (!dirs->list.head) { // Empty, so appending is the same a prepending - appendpath(a, dirs, path); + appendpath(dirs, path, perm); } else { // Append to an empty Search, then transplant in front - Search temp = newsearch(dirs->delim); - appendpath(a, &temp, path); - temp.list.tail->next = dirs->list.head; + search temp = newsearch(dirs->delim); + appendpath(&temp, path, perm); + *temp.list.tail = dirs->list.head; dirs->list.head = temp.list.head; } } -static Bool realnameispath(Str realname) +static b32 realnameispath(s8 realname) { - return realname.len>3 && equals(taketail(realname, 3), S(".pc")); + return realname.len>3 && s8equals(taketail(realname, 3), S(".pc")); } -static Str pathtorealname(Str path) +static s8 pathtorealname(s8 path) { if (!realnameispath(path)) { return path; } - Size baselen = 0; - for (Size i = 0; i < path.len; i++) { + size baselen = 0; + for (size i = 0; i < path.len; i++) { if (pathsep(path.s[i])) { baselen = i + 1; } } - Str name = cuthead(path, baselen); + s8 name = cuthead(path, baselen); return cuttail(name, 3); } -static Str readpackage(Arena *a, Out *err, Str path, Str realname) +static s8 readpackage(u8buf *err, s8 path, s8 realname, arena *perm) { - if (equals(realname, S("pkg-config"))) { + if (s8equals(realname, S("pkg-config"))) { return S( "Name: u-config\n" "Version: " VERSION "\n" @@ -961,72 +915,70 @@ static Str readpackage(Arena *a, Out *err, Str path, Str realname) ); } - Str null = {0}; - MapFileResult m = os_mapfile(a, path); + s8 null = {0}; + filemap m = os_mapfile(perm, path); switch (m.status) { - case MapFile_NOTFOUND: + case filemap_NOTFOUND: return null; - case MapFile_READERR: - outstr(err, S("pkg-config: ")); - outstr(err, S("could not read package '")); - outstr(err, realname); - outstr(err, S("' from '")); - outstr(err, path); - outstr(err, S("'\n")); + case filemap_READERR: + prints8(err, S("pkg-config: ")); + prints8(err, S("could not read package '")); + prints8(err, realname); + prints8(err, S("' from '")); + prints8(err, path); + prints8(err, S("'\n")); flush(err); os_fail(); - case MapFile_OK: - return m.contents; + case filemap_OK: + return m.data; } - ASSERT(0); - return null; + assert(0); } -static void expand(Out *out, Out *err, Env *global, Pkg *p, Str str) +static void expand(u8buf *out, u8buf *err, env *global, pkg *p, s8 str) { - int top = 0; - Str stack[128]; + i32 top = 0; + s8 stack[128]; stack[top] = str; while (top >= 0) { - Str s = stack[top--]; - for (Size i = 0; i < s.len-1; i++) { + s8 s = stack[top--]; + for (size i = 0; i < s.len-1; i++) { if (s.s[i]=='$' && s.s[i+1]=='{') { - if (top >= COUNTOF(stack)-2) { - outstr(err, S("pkg-config: ")); - outstr(err, S("exceeded max recursion depth in '")); - outstr(err, p->path); - outstr(err, S("'\n")); + if (top >= countof(stack)-2) { + prints8(err, S("pkg-config: ")); + prints8(err, S("exceeded max recursion depth in '")); + prints8(err, p->path); + prints8(err, S("'\n")); flush(err); os_fail(); } - Str head = {s.s, i}; - outstr(out, head); + prints8(out, takehead(s, i)); - Size beg = i + 2; - Size end = beg; + size beg = i + 2; + size end = beg; for (; endenv, name); + s8 value = lookup(global, p->env, name); if (!value.s) { - outstr(err, S("pkg-config: ")); - outstr(err, S("undefined variable '")); - outstr(err, name); - outstr(err, S("' in '")); - outstr(err, p->path); - outstr(err, S("'\n")); + prints8(err, S("pkg-config: ")); + prints8(err, S("undefined variable '")); + prints8(err, name); + prints8(err, S("' in '")); + prints8(err, p->path); + prints8(err, S("'\n")); flush(err); os_fail(); } @@ -1035,93 +987,93 @@ static void expand(Out *out, Out *err, Env *global, Pkg *p, Str str) break; } else if (s.s[i]=='$' && s.s[i+1]=='$') { - Str head = {s.s, i+1}; - outstr(out, head); - Str tail = {s.s+i+2, s.len-i-2}; - stack[++top] = tail; + s8 head = takehead(s, i+1); + prints8(out, head); + stack[++top] = cuthead(s, i+2); s.len = 0; break; } } - outstr(out, s); + prints8(out, s); } } // Merge and expand data from "update" into "base". -static void expandmerge(Arena *a, Out *err, Env *g, Pkg *base, Pkg *update) +static void expandmerge(u8buf *err, env *g, pkg *base, pkg *update, arena *perm) { base->path = update->path; base->contents = update->contents; base->env = update->env; base->flags = update->flags; - for (int i = 0; i < PKG_NFIELDS; i++) { - Out mem = newmembuf(a); - Str src = *fieldbyid(update, i); + for (i32 i = 0; i < PKG_NFIELDS; i++) { + u8buf mem = newmembuf(perm); + s8 src = *fieldbyid(update, i); expand(&mem, err, g, update, src); *fieldbyid(base, i) = finalize(&mem); } } -static Pkg findpackage(Arena *a, Search *dirs, Out *err, Str realname) +static pkg findpackage(search *dirs, u8buf *err, s8 realname, arena *perm) { - Str path = {0, 0}; - Str contents = {0, 0}; + s8 path = {0}; + s8 contents = {0}; if (realnameispath(realname)) { - path = newstr(a, realname.len+1); - copy(path, realname).s[0] = 0; - contents = readpackage(a, err, path, realname); + path = news8(perm, realname.len+1); + s8copy(path, realname).s[0] = 0; + contents = readpackage(err, path, realname, perm); path = cuttail(path, 1); // remove null terminator if (contents.s) { realname = pathtorealname(path); } } - for (StrListNode *n = dirs->list.head; n && !contents.s; n = n->next) { - path = buildpath(a, n->entry, realname); - contents = readpackage(a, err, path, realname); + for (s8node *n = dirs->list.head; n && !contents.s; n = n->next) { + path = buildpath(n->str, realname, perm); + contents = readpackage(err, path, realname, perm); path = cuttail(path, 1); // remove null terminator } if (!contents.s) { - outstr(err, S("pkg-config: ")); - outstr(err, S("could not find package '")); - outstr(err, realname); - outstr(err, S("'\n")); + prints8(err, S("pkg-config: ")); + prints8(err, S("could not find package '")); + prints8(err, realname); + prints8(err, S("'\n")); flush(err); os_fail(); } - ParseResult r = parsepackage(a, contents); - switch (r.status) { - case Parse_DUPVARABLE: - outstr(err, S("pkg-config: ")); - outstr(err, S("duplicate variable '")); - outstr(err, r.dupname); - outstr(err, S("' in '")); - outstr(err, path); - outstr(err, S("'\n")); + parseresult r = parsepackage(contents, perm); + switch (r.err) { + case parse_DUPVARABLE: + prints8(err, S("pkg-config: ")); + prints8(err, S("duplicate variable '")); + prints8(err, r.dupname); + prints8(err, S("' in '")); + prints8(err, path); + prints8(err, S("'\n")); flush(err); os_fail(); - case Parse_DUPFIELD: - outstr(err, S("pkg-config: ")); - outstr(err, S("duplicate field '")); - outstr(err, r.dupname); - outstr(err, S("' in '")); - outstr(err, path); - outstr(err, S("'\n")); + case parse_DUPFIELD: + prints8(err, S("pkg-config: ")); + prints8(err, S("duplicate field '")); + prints8(err, r.dupname); + prints8(err, S("' in '")); + prints8(err, path); + prints8(err, S("'\n")); flush(err); os_fail(); - case Parse_OK: + case parse_OK: break; } r.pkg.path = path; r.pkg.realname = realname; - *insert(a, &r.pkg.env, S("pcfiledir")) = dirname(path); + s8 pcfiledir = s8pathencode(dirname(path), perm); + *insert(&r.pkg.env, S("pcfiledir"), perm) = pcfiledir; - Str missing = {0, 0}; + s8 missing = {0}; if (!r.pkg.name.s) { missing = S("Name"); } else if (!r.pkg.version.s) { @@ -1130,14 +1082,14 @@ static Pkg findpackage(Arena *a, Search *dirs, Out *err, Str realname) missing = S("Description"); } if (missing.s) { - outstr(err, S("pkg-config: ")); - outstr(err, S("missing field '")); - outstr(err, missing); - outstr(err, S("' in '")); - outstr(err, r.pkg.path); - outstr(err, S("'\n")); + prints8(err, S("pkg-config: ")); + prints8(err, S("missing field '")); + prints8(err, missing); + prints8(err, S("' in '")); + prints8(err, r.pkg.path); + prints8(err, S("'\n")); flush(err); - #ifndef DEBUG + #ifndef FUZZTEST // Do not enforce during fuzzing os_fail(); #endif @@ -1147,17 +1099,18 @@ static Pkg findpackage(Arena *a, Search *dirs, Out *err, Str realname) } typedef struct { - Str arg; - Str tail; - Bool ok; -} DequoteResult; - -static Bool shellmeta(Byte c) -{ - // NOTE: matches pkg-config's listing, which excludes "$()" - Str meta = S("\"!#%&'*<>?[\\]`{|}"); - for (Size i = 0; i < meta.len; i++) { - if (meta.s[i] == c) { + s8 arg; + s8 tail; + b32 ok; +} dequoted; + +// Matches pkg-config's listing, which excludes "$()", but also match +// pathencode()ed bytes for escaping, which handles "$()" in paths. +static b32 shellmeta(u8 c) +{ + s8 meta = S("\"!#%&'*<>?[\\]`{|}"); + for (size i = 0; i < meta.len; i++) { + if (meta.s[i]==c || pathdecode(c)!=c) { return 1; } } @@ -1165,86 +1118,88 @@ static Bool shellmeta(Byte c) } // Process the next token. Return it and the unprocessed remainder. -static DequoteResult dequote(Arena *a, Str s) +static dequoted dequote(s8 s, arena *perm) { - Size i; - Byte quote = 0; - Bool escaped = 0; - Arena save = *a; - Out mem = newmembuf(a); + size i = 0; + u8 quote = 0; + b32 escaped = 0; + dequoted r = {0}; + arena rollback = *perm; + u8buf mem = newmembuf(perm); for (; s.len && whitespace(*s.s); s = cuthead(s, 1)) {} for (i = 0; i < s.len; i++) { - Byte c = s.s[i]; + u8 c = s.s[i]; if (whitespace(c)) { c = ' '; } + u8 decoded = pathdecode(c); if (quote == '\'') { if (c == '\'') { quote = 0; } else if (c==' ' || shellmeta(c)) { - outbyte(&mem, '\\'); - outbyte(&mem, c); + printu8(&mem, '\\'); + printu8(&mem, decoded); } else { - outbyte(&mem, c); + printu8(&mem, decoded); } } else if (quote == '"') { if (escaped) { escaped = 0; if (c!='\\' && c!='"') { - outbyte(&mem, '\\'); + printu8(&mem, '\\'); if (c==' ' || shellmeta(c)) { - outbyte(&mem, '\\'); + printu8(&mem, '\\'); } } - outbyte(&mem, c); + printu8(&mem, decoded); } else if (c == '\"') { quote = 0; } else if (c==' ' || shellmeta(c)) { - outbyte(&mem, '\\'); - outbyte(&mem, c); + printu8(&mem, '\\'); + printu8(&mem, decoded); } else { escaped = c == '\\'; - outbyte(&mem, c); + printu8(&mem, decoded); } } else if (c=='\'' || c=='"') { quote = c; } else if (shellmeta(c)) { - outbyte(&mem, '\\'); - outbyte(&mem, c); + printu8(&mem, '\\'); + printu8(&mem, decoded); } else if (c==' ') { break; } else { - outbyte(&mem, c); + printu8(&mem, c); } } if (quote) { - *a = save; - shredfree(a); - DequoteResult r = {0}; + *perm = rollback; return r; } - DequoteResult r = {finalize(&mem), cuthead(s, i), 1}; + r.arg = finalize(&mem); + r.tail = cuthead(s, i); + r.ok = 1; return r; } // Compare version strings, returning [-1, 0, +1]. Follows the RPM // version comparison specification like the original pkg-config. -static int compareversions(Str va, Str vb) +static i32 compareversions(s8 va, s8 vb) { - Size i = 0; + size i = 0; while (i pb.head.len) { @@ -1283,185 +1238,165 @@ static int compareversions(Str va, Str vb) } typedef enum { - VersionOp_ERR=0, - VersionOp_LT, - VersionOp_LTE, - VersionOp_EQ, - VersionOp_GTE, - VersionOp_GT -} VersionOp; + versop_ERR=0, + versop_LT, + versop_LTE, + versop_EQ, + versop_GTE, + versop_GT +} versop; -static VersionOp parseop(Str s) +static versop parseop(s8 s) { - if (equals(S("<"), s)) { - return VersionOp_LT; - } else if (equals(S("<="), s)) { - return VersionOp_LTE; - } else if (equals(S("="), s)) { - return VersionOp_EQ; - } else if (equals(S(">="), s)) { - return VersionOp_GTE; - } else if (equals(S(">"), s)) { - return VersionOp_GT; + if (s8equals(S("<"), s)) { + return versop_LT; + } else if (s8equals(S("<="), s)) { + return versop_LTE; + } else if (s8equals(S("="), s)) { + return versop_EQ; + } else if (s8equals(S(">="), s)) { + return versop_GTE; + } else if (s8equals(S(">"), s)) { + return versop_GT; } - return VersionOp_ERR; + return versop_ERR; } -static Str opname(VersionOp op) +static s8 opname(versop op) { switch (op) { - case VersionOp_ERR: break; - case VersionOp_LT: return S("<"); - case VersionOp_LTE: return S("<="); - case VersionOp_EQ: return S("="); - case VersionOp_GTE: return S(">="); - case VersionOp_GT: return S(">"); + case versop_ERR: break; + case versop_LT: return S("<"); + case versop_LTE: return S("<="); + case versop_EQ: return S("="); + case versop_GTE: return S(">="); + case versop_GT: return S(">"); } - ASSERT(0); - Str null = {0}; - return null; + assert(0); } -static Bool validcompare(VersionOp op, int result) +static b32 validcompare(versop op, i32 result) { switch (op) { - case VersionOp_ERR: break; - case VersionOp_LT: return result < 0; - case VersionOp_LTE: return result <= 0; - case VersionOp_EQ: return result == 0; - case VersionOp_GTE: return result >= 0; - case VersionOp_GT: return result > 0; - } - ASSERT(0); - return 0; + case versop_ERR: break; + case versop_LT: return result < 0; + case versop_LTE: return result <= 0; + case versop_EQ: return result == 0; + case versop_GTE: return result >= 0; + case versop_GT: return result > 0; + } + assert(0); } typedef struct { - Out *err; - Search search; - Env *global; - Pkgs *pkgs; - Pkg *last; - int maxdepth; - VersionOp op; - Bool define_prefix; - Bool recursive; - Bool ignore_versions; -} Processor; - -static Processor newprocessor(Config *c, Out *err, Env *g, Pkgs *pkgs) -{ - Arena *a = &c->arena; - Processor proc = {0}; - proc.err = err; - proc.search = newsearch(c->delim); - appendpath(a, &proc.search, c->envpath); - appendpath(a, &proc.search, c->fixedpath); - proc.global = g; - proc.pkgs = pkgs; - proc.maxdepth = (unsigned)-1 >> 1; - proc.define_prefix = 1; - proc.recursive = 1; + s8 arg; + pkg *last; + i32 depth; + i32 flags; + versop op; +} procstate; + +typedef struct { + u8buf *err; + search search; + env **global; + pkgs *pkgs; + pkg *last; + i32 maxdepth; + versop op; + b32 define_prefix; + b32 recursive; + b32 ignore_versions; + procstate stack[256]; +} processor; + +static processor *newprocessor(config *c, u8buf *err, env **g, pkgs *pkgs) +{ + arena *perm = &c->perm; + processor *proc = new(perm, processor, 1); + proc->err = err; + proc->search = newsearch(c->delim); + appendpath(&proc->search, c->envpath, perm); + appendpath(&proc->search, c->fixedpath, perm); + proc->global = g; + proc->pkgs = pkgs; + proc->maxdepth = (u32)-1 >> 1; + proc->define_prefix = 1; + proc->recursive = 1; return proc; } -static void procfail(Out *err, VersionOp op, Pkg *p) +static void procfail(u8buf *err, versop op, pkg *p) { - outstr(err, S("pkg-config: ")); - outstr(err, S("expected version following operator ")); - outstr(err, opname(op)); + prints8(err, S("pkg-config: ")); + prints8(err, S("expected version following operator ")); + prints8(err, opname(op)); if (p) { - outstr(err, S(" in package '")); - outstr(err, p->realname); - outstr(err, S("'")); + prints8(err, S(" in package '")); + prints8(err, p->realname); + prints8(err, S("'")); } - outstr(err, S("\n")); + prints8(err, S("\n")); flush(err); os_fail(); } -// Wrap the string in quotes if it contains whitespace. -static Str maybequote(Arena *a, Str s) +static void setprefix(pkg *p, arena *perm) { - for (Size i = 0; i < s.len; i++) { - if (whitespace(s.s[i])) { - Str r = newstr(a, s.len + 2); - Str t = copy(r, S("\"")); - t = copy(t, s); - copy(t, S("\"")); - return r; - } + s8 parent = dirname(p->path); + if (s8equals(S("pkgconfig"), basename(parent))) { + s8 prefix = dirname(dirname(parent)); + prefix = s8pathencode(prefix, perm); + *insert(&p->env, S("prefix"), perm) = prefix; } - return s; } -static void setprefix(Arena *a, Pkg *p) +static void failmaxrecurse(u8buf *err, s8 tok) { - Str parent = dirname(p->path); - if (equals(S("pkgconfig"), basename(parent))) { - Str prefix = dirname(dirname(parent)); - prefix = maybequote(a, prefix); - *insert(a, &p->env, S("prefix")) = prefix; - } -} - -typedef struct { - Str arg; - Pkg *last; - short depth; - short flags; - VersionOp op; -} ProcState; - -static void failmaxrecurse(Out *err, Str tok) -{ - outstr(err, S("pkg-config: ")); - outstr(err, S("exceeded max recursion depth on '")); - outstr(err, tok); - outstr(err, S("'\n")); + prints8(err, S("pkg-config: ")); + prints8(err, S("exceeded max recursion depth on '")); + prints8(err, tok); + prints8(err, S("'\n")); flush(err); os_fail(); } -static void failversion(Out *err, Pkg *pkg, VersionOp op, Str want) +static void failversion(u8buf *err, pkg *pkg, versop op, s8 want) { - outstr(err, S("pkg-config: ")); - outstr(err, S("requested '")); - outstr(err, pkg->realname); - outstr(err, S("' ")); - outstr(err, opname(op)); - outstr(err, S(" '")); - outstr(err, want); - outstr(err, S("' but got '")); - outstr(err, pkg->version); - outstr(err, S("'\n")); + prints8(err, S("pkg-config: ")); + prints8(err, S("requested '")); + prints8(err, pkg->realname); + prints8(err, S("' ")); + prints8(err, opname(op)); + prints8(err, S(" '")); + prints8(err, want); + prints8(err, S("' but got '")); + prints8(err, pkg->version); + prints8(err, S("'\n")); flush(err); os_fail(); } -static void process(Arena *a, Processor *proc, Str arg) +static void process(processor *proc, s8 arg, arena *perm) { - Out *err = proc->err; - Pkgs *pkgs = proc->pkgs; - Env *global = proc->global; - Search *search = &proc->search; + u8buf *err = proc->err; + pkgs *pkgs = proc->pkgs; + env **global = proc->global; + search *search = &proc->search; - // NOTE: At >=128, GCC generates a __chkstk_ms on x86-64 because the - // stack frame exceeds 4kB. A -mno-stack-arg-probe solves this, but - // limiting the recursion depth to 64, which is still plenty, avoids - // the issue entirely. - ProcState stack[64]; - int top = 0; + procstate *stack = proc->stack; + i32 cap = countof(proc->stack); + i32 top = 0; stack[0].arg = arg; stack[0].last = proc->last; stack[0].depth = 0; - stack[0].flags = Pkg_DIRECT | Pkg_PUBLIC; + stack[0].flags = pkg_DIRECT | pkg_PUBLIC; stack[0].op = proc->op; while (top >= 0) { - ProcState *s = stack + top; - StrPair pair = nexttoken(s->arg); - Str tok = pair.head; + procstate *s = stack + top; + s8pair pair = nexttoken(s->arg); + s8 tok = pair.head; if (!tok.len) { if (top>0 && s->op) { procfail(err, s->op, s->last); @@ -1473,83 +1408,83 @@ static void process(Arena *a, Processor *proc, Str arg) if (s->op) { if (!proc->ignore_versions) { - int cmp = compareversions(s->last->version, tok); + i32 cmp = compareversions(s->last->version, tok); if (!validcompare(s->op, cmp)) { failversion(err, s->last, s->op, tok); } } s->last = 0; - s->op = VersionOp_ERR; + s->op = versop_ERR; continue; } s->op = parseop(tok); if (s->op) { if (!s->last) { - outstr(err, S("pkg-config: ")); - outstr(err, S("unexpected operator '")); - outstr(err, tok); - outstr(err, S("'\n")); + prints8(err, S("pkg-config: ")); + prints8(err, S("unexpected operator '")); + prints8(err, tok); + prints8(err, S("'\n")); flush(err); os_fail(); } continue; } - short depth = s->depth + 1; - short flags = s->flags; - Pkg *pkg = s->last = locate(a, pkgs, pathtorealname(tok)); - if (pkg->contents.s) { - if (flags&Pkg_PUBLIC && !(pkg->flags & Pkg_PUBLIC)) { + i32 depth = s->depth + 1; + i32 flags = s->flags; + pkg *p = s->last = locate(pkgs, pathtorealname(tok), perm); + if (p->contents.s) { + if (flags&pkg_PUBLIC && !(p->flags & pkg_PUBLIC)) { // We're on a public branch, but this package was // previously loaded as private. Recursively traverse // its public requires and mark all as public. - pkg->flags |= Pkg_PUBLIC; + p->flags |= pkg_PUBLIC; if (proc->recursive && depthmaxdepth) { - if (top >= COUNTOF(stack)-1) { + if (top >= cap-1) { failmaxrecurse(err, tok); } top++; - stack[top].arg = pkg->requires; + stack[top].arg = p->requires; stack[top].last = 0; stack[top].depth = depth; - stack[top].flags = flags & ~Pkg_DIRECT; - stack[top].op = VersionOp_ERR; + stack[top].flags = flags & ~pkg_DIRECT; + stack[top].op = versop_ERR; } } } else { // Package hasn't been loaded yet, so find and load it. - Pkg newpkg = findpackage(a, search, err, tok); + pkg newpkg = findpackage(search, err, tok, perm); if (proc->define_prefix) { - setprefix(a, &newpkg); + setprefix(&newpkg, perm); } - expandmerge(a, err, global, pkg, &newpkg); + expandmerge(err, *global, p, &newpkg, perm); if (proc->recursive && depthmaxdepth) { - if (top >= COUNTOF(stack)-2) { + if (top >= cap-2) { failmaxrecurse(err, tok); } top++; - stack[top].arg = pkg->requiresprivate; + stack[top].arg = p->requiresprivate; stack[top].last = 0; stack[top].depth = depth; stack[top].flags = 0; - stack[top].op = VersionOp_ERR; + stack[top].op = versop_ERR; top++; - stack[top].arg = pkg->requires; + stack[top].arg = p->requires; stack[top].last = 0; stack[top].depth = depth; - stack[top].flags = flags & ~Pkg_DIRECT; - stack[top].op = VersionOp_ERR; + stack[top].flags = flags & ~pkg_DIRECT; + stack[top].op = versop_ERR; } } - pkg->flags |= flags; + p->flags |= flags; } proc->last = stack[0].last; proc->op = stack[0].op; } -static void endprocessor(Processor *proc, Out *err) +static void endprocessor(processor *proc, u8buf *err) { if (proc->op) { procfail(err, proc->op, 0); @@ -1557,78 +1492,95 @@ static void endprocessor(Processor *proc, Out *err) } typedef enum { - Filter_ANY, - Filter_I, - Filter_L, - Filter_l, - Filter_OTHERC, - Filter_OTHERL -} Filter; + filter_ANY, + filter_I, + filter_L, + filter_l, + filter_OTHERC, + filter_OTHERL +} filter; -static Bool filterok(Filter f, Str arg) +static b32 filterok(filter f, s8 arg) { switch (f) { - case Filter_ANY: + case filter_ANY: return 1; - case Filter_I: + case filter_I: return startswith(arg, S("-I")); - case Filter_L: + case filter_L: return startswith(arg, S("-L")); - case Filter_l: + case filter_l: return startswith(arg, S("-l")); - case Filter_OTHERC: + case filter_OTHERC: return !startswith(arg, S("-I")); - case Filter_OTHERL: + case filter_OTHERL: return !startswith(arg, S("-L")) && !startswith(arg, S("-l")); } - ASSERT(0); - return 0; + assert(0); } -static void msvcize(Out *out, Str arg) +static void msvcize(u8buf *out, s8 arg) { if (startswith(arg, S("-L"))) { - outstr(out, S("/libpath:")); - outstr(out, cuthead(arg, 2)); + prints8(out, S("/libpath:")); + prints8(out, cuthead(arg, 2)); } else if (startswith(arg, S("-I"))) { - outstr(out, S("/I")); - outstr(out, cuthead(arg, 2)); + prints8(out, S("/I")); + prints8(out, cuthead(arg, 2)); } else if (startswith(arg, S("-l"))) { - outstr(out, cuthead(arg, 2)); - outstr(out, S(".lib")); + prints8(out, cuthead(arg, 2)); + prints8(out, S(".lib")); } else if (startswith(arg, S("-D"))) { - outstr(out, S("/D")); - outstr(out, cuthead(arg, 2)); - } else if (equals(arg, S("-mwindows"))) { - outstr(out, S("/subsystem:windows")); - } else if (equals(arg, S("-mconsole"))) { - outstr(out, S("/subsystem:console")); + prints8(out, S("/D")); + prints8(out, cuthead(arg, 2)); + } else if (s8equals(arg, S("-mwindows"))) { + prints8(out, S("/subsystem:windows")); + } else if (s8equals(arg, S("-mconsole"))) { + prints8(out, S("/subsystem:console")); } else { - outstr(out, arg); + prints8(out, arg); } } -typedef struct { - Treap node; - Size position; -} ArgsNode; +typedef struct argpos argpos; +struct argpos { + argpos *child[4]; + argpos *next; + s8 arg; + size position; +}; typedef struct { - StrList list; - Treap *map; - Size count; -} Args; + s8list list; + argpos *positions; + size count; +} args; -static Bool dedupable(Str arg) +static argpos *findargpos(argpos **m, s8 arg, arena *perm) +{ + for (u32 h = s8hash(arg); *m; h <<= 2) { + if (s8equals((*m)->arg, arg)) { + return *m; + } + m = &(*m)->child[h>>30]; + } + if (perm) { + *m = new(perm, argpos, 1); + (*m)->arg = arg; + } + return *m; +} + +static b32 dedupable(s8 arg) { // Do not count "-I" or "-L" with detached argument if (arg.len<3 || arg.s[0]!='-') { return 0; - } else if (equals(arg, S("-pthread"))) { + } else if (s8equals(arg, S("-pthread"))) { return 1; } - Str flags = S("DILflm"); - for (Size i = 0; i < flags.len; i++) { + s8 flags = S("DILflm"); + for (size i = 0; i < flags.len; i++) { if (arg.s[1] == flags.s[i]) { return 1; } @@ -1636,12 +1588,12 @@ static Bool dedupable(Str arg) return 0; } -static void appendarg(Arena *a, Args *args, Str arg) +static void appendarg(args *args, s8 arg, arena *perm) { - Size position = args->count++; - append(a, &args->list, arg); + append(&args->list, arg, perm); + size position = args->count++; if (dedupable(arg)) { - ArgsNode *n = (ArgsNode *)treapinsert(a, &args->map, arg, SIZEOF(*n)); + argpos *n = findargpos(&args->positions, arg, perm); if (!n->position || startswith(arg, S("-l"))) { // Zero position reserved for null, so bias it by 1 n->position = 1 + position; @@ -1649,58 +1601,61 @@ static void appendarg(Arena *a, Args *args, Str arg) } } -static void excludearg(Arena *a, Args *args, Str arg) +static void excludearg(args *args, s8 arg, arena *perm) { - ArgsNode *n = (ArgsNode *)treapinsert(a, &args->map, arg, SIZEOF(*n)); + argpos *n = findargpos(&args->positions, arg, perm); n->position = -1; // i.e. position before first argument } // Is this the correct position for the given argument? -static Bool inposition(Args *args, Str arg, Size position) +static b32 inposition(args *args, s8 arg, size position) { - ArgsNode *n = (ArgsNode *)treapinsert(0, &args->map, arg, SIZEOF(*n)); + argpos *n = findargpos(&args->positions, arg, 0); return !n || n->position==position+1; } typedef struct { - Arena *arena; - Size *argcount; - Args args; - Filter filter; - Bool msvc; - Byte delim; -} FieldWriter; - -static FieldWriter newfieldwriter(Arena *a, Filter filter, Size *argcount) -{ - FieldWriter w = {0}; - w.arena = a; - w.filter = filter; + arena *perm; + size *argcount; + args args; + filter filter; + b32 msvc; + u8 delim; +} fieldwriter; + +static fieldwriter newfieldwriter(filter f, size *argcount, arena *perm) +{ + fieldwriter w = {0}; + w.perm = perm; + w.filter = f; w.argcount = argcount; return w; } -static void insertsyspath(FieldWriter *w, Str path, Byte delim, Byte flag) +static void insertsyspath(fieldwriter *w, s8 path, u8 delim, u8 flag) { - Arena *a = w->arena; - Byte flagbuf[] = {'-', flag}; - Str prefix = {flagbuf, SIZEOF(flagbuf)}; + arena *perm = w->perm; + + u8 flagbuf[3] = {0}; + flagbuf[0] = '-'; + flagbuf[1] = flag; + s8 prefix = S(flagbuf); while (path.len) { - Cut c = cut(path, delim); - Str dir = c.head; + cut c = s8cut(path, delim); + s8 dir = c.head; path = c.tail; if (!dir.len) { continue; } // Prepend option flag - Str syspath = newstr(a, prefix.len+dir.len); - copy(copy(syspath, prefix), dir); + dir = s8pathencode(dir, perm); + s8 syspath = news8(perm, prefix.len+dir.len); + s8copy(s8copy(syspath, prefix), dir); // Process as an argument, as though being printed - syspath = maybequote(a, syspath); - DequoteResult dr = dequote(a, syspath); + dequoted dr = dequote(syspath, perm); syspath = dr.arg; // NOTE(NRK): Technically, the path doesn't need to follow the flag @@ -1712,56 +1667,56 @@ static void insertsyspath(FieldWriter *w, Str path, Byte delim, Byte flag) // practice, `pkgconf` which is used by many distros, also doesn't // handle it. if (dr.ok && !dr.tail.len) { - excludearg(a, &w->args, syspath); + excludearg(&w->args, syspath, perm); } } } -static void appendfield(Out *err, FieldWriter *w, Pkg *p, Str field) +static void appendfield(u8buf *err, fieldwriter *w, pkg *p, s8 field) { - Arena *a = w->arena; - Filter f = w->filter; + arena *perm = w->perm; + filter f = w->filter; while (field.len) { - DequoteResult r = dequote(a, field); + dequoted r = dequote(field, perm); if (!r.ok) { - outstr(err, S("pkg-config: ")); - outstr(err, S("unmatched quote in '")); - outstr(err, p->realname); - outstr(err, S("'\n")); + prints8(err, S("pkg-config: ")); + prints8(err, S("unmatched quote in '")); + prints8(err, p->realname); + prints8(err, S("'\n")); flush(err); os_fail(); } if (filterok(f, r.arg)) { - appendarg(a, &w->args, r.arg); + appendarg(&w->args, r.arg, perm); } field = r.tail; } } -static void writeargs(Out *out, FieldWriter *w) +static void writeargs(u8buf *out, fieldwriter *w) { - Size position = 0; - Byte delim = w->delim ? w->delim : ' '; - for (StrListNode *n = w->args.list.head; n; n = n->next) { - Str arg = n->entry; + size position = 0; + u8 delim = w->delim ? w->delim : ' '; + for (s8node *n = w->args.list.head; n; n = n->next) { + s8 arg = n->str; if (inposition(&w->args, arg, position++)) { if ((*w->argcount)++) { - outbyte(out, delim); + printu8(out, delim); } if (w->msvc) { msvcize(out, arg); } else { - outstr(out, arg); + prints8(out, arg); } } } } -static int parseuint(Str s, int hi) +static i32 parseuint(s8 s, i32 hi) { - int v = 0; - for (Size i = 0; i < s.len; i++) { - Byte c = s.s[i]; + i32 v = 0; + for (size i = 0; i < s.len; i++) { + u8 c = s.s[i]; if (digit(c)) { v = v*10 + c - '0'; if (v >= hi) { @@ -1772,50 +1727,52 @@ static int parseuint(Str s, int hi) return v; } -static void appmain(Config conf) -{ - Arena *a = &conf.arena; - shredfree(a); - - Env global = {0}; - Filter filterc = Filter_ANY; - Filter filterl = Filter_ANY; - Pkgs pkgs = {0}; - Out out = newoutput(a, 1, 1<<12); - Out err = newoutput(a, 2, 1<<7); - Processor proc = newprocessor(&conf, &err, &global, &pkgs); - Size argcount = 0; - - Bool msvc = 0; - Bool libs = 0; - Bool cflags = 0; - Bool err_to_stdout = 0; - Bool silent = 0; - Bool static_ = 0; - Byte argdelim = ' '; - Bool modversion = 0; - VersionOp override_op = VersionOp_ERR; - Str override_version = {0, 0}; - Bool print_sysinc = 0; - Bool print_syslib = 0; - Str variable = {0, 0}; - - proc.define_prefix = conf.define_prefix; - if (!conf.top_builddir.s) { - conf.top_builddir = S("$(top_builddir)"); - } - - *insert(a, &global, S("pc_path")) = conf.fixedpath; - *insert(a, &global, S("pc_system_includedirs")) = conf.sys_incpath; - *insert(a, &global, S("pc_system_libdirs")) = conf.sys_libpath; - *insert(a, &global, S("pc_sysrootdir")) = S("/"); - *insert(a, &global, S("pc_top_builddir")) = conf.top_builddir; - - Str *args = (Str *)allocarray(a, SIZEOF(Str), conf.nargs); - Size nargs = 0; - - for (OptionParser opts = newoptionparser(conf.args, conf.nargs);;) { - OptionResult r = nextoption(&opts); +static void uconfig(config *conf) +{ + arena *perm = &conf->perm; + + env *global = 0; + filter filterc = filter_ANY; + filter filterl = filter_ANY; + pkgs *pkgs = newpkgs(perm); + u8buf *out = newfdbuf(perm, 1, 1<<12); + u8buf *err = newfdbuf(perm, 2, 1<<7); + processor *proc = newprocessor(conf, err, &global, pkgs); + size argcount = 0; + + b32 msvc = 0; + b32 libs = 0; + b32 cflags = 0; + b32 err_to_stdout = 0; + b32 silent = 0; + b32 static_ = 0; + u8 argdelim = ' '; + b32 modversion = 0; + versop override_op = versop_ERR; + s8 override_version = {0}; + b32 print_sysinc = !!conf->print_sysinc.s; + b32 print_syslib = !!conf->print_syslib.s; + s8 variable = {0}; + + proc->define_prefix = conf->define_prefix; + s8 top_builddir = conf->top_builddir; + if (top_builddir.s) { + top_builddir = s8pathencode(top_builddir, perm); + } else { + top_builddir = S("$(top_builddir)"); + } + + *insert(&global, S("pc_path"), perm) = conf->fixedpath; + *insert(&global, S("pc_system_includedirs"), perm) = conf->sys_incpath; + *insert(&global, S("pc_system_libdirs"), perm) = conf->sys_libpath; + *insert(&global, S("pc_sysrootdir"), perm) = S("/"); + *insert(&global, S("pc_top_builddir"), perm) = top_builddir; + + s8 *args = new(perm, s8, conf->nargs); + size nargs = 0; + + for (options opts = newoptions(conf->args, conf->nargs);;) { + optresult r = nextoption(&opts); if (!r.ok) { break; } @@ -1823,167 +1780,167 @@ static void appmain(Config conf) if (!r.isoption) { args[nargs++] = r.arg; - } else if (equals(r.arg, S("h")) || equals(r.arg, S("-help"))) { - usage(&out); - flush(&out); + } else if (s8equals(r.arg, S("h")) || s8equals(r.arg, S("-help"))) { + usage(out); + flush(out); return; - } else if (equals(r.arg, S("-version"))) { - outstr(&out, S(VERSION)); - outbyte(&out, '\n'); - flush(&out); + } else if (s8equals(r.arg, S("-version"))) { + prints8(out, S(VERSION)); + printu8(out, '\n'); + flush(out); return; - } else if (equals(r.arg, S("-modversion"))) { + } else if (s8equals(r.arg, S("-modversion"))) { modversion = 1; - } else if (equals(r.arg, S("-define-prefix"))) { - proc.define_prefix = 1; + } else if (s8equals(r.arg, S("-define-prefix"))) { + proc->define_prefix = 1; - } else if (equals(r.arg, S("-dont-define-prefix"))) { - proc.define_prefix = 0; + } else if (s8equals(r.arg, S("-dont-define-prefix"))) { + proc->define_prefix = 0; - } else if (equals(r.arg, S("-cflags"))) { + } else if (s8equals(r.arg, S("-cflags"))) { cflags = 1; - filterc = Filter_ANY; + filterc = filter_ANY; - } else if (equals(r.arg, S("-libs"))) { + } else if (s8equals(r.arg, S("-libs"))) { libs = 1; - filterl = Filter_ANY; + filterl = filter_ANY; - } else if (equals(r.arg, S("-variable"))) { + } else if (s8equals(r.arg, S("-variable"))) { if (!r.value.s) { - r.value = getargopt(&err, &opts, r.arg); + r.value = getargopt(err, &opts, r.arg); } variable = r.value; - } else if (equals(r.arg, S("-static"))) { + } else if (s8equals(r.arg, S("-static"))) { static_ = 1; - } else if (equals(r.arg, S("-libs-only-L"))) { + } else if (s8equals(r.arg, S("-libs-only-L"))) { libs = 1; - filterl = Filter_L; + filterl = filter_L; - } else if (equals(r.arg, S("-libs-only-l"))) { + } else if (s8equals(r.arg, S("-libs-only-l"))) { libs = 1; - filterl = Filter_l; + filterl = filter_l; - } else if (equals(r.arg, S("-libs-only-other"))) { + } else if (s8equals(r.arg, S("-libs-only-other"))) { libs = 1; - filterl = Filter_OTHERL; + filterl = filter_OTHERL; - } else if (equals(r.arg, S("-cflags-only-I"))) { + } else if (s8equals(r.arg, S("-cflags-only-I"))) { cflags = 1; - filterc = Filter_I; + filterc = filter_I; - } else if (equals(r.arg, S("-cflags-only-other"))) { + } else if (s8equals(r.arg, S("-cflags-only-other"))) { cflags = 1; - filterc = Filter_OTHERC; + filterc = filter_OTHERC; - } else if (equals(r.arg, S("-with-path"))) { + } else if (s8equals(r.arg, S("-with-path"))) { if (!r.value.s) { - r.value = getargopt(&err, &opts, r.arg); + r.value = getargopt(err, &opts, r.arg); } - prependpath(a, &proc.search, r.value); + prependpath(&proc->search, r.value, perm); - } else if (equals(r.arg, S("-maximum-traverse-depth"))) { + } else if (s8equals(r.arg, S("-maximum-traverse-depth"))) { if (!r.value.s) { - r.value = getargopt(&err, &opts, r.arg); + r.value = getargopt(err, &opts, r.arg); } - proc.maxdepth = parseuint(r.value, 1000); + proc->maxdepth = parseuint(r.value, 1000); - } else if (equals(r.arg, S("-msvc-syntax"))) { + } else if (s8equals(r.arg, S("-msvc-syntax"))) { msvc = 1; - } else if (equals(r.arg, S("-define-variable"))) { + } else if (s8equals(r.arg, S("-define-variable"))) { if (!r.value.s) { - r.value = getargopt(&err, &opts, r.arg); + r.value = getargopt(err, &opts, r.arg); } - Cut c = cut(r.value, '='); + cut c = s8cut(r.value, '='); if (!c.ok) { - outstr(&err, S("pkg-config: ")); - outstr(&err, S("value missing in --define-variable for '")); - outstr(&err, r.value); - outstr(&err, S("'\n")); - flush(&err); + prints8(err, S("pkg-config: ")); + prints8(err, S("value missing in --define-variable for '")); + prints8(err, r.value); + prints8(err, S("'\n")); + flush(err); os_fail(); } - *insert(a, &global, c.head) = c.tail; + *insert(&global, c.head, perm) = c.tail; - } else if (equals(r.arg, S("-newlines"))) { + } else if (s8equals(r.arg, S("-newlines"))) { argdelim = '\n'; - } else if (equals(r.arg, S("-exists"))) { + } else if (s8equals(r.arg, S("-exists"))) { // The check already happens, just disable the messages silent = 1; - } else if (equals(r.arg, S("-atleast-pkgconfig-version"))) { + } else if (s8equals(r.arg, S("-atleast-pkgconfig-version"))) { if (!r.value.s) { - r.value = getargopt(&err, &opts, r.arg); + r.value = getargopt(err, &opts, r.arg); } return; // always succeeds - } else if (equals(r.arg, S("-atleast-version"))) { + } else if (s8equals(r.arg, S("-atleast-version"))) { if (!r.value.s) { - r.value = getargopt(&err, &opts, r.arg); + r.value = getargopt(err, &opts, r.arg); } - override_op = VersionOp_GTE; + override_op = versop_GTE; override_version = r.value; silent = 1; - proc.recursive = 0; - proc.ignore_versions = 1; + proc->recursive = 0; + proc->ignore_versions = 1; - } else if (equals(r.arg, S("-exact-version"))) { + } else if (s8equals(r.arg, S("-exact-version"))) { if (!r.value.s) { - r.value = getargopt(&err, &opts, r.arg); + r.value = getargopt(err, &opts, r.arg); } - override_op = VersionOp_EQ; + override_op = versop_EQ; override_version = r.value; silent = 1; - proc.recursive = 0; - proc.ignore_versions = 1; + proc->recursive = 0; + proc->ignore_versions = 1; - } else if (equals(r.arg, S("-max-version"))) { + } else if (s8equals(r.arg, S("-max-version"))) { if (!r.value.s) { - r.value = getargopt(&err, &opts, r.arg); + r.value = getargopt(err, &opts, r.arg); } - override_op = VersionOp_LTE; + override_op = versop_LTE; override_version = r.value; silent = 1; - proc.recursive = 0; - proc.ignore_versions = 1; + proc->recursive = 0; + proc->ignore_versions = 1; - } else if (equals(r.arg, S("-silence-errors"))) { + } else if (s8equals(r.arg, S("-silence-errors"))) { silent = 1; - } else if (equals(r.arg, S("-errors-to-stdout"))) { + } else if (s8equals(r.arg, S("-errors-to-stdout"))) { err_to_stdout = 1; - } else if (equals(r.arg, S("-print-errors"))) { + } else if (s8equals(r.arg, S("-print-errors"))) { // Ignore - } else if (equals(r.arg, S("-short-errors"))) { + } else if (s8equals(r.arg, S("-short-errors"))) { // Ignore - } else if (equals(r.arg, S("-uninstalled"))) { + } else if (s8equals(r.arg, S("-uninstalled"))) { // Ignore - } else if (equals(r.arg, S("-keep-system-cflags"))) { + } else if (s8equals(r.arg, S("-keep-system-cflags"))) { print_sysinc = 1; - } else if (equals(r.arg, S("-keep-system-libs"))) { + } else if (s8equals(r.arg, S("-keep-system-libs"))) { print_syslib = 1; - } else if (equals(r.arg, S("-validate"))) { + } else if (s8equals(r.arg, S("-validate"))) { silent = 1; - proc.recursive = 0; + proc->recursive = 0; } else { - outstr(&err, S("pkg-config: ")); - outstr(&err, S("unknown option -")); - outstr(&err, r.arg); - outstr(&err, S("\n")); - flush(&err); + prints8(err, S("pkg-config: ")); + prints8(err, S("unknown option -")); + prints8(err, r.arg); + prints8(err, S("\n")); + flush(err); os_fail(); } } @@ -1993,94 +1950,135 @@ static void appmain(Config conf) } if (silent) { - err = newnullout(); + err = newnullout(perm); } - for (Size i = 0; i < nargs; i++) { - process(a, &proc, args[i]); + for (size i = 0; i < nargs; i++) { + process(proc, args[i], perm); } - endprocessor(&proc, &err); + endprocessor(proc, err); - if (!pkgs.count) { - outstr(&err, S("pkg-config: ")); - outstr(&err, S("requires at least one package name\n")); - flush(&err); + if (!pkgs->count) { + prints8(err, S("pkg-config: ")); + prints8(err, S("requires at least one package name\n")); + flush(err); os_fail(); } // --{atleast,exact,max}-version if (override_op) { - for (Pkg *p = pkgs.head; p; p = p->list) { - int cmp = compareversions(p->version, override_version); + for (pkg *p = pkgs->head; p; p = p->list) { + i32 cmp = compareversions(p->version, override_version); if (!validcompare(override_op, cmp)) { - failversion(&err, p, override_op, override_version); + failversion(err, p, override_op, override_version); } } } if (modversion) { - for (Pkg *p = pkgs.head; p; p = p->list) { - if (p->flags & Pkg_DIRECT) { - outstr(&out, p->version); - outstr(&out, S("\n")); + for (pkg *p = pkgs->head; p; p = p->list) { + if (p->flags & pkg_DIRECT) { + prints8(out, p->version); + prints8(out, S("\n")); } } } if (variable.s) { - for (Pkg *p = pkgs.head; p; p = p->list) { - if (p->flags & Pkg_DIRECT) { - Str value = lookup(&global, &p->env, variable); + for (pkg *p = pkgs->head; p; p = p->list) { + if (p->flags & pkg_DIRECT) { + s8 value = lookup(global, p->env, variable); if (value.s) { - expand(&out, &err, &global, p, value); - outstr(&out, S("\n")); + expand(out, err, global, p, value); + prints8(out, S("\n")); } } } } if (cflags) { - Arena temp = *a; // auto-free when done - FieldWriter fw = newfieldwriter(&temp, filterc, &argcount); + arena scratch = *perm; + fieldwriter fw = newfieldwriter(filterc, &argcount, &scratch); fw.delim = argdelim; fw.msvc = msvc; if (!print_sysinc) { - insertsyspath(&fw, conf.sys_incpath, conf.delim, 'I'); + insertsyspath(&fw, conf->sys_incpath, conf->delim, 'I'); } - for (Pkg *p = pkgs.head; p; p = p->list) { - appendfield(&err, &fw, p, p->cflags); + for (pkg *p = pkgs->head; p; p = p->list) { + appendfield(err, &fw, p, p->cflags); } - writeargs(&out, &fw); + writeargs(out, &fw); } if (libs) { - Arena temp = *a; // auto-free when done - FieldWriter fw = newfieldwriter(&temp, filterl, &argcount); + arena scratch = *perm; + fieldwriter fw = newfieldwriter(filterl, &argcount, &scratch); fw.delim = argdelim; fw.msvc = msvc; if (!print_syslib) { - insertsyspath(&fw, conf.sys_libpath, conf.delim, 'L'); + insertsyspath(&fw, conf->sys_libpath, conf->delim, 'L'); } - for (Pkg *p = pkgs.head; p; p = p->list) { + for (pkg *p = pkgs->head; p; p = p->list) { if (static_) { - appendfield(&err, &fw, p, p->libs); - appendfield(&err, &fw, p, p->libsprivate); - } else if (p->flags & Pkg_PUBLIC) { - appendfield(&err, &fw, p, p->libs); + appendfield(err, &fw, p, p->libs); + appendfield(err, &fw, p, p->libsprivate); + } else if (p->flags & pkg_PUBLIC) { + appendfield(err, &fw, p, p->libs); } } - writeargs(&out, &fw); + writeargs(out, &fw); } if (cflags || libs) { - outstr(&out, S("\n")); + prints8(out, S("\n")); } - flush(&out); + flush(out); } +// Win32 types, constants, and declarations (replaces windows.h) +// This is free and unencumbered software released into the public domain. + +typedef __SIZE_TYPE__ uptr; +typedef unsigned short char16_t; +typedef char16_t c16; + +enum { + FILE_ATTRIBUTE_NORMAL = 0x80, + + FILE_SHARE_ALL = 7, + + GENERIC_READ = 0x80000000, + + INVALID_HANDLE_VALUE = -1, + + MEM_COMMIT = 0x1000, + MEM_RESERVE = 0x2000, + + OPEN_EXISTING = 3, + + PAGE_READWRITE = 4, + + STD_OUTPUT_HANDLE = -11, + STD_ERROR_HANDLE = -12, +}; + +#define W32(r) __declspec(dllimport) r __stdcall +W32(b32) CloseHandle(uptr); +W32(i32) CreateFileW(c16 *, i32, i32, uptr, i32, i32, i32); +W32(void) ExitProcess(i32); +W32(c16 *) GetCommandLineW(void); +W32(b32) GetConsoleMode(uptr, i32 *); +W32(i32) GetEnvironmentVariableW(c16 *, c16 *, i32); +W32(i32) GetModuleFileNameW(uptr, c16 *, i32); +W32(i32) GetStdHandle(i32); +W32(b32) ReadFile(uptr, u8 *, i32, i32 *, uptr); +W32(byte *) VirtualAlloc(uptr, size, i32, i32); +W32(b32) WriteConsoleW(uptr, c16 *, i32, i32 *, uptr); +W32(b32) WriteFile(uptr, u8 *, i32, i32 *, uptr); + #define CMDLINE_CMD_MAX 32767 // max command line length on Windows -#define CMDLINE_ARGV_MAX (16384+(98298+(int)sizeof(char*))/(int)sizeof(char*)) +#define CMDLINE_ARGV_MAX (16384+(98298+(i32)sizeof(u8 *))/(i32)sizeof(u8 *)) // Convert an ill-formed-UTF-16 command line to a WTF-8 argv following // field splitting semantics identical to CommandLineToArgvW, including @@ -2098,17 +2096,17 @@ static void appmain(Config conf) // test if cmd[0] is zero and then act accordingly. // // If the input is UTF-16, then the output is UTF-8. -static int cmdline_to_argv8(unsigned short *cmd, char **argv) +static i32 cmdline_to_argv8(c16 *cmd, u8 **argv) { - int argc = 1; // worst case: argv[0] is an empty string - int state = 6; // special argv[0] state - int slash = 0; + i32 argc = 1; // worst case: argv[0] is an empty string + i32 state = 6; // special argv[0] state + i32 slash = 0; // Use second half as byte buffer - unsigned char *buf = (unsigned char *)(argv + 16384); + u8 *buf = (u8 *)(argv + 16384); - argv[0] = (char *)buf; + argv[0] = buf; while (*cmd) { - int c = *cmd++; + i32 c = *cmd++; if (c>>10 == 0x36 && *cmd>>10 == 0x37) { // surrogates? c = 0x10000 + ((c - 0xd800)<<10) + (*cmd++ - 0xdc00); } @@ -2117,14 +2115,14 @@ static int cmdline_to_argv8(unsigned short *cmd, char **argv) case 0: switch (c) { // outside token case 0x09: case 0x20: continue; - case 0x22: argv[argc++] = (char *)buf; + case 0x22: argv[argc++] = buf; state = 2; continue; - case 0x5c: argv[argc++] = (char *)buf; + case 0x5c: argv[argc++] = buf; slash = 1; state = 3; break; - default : argv[argc++] = (char *)buf; + default : argv[argc++] = buf; state = 1; } break; case 1: switch (c) { // inside unquoted token @@ -2187,16 +2185,16 @@ static int cmdline_to_argv8(unsigned short *cmd, char **argv) // WTF-8/UTF-8 encoding switch ((c >= 0x80) + (c >= 0x800) + (c >= 0x10000)) { - case 0: *buf++ = 0x00 | ((char)(c >> 0) ); break; - case 1: *buf++ = 0xc0 | ((char)(c >> 6) ); - *buf++ = 0x80 | ((char)(c >> 0) & 63); break; - case 2: *buf++ = 0xe0 | ((char)(c >> 12) ); - *buf++ = 0x80 | ((char)(c >> 6) & 63); - *buf++ = 0x80 | ((char)(c >> 0) & 63); break; - case 3: *buf++ = 0xf0 | ((char)(c >> 18) ); - *buf++ = 0x80 | ((char)(c >> 12) & 63); - *buf++ = 0x80 | ((char)(c >> 6) & 63); - *buf++ = 0x80 | ((char)(c >> 0) & 63); break; + case 0: *buf++ = (u8)(0x00 | ((c >> 0) )); break; + case 1: *buf++ = (u8)(0xc0 | ((c >> 6) )); + *buf++ = (u8)(0x80 | ((c >> 0) & 63)); break; + case 2: *buf++ = (u8)(0xe0 | ((c >> 12) )); + *buf++ = (u8)(0x80 | ((c >> 6) & 63)); + *buf++ = (u8)(0x80 | ((c >> 0) & 63)); break; + case 3: *buf++ = (u8)(0xf0 | ((c >> 18) )); + *buf++ = (u8)(0x80 | ((c >> 12) & 63)); + *buf++ = (u8)(0x80 | ((c >> 6) & 63)); + *buf++ = (u8)(0x80 | ((c >> 0) & 63)); break; } } @@ -2205,355 +2203,477 @@ static int cmdline_to_argv8(unsigned short *cmd, char **argv) return argc; } -// Win32 API: windows.h replacement, halves build times +// Mingw-w64 Win32 platform layer for u-config +// $ cc -nostartfiles -o pkg-config win32_main.c +// This is free and unencumbered software released into the public domain. -typedef int BOOL; -typedef void *HANDLE; -typedef unsigned DWORD; -#if __GNUC__ // in MSVC size_t is a built-in type - typedef __SIZE_TYPE__ size_t; -#endif -#if !__cplusplus || (_MSC_VER && !_NATIVE_WCHAR_T_DEFINED) - // NOTE: wchar_t is a built-in type in C++, except older versions of - // Visual Studio are not so C++-compliant without /Zc:wchar_t. - typedef unsigned short wchar_t; +#ifndef PKG_CONFIG_PREFIX +# define PKG_CONFIG_PREFIX #endif -#define CP_UTF8 65001 - -#define FILE_ATTRIBUTE_NORMAL 0x80 - -#define FILE_MAP_READ 4 - -#define FILE_SHARE_DELETE 4 -#define FILE_SHARE_READ 1 -#define FILE_SHARE_WRITE 2 +// For communication with os_write() +static struct { + i32 handle; + b32 isconsole; + b32 err; +} handles[3]; -#define GENERIC_READ 0x80000000 - -#define INVALID_HANDLE_VALUE ((HANDLE)-1) - -#define MAX_PATH 260 +typedef struct { + c16 *s; + size len; +} s16; -#define MEM_COMMIT 0x1000 -#define MEM_RESERVE 0x2000 +static s16 s16cuthead_(s16 s, size off) +{ + assert(off >= 0); + assert(off <= s.len); + s.s += off; + s.len -= off; + return s; +} -#define OPEN_EXISTING 3 +static arena newarena_(size cap) +{ + arena arena = {0}; + arena.beg = VirtualAlloc(0, cap, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE); + if (!arena.beg) { + arena.beg = (byte *)16; // aligned, non-null, zero-size arena + cap = 0; + } + arena.end = arena.beg + cap; + return arena; +} -#define PAGE_READONLY 2 -#define PAGE_READWRITE 4 +typedef i32 char32_t; +typedef char32_t c32; -#define STD_ERROR_HANDLE -12 -#define STD_OUTPUT_HANDLE -11 +enum { + REPLACEMENT_CHARACTER = 0xfffd +}; -#ifdef __cplusplus -extern "C" { -#endif -__declspec(dllimport) HANDLE __stdcall CreateFileW( - wchar_t *, DWORD, DWORD, void *, DWORD, DWORD, HANDLE); -__declspec(dllimport) BOOL __stdcall CloseHandle(HANDLE); -__declspec(dllimport) HANDLE __stdcall CreateFileMappingA( - HANDLE, void *, DWORD, DWORD, DWORD, char *); -__declspec(dllimport) int __stdcall MultiByteToWideChar( - unsigned, DWORD, char *, int, wchar_t *, int); -__declspec(dllimport) wchar_t *__stdcall GetCommandLineW(void); -__declspec(dllimport) BOOL __stdcall GetConsoleMode(HANDLE, DWORD *); -__declspec(dllimport) DWORD __stdcall GetEnvironmentVariableW( - const wchar_t *, wchar_t *, DWORD); -__declspec(dllimport) DWORD __stdcall GetFileSize(HANDLE, DWORD *); -__declspec(dllimport) DWORD __stdcall GetModuleFileNameW( - HANDLE, wchar_t *, DWORD); -__declspec(dllimport) HANDLE __stdcall GetStdHandle(DWORD); -__declspec(dllimport) void *__stdcall MapViewOfFile( - HANDLE, DWORD, DWORD, DWORD, size_t); -__declspec(dllimport) void *__stdcall VirtualAlloc( - void *, size_t, DWORD, DWORD); -__declspec(dllimport) int __stdcall WideCharToMultiByte( - unsigned, DWORD, wchar_t *, int, char *, int, char *, BOOL *); -__declspec(dllimport) BOOL __stdcall WriteConsoleW( - HANDLE, wchar_t *, DWORD, DWORD *, void *); -__declspec(dllimport) BOOL __stdcall WriteFile( - HANDLE, void *, DWORD, DWORD *, void *); -__declspec(dllimport) __declspec(noreturn) void __stdcall ExitProcess(DWORD); -#ifdef __cplusplus +typedef struct { + s8 tail; + c32 rune; +} utf8; + +static utf8 utf8decode_(s8 s) +{ + assert(s.len); + utf8 r = {0}; + switch (s.s[0]&0xf0) { + default : r.rune = s.s[0]; + if (r.rune > 0x7f) break; + r.tail = cuthead(s, 1); + return r; + case 0xc0: + case 0xd0: if (s.len < 2) break; + if ((s.s[1]&0xc0) != 0x80) break; + r.rune = (i32)(s.s[0]&0x1f) << 6 | + (i32)(s.s[1]&0x3f) << 0; + if (r.rune < 0x80) break; + r.tail = cuthead(s, 2); + return r; + case 0xe0: if (s.len < 3) break; + if ((s.s[1]&0xc0) != 0x80) break; + if ((s.s[2]&0xc0) != 0x80) break; + r.rune = (i32)(s.s[0]&0x0f) << 12 | + (i32)(s.s[1]&0x3f) << 6 | + (i32)(s.s[2]&0x3f) << 0; + if (r.rune < 0x800) break; + if (r.rune>=0xd800 && r.rune<=0xdfff) break; + r.tail = cuthead(s, 3); + return r; + case 0xf0: if (s.len < 4) break; + if ((s.s[1]&0xc0) != 0x80) break; + if ((s.s[2]&0xc0) != 0x80) break; + if ((s.s[3]&0xc0) != 0x80) break; + r.rune = (i32)(s.s[0]&0x0f) << 18 | + (i32)(s.s[1]&0x3f) << 12 | + (i32)(s.s[2]&0x3f) << 6 | + (i32)(s.s[3]&0x3f) << 0; + if (r.rune < 0x10000) break; + if (r.rune > 0x10ffff) break; + r.tail = cuthead(s, 4); + return r; + } + r.rune = REPLACEMENT_CHARACTER; + r.tail = cuthead(s, 1); + return r; } -#endif -// Win32 platform layer for u-config -// This is free and unencumbered software released into the public domain. +// Encode code point returning the output length (1-4). +static i32 utf8encode_(u8 *s, c32 rune) +{ + if (rune<0 || (rune>=0xd800 && rune<=0xdfff) || rune>0x10ffff) { + rune = REPLACEMENT_CHARACTER; + } + switch ((rune >= 0x80) + (rune >= 0x800) + (rune >= 0x10000)) { + case 0: s[0] = (u8)(0x00 | ((rune >> 0) )); return 1; + case 1: s[0] = (u8)(0xc0 | ((rune >> 6) )); + s[1] = (u8)(0x80 | ((rune >> 0) & 63)); return 2; + case 2: s[0] = (u8)(0xe0 | ((rune >> 12) )); + s[1] = (u8)(0x80 | ((rune >> 6) & 63)); + s[2] = (u8)(0x80 | ((rune >> 0) & 63)); return 3; + case 3: s[0] = (u8)(0xf0 | ((rune >> 18) )); + s[1] = (u8)(0x80 | ((rune >> 12) & 63)); + s[2] = (u8)(0x80 | ((rune >> 6) & 63)); + s[3] = (u8)(0x80 | ((rune >> 0) & 63)); return 4; + } + assert(0); +} -#ifndef PKG_CONFIG_PREFIX -# define PKG_CONFIG_PREFIX -#endif +typedef struct { + s16 tail; + c32 rune; +} utf16; + +static utf16 utf16decode_(s16 s) +{ + assert(s.len); + utf16 r = {0}; + r.rune = s.s[0]; + if (r.rune>=0xdc00 && r.rune<=0xdfff) { + goto reject; // unpaired low surrogate + } else if (r.rune>=0xd800 && r.rune<=0xdbff) { + if (s.len < 2) { + goto reject; // missing low surrogate + } + i32 hi = r.rune; + i32 lo = s.s[1]; + if (lo<0xdc00 || lo>0xdfff) { + goto reject; // expected low surrogate + } + r.rune = 0x10000 + ((hi - 0xd800)<<10) + (lo - 0xdc00); + r.tail = s16cuthead_(s, 2); + return r; + } + r.tail = s16cuthead_(s, 1); + return r; -#ifdef _MSC_VER - #ifdef __cplusplus - #define EXTERN extern "C" - #else - #define EXTERN - #endif - #define ENTRYPOINT EXTERN - #pragma comment(lib, "kernel32.lib") - #pragma comment(linker, "/subsystem:console") - EXTERN void *memset(void *, int, size_t); - #pragma function(memset) - EXTERN void *memset(void *d, int c, size_t n) - { - char *dst = (char *)d; - for (; n; n--) *dst++ = (char)c; - return d; - } - EXTERN void *memcpy(void *, const void *, size_t); - #pragma function(memcpy) - EXTERN void *memcpy(void *d, const void *s, size_t n) - { - char *dst = (char *)d; - char *src = (char *)s; - for (; n; n--) *dst++ = *src++; - return d; - } -#elif __GNUC__ - #ifdef __cplusplus - #define EXTERN extern "C" __attribute__((externally_visible)) - #else - #define EXTERN __attribute__((externally_visible)) - #endif - #if __i686__ - #define ENTRYPOINT EXTERN __attribute__((force_align_arg_pointer)) - #else - #define ENTRYPOINT EXTERN - #endif - // NOTE: These functions are required at higher GCC optimization - // levels. Placing them in their own section allows them to be - // ommitted via -Wl,--gc-sections when unused. - EXTERN - __attribute__((section(".text.memcpy"))) - void *memcpy(void *d, const void *s, size_t n) - { - // NOTE: polyglot x86 and x64 inline assembly - void *r = d; - __asm volatile ( - "rep movsb" - : "=D"(d), "=S"(s), "=c"(n) - : "0"(d), "1"(s), "2"(n) - : "memory" - ); - return r; - } - EXTERN - __attribute__((section(".text.strlen"))) - size_t strlen(const char *s) - { - const char *b = s; - __asm("repne scasb" : "=D"(s) : "0"(s), "a"(0), "c"((size_t)-1)); - return s - b - 1; - } -#endif + reject: + r.rune = REPLACEMENT_CHARACTER; + r.tail = s16cuthead_(s, 1); + return r; +} -static Bool error_is_console = 0; +// Encode code point returning the output length (1-2). +static i32 utf16encode_(c16 *dst, c32 rune) +{ + if (rune<0 || (rune>=0xd800 && rune<=0xdfff) || rune>0x10ffff) { + rune = REPLACEMENT_CHARACTER; + } + if (rune >= 0x10000) { + rune -= 0x10000; + dst[0] = (c16)((rune >> 10) + 0xd800); + dst[1] = (c16)((rune&0x3ff) + 0xdc00); + return 2; + } + dst[0] = (c16)rune; + return 1; +} -static Arena newarena_(void) +static s16 towide_(arena *perm, s8 s) { - Arena arena = {0}; - Size cap = 1<<28; - #if DEBUG - cap = 1<<21; - #endif - DWORD type = MEM_COMMIT | MEM_RESERVE; - arena.mem.s = (Byte *)VirtualAlloc(0, cap, type, PAGE_READWRITE); - arena.mem.len = arena.mem.s ? cap : 0; - shredfree(&arena); - return arena; + size len = 0; + utf8 state = {0}; + state.tail = s; + while (state.tail.len) { + state = utf8decode_(state.tail); + c16 tmp[2]; + len += utf16encode_(tmp, state.rune); + } + + s16 w = {0}; + w.s = new(perm, c16, len); + state.tail = s; + while (state.tail.len) { + state = utf8decode_(state.tail); + w.len += utf16encode_(w.s+w.len, state.rune); + } + return w; } -static Str fromwide_(Arena *a, wchar_t *w, Size wlen) +static s8 fromwide_(arena *perm, s16 w) { - // NOTE: consider replacing the Win32 UTF-8 encoder/decoder with an - // embedded WTF-8 encoder/decoder - int len = WideCharToMultiByte(CP_UTF8, 0, w, wlen, 0, 0, 0, 0); - Str s = newstr(a, len); - WideCharToMultiByte(CP_UTF8, 0, w, wlen, (char *)s.s, s.len, 0, 0); + size len = 0; + utf16 state = {0}; + state.tail = w; + while (state.tail.len) { + state = utf16decode_(state.tail); + u8 tmp[4]; + len += utf8encode_(tmp, state.rune); + } + + s8 s = {0}; + s.s = new(perm, u8, len); + state.tail = w; + while (state.tail.len) { + state = utf16decode_(state.tail); + s.len += utf8encode_(s.s+s.len, state.rune); + } return s; } -static Str fromenv_(Arena *a, const wchar_t *name) +static s8 fromenv_(arena *perm, c16 *name) { - // NOTE: maximum environment variable size is 2**15-1, so this - // cannot fail if the variable actually exists - static wchar_t w[1<<15]; - DWORD wlen = GetEnvironmentVariableW(name, w, sizeof(w)); + // Given no buffer, unset variables report as size 0, while empty + // variables report as size 1 for the null terminator. + i32 wlen = GetEnvironmentVariableW(name, 0, 0); if (!wlen) { - Str r = {0}; + s8 r = {0}; return r; } - return fromwide_(a, w, wlen); + + // Store temporarily at the beginning of the arena. + size cap = (perm->end - perm->beg) / (size)sizeof(c16); + if (wlen > cap) { + oom(); + } + s16 wvar = {0}; + wvar.s = (c16 *)perm->beg; + wvar.len = wlen - 1; + GetEnvironmentVariableW(name, wvar.s, wlen); + + byte *save = perm->beg; + perm->beg = (byte *)(wvar.s + wvar.len); + s8 var = fromwide_(perm, wvar); + perm->beg = save; + + return var; } -static Str installdir_(Arena *a) +static i32 truncsize(size len) { - wchar_t exe[MAX_PATH]; - Size len = GetModuleFileNameW(0, exe, MAX_PATH); - for (Size i = 0; i < len; i++) { - if (exe[i] == '\\') { - exe[i] = '/'; + i32 max = 0x7fffffff; + return len>max ? max : (i32)len; +} + +static s8 installdir_(arena *perm) +{ + byte *save = perm->beg; + + // GetModuleFileNameW does not communicate length. It only indicates + // success (buffer large enough) or failure (result truncated). To + // make matters worse, long paths have no fixed upper limit, though + // 64KiB is given as an approximate. To deal with this, offer the + // entire free region of the arena, far exceeding any path length. + // + // Computing sizes outside of the allocator isn't great, but the + // situation is constrained by this crummy API. + s16 exe = {0}; + exe.s = (c16 *)perm->beg; + i32 cap = truncsize(perm->end - perm->beg) / (i32)sizeof(c16); + exe.len = GetModuleFileNameW(0, exe.s, cap); + perm->beg = (byte *)(exe.s + exe.len); + + // Normalize by converting backslashes to slashes + for (size i = 0; i < exe.len; i++) { + if (exe.s[i] == '\\') { + exe.s[i] = '/'; } } - Str path = fromwide_(a, exe, len); + + s8 path = fromwide_(perm, exe); + perm->beg = save; // free the wide path return dirname(dirname(path)); } -static Str append2_(Arena *a, Str pre, Str suf) +static s8 append2_(arena *perm, s8 pre, s8 suf) { - Str s = newstr(a, pre.len+suf.len); - copy(copy(s, pre), suf); + s8 s = news8(perm, pre.len+suf.len); + s8copy(s8copy(s, pre), suf); return s; } -static Str makepath_(Arena *a, Str base, Str lib, Str share) +static s8 makepath_(arena *perm, s8 base, s8 lib, s8 share) { - Str delim = S(";"); - Size len = base.len + lib.len + delim.len + base.len + share.len; - Str s = newstr(a, len); - Str r = copy(s, base); - r = copy(r, lib); - r = copy(r, delim); - r = copy(r, base); - copy(r, share); + s8 delim = S(";"); + size len = base.len + lib.len + delim.len + base.len + share.len; + s8 s = news8(perm, len); + s8 r = s8copy(s, base); + r = s8copy(r, lib); + r = s8copy(r, delim); + r = s8copy(r, base); + s8copy(r, share); return s; } -static Str fromcstr_(char *z) +static s8 fromcstr_(u8 *z) { - Str s = {(Byte *)z, 0}; + s8 s = {0}; + s.s = z; if (s.s) { for (; s.s[s.len]; s.len++) {} } return s; } -ENTRYPOINT -int mainCRTStartup(void) +static config *newconfig_() +{ + arena perm = newarena_(1<<22); + config *conf = new(&perm, config, 1); + conf->perm = perm; + return conf; +} + +__attribute((force_align_arg_pointer)) +void mainCRTStartup(void) { - Config conf = {0}; - conf.delim = ';'; - conf.define_prefix = 1; - conf.arena = newarena_(); - Arena *a = &conf.arena; + config *conf = newconfig_(); + conf->delim = ';'; + conf->define_prefix = 1; + arena *perm = &conf->perm; - DWORD dummy; - HANDLE err = GetStdHandle(STD_ERROR_HANDLE); - error_is_console = GetConsoleMode(err, &dummy); + i32 dummy; + handles[1].handle = GetStdHandle(STD_OUTPUT_HANDLE); + handles[1].isconsole = GetConsoleMode(handles[1].handle, &dummy); + handles[2].handle = GetStdHandle(STD_ERROR_HANDLE); + handles[2].isconsole = GetConsoleMode(handles[2].handle, &dummy); - char **argv = (char **)allocarray(a, SIZEOF(*argv), CMDLINE_ARGV_MAX); - unsigned short *cmdline = (unsigned short *)GetCommandLineW(); - conf.nargs = cmdline_to_argv8(cmdline, argv) - 1; - conf.args = (Str *)allocarray(a, SIZEOF(Str), conf.nargs); - for (Size i = 0; i < conf.nargs; i++) { - conf.args[i] = fromcstr_(argv[i+1]); + u8 **argv = new(perm, u8 *, CMDLINE_ARGV_MAX); + c16 *cmdline = GetCommandLineW(); + conf->nargs = cmdline_to_argv8(cmdline, argv) - 1; + conf->args = new(perm, s8, conf->nargs); + for (size i = 0; i < conf->nargs; i++) { + conf->args[i] = fromcstr_(argv[i+1]); } - Str base = installdir_(a); - conf.envpath = fromenv_(a, L"PKG_CONFIG_PATH"); - conf.fixedpath = fromenv_(a, L"PKG_CONFIG_LIBDIR"); - if (!conf.fixedpath.s) { - Str lib = S(PKG_CONFIG_PREFIX "/lib/pkgconfig"); - Str share = S(PKG_CONFIG_PREFIX "/share/pkgconfig"); - conf.fixedpath = makepath_(a, base, lib, share); + s8 base = installdir_(perm); + conf->envpath = fromenv_(perm, L"PKG_CONFIG_PATH"); + conf->fixedpath = fromenv_(perm, L"PKG_CONFIG_LIBDIR"); + if (!conf->fixedpath.s) { + s8 lib = S(PKG_CONFIG_PREFIX "/lib/pkgconfig"); + s8 share = S(PKG_CONFIG_PREFIX "/share/pkgconfig"); + conf->fixedpath = makepath_(perm, base, lib, share); } - conf.top_builddir = fromenv_(a, L"PKG_CONFIG_TOP_BUILD_DIR"); - conf.sys_incpath = append2_(a, base, S(PKG_CONFIG_PREFIX "/include")); - conf.sys_libpath = append2_(a, base, S(PKG_CONFIG_PREFIX "/lib")); + conf->top_builddir = fromenv_(perm, L"PKG_CONFIG_TOP_BUILD_DIR"); + conf->sys_incpath = append2_(perm, base, S(PKG_CONFIG_PREFIX "/include")); + conf->sys_libpath = append2_(perm, base, S(PKG_CONFIG_PREFIX "/lib")); + conf->print_sysinc = fromenv_(perm, L"PKG_CONFIG_ALLOW_SYSTEM_CFLAGS"); + conf->print_syslib = fromenv_(perm, L"PKG_CONFIG_ALLOW_SYSTEM_LIBS"); - appmain(conf); - ExitProcess(0); + uconfig(conf); + ExitProcess(handles[1].err || handles[2].err); + assert(0); } -static MapFileResult os_mapfile(Arena *a, Str path) +static filemap os_mapfile(arena *perm, s8 path) { - (void)a; - ASSERT(path.len > 0); - ASSERT(!path.s[path.len-1]); + assert(path.len > 0); + assert(!path.s[path.len-1]); - wchar_t wpath[MAX_PATH]; - int wlen = MultiByteToWideChar( - CP_UTF8, 0, (char *)path.s, path.len, wpath, MAX_PATH - ); - if (!wlen) { - MapFileResult r = {{0, 0}, MapFile_NOTFOUND}; - return r; - } + filemap r = {0}; - HANDLE h = CreateFileW( - wpath, - GENERIC_READ, - FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, - 0, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - 0 - ); - if (h == INVALID_HANDLE_VALUE) { - MapFileResult r = {{0, 0}, MapFile_NOTFOUND}; - return r; - } - - DWORD hi, lo = GetFileSize(h, &hi); - if (hi || lo>Size_MAX) { - CloseHandle(h); - MapFileResult r = {{0, 0}, MapFile_READERR}; - return r; - } else if (!lo) { - CloseHandle(h); - // Cannot map an empty file, so use the arena for a zero-size - // allocation, distinguishing it from a null string. - MapFileResult r = {newstr(a, 0), MapFile_OK}; - return r; + i32 handle = 0; + { + arena scratch = *perm; + s16 wpath = towide_(&scratch, path); + handle = CreateFileW( + wpath.s, + GENERIC_READ, + FILE_SHARE_ALL, + 0, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + 0 + ); + if (handle == INVALID_HANDLE_VALUE) { + r.status = filemap_NOTFOUND; + return r; + } } - HANDLE map = CreateFileMappingA(h, 0, PAGE_READONLY, 0, lo, 0); - CloseHandle(h); - if (!map) { - MapFileResult r = {{0, 0}, MapFile_READERR}; - return r; + r.data.s = (u8 *)perm->beg; + size cap = perm->end - perm->beg; + while (r.data.len < cap) { + i32 len = truncsize(cap - r.data.len); + ReadFile(handle, r.data.s+r.data.len, len, &len, 0); + if (len < 1) { + break; + } + r.data.len += len; } + CloseHandle(handle); - void *p = MapViewOfFile(map, FILE_MAP_READ, 0, 0, lo); - CloseHandle(map); - if (!p) { - MapFileResult r = {{0, 0}, MapFile_READERR}; + if (r.data.len == cap) { + // If it filled all available space, assume the file is too large. + r.status = filemap_READERR; return r; } - MapFileResult r = {{(Byte *)p, (Size)lo}, MapFile_OK}; + perm->beg += r.data.len; + r.status = filemap_OK; return r; } static void os_fail(void) { ExitProcess(1); + assert(0); } -static void os_write(int fd, Str s) +typedef struct { + c16 buf[1<<8]; + i32 len; + i32 handle; + b32 err; +} u16buf; + +static void flushconsole_(u16buf *b) { - ASSERT(fd==1 || fd==2); - DWORD id = fd==1 ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE; - HANDLE h = GetStdHandle(id); - DWORD n; + if (!b->err && b->len) { + i32 dummy; + b->err = !WriteConsoleW(b->handle, b->buf, b->len, &dummy, 0); + } + b->len = 0; +} - if (fd==2 && error_is_console) { - static wchar_t tmp[1<<12]; - int len = MultiByteToWideChar( - CP_UTF8, 0, (char *)s.s, s.len, tmp, sizeof(tmp) - ); - if (len) { - WriteConsoleW(h, tmp, len, &n, 0); - return; - } - // Too large, fallback to WriteFile +static void printc32_(u16buf *b, c32 rune) +{ + if (b->len > countof(b->buf)-2) { + flushconsole_(b); } + b->len += utf16encode_(b->buf+b->len, rune); +} - BOOL r = WriteFile(h, s.s, s.len, &n, 0); - if (!r || (Size)n!=s.len) { - os_fail(); +static void os_write(i32 fd, s8 s) +{ + assert((i32)s.len == s.len); // NOTE: assume it's not a huge buffer + assert(fd==1 || fd==2); + + b32 *err = &handles[fd].err; + if (*err) { + return; + } + + i32 handle = handles[fd].handle; + if (handles[fd].isconsole) { + // NOTE: There is a small chance that a multi-byte code point + // spans flushes from the application. With no decoder state + // tracked between os_write calls, this will mistranslate for + // console outputs. The application could avoid such flushes, + // which would require a distinct "close" flush before exits. + // + // Alternatively, the platform layer could detect truncated + // encodings and buffer up to 3 bytes between calls. This buffer + // would need to be flushed on exit by the platform. + // + // The primary use case for u-config is non-console outputs into + // a build system, which will not experience this issue. Console + // output is mainly for human-friendly debugging, so the risk is + // acceptable. + u16buf b = {0}; + b.handle = handle; + utf8 state = {0}; + state.tail = s; + while (state.tail.len) { + state = utf8decode_(state.tail); + printc32_(&b, state.rune); + } + flushconsole_(&b); + *err = b.err; + } else { + i32 dummy; + *err = !WriteFile(handle, s.s, (i32)s.len, &dummy, 0); } } diff --git a/.gnu-windows/src/profile b/.gnu-windows/src/profile new file mode 100644 index 000000000..d82554a1b --- /dev/null +++ b/.gnu-windows/src/profile @@ -0,0 +1,6 @@ +# GNU Autotools "configure" detects w64devkit as an MSYS2 environment, so +# set some environment variables to disabuse it. Goes hand-in-hand with +# the busybox-w32 ash patch for libtool. +export PATH_SEPARATOR=';' +export ac_executable_extensions=.exe +export build_alias=ARCH diff --git a/.gnu-windows/src/variant-fortran.patch b/.gnu-windows/src/variant-fortran.patch deleted file mode 100644 index 55f4dfa53..000000000 --- a/.gnu-windows/src/variant-fortran.patch +++ /dev/null @@ -1,17 +0,0 @@ ---- a/Dockerfile -+++ b/Dockerfile -@@ -102,3 +102,3 @@ RUN cat $PREFIX/src/gcc-*.patch | patch -d/gcc-$GCC_VERSION -p1 \ - --with-pic \ -- --enable-languages=c,c++ \ -+ --enable-languages=c,c++,fortran \ - --enable-libgomp \ -@@ -254,3 +254,3 @@ RUN sed -i 's#=/mingw/include#=/include#' /gcc-$GCC_VERSION/gcc/config.gcc \ - --with-mpfr-lib=/deps/lib \ -- --enable-languages=c,c++ \ -+ --enable-languages=c,c++,fortran \ - --enable-libgomp \ -@@ -288,3 +288,3 @@ RUN $ARCH-gcc -DEXE=gcc.exe -DCMD=cc \ - gcc gcc-ar gcc-nm gcc-ranlib gcov gcov-dump gcov-tool ld nm objcopy \ -- objdump ranlib readelf size strings strip windmc windres \ -+ objdump ranlib readelf size strings strip windmc windres gfortran \ - | xargs -I{} -P$(nproc) \ diff --git a/.gnu-windows/src/variant-i686.patch b/.gnu-windows/src/variant-x86.patch similarity index 56% rename from .gnu-windows/src/variant-i686.patch rename to .gnu-windows/src/variant-x86.patch index 530758e29..6cf1afad4 100644 --- a/.gnu-windows/src/variant-i686.patch +++ b/.gnu-windows/src/variant-x86.patch @@ -1,43 +1,46 @@ --- a/Dockerfile +++ b/Dockerfile -@@ -65,3 +65,3 @@ COPY gnu-windows.c ../gnu-windows.ico \ +@@ -62,3 +62,3 @@ -ARG ARCH=x86_64-w64-mingw32 +ARG ARCH=i686-w64-mingw32 -@@ -93,2 +93,3 @@ RUN /mingw-w64-v$MINGW_VERSION/mingw-w64-headers/configure \ +@@ -90,2 +90,3 @@ --with-default-msvcrt=msvcrt-os \ + --with-default-win32-winnt=0x0501 \ && make -j$(nproc) \ -@@ -99,2 +100,5 @@ RUN ln -s $ARCH mingw - -+# Disable UTF-8 manifest for Windows XP (#58) -+RUN echo >/gcc-$GCC_VERSION/gcc/config/i386/winnt-utf8.manifest -+ - WORKDIR /x-gcc -@@ -103,2 +107,3 @@ RUN /gcc-$GCC_VERSION/configure \ +@@ -102,2 +103,3 @@ --with-sysroot=/bootstrap \ + --with-arch=pentium4 \ --target=$ARCH \ -@@ -132,4 +137,4 @@ RUN /mingw-w64-v$MINGW_VERSION/mingw-w64-crt/configure \ +@@ -138,4 +140,4 @@ --disable-dependency-tracking \ - --disable-lib32 \ - --enable-lib64 \ + --enable-lib32 \ + --disable-lib64 \ CFLAGS="-Os" \ -@@ -217,2 +222,3 @@ RUN /mingw-w64-v$MINGW_VERSION/mingw-w64-headers/configure \ +@@ -223,2 +225,3 @@ --with-default-msvcrt=msvcrt-os \ + --with-default-win32-winnt=0x0501 \ && make -j$(nproc) \ -@@ -227,4 +233,4 @@ RUN /mingw-w64-v$MINGW_VERSION/mingw-w64-crt/configure \ +@@ -233,4 +236,4 @@ --disable-dependency-tracking \ - --disable-lib32 \ - --enable-lib64 \ + --enable-lib32 \ + --disable-lib64 \ CFLAGS="-Os" \ -@@ -251,2 +257,3 @@ RUN /gcc-$GCC_VERSION/configure \ +@@ -257,2 +260,3 @@ --with-native-system-header-dir=/include \ + --with-arch=pentium4 \ --target=$ARCH \ +@@ -277,2 +281,3 @@ + --disable-win32-registry \ ++ --disable-win32-utf8-manifest \ + --enable-mingw-wildcard \ +@@ -384,3 +389,3 @@ + RUN cat $PREFIX/src/busybox-*.patch | patch -p1 \ +- && make mingw64u_defconfig \ ++ && make mingw64_defconfig \ + && sed -ri 's/^(CONFIG_AR)=y/\1=n/' .config \ diff --git a/.gnu-windows/src/gnu-windows.c b/.gnu-windows/src/w64devkit.c similarity index 61% rename from .gnu-windows/src/gnu-windows.c rename to .gnu-windows/src/w64devkit.c index 97ce0d525..7f9312987 100644 --- a/.gnu-windows/src/gnu-windows.c +++ b/.gnu-windows/src/w64devkit.c @@ -1,24 +1,17 @@ -// Tiny, standalone launcher for gnu_windows -// * Sets $gnu_windows to the release version (-DVERSION) -// * Sets $gnu_windows_HOME to the install location -// * Maybe sets $HOME according to gnu_windows.ini +// Tiny, standalone launcher for w64devkit +// * Sets $W64DEVKIT to the release version (-DVERSION) +// * Sets $W64DEVKIT_HOME to the install location +// * Maybe sets $HOME according to w64devkit.ini // * Starts a login shell with "sh -l" // // $ gcc -DVERSION="$VERSION" -nostartfiles -fno-builtin -// -o gnu_windows.exe gnu_windows.c +// -o w64devkit.exe w64devkit.c // // This is free and unencumbered software released into the public domain. -#define sizeof(a) (size)(sizeof(a)) -#define alignof(a) (size)(_Alignof(a)) -#define countof(a) (sizeof(a) / sizeof(*(a))) -#define lengthof(s) (countof(s) - 1) - -#define new(...) newx(__VA_ARGS__, new4, new3, new2)(__VA_ARGS__) -#define newx(a,b,c,d,e,...) e -#define new2(a, t) (t *)alloc(a, sizeof(t), alignof(t), 1, 0) -#define new3(a, t, n) (t *)alloc(a, sizeof(t), alignof(t), n, 0) -#define new4(a, t, n, f) (t *)alloc(a, sizeof(t), alignof(t), n, f) +#define countof(a) (size)(sizeof(a) / sizeof(*(a))) +#define assert(c) while (!(c)) __builtin_unreachable() +#define new(a, t, n) (t *)alloc(a, sizeof(t), _Alignof(t), n) typedef unsigned char byte; typedef __UINT8_TYPE__ u8; @@ -49,10 +42,7 @@ typedef struct { u32 tid; } pi; -#define MAX_PATH 260 #define MAX_ENVVAR 32767 -#define MAX_CMDLINE 32767 -#define MAX_INI (1<<18) #define CP_UTF8 65001 #define PAGE_READWRITE 0x04 #define MEM_COMMIT 0x1000 @@ -74,7 +64,7 @@ W32 u32 GetFullPathNameW(c16 *, u32, c16 *, c16 *); W32 u32 GetModuleFileNameW(handle, c16 *, u32); W32 i32 MessageBoxW(handle, c16 *, c16 *, u32); W32 i32 MultiByteToWideChar(u32, u32, u8 *, i32, c16 *, i32); -W32 b32 ReadFile(handle, u8 *, u32, u32 *, void *); +W32 b32 ReadFile(handle, u8 *, i32, i32 *, void *); W32 b32 SetConsoleTitleW(c16 *); W32 b32 SetCurrentDirectoryW(c16 *); W32 b32 SetEnvironmentVariableW(c16 *, c16 *); @@ -82,13 +72,13 @@ W32 byte *VirtualAlloc(byte *, usize, u32, u32); W32 b32 VirtualFree(byte *, usize, u32); W32 u32 WaitForSingleObject(handle, u32); -#define S(s) (s8){(u8 *)s, lengthof(s)} +#define S(s) (s8){(u8 *)s, countof(s)-1} typedef struct { u8 *s; size len; } s8; -#define U(s) (s16){s, lengthof(s)} +#define U(s) (s16){s, countof(s)-1} typedef struct { c16 *s; size len; @@ -117,68 +107,62 @@ static b32 s8equals(s8 a, s8 b) static void fatal(c16 *msg) { - MessageBoxW(0, msg, u"gnu_windows launcher", 0x10); + MessageBoxW(0, msg, u"w64devkit launcher", 0x10); ExitProcess(2); } typedef struct { - byte *mem; - size cap; - size off; + byte *beg; + byte *end; } arena; -static arena *newarena(size cap) -{ - arena *a = 0; - byte *mem = VirtualAlloc(0, cap, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); - if (mem) { - a = (arena *)mem; - a->mem = mem; - a->cap = cap; - a->off = sizeof(arena); - } - return a; -} - -static void freearena(arena *a) +static void outofmemory(void) { - VirtualFree(a->mem, 0, MEM_RELEASE); + fatal(u"Out of memory"); } -#define NOZERO (1<<0) -#define SOFTFAIL (1<<1) -__attribute((malloc)) -__attribute((alloc_align(3))) -__attribute((alloc_size(2, 4))) -static byte *alloc(arena *a, size objsize, size align, size count, i32 flags) +__attribute((malloc, alloc_size(2, 4))) +static byte *alloc(arena *a, size objsize, size align, size count) { - size avail = a->cap - a->off; - size pad = -a->off & (align - 1); - if (count > (avail - pad)/objsize) { - if (flags & SOFTFAIL) { - return 0; - } - fatal(u"Out of memory"); + size padding = (uptr)a->end & (align - 1); + if (count > (a->end - a->beg - padding)/objsize) { + outofmemory(); } size total = count*objsize; - byte *p = a->mem + a->off + pad; - if (!(flags & NOZERO)) { - for (size i = 0; i < total; i++) { - p[i] = 0; - } + byte *p = a->end -= total + padding; + for (size i = 0; i < total; i++) { + p[i] = 0; } - a->off += pad + total; return p; } -static arena splitarena(arena *a, i32 div) +typedef struct { + byte *base; + arena perm; + arena scratch; +} memory; + +static memory newmemory(size cap) +{ + memory r = {}; + r.base = VirtualAlloc(0, cap, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); + if (!r.base) return r; + r.perm.beg = r.base; + r.perm.end = r.base + cap/2; + r.scratch.beg = r.base + cap/2; + r.scratch.end = r.base + cap; + return r; +} + +static void freememory(memory m) +{ + VirtualFree(m.base, 0, MEM_RELEASE); +} + +static i32 truncsize(size len) { - size avail = a->cap - a->off; - size cap = avail / div; - arena sub = {}; - sub.mem = alloc(a, 1, 32, cap, NOZERO); - sub.cap = cap; - return sub; + i32 max = 0x7fffffff; + return len>max ? max : (i32)len; } typedef enum { @@ -308,8 +292,9 @@ static initoken iniparse(iniparser *p) typedef enum { sym_null = 0, - sym_gnu_windows, + sym_w64devkit, sym_home, + sym_title, } symbol; static symbol intern(s8 s) @@ -318,8 +303,9 @@ static symbol intern(s8 s) s8 name; symbol symbol; } symbols[] = { - {S("gnu_windows"), sym_gnu_windows}, + {S("w64devkit"), sym_w64devkit}, {S("home"), sym_home}, + {S("title"), sym_title}, }; for (size i = 0; i < countof(symbols); i++) { if (s8equals(symbols[i].name, s)) { @@ -329,25 +315,41 @@ static symbol intern(s8 s) return sym_null; } -static u8 *makecstr(arena *a, s8 s) +static c16 *expandvalue(s8 value, arena *perm, arena scratch) { - u8 *r = new(a, u8, s.len+1); - for (size i = 0; i < s.len; i++) { - r[i] = s.s[i]; - } + assert(value.len < 0x7fffffff); + + // First temporarily convert to a null-terminated wide string + i32 len = MultiByteToWideChar(CP_UTF8, 0, value.s, (i32)value.len, 0, 0); + if (len == 0x7fffffff) outofmemory(); + s16 w = {}; + w.len = len + 1; // append null terminator + w.s = new(&scratch, c16, w.len); + MultiByteToWideChar(CP_UTF8, 0, value.s, (i32)value.len, w.s, len); + + len = ExpandEnvironmentStringsW(w.s, 0, 0); + if (len < 0) outofmemory(); + c16 *r = new(perm, c16, len); + ExpandEnvironmentStringsW(w.s, r, len); return r; } -// Read and process "gnu_windows.home" from "gnu_windows.ini". Environment -// variables are expanded, and if relative, the result is converted into -// an absolute path. Returns null on error. -// -// Before calling, the current working directory must be changed to the -// location of gnu_windows.exe. -static c16 *homeconfig(arena *perm, arena scratch) +// Expand to a full path via GetFullPathNameW. +static c16 *tofullpath(c16 *path, arena *perm) +{ + i32 len = GetFullPathNameW(path, 0, 0, 0); + if (len < 0) outofmemory(); + c16 *r = new(perm, c16, len); + GetFullPathNameW(path, len, r, 0); + return r; +} + +static s8 loadfile(c16 *path, arena *perm) { + s8 r = {}; + handle h = CreateFileW( - u"gnu_windows.ini", + path, GENERIC_READ, FILE_SHARE_ALL, 0, @@ -356,64 +358,72 @@ static c16 *homeconfig(arena *perm, arena scratch) 0 ); if (h == (handle)-1) { - return 0; + return r; } - iniparser *p = new(&scratch, iniparser); - p->beg = new(&scratch, u8, MAX_INI, NOZERO); - u32 inilen; - b32 r = ReadFile(h, p->beg, MAX_INI, &inilen, 0); + r.s = (u8 *)perm->beg; + r.len = truncsize((perm->end - perm->beg)/sizeof(u8)); + i32 len; + b32 ok = ReadFile(h, r.s, (i32)r.len, &len, 0); CloseHandle(h); - if (!r || inilen == MAX_INI) { - return 0; - } - p->end = p->beg + inilen; + r.len = len; + r.s = ok ? r.s : 0; + perm->beg += r.len / sizeof(u8); + return r; +} + +typedef struct { + c16 *home; + c16 *title; + b32 ok; +} config; + +static config newconfig(void) +{ + config r = {}; + r.title = u"w64devkit"; + return r; +} + +// Read entries from w64devkit.ini. Expands environment variables, and +// if "home" is relative, converts it to an absolute path. Before the +// call, the working directory must be location of w64devkit.exe. +static config loadconfig(arena *perm, arena scratch) +{ + config conf = newconfig(); + + s8 ini = loadfile(u"w64devkit.ini", &scratch); + if (!ini.s) return conf; + + iniparser *p = new(&scratch, iniparser, 1); + p->beg = ini.s; + p->end = ini.s + ini.len; - u8 *home = 0; - u32 len = 0; for (symbol section = 0, key = 0;;) { initoken t = iniparse(p); switch (t.type) { case INI_eof: - break; + conf.ok = 1; + return conf; case INI_section: section = intern(t.name); - continue; + break; case INI_key: key = intern(t.name); - continue; + break; case INI_value: - if (!home && section==sym_gnu_windows && key==sym_home) { - home = makecstr(&scratch, t.name); - len = (u32)(t.name.len + 1); // include terminator + if (section == sym_w64devkit) { + if (!conf.home && key==sym_home) { + arena temp = scratch; + conf.home = expandvalue(t.name, &temp, *perm); + conf.home = tofullpath(conf.home, perm); + } else if (key == sym_title) { + conf.title = expandvalue(t.name, perm, scratch); + } } - continue; + break; } - break; - } - - c16 *whome = new(&scratch, c16, len); - if (!MultiByteToWideChar(CP_UTF8, 0, home, len, whome, len)) { - return 0; - } - - // Process INI string into a final HOME path. Allocate a bit more - // than MAX_PATH, because GetFullPathNameW could technically reduce - // it to within MAX_PATH if there are lots of relative components. - u32 cap = MAX_PATH*4; - c16 *expanded = new(&scratch, c16, cap); - len = ExpandEnvironmentStringsW(whome, expanded, cap); - if (!len || len>cap) { - return 0; - } - - // The final result must fit within MAX_PATH in order to be useful. - c16 *path = new(perm, c16, MAX_PATH); - len = GetFullPathNameW(expanded, MAX_PATH, path, 0); - if (!len || len>=MAX_PATH) { - return 0; } - return path; } typedef struct { @@ -426,7 +436,7 @@ typedef struct { static buf16 newbuf16(arena *a, size cap) { buf16 buf = {}; - buf.buf = new(a, c16, cap, NOZERO); + buf.buf = new(a, c16, cap); buf.cap = cap; return buf; } @@ -451,12 +461,20 @@ static void buf16c16(buf16 *buf, c16 c) static void buf16moduledir(buf16 *buf, arena scratch) { - c16 *path = new(&scratch, c16, MAX_PATH); - size len = GetModuleFileNameW(0, path, MAX_PATH); - for (; len; len--) { - switch (path[len-1]) { + // GetFullPathNameW does not allow querying the output size, instead + // indicating whether or not the buffer was large enough. So simply + // offer the entire scratch buffer, then crop out the actual result. + scratch.beg += -(uptr)scratch.beg & (sizeof(c16) - 1); // align + i32 len = truncsize((scratch.end - scratch.beg)/sizeof(c16)); + s16 path = {}; + path.s = (c16 *)scratch.beg; + path.len = GetModuleFileNameW(0, path.s, len); + if (len == path.len) outofmemory(); + for (; path.len; path.len--) { + switch (path.s[path.len-1]) { case '/': - case '\\': buf16cat(buf, (s16){path, len-1}); + case '\\': path.len--; + buf16cat(buf, path); return; } } @@ -464,10 +482,11 @@ static void buf16moduledir(buf16 *buf, arena scratch) static void buf16getenv(buf16 *buf, c16 *key, arena scratch) { + i32 len = GetEnvironmentVariableW(key, 0, 0); + if (len < 0) outofmemory(); s16 var = {}; - var.s = new(&scratch, c16, MAX_ENVVAR, NOZERO); - u32 len = GetEnvironmentVariableW(key, var.s, MAX_ENVVAR); - var.len = len>=MAX_ENVVAR ? 0 : len; + var.s = new(&scratch, c16, len); + var.len = GetEnvironmentVariableW(key, var.s, len); buf16cat(buf, var); } @@ -478,13 +497,14 @@ static void toslashes(c16 *path) } } -static u32 gnu_windows(void) +static u32 w64devkit(void) { - arena *perm = newarena(1<<22); - if (!perm) { + memory mem = newmemory(1<<22); + if (!mem.base) { fatal(u"Out of memory on startup"); } - arena scratch = splitarena(perm, 2); + arena *perm = &mem.perm; + arena scratch = mem.scratch; // First load the module directory into the fresh buffer, and use it // for a few different operations. @@ -493,14 +513,21 @@ static u32 gnu_windows(void) buf16 moduledir = path; // to truncate back to the module dir buf16c16(&path, 0); // null terminator - SetEnvironmentVariableW(u"gnu_windows_HOME", path.buf); // ignore errors + SetEnvironmentVariableW(u"W64DEVKIT_HOME", path.buf); // ignore errors + + #ifdef VERSION + #define LSTR(s) XSTR(s) + #define XSTR(s) u ## # s + SetEnvironmentVariableW(u"W64DEVKIT", LSTR(VERSION)); // ignore errors + #endif - // Maybe set HOME from gnu_windows.ini + // Maybe set HOME from w64devkit.ini + config conf = newconfig(); if (SetCurrentDirectoryW(path.buf)) { - c16 *home = homeconfig(perm, scratch); - if (home) { - toslashes(home); - SetEnvironmentVariableW(u"HOME", home); // ignore errors + conf = loadconfig(perm, scratch); + if (conf.home) { + toslashes(conf.home); + SetEnvironmentVariableW(u"HOME", conf.home); // ignore errors } } @@ -513,15 +540,11 @@ static u32 gnu_windows(void) fatal(u"Failed to configure $PATH"); } - #ifdef VERSION - #define LSTR(s) XSTR(s) - #define XSTR(s) u ## # s - SetEnvironmentVariableW(u"gnu_windows", LSTR(VERSION)); // ignore errors - #endif - // Set the console title as late as possible, but not after starting // the shell because .profile might change it. - SetConsoleTitleW(u"gnu_windows"); // ignore errors + if (conf.title) { + SetConsoleTitleW(conf.title); // ignore errors + } path = moduledir; buf16cat(&path, U(u"\\bin\\busybox.exe")); @@ -537,7 +560,7 @@ static u32 gnu_windows(void) } // Wait for shell to exit - freearena(perm); + freememory(mem); u32 ret; WaitForSingleObject(pi.process, -1); GetExitCodeProcess(pi.process, &ret); @@ -547,6 +570,6 @@ static u32 gnu_windows(void) __attribute((force_align_arg_pointer)) void mainCRTStartup(void) { - u32 r = gnu_windows(); + u32 r = w64devkit(); ExitProcess(r); } diff --git a/.gnu-windows/src/w64devkit.ico b/.gnu-windows/src/w64devkit.ico new file mode 100644 index 0000000000000000000000000000000000000000..9403bc941f5617cbb94bd20fc0d5639b13e12cae GIT binary patch literal 16131 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 M4ZTr+Ho@}$3)wNKrT_o{ literal 0 HcmV?d00001 diff --git a/.gnu-windows/src/gnu-windows.ini b/.gnu-windows/src/w64devkit.ini similarity index 65% rename from .gnu-windows/src/gnu-windows.ini rename to .gnu-windows/src/w64devkit.ini index bec644d0d..78c18c548 100644 --- a/.gnu-windows/src/gnu-windows.ini +++ b/.gnu-windows/src/w64devkit.ini @@ -1,7 +1,6 @@ -; Win-GDevKit.ini -- configuration for Win-GDevKit.exe -; This file must be encoded as UTF-8. +; w64devkit.ini -- configuration for w64devkit.exe -[Win-GDevKit] +[w64devkit] ; home: Sets the HOME environment variable for the shell. Place a ; .profile in this directory to do further environment configuration ; using the shell itself. @@ -11,8 +10,9 @@ ; la ExpandEnvironmentStrings, and a relative path will be converted to ; an absolute path relative to this .ini file. ; -; Known bugs: busybox-w32 uses the narrow API and does not support wide -; paths, so be mindful when using non-ASCII paths for this value. +; title: Sets the initial title for the new console window. This value +; may also contain environment variables. ; ;home = ..\home ;home = %HOMEDRIVE%%HOMEPATH% +;title = %USERNAME%@%COMPUTERNAME% [%W64DEVKIT_HOME% %W64DEVKIT%] From 53d205288559f1829947a14e43c85856d554c55c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 14:58:56 +0700 Subject: [PATCH 20/36] Update build.sh --- .gnu-windows/build.sh | 184 +++++++++++++++++++----------------------- 1 file changed, 84 insertions(+), 100 deletions(-) diff --git a/.gnu-windows/build.sh b/.gnu-windows/build.sh index 925026dbd..dd3b5d7c5 100644 --- a/.gnu-windows/build.sh +++ b/.gnu-windows/build.sh @@ -9,64 +9,49 @@ SOURCE_CODE="$WORKDIR/src" GNU_FOLDER="$WORKDIR/.." PATH="$BOOTSTRAP/bin:${PATH}" -BINUTILS_VERSION=2.41 -BUSYBOX_VERSION=FRP-5236-g7dff7f376 -CPPCHECK_VERSION=2.10 -CTAGS_VERSION=6.0.0 -EXPAT_VERSION=2.5.0 -GCC_VERSION=13.2.0 -GDB_VERSION=13.1 -GMP_VERSION=6.3.0 -LIBICONV_VERSION=1.17 -MAKE_VERSION=4.4.1 -MINGW_VERSION=11.0.1 -MPC_VERSION=1.3.1 -MPFR_VERSION=4.2.1 -NASM_VERSION=2.15.05 -PDCURSES_VERSION=3.9 -VERSION=1.21.0 -VIM_VERSION=9.0 +VERSION=1.1.0 cd $WORKDIR -# Cross-build system - -#cd $GNU_FOLDER/binutils-$BINUTILS_VERSION -#sed -ri 's/(static bool insert_timestamp = )/\1!/' ld/emultempl/pe*.em +# Build cross-compiler +cd $GNU_FOLDER/binutils +sed -ri 's/(static bool insert_timestamp = )/\1!/' ld/emultempl/pe*.em \ + && sed -ri 's/(int pe_enable_stdcall_fixup = )/\1!!/' ld/emultempl/pe*.em \ + && cat $SOURCE_CODE/binutils-*.patch | patch -p1 mkdir $MAKE_FOLDER/x-binutils && cd "$_" -chmod +x $GNU_FOLDER/binutils-$BINUTILS_VERSION/configure -$GNU_FOLDER/binutils-$BINUTILS_VERSION/configure \ +chmod +x $GNU_FOLDER/binutils/configure +$GNU_FOLDER/binutils/configure \ --prefix=$BOOTSTRAP \ --with-sysroot=$BOOTSTRAP/$ARCH \ --target=$ARCH \ --disable-nls \ --with-static-standard-libraries \ --disable-multilib \ - && make MAKEINFO=true \ + && make MAKEINFO=true -j$(nproc) \ && make MAKEINFO=true install -cd $WORKDIR -#sed -i /OpenThreadToken/d $GNU_FOLDER/mingw-w64-v$MINGW_VERSION/mingw-w64-crt/lib32/kernel32.def +# Fixes i686 Windows XP regression +# https://sourceforge.net/p/mingw-w64/bugs/821/ +sed -i /OpenThreadToken/d $GNU_FOLDER/mingw-w64/mingw-w64-crt/lib32/kernel32.def + mkdir $MAKE_FOLDER/x-mingw-headers && cd "$_" -chmod +x $GNU_FOLDER/mingw-w64-v$MINGW_VERSION/mingw-w64-headers/configure -$GNU_FOLDER/mingw-w64-v$MINGW_VERSION/mingw-w64-headers/configure \ +chmod +x $GNU_FOLDER/mingw-w64/mingw-w64-headers/configure +$GNU_FOLDER/mingw-w64/mingw-w64-headers/configure \ --prefix=$BOOTSTRAP/$ARCH \ --host=$ARCH \ --with-default-msvcrt=msvcrt-os \ - && make \ + && make -j$(nproc) \ && make install -cd $BOOTSTRAP -ln -s $ARCH mingw +cd $BOOTSTRAP && ln -s $ARCH mingw mkdir $MAKE_FOLDER/x-gcc && cd "$_" -mkdir $BOOTSTRAP/src && cp $SOURCE_CODE/gcc-*.patch $BOOTSTRAP/src/ -#cat $BOOTSTRAP/src/gcc-*.patch | patch -d $GNU_FOLDER/gcc-$GCC_VERSION -p1 -chmod +x $GNU_FOLDER/gcc-$GCC_VERSION/configure -$GNU_FOLDER/gcc-$GCC_VERSION/configure \ +cat $SOURCE_CODE/gcc-*.patch | patch -d $GNU_FOLDER/gcc -p1 +chmod +x $GNU_FOLDER/gcc/configure +$GNU_FOLDER/gcc/configure \ --prefix=$BOOTSTRAP \ --with-sysroot=$BOOTSTRAP \ --target=$ARCH \ @@ -74,7 +59,7 @@ $GNU_FOLDER/gcc-$GCC_VERSION/configure \ --disable-shared \ --with-pic \ --with-gnu-ld \ - --enable-languages=c,c++ \ + --enable-languages=c,c++,fortran \ --enable-libgomp \ --enable-threads=posix \ --enable-version-specific-runtime-libs \ @@ -88,17 +73,18 @@ $GNU_FOLDER/gcc-$GCC_VERSION/configure \ CFLAGS="-Os" \ CXXFLAGS="-Os" \ LDFLAGS="-s" \ - && make all-gcc \ + && make -j$(nproc) all-gcc \ && make install-gcc mkdir -p $BOOTSTRAP/$ARCH/lib \ - && chmod +x $BOOTSTRAP/bin/$ARCH-gcc \ - && CC=$BOOTSTRAP/bin/$ARCH-gcc DESTDIR=$BOOTSTRAP/$ARCH/lib/ sh $SOURCE_CODE/libmemory.c \ - && CC=$BOOTSTRAP/bin/$ARCH-gcc DESTDIR=$BOOTSTRAP/$ARCH/lib/ sh $SOURCE_CODE/libchkstk.S + && CC=$ARCH-gcc DESTDIR=$BOOTSTRAP/$ARCH/lib/ sh $SOURCE_CODE/libmemory.c \ + && ln $BOOTSTRAP/$ARCH/lib/libmemory.a $BOOTSTRAP/$ARCH/lib/ \ + && CC=$ARCH-gcc DESTDIR=$BOOTSTRAP/$ARCH/lib/ sh $SOURCE_CODE/libchkstk.S \ + && ln $BOOTSTRAP/$ARCH/lib/libchkstk.a $BOOTSTRAP/$ARCH/lib/ mkdir $MAKE_FOLDER/x-mingw-crt && cd "$_" -chmod +x $GNU_FOLDER/mingw-w64-v$MINGW_VERSION/mingw-w64-crt/configure -$GNU_FOLDER/mingw-w64-v$MINGW_VERSION/mingw-w64-crt/configure \ +chmod +x $GNU_FOLDER/mingw-w64/mingw-w64-crt/configure +$GNU_FOLDER/mingw-w64/mingw-w64-crt/configure \ --prefix=$BOOTSTRAP/$ARCH \ --with-sysroot=$BOOTSTRAP/$ARCH \ --host=$ARCH \ @@ -108,12 +94,12 @@ $GNU_FOLDER/mingw-w64-v$MINGW_VERSION/mingw-w64-crt/configure \ --enable-lib64 \ CFLAGS="-Os" \ LDFLAGS="-s" \ - && make \ + && make -j$(nproc) \ && make install mkdir $MAKE_FOLDER/x-winpthreads && cd "$_" -chmod +x $GNU_FOLDER/mingw-w64-v$MINGW_VERSION/mingw-w64-libraries/winpthreads/configure -$GNU_FOLDER/mingw-w64-v$MINGW_VERSION/mingw-w64-libraries/winpthreads/configure \ +chmod +x $GNU_FOLDER/mingw-w64/mingw-w64-libraries/winpthreads/configure +$GNU_FOLDER/mingw-w64/mingw-w64-libraries/winpthreads/configure \ --prefix=$BOOTSTRAP/$ARCH \ --with-sysroot=$BOOTSTRAP/$ARCH \ --host=$ARCH \ @@ -121,17 +107,17 @@ $GNU_FOLDER/mingw-w64-v$MINGW_VERSION/mingw-w64-libraries/winpthreads/configure --disable-shared \ CFLAGS="-Os" \ LDFLAGS="-s" \ - && make \ + && make -j$(nproc) \ && make install -cd $MAKE_FOLDER/x-gcc -make -make install +cd $MAKE_FOLDER/x-gcc \ + && make -j$(nproc) \ + && make install # Cross-compile GCC mkdir $MAKE_FOLDER/binutils && cd "$_" -$GNU_FOLDER/binutils-$BINUTILS_VERSION/configure \ +$GNU_FOLDER/binutils/configure \ --prefix=$BOOTSTRAP \ --with-sysroot=$BOOTSTRAP/$ARCH \ --host=$ARCH \ @@ -140,12 +126,13 @@ $GNU_FOLDER/binutils-$BINUTILS_VERSION/configure \ --with-static-standard-libraries \ CFLAGS="-Os" \ LDFLAGS="-s" \ - && make MAKEINFO=true \ - && make MAKEINFO=true install + && make MAKEINFO=true -j$(nproc) \ + && make MAKEINFO=true install \ + && rm $BOOTSTRAP/bin/elfedit.exe $BOOTSTRAP/bin/readelf.exe mkdir $MAKE_FOLDER/gmp && cd "$_" -chmod +x $GNU_FOLDER/gmp-$GMP_VERSION/configure -$GNU_FOLDER/gmp-$GMP_VERSION/configure \ +chmod +x $GNU_FOLDER/gmp/configure +$GNU_FOLDER/gmp/configure \ --prefix=$BOOTSTRAP \ --host=$ARCH \ --enable-static \ @@ -153,12 +140,12 @@ $GNU_FOLDER/gmp-$GMP_VERSION/configure \ CFLAGS="-Os" \ CXXFLAGS="-Os" \ LDFLAGS="-s" \ - && make \ + && make -j$(nproc) \ && make install mkdir $MAKE_FOLDER/mpfr && cd "$_" -chmod +x $GNU_FOLDER/mpfr-$MPFR_VERSION/configure -$GNU_FOLDER/mpfr-$MPFR_VERSION/configure \ +chmod +x $GNU_FOLDER/mpfr/configure +$GNU_FOLDER/mpfr/configure \ --prefix=$BOOTSTRAP \ --host=$ARCH \ --with-gmp-include=$BOOTSTRAP/include \ @@ -167,12 +154,12 @@ $GNU_FOLDER/mpfr-$MPFR_VERSION/configure \ --disable-shared \ CFLAGS="-Os" \ LDFLAGS="-s" \ - && make \ + && make -j$(nproc) \ && make install mkdir $MAKE_FOLDER/mpc && cd "$_" -chmod +x $GNU_FOLDER/mpc-$MPC_VERSION/configure -$GNU_FOLDER/mpc-$MPC_VERSION/configure \ +chmod +x $GNU_FOLDER/mpc/configure +$GNU_FOLDER/mpc/configure \ --prefix=$BOOTSTRAP \ --host=$ARCH \ --with-gmp-include=$BOOTSTRAP/include \ @@ -183,21 +170,21 @@ $GNU_FOLDER/mpc-$MPC_VERSION/configure \ --disable-shared \ CFLAGS="-Os" \ LDFLAGS="-s" \ - && make \ + && make -j$(nproc) \ && make install mkdir $MAKE_FOLDER/mingw-headers && cd "$_" -chmod +x $GNU_FOLDER/mingw-w64-v$MINGW_VERSION/mingw-w64-headers/configure -$GNU_FOLDER/mingw-w64-v$MINGW_VERSION/mingw-w64-headers/configure \ +chmod +x $GNU_FOLDER/mingw-w64/mingw-w64-headers/configure +$GNU_FOLDER/mingw-w64/mingw-w64-headers/configure \ --prefix=$BOOTSTRAP/$ARCH \ --host=$ARCH \ --with-default-msvcrt=msvcrt-os \ - && make \ + && make -j$(nproc) \ && make install mkdir $MAKE_FOLDER/mingw-crt && cd "$_" -chmod +x $GNU_FOLDER/mingw-w64-v$MINGW_VERSION/mingw-w64-crt/configure -$GNU_FOLDER/mingw-w64-v$MINGW_VERSION/mingw-w64-crt/configure \ +chmod +x $GNU_FOLDER/mingw-w64/mingw-w64-crt/configure +$GNU_FOLDER/mingw-w64/mingw-w64-crt/configure \ --prefix=$BOOTSTRAP/$ARCH \ --with-sysroot=$BOOTSTRAP/$ARCH \ --host=$ARCH \ @@ -207,19 +194,19 @@ $GNU_FOLDER/mingw-w64-v$MINGW_VERSION/mingw-w64-crt/configure \ --enable-lib64 \ CFLAGS="-Os" \ LDFLAGS="-s" \ - && make \ + && make -j$(nproc) \ && make install mkdir $MAKE_FOLDER/winpthreads && cd "$_" -chmod +x $GNU_FOLDER/mingw-w64-v$MINGW_VERSION/mingw-w64-libraries/winpthreads/configure -$GNU_FOLDER/mingw-w64-v$MINGW_VERSION/mingw-w64-libraries/winpthreads/configure \ +chmod +x $GNU_FOLDER/mingw-w64/mingw-w64-libraries/winpthreads/configure +$GNU_FOLDER/mingw-w64/mingw-w64-libraries/winpthreads/configure \ --prefix=$BOOTSTRAP/$ARCH \ --with-sysroot=$BOOTSTRAP/$ARCH \ --host=$ARCH \ --enable-static \ CFLAGS="-Os" \ LDFLAGS="-s" \ - && make \ + && make -j$(nproc) \ && make install mkdir $MAKE_FOLDER/gcc && cd "$_" @@ -240,7 +227,7 @@ $GNU_FOLDER/gcc-$GCC_VERSION/configure \ --with-mpc-lib=$BOOTSTRAP/lib \ --with-mpfr-include=$BOOTSTRAP/include \ --with-mpfr-lib=$BOOTSTRAP/lib \ - --enable-languages=c,c++ \ + --enable-languages=c,c++,fortran \ --enable-libgomp \ --enable-lto \ --enable-threads=posix \ @@ -257,13 +244,13 @@ $GNU_FOLDER/gcc-$GCC_VERSION/configure \ CFLAGS="-Os" \ CXXFLAGS="-Os" \ LDFLAGS="-s" \ - && make \ + && make -j$(nproc) \ && make install \ && $BOOTSTRAP/bin/$ARCH-gcc -DEXE=g++.exe -DCMD=c++ \ -Os -fno-asynchronous-unwind-tables \ -Wl,--gc-sections -s -nostdlib \ -o $BOOTSTRAP/bin/c++.exe \ - $WORKDIR/src/alias.c -lkernel32 + $SOURCE_CODE/alias.c -lkernel32 $BOOTSTRAP/bin/$ARCH-gcc -DEXE=gcc.exe -DCMD=cc \ -Os -fno-asynchronous-unwind-tables -Wl,--gc-sections -s -nostdlib \ @@ -283,67 +270,66 @@ $BOOTSTRAP/bin/$ARCH-gcc -DEXE=gcc.exe -DCMD=cc \ -Wl,--gc-sections -s -nostdlib \ -o $BOOTSTRAP/bin/$ARCH-{}.exe $SOURCE_CODE/alias.c -lkernel32 -mkdir $SOURCE_CODE/mingw-tools-gendef && cd "$_" -cp $SOURCE_CODE/gendef-silent.patch $BOOTSTRAP/src/ -#patch -d $GNU_FOLDER/mingw-w64-v$MINGW_VERSION -p1 <$BOOTSTRAP/src/gendef-silent.patch \ -chmod +x $GNU_FOLDER/mingw-w64-v$MINGW_VERSION/mingw-w64-tools/gendef/configure -$GNU_FOLDER/mingw-w64-v$MINGW_VERSION/mingw-w64-tools/gendef/configure \ +# Build some extra development tools, alongside with the primary development tools + +mkdir $MAKE_FOLDER/mingw-tools-gendef && cd "$_" +patch -d $GNU_FOLDER/mingw-w64 -p1 < $SOURCE_CODE/gendef-silent.patch +chmod +x $GNU_FOLDER/mingw-w64/mingw-w64-tools/gendef/configure +$GNU_FOLDER/mingw-w64/mingw-w64-tools/gendef/configure \ --host=$ARCH \ CFLAGS="-Os" \ LDFLAGS="-s" \ - && make \ + && make -j$(nproc) \ && cp gendef.exe $BOOTSTRAP/bin/ mkdir $MAKE_FOLDER/expat && cd "$_" -chmod +x $GNU_FOLDER/expat-$EXPAT_VERSION/configure -$GNU_FOLDER/expat-$EXPAT_VERSION/configure \ +chmod +x $GNU_FOLDER/expat/configure +$GNU_FOLDER/expat/configure \ --prefix=$BOOTSTRAP \ --host=$ARCH \ CFLAGS="-Os" \ LDFLAGS="-s" \ - && make \ + && make -j$(nproc) \ && make install -cd $GNU_FOLDER/PDCurses-$PDCURSES_VERSION -make -C wincon \ - CC=$BOOTSTRAP/bin/$ARCH-gcc AR=$ARCH-ar CFLAGS="-I.. -Os -DPDC_WIDE" pdcurses.a \ +cd $GNU_FOLDER/pdcurses +make -j$(nproc) -C wincon CC=$BOOTSTRAP/bin/$ARCH-gcc AR=$ARCH-ar CFLAGS="-I.. -Os -DPDC_WIDE" pdcurses.a \ && cp wincon/pdcurses.a $BOOTSTRAP/lib/libcurses.a \ && cp curses.h $BOOTSTRAP/include mkdir $MAKE_FOLDER/libiconv && cd "$_" -chmod +x $GNU_FOLDER/libiconv-$LIBICONV_VERSION/configure -$GNU_FOLDER/libiconv-$LIBICONV_VERSION/configure \ +chmod +x $GNU_FOLDER/libiconv/configure +$GNU_FOLDER/libiconv/configure \ --prefix=$BOOTSTRAP \ --host=$ARCH \ --disable-nls \ --disable-shared \ CFLAGS="-Os" \ LDFLAGS="-s" \ - && make \ + && make -j$(nproc) \ && make install mkdir $MAKE_FOLDER/gdb && cd "$_" -cp $SOURCE_CODE/gdb-*.patch $BOOTSTRAP/src/ -#cat $SOURCE_CODE/gdb-*.patch | patch -d $GNU_FOLDER/gdb-$GDB_VERSION -p1 \ -# && sed -i 's/quiet = 0/quiet = 1/' $GNU_FOLDER/gdb-$GDB_VERSION/gdb/main.c \ -chmod +x $GNU_FOLDER/gdb-$GDB_VERSION/configure -$GNU_FOLDER/gdb-$GDB_VERSION/configure \ +cat $SOURCE_CODE/gdb-*.patch | patch -d $GNU_FOLDER/gdb -p1 \ + && sed -i 's/quiet = 0/quiet = 1/' $GNU_FOLDER/gdb/gdb/main.c +chmod +x $GNU_FOLDER/gdb/configure +$GNU_FOLDER/gdb/configure \ --host=$ARCH \ --enable-tui \ CFLAGS="-Os -DPDC_WIDE -I$BOOTSTRAP/include" \ CXXFLAGS="-Os -DPDC_WIDE -I$BOOTSTRAP/include" \ LDFLAGS="-s -L$BOOTSTRAP/lib" \ - && make MAKEINFO=true \ + && make MAKEINFO=true -j$(nproc) \ && cp gdb/.libs/gdb.exe gdbserver/gdbserver.exe $BOOTSTRAP/bin/ mkdir $MAKE_FOLDER/make && cd "$_" -chmod +x $GNU_FOLDER/make-$MAKE_VERSION/configure -$GNU_FOLDER/make-$MAKE_VERSION/configure \ +chmod +x $GNU_FOLDER/make/configure +$GNU_FOLDER/make/configure \ --host=$ARCH \ --disable-nls \ CFLAGS="-Os" \ LDFLAGS="-s" \ - && make \ + && make -j$(nproc) \ && cp make.exe $BOOTSTRAP/bin/ \ && $BOOTSTRAP/bin/$ARCH-gcc -DEXE=make.exe -DCMD=make \ -Os -fno-asynchronous-unwind-tables \ @@ -351,7 +337,6 @@ $GNU_FOLDER/make-$MAKE_VERSION/configure \ -o $BOOTSTRAP/bin/mingw32-make.exe $SOURCE_CODE/alias.c -lkernel32 cd $GNU_FOLDER/busybox-w32 -#cp $SOURCE_CODE/busybox-* $BOOTSTRAP/src/ cat $SOURCE_CODE/busybox-*.patch | patch -p1 make mingw64_defconfig \ && sed -ri 's/^(CONFIG_AR)=y/\1=n/' .config \ @@ -369,12 +354,11 @@ make mingw64_defconfig \ && sed -ri 's/^(CONFIG_UNLINK)=y/\1=n/' .config \ && sed -ri 's/^(CONFIG_VI)=y/\1=n/' .config \ && sed -ri 's/^(CONFIG_XXD)=y/\1=n/' .config \ - && make CROSS_COMPILE=$ARCH- \ + && make -j$(nproc) CROSS_COMPILE=$ARCH- \ CONFIG_EXTRA_CFLAGS="-D_WIN32_WINNT=0x502" \ && cp busybox.exe $BOOTSTRAP/bin/ cd $BOOTSTRAP/bin - $BOOTSTRAP/bin/$ARCH-gcc -Os -fno-asynchronous-unwind-tables -Wl,--gc-sections -s \ -nostdlib -o alias.exe $SOURCE_CODE/busybox-alias.c -lkernel32 \ && printf '%s\n' arch ash awk base32 base64 basename bash bc bunzip2 bzcat \ From 8740b194c5fee0ffb3b43434a5bfff96d71e3027 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 15:07:46 +0700 Subject: [PATCH 21/36] update nasm --- .gitmodules | 3 +++ nasm | 1 + 2 files changed, 4 insertions(+) create mode 160000 nasm diff --git a/.gitmodules b/.gitmodules index 7028a1832..d042f6931 100644 --- a/.gitmodules +++ b/.gitmodules @@ -43,3 +43,6 @@ [submodule "7z"] path = 7z url = https://github.com/tfslabs/7z.git +[submodule "nasm"] + path = nasm + url = https://github.com/tfslabs/nasm.git diff --git a/nasm b/nasm new file mode 160000 index 000000000..bb1c80a39 --- /dev/null +++ b/nasm @@ -0,0 +1 @@ +Subproject commit bb1c80a3913bd2b31d7f48e74ac654ecd38a91a0 From be66831cfa15e6ed55cc9e75bc82a2dceb46d51e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 15:31:17 +0700 Subject: [PATCH 22/36] update cppcheck --- .gitmodules | 3 +++ cppcheck | 1 + 2 files changed, 4 insertions(+) create mode 160000 cppcheck diff --git a/.gitmodules b/.gitmodules index d042f6931..5e1743251 100644 --- a/.gitmodules +++ b/.gitmodules @@ -46,3 +46,6 @@ [submodule "nasm"] path = nasm url = https://github.com/tfslabs/nasm.git +[submodule "cppcheck"] + path = cppcheck + url = https://github.com/tfslabs/cppcheck.git diff --git a/cppcheck b/cppcheck new file mode 160000 index 000000000..036c5091b --- /dev/null +++ b/cppcheck @@ -0,0 +1 @@ +Subproject commit 036c5091b50532401d02666c46e5641df19681ab From cb7f31ef682753ddd459e673a380c813714ceccc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 15:33:55 +0700 Subject: [PATCH 23/36] update cppcheck patches --- .gnu-windows/src/cppcheck-gcc13.patch | 18 ++++++++++++++++++ .gnu-windows/src/cppcheck-quiet.patch | 7 +++++++ .gnu-windows/src/cppcheck.mak | 8 ++++++++ 3 files changed, 33 insertions(+) create mode 100644 .gnu-windows/src/cppcheck-gcc13.patch create mode 100644 .gnu-windows/src/cppcheck-quiet.patch create mode 100644 .gnu-windows/src/cppcheck.mak diff --git a/.gnu-windows/src/cppcheck-gcc13.patch b/.gnu-windows/src/cppcheck-gcc13.patch new file mode 100644 index 000000000..4e4953a9b --- /dev/null +++ b/.gnu-windows/src/cppcheck-gcc13.patch @@ -0,0 +1,18 @@ +GCC 13 has stricter allocator checks: +https://gcc.gnu.org/gcc-13/porting_to.html + +Also, libstdc++ no longer leaks stdint.h definitions. +--- a/lib/mathlib.cpp ++++ b/lib/mathlib.cpp +@@ -25,2 +25,3 @@ + #include ++#include + #include +--- a/lib/smallvector.h ++++ b/lib/smallvector.h +@@ -43,2 +43,5 @@ + {} ++ ++ template TaggedAllocator(const TaggedAllocator); ++ template struct rebind { using other = TaggedAllocator; }; + }; diff --git a/.gnu-windows/src/cppcheck-quiet.patch b/.gnu-windows/src/cppcheck-quiet.patch new file mode 100644 index 000000000..b47189911 --- /dev/null +++ b/.gnu-windows/src/cppcheck-quiet.patch @@ -0,0 +1,7 @@ +--- a/cli/cmdlineparser.cpp ++++ b/cli/cmdlineparser.cpp +@@ -131,3 +131,3 @@ + #if defined(_WIN64) || defined(_WIN32) +-bool CmdLineParser::SHOW_DEF_PLATFORM_MSG = true; ++bool CmdLineParser::SHOW_DEF_PLATFORM_MSG = false; + #endif diff --git a/.gnu-windows/src/cppcheck.mak b/.gnu-windows/src/cppcheck.mak new file mode 100644 index 000000000..e7ae46b47 --- /dev/null +++ b/.gnu-windows/src/cppcheck.mak @@ -0,0 +1,8 @@ +ext := $(shell find externals -mindepth 1 -type d) +src := $(shell find cli lib externals -name '*.cpp') +obj := $(src:.cpp=.o) +CXXFLAGS := -w -Os -Ilib $(addprefix -I,$(ext)) +cppcheck.exe: $(obj) + $(CXX) -s -o $@ $(obj) -lshlwapi +cppcheck: $(obj) + $(CXX) -pthread -s -o $@ $(obj) From 7d000887e18c3fe87d474a6f70dc7417eb778249 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 15:53:17 +0700 Subject: [PATCH 24/36] ren --- .gnu-windows/src/gnu-windows.ico | Bin 0 -> 7466 bytes .../src/{w64devkit.ini => gnu-windows.ini} | 0 .gnu-windows/src/w64devkit.c | 575 ------------------ .gnu-windows/src/w64devkit.ico | Bin 16131 -> 0 bytes 4 files changed, 575 deletions(-) create mode 100644 .gnu-windows/src/gnu-windows.ico rename .gnu-windows/src/{w64devkit.ini => gnu-windows.ini} (100%) delete mode 100644 .gnu-windows/src/w64devkit.c delete mode 100644 .gnu-windows/src/w64devkit.ico diff --git a/.gnu-windows/src/gnu-windows.ico b/.gnu-windows/src/gnu-windows.ico new file mode 100644 index 0000000000000000000000000000000000000000..b68828d1a9d85c1d6c37259f33913d1e76f03afb GIT binary patch literal 7466 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 & (align - 1); - if (count > (a->end - a->beg - padding)/objsize) { - outofmemory(); - } - size total = count*objsize; - byte *p = a->end -= total + padding; - for (size i = 0; i < total; i++) { - p[i] = 0; - } - return p; -} - -typedef struct { - byte *base; - arena perm; - arena scratch; -} memory; - -static memory newmemory(size cap) -{ - memory r = {}; - r.base = VirtualAlloc(0, cap, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); - if (!r.base) return r; - r.perm.beg = r.base; - r.perm.end = r.base + cap/2; - r.scratch.beg = r.base + cap/2; - r.scratch.end = r.base + cap; - return r; -} - -static void freememory(memory m) -{ - VirtualFree(m.base, 0, MEM_RELEASE); -} - -static i32 truncsize(size len) -{ - i32 max = 0x7fffffff; - return len>max ? max : (i32)len; -} - -typedef enum { - INI_eof, - INI_section, - INI_key, - INI_value -} initype; - -typedef struct { - s8 name; - initype type; -} initoken; - -typedef struct { - u8 *beg; - u8 *end; - b32 invalue; -} iniparser; - -static b32 inidone(iniparser *p) -{ - return p->beg == p->end; -} - -static u8 ininext(iniparser *p) -{ - return *p->beg++; -} - -static b32 iniblank(u8 c) -{ - return c==' ' || c=='\t' || c=='\r'; -} - -static void iniskip(iniparser *p) -{ - for (; !inidone(p) && iniblank(*p->beg); p->beg++) {} -} - -static u8 *initok(iniparser *p, u8 term) -{ - u8 *end = p->beg; - while (!inidone(p)) { - u8 c = ininext(p); - if (c == term) { - return end; - } else if (c == '\n') { - break; - } else if (!iniblank(c)) { - end = p->beg; - } - } - return term=='\n' ? end : 0; -} - -static b32 iniquoted(s8 s) -{ - return s.len>1 && s.s[0]=='"' && s.s[s.len-1]=='"'; -} - -// Parses like GetPrivateProfileString except sections cannot contain -// newlines. Invalid input lines are ignored. Comment lines begin with -// ';' following any whitespace. No trailing comments. Trims leading and -// trailing whitespace from sections, keys, and values. To preserve -// whitespace, values may be double-quoted. No quote escapes. Content on -// a line following a closing section ']' is ignored. Token encoding -// matches input encoding. An INI_value always follows an INI_key key. -static initoken iniparse(iniparser *p) -{ - initoken r = {}; - - if (p->invalue) { - p->invalue = 0; - iniskip(p); - u8 *beg = p->beg; - u8 *end = initok(p, '\n'); - r.name = s8span(beg, end); - r.type = INI_value; - if (iniquoted(r.name)) { - r.name.s++; - r.name.len -= 2; - } - return r; - } - - for (;;) { - iniskip(p); - if (inidone(p)) { - return r; - } - - u8 *end; - u8 *beg = p->beg; - switch (ininext(p)) { - case ';': - while (!inidone(p) && ininext(p)!='\n') {} - break; - - case '[': - iniskip(p); - beg = p->beg; - end = initok(p, ']'); - if (end) { - // skip over anything else on the line - while (!inidone(p) && ininext(p)!='\n') {} - r.name = s8span(beg, end); - r.type = INI_section; - return r; - } - break; - - case '\n': - break; - - default: - end = initok(p, '='); - if (end) { - p->invalue = 1; - r.name = s8span(beg, end); - r.type = INI_key; - return r; - } - } - } -} - -typedef enum { - sym_null = 0, - sym_w64devkit, - sym_home, - sym_title, -} symbol; - -static symbol intern(s8 s) -{ - static struct { - s8 name; - symbol symbol; - } symbols[] = { - {S("w64devkit"), sym_w64devkit}, - {S("home"), sym_home}, - {S("title"), sym_title}, - }; - for (size i = 0; i < countof(symbols); i++) { - if (s8equals(symbols[i].name, s)) { - return symbols[i].symbol; - } - } - return sym_null; -} - -static c16 *expandvalue(s8 value, arena *perm, arena scratch) -{ - assert(value.len < 0x7fffffff); - - // First temporarily convert to a null-terminated wide string - i32 len = MultiByteToWideChar(CP_UTF8, 0, value.s, (i32)value.len, 0, 0); - if (len == 0x7fffffff) outofmemory(); - s16 w = {}; - w.len = len + 1; // append null terminator - w.s = new(&scratch, c16, w.len); - MultiByteToWideChar(CP_UTF8, 0, value.s, (i32)value.len, w.s, len); - - len = ExpandEnvironmentStringsW(w.s, 0, 0); - if (len < 0) outofmemory(); - c16 *r = new(perm, c16, len); - ExpandEnvironmentStringsW(w.s, r, len); - return r; -} - -// Expand to a full path via GetFullPathNameW. -static c16 *tofullpath(c16 *path, arena *perm) -{ - i32 len = GetFullPathNameW(path, 0, 0, 0); - if (len < 0) outofmemory(); - c16 *r = new(perm, c16, len); - GetFullPathNameW(path, len, r, 0); - return r; -} - -static s8 loadfile(c16 *path, arena *perm) -{ - s8 r = {}; - - handle h = CreateFileW( - path, - GENERIC_READ, - FILE_SHARE_ALL, - 0, - OPEN_EXISTING, - 0, - 0 - ); - if (h == (handle)-1) { - return r; - } - - r.s = (u8 *)perm->beg; - r.len = truncsize((perm->end - perm->beg)/sizeof(u8)); - i32 len; - b32 ok = ReadFile(h, r.s, (i32)r.len, &len, 0); - CloseHandle(h); - r.len = len; - r.s = ok ? r.s : 0; - perm->beg += r.len / sizeof(u8); - return r; -} - -typedef struct { - c16 *home; - c16 *title; - b32 ok; -} config; - -static config newconfig(void) -{ - config r = {}; - r.title = u"w64devkit"; - return r; -} - -// Read entries from w64devkit.ini. Expands environment variables, and -// if "home" is relative, converts it to an absolute path. Before the -// call, the working directory must be location of w64devkit.exe. -static config loadconfig(arena *perm, arena scratch) -{ - config conf = newconfig(); - - s8 ini = loadfile(u"w64devkit.ini", &scratch); - if (!ini.s) return conf; - - iniparser *p = new(&scratch, iniparser, 1); - p->beg = ini.s; - p->end = ini.s + ini.len; - - for (symbol section = 0, key = 0;;) { - initoken t = iniparse(p); - switch (t.type) { - case INI_eof: - conf.ok = 1; - return conf; - case INI_section: - section = intern(t.name); - break; - case INI_key: - key = intern(t.name); - break; - case INI_value: - if (section == sym_w64devkit) { - if (!conf.home && key==sym_home) { - arena temp = scratch; - conf.home = expandvalue(t.name, &temp, *perm); - conf.home = tofullpath(conf.home, perm); - } else if (key == sym_title) { - conf.title = expandvalue(t.name, perm, scratch); - } - } - break; - } - } -} - -typedef struct { - c16 *buf; - size cap; - size len; - b32 err; -} buf16; - -static buf16 newbuf16(arena *a, size cap) -{ - buf16 buf = {}; - buf.buf = new(a, c16, cap); - buf.cap = cap; - return buf; -} - -static void buf16cat(buf16 *buf, s16 s) -{ - size avail = buf->cap - buf->len; - size count = s.lenbuf + buf->len; - for (size i = 0; i < count; i++) { - dst[i] = s.s[i]; - } - buf->len += count; - buf->err |= count < s.len; -} - -static void buf16c16(buf16 *buf, c16 c) -{ - s16 s = {&c, 1}; - buf16cat(buf, s); -} - -static void buf16moduledir(buf16 *buf, arena scratch) -{ - // GetFullPathNameW does not allow querying the output size, instead - // indicating whether or not the buffer was large enough. So simply - // offer the entire scratch buffer, then crop out the actual result. - scratch.beg += -(uptr)scratch.beg & (sizeof(c16) - 1); // align - i32 len = truncsize((scratch.end - scratch.beg)/sizeof(c16)); - s16 path = {}; - path.s = (c16 *)scratch.beg; - path.len = GetModuleFileNameW(0, path.s, len); - if (len == path.len) outofmemory(); - for (; path.len; path.len--) { - switch (path.s[path.len-1]) { - case '/': - case '\\': path.len--; - buf16cat(buf, path); - return; - } - } -} - -static void buf16getenv(buf16 *buf, c16 *key, arena scratch) -{ - i32 len = GetEnvironmentVariableW(key, 0, 0); - if (len < 0) outofmemory(); - s16 var = {}; - var.s = new(&scratch, c16, len); - var.len = GetEnvironmentVariableW(key, var.s, len); - buf16cat(buf, var); -} - -static void toslashes(c16 *path) -{ - for (size i = 0; i < path[i]; i++) { - path[i] = path[i]=='\\' ? '/' : path[i]; - } -} - -static u32 w64devkit(void) -{ - memory mem = newmemory(1<<22); - if (!mem.base) { - fatal(u"Out of memory on startup"); - } - arena *perm = &mem.perm; - arena scratch = mem.scratch; - - // First load the module directory into the fresh buffer, and use it - // for a few different operations. - buf16 path = newbuf16(perm, MAX_ENVVAR); - buf16moduledir(&path, scratch); - buf16 moduledir = path; // to truncate back to the module dir - - buf16c16(&path, 0); // null terminator - SetEnvironmentVariableW(u"W64DEVKIT_HOME", path.buf); // ignore errors - - #ifdef VERSION - #define LSTR(s) XSTR(s) - #define XSTR(s) u ## # s - SetEnvironmentVariableW(u"W64DEVKIT", LSTR(VERSION)); // ignore errors - #endif - - // Maybe set HOME from w64devkit.ini - config conf = newconfig(); - if (SetCurrentDirectoryW(path.buf)) { - conf = loadconfig(perm, scratch); - if (conf.home) { - toslashes(conf.home); - SetEnvironmentVariableW(u"HOME", conf.home); // ignore errors - } - } - - // Continue building PATH - path = moduledir; - buf16cat(&path, U(u"\\bin;")); - buf16getenv(&path, u"PATH", scratch); - buf16c16(&path, 0); // null terminator - if (path.err || !SetEnvironmentVariableW(u"PATH", path.buf)) { - fatal(u"Failed to configure $PATH"); - } - - // Set the console title as late as possible, but not after starting - // the shell because .profile might change it. - if (conf.title) { - SetConsoleTitleW(conf.title); // ignore errors - } - - path = moduledir; - buf16cat(&path, U(u"\\bin\\busybox.exe")); - buf16c16(&path, 0); // null terminator - - // Start a BusyBox login shell - si si = {}; - si.cb = sizeof(si); - pi pi; - c16 cmdline[] = u"sh -l"; // NOTE: must be mutable! - if (!CreateProcessW(path.buf, cmdline, 0, 0, 1, 0, 0, 0, &si, &pi)) { - fatal(u"Failed to launch a login shell"); - } - - // Wait for shell to exit - freememory(mem); - u32 ret; - WaitForSingleObject(pi.process, -1); - GetExitCodeProcess(pi.process, &ret); - return ret; -} - -__attribute((force_align_arg_pointer)) -void mainCRTStartup(void) -{ - u32 r = w64devkit(); - ExitProcess(r); -} diff --git a/.gnu-windows/src/w64devkit.ico b/.gnu-windows/src/w64devkit.ico deleted file mode 100644 index 9403bc941f5617cbb94bd20fc0d5639b13e12cae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16131 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 M4ZTr+Ho@}$3)wNKrT_o{ From 3fad4c0eb3b9435bfd335f1ddb5f481a36967798 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 15:53:22 +0700 Subject: [PATCH 25/36] Update build.sh --- .gnu-windows/build.sh | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/.gnu-windows/build.sh b/.gnu-windows/build.sh index dd3b5d7c5..7ba61e0fb 100644 --- a/.gnu-windows/build.sh +++ b/.gnu-windows/build.sh @@ -396,31 +396,29 @@ ARCH= make -f Make_ming.mak \ '$VIMRUNTIME/tutor/tutor' '%TMP%/tutor%RANDOM%' \ >$BOOTSTRAP/bin/vimtutor.bat -# NOTE: nasm's configure script is broken, so no out-of-source build -chmod +x $GNU_FOLDER/nasm-$NASM_VERSION/configure && chmod +x $GNU_FOLDER/nasm-$NASM_VERSION/autogen.sh -cd $GNU_FOLDER/nasm-$NASM_VERSION/ -$GNU_FOLDER/nasm-$NASM_VERSION/autogen.sh -mkdir $MAKE_FOLDER/nasm-$NASM_VERSION && cd "$_" +chmod +x $GNU_FOLDER/nasm/configure && chmod +x $GNU_FOLDER/nasm/autogen.sh +cd $GNU_FOLDER/nasm/ +$GNU_FOLDER/nasm/autogen.sh +mkdir $MAKE_FOLDER/nasm && cd "$_" $GNU_FOLDER/nasm-$NASM_VERSION/configure \ --host=$ARCH \ CFLAGS="-Os" \ LDFLAGS="-s" \ && mkdir include \ - && make \ + && make -j$(nproc) \ && cp nasm.exe ndisasm.exe $BOOTSTRAP/bin -cd $GNU_FOLDER/ctags-$CTAGS_VERSION -sed -i RT_MANIFEST/d win32/ctags.rc \ - && make -f mk_mingw.mak CC=gcc packcc.exe \ - && make -f mk_mingw.mak \ +cd $GNU_FOLDER/ctags +sed -i /RT_MANIFEST/d win32/ctags.rc \ + && make -j$(nproc) -f mk_mingw.mak CC=gcc packcc.exe \ + && make -j$(nproc) -f mk_mingw.mak \ CC=$BOOTSTRAP/bin/$ARCH-gcc WINDRES=$ARCH-windres \ OPT= CFLAGS=-Os LDFLAGS=-s \ && cp ctags.exe $BOOTSTRAP/bin/ -cd $GNU_FOLDER/cppcheck-$CPPCHECK_VERSION -cp $SOURCE_CODE/cppcheck* $BOOTSTRAP/src/ -cat $BOOTSTRAP/src/cppcheck-*.patch | patch -p1 \ - && make -f $BOOTSTRAP/src/cppcheck.mak CXX=$ARCH-g++ \ +cd $GNU_FOLDER/cppcheck +cat $SOURCE_CODE/cppcheck-*.patch | patch -p1 \ + && make -f $SOURCE_CODE/cppcheck.mak CXX=$ARCH-g++ \ && mkdir $BOOTSTRAP/share/cppcheck/ \ && cp -r cppcheck.exe cfg/ $BOOTSTRAP/share/cppcheck \ && $BOOTSTRAP/bin/$ARCH-gcc -DEXE=../share/cppcheck/cppcheck.exe -DCMD=cppcheck \ @@ -432,8 +430,7 @@ cat $BOOTSTRAP/src/cppcheck-*.patch | patch -p1 \ cd $WORKDIR -cp -r $SOURCE_CODE/* $BOOTSTRAP/src #?? -printf "id ICON \"$BOOTSTRAP/src/gnu-windows.ico\"" >gnu-windows.rc \ +printf "id ICON \"$SOURCE_CODE/gnu-windows.ico\"" > gnu-windows.rc \ && $BOOTSTRAP/bin/$ARCH-windres -o gnu-windows.o gnu-windows.rc \ && $BOOTSTRAP/bin/$ARCH-gcc \ -Os -fno-asynchronous-unwind-tables \ @@ -461,6 +458,8 @@ printf "id ICON \"$BOOTSTRAP/src/gnu-windows.ico\"" >gnu-windows.rc \ cd $WORKDIR -cp $BOOTSTRAP/$ARCH/bin/libwinpthread-1.dll $BOOTSTRAP/bin/libwinpthread-1.dll +# Copy all executable from $ARCH into the primary folder +cp $BOOTSTRAP/$ARCH/bin/*.dll $BOOTSTRAP/bin +cp $BOOTSTRAP/$ARCH/bin/*.exe $BOOTSTRAP/bin echo -e -n "Build sucessfully. Your GNU Windows is under path: $BOOTSTRAP" From 89913606f100f588b311e728edcb863ab27155eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 15:54:09 +0700 Subject: [PATCH 26/36] Update build.sh --- .gnu-windows/build.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gnu-windows/build.sh b/.gnu-windows/build.sh index 7ba61e0fb..3dc205eb3 100644 --- a/.gnu-windows/build.sh +++ b/.gnu-windows/build.sh @@ -425,8 +425,7 @@ cat $SOURCE_CODE/cppcheck-*.patch | patch -p1 \ -Os -fno-asynchronous-unwind-tables -Wl,--gc-sections -s -nostdlib \ -o $BOOTSTRAP/bin/cppcheck.exe $SOURCE_CODE/alias.c -lkernel32 - -#pack-up +# Pack up new executables cd $WORKDIR From d4ce1ee88d29f44e5e7658fa1e6aca29f8a18b05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 15:56:44 +0700 Subject: [PATCH 27/36] Update cppcheck --- cppcheck | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cppcheck b/cppcheck index 036c5091b..6813edd69 160000 --- a/cppcheck +++ b/cppcheck @@ -1 +1 @@ -Subproject commit 036c5091b50532401d02666c46e5641df19681ab +Subproject commit 6813edd69248ec49b4706f195eb8830b75738ad2 From 458ed99c9e6574748fa1c2901927e20606c81722 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 15:56:49 +0700 Subject: [PATCH 28/36] Update run_admin.sh --- .admin/run_admin.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.admin/run_admin.sh b/.admin/run_admin.sh index 45b0c6f32..00cca5389 100644 --- a/.admin/run_admin.sh +++ b/.admin/run_admin.sh @@ -7,6 +7,7 @@ WORKDIR="$(cd "$(dirname "$0")" && pwd)" BINUTILS_VERSION=2.42 BUSYBOX_VERSION=FRP-5467-g9376eebd8 CTAGS_VERSION=6.0.0 +CPPCHECK_VERSION=2.10 EXPAT_VERSION=2.6.2 GCC_VERSION=14.2.0 GDB_VERSION=15.1 @@ -16,8 +17,10 @@ MAKE_VERSION=4.4.1 MINGW_VERSION=12.0.0 MPC_VERSION=1.3.1 MPFR_VERSION=4.2.1 +NASM_VERSION=2.15.05rc2 PDCURSES_VERSION=3.9 VIM_VERSION=9.0 Z7_VERSION=2301 + VERSION=1.0.0-hf1 From 09f99300695db76f60b88503792af60b65656d44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 16:01:30 +0700 Subject: [PATCH 29/36] Update run_admin.sh --- .admin/run_admin.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.admin/run_admin.sh b/.admin/run_admin.sh index 00cca5389..d42aac57d 100644 --- a/.admin/run_admin.sh +++ b/.admin/run_admin.sh @@ -23,4 +23,5 @@ VIM_VERSION=9.0 Z7_VERSION=2301 -VERSION=1.0.0-hf1 +VERSION=1.1.0 + From f928de4442ba9eca5462e3e2a04fc54ebb3309e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 20:31:22 +0700 Subject: [PATCH 30/36] Delete busybox-w32 --- busybox-w32 | 1 - 1 file changed, 1 deletion(-) delete mode 160000 busybox-w32 diff --git a/busybox-w32 b/busybox-w32 deleted file mode 160000 index 97be75c05..000000000 --- a/busybox-w32 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 97be75c055259baadb6c1ad50d4f0bca94ebb680 From 63d1eb6b2003cae26175cf874827abb26d224bf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 20:33:22 +0700 Subject: [PATCH 31/36] Create busybox-w32 --- busybox-w32 | 1 + 1 file changed, 1 insertion(+) create mode 160000 busybox-w32 diff --git a/busybox-w32 b/busybox-w32 new file mode 160000 index 000000000..0ed1aea53 --- /dev/null +++ b/busybox-w32 @@ -0,0 +1 @@ +Subproject commit 0ed1aea532ce9b523e32c0e7841bcaea986a0371 From 584a01be04a82c2dbf8a8994bc38e6a7a33f8db0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 20:58:18 +0700 Subject: [PATCH 32/36] Delete nasm --- nasm | 1 - 1 file changed, 1 deletion(-) delete mode 160000 nasm diff --git a/nasm b/nasm deleted file mode 160000 index bb1c80a39..000000000 --- a/nasm +++ /dev/null @@ -1 +0,0 @@ -Subproject commit bb1c80a3913bd2b31d7f48e74ac654ecd38a91a0 From f28263b18037f9e90dd74638015b0f439739f942 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 21:00:05 +0700 Subject: [PATCH 33/36] Create nasm --- nasm | 1 + 1 file changed, 1 insertion(+) create mode 160000 nasm diff --git a/nasm b/nasm new file mode 160000 index 000000000..85b4eb6ab --- /dev/null +++ b/nasm @@ -0,0 +1 @@ +Subproject commit 85b4eb6abc59284319d0ac72c659d6a05f83e25f From c1b15edd5659c48005d046d8db9a4034fe4f576d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 22:19:17 +0700 Subject: [PATCH 34/36] Update build.sh --- .gnu-windows/build.sh | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/.gnu-windows/build.sh b/.gnu-windows/build.sh index 3dc205eb3..247c3ae00 100644 --- a/.gnu-windows/build.sh +++ b/.gnu-windows/build.sh @@ -210,8 +210,8 @@ $GNU_FOLDER/mingw-w64/mingw-w64-libraries/winpthreads/configure \ && make install mkdir $MAKE_FOLDER/gcc && cd "$_" -chmod +x $GNU_FOLDER/gcc-$GCC_VERSION/configure -$GNU_FOLDER/gcc-$GCC_VERSION/configure \ +chmod +x $GNU_FOLDER/gcc/configure +$GNU_FOLDER/gcc/configure \ --prefix=$BOOTSTRAP \ --with-sysroot=$BOOTSTRAP/$ARCH \ --with-native-system-header-dir=/include \ @@ -287,10 +287,11 @@ chmod +x $GNU_FOLDER/expat/configure $GNU_FOLDER/expat/configure \ --prefix=$BOOTSTRAP \ --host=$ARCH \ + --disable-shared \ CFLAGS="-Os" \ LDFLAGS="-s" \ - && make -j$(nproc) \ - && make install + && make -k -j$(nproc) \ + && make -k install cd $GNU_FOLDER/pdcurses make -j$(nproc) -C wincon CC=$BOOTSTRAP/bin/$ARCH-gcc AR=$ARCH-ar CFLAGS="-I.. -Os -DPDC_WIDE" pdcurses.a \ @@ -338,7 +339,7 @@ $GNU_FOLDER/make/configure \ cd $GNU_FOLDER/busybox-w32 cat $SOURCE_CODE/busybox-*.patch | patch -p1 -make mingw64_defconfig \ +make mingw64u_defconfig \ && sed -ri 's/^(CONFIG_AR)=y/\1=n/' .config \ && sed -ri 's/^(CONFIG_ASCII)=y/\1=n/' .config \ && sed -ri 's/^(CONFIG_DPKG\w*)=y/\1=n/' .config \ @@ -376,7 +377,7 @@ $BOOTSTRAP/bin/$ARCH-gcc -Os -fno-asynchronous-unwind-tables -Wl,--gc-sections - wc wget which whoami whois xargs xz xzcat yes zcat \ | xargs -I{} cp alias.exe $BOOTSTRAP/bin/{}.exe -cd $GNU_FOLDER/vim90/src +cd $GNU_FOLDER/vim/src ARCH= make -f Make_ming.mak \ OPTIMIZE=SIZE STATIC_STDCPLUS=yes HAS_GCC_EH=no \ UNDER_CYGWIN=yes CROSS=yes CROSS_COMPILE=$ARCH- \ @@ -396,15 +397,14 @@ ARCH= make -f Make_ming.mak \ '$VIMRUNTIME/tutor/tutor' '%TMP%/tutor%RANDOM%' \ >$BOOTSTRAP/bin/vimtutor.bat -chmod +x $GNU_FOLDER/nasm/configure && chmod +x $GNU_FOLDER/nasm/autogen.sh cd $GNU_FOLDER/nasm/ +chmod +x $GNU_FOLDER/nasm/autogen.sh $GNU_FOLDER/nasm/autogen.sh -mkdir $MAKE_FOLDER/nasm && cd "$_" -$GNU_FOLDER/nasm-$NASM_VERSION/configure \ - --host=$ARCH \ - CFLAGS="-Os" \ - LDFLAGS="-s" \ - && mkdir include \ +$GNU_FOLDER/nasm/configure \ + --prefix=$BOOTSTRAP \ + --host=$ARCH \ + CFLAGS="-Os" \ + LDFLAGS="-s" \ && make -j$(nproc) \ && cp nasm.exe ndisasm.exe $BOOTSTRAP/bin From 6bd416e8c387c9d560fbf3d4cd17e5fe3ccf29c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 22:33:23 +0700 Subject: [PATCH 35/36] Update .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 3c59d5cc2..d6804d307 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ .gnu-windows/make .gnu-windows/ad-installer *.exe -*.dll \ No newline at end of file +*.dll +.gnu-windows/gnu-windows.rc From 7bbadcab8ee2dcdb186b9e8f85eae0d35773785c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E3=81=84=E3=81=AD=E3=81=93?= Date: Sat, 26 Oct 2024 22:43:54 +0700 Subject: [PATCH 36/36] Update build.sh --- .gnu-windows/build.sh | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.gnu-windows/build.sh b/.gnu-windows/build.sh index 247c3ae00..96a422446 100644 --- a/.gnu-windows/build.sh +++ b/.gnu-windows/build.sh @@ -282,16 +282,22 @@ $GNU_FOLDER/mingw-w64/mingw-w64-tools/gendef/configure \ && make -j$(nproc) \ && cp gendef.exe $BOOTSTRAP/bin/ -mkdir $MAKE_FOLDER/expat && cd "$_" +cd $GNU_FOLDER/expat chmod +x $GNU_FOLDER/expat/configure $GNU_FOLDER/expat/configure \ --prefix=$BOOTSTRAP \ --host=$ARCH \ + CPPFLAGS=-DXML_UNICODE \ + --without-xmlwf \ --disable-shared \ + --without-docbook \ + --without-examples \ + --without-tests \ + --disable-xml-context \ CFLAGS="-Os" \ LDFLAGS="-s" \ - && make -k -j$(nproc) \ - && make -k install + && make -j$(nproc) \ + && make install cd $GNU_FOLDER/pdcurses make -j$(nproc) -C wincon CC=$BOOTSTRAP/bin/$ARCH-gcc AR=$ARCH-ar CFLAGS="-I.. -Os -DPDC_WIDE" pdcurses.a \