diff --git a/Makefile.in b/Makefile.in index 7461328..a7dc02a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -19,6 +19,11 @@ BINUTILS_URL = https://ftp.gnu.org/gnu/binutils/$(BINUTILS_VERS GCC_URL = https://ftp.gnu.org/gnu/gcc/$(GCC_VERSION)/$(GCC_VERSION).tar.xz NEWLIB_URL = https://sourceware.org/pub/newlib/$(NEWLIB_VERSION).tar.gz GDB_URL = https://ftp.gnu.org/gnu/gdb/$(GDB_VERSION).tar.xz +N64_TOOLCHAIN_ARCHIVE_DIR = @N64_TOOLCHAIN_ARCHIVE_DIR@ +BINUTILS_ARCHIVE = @BINUTILS_ARCHIVE@ +GCC_ARCHIVE = @GCC_ARCHIVE@ +NEWLIB_ARCHIVE = @NEWLIB_ARCHIVE@ +GDB_ARCHIVE = @GDB_ARCHIVE@ BINUTILS_SUBDIRS = bfd binutils cpu gas ld libctf libsframe opcodes NEWLIB_SUBDIRS = libgloss newlib GDB_SUBDIRS = gdb gdbsupport gnulib readline sim @@ -27,11 +32,17 @@ NEWLIB_SYMLINKS = $(NEWLIB_SUBDIRS:%=$(GCC_VERSION)/%) GDB_SYMLINKS = $(GDB_SUBDIRS:%=$(GCC_VERSION)/%) GCC_IN_TREE_DEPS = @GCC_IN_TREE_DEPS@ CONFIG_TOOLCHAIN = @CONFIG_TOOLCHAIN@ +CPPFLAGS = @CPPFLAGS@ LDFLAGS = @LDFLAGS@ CFLAGS_FOR_TARGET = @CFLAGS_FOR_TARGET@ CXXFLAGS_FOR_TARGET = @CXXFLAGS_FOR_TARGET@ MKDIR_P = @MKDIR_P@ WGET = @WGET@ +TOOLCHAIN_PATH = @TOOLCHAIN_PATH@ + +ifneq ($(strip $(TOOLCHAIN_PATH)),) +export PATH := $(TOOLCHAIN_PATH):$(PATH) +endif all: @@ -91,27 +102,33 @@ $(DISTCLEANPROGS): $(MKDIR_P) $(@) src-binutils: - $(WGET) - "$(BINUTILS_URL)" | tar xJ + archive="$(BINUTILS_ARCHIVE)"; \ + if test -z "$$archive" && test -n "$(N64_TOOLCHAIN_ARCHIVE_DIR)"; then archive="$(N64_TOOLCHAIN_ARCHIVE_DIR)/$(BINUTILS_VERSION).tar.xz"; fi; \ + if test -n "$$archive"; then test -f "$$archive" || { echo "Missing local archive: $$archive" >&2; exit 1; }; cat "$$archive"; else $(WGET) - "$(BINUTILS_URL)"; fi | tar xJ touch $(@) src-gcc: - $(WGET) - "$(GCC_URL)" | tar xJ + archive="$(GCC_ARCHIVE)"; \ + if test -z "$$archive" && test -n "$(N64_TOOLCHAIN_ARCHIVE_DIR)"; then archive="$(N64_TOOLCHAIN_ARCHIVE_DIR)/$(GCC_VERSION).tar.xz"; fi; \ + if test -n "$$archive"; then test -f "$$archive" || { echo "Missing local archive: $$archive" >&2; exit 1; }; cat "$$archive"; else $(WGET) - "$(GCC_URL)"; fi | tar xJ if [ x"$(GCC_IN_TREE_DEPS)" = x"yes" ]; then \ cd $(GCC_VERSION) && ./contrib/download_prerequisites; \ fi for d in $(BINUTILS_SUBDIRS); do \ - sed -i s@module_srcdir=$${d}\\b@module_srcdir=../$(BINUTILS_VERSION)/$${d}@g $(GCC_VERSION)/Makefile.in; \ + "$(srcdir)/config/replace-module-srcdir" "$(GCC_VERSION)/Makefile.in" "$${d}" "../$(BINUTILS_VERSION)/$${d}"; \ done for d in $(NEWLIB_SUBDIRS); do \ - sed -i s@module_srcdir=$${d}\\b@module_srcdir=../$(NEWLIB_VERSION)/$${d}@g $(GCC_VERSION)/Makefile.in; \ + "$(srcdir)/config/replace-module-srcdir" "$(GCC_VERSION)/Makefile.in" "$${d}" "../$(NEWLIB_VERSION)/$${d}"; \ done for d in $(GDB_SUBDIRS); do \ - sed -i s@module_srcdir=$${d}\\b@module_srcdir=../$(GDB_VERSION)/$${d}@g $(GCC_VERSION)/Makefile.in; \ + "$(srcdir)/config/replace-module-srcdir" "$(GCC_VERSION)/Makefile.in" "$${d}" "../$(GDB_VERSION)/$${d}"; \ done touch $(@) src-newlib: - $(WGET) - "$(NEWLIB_URL)" | tar xz + archive="$(NEWLIB_ARCHIVE)"; \ + if test -z "$$archive" && test -n "$(N64_TOOLCHAIN_ARCHIVE_DIR)"; then archive="$(N64_TOOLCHAIN_ARCHIVE_DIR)/$(NEWLIB_VERSION).tar.gz"; fi; \ + if test -n "$$archive"; then test -f "$$archive" || { echo "Missing local archive: $$archive" >&2; exit 1; }; cat "$$archive"; else $(WGET) - "$(NEWLIB_URL)"; fi | tar xz # for newlib = 4.6.0.20260123 if patch -t -N --dry-run -d $(NEWLIB_VERSION) -p 1 <"$(srcdir)/config/newlib/fix-mips3.diff"; then \ patch -t -N -d $(NEWLIB_VERSION) -p 1 <"$(srcdir)/config/newlib/fix-mips3.diff"; \ @@ -123,7 +140,9 @@ src-newlib: touch $(@) src-gdb: - $(WGET) - "$(GDB_URL)" | tar xJ + archive="$(GDB_ARCHIVE)"; \ + if test -z "$$archive" && test -n "$(N64_TOOLCHAIN_ARCHIVE_DIR)"; then archive="$(N64_TOOLCHAIN_ARCHIVE_DIR)/$(GDB_VERSION).tar.xz"; fi; \ + if test -n "$$archive"; then test -f "$$archive" || { echo "Missing local archive: $$archive" >&2; exit 1; }; cat "$$archive"; else $(WGET) - "$(GDB_URL)"; fi | tar xJ touch $(@) src-all: src-binutils src-gcc src-newlib src-gdb @@ -205,6 +224,7 @@ build-toolchain/config.status: | build-toolchain/ --disable-multilib \ --disable-threads \ --disable-nls \ + CPPFLAGS="$(CPPFLAGS)" \ LDFLAGS="$(LDFLAGS)" \ CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ diff --git a/README.md b/README.md index a5495e8..c73d79d 100644 --- a/README.md +++ b/README.md @@ -34,8 +34,8 @@ mips64, with `-march=vr4300` and `-mabi=32` as defaults for `gcc`. ## Prerequisites You'll need to have these packages installed: `wget tar make diffutils texinfo -gcc g++ lua5.3 jansson libusb-1.0 libgmp`. See Installation, step 4. If you -want to use the included `luapatch` program with BizHawk, you should set the +gcc g++ lua zlib jansson libusb-1.0 libgmp libmpfr libmpc`. See Installation, +step 3. If you want to use the included `luapatch` program with BizHawk, you should set the `EMUDIR` environment variable to the path to your BizHawk installation. ## Installation @@ -43,14 +43,31 @@ want to use the included `luapatch` program with BizHawk, you should set the Binary packages are available, see https://github.com/PracticeROM/packages. Packages are built from the `n64-ultra` branch and target `mips64-ultra-elf` +### macOS +Install the Xcode command-line tools and Homebrew, then run `./install_deps`. +Use `gmake` for the toolchain targets. Homebrew dependency paths and keg-only +GNU sed and texinfo tools are detected automatically during configuration. + +On Apple Silicon, current independently released GDB and binutils sources may +not be compatible when combined. GDB is enabled by default for source builds; +configure with `--disable-toolchain-gdb` when it is not needed. Homebrew +formulae may select this option automatically on affected hosts. + +### Local toolchain archives +Network downloads remain the default. To use local archives, set +`N64_TOOLCHAIN_ARCHIVE_DIR` to a directory containing files named like +`binutils-X.Y.tar.xz`, `gcc-X.Y.Z.tar.xz`, `newlib-X.Y.Z.YYYYMMDD.tar.gz`, and +`gdb-X.Y.tar.xz`. Individual archives can be selected with `BINUTILS_ARCHIVE`, +`GCC_ARCHIVE`, `NEWLIB_ARCHIVE`, and `GDB_ARCHIVE`. + ### Building from source 1. If you're on Windows, download and install MSYS2 from [here](https://msys2.github.io/). Open a `MSYS2 MinGW 64-bit` shell. 2. Clone the repository and navigate into it by running `git clone https://github.com/glankk/n64 && cd n64`. 3. Optionally, have the included script try to install the prerequisite - packages automatically by running `./install_deps`. You'll need root - privileges for this. + packages automatically by running `./install_deps`. Homebrew runs without + root; other package managers may require administrator privileges. 4. Configure the package with `./configure --prefix=/opt/n64`. You may use another installation prefix if you wish. To enable Wii VC compatibility, append ` --enable-vc` to the configure command. To produce portable Windows diff --git a/config/replace-module-srcdir b/config/replace-module-srcdir new file mode 100755 index 0000000..98d6779 --- /dev/null +++ b/config/replace-module-srcdir @@ -0,0 +1,35 @@ +#!/usr/bin/env sh +# Portably update a GCC top-level module_srcdir assignment. This replaces the +# previous GNU-sed-only use of sed -i and GNU word-boundary matching. +set -eu + +if test "$#" -ne 3; then + echo "usage: $0 FILE MODULE REPLACEMENT" >&2 + exit 2 +fi + +file=$1 +module=$2 +replacement=$3 +tmp="${file}.n64-tmp.$$" +trap 'rm -f "$tmp"' EXIT HUP INT TERM + +awk -v module="$module" -v replacement="$replacement" ' +{ + needle = "module_srcdir=" module + content = $0 + sub(/^[[:space:]]*/, "", content) + indent_length = length($0) - length(content) + if (index(content, needle) == 1) { + suffix = substr(content, length(needle) + 1) + if (suffix == "" || suffix ~ /^[[:space:]]/) { + indent = substr($0, 1, indent_length) + $0 = indent "module_srcdir=" replacement suffix + } + } + print +} +' "$file" > "$tmp" + +mv "$tmp" "$file" +trap - EXIT HUP INT TERM diff --git a/config/version-sort b/config/version-sort new file mode 100755 index 0000000..286fc01 --- /dev/null +++ b/config/version-sort @@ -0,0 +1,19 @@ +#!/usr/bin/env sh +# Sort archive stems containing dotted numeric versions without GNU sort -V. +# Input examples: gcc-15.1.0, newlib-4.6.0.20260123. +set -e +LC_ALL=C awk ' +{ + original = $0 + version = $0 + sub(/^[^0-9]*/, "", version) + count = split(version, part, ".") + key = "" + for (i = 1; i <= 12; ++i) { + value = (i <= count ? part[i] : 0) + sub(/[^0-9].*$/, "", value) + key = key sprintf("%012d", value + 0) + } + print key "\t" original +} +' | LC_ALL=C sort | cut -f2- diff --git a/configure b/configure index 0152111..0cf153e 100755 --- a/configure +++ b/configure @@ -640,6 +640,11 @@ ac_includes_default="\ ac_header_c_list= ac_subst_vars='LTLIBOBJS LIBOBJS +GDB_ARCHIVE +NEWLIB_ARCHIVE +GCC_ARCHIVE +BINUTILS_ARCHIVE +N64_TOOLCHAIN_ARCHIVE_DIR GDB_VERSION NEWLIB_VERSION GCC_VERSION @@ -664,6 +669,10 @@ CPPFLAGS LDFLAGS CFLAGS CC +TOOLCHAIN_PATH +HOST_ARCH +HOST_OS +HOMEBREW_PREFIX CONFIG_TOOLCHAIN CXXFLAGS_FOR_TARGET CFLAGS_FOR_TARGET @@ -715,10 +724,12 @@ enable_gcc_in_tree_deps enable_vc with_configure_toolchain with_toolchain +enable_toolchain_gdb ' ac_precious_vars='build_alias host_alias target_alias +HOMEBREW_PREFIX CC CFLAGS LDFLAGS @@ -727,7 +738,12 @@ CPPFLAGS BINUTILS_VERSION GCC_VERSION NEWLIB_VERSION -GDB_VERSION' +GDB_VERSION +N64_TOOLCHAIN_ARCHIVE_DIR +BINUTILS_ARCHIVE +GCC_ARCHIVE +NEWLIB_ARCHIVE +GDB_ARCHIVE' # Initialize some variables set by options. @@ -1349,6 +1365,8 @@ Optional Features: --disable-gcc-in-tree-deps do not download in-tree gcc prerequisites --enable-vc compile libraries with wii vc compatibility + --disable-toolchain-gdb do not build the optional GDB and simulator + components Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] @@ -1359,6 +1377,8 @@ Optional Packages: --without-toolchain do not check any toolchain package versions Some influential environment variables: + HOMEBREW_PREFIX + Homebrew prefix to use on macOS CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a @@ -1372,6 +1392,15 @@ Some influential environment variables: NEWLIB_VERSION manually set the version of newlib to use GDB_VERSION manually set the version of gdb to use + N64_TOOLCHAIN_ARCHIVE_DIR + directory containing local binutils, GCC, newlib, and GDB + archives + BINUTILS_ARCHIVE + local binutils .tar.xz archive + GCC_ARCHIVE local GCC .tar.xz archive + NEWLIB_ARCHIVE + local newlib .tar.gz archive + GDB_ARCHIVE local GDB .tar.xz archive Use these variables to override the choices made by 'configure' or to help it to find libraries and programs with nonstandard names/locations. @@ -2528,6 +2557,156 @@ else case e in #( esac fi +# Check whether --enable-toolchain-gdb was given. +if test ${enable_toolchain_gdb+y} +then : + enableval=$enable_toolchain_gdb; if test "x$enableval" != xno +then : + as_fn_error $? "GDB is enabled by default; only --disable-toolchain-gdb is supported" "$LINENO" 5 +fi + enable_toolchain_gdb=no +else case e in #( + e) enable_toolchain_gdb=yes ;; +esac +fi + + +# Host platform setup. The target remains mips64 on every supported host. + + + + +HOST_OS=`uname -s 2>/dev/null || echo unknown` +HOST_ARCH=`uname -m 2>/dev/null || echo unknown` +TOOLCHAIN_PATH= +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: host platform: $HOST_OS/$HOST_ARCH" >&5 +printf "%s\n" "$as_me: host platform: $HOST_OS/$HOST_ARCH" >&6;} + +# GDB and the simulator are optional toolchain components. +if test "x$enable_toolchain_gdb" = xno +then : + + case " $CONFIG_TOOLCHAIN " in + *" --disable-gdb"*) ;; + *) CONFIG_TOOLCHAIN="$CONFIG_TOOLCHAIN --disable-gdb --disable-sim" ;; + esac + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: toolchain GDB component: $enable_toolchain_gdb" >&5 +printf "%s\n" "$as_me: toolchain GDB component: $enable_toolchain_gdb" >&6;} + +# Apple Silicon Homebrew installs outside the compiler's default search path. +# Add both the global prefix and formula-specific prefixes (including keg-only +# formulae such as zlib and texinfo). These flags are only added on Darwin and +# therefore do not alter Linux, BSD, or MSYS2 builds. +if test "x$HOST_OS" = xDarwin +then : + + if test "x$HOST_ARCH" = xarm64 +then : + case " $CONFIG_TOOLCHAIN " in + *" --disable-werror"*) ;; + *) CONFIG_TOOLCHAIN="$CONFIG_TOOLCHAIN --disable-werror" ;; + esac +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Homebrew" >&5 +printf %s "checking for Homebrew... " >&6; } + n64_brew= + for n64_brew_candidate in brew /opt/homebrew/bin/brew /usr/local/bin/brew; do + if test "x$n64_brew_candidate" = xbrew; then + n64_brew_candidate=`command -v brew 2>/dev/null || true` + fi + if test -n "$n64_brew_candidate" && test -x "$n64_brew_candidate"; then + n64_brew="$n64_brew_candidate" + break + fi + done + if test -z "$HOMEBREW_PREFIX" && test -n "$n64_brew"; then + HOMEBREW_PREFIX=`"$n64_brew" --prefix 2>/dev/null || true` + fi + if test -n "$HOMEBREW_PREFIX" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $HOMEBREW_PREFIX" >&5 +printf "%s\n" "$HOMEBREW_PREFIX" >&6; } +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +printf "%s\n" "not found" >&6; } ;; +esac +fi + + n64_gmp_prefix= + n64_mpfr_prefix= + n64_mpc_prefix= + if test -n "$HOMEBREW_PREFIX"; then + test -d "$HOMEBREW_PREFIX/include" && CPPFLAGS="$CPPFLAGS -I$HOMEBREW_PREFIX/include" + test -d "$HOMEBREW_PREFIX/lib" && LDFLAGS="$LDFLAGS -L$HOMEBREW_PREFIX/lib" + + for n64_formula in lua zlib jansson libusb gmp mpfr libmpc; do + n64_formula_prefix= + if test -n "$n64_brew"; then + n64_formula_prefix=`"$n64_brew" --prefix "$n64_formula" 2>/dev/null || true` + elif test -d "$HOMEBREW_PREFIX/opt/$n64_formula"; then + n64_formula_prefix="$HOMEBREW_PREFIX/opt/$n64_formula" + fi + if test -n "$n64_formula_prefix"; then + test -d "$n64_formula_prefix/include" && CPPFLAGS="$CPPFLAGS -I$n64_formula_prefix/include" + test -d "$n64_formula_prefix/lib" && LDFLAGS="$LDFLAGS -L$n64_formula_prefix/lib" + case "$n64_formula" in + gmp) n64_gmp_prefix="$n64_formula_prefix" ;; + mpfr) n64_mpfr_prefix="$n64_formula_prefix" ;; + libmpc) n64_mpc_prefix="$n64_formula_prefix" ;; + esac + fi + done + + # GCC's libgcc generators rely on GNU sed regular-expression + # behaviour. Homebrew installs it keg-only, so expose its unprefixed + # tools to the recursive toolchain build on macOS only. + if test -d "$HOMEBREW_PREFIX/opt/gnu-sed/libexec/gnubin"; then + TOOLCHAIN_PATH="$HOMEBREW_PREFIX/opt/gnu-sed/libexec/gnubin" + fi + + # Homebrew's texinfo is keg-only. Export its tools to every recursive + # toolchain build through the generated Makefile. + if test -d "$HOMEBREW_PREFIX/opt/texinfo/bin"; then + if test -n "$TOOLCHAIN_PATH"; then + TOOLCHAIN_PATH="$TOOLCHAIN_PATH:$HOMEBREW_PREFIX/opt/texinfo/bin" + else + TOOLCHAIN_PATH="$HOMEBREW_PREFIX/opt/texinfo/bin" + fi + fi + if test -d "$HOMEBREW_PREFIX/bin"; then + if test -n "$TOOLCHAIN_PATH"; then + TOOLCHAIN_PATH="$TOOLCHAIN_PATH:$HOMEBREW_PREFIX/bin" + else + TOOLCHAIN_PATH="$HOMEBREW_PREFIX/bin" + fi + fi + + # Pass Homebrew's prerequisite prefixes to the recursive GNU + # toolchain configure unless the user supplied an override. + if test -n "$n64_gmp_prefix"; then + case " $CONFIG_TOOLCHAIN " in + *" --with-gmp="*) ;; + *) CONFIG_TOOLCHAIN="$CONFIG_TOOLCHAIN --with-gmp=$n64_gmp_prefix" ;; + esac + fi + if test -n "$n64_mpfr_prefix"; then + case " $CONFIG_TOOLCHAIN " in + *" --with-mpfr="*) ;; + *) CONFIG_TOOLCHAIN="$CONFIG_TOOLCHAIN --with-mpfr=$n64_mpfr_prefix" ;; + esac + fi + if test -n "$n64_mpc_prefix"; then + case " $CONFIG_TOOLCHAIN " in + *" --with-mpc="*) ;; + *) CONFIG_TOOLCHAIN="$CONFIG_TOOLCHAIN --with-mpc=$n64_mpc_prefix" ;; + esac + fi + fi + +fi # Checks for programs. @@ -4743,6 +4922,12 @@ if test "x$ac_cv_header_lua53_lua_h" = xyes then : printf "%s\n" "#define HAVE_LUA53_LUA_H 1" >>confdefs.h +fi +ac_fn_c_check_header_compile "$LINENO" "lua/lua.h" "ac_cv_header_lua_lua_h" "$ac_includes_default" +if test "x$ac_cv_header_lua_lua_h" = xyes +then : + printf "%s\n" "#define HAVE_LUA_LUA_H 1" >>confdefs.h + fi ac_fn_c_check_header_compile "$LINENO" "lua.h" "ac_cv_header_lua_h" "$ac_includes_default" if test "x$ac_cv_header_lua_h" = xyes @@ -4891,12 +5076,61 @@ printf "%s\n" "#define HAVE_DECL_ASPRINTF $ac_have_decl" >>confdefs.h + + + + + + +# Local archives are optional. Existing network URLs remain the default, but +# infer archive stems when local files were selected so offline builds do not +# need to scrape the upstream directory listings. +if test -z "$BINUTILS_VERSION" && test -n "$BINUTILS_ARCHIVE" +then : + BINUTILS_VERSION=`basename "$BINUTILS_ARCHIVE" .tar.xz` +fi +if test -z "$GCC_VERSION" && test -n "$GCC_ARCHIVE" +then : + GCC_VERSION=`basename "$GCC_ARCHIVE" .tar.xz` +fi +if test -z "$NEWLIB_VERSION" && test -n "$NEWLIB_ARCHIVE" +then : + NEWLIB_VERSION=`basename "$NEWLIB_ARCHIVE" .tar.gz` +fi +if test -z "$GDB_VERSION" && test -n "$GDB_ARCHIVE" +then : + GDB_VERSION=`basename "$GDB_ARCHIVE" .tar.xz` +fi + +if test -n "$N64_TOOLCHAIN_ARCHIVE_DIR" +then : + + if test -z "$BINUTILS_VERSION" +then : + BINUTILS_VERSION=`for f in "$N64_TOOLCHAIN_ARCHIVE_DIR"/binutils-*.tar.xz; do test -f "$f" && basename "$f" .tar.xz; done | "$srcdir/config/version-sort" | tail -n 1` +fi + if test -z "$GCC_VERSION" +then : + GCC_VERSION=`for f in "$N64_TOOLCHAIN_ARCHIVE_DIR"/gcc-*.tar.xz; do test -f "$f" && basename "$f" .tar.xz; done | "$srcdir/config/version-sort" | tail -n 1` +fi + if test -z "$NEWLIB_VERSION" +then : + NEWLIB_VERSION=`for f in "$N64_TOOLCHAIN_ARCHIVE_DIR"/newlib-*.tar.gz; do test -f "$f" && basename "$f" .tar.gz; done | "$srcdir/config/version-sort" | tail -n 1` +fi + if test -z "$GDB_VERSION" +then : + GDB_VERSION=`for f in "$N64_TOOLCHAIN_ARCHIVE_DIR"/gdb-*.tar.xz; do test -f "$f" && basename "$f" .tar.xz; done | "$srcdir/config/version-sort" | tail -n 1` +fi + +fi if test "x$with_toolchain" != xno then : - if test -z "$WGET" + if test -z "$WGET" && + (test -z "$BINUTILS_VERSION" || test -z "$GCC_VERSION" || + test -z "$NEWLIB_VERSION" || test -z "$GDB_VERSION") then : - as_fn_error 1 "don't know how to check package versions, configure --without-toolchain" "$LINENO" 5 + as_fn_error 1 "don't know how to check package versions; provide local archives and version stems, or configure --without-toolchain" "$LINENO" 5 fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking binutils version" >&5 printf %s "checking binutils version... " >&6; } @@ -4906,7 +5140,7 @@ then : BINUTILS_VERSION=`$WGET_Q - "https://ftp.gnu.org/gnu/binutils/" | grep -E -o ">binutils-[0-9\\\\.]+tar\\\\.xz<" | sed -e s/\\>// -e s/\\\\.tar\\\\.xz\\&5 @@ -4919,7 +5153,7 @@ then : GCC_VERSION=`$WGET_Q - "https://ftp.gnu.org/gnu/gcc/" | grep -E -o ">gcc-[0-9\\\\.]+/<" | sed -e s/\\>// -e s/\\\\/\\&5 @@ -4932,7 +5166,7 @@ then : NEWLIB_VERSION=`$WGET_Q - "https://sourceware.org/pub/newlib/" | grep -E -o ">newlib-[0-9\\\\.]+tar\\\\.gz<" | sed -e s/\\>// -e s/\\\\.tar\\\\.gz\\&5 @@ -4945,11 +5179,16 @@ then : GDB_VERSION=`$WGET_Q - "https://ftp.gnu.org/gnu/gdb/" | grep -E -o ">gdb-[0-9\\\\.]+tar\\\\.xz<" | sed -e s/\\>// -e s/\\\\.tar\\\\.xz\\&5 printf "%s\n" "$GDB_VERSION" >&6; } + if test -z "$BINUTILS_VERSION" || test -z "$GCC_VERSION" || + test -z "$NEWLIB_VERSION" || test -z "$GDB_VERSION" +then : + as_fn_error $? "failed to determine one or more toolchain versions; set BINUTILS_VERSION, GCC_VERSION, NEWLIB_VERSION, and GDB_VERSION explicitly" "$LINENO" 5 +fi fi diff --git a/configure.ac b/configure.ac index 6fdb63e..336bf96 100644 --- a/configure.ac +++ b/configure.ac @@ -40,6 +40,135 @@ AC_ARG_WITH([toolchain], [AS_HELP_STRING([--without-toolchain], [do not check any toolchain package versions])], [], [with_toolchain=yes]) +AC_ARG_ENABLE([toolchain-gdb], + [AS_HELP_STRING([--disable-toolchain-gdb], + [do not build the optional GDB and simulator components])], + [AS_IF([test "x$enableval" != xno], + [AC_MSG_ERROR([GDB is enabled by default; only --disable-toolchain-gdb is supported])]) + enable_toolchain_gdb=no], + [enable_toolchain_gdb=yes]) + +# Host platform setup. The target remains mips64 on every supported host. +AC_ARG_VAR([HOMEBREW_PREFIX], [Homebrew prefix to use on macOS]) +AC_SUBST([HOST_OS]) +AC_SUBST([HOST_ARCH]) +AC_SUBST([TOOLCHAIN_PATH]) +HOST_OS=`uname -s 2>/dev/null || echo unknown` +HOST_ARCH=`uname -m 2>/dev/null || echo unknown` +TOOLCHAIN_PATH= +AC_MSG_NOTICE([host platform: $HOST_OS/$HOST_ARCH]) + +# GDB and the simulator are optional toolchain components. +AS_IF([test "x$enable_toolchain_gdb" = xno], + [ + case " $CONFIG_TOOLCHAIN " in + *" --disable-gdb"*) ;; + *) CONFIG_TOOLCHAIN="$CONFIG_TOOLCHAIN --disable-gdb --disable-sim" ;; + esac + ]) +AC_MSG_NOTICE([toolchain GDB component: $enable_toolchain_gdb]) + +# Apple Silicon Homebrew installs outside the compiler's default search path. +# Add both the global prefix and formula-specific prefixes (including keg-only +# formulae such as zlib and texinfo). These flags are only added on Darwin and +# therefore do not alter Linux, BSD, or MSYS2 builds. +AS_IF([test "x$HOST_OS" = xDarwin], + [ + AS_IF([test "x$HOST_ARCH" = xarm64], + [case " $CONFIG_TOOLCHAIN " in + *" --disable-werror"*) ;; + *) CONFIG_TOOLCHAIN="$CONFIG_TOOLCHAIN --disable-werror" ;; + esac]) + + AC_MSG_CHECKING([for Homebrew]) + n64_brew= + for n64_brew_candidate in brew /opt/homebrew/bin/brew /usr/local/bin/brew; do + if test "x$n64_brew_candidate" = xbrew; then + n64_brew_candidate=`command -v brew 2>/dev/null || true` + fi + if test -n "$n64_brew_candidate" && test -x "$n64_brew_candidate"; then + n64_brew="$n64_brew_candidate" + break + fi + done + if test -z "$HOMEBREW_PREFIX" && test -n "$n64_brew"; then + HOMEBREW_PREFIX=`"$n64_brew" --prefix 2>/dev/null || true` + fi + AS_IF([test -n "$HOMEBREW_PREFIX"], + [AC_MSG_RESULT([$HOMEBREW_PREFIX])], + [AC_MSG_RESULT([not found])]) + + n64_gmp_prefix= + n64_mpfr_prefix= + n64_mpc_prefix= + if test -n "$HOMEBREW_PREFIX"; then + test -d "$HOMEBREW_PREFIX/include" && CPPFLAGS="$CPPFLAGS -I$HOMEBREW_PREFIX/include" + test -d "$HOMEBREW_PREFIX/lib" && LDFLAGS="$LDFLAGS -L$HOMEBREW_PREFIX/lib" + + for n64_formula in lua zlib jansson libusb gmp mpfr libmpc; do + n64_formula_prefix= + if test -n "$n64_brew"; then + n64_formula_prefix=`"$n64_brew" --prefix "$n64_formula" 2>/dev/null || true` + elif test -d "$HOMEBREW_PREFIX/opt/$n64_formula"; then + n64_formula_prefix="$HOMEBREW_PREFIX/opt/$n64_formula" + fi + if test -n "$n64_formula_prefix"; then + test -d "$n64_formula_prefix/include" && CPPFLAGS="$CPPFLAGS -I$n64_formula_prefix/include" + test -d "$n64_formula_prefix/lib" && LDFLAGS="$LDFLAGS -L$n64_formula_prefix/lib" + case "$n64_formula" in + gmp) n64_gmp_prefix="$n64_formula_prefix" ;; + mpfr) n64_mpfr_prefix="$n64_formula_prefix" ;; + libmpc) n64_mpc_prefix="$n64_formula_prefix" ;; + esac + fi + done + + # GCC's libgcc generators rely on GNU sed regular-expression + # behaviour. Homebrew installs it keg-only, so expose its unprefixed + # tools to the recursive toolchain build on macOS only. + if test -d "$HOMEBREW_PREFIX/opt/gnu-sed/libexec/gnubin"; then + TOOLCHAIN_PATH="$HOMEBREW_PREFIX/opt/gnu-sed/libexec/gnubin" + fi + + # Homebrew's texinfo is keg-only. Export its tools to every recursive + # toolchain build through the generated Makefile. + if test -d "$HOMEBREW_PREFIX/opt/texinfo/bin"; then + if test -n "$TOOLCHAIN_PATH"; then + TOOLCHAIN_PATH="$TOOLCHAIN_PATH:$HOMEBREW_PREFIX/opt/texinfo/bin" + else + TOOLCHAIN_PATH="$HOMEBREW_PREFIX/opt/texinfo/bin" + fi + fi + if test -d "$HOMEBREW_PREFIX/bin"; then + if test -n "$TOOLCHAIN_PATH"; then + TOOLCHAIN_PATH="$TOOLCHAIN_PATH:$HOMEBREW_PREFIX/bin" + else + TOOLCHAIN_PATH="$HOMEBREW_PREFIX/bin" + fi + fi + + # Pass Homebrew's prerequisite prefixes to the recursive GNU + # toolchain configure unless the user supplied an override. + if test -n "$n64_gmp_prefix"; then + case " $CONFIG_TOOLCHAIN " in + *" --with-gmp="*) ;; + *) CONFIG_TOOLCHAIN="$CONFIG_TOOLCHAIN --with-gmp=$n64_gmp_prefix" ;; + esac + fi + if test -n "$n64_mpfr_prefix"; then + case " $CONFIG_TOOLCHAIN " in + *" --with-mpfr="*) ;; + *) CONFIG_TOOLCHAIN="$CONFIG_TOOLCHAIN --with-mpfr=$n64_mpfr_prefix" ;; + esac + fi + if test -n "$n64_mpc_prefix"; then + case " $CONFIG_TOOLCHAIN " in + *" --with-mpc="*) ;; + *) CONFIG_TOOLCHAIN="$CONFIG_TOOLCHAIN --with-mpc=$n64_mpc_prefix" ;; + esac + fi + fi + ]) # Checks for programs. AC_PROG_CC @@ -86,7 +215,7 @@ AC_SEARCH_LIBS([gai_strerrorA], [Ws2_32], [AS_IF([test -n "$ac_lib"], [LIBWS2_32=-l$ac_lib])]) # Checks for header files. -AC_CHECK_HEADERS([lua5.4/lua.h lua54/lua.h lua5.3/lua.h lua53/lua.h lua.h]) +AC_CHECK_HEADERS([lua5.4/lua.h lua54/lua.h lua5.3/lua.h lua53/lua.h lua/lua.h lua.h]) AC_CHECK_HEADERS([zlib.h]) AC_CHECK_HEADERS([libusb-1.0/libusb.h libusb.h]) AC_CHECK_HEADERS([pty.h util.h libutil.h]) @@ -99,10 +228,41 @@ AC_ARG_VAR([BINUTILS_VERSION], [manually set the version of binutils to use]) AC_ARG_VAR([GCC_VERSION], [manually set the version of gcc to use]) AC_ARG_VAR([NEWLIB_VERSION], [manually set the version of newlib to use]) AC_ARG_VAR([GDB_VERSION], [manually set the version of gdb to use]) +AC_ARG_VAR([N64_TOOLCHAIN_ARCHIVE_DIR], [directory containing local binutils, GCC, newlib, and GDB archives]) +AC_ARG_VAR([BINUTILS_ARCHIVE], [local binutils .tar.xz archive]) +AC_ARG_VAR([GCC_ARCHIVE], [local GCC .tar.xz archive]) +AC_ARG_VAR([NEWLIB_ARCHIVE], [local newlib .tar.gz archive]) +AC_ARG_VAR([GDB_ARCHIVE], [local GDB .tar.xz archive]) + +# Local archives are optional. Existing network URLs remain the default, but +# infer archive stems when local files were selected so offline builds do not +# need to scrape the upstream directory listings. +AS_IF([test -z "$BINUTILS_VERSION" && test -n "$BINUTILS_ARCHIVE"], + [BINUTILS_VERSION=`basename "$BINUTILS_ARCHIVE" .tar.xz`]) +AS_IF([test -z "$GCC_VERSION" && test -n "$GCC_ARCHIVE"], + [GCC_VERSION=`basename "$GCC_ARCHIVE" .tar.xz`]) +AS_IF([test -z "$NEWLIB_VERSION" && test -n "$NEWLIB_ARCHIVE"], + [NEWLIB_VERSION=`basename "$NEWLIB_ARCHIVE" .tar.gz`]) +AS_IF([test -z "$GDB_VERSION" && test -n "$GDB_ARCHIVE"], + [GDB_VERSION=`basename "$GDB_ARCHIVE" .tar.xz`]) + +AS_IF([test -n "$N64_TOOLCHAIN_ARCHIVE_DIR"], + [ + AS_IF([test -z "$BINUTILS_VERSION"], + [BINUTILS_VERSION=`for f in "$N64_TOOLCHAIN_ARCHIVE_DIR"/binutils-*.tar.xz; do test -f "$f" && basename "$f" .tar.xz; done | "$srcdir/config/version-sort" | tail -n 1`]) + AS_IF([test -z "$GCC_VERSION"], + [GCC_VERSION=`for f in "$N64_TOOLCHAIN_ARCHIVE_DIR"/gcc-*.tar.xz; do test -f "$f" && basename "$f" .tar.xz; done | "$srcdir/config/version-sort" | tail -n 1`]) + AS_IF([test -z "$NEWLIB_VERSION"], + [NEWLIB_VERSION=`for f in "$N64_TOOLCHAIN_ARCHIVE_DIR"/newlib-*.tar.gz; do test -f "$f" && basename "$f" .tar.gz; done | "$srcdir/config/version-sort" | tail -n 1`]) + AS_IF([test -z "$GDB_VERSION"], + [GDB_VERSION=`for f in "$N64_TOOLCHAIN_ARCHIVE_DIR"/gdb-*.tar.xz; do test -f "$f" && basename "$f" .tar.xz; done | "$srcdir/config/version-sort" | tail -n 1`]) + ]) AS_IF([test "x$with_toolchain" != xno], [ - AS_IF([test -z "$WGET"], - [AC_MSG_ERROR([don't know how to check package versions, configure --without-toolchain], + AS_IF([test -z "$WGET" && + (test -z "$BINUTILS_VERSION" || test -z "$GCC_VERSION" || + test -z "$NEWLIB_VERSION" || test -z "$GDB_VERSION")], + [AC_MSG_ERROR([don't know how to check package versions; provide local archives and version stems, or configure --without-toolchain], [1])]) AC_MSG_CHECKING([binutils version]) AS_IF([test -z "$BINUTILS_VERSION"], @@ -110,7 +270,7 @@ AS_IF([test "x$with_toolchain" != xno], BINUTILS_VERSION=`$WGET_Q - "https://ftp.gnu.org/gnu/binutils/" | grep -E -o ">binutils-[[0-9\\\\.]]+tar\\\\.xz<" | sed -e s/\\>// -e s/\\\\.tar\\\\.xz\\gcc-[[0-9\\\\.]]+/<" | sed -e s/\\>// -e s/\\\\/\\newlib-[[0-9\\\\.]]+tar\\\\.gz<" | sed -e s/\\>// -e s/\\\\.tar\\\\.gz\\gdb-[[0-9\\\\.]]+tar\\\\.xz<" | sed -e s/\\>// -e s/\\\\.tar\\\\.xz\\/dev/null 2>&1; then +OS=`uname -s 2>/dev/null || echo unknown` +ARCH=`uname -m 2>/dev/null || echo unknown` +echo "Checking platform ($OS/$ARCH)..." + +if test "x$OS" = xDarwin; then + BREW="" + for candidate in "`command -v brew 2>/dev/null || true`" /opt/homebrew/bin/brew /usr/local/bin/brew; do + if test -n "$candidate" && test -x "$candidate"; then + BREW="$candidate" + break + fi + done + if test -n "$BREW"; then + echo "Found Homebrew, assuming macOS." + if test "x$ARCH" = xarm64; then + echo "Detected Apple Silicon; native arm64 dependencies will be installed." + fi + DEPS="pkg-config texinfo gnu-sed lua zlib jansson libusb gmp mpfr libmpc make xz" + PKM="brew" + else + echo "Homebrew was not found. Install it first, then rerun this script." + echo "Make sure these packages are installed: $RCDEPS" + exit 1 + fi +elif type yum >/dev/null 2>&1; then echo Found yum, assuming Red Hat. DEPS="$DEPS gcc gcc-c++ lua-devel zlib-devel jansson-devel libusb-devel gmp-devel" PKM="yum" @@ -17,31 +40,25 @@ elif type zypper >/dev/null 2>&1; then elif type emerge >/dev/null 2>&1; then echo Found emerge, assuming Gentoo. if type equo >/dev/null 2>&1; then - read -p "Warning: Also found equo. If you're running Sabayon, then this will probably not work. Continue? (y/n) " yn + printf "Warning: Also found equo. If you're running Sabayon, this may not work. Continue? (y/n) " + read yn case "$yn" in [Yy]*) ;; *) exit;; esac fi DEPS="$DEPS gcc lua:5.3 zlib jansson libusb gmp" PKM="emerge" elif type pkg >/dev/null 2>&1; then echo Found pkg, assuming FreeBSD. - echo Note: Configure with 'CPPFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib'. - echo Note: gsed needs to be in your PATH as 'sed'. - echo Note: Make with gmake. - DEPS="texinfo lua53 zlib jansson gmake gsed gmp" + echo "Note: Configure with 'CPPFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib'." + echo "Note: Make with gmake." + DEPS="texinfo lua53 zlib jansson gmake gmp" PKM="pkg" -elif type brew >/dev/null 2>&1; then - echo Found brew, assuming macOS. - echo Note: gsed needs to be in your PATH as 'sed'. - echo Note: Make with gmake. - DEPS="texinfo lua zlib jansson libusb make gnu-sed gmp" - PKM="brew" elif type apt >/dev/null 2>&1; then echo Found apt, assuming Debian. DEPS="$DEPS gcc g++ liblua5.3-dev zlib1g-dev libjansson-dev libusb-1.0-0-dev libgmp-dev" PKM="apt" elif type pacman >/dev/null 2>&1; then - if test "x`uname -o`" = xMsys; then - echo Found pacman with \`uname -o\` = "Msys", assuming MSYS2. + if test "x`uname -o 2>/dev/null || true`" = xMsys; then + echo "Found pacman with \`uname -o\` = Msys, assuming MSYS2." DEPS="$DEPS mingw-w64-x86_64-gcc mingw-w64-x86_64-lua mingw-w64-x86_64-zlib mingw-w64-x86_64-jansson mingw-w64-x86_64-libusb mingw-w64-x86_64-gmp" PKM="pacman" else @@ -61,7 +78,7 @@ else zypper) zypper install -y $DEPS;; emerge) emerge -n --autounmask-write $DEPS || ( dispatch-conf && emerge -n $DEPS );; pkg) pkg install $DEPS;; - brew) brew install $DEPS;; + brew) "$BREW" install $DEPS;; apt) apt install -y $DEPS;; pacman) pacman -S --needed --noconfirm $DEPS;; esac diff --git a/src/config.h.in b/src/config.h.in index 6ca10d9..54c0805 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -34,6 +34,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_LUA_H +/* Define to 1 if you have the header file. */ +#undef HAVE_LUA_LUA_H + /* Define to 1 if you have the header file. */ #undef HAVE_PTY_H diff --git a/src/libgru/src/exe/lauxlib.h b/src/libgru/src/exe/lauxlib.h index a64b008..4ed4765 100644 --- a/src/libgru/src/exe/lauxlib.h +++ b/src/libgru/src/exe/lauxlib.h @@ -6,6 +6,8 @@ #include #elif defined(HAVE_LUA53_LUA_H) #include +#elif defined(HAVE_LUA_LUA_H) +#include #elif defined(HAVE_LUA_H) #include #endif diff --git a/src/libgru/src/exe/lua.h b/src/libgru/src/exe/lua.h index 2882d41..202b0dd 100644 --- a/src/libgru/src/exe/lua.h +++ b/src/libgru/src/exe/lua.h @@ -6,6 +6,8 @@ #include #elif defined(HAVE_LUA53_LUA_H) #include +#elif defined(HAVE_LUA_LUA_H) +#include #elif defined(HAVE_LUA_H) #include #endif diff --git a/src/libgru/src/exe/lualib.h b/src/libgru/src/exe/lualib.h index cc5ea0e..b613815 100644 --- a/src/libgru/src/exe/lualib.h +++ b/src/libgru/src/exe/lualib.h @@ -6,6 +6,8 @@ #include #elif defined(HAVE_LUA53_LUA_H) #include +#elif defined(HAVE_LUA_LUA_H) +#include #elif defined(HAVE_LUA_H) #include #endif