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.
This commit is contained in:
2026-08-04 16:12:56 +03:00
parent de47c901c2
commit 4e9fbf4c38
2 changed files with 37 additions and 0 deletions
+16
View File
@@ -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"
+21
View File
@@ -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"