Skip to content

Commit 4350e69

Browse files
committed
fix: use runtime dlvsym instead of link-time .symver for cfgetospeed compat
The .symver approach broke the final link (ncurses' own -Wl,--version-script conflicts with a link-time versioned external symbol reference), and separately, the naive dlvsym-with-fallback first attempt still linked a bare reference to cfgetospeed for its fallback path, which just re-added the GLIBC_2.42 requirement it was meant to avoid. Resolving both dlvsym and its dlsym fallback dynamically (never referencing the bare cfgetospeed identifier in compiled code) sidesteps the linker entirely and degrades gracefully on any glibc, verified by building the patched ncurses against the bumped glibc: no cfgetospeed reference of any kind remains in the dynamic symbol table, and the max GLIBC symbol requirement drops back to 2.38, matching every other library in the bundle.
1 parent 7a5a332 commit 4350e69

3 files changed

Lines changed: 128 additions & 56 deletions

File tree

nix/overlays/default.nix

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
# Force the pre-2.42 glibc symbol version for cfgetospeed so the portable CLI bundle keeps working on older-glibc hosts.
2121
ncurses = prev.ncurses.overrideAttrs (old: {
22-
patches = (old.patches or [ ]) ++ [ ./patches/ncurses-cfgetospeed-old-glibc-symver.patch ];
22+
patches = (old.patches or [ ]) ++ [ ./patches/ncurses-cfgetospeed-old-glibc-compat.patch ];
2323
});
2424

2525
cargo-pgrx = final.callPackage ../cargo-pgrx/default.nix {
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
--- a/ncurses/tinfo/lib_baudrate.c 2026-07-31 08:24:24
2+
+++ b/ncurses/tinfo/lib_baudrate.c 2026-07-31 12:03:39
3+
@@ -45,6 +45,39 @@
4+
#endif
5+
6+
/*
7+
+ * On Linux/glibc, resolve cfgetospeed to the old (functionally identical)
8+
+ * GLIBC_2.17 symbol version at runtime, so binaries built against newer
9+
+ * glibc still run on hosts with older glibc that only export that version.
10+
+ * Done via dlvsym rather than a link-time .symver directive, since the
11+
+ * latter conflicts with ncurses' own --version-script linking. Both dlvsym
12+
+ * and its dlsym fallback are declared directly (rather than via
13+
+ * <dlfcn.h>/_GNU_SOURCE, which may already be locked in by earlier headers
14+
+ * in this file), and neither path calls the bare cfgetospeed identifier, so
15+
+ * no versioned reference to it survives in the compiled output.
16+
+ */
17+
+#if defined(__linux__) && defined(__GLIBC__)
18+
+extern void *dlvsym(void *handle, const char *symbol, const char *version);
19+
+extern void *dlsym(void *handle, const char *symbol);
20+
+static speed_t
21+
+_supabase_compat_cfgetospeed(const struct termios *t)
22+
+{
23+
+ static int inited = 0;
24+
+ static speed_t (*fn)(const struct termios *) = NULL;
25+
+ if (!inited) {
26+
+ fn = (speed_t (*)(const struct termios *))
27+
+ dlvsym((void *) 0, "cfgetospeed", "GLIBC_2.17");
28+
+ if (!fn) {
29+
+ fn = (speed_t (*)(const struct termios *))
30+
+ dlsym((void *) 0, "cfgetospeed");
31+
+ }
32+
+ inited = 1;
33+
+ }
34+
+ return fn ? fn(t) : 0;
35+
+}
36+
+#define cfgetospeed(t) _supabase_compat_cfgetospeed(t)
37+
+#endif
38+
+
39+
+/*
40+
* These systems use similar header files, which define B1200 as 1200, etc.,
41+
* but can be overridden by defining USE_OLD_TTY so B1200 is 9, which makes all
42+
* of the indices up to B115200 fit nicely in a 'short', allowing us to retain
43+
--- a/ncurses/tinfo/tinfo_driver.c 2026-07-31 08:24:24
44+
+++ b/ncurses/tinfo/tinfo_driver.c 2026-07-31 12:03:50
45+
@@ -37,6 +37,39 @@
46+
#include <tic.h>
47+
#include <termcap.h> /* ospeed */
48+
49+
+/*
50+
+ * On Linux/glibc, resolve cfgetospeed to the old (functionally identical)
51+
+ * GLIBC_2.17 symbol version at runtime, so binaries built against newer
52+
+ * glibc still run on hosts with older glibc that only export that version.
53+
+ * Done via dlvsym rather than a link-time .symver directive, since the
54+
+ * latter conflicts with ncurses' own --version-script linking. Both dlvsym
55+
+ * and its dlsym fallback are declared directly (rather than via
56+
+ * <dlfcn.h>/_GNU_SOURCE, which may already be locked in by earlier headers
57+
+ * in this file), and neither path calls the bare cfgetospeed identifier, so
58+
+ * no versioned reference to it survives in the compiled output.
59+
+ */
60+
+#if defined(__linux__) && defined(__GLIBC__)
61+
+extern void *dlvsym(void *handle, const char *symbol, const char *version);
62+
+extern void *dlsym(void *handle, const char *symbol);
63+
+static speed_t
64+
+_supabase_compat_cfgetospeed(const struct termios *t)
65+
+{
66+
+ static int inited = 0;
67+
+ static speed_t (*fn)(const struct termios *) = NULL;
68+
+ if (!inited) {
69+
+ fn = (speed_t (*)(const struct termios *))
70+
+ dlvsym((void *) 0, "cfgetospeed", "GLIBC_2.17");
71+
+ if (!fn) {
72+
+ fn = (speed_t (*)(const struct termios *))
73+
+ dlsym((void *) 0, "cfgetospeed");
74+
+ }
75+
+ inited = 1;
76+
+ }
77+
+ return fn ? fn(t) : 0;
78+
+}
79+
+#define cfgetospeed(t) _supabase_compat_cfgetospeed(t)
80+
+#endif
81+
+
82+
#if HAVE_NANOSLEEP
83+
#include <time.h>
84+
#if HAVE_SYS_TIME_H
85+
--- a/progs/tset.c 2026-07-31 08:24:24
86+
+++ b/progs/tset.c 2026-07-31 12:03:59
87+
@@ -89,6 +89,40 @@
88+
#include <reset_cmd.h>
89+
#include <termcap.h>
90+
#include <transform.h>
91+
+
92+
+/*
93+
+ * On Linux/glibc, resolve cfgetospeed to the old (functionally identical)
94+
+ * GLIBC_2.17 symbol version at runtime, so binaries built against newer
95+
+ * glibc still run on hosts with older glibc that only export that version.
96+
+ * Done via dlvsym rather than a link-time .symver directive, since the
97+
+ * latter conflicts with ncurses' own --version-script linking. Both dlvsym
98+
+ * and its dlsym fallback are declared directly (rather than via
99+
+ * <dlfcn.h>/_GNU_SOURCE, which may already be locked in by earlier headers
100+
+ * in this file), and neither path calls the bare cfgetospeed identifier, so
101+
+ * no versioned reference to it survives in the compiled output.
102+
+ */
103+
+#if defined(__linux__) && defined(__GLIBC__)
104+
+extern void *dlvsym(void *handle, const char *symbol, const char *version);
105+
+extern void *dlsym(void *handle, const char *symbol);
106+
+static speed_t
107+
+_supabase_compat_cfgetospeed(const struct termios *t)
108+
+{
109+
+ static int inited = 0;
110+
+ static speed_t (*fn)(const struct termios *) = NULL;
111+
+ if (!inited) {
112+
+ fn = (speed_t (*)(const struct termios *))
113+
+ dlvsym((void *) 0, "cfgetospeed", "GLIBC_2.17");
114+
+ if (!fn) {
115+
+ fn = (speed_t (*)(const struct termios *))
116+
+ dlsym((void *) 0, "cfgetospeed");
117+
+ }
118+
+ inited = 1;
119+
+ }
120+
+ return fn ? fn(t) : 0;
121+
+}
122+
+#define cfgetospeed(t) _supabase_compat_cfgetospeed(t)
123+
+#endif
124+
+
125+
#include <tty_settings.h>
126+
127+
#if HAVE_GETTTYNAM

nix/overlays/patches/ncurses-cfgetospeed-old-glibc-symver.patch

Lines changed: 0 additions & 55 deletions
This file was deleted.

0 commit comments

Comments
 (0)