CI updates

This commit is contained in:
Markus F.X.J. Oberhumer 2024-05-01 13:11:12 +02:00
parent b0dc483165
commit 8393ded1b3
11 changed files with 136 additions and 46 deletions

View File

@ -50,8 +50,7 @@ jobs:
curl -sS -L https://github.com/upx/upx-stubtools/releases/download/v20221212/bin-upx-20221212.tar.xz | tar -xJ
- name: 'Check out code'
run: |
# this seems to be needed when running in a container (beause of UID mismatch??)
git config --global --add safe.directory '*'
git config --global --add safe.directory '*' # needed when running in a container
git clone --branch "$GITHUB_REF_NAME" --depth 1 "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY" .
git submodule update --init -- vendor/lzma-sdk
- name: 'Rebuild and verify stubs'
@ -292,7 +291,7 @@ jobs:
with: { submodules: true }
- name: 'Check out test suite'
run: 'git clone --depth=1 https://github.com/upx/upx-testsuite ../deps/upx-testsuite'
- name: 'Set up Developer Command Prompt'
- name: 'Set up MSVC Developer Command Prompt'
uses: ilammy/msvc-dev-cmd@v1
with:
vsversion: ${{ matrix.vsversion }}
@ -358,7 +357,7 @@ jobs:
mkdir -p -v build/$C/$B/{bzip2,ucl,upx,zlib,zstd}
repository_name="${GITHUB_REPOSITORY##*/}" # basename
echo "H=d:\\a\\$repository_name\\$repository_name" >> $GITHUB_ENV
- name: 'Set up Developer Command Prompt'
- name: 'Set up MSVC Developer Command Prompt'
uses: ilammy/msvc-dev-cmd@v1
with:
vsversion: ${{ matrix.vsversion }}
@ -464,8 +463,8 @@ jobs:
- { zig_target: mips-linux-musl, zig_flags: -msoft-float, qemu: qemu-mips }
- { zig_target: mipsel-linux-musl, zig_flags: -msoft-float, qemu: qemu-mipsel }
- { zig_target: powerpc-linux-musl, qemu: qemu-ppc }
# powerpc64: obscure problem with C++ exceptions in UPX doctest checks when *NOT* using -fstack-protector
- { zig_target: powerpc64-linux-musl, zig_flags: -fstack-protector, qemu: qemu-ppc64 }
# powerpc64: obscure problem with C++ exceptions in UPX doctest checks; use -fPIC to work-around
- { zig_target: powerpc64-linux-musl, zig_flags: -fPIC, qemu: qemu-ppc64 }
- { zig_target: powerpc64le-linux-musl, qemu: qemu-ppc64le }
- { zig_target: x86_64-linux-gnu.2.3.4 }
- { zig_target: x86_64-linux-musl, qemu: qemu-x86_64 }
@ -492,8 +491,7 @@ jobs:
mkdir -p ~/.parallel && : > ~/.parallel/$(echo 6305-4721 | tr 0-7 leticlwi)
# set PATH like in Ubuntu
echo "PATH=$HOME/.local/bin:$PATH" >> $GITHUB_ENV
# this seems to be needed when running in a container (beause of UID mismatch??)
git config --global --add safe.directory '*'
git config --global --add safe.directory '*' # needed when running in a container
- name: 'Check out code'
uses: actions/checkout@v4
with: { submodules: true }

View File

@ -0,0 +1,39 @@
# Copyright (C) Markus Franz Xaver Johannes Oberhumer
# see https://docs.github.com/en/actions/managing-issues-and-pull-requests/closing-inactive-issues
# see https://github.com/actions/stale
# Automatically closing issues is far from perfect, but then we only
# have limited resources and this approach favors issues that people
# actually care about.
#
# also see:
# "Should I Stale or Should I Close? An Analysis of a Bot that Closes
# Abandoned Issues and Pull Request".
# https://igorwiese.com/images/papers/Paper_BotSE_19.pdf
name: 'GitHub - Close stale issues'
on:
schedule: [cron: '50 0 * * 1'] # run weekly Monday 00:50 UTC
workflow_dispatch:
jobs:
job-close-stale-issues:
if: github.repository_owner == 'upx' && github.repository == 'upx/upx'
name: 'Close stale issues'
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v9
with:
operations-per-run: 300
exempt-all-milestones: true
exempt-issue-labels: 'blocker,bug,enhancement,help wanted,regression'
days-before-stale: 90
days-before-close: 30
stale-issue-message: 'This issue is stale because it has been open for 90 days with no activity. Please remove the stale label or add a comment or this issue will be closed in 30 days.'
stale-pr-message: 'This PR is stale because it has been open for 90 days with no activity. Please remove the stale label or add a comment or this PR will be closed in 30 days.'
close-issue-message: 'This issue was closed because it has been stalled for 30 days with no activity. Please feel free to reopen.'
close-pr-message: 'This PR was closed because it has been stalled for 30 days with no activity. Please feel free to reopen.'
repo-token: ${{ secrets.GITHUB_TOKEN }}

View File

@ -8,21 +8,41 @@
# print some info about the build configuration
#***********************************************************************
# generator
upx_print_var(CMAKE_GENERATOR_TOOLSET CMAKE_GENERATOR_PLATFORM)
# directories
if(NOT ",${CMAKE_BINARY_DIR}," STREQUAL ",${CMAKE_CURRENT_BINARY_DIR}," OR NOT ",${CMAKE_SOURCE_DIR}," STREQUAL ",${CMAKE_CURRENT_SOURCE_DIR},")
upx_print_var(CMAKE_BINARY_DIR CMAKE_SOURCE_DIR CMAKE_CURRENT_BINARY_DIR CMAKE_CURRENT_SOURCE_DIR)
endif()
upx_print_var(CMAKE_HOST_SYSTEM_NAME CMAKE_HOST_SYSTEM_VERSION CMAKE_HOST_SYSTEM_PROCESSOR CMAKE_APPLE_SILICON_PROCESSOR)
upx_print_var(CMAKE_SYSTEM_NAME CMAKE_SYSTEM_VERSION CMAKE_SYSTEM_PROCESSOR CMAKE_CROSSCOMPILING CMAKE_CROSSCOMPILING_EMULATOR)
upx_print_var(CMAKE_OSX_DEPLOYMENT_TARGET CMAKE_OSX_SYSROOT)
# system
upx_print_var(CMAKE_HOST_SYSTEM_NAME CMAKE_HOST_SYSTEM_VERSION CMAKE_HOST_SYSTEM_PROCESSOR)
upx_print_var(CMAKE_SYSTEM_NAME CMAKE_SYSTEM_VERSION CMAKE_SYSTEM_PROCESSOR)
upx_print_var(CMAKE_ANDROID_NDK CMAKE_ANDROID_NDK_VERSION CMAKE_ANDROID_STANDALONE_TOOLCHAIN)
upx_print_var(CMAKE_APPLE_SILICON_PROCESSOR CMAKE_OSX_DEPLOYMENT_TARGET CMAKE_OSX_SYSROOT)
upx_print_Var(CMAKE_CROSSCOMPILING CMAKE_CROSSCOMPILING_EMULATOR)
upx_print_var(CMAKE_C_COMPILER_LAUNCHER CMAKE_CXX_COMPILER_LAUNCHER)
upx_print_var(CMAKE_C_COMPILER CMAKE_CXX_COMPILER CMAKE_AR CMAKE_RANLIB)
upx_print_var(CMAKE_C_COMPILER_ID CMAKE_C_COMPILER_VERSION CMAKE_C_COMPILER_FRONTEND_VARIANT CMAKE_C_COMPILER_ARCHITECTURE_ID CMAKE_C_PLATFORM_ID CMAKE_C_COMPILER_ABI)
upx_print_var(CMAKE_CXX_COMPILER_ID CMAKE_CXX_COMPILER_VERSION CMAKE_CXX_COMPILER_FRONTEND_VARIANT CMAKE_CXX_COMPILER_ARCHITECTURE_ID CMAKE_CXX_PLATFORM_ID CMAKE_CXX_COMPILER_ABI)
# binutils
upx_print_var(CMAKE_AR CMAKE_OBJCOPY CMAKE_RANLIB)
# compilers
foreach(lang IN ITEMS ASM C CXX)
upx_print_var(CMAKE_${lang}_COMPILER_LAUNCHER)
upx_print_var(CMAKE_${lang}_COMPILER)
upx_print_var(CMAKE_${lang}_COMPILER_ID)
upx_print_var(CMAKE_${lang}_COMPILER_VERSION)
upx_print_var(CMAKE_${lang}_COMPILER_FRONTEND_VARIANT )
upx_print_var(CMAKE_${lang}_COMPILER_ARCHITECTURE_ID)
upx_print_var(CMAKE_${lang}_PLATFORM_ID)
upx_print_var(CMAKE_${lang}_COMPILER_ABI)
upx_print_var(CMAKE_${lang}_COMPILER_TARGET)
endforeach()
# misc
upx_print_var(CMAKE_INTERPROCEDURAL_OPTIMIZATION CMAKE_POSITION_INDEPENDENT_CODE CMAKE_TRY_COMPILE_CONFIGURATION)
# shortcuts
upx_print_var(APPLE CLANG CYGWIN GNU_FRONTEND GNUC MINGW MSVC MSVC_FRONTEND MSVC_IDE MSVC_TOOLSET_VERSION MSVC_VERSION MSYS UNIX WIN32 WIN64)
# vim:set ft=cmake ts=4 sw=4 tw=0 et:

View File

@ -23,7 +23,7 @@ if [[ 1 == 1 ]]; then
# NOTE: we mount the upx top-level directory read-write under /home/upx/src/upx
# INFO: SELinux users *may* have to add ":z" to the volume mount flags; check the docs!
flags+=( -v "${argv0dir}/../../..:/home/upx/src/upx" )
flags+=( -w /home/upx/src/upx ) # set working directory
flags+=( -w /home/upx/src/upx ) # set working directory
flags+=( --tmpfs /home/upx/.cache:rw,exec ) # mount a writeable tmpfs
flags+=( --tmpfs /home/upx/.config:rw,exec ) # mount a writeable tmpfs
flags+=( --tmpfs /home/upx/.local:rw,exec ) # mount a writeable tmpfs

View File

@ -29,6 +29,7 @@ podman run "${flags[@]}" "$image" bash -c $'
set -ex; set -o pipefail
cd /home/upx/src/upx/src/stub
make maintainer-clean extra-clean
git status . || true # make sure the stub files got deleted
make extra-all all
echo "===== Rebuilt stubs. All done. ====="
exit 0

View File

@ -30,7 +30,7 @@ ii cpp 4:13.2.0-7ubuntu1 amd64
ii cpp-13 13.2.0-23ubuntu4 amd64 GNU C preprocessor
ii cpp-13-x86-64-linux-gnu 13.2.0-23ubuntu4 amd64 GNU C preprocessor for x86_64-linux-gnu
ii cpp-x86-64-linux-gnu 4:13.2.0-7ubuntu1 amd64 GNU C preprocessor (cpp) for the amd64 architecture
ii curl 8.5.0-2ubuntu10 amd64 command line tool for transferring data with URL syntax
ii curl 8.5.0-2ubuntu10.1 amd64 command line tool for transferring data with URL syntax
ii dash 0.5.12-6ubuntu5 amd64 POSIX-compliant shell
ii debconf 1.5.86ubuntu1 all Debian configuration management system
ii debianutils 5.17build1 amd64 Miscellaneous utilities specific to Debian
@ -78,7 +78,7 @@ ii init-system-helpers 1.66ubuntu1 all
ii jq 1.7.1-3build1 amd64 lightweight and flexible command-line JSON processor
ii ksh 20240113 all transitional package
ii ksh93u+m 1.0.8-1 amd64 AT&T KornShell
ii less 590-2ubuntu2 amd64 pager program similar to more
ii less 590-2ubuntu2.1 amd64 pager program similar to more
ii lib32asan8 14-20240412-0ubuntu1 amd64 AddressSanitizer -- a fast memory error detector (32bit)
ii lib32atomic1 14-20240412-0ubuntu1 amd64 support library providing __atomic built-in functions (32bit)
ii lib32gcc-13-dev 13.2.0-23ubuntu4 amd64 GCC support library (32 bit development files)
@ -107,15 +107,15 @@ ii libbrotli1:amd64 1.1.0-2build2 amd64
ii libbsd0:amd64 0.12.1-1build1 amd64 utility functions from BSD systems - shared library
ii libbz2-1.0:amd64 1.0.8-5.1 amd64 high-quality block-sorting file compressor library - runtime
ii libbzip3-0:amd64 1.4.0-1 amd64 better, faster and stronger spiritual successor to bzip2 - runtime
ii libc-bin 2.39-0ubuntu8 amd64 GNU C Library: Binaries
ii libc-dev-bin 2.39-0ubuntu8 amd64 GNU C Library: Development binaries
ii libc6-dev-i386 2.39-0ubuntu8 amd64 GNU C Library: 32-bit development libraries for AMD64
ii libc6-dev-x32 2.39-0ubuntu8 amd64 GNU C Library: X32 ABI Development Libraries for AMD64
ii libc6-dev:amd64 2.39-0ubuntu8 amd64 GNU C Library: Development Libraries and Header Files
ii libc6-i386 2.39-0ubuntu8 amd64 GNU C Library: 32-bit shared libraries for AMD64
ii libc6-x32 2.39-0ubuntu8 amd64 GNU C Library: X32 ABI Shared libraries for AMD64
ii libc6:amd64 2.39-0ubuntu8 amd64 GNU C Library: Shared libraries
ii libc6:i386 2.39-0ubuntu8 i386 GNU C Library: Shared libraries
ii libc-bin 2.39-0ubuntu8.1 amd64 GNU C Library: Binaries
ii libc-dev-bin 2.39-0ubuntu8.1 amd64 GNU C Library: Development binaries
ii libc6-dev-i386 2.39-0ubuntu8.1 amd64 GNU C Library: 32-bit development libraries for AMD64
ii libc6-dev-x32 2.39-0ubuntu8.1 amd64 GNU C Library: X32 ABI Development Libraries for AMD64
ii libc6-dev:amd64 2.39-0ubuntu8.1 amd64 GNU C Library: Development Libraries and Header Files
ii libc6-i386 2.39-0ubuntu8.1 amd64 GNU C Library: 32-bit shared libraries for AMD64
ii libc6-x32 2.39-0ubuntu8.1 amd64 GNU C Library: X32 ABI Shared libraries for AMD64
ii libc6:amd64 2.39-0ubuntu8.1 amd64 GNU C Library: Shared libraries
ii libc6:i386 2.39-0ubuntu8.1 i386 GNU C Library: Shared libraries
ii libcap-ng0:amd64 0.8.4-2build2 amd64 alternate POSIX capabilities library
ii libcap2:amd64 1:2.66-5ubuntu2 amd64 POSIX 1003.1e capabilities (library)
ii libcares2:amd64 1.27.0-1.0ubuntu1 amd64 asynchronous name resolver
@ -125,8 +125,8 @@ ii libcrypt-dev:amd64 1:4.4.36-4build1 amd64
ii libcrypt1:amd64 1:4.4.36-4build1 amd64 libcrypt shared library
ii libctf-nobfd0:amd64 2.42-4ubuntu2 amd64 Compact C Type Format library (runtime, no BFD dependency)
ii libctf0:amd64 2.42-4ubuntu2 amd64 Compact C Type Format library (runtime, BFD dependency)
ii libcurl3t64-gnutls:amd64 8.5.0-2ubuntu10 amd64 easy-to-use client-side URL transfer library (GnuTLS flavour)
ii libcurl4t64:amd64 8.5.0-2ubuntu10 amd64 easy-to-use client-side URL transfer library (OpenSSL flavour)
ii libcurl3t64-gnutls:amd64 8.5.0-2ubuntu10.1 amd64 easy-to-use client-side URL transfer library (GnuTLS flavour)
ii libcurl4t64:amd64 8.5.0-2ubuntu10.1 amd64 easy-to-use client-side URL transfer library (OpenSSL flavour)
ii libdb5.3t64:amd64 5.3.28+dfsg2-7 amd64 Berkeley v5.3 Database Libraries [runtime]
ii libdebconfclient0:amd64 0.271ubuntu3 amd64 Debian Configuration Management System (C-implementation library)
ii libdebuginfod-common 0.190-1.1build4 all configuration to enable the Debian debug info server
@ -145,7 +145,7 @@ ii libgdbm-compat4t64:amd64 1.23-5.1build1 amd64
ii libgdbm6t64:amd64 1.23-5.1build1 amd64 GNU dbm database routines (runtime version)
ii libglib2.0-0t64:amd64 2.80.0-6ubuntu1 amd64 GLib library of C routines
ii libgmp10:amd64 2:6.3.0+dfsg-2ubuntu6 amd64 Multiprecision arithmetic library
ii libgnutls30t64:amd64 3.8.3-1.1ubuntu3 amd64 GNU TLS library - main runtime library
ii libgnutls30t64:amd64 3.8.3-1.1ubuntu3.1 amd64 GNU TLS library - main runtime library
ii libgomp1:amd64 14-20240412-0ubuntu1 amd64 GCC OpenMP (GOMP) support library
ii libgpg-error0:amd64 1.47-3build2 amd64 GnuPG development runtime library
ii libgprofng0:amd64 2.42-4ubuntu2 amd64 GNU Next Generation profiler (runtime library)
@ -356,7 +356,7 @@ ii zstd 1.5.5+dfsg2-2build1 amd64
||/ Name Version Architecture Description
Packages sorted by Installed-Size:
874046 ===== TOTAL (350 packages)
874050 ===== TOTAL (350 packages)
72249 gcc-13-x86-64-linux-gnu amd64
37841 g++-13-x86-64-linux-gnu amd64
36493 cmake amd64
@ -432,7 +432,7 @@ Packages sorted by Installed-Size:
2770 libx32stdc++6 amd64
2431 zsh amd64
2419 passwd amd64
2348 libgnutls30t64 amd64
2352 libgnutls30t64 amd64
2346 libbinutils amd64
2191 ht amd64
2182 libc-bin amd64

View File

@ -329,6 +329,13 @@ struct TestIntegerWrap {
// basic exception handling checks to early catch toolchain/qemu/wine/etc problems
//
struct TestDestructor {
explicit TestDestructor(int *pp, int vv) noexcept : p(pp), v(vv) {}
virtual noinline ~TestDestructor() noexcept { *p = (*p << 2) + v; }
int *p;
int v;
};
static noinline void throwSomeValue(int x) may_throw {
if (x < 0)
throw int(x);
@ -336,12 +343,19 @@ static noinline void throwSomeValue(int x) may_throw {
throw size_t(x);
}
static noinline void check_exceptions_2(void (*func)(int), int *x) may_throw {
TestDestructor d(x, *x);
func(*x);
}
static noinline void check_basic_cxx_exception_handling(void (*func)(int)) noexcept {
bool cxx_exception_handling_works = false;
int x = 1;
try {
func(42);
TestDestructor d(&x, 3);
check_exceptions_2(func, &x);
} catch (const size_t &e) {
if (e == 42)
if (e == 1 && x == 23)
cxx_exception_handling_works = true;
} catch (...) {
}
@ -490,13 +504,18 @@ void upx_compiler_sanity_check(void) noexcept {
COMPILE_TIME_ASSERT_ALIGNED1(upx_charptr_unit_type)
COMPILE_TIME_ASSERT(sizeof(*((charptr) nullptr)) == 1)
COMPILE_TIME_ASSERT(sizeof(UPX_VERSION_STRING4) == 4 + 1)
assert_noexcept(strlen(UPX_VERSION_STRING4) == 4);
COMPILE_TIME_ASSERT(sizeof(UPX_VERSION_YEAR) == 4 + 1)
assert_noexcept(strlen(UPX_VERSION_YEAR) == 4);
assert_noexcept(memcmp(UPX_VERSION_DATE_ISO, UPX_VERSION_YEAR, 4) == 0);
assert_noexcept(
memcmp(&UPX_VERSION_DATE[sizeof(UPX_VERSION_DATE) - 1 - 4], UPX_VERSION_YEAR, 4) == 0);
{
using upx::compile_time::mem_eq;
using upx::compile_time::string_len;
static_assert(string_len(UPX_VERSION_STRING4) == 4);
static_assert(string_len(UPX_VERSION_YEAR) == 4);
static_assert(string_len(UPX_VERSION_DATE_ISO) == 10);
static_assert(string_len(UPX_VERSION_DATE) == 12 || string_len(UPX_VERSION_DATE) == 13);
static_assert(mem_eq(UPX_VERSION_STRING, UPX_VERSION_STRING4, 3));
static_assert(mem_eq(UPX_VERSION_DATE_ISO, UPX_VERSION_YEAR, 4));
static_assert(mem_eq(&UPX_VERSION_DATE[sizeof(UPX_VERSION_DATE) - 5], UPX_VERSION_YEAR, 4));
}
if (gitrev[0]) {
size_t revlen = strlen(gitrev);
if (strncmp(gitrev, "ERROR", 5) == 0) {

View File

@ -105,6 +105,12 @@ ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_gt("abc", "abz"))
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_ge("abc", "abz"))
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_le("abc", "abz"))
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::mem_eq((const char *) nullptr, nullptr, 0))
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::mem_eq((const byte *) nullptr, nullptr, 0))
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::mem_eq("", "", 0))
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::mem_eq("abc", "abc", 3))
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::mem_eq("abc", "abz", 3))
/*************************************************************************
//
**************************************************************************/

View File

@ -592,7 +592,7 @@ void ElfLinkerAMD64::relocate1(const Relocation *rel, byte *location, upx_uint64
}
if (strcmp(type, "8") == 0) {
int displ = (signed char) *location + (int) value;
int displ = (upx_int8_t) *location + (int) value;
if (range_check && (displ < -128 || displ > 127))
internal_error("target out of range (%d) in reloc %s:%x\n", displ, rel->section->name,
rel->offset);
@ -846,7 +846,7 @@ void ElfLinkerPpc64le::relocate1(const Relocation *rel, byte *location, upx_uint
// FIXME: displacement overflow?
set_le32(location, (0xfc000003 & get_le32(location)) + (0x03fffffc & value));
} else if (strcmp(type, "8") == 0) {
int displ = (signed char) *location + (int) value;
int displ = (upx_int8_t) *location + (int) value;
if (range_check && (displ < -128 || displ > 127))
internal_error("target out of range (%d) in reloc %s:%x\n", displ, rel->section->name,
rel->offset);
@ -896,7 +896,7 @@ void ElfLinkerPpc64::relocate1(const Relocation *rel, byte *location, upx_uint64
// FIXME: displacement overflow?
set_be32(location, (0xfc000003 & get_be32(location)) + (0x03fffffc & value));
} else if (strcmp(type, "8") == 0) {
int displ = (signed char) *location + (int) value;
int displ = (upx_int8_t) *location + (int) value;
if (range_check && (displ < -128 || displ > 127))
internal_error("target out of range (%d) in reloc %s:%x\n", displ, rel->section->name,
rel->offset);
@ -925,7 +925,7 @@ void ElfLinkerX86::relocate1(const Relocation *rel, byte *location, upx_uint64_t
}
if (strcmp(type, "8") == 0) {
int displ = (signed char) *location + (int) value;
int displ = (upx_int8_t) *location + (int) value;
if (range_check && (displ < -128 || displ > 127))
internal_error("target out of range (%d,%d,%llu) in reloc %s:%x\n", displ, *location,
value, rel->section->name, rel->offset);

View File

@ -117,7 +117,7 @@ static const Lc_seg_info lc_seg_info[2] = {
// > 0 : actual size
// < 0 : neg. of minimum size; total must be (0 mod 4) or (0 mod 8)
//
static const signed char lc_cmd_size[] = {
static const upx_int8_t lc_cmd_size[] = {
// 2021-12: gcc 11.2.1 does not support 'sizeof' in designated initializer.
// 2021-12: gcc 11.2.1 does not support [enum] as designator.
// 2021-12: "clang++-10 -std=c++14":

View File

@ -241,6 +241,13 @@ constexpr bool string_ne(const char *a, const char *b) { return !string_eq(a, b)
constexpr bool string_gt(const char *a, const char *b) { return string_lt(b, a); }
constexpr bool string_le(const char *a, const char *b) { return !string_lt(b, a); }
constexpr bool string_ge(const char *a, const char *b) { return !string_lt(a, b); }
constexpr bool mem_eq(const char *a, const char *b, size_t n) {
return n == 0 || (*a == *b && mem_eq(a + 1, b + 1, n - 1));
}
constexpr bool mem_eq(const unsigned char *a, const unsigned char *b, size_t n) {
return n == 0 || (*a == *b && mem_eq(a + 1, b + 1, n - 1));
}
} // namespace compile_time
/*************************************************************************