Etapa G: tanda C tier-2 construye+corre — 6 al corpus (45->51) + wrap abuild local

BUILD-YIELD C MEDIDO (no especulacion): 6/8 de la tanda construyen+corren como ELF
estatico musl. Promovidos: file 5.47, gawk 5.3.2, gzip 1.14, tar 1.35, tree 2.3.2,
which 2.23 (+ sus parches musl de Alpine).

Texture honesta del tier-2 C (la friccion que el tier-1 Rust no tiene):
- gawk/tar/tree/which: zig-cc directo, sin tocar nada.
- file: zig-cc MISCOMPILA -> el `file` recien hecho segfaultea generando magic.mgc
  (mismo sintoma que binutils). Escape compiler="gcc" -> construye.
- gzip: (1) configure "C compiler cannot create executables" con zig-cc -> compiler="gcc";
  (2) luego el install fallaba por `local i;` de la package() de Alpine.
- jq (oniguruma), sed (perl): NO build-friction sino dep faltante en el corpus
  (completitud) -> quedan pendientes hasta importar esas libs.

Fix generico que destrabo gzip (y futuros): el importador Alpine ENVUELVE el cuerpo de
build()/package() en una funcion shell. abuild los corre COMO funciones (donde `local`
es valido); el lab corre la fase plana bajo sh -c, donde `local` fuera de funcion es
error. Envolver restaura el contexto de abuild sin tocar el sandbox ni las fases planas
del corpus (solo lo importado). test translate_wraps_body_in_function_for_local.

Confirmado: los 6 binarios corren (--version). file/gzip llevan compiler="gcc" en su
receta (escape declarativo, gueto conocido).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-21 10:07:08 -04:00
co-authored by Claude Opus 4.8
parent db84ee6647
commit 89061cac03
12 changed files with 419 additions and 2 deletions
+19 -2
View File
@@ -260,13 +260,20 @@ fn func_body(text: &str, name: &str) -> Option<String> {
/// NO toca `$CBUILD/$CHOST/$srcdir/$builddir` ni `--shared`. `$CBUILD/$CHOST` los RESUELVE el lab en
/// runtime (env con el triple nativo saneado, Etapa G Fase 3 — `hammer-build`); `$srcdir/$builddir` y
/// `--shared` quedan para el humano. `make DESTDIR="$pkgdir"` → `make DESTDIR="/out"`.
///
/// Además ENVUELVE el cuerpo en una función shell: abuild ejecuta `build()/package()` COMO funciones,
/// donde `local i; …` es válido; el lab corre la fase bajo `sh -c "<cuerpo>"` plano, donde `local`
/// fuera de función es error (rompía gzip al instalar). Envolver restaura el contexto de abuild sin
/// tocar el sandbox ni las fases planas escritas a mano del corpus (sólo se envuelve lo importado).
fn translate_abuild(body: &str, name: &str, version: &str) -> String {
body.replace("${pkgdir}", "/out")
let subst = body
.replace("${pkgdir}", "/out")
.replace("$pkgdir", "/out")
.replace("${pkgname}", name)
.replace("$pkgname", name)
.replace("${pkgver}", version)
.replace("$pkgver", version)
.replace("$pkgver", version);
format!("_abuild_phase() {{\n{subst}\n}}\n_abuild_phase")
}
/// Primer hash de un bloque `sha512sums="<hash> <fichero>\n..."`.
@@ -348,6 +355,16 @@ package() {
assert!(!t.contains("$pkg"));
}
#[test]
fn translate_wraps_body_in_function_for_local() {
// abuild package() usa `local i;` (válido en función); el lab corre la fase plana ⇒ hay que
// envolverla o `local` rompe (gzip). El cuerpo queda DENTRO de la función, invocada al final.
let t = translate_abuild("local i; for i in a b; do mv $i /out/; done", "p", "1");
assert!(t.starts_with("_abuild_phase() {"), "{t}");
assert!(t.trim_end().ends_with("_abuild_phase"), "se invoca al final: {t}");
assert!(t.contains("local i;"), "el `local` se preserva dentro de la función: {t}");
}
#[test]
fn no_patches_is_empty() {
let apk = "pkgname=zlib\npkgver=1.3\nsource=\"https://zlib.net/zlib-$pkgver.tar.gz\"\nsha512sums=\"x z\"\n";
@@ -0,0 +1,76 @@
From 80297b6e252963d2c08f84f40bc3b5e517505ff4 Mon Sep 17 00:00:00 2001
From: Natanael Copa <ncopa@alpinelinux.org>
Date: Tue, 10 Mar 2026 11:54:48 +0100
Subject: [PATCH] softmagic: compare FILE_GUID values in wire format
Comparing GUIDs with memcmp() on native struct storage breaks on
big-endian systems like s390x, since EFI GUIDs are stored in mixed-endian
wire format. Convert the parsed magic GUID to on-disk byte order before
comparing against file contents.
Fixes efi-signature-list-sha256 test on s390x.
---
src/file.h | 1 +
src/funcs.c | 20 ++++++++++++++++++++
src/softmagic.c | 2 +-
3 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/src/file.h b/src/file.h
index 06cf91d1..6f4087cd 100644
--- a/src/file.h
+++ b/src/file.h
@@ -559,6 +559,7 @@ file_protected int file_checkfmt(char *, size_t, const char *);
file_protected size_t file_printedlen(const struct magic_set *);
file_protected int file_print_guid(char *, size_t, const uint64_t *);
file_protected int file_parse_guid(const char *, uint64_t *);
+file_protected int file_compare_guid(const uint64_t *, const uint64_t *);
file_protected int file_replace(struct magic_set *, const char *, const char *);
file_protected int file_printf(struct magic_set *, const char *, ...)
__attribute__((__format__(__printf__, 2, 3)));
diff --git a/src/funcs.c b/src/funcs.c
index fa62b26d..c3cc0341 100644
--- a/src/funcs.c
+++ b/src/funcs.c
@@ -955,6 +955,26 @@ file_print_guid(char *str, size_t len, const uint64_t *guid)
#endif
}
+file_protected int
+file_compare_guid(const uint64_t *mguid, const uint64_t *fguid)
+{
+ const struct guid *m = CAST(const struct guid *, CAST(const void *, mguid));
+ const unsigned char *f = CAST(const unsigned char *, CAST(const void *, fguid));
+ unsigned char mbuf[16];
+
+ mbuf[0] = (unsigned char)(m->data1);
+ mbuf[1] = (unsigned char)(m->data1 >> 8);
+ mbuf[2] = (unsigned char)(m->data1 >> 16);
+ mbuf[3] = (unsigned char)(m->data1 >> 24);
+ mbuf[4] = (unsigned char)(m->data2);
+ mbuf[5] = (unsigned char)(m->data2 >> 8);
+ mbuf[6] = (unsigned char)(m->data3);
+ mbuf[7] = (unsigned char)(m->data3 >> 8);
+ memcpy(mbuf + 8, m->data4, 8);
+
+ return memcmp(mbuf, f, 16);
+}
+
file_protected int
file_pipe_closexec(int *fds)
{
diff --git a/src/softmagic.c b/src/softmagic.c
index 1a198005..ee85356d 100644
--- a/src/softmagic.c
+++ b/src/softmagic.c
@@ -2407,7 +2407,7 @@ magiccheck(struct magic_set *ms, struct magic *m, file_regex_t **m_cache)
return matched;
case FILE_GUID:
l = 0;
- v = memcmp(m->value.guid, p->guid, sizeof(p->guid));
+ v = file_compare_guid(m->value.guid, p->guid);
break;
default:
file_magerror(ms, "invalid type %d in magiccheck()", m->type);
--
2.53.0
@@ -0,0 +1,25 @@
Patch-Source: https://github.com/file/file/commit/c54605718190ad8fe9c25cb475f1f32ca7cd54f7
---
From c54605718190ad8fe9c25cb475f1f32ca7cd54f7 Mon Sep 17 00:00:00 2001
From: Christos Zoulas <christos@zoulas.com>
Date: Sun, 12 Apr 2026 22:15:14 +0000
Subject: [PATCH] PR/725: inliniac: Revert previous and always set offset.
---
src/softmagic.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/src/softmagic.c b/src/softmagic.c
index 9aaf8b3e5..7cf7c798f 100644
--- a/src/softmagic.c
+++ b/src/softmagic.c
@@ -1577,8 +1577,7 @@ msetoffset(struct magic_set *ms, struct magic *m, struct buffer *bb,
ms->offset = offset;
ms->eoffset = 0;
} else {
- if (b->fd != -1)
- ms->offset = ms->eoffset + offset;
+ ms->offset = ms->eoffset + offset;
}
}
if ((ms->flags & MAGIC_DEBUG) != 0) {
+14
View File
@@ -0,0 +1,14 @@
musl and glibc use different string values for the ECHILD errno.
diff -upr gawk-5.1.0.orig/test/testext.ok gawk-5.1.0/test/testext.ok
--- gawk-5.1.0.orig/test/testext.ok 2021-02-06 12:39:05.990158877 +0100
+++ gawk-5.1.0/test/testext.ok 2021-02-06 12:39:24.080236494 +0100
@@ -21,7 +21,7 @@ var_test: sym_update of ARGC failed - co
var_test: sym_update("testvar") succeeded
var_test() returned 1, test_var = 42
-test_errno() returned 1, ERRNO = No child processes
+test_errno() returned 1, ERRNO = No child process
fubar = 9
rumpus = -5
+40
View File
@@ -0,0 +1,40 @@
# Importada de Alpine aports por `hammer import-alpine` (Etapa G). PUNTO DE PARTIDA — pero
# YA trae los parches de musl de Alpine (lo que un import de nix pierde). Pendiente: el
# sha256 del tarball (el wrapper lo calcula), y adaptar build/install del shell de abuild.
name = "file"
version = "5.47"
[source]
tarball = "https://astron.com/pub/file/file-5.47.tar.gz"
# FIXME sha256: el wrapper lo calcula (Alpine publica sha512). sha512 de Alpine:
# sha512 = "a19c1f2b584bcfa70d4a02545667a90ff9e069523a5fc7b84d79b2b32cb7e59b73c555943784a13d56fa6d4618e18a254fd6102187def1a4a7d936b41ae7ce31"
sha256 = "45672fec165cb4cc1358a2d76b5d57d22876dcb97ab169427ac385cbe1d5597a"
patches = ["0001-softmagic-compare-FILE_GUID-values-in-wire-format.patch", "0002-inliniac-revert-previous-and-always-offset.patch"]
[build]
compiler = "gcc"
target = "x86_64-linux-musl"
link = "static"
flags = []
[build.phases]
# de build() de Alpine (traducido; el lab provee $CBUILD/$CHOST — Etapa G Fase 3; revisá --shared para estático):
compile = '''
_abuild_phase() {
./configure \
--build=$CBUILD \
--host=$CHOST \
--prefix=/usr \
--datadir=/usr/share \
--enable-static
make
}
_abuild_phase
'''
# de package() de Alpine (traducido $pkgdir→/out):
install = '''
_abuild_phase() {
make DESTDIR="/out" install
}
_abuild_phase
'''
+36
View File
@@ -0,0 +1,36 @@
# Importada de Alpine aports por `hammer import-alpine` (Etapa G). PUNTO DE PARTIDA — pero
# YA trae los parches de musl de Alpine (lo que un import de nix pierde). Pendiente: el
# sha256 del tarball (el wrapper lo calcula), y adaptar build/install del shell de abuild.
name = "gawk"
version = "5.3.2"
[source]
tarball = "https://ftp.gnu.org/gnu/gawk/gawk-5.3.2.tar.xz"
# FIXME sha256: el wrapper lo calcula (Alpine publica sha512). sha512 de Alpine:
# sha512 = "2268150fa35ae049a6ff3d0d0fa110db10477014c25f50e2ab4e3ee5fd60133369d2a994f59db4eb718020a0af5c4003ae7278c63e7fffa72f431ff4a1429e48"
sha256 = "f8c3486509de705192138b00ef2c00bbbdd0e84c30d5c07d23fc73a9dc4cc9cc"
patches = ["echild-strerror.patch"]
[build]
compiler = "zig-cc"
target = "x86_64-linux-musl"
link = "static"
flags = []
[build.phases]
# de build() de Alpine (traducido; el lab provee $CBUILD/$CHOST — Etapa G Fase 3; revisá --shared para estático):
compile = '''
CFLAGS="$CFLAGS -flto=auto" \
./configure \
--build=$CBUILD \
--host=$CHOST \
--prefix=/usr \
--sysconfdir=/etc \
--mandir=/usr/share/man \
--infodir=/usr/share/info \
--disable-nls \
--disable-pma
make
'''
# de package() de Alpine (traducido $pkgdir→/out):
install = "make DESTDIR=\"/out\" install"
+44
View File
@@ -0,0 +1,44 @@
Patch-Source: https://lists.gnu.org/archive/html/which-bugs/2025-03/msg00000.html
---
From 16a1647fc26953fab659de5f55d4c0defdfb894f Mon Sep 17 00:00:00 2001
From: Khem Raj <raj.khem@gmail.com>
Date: Sat, 22 Mar 2025 17:56:19 -0700
Subject: [PATCH] getopt: Fix signature of getenv function
This happens on musl systems using GCC 15
../which-2.21/getopt.h:106:12: error: conflicting types for 'getopt'; have
'int(void)'
106 | extern int getopt ();
| ^~~~~~
---
getopt.c | 2 +-
getopt.h | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/getopt.c b/getopt.c
index 9ac2ed6..7e14270 100644
--- a/getopt.c
+++ b/getopt.c
@@ -205,7 +205,7 @@ static char *posixly_correct;
/* Avoid depending on library functions or files
whose names are inconsistent. */
-char *getenv();
+char *getenv(const char*);
static char *my_index(str, chr) const char *str;
int chr;
diff --git a/getopt.h b/getopt.h
index f080053..635fc46 100644
--- a/getopt.h
+++ b/getopt.h
@@ -102,7 +102,7 @@ struct option {
errors, only prototype getopt for the GNU C library. */
extern int getopt(int argc, char *const *argv, const char *shortopts);
#else /* not __GNU_LIBRARY__ */
-extern int getopt();
+extern int getopt(int, char * const [], const char *);
#endif /* __GNU_LIBRARY__ */
extern int getopt_long(int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind);
extern int getopt_long_only(int argc, char *const *argv, const char *shortopts, const struct option *longopts,
+54
View File
@@ -0,0 +1,54 @@
# Importada de Alpine aports por `hammer import-alpine` (Etapa G). PUNTO DE PARTIDA — pero
# YA trae los parches de musl de Alpine (lo que un import de nix pierde). Pendiente: el
# sha256 del tarball (el wrapper lo calcula), y adaptar build/install del shell de abuild.
name = "gzip"
version = "1.14"
[source]
tarball = "https://ftp.gnu.org/gnu/gzip/gzip-1.14.tar.xz"
# FIXME sha256: el wrapper lo calcula (Alpine publica sha512). sha512 de Alpine:
# sha512 = "82aef53188b3e69b51b7ddab5b8c44a11a5b73c0039b22a315a0c7d244694feab0146748add4265901eb1b4c0cee8a9eb69594995f098830d964091af97079c5"
sha256 = "01a7b881bd220bfdf615f97b8718f80bdfd3f6add385b993dcf6efd14e8c0ac6"
[build]
compiler = "gcc"
target = "x86_64-linux-musl"
link = "static"
flags = []
[build.phases]
# de build() de Alpine (traducido; el lab provee $CBUILD/$CHOST — Etapa G Fase 3; revisá --shared para estático):
compile = '''
_abuild_phase() {
# avoid text relocation
export DEFS="NO_ASM"
./configure \
--build=$CBUILD \
--host=$CHOST \
--prefix=/usr \
--mandir=/usr/share/man \
--infodir=/usr/share/info
make
}
_abuild_phase
'''
# de package() de Alpine (traducido $pkgdir→/out):
install = '''
_abuild_phase() {
make DESTDIR=/out install
rm -rf "/out"/usr/lib/charset.alias
rmdir -p "/out"/usr/lib 2>/dev/null || true
mkdir -p "/out"/bin
local i; for i in gzip gunzip zcat; do
mv "/out"/usr/bin/$i "/out"/bin/
done
# http://bugs.alpinelinux.org/issues/4011
ln -sf /bin/gunzip "/out"/usr/bin/uncompress
}
_abuild_phase
'''
# depends de runtime de Alpine (NO build-deps): less
+17
View File
@@ -0,0 +1,17 @@
Make GNU tar ignore the apk-tools header fields
This should problably not be upstreamed
diff --git a/src/xheader.c b/src/xheader.c
index 1347ce1..89b3a44 100644
--- a/src/xheader.c
+++ b/src/xheader.c
@@ -1777,5 +1777,8 @@ struct xhdr_tab const xhdr_tab[] = {
they are restored *only once* during extraction later on. */
{ "SCHILY.xattr", xattr_coder, xattr_decoder, 0, true },
+ /* Ignore apk-tools headers */
+ { "APK-TOOLS", dummy_coder, dummy_decoder, 0, true },
+
{ NULL, NULL, NULL, 0, false }
};
+41
View File
@@ -0,0 +1,41 @@
# Importada de Alpine aports por `hammer import-alpine` (Etapa G). PUNTO DE PARTIDA — pero
# YA trae los parches de musl de Alpine (lo que un import de nix pierde). Pendiente: el
# sha256 del tarball (el wrapper lo calcula), y adaptar build/install del shell de abuild.
name = "tar"
version = "1.35"
[source]
tarball = "https://ftp.gnu.org/gnu/tar/tar-1.35.tar.xz"
# FIXME sha256: el wrapper lo calcula (Alpine publica sha512). sha512 de Alpine:
# sha512 = "8b84ed661e6c878fa33eb5c1808d20351e6f40551ac63f96014fb0d0b9c72d5d94d8865d39e36bcb184fd250f84778a3b271bbd8bd2ceb69eece0c3568577510"
sha256 = "4d62ff37342ec7aed748535323930c7cf94acf71c3591882b26a7ea50f3edc16"
patches = ["ignore-apk-tools-checksums.patch"]
[build]
compiler = "zig-cc"
target = "x86_64-linux-musl"
link = "static"
flags = []
[build.phases]
# de build() de Alpine (traducido; el lab provee $CBUILD/$CHOST — Etapa G Fase 3; revisá --shared para estático):
compile = '''
export CFLAGS="$CFLAGS -flto=auto"
gl_cv_func_gettimeofday_clobber=no \
gl_cv_func_tzset_clobber=no \
./configure \
--build=$CBUILD \
--host=$CHOST \
--prefix=/usr \
--sysconfdir=/etc \
--mandir=/usr/share/man \
--localstatedir=/var
make
'''
# de package() de Alpine (traducido $pkgdir→/out):
install = '''
make DESTDIR="/out" install
mkdir -p "/out"/bin
mv -v "/out"/usr/bin/tar "/out"/bin/
'''
+23
View File
@@ -0,0 +1,23 @@
# Importada de Alpine aports por `hammer import-alpine` (Etapa G). PUNTO DE PARTIDA — pero
# YA trae los parches de musl de Alpine (lo que un import de nix pierde). Pendiente: el
# sha256 del tarball (el wrapper lo calcula), y adaptar build/install del shell de abuild.
name = "tree"
version = "2.3.2"
[source]
tarball = "https://gitlab.com/OldManProgrammer/unix-tree/-/archive/2.3.2/unix-tree-2.3.2.tar.gz"
# FIXME sha256: el wrapper lo calcula (Alpine publica sha512). sha512 de Alpine:
# sha512 = "c22dd6bd6074f521959d31c3c9adbccec5a039029ca818df8345c7572f5b29b4b7b813e9ce4336cc0d600095130a709f7cbf7f88765a7a1e6894b16701d1fcd9"
sha256 = "513a53cbc42ca1f4ea06af2bab1f5283524a3848266b1d162416f8033afc4985"
[build]
compiler = "zig-cc"
target = "x86_64-linux-musl"
link = "static"
flags = []
[build.phases]
# de build() de Alpine (traducido; el lab provee $CBUILD/$CHOST — Etapa G Fase 3; revisá --shared para estático):
compile = "make LDFLAGS=\"$LDFLAGS\" CFLAGS=\"$CFLAGS\""
# de package() de Alpine (traducido $pkgdir→/out):
install = "make PREFIX=\"/out/usr\" MANDIR=\"/out/usr/share/man\" install"
+30
View File
@@ -0,0 +1,30 @@
# Importada de Alpine aports por `hammer import-alpine` (Etapa G). PUNTO DE PARTIDA — pero
# YA trae los parches de musl de Alpine (lo que un import de nix pierde). Pendiente: el
# sha256 del tarball (el wrapper lo calcula), y adaptar build/install del shell de abuild.
name = "which"
version = "2.23"
[source]
tarball = "https://ftp.gnu.org/gnu/which/which-2.23.tar.gz"
# FIXME sha256: el wrapper lo calcula (Alpine publica sha512). sha512 de Alpine:
# sha512 = "738807f79e8cfc5967541a28ae7021247c04c4177279f09be2c19c069af450a7e3b19baf9079fe5569b25b4630bb400be242a123647e52c9fe54f0ad007317bf"
sha256 = "a2c558226fc4d9e4ce331bd2fd3c3f17f955115d2c00e447618a4ef9978a2a73"
patches = ["gcc15.patch"]
[build]
compiler = "zig-cc"
target = "x86_64-linux-musl"
link = "static"
flags = []
[build.phases]
# de build() de Alpine (traducido; el lab provee $CBUILD/$CHOST — Etapa G Fase 3; revisá --shared para estático):
compile = '''
./configure \
--build=$CBUILD \
--host=$CHOST \
--prefix=/usr
make
'''
# de package() de Alpine (traducido $pkgdir→/out):
install = "make DESTDIR=\"/out\" install"