1. 程式人生 > >C呼叫C++動態庫以及靜態連結庫

C呼叫C++動態庫以及靜態連結庫

最近想在TI DM8168 上使用live555,但是Ti的程式碼都是C的,而live555是C++編寫。於是就想通過吧live555編譯為C庫,就到網上探尋方法,現在總結如下:

C++ 檔案編譯庫, C++介面檔案編譯為庫,C檔案呼叫C++介面即可。

OS : Ubuntu 14.04 32bit

tool:gcc g++

C++ 原檔案:

//cppfunc.h

#ifndef _CPPFUNC_H_
#define _CPPFUNC_H_
class CppFun;
class CppFun{
public:
	CppFun();
	void print(void);
private:
	int a;
};
#endif
//cppfunc.cpp
#include "CppFunc.h"
#include <iostream>
using namespace std;
CppFun::CppFun(){
	cout<<"CppFun Construct \n";
	a =1;
}
void CppFun::print(void){
	cout<<a<<endl;
}

介面檔案CPP

//cppso.h

#ifdef __cplusplus
extern "C"
{
#endif
    int CppSo();
#ifdef __cplusplus
};
#endif

//cppso.cpp

#include "CppFunc.h"
#include "CppSo.h"
int CppSo(){
   CppFun cppFunTest;
   cppFunTest.print();
   return 0;
}
//cpptest.c檔案
#include <stdio.h> 
#include <dlfcn.h> 
#include "CppSo.h"

int main() 
{ 
	CppSo();
	return 0; 
} 
makefile檔案:編譯為動態連結庫
#!/bin/sh
CUR_DIR = $(shell pwd)

CPPFUNCINC = $(CUR_DIR)/
CPPSOINC = $(CUR_DIR)/

CPPFUNSRC = $(CUR_DIR)/CppFunc.cpp
CPPSOSRC = $(CUR_DIR)/CppSo.cpp
TESTSRC = $(CUR_DIR)/Ctest.c 

CPPFUNTARGET = libCppFunc.so
CPPSOTARGET = libCppSo.so
TESTTARGET = myapp

CPPLIB = CppFunc
CPPSO = CppSo 
LD_PATH = $(CUR_DIR)/
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$(LD_PATH)
all:
#cpplib:
g++ -I$(CPPFUNCINC) -fPIC -shared -o $(CPPFUNTARGET) $(CPPFUNSRC)
#cppso: 
g++ -I$(CPPFUNCINC) -fPIC -shared -o  $(CPPSOTARGET) $(CPPSOSRC) -L. -l$(CPPLIB)
#cpptest:
gcc -I$(CPPSOINC) -o $(TESTTARGET) $(TESTSRC) -L. -l$(CPPSO) 

.PHONY : clean
clean:
rm *.o *.so $(TESTTARGET) -rf

編譯為DM8168可測試:Makefile

#!/bin/sh

ARCH	= i386

ifeq ($(ARCH),arm)
ACROSS_COMPILE	= arm-none-linux-gnueabi-
endif

ifeq ($(ARCH),i386)
ACROSS_COMPILE =
endif

CC 				= $(ACROSS_COMPILE)gcc
CPP 			= $(ACROSS_COMPILE)g++

CUR_DIR 	= $(shell pwd)
CPPFUNCINC 	= $(CUR_DIR)/
CPPSOINC	= $(CUR_DIR)/

CPPFUNSRC 	= $(CUR_DIR)/CppFunc.cpp
CPPSOSRC	= $(CUR_DIR)/CppSo.cpp
TESTSRC 	= $(CUR_DIR)/Ctest.c 

CPPFUNTARGET 	= libCppFunc.so
CPPSOTARGET 	= libCppSo.so
TESTTARGET 		= myapp

LIBS_PATH =$(CUR_DIR)
LIBS+=$(CPPSOTARGET)

CPPLIB	= CppFunc
CPPSO 	= CppSo	

LD_PATH = $(CUR_DIR)/
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$(LD_PATH)

all:
#cpplib:
	$(CPP) 	-I$(CPPFUNCINC) -fPIC -shared -o $(CPPFUNTARGET) $(CPPFUNSRC)
#cppso: 
	$(CPP)	-I$(CPPFUNCINC) -fPIC -shared -o  $(CPPSOTARGET) $(CPPSOSRC) -L$(LIBS_PATH) -l$(CPPLIB)
#cpptest:
	$(CC) 	-I$(CPPSOINC) -o $(TESTTARGET) $(TESTSRC)  -L$(LIBS_PATH) -l$(CPPSO) -l$(CPPLIB)

.PHONY : clean
clean:
	rm *.o *.so $(TESTTARGET) -rf
	

Note:

1、注意.a(靜態連結庫)和.so(動態連結庫)檔案的區別;

2、注意-fPIC(Position-Independent Code)編譯選項,編譯的程式碼和地址無光,可在記憶體的任意位置執行。

3、-L.當前目錄下搜尋lib

4、-shared共享

5、錯誤提示:

沒有找到libCppSo.so,又有系統的連結庫位於 /lib 、/usr/lib下,

所以我們可以把該連結庫放在此目錄,當然這個是不必要的。臨時改變 LD_LIBRARY_PATH環境變數即可。如下:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./

即可,然後在執行。

在DM8168上執行的時候,要把 生成libCppSo.so libCppFunc.so 放在/lib目錄下面。

C呼叫CPP靜態連結庫

ar -scr libCppA.a *.o 
連結為靜態連結庫後,使用時候,注意 必須加上lstdc++,否則編譯會出錯!
gcc -o main main.c libCppA.a -lstdc++

動態連結庫不方便使用,不易管理,每次使用執行程式都要動態載入,好處就是程式會比靜態連結庫的程式小很多,就算程式加上動態連結庫的大小也比靜態連結庫編譯出來的程式小很多。當然了,動態連結庫可以給每個程式使用,而靜態連結庫每次都要編譯在程式裡面。如果多個程式都會用到的話還是建議用動態連結庫好一點。