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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions