Использование curl/libcurl в расширении C Ruby

В предисловие: я очень новичок в C, поэтому я, вероятно, упускаю что-то очевидное, но бегал несколько дней, пытаясь понять, что это такое...

Я пытаюсь создать расширение Ruby C, которое будет работать как на Mac, так и на ПК и использует libcurl для загрузки файлов.

По сути, все, что делает инструмент, это получает список файлов из Ruby, загружает файлы и помещает их туда, куда им указывает Ruby.

У меня есть расширение, работающее внутри Ruby, и я скомпилировал расширение C для взаимодействия с Ruby.

В основном мой код выглядит так:

#include <string.h>
#include <curl/curl.h>
#include <curl/types.h>
#include <curl/easy.h>
#include "ruby.h"

VALUE Test = Qnil;

void Init_test();

VALUE download_file(VALUE self, VALUE from, VALUE to);

void Init_test()
{
    Test = rb_define_class("Test", rb_cObject);
    rb_define_method(Test, "download_file", download_file, 2);
}

VALUE download_file(VALUE self, VALUE from, VALUE to)
{
    CURL *curl;
    FILE *fp;
    CURLcode res;

    char *url = STR2CSTR(from);
    char outfilename[FILENAME_MAX] = STR2CSTR(to);

    curl = curl_easy_init();
    if (curl) {
        fp = fopen(outfilename,"wb");
        curl_easy_setopt(curl, CURLOPT_URL, url);
        // curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
        res = curl_easy_perform(curl);
        curl_easy_cleanup(curl);
        fclose(fp);
    }
    return 0;
}

У меня проблемы с тем, что libcurl действительно работает:

$ ruby test.rb
dyld: lazy symbol binding failed: Symbol not found: _curl_easy_init
  Referenced from: /path/to/test.bundle
  Expected in: flat namespace

dyld: Symbol not found: _curl_easy_init
  Referenced from: /path/to/test.bundle
  Expected in: flat namespace

Trace/BPT trap

Я использую Ruby mkmf для создания Makefile для моего расширения:

require 'mkmf'
extension_name = 'test'
dir_config(extension_name)
create_makefile(extension_name)

Я предполагаю, что при компиляции расширения Makefile не может найти эти файлы Curl, но, поскольку я новичок в расширениях C/Ruby, я не могу понять, почему это может быть.

Когда я запускаю curl-config --cflags, это то, что я получаю:

$  curl-config --cflags
-I/usr/local/include

Мои файлы libcurl include/library:

/usr/local/include/curl/
/usr/local/lib/libcurl.dylib

Моя установка:

  • Mac OSX 10.6.4
  • Рубин 1.8.6-p420
  • Curl 7.21.7-DEV (i386-apple-darwin10.7.0) libcurl/7.21.7-DEV OpenSSL/0.9.8l zlib/1.2.3

Любая помощь будет принята с благодарностью!

Ваше здоровье


person Dana Woodman    schedule 06.06.2011    source источник
comment
Вы видели в качестве примера curb?   -  person tadman    schedule 07.06.2011
comment
@tadman, как посмотреть на источник? Не могу найти ссылки...   -  person Dana Woodman    schedule 07.06.2011
comment
@tadman неважно! svn checkout http://curb.rubyforge.org/svn/   -  person Dana Woodman    schedule 07.06.2011
comment
Почему C, когда есть так много хороших библиотек Ruby, которые могут это сделать?   -  person Mark Thomas    schedule 07.06.2011
comment
@Mark, потому что расширение предназначено для работы в Google SketchUp, в котором используется устаревшая и урезанная версия Ruby.   -  person Dana Woodman    schedule 07.06.2011


Ответы (2)


Вам нужно указать mkmf, чтобы он ссылался на libcurl при создании вашего расширения. Используемая команда: have_library< /а>.

В exconf.rb добавьте

have_library("curl", "curl_easy_init")

перед вызовом create_makefile.

Кроме того, я не думаю, что вам нужна строка dir_config(extension_name).

(На Mac вы можете увидеть, какие библиотеки связаны с двоичным файлом с помощью otool -L. Попробуйте

otool -L test.bundle

до и после добавления have_library вы должны увидеть строку, похожую на добавленную /usr/lib/libcurl.4.dylib (compatibility version 6.0.0, current version 6.1.0).)

person matt    schedule 07.06.2011
comment
ты совершенно прав. Вот чего не хватало. Я обнаружил это с трудом, прежде чем вы опубликовали свой ответ, но приятно знать об otool, который очень полезен. Нужна ли часть curl_easy_init? Что оно делает? - person Dana Woodman; 07.06.2011
comment
@ Дана, я не совсем уверен, для чего нужен второй аргумент, кажется, он работает без него. Я думаю, может быть, это для того, чтобы вы могли проверить, действительно ли нужная вам библиотека имеет заданную функцию. - person matt; 08.06.2011
comment
Да, я думаю, ты прав. have_library("curl") работает нормально. Спасибо еще раз! - person Dana Woodman; 09.06.2011

Symbol not found: _curl_easy_init звучит как ошибка ссылки. Похоже, вы должны передать некоторые флаги вашему компоновщику (см. curl-config --libs)

person cam    schedule 06.06.2011
comment
cam, спасибо за ответ! В конечном итоге это оказалась проблема с компоновщиком, но ответ Мэтта был немного более конкретным. Спасибо за информацию. - person Dana Woodman; 07.06.2011