写在前面:
1、在实际项目开发当中,库文件用的很多,尤其是在不同的 企业之间为了防止源码公开,都是以库的形式提供给对方,然后提供必要的头文件就可以了。本文主要介绍Linux下和Windows下的库的格式,以及动态链接库和静态链接库的作用,Linux下如何用Makefile编译制作动态链接库的方法。
2、Makefile博大精深,在平时用的不多,所以本文也是对刚刚用过的Makefile简单使用的方法做一下总结,加深下印象。
QQ:993650814
正文:
一、 动态链接库和静态链接库
1、Windows下和Linux下的格式:
Windows下动态链接库的格式:.dll ; 静态链接库的格式: .lib;
Linux 下动态链接库的格式: .so; 静态链接库的格式: .a
2、Linux下动态链接库和静态链接库的不同点:
.a静态库:
链接时间:静态库在编译的过程中被加载入程序中。
链接方式:静态库的链接是将整个库中所有的函数整合进了目标代码。这样的优点是编译后的程序不再需要外部函数库 支 持。缺点是,如果要改变静态库,则需要重新编译整个工程。
.so动态库:
链接时间:编译的过程中不需要将动态库编译进目标代码,而是当程序执行到相关函数的时候才去调用动态库中的相应 函数。优点是,动态库的改变不影响程序,动态库的升级比较方便。缺点是,程序在运行的时候必须提供 相应的库。
所以,他们两者还有一个很大的不同点:同一个程序分别使用静态库和动态库两种方式来生成可执行文件的时候,静态 链接所生成的文件所占的内存要远远大于动态链接。
二、用Makefile来制作动态链接库
直接粘贴代码,注释都在代码里了
#指定交叉编译工具链
CROSS_COMPILE = arm-hisiv100nptl-linux-
AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar
NM = $(CROSS_COMPILE)nm
#获取工程的根目录的全路径
SOURCE_ROOT = $(shell pwd)
CFLAGS := -Wall -O2 -fno-builtin
CPPFLAGS :=
#-I是指定头文件的意思,所以这里是将所有的头文件的变量都包含在 INCLUDE_DIR 变量中
INCLUDE_DIR := -I $(SOURCE_ROOT)/ \
-I$(SOURCE_ROOT)/app\
-I$(SOURCE_ROOT)/control\
-I$(SOURCE_ROOT)/libevent \
-I$(SOURCE_ROOT)/libevent/include \
-I$(SOURCE_ROOT)/libskylink \
-I$(SOURCE_ROOT)/platform \
-I$(SOURCE_ROOT)/utils \
-I$(SOURCE_ROOT)/libmqtt/MQTTPacket \
-I$(SOURCE_ROOT)/include
#生成的目标的库文件名称是mylib.so
APP_NAME=mylib.so
#将所有的.c文件都包含在APP_OBJECTC中,当然这里肯定还有其他的方法,我这里
#的效率肯定不是特别高
all: $(APP_NAME)
APP_OBJECTC += aliyun_mqtt_client.c
APP_OBJECTC += iot_device_info.c
APP_OBJECTC += lan_discovery.c
APP_OBJECTC += app/http_client.c
APP_OBJECTC += libevent/buffer.c
APP_OBJECTC += libevent/bufferevent.c
APP_OBJECTC += libevent/bufferevent_sock.c
APP_OBJECTC += libevent/bufferevent_ssl.c
APP_OBJECTC += libevent/evdns.c
APP_OBJECTC += libevent/event.c
APP_OBJECTC += libevent/evmap.c
APP_OBJECTC += libevent/evutil.c
APP_OBJECTC += libevent/evutil_rand.c
APP_OBJECTC += libevent/http.c
APP_OBJECTC += libevent/listener.c
APP_OBJECTC += libevent/log-internal.c
APP_OBJECTC += libevent/minheap-internal.c
APP_OBJECTC += libevent/mm-internal.c
APP_OBJECTC += libevent/select.c
APP_OBJECTC += libevent/strlcpy.c
APP_OBJECTC += libmqtt/MQTTPacket/MQTTConnectClient.c
APP_OBJECTC += libmqtt/MQTTPacket/MQTTDeserializePublish.c
APP_OBJECTC += libmqtt/MQTTPacket/MQTTPacket.c
APP_OBJECTC += libmqtt/MQTTPacket/MQTTSerializePublish.c
APP_OBJECTC += libmqtt/MQTTPacket/MQTTSubscribeClient.c
APP_OBJECTC += libmqtt/MQTTPacket/MQTTUnsubscribeClient.c
APP_OBJECTC += libskylink/crc.c
APP_OBJECTC += libskylink/skylink.c
APP_OBJECTC += libskylink/skylink_setting.c
APP_OBJECTC += utils/cJSON.c
APP_OBJECTC += utils/hashmap.c
APP_OBJECTC += utils/utils_hmac.c
APP_OBJECTC += utils/utils_list.c
APP_OBJECTC += utils/utils_md5.c
APP_OBJECTC += utils/utils_sha1.c
#介绍一下 patsubst,
#patsubst:扩展通配符
#作用: $(patsubst %.c,%.o,$(dir) )中,patsubst把$(dir)中的变量符合后缀是.c的全部替换成.o
#所以,本例中,patsubst把 $(APP_OBJECTC)中的复合.c的全部替换成.o
STATIC_OBJ_O = $(patsubst %.c, %.o, $(APP_OBJECTC))
#再介绍一下 foreach 函数
#作用:这个函数是用来做循环用的
#例如:$(foreach <var>,<list>,<text>)
#这个函数的意思是,把参数<list>;中的单词逐一取出放到参数<var>;所指定的变量中,然后再执行< #text>;所包含的表达式。每一次<text>;会返回一个字符串,循环过程中,<text>;的所返回的每个字符串会#以空格分隔,最后当整个循环结束时,<text>;所返回的每个字符串所组成的整个字符串(以空格分隔)将会
#是foreach函数的返回值。
#所以,本例中,就是将STATIC_OBJ_O中所有的.o文件取出来放到STATIC_OBJ_C中,每个.o文件以空格间隔
STATIC_OBJ_C = $(foreach file, $(STATIC_OBJ_O), $(file) )
#下面:目标是.o文件,依赖是.c文件
#-fPIC的作用是:告诉编译器,产生位置无关码
$(STATIC_OBJ_C) : %.o:%.c
$(CC) $(INCLUDE_DIR) $(CPPFLAGS) -c -fPIC $(APP_OBJECTC)
#下面:目标是.so,依赖是.o文件
#-shared的作用就是制定成才.so文件
$(APP_NAME): $(STATIC_OBJ_C)
$(CC) -shared -o $(APP_NAME) ./*.o
clean:
@rm -f *.o *.so
.PHONY: clean
这个Makefile写好了,在此Makefile的目录下就直接make就好了。这个Makefile中生成的.so和.o文件都在工程的根目录下,如下图: