c++ - 我如何从 Ocaml 调用 C++ 代码,使用它自己的共享库 .so ?

标签 c++ linux interop shared-libraries ocaml

我需要构建一个调用共享对象的 Ocaml/C++ 模块(Linux 下的 .so)

只要编译一个简单的 Ocaml/C++ stub 是一个问题,我就可以管理它,但是当我需要将 .so 与 ocamlmklib 或 ocamlopt 链接时,它会失败

我在 gcc 4.5 (c++0x) 下工作

共享对象的文件:

你好.hpp

#include <iostream>
#include <string>

using namespace std;

class HelloApplication
{
public :

    HelloApplication();
    ~HelloApplication();

    void say(string s);

};

typedef HelloApplication *(*create_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();
    }

}

用于编译东西的 CMake.txt 文件:

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

我得到一个名为 libtestHello.so 的库

现在的 Ocaml/C++ 模块文件,名为 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(测试文件):

Mymod.initHello;;

Mymod.say "tout le monde";;

生成文件:

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}

它编译但我无法打开共享对象 libtestHello.so:

$: ./caller.opt ./caller.opt: error while loading shared libraries: libtestHello.so: cannot open shared object file: No such file or directory

感谢您的帮助:)

最佳答案

您可能需要在链接时传递 -rdynamic-Wl,-rpath

(而且我不确定您是否可以不小心从 C 或 C++ 代码调用 Ocaml 代码;您需要初始化 Ocaml 运行时系统;同样,std C++ 库可能无法在未打补丁的 ocaml 程序中运行,例如,因为静态对象的构造函数...)

关于c++ - 我如何从 Ocaml 调用 C++ 代码,使用它自己的共享库 .so ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8962747/

相关文章:

当我包含 iostream header 时,C++ 断言不会生成堆栈帧

c++ - std::move 的无限递归

python - 使用python在itertools中用两组排列

c# - 如何将 C# 元组公开给 C++

C# .net Excel Interop 使 Excel 进程挂起

c# - 另一个 System.Runtime.InteropServices 错误

C# 到 C++ 多线程,会出现什么问题?

c++ - 如何填充椭圆形状?

linux - 在特定时间间隔后停止 Bash 脚本

php - Wordpress 函数在 bash 中运行的 php 脚本中不起作用