Skip to content

Ruby 3.4 compatibility: function pointer type checking fixes #75

@cardmagic

Description

@cardmagic

Problem

rb-gsl fails to compile on Ruby 3.4 due to stricter function pointer type checking. Ruby 3.4 treats incompatible function pointer types as errors (via -Werror=incompatible-function-pointer-types), causing ~20+ compilation failures.

Root Causes

1. Incorrect argc values in rb_define_method/rb_define_module_function

Ruby's C API expects specific function signatures based on the argc parameter:

  • argc >= 0: Fixed args → VALUE func(VALUE self, VALUE arg1, ...)
  • argc = -1: Variadic → VALUE func(int argc, VALUE *argv, VALUE self)

Many functions were registered with wrong argc values:

// BEFORE: argc=4 but function takes 3 VALUE args (self + 2)
rb_define_module_function(module, "ellint_D_e", rb_gsl_sf_ellint_D_e, 4);

// AFTER: argc=3 matches function signature
rb_define_module_function(module, "ellint_D_e", rb_gsl_sf_ellint_D_e, 3);

2. Wrong parameter order for variadic functions

Functions registered with argc=-1 must have signature (int argc, VALUE *argv, VALUE self), but several had the parameters in wrong order:

// BEFORE: wrong order
static VALUE rb_gsl_sf_mathieu_a_array(VALUE module, int argc, VALUE *argv)

// AFTER: correct order for argc=-1
static VALUE rb_gsl_sf_mathieu_a_array(int argc, VALUE *argv, VALUE module)

3. Double pointer typos

// BEFORE: VALUE *argv[] is double pointer
static VALUE rb_gsl_vector_complex_indgen_bang(int argc, VALUE *argv[], VALUE obj)

// AFTER: VALUE *argv is single pointer
static VALUE rb_gsl_vector_complex_indgen_bang(int argc, VALUE *argv, VALUE obj)

4. Unused parameters in function signatures

// BEFORE: unused VALUE s parameter
static VALUE rb_gsl_rng_max(VALUE obj, VALUE s)

// AFTER: removed unused parameter
static VALUE rb_gsl_rng_max(VALUE obj)

5. rb_rescue callback signature change

Ruby 3.4 requires rescue callbacks to accept 2 arguments:

// BEFORE: 1 argument
static VALUE rb_gsl_call_rescue(VALUE obj)

// AFTER: 2 arguments (data, exception)
static VALUE rb_gsl_call_rescue(VALUE obj, VALUE exc)
{
  (void)exc;
  return Qfalse;
}

6. GSL 2.8 API changes

// BEFORE: accessing struct internals (no longer available)
B = gsl_vector_alloc(w->nbreak + w->k - 2);

// AFTER: use public API
B = gsl_vector_alloc(gsl_bspline_ncontrol(w));

Also, gsl_matrix_complex_conjugate is now provided by GSL 2.8+, so the local definition causes a duplicate symbol error.

7. CLASS_OF() with wrong type

// BEFORE: passing C struct pointer
return Data_Wrap_Struct(CLASS_OF(h1), ...);

// AFTER: passing Ruby VALUE
return Data_Wrap_Struct(CLASS_OF(obj), ...);

8. RARRAY_LEN with void pointer

// BEFORE: void* params
for (i = 0; (int) i < RARRAY_LEN(f->params); i++)

// AFTER: explicit VALUE cast
for (i = 0; (int) i < RARRAY_LEN((VALUE) f->params); i++)

Files Requiring Changes

  • blas2.c - argc fixes for dsyr2/zher2
  • bspline.c - GSL 2.8 API (gsl_bspline_ncontrol)
  • gsl.c - rb_rescue callback signature
  • histogram2d.c - CLASS_OF fixes, fscanf argc
  • ieee.c - printf argc
  • linalg.c - removed unused flag params, argc fixes
  • matrix_complex.c - removed duplicate gsl_matrix_complex_conjugate, fixed indgen_bang signature
  • monte.c - eval argc
  • multiroots.c - RARRAY_LEN VALUE cast
  • ntuple.c - close/size argc
  • odeiv.c - scaled_alloc argc
  • poly_source.h - reduce/deriv/integ argc
  • rng.c - removed unused parameters from max/min/size
  • sf_bessel.c - sequence_Jnu_e argc
  • sf_ellint.c - ellint_D_e argc
  • sf_mathieu.c - array function parameter order
  • spline.c - eval_integ_e argc
  • stats.c - weighted stats function argc values
  • vector_complex.c - indgen_bang signature, matrix_view_with_tda argc

Testing

Verified fixes compile and pass full test suite with:

  • Ruby 3.4.8
  • GSL 2.8
  • macOS (arm64-darwin)

755 tests, 1,514,054 assertions, 0 failures, 0 errors

Related: TypedData Migration (Separate Issue)

There are deprecation warnings about Data_Get_Struct / Data_Wrap_Struct:

warning: undefining the allocator of T_DATA class GSL::Vector

This requires migrating to TypedData_Wrap_Struct (~3,300 occurrences) and will be tracked as a separate issue. Users can suppress warnings with:

Warning[:deprecated] = false
require 'gsl'
Warning[:deprecated] = true

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions