2012-01-22 10 views
5

muszę zbudować/C++ moduł SML który wywołuje obiekt udostępniony (.so pod Linuksem)W jaki sposób z Ocaml można wywołać kod C++, korzystając z biblioteki współdzielonej .so?

tak długo, jak jest to kwestia do opracowania prostego Ocaml/C++ niedopałek, udaje mi się coś, ale kiedy muszę połączyć .so z ocamlmklib lub ocamlopt, to nie

pracuję pod gcc 4.5 (C++ 0x)

pliki do współdzielonego obiektu:

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(); 
    } 

} 

plik CMake.txt skompilować rzeczy:

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} 
) 

mam bibliotekę o nazwie libtestHello.so

teraz pliki z Ocaml/C++ moduł, nazwany 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 (plik testowy):

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} 

kompiluje, ale nie mogę otworzyć obiekt udostępniony libtestHello.so:

$: ./caller.opt ./caller.opt: ​​Błąd podczas Ładowanie biblioteki współdzielone: ​​ libtestHello.so: nie można otworzyć pliku obiektu dzielonego: nie ma takiego pliku lub katalogu

dzięki za godzinę elp :)

Odpowiedz

1

Prawdopodobnie musisz podać -rdynamic i -Wl,-rpath w czasie połączenia.

(i nie jestem pewien, czy można zadzwonić do kodu Ocaml z kodu C lub C++ bez opieki, trzeba zainicjować system uruchomieniowy Ocaml, podobnie std biblioteka C++ może nie działać z niepotwierdzonego programu ocaml, np. z powodu konstruktorów obiektów statycznych ...)

+0

z tego samouczka: http://www.linux-nantes.org/~fmonnier/ocaml/ocaml-wrapping-c.php; dobrze czytać :) – codablank1

Powiązane problemy