前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >linux 编译 c或cpp 文件为动态库 so 文件(最简单直观的模板)

linux 编译 c或cpp 文件为动态库 so 文件(最简单直观的模板)

作者头像
杨永贞
发布2020-08-04 10:42:50
5.3K0
发布2020-08-04 10:42:50
举报

把源码编译打包为动态库so文件,做平台的可能对这些不熟悉。

对我们这些算是经常用到的。

总结个模板,一看就懂的那种,提供给有需要的人。

前提条件,机器上有 gcc工具链。

如果文件个数少,可以直接单个编译,如下:

Building shared lib... g++ -c -fPIC Quote.cpp -o Quote.o g++ -c -fPIC QuoteExport.cpp -o QuoteExport.o g++ -c -fPIC Start.cpp -o Start.o Generating shared lib... g++ -shared -fPIC -o libQuoteLib.so ./Quote.o ./QuoteExport.o ./Start.o cp libQuoteLib.so ../ OK!

如果文件个数较多,或者夸文件夹了,层层嵌套。

那么就整个makefile模板文件,放到代码的根目录下,直接执行一个make即可。

模板文件如下:

代码语言:javascript
复制
############################################################################
#makefile,created by yangyongzhen qq:534117529
############################################################################

#****************************************************************************
# Cross complie path
#****************************************************************************
#GCC_PATH=D:\msysgit\mingw

CROSS_COMPILE=


CC     := $(CROSS_COMPILE)gcc
CXX    := $(CROSS_COMPILE)g++
AS	   := $(CROSS_COMPILE)as
AR     := $(CROSS_COMPILE)ar 
LD     := $(CROSS_COMPILE)ld
RANLIB := $(CROSS_COMPILE)ranlib
OBJDUMP:= $(CROSS_COMPILE)objdump
OBJCOPY:= $(CROSS_COMPILE)objcopy
STRIP  := $(CROSS_COMPILE)strip

#****************************************************************************
# Flags
#****************************************************************************

CFLAGS= 
LDSCRIPT= 
LDFLAGS= 


#****************************************************************************
# Source files
#****************************************************************************
SRC_C=$(shell find . -name "*.cpp")

OBJ_C=$(patsubst %.cpp, %.o, $(SRC_C))

SRCS := $(SRC_C) $(SRC_C)

OBJS := $(OBJ_C) 


#****************************************************************************
# Targets of the build
#****************************************************************************
TARGET   	:= libQuoteLib

.PHONY: clean
all:  prebuild  $(TARGET).so

#****************************************************************************
# TARGET
#****************************************************************************
prebuild:
	@echo Building shared lib...

$(TARGET).so : $(OBJS)
	@echo Generating shared lib...
	$(CXX) -shared -fPIC -o  $(TARGET).so $(OBJS) 
	cp $(TARGET).so ../
	@echo OK!

%.o : %.cpp
	$(CXX) -c -fPIC $(CFLAGS) $< -o  $@
	
clean:
	@echo The following files:
	rm  -f  $(TARGET) *.so
	find . -name "*.[od]" |xargs rm
	@echo Removed!

注:在linux上,源文件的函数或方法前,不需要声明 __declspec(dllexport) 在WIn32上才需要。

所以在头文件中一般会看到:

#ifdef _WIN32 #define TAP_CDECL __cdecl #define TAP_DLLEXPORT __declspec(dllexport) #else #define TAP_CDECL #define TAP_DLLEXPORT #endif

__cdecl 是C Declaration的缩写(declaration,声明),表示C语言默认的函数调用方法:所有参数从右到左依次入栈,这些参数由调用者清除,称为手动清栈。

被调用函数不会要求调用者传递多少参数,调用者传递过多或者过少的参数,甚至完全不同的参数都不会产生编译阶段的错误。

_stdcall 是StandardCall的缩写,是C++的标准调用方式:所有参数从右到左依次入栈,如果是调用类成员的话,最后一个入栈的是this指针。这些堆栈中的参数由被调用的函数在返回后清除,使用的指令是 retnX,X表示参数占用的字节数,CPU在ret之后自动弹出X个字节的堆栈空间。称为自动清栈。函数在编译的时候就必须确定参数个数,并且调用者必须严格的控制参数的生成,不能多,不能少,否则返回后会出错。

C中不加说明默认函数为_cdecl方式(C中也只能用这种方式),C++也一样,但是默认的调用方式可以在IDE环境中设置。

带有可变参数的函数必须且只能使用_cdecl方式

__cdecl __fastcall与__stdcall,三者都是调用约定(Calling convention),它决定以下内容:1)函数参数的压栈顺序,2)由调用者还是被调用者把参数弹出栈,3)以及产生函数修饰名的方法。

1、__stdcall调用约定:函数的参数自右向左通过栈传递,被调用的函数在返回前清理传送参数的内存栈。

2、__cdecl是C和C++程序的缺省调用方式。每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行文件大小会比调用_stdcall函数的大。函数采用从右到左的压栈方式。注意:对于可变参数的成员函数,始终使用__cdecl的转换方式。

3、__fastcall调用约定:它是通过寄存器来传送参数的(实际上,它用ECX和EDX传送前两个双字(DWORD)或更小的参数,剩下的参数仍旧自右向左压栈传送,被调用的函数在返回前清理传送参数的内存栈)。

4、thiscall仅仅应用于"C++"成员函数。this指针存放于CX寄存器,参数从右到左压。thiscall不是关键词,因此不能被程序员指定。

5、nakedcall采用1-4的调用约定时,如果必要的话,进入函数时编译器会产生代码来保存ESI,EDI,EBX,EBP寄存器,退出函数时则产生代码恢复这些寄存器的内容。naked call不产生这样的代码。naked call不是类型修饰符,故必须和_declspec共同使用。

关于__declspec的解释,转自:CSDN博主「fengbingchun」

原文链接:https://blog.csdn.net/fengbingchun/article/details/78825004

__declspec是Microsoft VC中专用的关键字,它配合着一些属性可以对标准C/C++进行扩充。__declspec关键字应该出现在声明的前面。

__declspec(dllexport)用于Windows中的动态库中,声明导出函数、类、对象等供外面调用,省略给出.def文件。即将函数、类等声明为导出函数,供其它程序调用,作为动态库的对外接口函数、类等。

.def文件(模块定义文件)是包含一个或多个描述各种DLL属性的Module语句的文本文件。.def文件或__declspec(dllexport)都是将公共符号导入到应用程序或从DLL导出函数。如果不提供__declspec(dllexport)导出DLL函数,则DLL需要提供.def文件。

__declspec(dllimport)用于Windows中,从别的动态库中声明导入函数、类、对象等供本动态库或exe文件使用。当你需要使用DLL中的函数时,往往不需要显示地导入函数,编译器可自动完成。

不使用__declspec(dllimport)也能正确编译代码,但使用__declspec(dllimport)使编译器可以生成更好的代码。编译器之所以能够生成更好的代码,是因为它可以确定函数是否存在于DLL中,这使得编译器可以生成跳过间接寻址级别的代码,而这些代码通常会出现在跨DLL边界的函数调用中。声明一个导入函数,是说这个函数是从别的DLL导入。一般用于使用某个DLL的exe中。 ---------------------

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-08-15 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档