Bug #17777


2.6.7 fails to build on macOS: implicit declaration of function 'rb_native_mutex_destroy' is invalid in C99

Added by Eregon (Benoit Daloze) 10 days ago. Updated 8 days ago.

Target version:


vm.c:2295:9: error: implicit declaration of function 'rb_native_mutex_destroy' is invalid in C99 

There is also a warning below that might be worth solving:

vm.c:2489:34: warning: expression does not compute the number of elements in this array; element type is 'const int', not 'VALUE' (aka 'unsigned long') [-Wsizeof-array-div]
                             sizeof(ec->machine.regs) / sizeof(VALUE));
                                    ~~~~~~~~~~~~~~~~  ^
vm.c:2489:34: note: place parentheses around the 'sizeof(VALUE)' expression to silence this warning

Updated by chrisseaton (Chris Seaton) 10 days ago

I've also been experiencing this build failure and can reproduce on multiple systems.

Updated by Eregon (Benoit Daloze) 10 days ago

A workaround is export warnflags=-Wno-error=implicit-function-declaration and then attempt to build/install 2.6.7 again.

That downgrades the error to a warning, but relying on implicit function declaration seems potentially dangerous as the argument types are unknown.

Actions #3

Updated by usa (Usaku NAKAMURA) 9 days ago

  • Backport changed from 2.5: UNKNOWN, 2.6: UNKNOWN, 2.7: UNKNOWN, 3.0: UNKNOWN to 2.6: REQUIRED, 2.7: DONTNEED, 3.0: DONTNEED

Updated by usa (Usaku NAKAMURA) 9 days ago

In principal, we will not change ruby_2_6 no longer except security issue.
But this is a severe build problem, therefore I'll patch for it exceptionally, if a patch verified by macOS user will be provided :)

Updated by udzura (Uchio KONDO) 9 days ago


Using MacOS 10.15.7 / Apple clang version 11.0.3 (clang-1103.0.32.62), building ruby 2.6.7 will be sccessful.

Using MacOS 10.15.7 / Apple clang version 12.0.0 (clang-1200.0.32.28), it is broken (reported by ima1zumi (Mari Imaizumi)).

I hope this will be of some help.

Updated by xtkoba (Tee KOBAYASHI) 9 days ago

I believe this issue was introduced by #15852#note-9 (backport of 2a83650b0fd25719fb6c03bfec7bd895734d3ceb into ruby_2_6).

A workaround is to define a prototype of the function rb_native_mutex_destroy before it is called, as in the following patch:

--- ruby-2.6.7/vm.c.orig
+++ ruby-2.6.7/vm.c
@@ -2292,6 +2292,7 @@ ruby_vm_destruct(rb_vm_t *vm)
    if (objspace) {
+        void rb_native_mutex_destroy(rb_nativethread_lock_t *);
    /* after freeing objspace, you *can't* use ruby_xfree() */

Updated by austin (Austin Ziegler) 8 days ago

Copying the include/ruby/thread_native.h from master appears to work to a point. This is what I found: git show 5e3259ea749 -- include/ruby/thread_native.h.

5e3259ea74 2020-11-17 | fix public interface [Koichi Sasada]

diff --git a/include/ruby/thread_native.h b/include/ruby/thread_native.h
index 0285c8ff40..7e08c2e97f 100644
--- a/include/ruby/thread_native.h
+++ b/include/ruby/thread_native.h
@@ -31,10 +31,14 @@ typedef union rb_thread_lock_union {
 } rb_nativethread_lock_t;

+typedef struct rb_thread_cond_struct rb_nativethread_cond_t;
 #elif defined(HAVE_PTHREAD_H)
 #include <pthread.h>
 typedef pthread_t rb_nativethread_id_t;
 typedef pthread_mutex_t rb_nativethread_lock_t;
+typedef pthread_cond_t rb_nativethread_cond_t;

 #error "unsupported thread type"
@@ -50,6 +54,19 @@ void rb_nativethread_lock_destroy(rb_nativethread_lock_t *lock);
 void rb_nativethread_lock_lock(rb_nativethread_lock_t *lock);
 void rb_nativethread_lock_unlock(rb_nativethread_lock_t *lock);

+void rb_native_mutex_lock(rb_nativethread_lock_t *lock);
+int  rb_native_mutex_trylock(rb_nativethread_lock_t *lock);
+void rb_native_mutex_unlock(rb_nativethread_lock_t *lock);
+void rb_native_mutex_initialize(rb_nativethread_lock_t *lock);
+void rb_native_mutex_destroy(rb_nativethread_lock_t *lock);
+void rb_native_cond_signal(rb_nativethread_cond_t *cond);
+void rb_native_cond_broadcast(rb_nativethread_cond_t *cond);
+void rb_native_cond_wait(rb_nativethread_cond_t *cond, rb_nativethread_lock_t *mutex);
+void rb_native_cond_timedwait(rb_nativethread_cond_t *cond, rb_nativethread_lock_t *mutex, unsigned long msec);
+void rb_native_cond_initialize(rb_nativethread_cond_t *cond);
+void rb_native_cond_destroy(rb_nativethread_cond_t *cond);


However, when building ext/fiddle, I get the following error:

closure.c:264:14: error: implicit declaration of function 'ffi_prep_closure' is invalid in C99
    result = ffi_prep_closure(pcl, cif, callback, (void *)self);

I’m not sure why this is failing here, because it doesn’t look like it’s implicit (the function ffi_prep_closure is in ffi.h which is included from fiddle.h, which is included in closure.c.

Updated by austin (Austin Ziegler) 8 days ago

Digging a bit deeper in to this second item; it looks like we’re doing USE_HEADER_HACKS, which means we’re loading <ffi/ffi.h> and using the compiler that came with Big Sur (based on Xcode 12), I see the following:

ffi_prep_closure (ffi_closure*,
          ffi_cif *,
          void (*fun)(ffi_cif*,void*,void**,void*),
          void *user_data)
#if defined(__GNUC__) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 405)
  __attribute__((deprecated ("use ffi_prep_closure_loc instead")))
#elif defined(__GNUC__) && __GNUC__ >= 3

However, it looks like the 2.7 version of fiddle does a little more investigation:

--- ext/fiddle/extconf.rb   2021-04-05 07:48:34.000000000 -0400
+++ ../ruby-2.7.3/ext/fiddle/extconf.rb 2021-04-05 08:39:38.000000000 -0400
@@ -13,7 +13,7 @@
   if have_header(ffi_header = 'ffi.h')
   elsif have_header(ffi_header = 'ffi/ffi.h')
-    $defs.push(format('-DUSE_HEADER_HACKS'))
+    $defs.push('-DUSE_HEADER_HACKS')
   end and (have_library('ffi') || have_library('libffi'))
 end or
@@ -114,8 +114,17 @@

 if ver
   ver = ver.gsub(/-rc\d+/, '') # If ver contains rc version, just ignored.
-  ver = (ver.split('.') + [0,0])[0,3]
+  ver = (ver.split('.').map(&:to_i) + [0,0])[0,3]
   $defs.push(%{-DRUBY_LIBFFI_MODVERSION=#{ '%d%03d%03d' % ver }})
+  warn "libffi_version: #{ver.join('.')}"
+when $mswin, $mingw, (ver && (ver <=> [3, 2]) >= 0)
+  $defs << "-DUSE_FFI_CLOSURE_ALLOC=1"
+when (ver && (ver <=> [3, 2]) < 0)
+  have_func('ffi_closure_alloc', ffi_header)

 have_header 'sys/mman.h'
@@ -142,7 +151,7 @@
   if /^\#define\s+SIZEOF_#{type}\s+(SIZEOF_(.+)|\d+)/ =~ config
     if size = $2 and size != 'VOIDP'
       size = types.fetch(size) {size}
-      $defs << format("-DTYPE_%s=TYPE_%s", signed||type, size)
+      $defs << "-DTYPE_#{signed||type}=TYPE_#{size}"
     if signed
       check_signedness(type.downcase, "stddef.h")

This is from 229c041f057.

Updated by austin (Austin Ziegler) 8 days ago

Copying the ext/fiddle/extconf.rb from 229c041f057 also seems to work.


Also available in: Atom PDF