Bug #20908
closedRuby extension builds fail with GCC 15 which defaults to -std=gnu23
Description
Hi!
Upcoming GCC 15 defaults to C23 (-std=gnu23
). One thing C23 changes is removing unprototyped functions, so void foo()
now means void foo(void)
, rather than "any arguments".
Ruby extensions fail to build as a result with GCC 15. This was reported downstream in Gentoo at https://bugs.gentoo.org/943784 where brotli-0.6.0 is an example:
make: Entering directory '/var/tmp/portage/dev-ruby/brotli-0.6.0/work/ruby32/brotli-0.6.0/ext/brotli'
x86_64-pc-linux-gnu-gcc -I. -I/usr/include/ruby-3.2.0/x86_64-linux -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -DHAVE_BROTLI_DECODE_H -DHAVE_BROTLI_ENCODE_H -fPIC -O2 -pipe -march=native -fno-diagnostics-color -o brotli.o -c brotli.c
In file included from /usr/include/ruby-3.2.0/ruby/ruby.h:27,
from /usr/include/ruby-3.2.0/ruby.h:38,
from brotli.h:4,
from brotli.c:1:
brotli.c: In function ‘Init_brotli’:
/usr/include/ruby-3.2.0/ruby/internal/anyargs.h:363:45: error: passing argument 3 of ‘rb_define_singleton_method_m1’ from incompatible pointer type [-Wincompatible-pointer-types]
363 | # define RUBY_METHOD_FUNC(func) RBIMPL_CAST((VALUE (*)(ANYARGS))(func))
| ^
| |
| VALUE (*)(void) {aka long unsigned int (*)(void)}
/usr/include/ruby-3.2.0/ruby/internal/anyargs.h:308:144: note: in definition of macro ‘rb_define_singleton_method’
308 | #define rb_define_singleton_method(obj, mid, func, arity) RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method((arity), (func))((obj), (mid), (func), (arity))
| ^~~~
/usr/include/ruby-3.2.0/ruby/internal/anyargs.h:363:33: note: in expansion of macro ‘RBIMPL_CAST’
363 | # define RUBY_METHOD_FUNC(func) RBIMPL_CAST((VALUE (*)(ANYARGS))(func))
| ^~~~~~~~~~~
brotli.c:478:55: note: in expansion of macro ‘RUBY_METHOD_FUNC’
478 | rb_define_singleton_method(rb_mBrotli, "deflate", RUBY_METHOD_FUNC(brotli_deflate), -1);
| ^~~~~~~~~~~~~~~~
/usr/include/ruby-3.2.0/ruby/internal/anyargs.h:271:21: note: expected ‘VALUE (*)(int, union <anonymous>, VALUE)’ {aka ‘long unsigned int (*)(int, union <anonymous>, long unsigned int)’} but argument is of type ‘VALUE (*)(void)’ {aka ‘long unsigned int (*)(void)’}
271 | RBIMPL_ANYARGS_DECL(rb_define_singleton_method, VALUE, const char *)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/ruby-3.2.0/ruby/internal/anyargs.h:254:41: note: in definition of macro ‘RBIMPL_ANYARGS_DECL’
254 | RBIMPL_ANYARGS_ATTRSET(sym) static void sym ## _m1(__VA_ARGS__, VALUE(*)(int, union { VALUE *x; const VALUE *y; } __attribute__((__transparent_union__)), VALUE), int); \
| ^~~
The ANYARGS
macro can't work in its current form, as defined at e.g. https://github.com/ruby/ruby/blob/f127bcb8294fd417c253dd7acab3ff3b9f0bf555/parser_st.h#L45:
#ifndef ANYARGS
# ifdef __cplusplus
# define ANYARGS ...
# else
# define ANYARGS
# endif
#endif
... because of the change in C23 I mentioned above, i.e. (ANYARGS)
being ()
now means no arguments, not any.
I note that Ruby was adapted in part already for this change, see e.g. https://github.com/ruby/ruby/commit/4e64edb6cd8d1b444c591bfd50ec3d357e794f6e, but it appears that the headers that extensions need to build against aren't yet ready.
Updated by thesamesam (Sam James) about 2 months ago
cc @shyouhei (Shyouhei Urabe) who made other C23 porting changes
Updated by shyouhei (Shyouhei Urabe) about 2 months ago
- Status changed from Open to Third Party's Issue
The extension library is confusing our C level API. rb_define_singleton_method()
and friends do not intend to take RUBY_METHOD_FUNC
. That had accidentally worked because of the past C specifications you described, but not any longer in C23.
Can you inform the extension authors that passing bare function pointers should just work here, like this? :
From 8e589adb92a7d5c8c9e8d35bb116ad5ab0686e30 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=8D=9C=E9=83=A8=E6=98=8C=E5=B9=B3?=
<shyouhei@ruby-lang.org>
Date: Tue, 26 Nov 2024 13:42:54 +0900
Subject: [PATCH] stop worrying and just pass bare function
`rb_define_method` etc. already take care arities. You don't have
to apply RUBY_METHOD_FUNC.
---
ext/brotli/brotli.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/ext/brotli/brotli.c b/ext/brotli/brotli.c
index cb69500..a9cc23d 100644
--- a/ext/brotli/brotli.c
+++ b/ext/brotli/brotli.c
@@ -475,9 +475,9 @@ Init_brotli(void)
rb_mBrotli = rb_define_module("Brotli");
rb_eBrotli = rb_define_class_under(rb_mBrotli, "Error", rb_eStandardError);
rb_global_variable(&rb_eBrotli);
- rb_define_singleton_method(rb_mBrotli, "deflate", RUBY_METHOD_FUNC(brotli_deflate), -1);
- rb_define_singleton_method(rb_mBrotli, "inflate", RUBY_METHOD_FUNC(brotli_inflate), 1);
- rb_define_singleton_method(rb_mBrotli, "version", RUBY_METHOD_FUNC(brotli_version), 0);
+ rb_define_singleton_method(rb_mBrotli, "deflate", brotli_deflate, -1);
+ rb_define_singleton_method(rb_mBrotli, "inflate", brotli_inflate, 1);
+ rb_define_singleton_method(rb_mBrotli, "version", brotli_version, 0);
id_read = rb_intern("read");
// Brotli::Writer
id_write = rb_intern("write");
@@ -485,9 +485,9 @@ Init_brotli(void)
id_close = rb_intern("close");
rb_Writer = rb_define_class_under(rb_mBrotli, "Writer", rb_cObject);
rb_define_alloc_func(rb_Writer, rb_writer_alloc);
- rb_define_method(rb_Writer, "initialize", RUBY_METHOD_FUNC(rb_writer_initialize), -1);
- rb_define_method(rb_Writer, "write", RUBY_METHOD_FUNC(rb_writer_write), 1);
- rb_define_method(rb_Writer, "finish", RUBY_METHOD_FUNC(rb_writer_finish), 0);
- rb_define_method(rb_Writer, "flush", RUBY_METHOD_FUNC(rb_writer_flush), 0);
- rb_define_method(rb_Writer, "close", RUBY_METHOD_FUNC(rb_writer_close), 0);
+ rb_define_method(rb_Writer, "initialize", rb_writer_initialize, -1);
+ rb_define_method(rb_Writer, "write", rb_writer_write, 1);
+ rb_define_method(rb_Writer, "finish", rb_writer_finish, 0);
+ rb_define_method(rb_Writer, "flush", rb_writer_flush, 0);
+ rb_define_method(rb_Writer, "close", rb_writer_close, 0);
}
--
2.47.0
Updated by nobu (Nobuyoshi Nakada) about 2 months ago
Can't we prioritize the condition defined(rb_define_method)
for RUBY_METHOD_FUNC
?
Updated by shyouhei (Shyouhei Urabe) about 2 months ago
Ah, that could be a nice idea. Not sure if that breaks other parts though.
Updated by hansdegraaff (Hans de Graaff) about 1 month ago
We initially opened this bug because we had multiple cases of this issue and the one in brotli was an example. Another case shows up in io-console:
x86_64-pc-linux-gnu-gcc -I. -I/usr/include/ruby-3.1.0/x86_64-linux -I/usr/include/ruby-3.1.0/ruby/backward -I/usr/include/ruby-3.1.0 -I. -DHAVE_RB_IO_DESCRIPTOR -DHAVE_RB_IO_GET_WRITE_IO -DHAVE_TERMIOS_H -DHAVE_CFMAKERAW -DHAVE_SYS_IOCTL_H -DHAVE_RB_IO_WAIT=1 -fPIC -std=gnu23 -o console.o -c console.c
In file included from /usr/include/ruby-3.1.0/ruby/ruby.h:26,
from /usr/include/ruby-3.1.0/ruby.h:38,
from console.c:9:
console.c: In function ‘InitVM_console’:
/usr/include/ruby-3.1.0/ruby/internal/anyargs.h:287:135: error: passing argument 3 of ‘rb_define_method_m3’ from incompatible pointer type [-Wincompatible-pointer-types]
287 | #define rb_define_method(klass, mid, func, arity) RBIMPL_ANYARGS_DISPATCH_rb_define_method((arity), (func))((klass), (mid), (func), (arity))
| ^~~~~~
| |
| __attribute__((noreturn)) VALUE (*)(int, const VALUE *, VALUE, VALUE) {aka __attribute__((noreturn)) long unsigned int (*)(int, const long unsigned int *, long unsigned int, long unsigned int)}
console.c:1815:5: note: in expansion of macro ‘rb_define_method’
1815 | rb_define_method(rb_cIO, "pressed?", console_key_pressed_p, 1);
| ^~~~~~~~~~~~~~~~
console_key_pressed_p
is defined as rb_f_notimplement
and RUBY_METHOD_FUNC
is not used anywhere in this gem.
Updated by shyouhei (Shyouhei Urabe) about 1 month ago
Thank you for the report anyways! It's totally fine.
The io-console build log reads that it builds against ruby 3.1, which is a bit older than C23. It didn't know the breaking C change.
It's now continuously integrated against (clang's) C23 and builds well (see: https://github.com/ruby/ruby/actions/runs/12104018027/job/33746931422#step:8:1534 ). I guess newer versions could have rerouted the problem.