Linux系统上java调用C++ so库文件

 

PART1:

    java中使用jna替代jni调用c++/c生成的 dll/so库文件需要做的事项

1、引入JNA依赖或者直接下载JNAjar包
 
                    <dependency>
                        <groupId>net.java.dev.jna</groupId>
                        <artifactId>jna</artifactId>
                        <version>5.2.0</version>
                    </dependency>
 
2、编写Java 调用类
 
           
        package com.tree.go.util;
            import com.sun.jna.Library;
            import com.sun.jna.Native;
 
            //继承Library,用于加载库文件 --Class mapping
            public  interface CPPTest  extends Library { 
                // 加载libhello.so链接库 
                  public static final String JNA_ImgProcess = "hello";
                  public static final CPPTest instance = (CPPTest)Native.loadLibrary(CPPTest.JNA_ImgProcess,CPPTest.class);
 
                // 此方法为链接库中的方法  function mapping
                void test(); 
                int addTest(int a,int b);
             
            //调用,singleton
            public static void main(String[] args) {
                  CPPTest instance =CPPTest.instance;
                  instance.test(); 
                  int c =instance.addTest(10,20);   
            }
    }     

  

 
 
            
接下来的工作就是如何编写可供调用的Cpp文件,以及编译加载的问题了,查看part 2  

 
 

PART2:

    编写C++/C文件,编译

 
准备编写C++代码[T1.cpp],如下:
 
#include <iostream>  
 using namespace std;
 
 extern "C"{ //避免name mangling,编译后名称symbol破坏,导致无法找到函数,告诉编译器下面的代码块使用c编译器来编译
       int addTest(int a, int b)
{
       cout << "a+b" << a + b << endl; 
       return a + b;
}
       void test()
       {
             cout << "hello word from C++ ! " << endl; 
}
}

  

 
 
1、如何将C++文件编译为so文件?
 
    这里需要区分编译c文件和c++文件使用的是不同的编译器,具体编译参数可以复用
 
        1.1、编译c文件使用 gcc
    示例:
    使用命令:gcc -fPIC -shared -o libGoT.so  T1.c
 
 
        1.2、编译c++文件使用的是 g++
                                g++ -fPIC -shared -o libhello.so  T1.cpp
 
        编译完成后生成如下文件:
                    
 
2、如何加载编译好的so文件?
 
         配置so文件加载位置:
打开  vim /etc/profile
添加如下配置:
/home/data/libso是自定义目录,
export LD_LIBRARY_PATH=/home/data/libso
多个目录用:隔开,如下
export LD_LIBRARY_PATH=/home/data/libso:/usr/lib
 
这样就可在Java中调用使用C程序编写好的代码了

 
 

PART3:

    注意事项:

1、C++编译后函数名称破环问题
        名称一致性问题,java中调用的和cpp文件中定义的名称需要保持一致
        解决:使用   extern "C"放到一句代码前,或者一段代码前 extern "C"{ your code}
    
 
2、   编译生成动态库名的问题
            注意在编译的时候一点要在库民前面加上  lib+soname.so
            否则JNA如法加载到库文件
            示例:我们需要一个hello库需要这样编译,前面加上lib
 
                 g++ -fPIC -shared -o libhello.so  T1.cpp
                    
        

linux动态库的命名规则

动态链接库的名字形式为 libxxx.so,前缀是lib,后缀名为“.so”。
  针对于实际库文件,每个共享库都有个特殊的名字“soname”。在程序启动后,程序通过这个名字来告诉动态加载器该载入哪个共享库。
  在文件系统中,soname仅是一个链接到实际动态库的链接。对于动态库而言,每个库实际上都有另一个名字给编译器来用。它是一个指向实际库镜像文件的链接文件(lib+soname+.so)。
 
 
 

显式调用C++动态库注意点

对C++来说,情况稍微复杂。显式加载一个C++动态库的困难一部分是因为C++的name mangling;另一部分是因为没有提供一个合适的API来装载类,在C++中,您可能要用到库中的一个类,而这需要创建该类的一个实例,这不容易做到。
name mangling可以通过extern "C"解决。C++有个特定的关键字用来声明采用C binding的函数:extern "C" 。用 extern "C"声明的函数将使用函数名作符号名,就像C函数一样。因此,只有非成员函数才能被声明为extern "C",并且不能被重载。尽管限制多多,extern "C"函数还是非常有用,因为它们可以象C函数一样被dlopen动态加载。冠以extern "C"限定符后,并不意味着函数中无法使用C++代码了,相反,它仍然是一个完全的C++函数,可以使用任何C++特性和各种类型的参数。
另外如何从C++动态库中获取类,附上几篇相关文章,但我并不建议这么做:
l  《LoadLibrary调用DLL中的Class》:http://www.cppblog.com/codejie/archive/2009/09/24/97141.html
“显式”使用C++动态库中的Class是非常繁琐和危险的事情,因此能用“隐式”就不要用“显式”,能静态就不要用动态。

附件:Linux下库相关命令

g++(gcc)编译选项

  -shared :指定生成动态链接库。
  -static :指定生成静态链接库。
  -fPIC :表示编译为位置独立的代码,用于编译共享库。目标文件需要创建成位置无关码,念上就是在可执行程序装载它们的时候,它们可以放在可执行程序的内存里的任何地方。
  -L. :表示要连接的库所在的目录。
  -l:指定链接时需要的动态库。编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.a/.so来确定库的名称。
  -Wall :生成所有警告信息。
  -ggdb :此选项将尽可能的生成gdb 的可以使用的调试信息。
  -g :编译器在编译的时候产生调试信息。
  -c :只激活预处理、编译和汇编,也就是把程序做成目标文件(.o文件) 。
  -Wl,options :把参数(options)传递给链接器ld 。如果options 中间有逗号,就将options分成多个选项,然后传递给链接程序。

nm命令

有时候可能需要查看一个库中到底有哪些函数,nm命令可以打印出库中的涉及到的所有符号。库既可以是静态的也可以是动态的。nm列出的符号有很多,常见的有三种:
  一种是在库中被调用,但并没有在库中定义(表明需要其他库支持),用U表示;
  一种是库中定义的函数,用T表示,这是最常见的;
  一种是所谓的弱态”符号,它们虽然在库中被定义,但是可能被其他库中的同名符号覆盖,用W表示。
$nm libhello.h

ldd命令

    ldd命令可以查看一个可执行程序依赖的共享库,例如我们编写的测试动态库依赖下面这些库:
        
 
 

posted on 2019-05-23 17:23  滚动的蛋  阅读(4941)  评论(0编辑  收藏  举报

导航