Tags: g++ C++ so library
在Linux系统下用g++命令编译C++程序.也可以生成so,a链接库
示例一 编译时链接so库
Test.h 文件内容
Main.cpp文件内容
命令执行过程
//生成so文件
g++ -shared -fPIC -o libTestLib.so Test.h
//编译Main.cpp并链接so.生成可执行文件Main
g++ Main.cpp -o Main -L.
//执行可执行文件Main
./Main
使用Makefile
Makefile解读
Makefile的基本规则是
生成目标 : 依赖目标
<TAB>命令
Makefile会首先检查生成目标的依赖目标,若所有依赖目标准备好,则执行下一行以<TAB>(制表符)开头的命令,来产生生成目标.
一般来说一个Makefile只有一个最终目标(一般是Makefile定义的第一个).而这个目标可以依赖其他目标,Makefile会自动检查依赖,并且按依赖关系逐个生成
上面Main目标依赖LibTest.so Main.cpp,其中Main.cpp是源文件,不需要生成,而LibTest.so是一个目标,因此Makefile会找到LibTest.so的生成规则,并首先生成LibTest.so再生成最终目标Main
LibTest.so的生成又依赖于Test.h文件,其中Test.h是源文件,所以可以直接利用下面的<Tab>后的命令生成LibTest.so.因此Makefile首先执行的是g++ -shared -fPIC -o LibTest.so Test.h
在生成LibTest.so后,最终目标Main的所有依赖文件已经准备好,则Makefile执行
g++ Main.cpp -o Main -L.
来生成最终目标Main文件
伪目标
Mainfile中的clean也是一个目标,但是并不依赖于任何文件,这种目标称为伪目标,而且应该用
.PHONY: clean
来声明该伪目标.
Makefile的执行:
对于Makefile的最终目标(一般为第一个),可以直接在命令行执行make命令,由Makefile自动识别来执行
也可以使用
make 目标名
来执行指定目标,而对于伪目标clean,则必须使用 make clean的方式显示执行:
make clean
参考
http://blog.csdn.net/haoel/article/details/2887
注意:
-shared 是指生成动态链接库,详细查Google
http://blog.sina.com.cn/s/blog_54f82cc201011op1.html-fPIC 是指编译代码为可共享,参考:
-o 后面为输出文件名称
-L. 是指的在以下位置查找链接库,其中L后面的(.)是指的是当前目录
示例二 代码动态加载库
若要动态加载.so库则需要使用dlopen 等函数
目录结构
Test.h内容
extern "C" {
int TestAdd(int x, int y);
}
Test.cpp内容
#include "Test.h"
extern "C" int TestAdd(int x, int y)
{
return x + y;
}
Main.cpp内容
#include <dlfcn.h>
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
void *handle = dlopen("./Test.so", RTLD_LAZY);
if (!handle)
{
cout << dlerror() << endl;
return -1;
}
typedef int (*add_t)(int a, int b);
add_t add = (add_t) dlsym(handle, "TestAdd");
if (!add)
{
cout << dlerror() << endl;
dlclose(handle);
return -1;
}
int a = add(3,5);
cout << "a = " << a << endl;
dlclose(handle);
return 0;
}
Makefile内容:
Main: libTest.so Main.cpp
g++ -ldl -o Main Main.cpp
libTest.so: ./Sources/*.cpp
g++ -shared -fPIC -o libTest.so ./Sources/*.cpp -I ./Headers/
.PHONY: clean
clean:
-rm -f Main
-rm -f libTest.so
注意:
1.
不管什么库文件,你都既要在包含.h文件(不然编译通不过:有未声明的函数),也要在gcc选项里面指定.so文件的位置(不然链接通不过:未知的符号) 比如 gcc -I include_path -L lib_path -lyourlib include_path改成你头文件的目录 lib_path改成你动态库文件的目录 -lyourlib 改成l加上你要引用的库文件名字 比如libpthread.so就改成-lpthread
http://blog.chinaunix.net/uid-21273878-id-4148042.html
示例三 Linux下Eclipse 中调用so文件
首先在Linux下安装Eclipse,确保jdk环境都配置ok
创建Eclipse工程,创建java代码源文件
TestLib.java
public class TestLib {
static{
System.loadLibrary("Test");
}
public static native int TestAdd(int a, int b);
public static void main(String args[])
{
System.out.println(TestAdd(1, 2));
}
}
在TestLib.java文件目录下,使用javac命令生成TestLib.class文件
javac TestLib.java
在bin目录下,找到生成的TestLib.class 文件(若没有该文件,则在TestLib.java相同目录下找,并复制到bin目录下.
在bin目录下,执行以下命令生成C++工程使用的TestLib.h文件
javah -classpath . -jni TestLib
生成的TestLib.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class TestLib */
#ifndef _Included_TestLib
#define _Included_TestLib
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: TestLib
* Method: TestAdd
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_TestLib_TestAdd
(JNIEnv *, jclass, jint, jint);
#ifdef __cplusplus
}
#endif
#endif
创建C++代码Test.cpp,实现TestLib.h中定义的各接口:
Test.cpp
include "TestLib.h"
JNIEXPORT jint JNICALL Java_TestLib_TestAdd
(JNIEnv *env, jclass cls, jint a, jint b)
{
return a + b;
}
编写Makefile
Makefile 内容
libTest.so: ./Sources/*.cpp
g++ -shared -fPIC -o libTest.so ./Sources/*.cpp -I ./Headers/ \
-I /usr/lib/jvm/java-1.7.0-openjdk.x86_64/include \
-I /usr/lib/jvm/java-1.7.0-openjdk.x86_64/include/linux
命令行执行 make libTest.so
生成libTest.so文件,将so文件拖到Eclipse项目中.运行Eclipse项目.
正确调用libTest.so中定义的接口
注意:
生成的TestLib.h包含了jni.h文件,而且需要jni_md.h文件.所以在g++命令时,需要用 -I 参数指定这两个头文件的路径