`

rubygems.org guides 翻译四(Gems with Extensions)

    博客分类:
  • gem
阅读更多

目录

1.gem布局

2.extconf.rb

3.C扩展

4.rake编译

5.gem说明

6.扩展命名规范

7.扩展阅读

 

前言:

许多gem使用C库作为扩展,使用ruby的接口来使用C代码。例如nokogiri这个gem包含了两个扩展库libxml2 and libxslt

pg(PostgreSQL的驱动)和mysql,mysql2(mysql的驱动)也使用了c扩展。

创建一个包含扩展的gem包含几个步骤,下面将关注此,是你轻松创建带扩展的gem。这个文档会使用到malloc和free两个c标准库。

 

一、gem布局

每一个gem都开始于一个包含任务的Rakefile文件,扩展的文件需要放在ext目录下,他是extention的缩写。在这个例子里面,我们会使用my_malloc作为名字。

一些扩展一部分是用C写的,一部分是用ruby写的。如果你要支持多语言扩展,例如C和java。你应该把ext目录下C文件对应的ruby文件也放入到lib目录下。

原文:If you are going to support multiple languages, such as C and Java extensions, you should put the C-specific ruby files under the ext/ directory as well in a lib/ directory.

Rakefile
ext/my_malloc/extconf.rb               # extension configuration
ext/my_malloc/my_malloc.c              # extension source
lib/my_malloc.rb                       # generic features

 

当扩展编译ext/my_malloc/lib/下的c文件后,就会安装到lib目录下。

 

二、extconf.rb

extconf.rb中是编译你自己的C扩展所需要的Makefile文件。extconf.rb会检查你的扩展所需要的函数,宏指令(macros)和共享库。如果缺少某一项,extconf.rb会立即退出。

下面这个extconf.rb会检查malloc和free,然后创建一个makefile,再将编译后的lib/my_malloc/my_malloc.so扩展按照。

require "mkmf"

abort "missing malloc()" unless have_func "malloc"
abort "missing free()"   unless have_func "free"

create_makefile "my_malloc/my_malloc"

 

mkmf documentation and README.EXT

 查看更多关于创建extconf.rb以及其函数文档的细节。

 

 

三、C扩展

C扩展包含malloc和free两个函数到ext/my_malloc/my_malloc.c,如下:

#include <ruby.h>

struct my_malloc {
size_t size;
void *ptr;
};

static void
my_malloc_free(void *p) {
struct my_malloc *ptr = p;

if (ptr->size > 0)
    free(ptr->ptr);
}

static VALUE
my_malloc_alloc(VALUE klass) {
VALUE obj;
struct my_malloc *ptr;

obj = Data_Make_Struct(klass, struct my_malloc, NULL, my_malloc_free, ptr);

ptr->size = 0;
ptr->ptr  = NULL;

return obj;
}

static VALUE
my_malloc_init(VALUE self, VALUE size) {
struct my_malloc *ptr;
size_t requested = NUM2SIZET(size);

if (0 == requested)
    rb_raise(rb_eArgError, "unable to allocate 0 bytes");

Data_Get_Struct(self, struct my_malloc, ptr);

ptr->ptr = malloc(requested);

if (NULL == ptr->ptr)
    rb_raise(rb_eNoMemError, "unable to allocate %ld bytes", requested);

ptr->size = requested;

return self;
}

static VALUE
my_malloc_release(VALUE self) {
struct my_malloc *ptr;

Data_Get_Struct(self, struct my_malloc, ptr);

if (0 == ptr->size)
    return self;

ptr->size = 0;
free(ptr->ptr);

return self;
}

void
Init_my_malloc(void) {
VALUE cMyMalloc;

cMyMalloc = rb_const_get(rb_cObject, rb_intern("MyMalloc"));

rb_define_alloc_func(cMyMalloc, my_malloc_alloc);
rb_define_method(cMyMalloc, "initialize", my_malloc_init, 1);
rb_define_method(cMyMalloc, "free", my_malloc_release, 0);
}

 

这个c扩展文件很简单,包含以下几部分。

  • struct my_malloc to hold the allocated memory
  • my_malloc_free() to free the allocated memory after garbage collection
  • my_malloc_alloc() to create the ruby wrapper object
  • my_malloc_init() to allocate memory from ruby
  • my_malloc_release() to free memory from ruby
  • Init_my_malloc() to register the functions in the MyMalloc class.

你可以像下面这样测试扩展:

$ cd ext/my_malloc
$ ruby extconf.rb
checking for malloc()... yes
checking for free()... yes
creating Makefile
$ make
compiling my_malloc.c
linking shared-object my_malloc.bundle
$ cd ../..
$ ruby -Ilib:ext -r my_malloc -e "p MyMalloc.new(5).free"
#<MyMalloc:0x007fed838addb0>

但这会跑好一会儿,我们使之自动化。

 

四、rake编译

rake-compiler 是一个负责编译扩展的任务集合。rake-compiler可以同时使用java或者C在同一个项目里面(nokogiri 就是这么干的),添加rake-compiler灰常简单。

 

require "rake/extensiontask"

Rake::ExtensionTask.new "my_malloc" do |ext|
  ext.lib_dir = "lib/my_malloc"
end
现在你就可以使用rake compile编译这个扩展,而且可以hook这个编译任务到其他任务(例如test)

 

设置lib_dir参数以便放置lib/my_malloc/my_malloc.so(.bundle or .dll)的扩展文件。

This allows the top-level file for the gem to be a ruby file. This allows you to write the parts that are best suited to ruby in ruby.(待翻译)

例如:

 

class MyMalloc
  VERSION = "1.0"
end

require "my_malloc/my_malloc"
设置lib_dir也可以使你包含预编译的扩展,以便适应多个ruby版本。(ruby1.9.3的扩展不适用与ruby2.0.0),lib/my_malloc.rb会选取合适的扩展来安装。

 

 

五、gem说明

构建gem的最后一步就是把extconf.rb注册到gemspec的extensions数组中。

 

Gem::Specification.new "my_malloc", "1.0" do |s|
  # [...]

  s.extensions = %w[ext/my_malloc/extconf.rb]
end

 

现在你可以release这个gem了。

 

六、扩展命名

为了避免gem中无意识的交互(unintended interactions),最好的做法是每一个gem都放在一个单独的目录下。下面是关于gem命名的建议。

  1. ext/<name> 目录包含源代码和 extconf.rb
  2. ext/<name>/<name>.c 主函数源代码文件 (there may be others)
  3. ext/<name>/<name>.c contains a function Init_<name>. (The name following Init_ function must exactly match the name of the extension for it to be loadable by require.)
  4. ext/<name>/extconf.rb calls create_makefile('<name>/<name>') only when the all the pieces needed to compile the extension are present.
  5. The gemspec sets extensions = ['ext/<name>/extconf.rb'] and includes any of the necessary extension source files in the files list.
  6. lib/<name>.rb contains require '<name>/<name>' which loads the C extension

七、扩展阅读

  • my_malloc 包含该扩展的源码以及详细的注释
  • README.EXT 详细描述了如何在ruby中构建一个gem
  • MakeMakefile 包含 mkmf.rb 的文档, the library extconf.rb uses to detect ruby and C library features
  • rake-compiler integrates building C and Java extensions into your Rakefile in a smooth manner.
  • Writing C extensions part 1 and part 2) by Aaron Patterson
  • Interfaces to C libraries can be written using ruby and fiddle (part of the standard library) or ruby-ffi
分享到:
评论

相关推荐

    gemstash, 一个 RubyGems.org 缓存和 private gem 服务器.zip

    gemstash, 一个 RubyGems.org 缓存和 private gem 服务器 什么是 Gemstash?Gemstash是远程服务器( 如 https://rubygems.org ) 和 private gem 源的缓存。在你的控制范围内,如果你使用的是多个可以访问服务器的...

    rubygems-update-3.1.3.gem

    A package (also known as a library) contains a set of functionality that can be invoked by a Ruby program, such as reading and parsing an XML ... See our guide on publishing a Gem at guides.rubygems.org

    Ruby Toolbox data on Rubygems.org-crx插件

    例如,如果您正在https://rubygems.org/gems/simplecov上查看诸如simplecov之类的gem,它将从Ruby Toolbox中获取信息,它是“一个仍在接受更新的长期项目”。 其他gem将基于Ruby Toolbox收集的指标显示其他信息。

    rubygems.org-backup:这是历史重写之前 ruby​​gems.org 的 BACKUP 存储库。 不使用。 请不要拉请求

    组织RubyGems.org 由几个主要部分组成: Rails 应用程序:管理用户并允许其他人查看 gems 等。 Sinatra 应用程序(Hostess):gem 服务器Gem 处理器:处理传入的 gem 并将它们存储在 S3(生产)或server/ (开发)...

    meg:帮助管理和支持 RubyGems.org 的快速命令

    帮助管理和支持 RubyGems.org 的快速命令。 目前帮助通过 SSH 连接到 RubyGems.org 基础设施和运行命令。 安装 $ cd $ git clone git://github.com/rubygems/meg.git .meg 对于 bash 用户: $ echo 'eval "$($...

    adoption.rubygems.org

    option.rubygems.org 项目导师的姓名: Nick Quaranto,Benjamin Fleischer 项目团队的名称:丽娜·托雷斯(Lina Torres)的安吉拉(Angela Guette) 项目名称: RubyGems.org采用中心 网址: : 关于该项目: ...

    2.4-3.0.rubygems.rar

    标题“2.4-3.0.rubygems.rar”暗示了这个压缩包可能包含了Ruby Gems从版本2.4到3.0之间的升级或集合,这对于Ruby开发者来说是一个重要的资源,因为版本升级通常会带来性能优化、新功能以及对旧问题的修复。...

    rubygems.org:Ruby社区的gem托管服务

    RubyGems.org(néeGemcutter) Ruby社区的gem主机。 目的 提供更好的API处理宝石 创建更透明,更易于访问的项目页面 使社区能够改善和增强网站 支持 由管理, 是一个社区资助的组织,通过门票和赞助为和的会议...

    Apress.Practical.Ruby.Gems.Apr.2007.pdf

    - **广泛的资源库:** RubyGems.org是一个庞大的社区驱动的Gems仓库,包含了大量的开源代码供开发者使用。 #### 四、如何使用Ruby Gems 1. **安装Ruby环境:** 首先需要在计算机上安装Ruby运行时环境。 2. **安装...

    rubygems-incident-verifiers

    目前正在进行一些验证工作: 对镜像进行验证(接近完成) 用户根据 ruby​​gems 验证他们的本地 gems(有单独的脚本) Gem 所有者通过 Rubygems.org 进行验证(您将学习如何进行) 作为 gem 所有者,您可以通过...

    rubygems-3.2.27.zip

    RubyGems是Ruby编程语言的一个核心组成部分,它提供了一个管理和分发Ruby库和程序的框架。这个名为"rubygems-3.2.27.zip"的压缩包包含了RubyGems的3.2.27版本,这是一个重要的更新,旨在提高稳定性和性能,同时也...

    rubygems-1.8.7.gz for linux

    RubyGems(通常简称为Gems)是一个软件包管理系统,允许开发者创建、发布和安装自包含的Ruby模块。这些模块包含了代码、元数据和文档,使得开发人员能够方便地重用和分享代码,类似于Python的pip或Java的Maven库。...

    rubygems-master-(1).zip_GEM

    Download from: rubygems.org/pages/download Unpack into a directory and cd there Install with: ruby setup.rb # you may need admin/root privilege For more details and other options, see: ruby setup....

    曲柄的Rubygems「Crank for Rubygems」-crx插件

    ★导航至ruby gem的GitHub或Rubygems.org页面。 在GitHub上打开'Gemfile'或'.gemspec'文件,然后单击任何gem名称。 您将被重定向到gem项目页面。 ★从上下文菜单中打开RubyGems.org中的ruby gem页面。 用鼠标突出...

    RubyGems.txt

    RubyGems

    gemstash:RubyGems.org缓存和私有gem服务器

    今天或什至更好的做出贡献,并确保Bundler,RubyGems,Gemstash和其他共享工具在未来数年内都存在。 快速入门指南 设置 Gemstash旨在快速,轻松地进行设置。 到本《快速入门指南》结束时,您将能够将公共资源中的...

    guides:努力为RubyGems生态系统提供出色的文档

    从rubygems.org/pages/docs移植内容 从help.rubygems.org知识库移植内容 在这里找到许多StackOverflow / ruby​​-talk问题并获得其常见答案 填写更多指南! 设置 确保已gem install jekyll ( gem install jekyll ...

    rubygems-2.7.6.tgz

    1. **安装**:使用`gem install &lt;gem_name&gt;`命令,RubyGems会从官方的Gem仓库(rubygems.org)下载指定gem的最新版本,并将其安装到本地系统。同时,RubyGems还会处理gem的依赖关系,确保所有必需的依赖项都被正确...

Global site tag (gtag.js) - Google Analytics