2012-02-12 20 views
5

Rozpocząłem dzisiaj mały eksperyment: napisałem klasę C++, która zależy od innych bibliotek (ALGLIB, Eigen, narzędzia wewnętrzne) i chciałem stworzyć opakowanie Ruby dla tej klasy. Obecnie używam do tego celu Rice. Pierwszy napisałem bardzo proste C++ wrapper dla mojej klasy:Rozszerzenie C++ z bibliotekami zewnętrznymi

// @file MLPWrapper.h 
#pragma once 

#include "mlp/MLP.h" 
#include <ruby.h> 

class MLPWrapper 
{ 
    MLP mlp; // <- my C++ class 
public: 
    ... 
    void fit() 
    { 
    ... 
    mlp.fit(stop); 
    } 
}; 

Biblioteki CPP-file to:

// @file cmlp.cpp 
#include "rice/Data_Type.hpp" 
#include "rice/Constructor.hpp" 
#include "MLPWrapper.h" 

using namespace Rice; 

extern "C" 
void Init_cmlp() 
{ 
    Data_Type<MLPWrapper> rb_cMLPWrapper = define_class<MLPWrapper>("MLP") 
     .define_constructor(Constructor<MLPWrapper>()) 
     ... 
     .define_method("fit", &MLPWrapper::fit); 
} 

I to jest extconf.rb:

require "mkmf-rice" 

$CFLAGS << "-O3" 

HEADER_DIRS = [ 
    "..", 
    "../../external/libraries/eigen-eigen-3.0.1", 
    "../../external/libraries/alglib/cpp/src", 
    "../../external/libraries/CMA-ESpp" 
] 
LIB_DIRS = [ 
    "../../build/external/libraries/alglib/cpp/src", 
    "../../build/external/libraries/CMA-ESpp/cma-es", 
    "../../build/src/tools" 
] 

dir_config("libs", HEADER_DIRS, LIB_DIRS) 

have_library("libtools") 
have_library("libalglib") 

create_makefile("cmlp") 

Wszystko działa dobrze, z wyjątkiem łączenia. Oczywiście pliki nagłówkowe bibliotek są zawarte, w przeciwnym razie nie skompilowałoby się. Ale kiedy uruchomię mały program testowy ("wymagają" cmlp "; mlp = MLP.new") w Rubim nie znajduje się symbol _ZN6LoggerC1ENS_6TargetESs, który jest częścią libtools (enum). To co się dzieje, kiedy budować C++ rozszerzenie i uruchomić program testowy:

$ ruby extconf.rb 
checking for main() in -lrice... yes 
checking for main() in -llibtools... no 
checking for main() in -llibalglib... no 
checking for main() in -llibcmaes... no 
creating Makefile 
$ make 
g++ -I. -I. -I/usr/lib/ruby/1.8/x86_64-linux -I. -I.. -I../../external/libraries/eigen-eigen-3.0.1 -I../../external/libraries/alglib/cpp/src -I../../external/libraries/CMA-ESpp  -I/var/lib/gems/1.8/gems/rice-1.4.3/ruby/lib/include -fPIC -fno-strict-aliasing -g -g -O2 -fPIC -O3 -Wall -g -c cmlp.cpp 
g++ -shared -o cmlp.so cmlp.o -L. -L/usr/lib -L../../build/external/libraries/alglib/cpp/src -L../../build/external/libraries/CMA-ESpp/cma-es -L../../build/src/tools -L. -Wl,-Bsymbolic-functions -rdynamic -Wl,-export-dynamic -L/var/lib/gems/1.8/gems/rice-1.4.3/ruby/lib/lib -lrice -lruby1.8 -lpthread -lrt -ldl -lcrypt -lm -lc 
$ ruby test.rb 
ruby: symbol lookup error: ./cmlp.so: undefined symbol: _ZN6LoggerC1ENS_6TargetESs 

Biblioteki są zestawiane z CMake (add_library (...)) i znajdują się w

../../build/src/tools/libtools.so 
../../build/external/libraries/alglib/cpp/src/libalglib.so 
../../build/external/libraries/CMA-ESpp/cma-es/libcmaes.so 

I nie wiem, jak rozwiązać ten problem na własną rękę i nie mogłem znaleźć żadnej przydatnej dokumentacji dla mojego problemu. Jak mogę naprawić ten extconf.rb? Doceniam każdą podpowiedź.

edit: OK, zmieniłem extconf.rb:

require "rubygems" 
require "mkmf-rice" 

BASE_DIR = "/bla/" 

$CFLAGS << " -O3" 

dir_config("tools", [BASE_DIR + "src", BASE_DIR + "external/libraries/eigen-eigen-3.0.1"], BASE_DIR + "build/src/tools") 
unless have_library("tools") 
    abort "tools are missing. please compile tools" 
end 

dir_config("alglib", BASE_DIR + "external/libraries/alglib/cpp/src", BASE_DIR + "build/external/libraries/alglib/cpp/src") 
unless have_library("alglib") 
    abort "alglib is missing. please compile alglib" 
end 

dir_config("cmaes", BASE_DIR + "external/libraries/CMA-ESpp", BASE_DIR + "build/external/libraries/CMA-ESpp/cma-es") 
unless have_library("cmaes") 
    abort "cmaes is missing. please compile cmaes" 
end 

create_makefile("cmlp") 

Wygenerowany Makefile brzmi:

SHELL = /bin/sh 

#### Start of system configuration section. #### 

srcdir = . 
topdir = /usr/lib/ruby/1.8/x86_64-linux 
hdrdir = $(topdir) 
VPATH = $(srcdir):$(topdir):$(hdrdir) 
exec_prefix = $(prefix) 
prefix = $(DESTDIR)/usr 
sharedstatedir = $(prefix)/com 
mandir = $(prefix)/share/man 
psdir = $(docdir) 
oldincludedir = $(DESTDIR)/usr/include 
localedir = $(datarootdir)/locale 
bindir = $(exec_prefix)/bin 
libexecdir = $(prefix)/lib/ruby1.8 
sitedir = $(DESTDIR)/usr/local/lib/site_ruby 
htmldir = $(docdir) 
vendorarchdir = $(vendorlibdir)/$(sitearch) 
includedir = $(prefix)/include 
infodir = $(prefix)/share/info 
vendorlibdir = $(vendordir)/$(ruby_version) 
sysconfdir = $(DESTDIR)/etc 
libdir = $(exec_prefix)/lib 
sbindir = $(exec_prefix)/sbin 
rubylibdir = $(libdir)/ruby/$(ruby_version) 
docdir = $(datarootdir)/doc/$(PACKAGE) 
dvidir = $(docdir) 
vendordir = $(libdir)/ruby/vendor_ruby 
datarootdir = $(prefix)/share 
pdfdir = $(docdir) 
archdir = $(rubylibdir)/$(arch) 
sitearchdir = $(sitelibdir)/$(sitearch) 
datadir = $(datarootdir) 
localstatedir = $(DESTDIR)/var 
sitelibdir = $(sitedir)/$(ruby_version) 

CC = gcc 
LIBRUBY = $(LIBRUBY_SO) 
LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a 
LIBRUBYARG_SHARED = -l$(RUBY_SO_NAME) 
LIBRUBYARG_STATIC = -lruby1.8-static 

RUBY_EXTCONF_H = 
CFLAGS = -fPIC -fno-strict-aliasing -g -g -O2 -fPIC $(cflags) -O3 
INCFLAGS = -I. -I. -I/usr/lib/ruby/1.8/x86_64-linux -I. 
DEFS  = 
CPPFLAGS = -I/bla/external/libraries/CMA-ESpp -I/bla//external/libraries/alglib/cpp/src -I//bla/src -I/bla/external/libraries/eigen-eigen-3.0.1  -I/var/lib/gems/1.8/gems/rice-1.4.3/ruby/lib/include 
CXXFLAGS = $(CFLAGS) -Wall -g 
ldflags = -L. -Wl,-Bsymbolic-functions -rdynamic -Wl,-export-dynamic -L/var/lib/gems/1.8/gems/rice-1.4.3/ruby/lib/lib 
dldflags = 
archflag = 
DLDFLAGS = $(ldflags) $(dldflags) $(archflag) 
LDSHARED = g++ -shared 
AR = ar 
EXEEXT = 

RUBY_INSTALL_NAME = ruby1.8 
RUBY_SO_NAME = ruby1.8 
arch = x86_64-linux 
sitearch = x86_64-linux 
ruby_version = 1.8 
ruby = /usr/bin/ruby1.8 
RUBY = $(ruby) 
RM = rm -f 
MAKEDIRS = mkdir -p 
INSTALL = /usr/bin/install -c 
INSTALL_PROG = $(INSTALL) -m 0755 
INSTALL_DATA = $(INSTALL) -m 644 
COPY = cp 

#### End of system configuration section. #### 

preload = 

CXX = g++ 
libpath = . $(libdir) /bla/external/libraries/CMA-ESpp/cma-es /bla/build/external/libraries/alglib/cpp/src /bla/build/src/tools 
LIBPATH = -L. -L$(libdir) -L/bla/build/external/libraries/CMA-ESpp/cma-es -L/bla/build/external/libraries/alglib/cpp/src -L/bla/build/src/tools 
DEFFILE = 

CLEANFILES = mkmf.log 
DISTCLEANFILES = 

extout = 
extout_prefix = 
target_prefix = 
LOCAL_LIBS = 
LIBS = -lcmaes -lalglib -ltools -lrice -lruby1.8 -lpthread -lrt -ldl -lcrypt -lm -lc 
SRCS = cmlp.cpp 
OBJS = cmlp.o 
TARGET = cmlp 
DLLIB = $(TARGET).so 
EXTSTATIC = 
STATIC_LIB = 

BINDIR  = $(bindir) 
RUBYCOMMONDIR = $(sitedir)$(target_prefix) 
RUBYLIBDIR = $(sitelibdir)$(target_prefix) 
RUBYARCHDIR = $(sitearchdir)$(target_prefix) 

TARGET_SO  = $(DLLIB) 
CLEANLIBS  = $(TARGET).so $(TARGET).il? $(TARGET).tds $(TARGET).map 
CLEANOBJS  = *.o *.a *.s[ol] *.pdb *.exp *.bak 

all:  $(DLLIB) 
static:  $(STATIC_LIB) 

clean: 
     @-$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES) 

distclean: clean 
     @-$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log 
     @-$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES) 

realclean: distclean 
install: install-so install-rb 

install-so: $(RUBYARCHDIR) 
install-so: $(RUBYARCHDIR)/$(DLLIB) 
$(RUBYARCHDIR)/$(DLLIB): $(DLLIB) 
    $(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR) 
install-rb: pre-install-rb install-rb-default 
install-rb-default: pre-install-rb-default 
pre-install-rb: Makefile 
pre-install-rb-default: Makefile 
$(RUBYARCHDIR): 
    $(MAKEDIRS) [email protected] 

site-install: site-install-so site-install-rb 
site-install-so: install-so 
site-install-rb: install-rb 

.SUFFIXES: .c .m .cc .cxx .cpp .C .o 

.cc.o: 
    $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $< 

.cxx.o: 
    $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $< 

.cpp.o: 
    $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $< 

.C.o: 
    $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $< 

.c.o: 
    $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) -c $< 

$(DLLIB): $(OBJS) Makefile 
    @-$(RM) [email protected] 
    $(LDSHARED) -o [email protected] $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS) 



$(OBJS): ruby.h defines.h 

Odpowiedz

4
../../build/src/tools/libtools.so 
../../build/external/libraries/alglib/cpp/src/libalglib.so  
../../build/external/libraries/CMA-ESpp/cma-es/libcmaes.so 

może być problem. Chciałbym tutaj wypróbować bezwzględne ścieżki, mogłem sobie wyobrazić, że pwd jest inny niż oczekiwany podczas uruchamiania ruby extconf.rb. Również zakładam trzeba dir_config wpis dla każdej biblioteki, które chcesz połączyć. Więc

dir_config('libs', HEADER_DIRS, LIB_DIRS) 

należy zastąpić

dir_config('tools', '<Path to include dir>', '<Path to lib dir>') 
dir_config('alglib', '<Path to include dir>', '<Path to lib dir>') 

Należy pamiętać, że prowadząc „lib” powinno być pominięte , tak jak w opcji -l linker. Następnie, jeśli chcesz mieć pewność, że biblioteka zostanie znaleziony, zastąpi

have_library('libtools') 

przez

have_library('tools') or raise 

Znowu 'lib' został pominięty.

Jeśli nadal nie możesz rozwiązać problemu, opublikuj plik Makefile wygenerowany przez `ruby extconf.rb '.

+0

OK, twoje sugestie pomogły mi trochę. Ruby znajduje teraz biblioteki, ale nie są one ładowane po uruchomieniu skryptu testowego. Jest to wynik: _./cmlp.so: libcmaes.so: nie można otworzyć pliku udostępnionego obiektu: brak takiego pliku lub katalogu - ./cmlp.so (LoadError) from /usr/lib/ruby/vendor_ruby/1.8/ rubygems/custom_require.rb: 36: w 'require ' from test.rb: 2_ Dołączyłem plik Makefile. – alfa

+0

Po ustawieniu LD_LIBRARY_PATH działa, gdy próbuje połączyć się z bibliotekami statycznymi, pojawia się następujący błąd: _/usr/bin/ld:/bla/build/external/libraries/CMA-ESpp/cma-es/libcmaes. a (timings.cpp.o): relokacja R_X86_64_PC32 z niezdefiniowanym symbolem 'clock @@ GLIBC_2.2.5 'nie może być używana podczas tworzenia obiektu współdzielonego; rekompilacja z -fPIC_ Czy istnieje lepszy sposób na rozwiązanie tego problemu niż ustawienie zmiennej środowiskowej? – alfa

+2

Tak, jeśli poprawnie ustawisz opcję "rpath" swojego linkera ([patrz też] (http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html)), nie ma potrzeby ustaw LD_LIBRARY_PATH. Bez ryżu mogę potwierdzić, że jest poprawnie ustawione w pliku Makefile, gdy wywołasz 'ruby extconf.rb --with-tools-lib-dir = --with-alglib-dir = '. Może spróbujesz? Sprawdź w wygenerowanym pliku Makefile, czy ścieżka wyszukiwania w środowisku uruchomieniowym jest ustawiona poprawnie. Inną opcją jest oczywiście po prostu zainstalowanie bibliotek w jednej ze standardowych ścieżek wyszukiwania. – emboss

Powiązane problemy