Ruby扩展开发:如何在extconf.rb中引入外部目录的C文件并编译进扩展库
Ruby扩展开发:如何在extconf.rb中引入外部目录的C文件并编译进扩展库
我完全懂你现在的困扰——你想把上级目录里的dodaj.c编译进Ruby扩展hej.so,但当前的extconf.rb只处理了ext目录下的文件,导致运行脚本时出现undefined symbol: dodaj的链接错误。别着急,我们只需要调整extconf.rb的配置,让它把外部的C文件也纳入编译和链接流程就行。
问题根源
你的extconf.rb没有告诉Ruby的扩展构建工具(mkmf)要编译../dodaj.c,所以这个文件的代码没有被打包进hej.so,运行时自然找不到dodaj函数的实现。
修改后的extconf.rb
把你的ext/extconf.rb替换成下面的代码,我会逐行解释作用:
require 'mkmf' # 添加上级目录的头文件搜索路径(和你原来的一样,确保能找到dodaj.h) $CFLAGS += ' -I..' # 把上级目录的dodaj.c添加到要编译的源文件列表中 # $srcs是mkmf的全局变量,保存所有需要编译的C文件 $srcs << '../dodaj.c' # 配置库的目录(这里参数用库名更规范,原来的"../"可以去掉) dir_config("hej") # 生成最终的Makefile create_makefile('hej')
代码解释
$CFLAGS += ' -I..':保持你原来的配置,让编译器能从上级目录找到dodaj.h头文件。$srcs << '../dodaj.c':这是关键!$srcs变量控制了mkmf要编译的所有C源文件。把../dodaj.c加入后,生成的Makefile会自动编译这个文件,生成dodaj.o目标文件。dir_config("hej"):规范的用法是传入库名,mkmf会自动处理头文件和库的搜索路径,这里替换你原来的dir_config("../")更合理。create_makefile('hej'):生成包含所有编译规则的Makefile,现在会同时处理hej.c和../dodaj.c。
重新构建并测试
按下面的步骤操作,确保清理旧文件并重新构建:
- 先清理ext目录下的旧构建文件:
cd ext rm -f Makefile *.o *.so - 重新生成Makefile:
ruby extconf.rb - 执行编译:
这时候你会看到输出里同时编译了makehej.c和../dodaj.c,然后把两个目标文件链接成hej.so:compiling hej.c compiling ../dodaj.c linking shared-object hej.so - 回到项目根目录运行test.rb:
现在应该能正常调用cd .. ruby test.rbHej.dodaj方法,不会再出现符号未定义的错误了!
备选方案(如果以后需要静态库)
如果你的dodaj.c以后会变得更复杂,或者需要被其他程序共享,你可以先把它编译成静态库,再在extconf.rb中链接:
- 在项目根目录编译静态库:
gcc -c dodaj.c -o dodaj.o ar rcs libdodaj.a dodaj.o - 修改extconf.rb链接这个静态库:
这种方式适合require 'mkmf' $CFLAGS += ' -I..' # 链接上级目录的静态库libdodaj.a $LDFLAGS += ' ../libdodaj.a' dir_config("hej") create_makefile('hej')dodaj.c需要独立维护的场景,但对于当前的简单需求,直接把文件加入$srcs更省心。
内容来源于stack exchange
相关产品推荐
相关产品推荐

