Add runtime compatibility patch set

Add an LLVM 22.1.6 runtimes patch for building libc++, libc++abi, and llvm-libgcc together. The patch lets libc++abi accept llvm-libgcc as the provider of the LLVM unwinder, keeps the libgcc_s version script private to libunwind so it does not leak into libc++abi links, and adds an opt-out for building compiler-rt inside llvm-libgcc when an exported external builtins archive is available.

Add libxcrypt patches for current Clang/glibc builds: avoid treating Clang as old GCC in yescrypt assembly selection and adjust yescrypt strchr call sites for the newer glibc const-correct prototype behavior.

Add a mandoc 1.14.6 patch for zstd-compressed manual pages, including configure checks, linker flags, documentation, section matching, and decompression handling.

Remove the obsolete Perl 5.42.2 LBI patch from the patch set.
This commit is contained in:
2026-05-29 22:23:57 -05:00
parent 90076fecfc
commit accdf3d3fb
5 changed files with 666 additions and 188 deletions
@@ -0,0 +1,13 @@
diff -ruN a/lib/alg-yescrypt-opt.c b/lib/alg-yescrypt-opt.c
--- a/lib/alg-yescrypt-opt.c 2025-11-05 03:49:40.000000000 -0600
+++ b/lib/alg-yescrypt-opt.c 2026-05-29 16:10:57.694185418 -0500
@@ -464,7 +464,8 @@
#endif
#if defined(__x86_64__) && \
- __GNUC__ == 4 && __GNUC_MINOR__ < 6 && !defined(__ICC)
+ __GNUC__ == 4 && __GNUC_MINOR__ < 6 && !defined(__clang__) && \
+ !defined(__ICC)
#ifdef __AVX__
#define MOVQ "vmovq"
#else
@@ -0,0 +1,24 @@
diff -ruN a/lib/crypt-gost-yescrypt.c b/lib/crypt-gost-yescrypt.c
--- a/lib/crypt-gost-yescrypt.c 2025-01-03 12:08:44.000000000 -0600
+++ b/lib/crypt-gost-yescrypt.c 2026-05-29 16:07:10.245211533 -0500
@@ -131,7 +131,7 @@
intbuf->outbuf[1] = 'g';
/* extract yescrypt output from "$y$param$salt$output" */
- char *hptr = strchr ((const char *) intbuf->retval + 3, '$');
+ char *hptr = strchr (( char *) intbuf->retval + 3, '$');
if (!hptr)
{
errno = EINVAL;
diff -ruN a/lib/crypt-sm3-yescrypt.c b/lib/crypt-sm3-yescrypt.c
--- a/lib/crypt-sm3-yescrypt.c 2025-11-05 03:49:40.000000000 -0600
+++ b/lib/crypt-sm3-yescrypt.c 2026-05-29 16:07:10.245128194 -0500
@@ -136,7 +136,7 @@
intbuf->outbuf[3] = '3';
/* extract yescrypt output from "$y$param$salt$output" */
- char *hptr = strchr ((const char *) intbuf->retval + 3, '$');
+ char *hptr = strchr (( char *) intbuf->retval + 3, '$');
if (!hptr)
{
errno = EINVAL;
@@ -0,0 +1,169 @@
diff --git a/libcxxabi/CMakeLists.txt b/libcxxabi/CMakeLists.txt
index 2b67c59..02124de 100644
--- a/libcxxabi/CMakeLists.txt
+++ b/libcxxabi/CMakeLists.txt
@@ -53,8 +53,10 @@ option(LIBCXXABI_ENABLE_ASSERTIONS "Enable assertions independent of build mode.
option(LIBCXXABI_ENABLE_PEDANTIC "Compile with pedantic enabled." OFF)
option(LIBCXXABI_ENABLE_WERROR "Fail and stop if a warning is triggered." OFF)
option(LIBCXXABI_USE_LLVM_UNWINDER "Build and use the LLVM unwinder." ON)
-if (LIBCXXABI_USE_LLVM_UNWINDER AND NOT "libunwind" IN_LIST LLVM_ENABLE_RUNTIMES)
- message(FATAL_ERROR "LIBCXXABI_USE_LLVM_UNWINDER is set to ON, but libunwind is not specified in LLVM_ENABLE_RUNTIMES.")
+if (LIBCXXABI_USE_LLVM_UNWINDER AND
+ NOT "libunwind" IN_LIST LLVM_ENABLE_RUNTIMES AND
+ NOT "llvm-libgcc" IN_LIST LLVM_ENABLE_RUNTIMES)
+ message(FATAL_ERROR "LIBCXXABI_USE_LLVM_UNWINDER is set to ON, but neither libunwind nor llvm-libgcc is specified in LLVM_ENABLE_RUNTIMES.")
endif()
option(LIBCXXABI_ENABLE_STATIC_UNWINDER "Statically link the LLVM unwinder." OFF)
option(LIBCXXABI_USE_COMPILER_RT "Use compiler-rt instead of libgcc" OFF)
diff --git a/llvm-libgcc/CMakeLists.txt b/llvm-libgcc/CMakeLists.txt
index 47208fc..9f31762 100644
--- a/llvm-libgcc/CMakeLists.txt
+++ b/llvm-libgcc/CMakeLists.txt
@@ -32,8 +32,13 @@ set(LLVM_LIBGCC_LIBUNWIND_PATH "${CMAKE_CURRENT_LIST_DIR}/../libunwind"
CACHE PATH "Specify path to libunwind source.")
set(LLVM_LIBGCC_COMPILER_RT_PATH "${CMAKE_CURRENT_LIST_DIR}/../compiler-rt"
CACHE PATH "Specify path to compiler-rt source.")
+option(LLVM_LIBGCC_BUILD_COMPILER_RT
+ "Build compiler-rt builtins as part of llvm-libgcc." ON)
include(GNUInstallDirs)
+list(APPEND CMAKE_MODULE_PATH "${LLVM_LIBGCC_COMPILER_RT_PATH}/cmake/Modules")
+include(CompilerRTUtils)
+include(HandleCompilerRT)
if(NOT LLVM_LIBGCC_EXPLICIT_OPT_IN)
message(FATAL_ERROR
@@ -88,9 +93,11 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${LLVM_LIBGCC_LIBRARY_DIR})
# Build libraries
#===============================================================================
-set(COMPILER_RT_BUILD_BUILTINS ON)
-set(COMPILER_RT_BUILTINS_HIDE_SYMBOLS OFF)
-add_subdirectory(${LLVM_LIBGCC_COMPILER_RT_PATH} ${LLVM_LIBGCC_COMPILER_RT_BINARY_DIR})
+if(LLVM_LIBGCC_BUILD_COMPILER_RT)
+ set(COMPILER_RT_BUILD_BUILTINS ON)
+ set(COMPILER_RT_BUILTINS_HIDE_SYMBOLS OFF)
+ add_subdirectory(${LLVM_LIBGCC_COMPILER_RT_PATH} ${LLVM_LIBGCC_COMPILER_RT_BINARY_DIR})
+endif()
set(LIBUNWIND_ENABLE_STATIC ON)
set(LIBUNWIND_ENABLE_SHARED ON)
@@ -108,33 +115,65 @@ add_custom_target(gcc_s.ver
add_dependencies(unwind_shared gcc_s.ver)
+if(NOT LLVM_TARGET_TRIPLE)
+ set(LLVM_TARGET_TRIPLE "${LLVM_DEFAULT_TARGET_TRIPLE}")
+endif()
construct_compiler_rt_default_triple()
-target_link_options(unwind_shared PUBLIC
+target_link_options(unwind_shared PRIVATE
-Wl,--version-script,${CMAKE_CURRENT_BINARY_DIR}/gcc_s.ver
)
-target_link_libraries(unwind_shared PUBLIC
- $<TARGET_OBJECTS:clang_rt.builtins-${COMPILER_RT_DEFAULT_TARGET_ARCH}>
- m
-)
+if(LLVM_LIBGCC_BUILD_COMPILER_RT)
+ set(LLVM_LIBGCC_COMPILER_RT_DEPS clang_rt.builtins-${COMPILER_RT_DEFAULT_TARGET_ARCH})
+ set(LLVM_LIBGCC_COMPILER_RT_OBJECTS
+ $<TARGET_OBJECTS:clang_rt.builtins-${COMPILER_RT_DEFAULT_TARGET_ARCH}>)
+else()
+ set(LLVM_LIBGCC_COMPILER_RT_BUILTINS_LIBRARY "" CACHE FILEPATH
+ "Path to an existing compiler-rt builtins archive when LLVM_LIBGCC_BUILD_COMPILER_RT is OFF.")
+ if(NOT LLVM_LIBGCC_COMPILER_RT_BUILTINS_LIBRARY)
+ find_compiler_rt_library(builtins LLVM_LIBGCC_COMPILER_RT_BUILTINS_LIBRARY
+ TARGET ${COMPILER_RT_DEFAULT_TARGET_TRIPLE})
+ endif()
+ if(NOT LLVM_LIBGCC_COMPILER_RT_BUILTINS_LIBRARY OR
+ LLVM_LIBGCC_COMPILER_RT_BUILTINS_LIBRARY STREQUAL "NOTFOUND")
+ message(FATAL_ERROR
+ "LLVM_LIBGCC_BUILD_COMPILER_RT is OFF, but compiler-rt builtins could not "
+ "be found. Set LLVM_LIBGCC_COMPILER_RT_BUILTINS_LIBRARY to an existing "
+ "libclang_rt.builtins archive.")
+ endif()
+ set(LLVM_LIBGCC_COMPILER_RT_LINK_TARGET
+ "${LLVM_LIBGCC_COMPILER_RT_BUILTINS_LIBRARY}" CACHE STRING
+ "Install-tree target used by the libgcc.a symlink when LLVM_LIBGCC_BUILD_COMPILER_RT is OFF.")
+ set(LLVM_LIBGCC_COMPILER_RT_OBJECTS
+ -Wl,--whole-archive
+ ${LLVM_LIBGCC_COMPILER_RT_BUILTINS_LIBRARY}
+ -Wl,--no-whole-archive)
+endif()
+
+target_link_libraries(unwind_shared PRIVATE ${LLVM_LIBGCC_COMPILER_RT_OBJECTS})
+target_link_libraries(unwind_shared PUBLIC m)
#===============================================================================
# Install Symlinks
#===============================================================================
-get_compiler_rt_install_dir(${COMPILER_RT_DEFAULT_TARGET_ARCH} install_dir_builtins)
-string(REGEX REPLACE "^lib/" "" install_dir_builtins "${install_dir_builtins}")
-string(FIND "${install_dir_builtins}" "clang" install_path_contains_triple)
-if(install_path_contains_triple EQUAL -1)
- set(builtins_suffix "-${COMPILER_RT_DEFAULT_TARGET_ARCH}")
+if(LLVM_LIBGCC_BUILD_COMPILER_RT)
+ get_compiler_rt_install_dir(${COMPILER_RT_DEFAULT_TARGET_ARCH} install_dir_builtins)
+ string(REGEX REPLACE "^lib/" "" install_dir_builtins "${install_dir_builtins}")
+ string(FIND "${install_dir_builtins}" "clang" install_path_contains_triple)
+ if(install_path_contains_triple EQUAL -1)
+ set(builtins_suffix "-${COMPILER_RT_DEFAULT_TARGET_ARCH}")
+ else()
+ string(PREPEND install_dir_builtins "../")
+ endif()
+ set(LLVM_LIBGCC_COMPILER_RT ${install_dir_builtins}/libclang_rt.builtins${builtins_suffix}.a)
else()
- string(PREPEND install_dir_builtins "../")
+ set(LLVM_LIBGCC_COMPILER_RT "${LLVM_LIBGCC_COMPILER_RT_LINK_TARGET}")
endif()
-set(LLVM_LIBGCC_COMPILER_RT ${install_dir_builtins}/libclang_rt.builtins${builtins_suffix}.a)
add_custom_target(llvm-libgcc ALL
- DEPENDS unwind_shared unwind_static clang_rt.builtins-${COMPILER_RT_DEFAULT_TARGET_ARCH}
+ DEPENDS unwind_shared unwind_static ${LLVM_LIBGCC_COMPILER_RT_DEPS}
COMMAND ${CMAKE_COMMAND} -E create_symlink ${LLVM_LIBGCC_COMPILER_RT} libgcc.a
COMMAND ${CMAKE_COMMAND} -E create_symlink libunwind.a libgcc_eh.a
COMMAND ${CMAKE_COMMAND} -E create_symlink libunwind.so libgcc_s.so.1.0
@@ -147,10 +186,12 @@ install(TARGETS unwind_shared unwind_static
ARCHIVE DESTINATION ${LLVM_LIBGCC_INSTALL_LIBRARY_DIR} COMPONENT llvm-libgcc
RUNTIME DESTINATION ${LLVM_LIBGCC_INSTALL_RUNTIME_DIR} COMPONENT llvm-libgcc)
-install(TARGETS clang_rt.builtins-${COMPILER_RT_DEFAULT_TARGET_ARCH}
- LIBRARY DESTINATION ${LLVM_LIBGCC_INSTALL_LIBRARY_DIR}/${install_dir_builtins} COMPONENT llvm-libgcc
- ARCHIVE DESTINATION ${LLVM_LIBGCC_INSTALL_LIBRARY_DIR}/${install_dir_builtins} COMPONENT llvm-libgcc
- RUNTIME DESTINATION ${LLVM_LIBGCC_INSTALL_RUNTIME_DIR}/${install_dir_builtins} COMPONENT llvm-libgcc)
+if(LLVM_LIBGCC_BUILD_COMPILER_RT)
+ install(TARGETS clang_rt.builtins-${COMPILER_RT_DEFAULT_TARGET_ARCH}
+ LIBRARY DESTINATION ${LLVM_LIBGCC_INSTALL_LIBRARY_DIR}/${install_dir_builtins} COMPONENT llvm-libgcc
+ ARCHIVE DESTINATION ${LLVM_LIBGCC_INSTALL_LIBRARY_DIR}/${install_dir_builtins} COMPONENT llvm-libgcc
+ RUNTIME DESTINATION ${LLVM_LIBGCC_INSTALL_RUNTIME_DIR}/${install_dir_builtins} COMPONENT llvm-libgcc)
+endif()
foreach(VAR libgcc.a libgcc_eh.a libgcc_s.so.1.0 libgcc_s.so.1 libgcc_s.so)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${VAR}
diff --git a/llvm-libgcc/docs/LLVMLibgcc.rst b/llvm-libgcc/docs/LLVMLibgcc.rst
index 22dae7a..88e3fa2 100644
--- a/llvm-libgcc/docs/LLVMLibgcc.rst
+++ b/llvm-libgcc/docs/LLVMLibgcc.rst
@@ -72,6 +72,18 @@ CMake options
Since llvm-libgcc is such a fundamental, low-level component, we have made it
difficult to accidentally build, by requiring you to set an opt-in flag.
+.. option:: `LLVM_LIBGCC_BUILD_COMPILER_RT`
+
+ **Default**: ``ON``
+
+ Build the compiler-rt builtins archive as part of llvm-libgcc. When set to
+ ``OFF``, llvm-libgcc finds an existing compiler-rt builtins archive with the
+ compiler driver, links it into ``libunwind.so``, and only creates the
+ compatibility symlinks instead of installing compiler-rt. Set
+ ``LLVM_LIBGCC_COMPILER_RT_BUILTINS_LIBRARY`` if the compiler driver cannot
+ find the archive, and set ``LLVM_LIBGCC_COMPILER_RT_LINK_TARGET`` if the
+ installed symlink should point at a different path.
+
.. _Building llvm-libgcc
Building llvm-libgcc
+460
View File
@@ -0,0 +1,460 @@
diff -ruN a/INSTALL b/INSTALL
--- a/INSTALL 2021-09-23 13:03:23.000000000 -0500
+++ b/INSTALL 2026-05-29 18:09:12.237717849 -0500
@@ -103,7 +103,9 @@
1. zlib for decompressing gzipped manual pages.
-2. The fts(3) directory traversion functions.
+2. libzstd for decompressing zstd-compressed manual pages.
+
+3. The fts(3) directory traversion functions.
If your system does not have them, the bundled compatibility version
will be used, so you need not worry in that case. But be careful: old
glibc versions of fts(3) were known to be broken on 32bit platforms,
@@ -111,7 +113,7 @@
That was presumably fixed in glibc-2.23.
If you run into that problem, set "HAVE_FTS=0" in configure.local.
-3. Marc Espie's ohash(3) library.
+4. Marc Espie's ohash(3) library.
If your system does not have it, the bundled compatibility version
will be used, so you probably need not worry about it.
diff -ruN a/Makefile b/Makefile
--- a/Makefile 2021-09-23 13:03:23.000000000 -0500
+++ b/Makefile 2026-05-29 18:06:59.682203510 -0500
@@ -54,7 +54,8 @@
test-strsep.c \
test-strtonum.c \
test-vasprintf.c \
- test-wchar.c
+ test-wchar.c \
+ test-zstd.c
SRCS = arch.c \
att.c \
diff -ruN a/configure b/configure
--- a/configure 2021-09-23 13:03:23.000000000 -0500
+++ b/configure 2026-05-29 18:06:59.682203510 -0500
@@ -50,6 +50,7 @@
LD_NANOSLEEP=
LD_OHASH=
LD_RECVMSG=
+LD_ZSTD=-lzstd
STATIC=
BUILD_CGI=0
@@ -94,6 +95,7 @@
HAVE_SYS_ENDIAN=
HAVE_VASPRINTF=
HAVE_WCHAR=
+HAVE_ZSTD=
NEED_GNU_SOURCE=0
NEED_OPENBSD_SOURCE=0
@@ -331,6 +333,7 @@
runtest strsep STRSEP || true
runtest strtonum STRTONUM "" -D_OPENBSD_SOURCE || true
runtest vasprintf VASPRINTF "" -D_GNU_SOURCE || true
+runtest zstd ZSTD "${LD_ZSTD}" || true
# --- fts ---
if [ "${1}" = "-depend" ]; then
@@ -415,6 +418,11 @@
echo "FATAL: nanosleep: no" 1>&3
FATAL=1
fi
+if [ "${HAVE_ZSTD}" -eq 0 ]; then
+ echo "FATAL: zstd: no" 1>&2
+ echo "FATAL: zstd: no" 1>&3
+ FATAL=1
+fi
if [ ${BUILD_CATMAN} -gt 0 -a "${HAVE_RECVMSG}" -eq 0 ]; then
echo "FATAL: recvmsg: no" 1>&2
echo "FATAL: recvmsg: no" 1>&3
@@ -430,7 +438,7 @@
[ "${FATAL}" -eq 0 ] || exit 1
# --- LDADD ---
-LDADD="${LDADD} ${LD_NANOSLEEP} ${LD_RECVMSG} ${LD_OHASH} -lz"
+LDADD="${LDADD} ${LD_NANOSLEEP} ${LD_RECVMSG} ${LD_OHASH} -lz ${LD_ZSTD}"
echo "selected LDADD=\"${LDADD}\"" 1>&2
echo "selected LDADD=\"${LDADD}\"" 1>&3
echo 1>&3
@@ -506,6 +514,7 @@
#define HAVE_SYS_ENDIAN ${HAVE_SYS_ENDIAN}
#define HAVE_VASPRINTF ${HAVE_VASPRINTF}
#define HAVE_WCHAR ${HAVE_WCHAR}
+#define HAVE_ZSTD ${HAVE_ZSTD}
#define HAVE_OHASH ${HAVE_OHASH}
#define NEED_XPG4_2 ${NEED_XPG4_2}
diff -ruN a/main.c b/main.c
--- a/main.c 2021-09-23 13:03:23.000000000 -0500
+++ b/main.c 2026-05-29 18:08:19.108307544 -0500
@@ -538,7 +538,10 @@
prio += 10; /* Wrong dir name. */
if (search.sec != NULL) {
ep = strchr(sec, '\0');
- if (ep - sec > 3 &&
+ if (ep - sec > 4 &&
+ strncmp(ep - 4, ".zst", 4) == 0)
+ ep -= 4;
+ else if (ep - sec > 3 &&
strncmp(ep - 3, ".gz", 3) == 0)
ep -= 3;
if ((size_t)(ep - sec) < ssz + 3 ||
diff -ruN a/mandoc.3 b/mandoc.3
--- a/mandoc.3 2021-09-23 13:03:23.000000000 -0500
+++ b/mandoc.3 2026-05-29 18:09:19.497910732 -0500
@@ -273,10 +273,14 @@
If that fails and
.Fa fname
does not already end in
-.Ql .gz ,
+.Ql .gz
+or
+.Ql .zst ,
try again after appending
-.Ql .gz .
-Save the information whether the file is zipped or not.
+.Ql .gz
+and
+.Ql .zst .
+Save the information whether the file is compressed or not.
Return a file descriptor open for reading or -1 on failure.
It can be passed to
.Fn mparse_readfd
diff -ruN a/mandocdb.c b/mandocdb.c
--- a/mandocdb.c 2021-09-23 13:03:23.000000000 -0500
+++ b/mandocdb.c 2026-05-29 18:09:00.199398109 -0500
@@ -102,7 +102,7 @@
char *fsec; /* section from file name suffix */
struct mlink *next; /* singly linked list */
struct mpage *mpage; /* parent */
- int gzip; /* filename has a .gz suffix */
+ int gzip; /* filename has a compression suffix */
enum form dform; /* format from directory */
enum form fform; /* format from file name suffix */
};
@@ -580,7 +580,7 @@
FTS *f;
FTSENT *ff;
struct mlink *mlink;
- int gzip;
+ int compressed;
enum form dform;
char *dsec, *arch, *fsec, *cp;
const char *path;
@@ -645,13 +645,15 @@
say(path, "Extraneous file");
continue;
}
- gzip = 0;
+ compressed = 0;
fsec = NULL;
while (fsec == NULL) {
fsec = strrchr(ff->fts_name, '.');
- if (fsec == NULL || strcmp(fsec+1, "gz"))
+ if (fsec == NULL ||
+ (strcmp(fsec + 1, "gz") &&
+ strcmp(fsec + 1, "zst")))
break;
- gzip = 1;
+ compressed = 1;
*fsec = '\0';
fsec = NULL;
}
@@ -697,7 +699,7 @@
mlink->arch = arch;
mlink->name = ff->fts_name;
mlink->fsec = fsec;
- mlink->gzip = gzip;
+ mlink->gzip = compressed;
mlink_add(mlink, ff->fts_statp);
continue;
@@ -962,9 +964,19 @@
* Now check the file suffix.
* Suffix of `.0' indicates a catpage, `.1-9' is a manpage.
*/
- p = strrchr(start, '\0');
- while (p-- > start && *p != '/' && *p != '.')
- continue;
+ if ((p = strrchr(start, '/')) == NULL)
+ p = start;
+ else
+ p++;
+ if ((p = strrchr(p, '.')) != NULL &&
+ (strcmp(p + 1, "gz") == 0 || strcmp(p + 1, "zst") == 0))
+ *p = '\0';
+
+ for (p = strchr(start, '\0'); p > start; ) {
+ p--;
+ if (*p == '/' || *p == '.')
+ break;
+ }
if (*p == '.') {
*p++ = '\0';
@@ -1213,6 +1225,12 @@
mlink_dest = ohash_find(&mlinks,
ohash_qlookup(&mlinks, cp));
free(cp);
+ }
+ if (mlink_dest == NULL) {
+ mandoc_asprintf(&cp, "%s.zst", meta->sodest);
+ mlink_dest = ohash_find(&mlinks,
+ ohash_qlookup(&mlinks, cp));
+ free(cp);
}
if (mlink_dest != NULL) {
diff -ruN a/read.c b/read.c
--- a/read.c 2021-09-23 13:03:23.000000000 -0500
+++ b/read.c 2026-05-29 18:09:41.222488117 -0500
@@ -38,6 +38,7 @@
#include <string.h>
#include <unistd.h>
#include <zlib.h>
+#include <zstd.h>
#include "mandoc_aux.h"
#include "mandoc.h"
@@ -60,6 +61,7 @@
const char *os_s; /* default operating system */
int options; /* parser options */
int gzip; /* current input file is gzipped */
+ int zstd; /* current input file is zstd-compressed */
int filenc; /* encoding of the current file */
int reparse_count; /* finite interp. stack */
int line; /* line number in the file */
@@ -70,6 +72,7 @@
static void resize_buf(struct buf *, size_t);
static int mparse_buf_r(struct mparse *, struct buf, size_t, int);
static int read_whole_file(struct mparse *, int, struct buf *, int *);
+static int read_zstd_file(struct mparse *, int, struct buf *);
static void mparse_end(struct mparse *);
@@ -432,6 +435,89 @@
}
static int
+read_zstd_file(struct mparse *curp, int fd, struct buf *fb)
+{
+ ZSTD_DStream *zds;
+ ZSTD_inBuffer zin;
+ ZSTD_outBuffer zout;
+ char *ibuf;
+ size_t ibufsz, off, ret;
+ ssize_t ssz;
+ int eof, retval;
+
+ if ((zds = ZSTD_createDStream()) == NULL) {
+ mandoc_msg(MANDOCERR_READ, 0, 0,
+ "zstd: unable to allocate decompressor");
+ return -1;
+ }
+
+ ibufsz = ZSTD_DStreamInSize();
+ ibuf = mandoc_malloc(ibufsz);
+ zin.src = ibuf;
+ zin.size = 0;
+ zin.pos = 0;
+
+ fb->sz = 0;
+ fb->buf = NULL;
+ off = 0;
+ ret = 1;
+ eof = 0;
+ retval = -1;
+
+ while (eof == 0 || zin.pos < zin.size) {
+ if (zin.pos == zin.size && eof == 0) {
+ if ((ssz = read(fd, ibuf, ibufsz)) == -1) {
+ mandoc_msg(MANDOCERR_READ, 0, 0,
+ "%s", strerror(errno));
+ goto out;
+ }
+ if (ssz == 0) {
+ eof = 1;
+ continue;
+ }
+ zin.size = (size_t)ssz;
+ zin.pos = 0;
+ }
+
+ if (off == fb->sz) {
+ if (fb->sz == (1U << 31)) {
+ mandoc_msg(MANDOCERR_TOOLARGE, 0, 0, NULL);
+ goto out;
+ }
+ resize_buf(fb, 65536);
+ }
+
+ zout.dst = fb->buf + off;
+ zout.size = fb->sz - off;
+ zout.pos = 0;
+ ret = ZSTD_decompressStream(zds, &zout, &zin);
+ if (ZSTD_isError(ret)) {
+ mandoc_msg(MANDOCERR_READ, 0, 0,
+ "zstd: %s", ZSTD_getErrorName(ret));
+ goto out;
+ }
+ off += zout.pos;
+ }
+
+ if (ret != 0)
+ mandoc_msg(MANDOCERR_READ, 0, 0,
+ "zstd: unexpected end of file");
+ else {
+ fb->sz = off;
+ retval = 0;
+ }
+
+out:
+ free(ibuf);
+ ZSTD_freeDStream(zds);
+ if (retval == -1) {
+ free(fb->buf);
+ fb->buf = NULL;
+ }
+ return retval;
+}
+
+static int
read_whole_file(struct mparse *curp, int fd, struct buf *fb, int *with_mmap)
{
struct stat st;
@@ -452,7 +538,7 @@
* concerned that this is going to tank any machines.
*/
- if (curp->gzip == 0 && S_ISREG(st.st_mode)) {
+ if (curp->gzip == 0 && curp->zstd == 0 && S_ISREG(st.st_mode)) {
if (st.st_size > 0x7fffffff) {
mandoc_msg(MANDOCERR_TOOLARGE, 0, 0, NULL);
return -1;
@@ -464,6 +550,11 @@
return 0;
}
+ if (curp->zstd) {
+ *with_mmap = 0;
+ return read_zstd_file(curp, fd, fb);
+ }
+
if (curp->gzip) {
/*
* Duplicating the file descriptor is required
@@ -557,7 +648,7 @@
struct buf blk;
struct buf *save_primary;
- const char *save_filename, *cp;
+ const char *save_filename, *cp, *ep;
size_t offset;
int save_filenc, save_lineno;
int with_mmap;
@@ -565,12 +656,26 @@
if (recursion_depth > 64) {
mandoc_msg(MANDOCERR_ROFFLOOP, curp->line, 0, NULL);
return;
- } else if (recursion_depth == 0 &&
- (cp = strrchr(filename, '.')) != NULL &&
- cp[1] >= '1' && cp[1] <= '9')
- curp->man->filesec = cp[1];
- else
- curp->man->filesec = '\0';
+ } else if (recursion_depth == 0) {
+ ep = strrchr(filename, '.');
+ if (ep != NULL &&
+ (strcmp(ep + 1, "gz") == 0 ||
+ strcmp(ep + 1, "zst") == 0)) {
+ for (cp = ep; cp > filename; cp--)
+ if (cp[-1] == '.') {
+ cp--;
+ break;
+ }
+ if (cp == filename)
+ cp = NULL;
+ } else
+ cp = ep;
+ if (cp != NULL && cp[1] >= '1' && cp[1] <= '9')
+ curp->man->filesec = cp[1];
+ else
+ curp->man->filesec = '\0';
+ } else
+ curp->man->filesec = '\0';
if (read_whole_file(curp, fd, &blk, &with_mmap) == -1)
return;
@@ -623,11 +728,13 @@
int
mparse_open(struct mparse *curp, const char *file)
{
+ const char *ep;
char *cp;
int fd, save_errno;
- cp = strrchr(file, '.');
- curp->gzip = (cp != NULL && ! strcmp(cp + 1, "gz"));
+ ep = strrchr(file, '.');
+ curp->gzip = (ep != NULL && ! strcmp(ep + 1, "gz"));
+ curp->zstd = (ep != NULL && ! strcmp(ep + 1, "zst"));
/* First try to use the filename as it is. */
@@ -635,20 +742,27 @@
return fd;
/*
- * If that doesn't work and the filename doesn't
- * already end in .gz, try appending .gz.
+ * If that doesn't work and the filename doesn't already
+ * end in .gz or .zst, try appending these suffixes.
*/
- if ( ! curp->gzip) {
+ if ( ! curp->gzip && ! curp->zstd) {
save_errno = errno;
mandoc_asprintf(&cp, "%s.gz", file);
fd = open(cp, O_RDONLY);
free(cp);
- errno = save_errno;
if (fd != -1) {
curp->gzip = 1;
return fd;
}
+ mandoc_asprintf(&cp, "%s.zst", file);
+ fd = open(cp, O_RDONLY);
+ free(cp);
+ errno = save_errno;
+ if (fd != -1) {
+ curp->zstd = 1;
+ return fd;
+ }
}
/* Neither worked, give up. */
@@ -693,6 +807,7 @@
free_buf_list(curp->secondary);
curp->secondary = NULL;
curp->gzip = 0;
+ curp->zstd = 0;
tag_alloc();
}
diff -ruN a/test-zstd.c b/test-zstd.c
--- a/test-zstd.c 1969-12-31 18:00:00.000000000 -0600
+++ b/test-zstd.c 2026-05-29 18:06:59.682203510 -0500
@@ -0,0 +1,7 @@
+#include <zstd.h>
+
+int
+main(void)
+{
+ return ZSTD_versionNumber() == 0;
+}
-188
View File
@@ -1,188 +0,0 @@
--- a/Makefile.SH
+++ b/Makefile.SH
@@ -373,16 +373,64 @@
$spitshell >>$Makefile <<!GROK!THIS!
# Macros to invoke a copy of our fully operational perl during the build.
PERL_EXE = perl\$(EXE_EXT)
-RUN_PERL = \$(LDLIBPTH) \$(RUN) $perl\$(EXE_EXT)
+BUILD_PERL_INC = -Ilib -I. \
+ -Icpan/AutoLoader/lib \
+ -Idist/Carp/lib \
+ -Idist/PathTools \
+ -Idist/PathTools/lib \
+ -Icpan/ExtUtils-Install/lib \
+ -Icpan/ExtUtils-MakeMaker/lib \
+ -Icpan/ExtUtils-Manifest/lib \
+ -Icpan/File-Path/lib \
+ -Iext/re \
+ -Idist/Term-ReadLine/lib \
+ -Idist/Exporter/lib \
+ -Iext/File-Find/lib \
+ -Icpan/Text-Tabs/lib \
+ -Idist/constant/lib \
+ -Icpan/version/lib \
+ -Icpan/Getopt-Long/lib \
+ -Icpan/Text-ParseWords/lib \
+ -Icpan/ExtUtils-PL2Bat/lib \
+ -Icpan/parent/lib \
+ -Idist/ExtUtils-ParseXS/lib \
+ -Idist/base/lib \
+ -Idist/XSLoader
+RUN_PERL = \$(LDLIBPTH) \$(RUN) $perl\$(EXE_EXT) \$(BUILD_PERL_INC)
+RUN_MINIPERL = \$(LDLIBPTH) ./miniperl\$(EXE_EXT) \$(BUILD_PERL_INC)
!GROK!THIS!
;;
*)
$spitshell >>$Makefile <<!GROK!THIS!
# Macros to invoke a copy of our fully operational perl during the build.
PERL_EXE = perl\$(EXE_EXT)
-RUN_PERL = \$(LDLIBPTH) \$(RUN) ./perl\$(EXE_EXT) -Ilib -I.
-!GROK!THIS!
- ;;
+BUILD_PERL_INC = -Ilib -I. \
+ -Icpan/AutoLoader/lib \
+ -Idist/Carp/lib \
+ -Idist/PathTools \
+ -Idist/PathTools/lib \
+ -Icpan/ExtUtils-Install/lib \
+ -Icpan/ExtUtils-MakeMaker/lib \
+ -Icpan/ExtUtils-Manifest/lib \
+ -Icpan/File-Path/lib \
+ -Iext/re \
+ -Idist/Term-ReadLine/lib \
+ -Idist/Exporter/lib \
+ -Iext/File-Find/lib \
+ -Icpan/Text-Tabs/lib \
+ -Idist/constant/lib \
+ -Icpan/version/lib \
+ -Icpan/Getopt-Long/lib \
+ -Icpan/Text-ParseWords/lib \
+ -Icpan/ExtUtils-PL2Bat/lib \
+ -Icpan/parent/lib \
+ -Idist/ExtUtils-ParseXS/lib \
+ -Idist/base/lib \
+ -Idist/XSLoader
+RUN_PERL = \$(LDLIBPTH) \$(RUN) ./perl\$(EXE_EXT) \$(BUILD_PERL_INC)
+RUN_MINIPERL = \$(LDLIBPTH) ./miniperl\$(EXE_EXT) \$(BUILD_PERL_INC)
+!GROK!THIS!
+ ;;
esac
$spitshell >>$Makefile <<!GROK!THIS!
@@ -706,12 +754,20 @@
!NO!SUBS!
-# Making utilities requires Cwd. If we have dynamic
-# loading, we only need miniperl and Cwd.$dlext. If we have static
-# loading, we need to build perl first.
+# Making utilities requires Cwd. If we have dynamic loading, we only need
+# miniperl and the Cwd extension. If we have static loading, we need to
+# build perl first. Use an explicit helper target for the dynamic case so
+# makes that do not know how to drive the lib/auto/Cwd output directly still
+# have a concrete dependency to build.
case "$usedl$static_cwd" in
defineundef)
- util_deps='$(MINIPERL_EXE) $(CONFIGPM) lib/auto/Cwd/Cwd$(DLSUFFIX) FORCE'
+ util_deps='$(MINIPERL_EXE) $(CONFIGPM) buildext-Cwd FORCE'
+ $spitshell >>$Makefile <<'!NO!SUBS!'
+.PHONY: buildext-Cwd
+buildext-Cwd: $(MINIPERL_EXE) lib/buildcustomize.pl preplibrary makeppport $(DYNALOADER) FORCE $(PERLEXPORT) $(LIBPERL)
+ $(MINIPERL) make_ext.pl lib/auto/Cwd/Cwd$(DLSUFFIX) $(MAKE_EXT_ARGS) MAKE="$(MAKE)" LIBPERL_A=$(LIBPERL) LINKTYPE=dynamic
+
+!NO!SUBS!
;;
definedefine)
util_deps='$(PERL_EXE) $(CONFIGPM) FORCE'
@@ -820,8 +876,8 @@
case "$osname" in
amigaos*)
$spitshell >>$Makefile <<'!NO!SUBS!'
-perlmain.c: $(MINIPERL_EXE) ext/ExtUtils-Miniperl/pm_to_blib
- $(MINIPERL) -MExtUtils::Miniperl -e 'writemain(\\"perlmain.c", @ARGV)' DynaLoader $(static_ext)
+perlmain.c: $(MINIPERL_EXE) $(CONFIGPM) ext/ExtUtils-Miniperl/lib/ExtUtils/Miniperl.pm
+ $(MINIPERL) -Iext/ExtUtils-Miniperl/lib -MExtUtils::Miniperl -e 'writemain(\\"perlmain.c", @ARGV)' DynaLoader $(static_ext)
# The file ext.libs is a list of libraries that must be linked in
# for static extensions, e.g. -lm -lgdbm, etc. The individual
@@ -829,18 +885,24 @@
ext.libs: $(static_ext)
-@test -f ext.libs || touch ext.libs
+dist/XSLoader/XSLoader.pm: $(MINIPERL_EXE) $(CONFIGPM) dist/XSLoader/XSLoader_pm.PL
+ cd dist/XSLoader && ../../$(MINIPERL_EXE) -I../../lib XSLoader_pm.PL
+
!NO!SUBS!
;;
*)
$spitshell >>$Makefile <<'!NO!SUBS!'
-perlmain.c: $(MINIPERL_EXE) ext/ExtUtils-Miniperl/pm_to_blib
- $(MINIPERL) -MExtUtils::Miniperl -e 'writemain(\"perlmain.c", @ARGV)' DynaLoader $(static_ext)
+perlmain.c: $(MINIPERL_EXE) $(CONFIGPM) ext/ExtUtils-Miniperl/lib/ExtUtils/Miniperl.pm
+ $(MINIPERL) -Iext/ExtUtils-Miniperl/lib -MExtUtils::Miniperl -e 'writemain(\"perlmain.c", @ARGV)' DynaLoader $(static_ext)
# The file ext.libs is a list of libraries that must be linked in
# for static extensions, e.g. -lm -lgdbm, etc. The individual
# static extension Makefile's add to it.
ext.libs: $(static_ext)
-@test -f ext.libs || touch ext.libs
+
+dist/XSLoader/XSLoader.pm: $(MINIPERL_EXE) $(CONFIGPM) dist/XSLoader/XSLoader_pm.PL
+ cd dist/XSLoader && ../../$(MINIPERL_EXE) -I../../lib XSLoader_pm.PL
!NO!SUBS!
;;
@@ -1130,11 +1192,12 @@
# can in this makefile to decide if needs to run or not
# touch uni.data
-# $(PERL_EXE) and ext because pod_lib.pl needs Digest::MD5
-# But also this ensures that all extensions are built before we try to scan
+# Build this with miniperl plus the same expanded \@INC as RUN_PERL so
+# File::Spec can load PathTools without needing the XS Cwd extension.
+# $(ext) still ensures that all extensions are built before we try to scan
# them, which picks up Devel::PPPort's documentation.
-pod/perltoc.pod: $(perltoc_pod_prereqs) $(PERL_EXE) $(ext) pod/buildtoc
- $(RUN_PERL) -f pod/buildtoc -q
+pod/perltoc.pod: $(perltoc_pod_prereqs) $(MINIPERL_EXE) $(ext) pod/buildtoc
+ $(RUN_MINIPERL) -f pod/buildtoc -q
pod/perlapi.pod: pod/perlintern.pod
@@ -1300,11 +1363,11 @@
.PHONY: manisort manicheck
manisort: FORCE
- @perl Porting/manisort -q || (echo "WARNING: re-sorting MANIFEST"; \
- perl Porting/manisort -q -o MANIFEST; sh -c true)
+ @$(RUN_PERL) Porting/manisort -q || (echo "WARNING: re-sorting MANIFEST"; \
+ $(RUN_PERL) Porting/manisort -q -o MANIFEST; sh -c true)
manicheck: FORCE
- perl Porting/manicheck
+ $(RUN_PERL) Porting/manicheck
# Extensions:
# Names added to $(dynamic_ext) or $(static_ext) or $(nonxs_ext) will
--- a/write_buildcustomize.pl
+++ b/write_buildcustomize.pl
@@ -47,15 +47,16 @@
cpan/Getopt-Long/lib
cpan/Text-ParseWords/lib
cpan/ExtUtils-PL2Bat/lib
+ cpan/parent/lib
+ dist/ExtUtils-ParseXS/lib
+ dist/base/lib
+ dist/XSLoader
);
# These are for XS building on Win32, since nonxs and xs build simultaneously
# on Win32 if parallel building
push @toolchain, qw(
- dist/ExtUtils-ParseXS/lib
- cpan/parent/lib
cpan/ExtUtils-Constant/lib
- dist/base/lib
) if $^O eq 'MSWin32';
push @toolchain, 'ext/VMS-Filespec/lib' if $^O eq 'VMS';