From 4e9fbf4c38dfe86a93bc9c880d88ef769c880781 Mon Sep 17 00:00:00 2001 From: vasilito Date: Tue, 4 Aug 2026 16:12:56 +0300 Subject: [PATCH] headers: give timerfd/signalfd prototypes C linkage sys/timerfd.h and sys/signalfd.h declare their functions in the cbindgen `trailer`, which is emitted after the include guard closes and OUTSIDE the extern "C" block that cpp_compat=true generates. The prototypes therefore took C++ linkage, so a C++ consumer asked the linker for a mangled symbol while relibc exports the plain C one: alignedtimer.cpp:(.text+0x29a): undefined reference to `timerfd_create(int, int)' (plasma-workspace libclock). C callers were unaffected, which is why this survived until a C++ consumer appeared. The prototypes are hand-written rather than generated on purpose: cbindgen renders them with a bare `itimerspec` and a `clockid_t` parameter, which does not resolve in a plain C99 include and previously broke libwayland's TFD_CLOEXEC probe. That stays; only the linkage is corrected. signalfd has no in-tree C++ consumer yet and is fixed pre-emptively. --- src/header/sys_signalfd/cbindgen.toml | 16 ++++++++++++++++ src/header/sys_timerfd/cbindgen.toml | 21 +++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/src/header/sys_signalfd/cbindgen.toml b/src/header/sys_signalfd/cbindgen.toml index acd5ddd02d..d4f8dc5ec9 100644 --- a/src/header/sys_signalfd/cbindgen.toml +++ b/src/header/sys_signalfd/cbindgen.toml @@ -9,8 +9,24 @@ trailer = """ #define SFD_NONBLOCK 0x800 #endif +/* extern "C" is REQUIRED here; cpp_compat only wraps cbindgen's GENERATED + * body, and this trailer is emitted outside it. Without this a C++ consumer + * links against the mangled name while relibc exports the plain C symbol. + * Same defect as sys_timerfd, which surfaced as + * undefined reference to `timerfd_create(int, int)' + * once plasma-workspace (C++) used it. Fixed here pre-emptively: no in-tree + * C++ consumer of signalfd exists yet, so this is latent rather than observed. + */ +#ifdef __cplusplus +extern "C" { +#endif + int signalfd(int fd, const sigset_t *mask, size_t masksize); int signalfd4(int fd, const sigset_t *mask, size_t masksize, int flags); + +#ifdef __cplusplus +} +#endif """ language = "C" style = "Tag" diff --git a/src/header/sys_timerfd/cbindgen.toml b/src/header/sys_timerfd/cbindgen.toml index 79ced7361f..32e10cfb8c 100644 --- a/src/header/sys_timerfd/cbindgen.toml +++ b/src/header/sys_timerfd/cbindgen.toml @@ -25,9 +25,30 @@ trailer = """ #define TFD_TIMER_CANCEL_ON_SET 0x2 #endif +/* extern "C" is REQUIRED here and cannot be left to cpp_compat. + * + * cpp_compat=true wraps only the body cbindgen GENERATES. These three + * prototypes are hand-written in this trailer (see the [export] note below), + * and the trailer is emitted after the include guard closes, outside that + * wrapper. Without an explicit extern "C" they take C++ linkage, so a C++ + * consumer asks the linker for the mangled name while relibc exports the plain + * C symbol: + * alignedtimer.cpp:(.text+0x29a): undefined reference to + * `timerfd_create(int, int)' + * (first hit: plasma-workspace libclock/alignedtimer.cpp). C callers were + * unaffected, which is why this survived until a C++ consumer appeared. + */ +#ifdef __cplusplus +extern "C" { +#endif + int timerfd_create(int clockid, int flags); int timerfd_settime(int fd, int flags, const struct itimerspec *new_value, struct itimerspec *old_value); int timerfd_gettime(int fd, struct itimerspec *curr_value); + +#ifdef __cplusplus +} +#endif """ language = "C" style = "Tag"