The include statements presented here corresponds to the values of RbConfig::CONFIG["rubyhdrdir"]
and RbConfig::CONFIG["rubyarchhdrdir"]
, so I thought using RbConfig to setup the compilation will give me much better results when compiling on different platforms. I wrote the following Makefile with the prior in mind:
librb = $(shell ruby -e 'puts RbConfig::CONFIG["rubyhdrdir"]')
archdir = $(shell ruby -e 'puts RbConfig::CONFIG["rubyarchhdrdir"]')
CC := gcc -std=c23
EXEC := test
SRCS := src/[a-z]*.c
LIBS := -I$(librb) -I$(archdir) -Lruby
CFLAGS := -g -Wall -Wextra -Woverflow -Og -pedantic
$(EXEC): $(SRCS)
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
@echo "Compiled CRuby $(shell ruby -e 'puts RbConfig::CONFIG["ruby_version"]')"
Which on my system results in:
gcc -std=c23 -o object_test src/main.c -g -Wall -Wextra -Woverflow -Og -pedantic -I/home/user/.rbenv/versions/3.2.2/include/ruby-3.2.0 -I/home/user/.rbenv/versions/3.2.2/include/ruby-3.2.0/x86_64-linux -Lruby
The ruby header files seems to be linked correctly but I still get undefined reference compilation error for ruby symbols like ruby_init
and ruby_cleanup
when compiling following code.
#include <ruby.h>
int main(int argc, char* argv[])
{
ruby_init();
//...
return ruby_cleanup(0);
}
I know that my question may seem a duplicate of this one, but the links are broken there and it's outdated by 13 years. I am most concerned about ruby > 3.1 for my project.
I try to maintain docs for this process in my Ruby C API Guide.
At minimum, the C compiler needs to find three things:
Depending on how you set up Ruby and your C compiler, these could already be in standard locations where your compiler can automatically find them. At worst, you need to specify the locations of all three. Using RbConfig
to find them is a great idea, you're just not doing it quite right. The correct config keys are:
rubyhdrdir
to be used with -I
to add an include pathrubyarchhdrdir
to be used with -I
to add an include pathlibdir
to be used with -L
to add a linker path (and -Wl,-rpath,
if you need to add a runtime search path as well)So here's an example of a Ruby script that outputs all of the compiler options you need:
require 'rbconfig'
require 'shellwords'
rblib = RbConfig::CONFIG['libdir']
# location of ruby.h
puts "-I#{Shellwords.escape RbConfig::CONFIG['rubyhdrdir']}"
# location of ruby/config.h
puts "-I#{Shellwords.escape RbConfig::CONFIG['rubyarchhdrdir']}"
# location of libruby
puts "-L#{Shellwords.escape rblib}"
# add libruby location to runtime library search path
puts "-Wl,-rpath,#{Shellwords.escape rblib}"
# link with libruby
puts "-lruby"