2012-01-22 4 views
5

Ho bisogno di costruire un modulo O'Caml/C++ che chiama un oggetto condiviso (.so sotto Linux)Come da Ocaml posso chiamare codice C++ usando se stesso una libreria condivisa .so?

Finché si tratta di compilare un semplice stub O'Caml/C++, gestisco la cosa, ma quando ho bisogno per collegare il .so con ocamlmklib o ocamlopt, non riesce

io lavoro sotto gcc 4.5 (C++ 0x)

file per l'oggetto condiviso:

hello.hpp

#include <iostream> 
#include <string> 

using namespace std; 

class HelloApplication 
{ 
public : 

    HelloApplication(); 
    ~HelloApplication(); 

    void say(string s); 

}; 

typedef HelloApplication *(*create_hello)(); 

hello.cpp:

#include "hello.hpp" 

HelloApplication::HelloApplication(){} 
HelloApplication::~HelloApplication(){} 

void HelloApplication::say(string s) 
{ 
    cout << "Hello : " << s << endl; 
} 

extern "C" 
{ 
    HelloApplication *create() 
    { 
     return new HelloApplication(); 
    } 

} 

il file CMake.txt per compilare la cosa:

cmake_minimum_required(VERSION 2.6) 

project(testHello_proj) 
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Release" FORCE) 
#set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Debug" FORCE) 

set(LIBRARY_OUTPUT_PATH lib/${CMAKE_BUILD_TYPE}) 

## Compiler flags 
if(CMAKE_COMPILER_IS_GNUCXX) 
    set (CMAKE_CXX_FLAGS "-O2 -std=c++0x" 
     CACHE STRING "g++ Compiler Flags for All Builds" FORCE) 

    set (CMAKE_CXX_FLAGS_DEBUG "-std=c++0x -O2 -g -Wall" 
     CACHE STRING "g++ Compiler Flags for Debug Builds" FORCE) 

    set (CMAKE_CXX_FLAGS_RELEASE "-O2 -fmessage-length=0 -std=c++0x" 
    CACHE STRING "g++ Compiler Flags for Release Builds" FORCE) 

    set (CMAKE_CXX_FLAGS_MINSIZEREL "-Os -std=c++0x" 
    CACHE STRING "g++ Compiler Flags for Release minsize builds" FORCE) 

    set (CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g1 -std=c++0x" 
    CACHE STRING "g++ Compiler Flags for Release with Debug Info builds" FORCE) 

endif() 

file(
    GLOB_RECURSE 
    source_files 
    src/* 
) 

add_library(
    testHello 
    SHARED 
    ${source_files} 
) 

ricevo una libreria denominata libtestHello.so

ora file di Ocaml/C++ modulo, chiamato mymod:

* mymod_stubs.cpp: *

#include <cstdlib> 
#include <dlfcn.h> 
#include <string> 

#include "hello.hpp" 

extern "C" { 
#include <memory.h> 
#include <mlvalues.h> 
} 

using namespace std; 

HelloApplication* hello; 

extern "C" value initHello (value unit) { 
    CAMLparam1 (unit); 

    create_hello hello_pMaker; 

    void* hello_hndl = dlopen("/path_to_cmake_dir/build/lib/Release/libtestHello.so", RTLD_LAZY); 

    if(hello_hndl == NULL) 
    { 
     cerr << "dlopen : " << dlerror() << endl; 
     exit(EXIT_FAILURE); 
    } 

    void *hello_mkr = dlsym(hello_hndl, "create"); 
    if (hello_mkr == NULL) 
    { 
     cerr << "dlsym : " << dlerror() << endl; 
     exit(EXIT_FAILURE); 
    } 

    hello_pMaker = (create_hello)hello_mkr; 

    HelloApplication* hello_ptr(hello_pMaker()); 
    hello = hello_ptr; 

    CAMLreturn (Val_unit); 
} 

extern "C" value say (value v_str) { 
    CAMLparam1 (v_str); 

    string s = String_val(v_str); 

    hello->say(s); 

    CAMLreturn (Val_unit); 
} 

mymod.ml:

external initHello : unit -> unit = "initHello" 

external say : string -> unit = "say" 

caller.ml (file di test):

Mymod.initHello;; 

Mymod.say "tout le monde";; 

Makefile:

CPPSRC=mymod_stubs.cpp 
CPPOBJ=mymod_stubs.o 
CPPINC=-I/usr/local/lib/ocaml/caml -I/path_to_cmake_dir/src 
CPPLIB=-std=c++0x 
MODSRC=mymod.ml 
MODNAME=mymod 
OPTOBJ=mymod.cmx 
OPTLIB=mymod.cmxa 
CALLERSRC=caller.ml 
OPTCALLERFLAGS=-I . -cclib 
CALLERLIB=-lstdc++ 
OPTCALLEREXEC=caller.opt 

all: opttest 

#g++ 

cppcompile: 
    g++ -o ${CPPOBJ} ${CPPLIB} ${CPPINC} -c ${CPPSRC} 

#native 

optcompile: cppcompile 
    ocamlopt -c ${MODSRC} 

optmklib: optcompile 
    ocamlmklib -o ${MODNAME} -ccopt -L/path_to_cmake_dir/build/lib/Release -cclib -ltestHello ${CPPOBJ} 
    ocamlmklib -o ${MODNAME} -ccopt -L/path_to_cmake_dir/build/lib/Release -cclib -ltestHello ${OPTOBJ} 

opttest: optmklib 
    ocamlopt ${OPTCALLERFLAGS} ${CALLERLIB} ${OPTLIB} ${CALLERSRC} -o ${OPTCALLEREXEC} 

#clean 

clean : 
    rm -f *.cma *.cmo *.cmx *.cmxa *.cmi *.so *.a *.o ${OPTCALLEREXEC} 

compila ma non posso aprire l'oggetto condiviso libtestHello.so:

$: ./caller.opt ./caller.opt: ​​errore durante il caricamento delle librerie condivise: libtestHello.so: non è possibile aprire il file oggetto condiviso: Nessun file o directory

grazie per la tua h elp :)

risposta

1

Probabilmente è necessario passare -rdynamic e -Wl,-rpath al momento del collegamento.

(e io non sono sicuro che si può chiamare il codice O'Caml da C o codice C++ senza assistenza; è necessario inizializzare il sistema di runtime O'Caml, allo stesso modo la std libreria C++ non potrebbe funzionare da un programma OCaml senza patch, ad esempio, a causa di costruttori per oggetti statici ...)

+0

da questo tutorial: http://www.linux-nantes.org/~fmonnier/ocaml/ocaml-wrapping-c.php; buona lettura :) – codablank1