gnu make 手册 学习笔记 C语言 / C++ 构建工具 part.6 编译 静态库 动态库

6.静态库,动态库

库命名规范
gcc下:
静态库     libxxxx.a
动态库     libxxxx.so   或者加上版本号  libxxxx.so.major.minor
window下:
静态库	  xxx.lib
动态库     xxx.dll

静态库的编译方式
编译为二进制文件  gcc -c xxx.c -o xxx.o
打包            ar  rcs  libxxx.a xxx.o
进行链接         gcc main.o xxx.o -o xxx.exe(exe是window下才需要的后缀,这样写是为了好看。)

动态库的编译方式
编译为二进制文件   gcc -c xxx.c -o xxx.o
打成动态库     	 gcc -fPIC -shared  xxx.  -o libxxx.so
进行链接	         gcc -L .  main.o libxxx.so -o xxx.exe

6-1.静态库

最简单的理解方式是,将.c的源文件,编译为.o文件,然后使用ar命令,将同一个lib的.o文件打包在一起。

6-1-1.头文件和源文件,在同一个目录

在这里插入图片描述
plus.c

int plus(int first,int second)
{
	return first+second;
}

plus.h

#ifndef plus
#define plus
int plus_method(int ,int );
#endif

invoke_plus.c

#include "plus.h"

#include <stdio.h>

int invoke_plus()
{
	int result=plus(2,3);
	printf("result=%d",result);
}

invoke_plus.h

#ifndef invoke_plush
#define invoke_plush
void invoke_plus_print();
#endif

main.c

#include "invoke_plus.h"

int main()
{
	invoke_plus();
}
上面的文件都在同一级目录

Makefile

cc=gcc                   #指定编译器

main_source=main.o		 #会放在依赖,写成.o触发pattern rule,自动将.c文件编译为.o文件
lib_source =plus.o invoke_plus.o    

lib=libarch.a            #指定静态库的名字


.PHONY: clean all

all:main.exe $(lib)

$(lib): $(lib_source)
	ar -rcs $@ $^      	     #将静态库的.o文件进行打包
	rm -rf $^				 #清除没用的.o文件
	
main.exe:$(main_source) $(lib)
	gcc -o $@  $< $(lib)	 #链接.o文件
	
clean:
	rm -rf *.o *.exe

在这里插入图片描述

6-1-2.头文件和源文件,不在同一个目录

文件的内容不变,仅改变文件的路径
.c-->.o的时候需要指定include的路径
CFLAGS=-I static_lib_header  

在这里插入图片描述
配置Makefile

.PHONY: all clean print


	#定义lib的.O文件,会用在prerequisites ,触发pattern rule,从.c文件编译为.o文件
lib_source =static_lib_src/plus.o static_lib_src/invoke_plus.o
main_source=src/main.o


	#使用pattern rule 编译的时候,由于lib_source的源文件和头文件分开,需要指定include的路径
CFLAGS=-I static_lib_header  

	#定义最终生成的exe文件的保存路径
main_dest=build/Debug/
	#定义lib生成的路径,就是静态库的保存路径
lib_dest=lib/
	#定义静态库的名字
static_arch_lib=libStaticArch.a


all:$(static_arch_lib) main.exe

	#将pattern rule编译好的.o文件,进行打包
$(static_arch_lib): $(lib_source)
	ar -rcs $(lib_dest)/$@ $?
	rm -rf $?
	
	#将pattern rule生成的main.o文件 和 静态库 进行链接
main.exe:$(main_source)	$(static_arch_lib)
	gcc $< $(lib_dest)$(static_arch_lib) -o $(main_dest)$@ 

#pattern rule
# %.o:%.c
#   	$(COMPILE.c) $(OUTPUT_OPTION) $<
#用在pattern rule的默认变量
#		COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c   
#		OUTPUT_OPTION = -o $@         

	    
clean:
	rm -rf  *.o src/*.o lib/*.o  *.exe src/*.exe lib/*.exe build/Debug/*.exe

在这里插入图片描述

6-1-3.静态库 依赖 静态库

need_plus依赖plus

在这里插入图片描述
need_plus.c

#include "plus.h"
#include <stdio.h>

void need_plus_print()
{

    int result=plus(2,3);
	printf("print in nees_plus :result = %d",result);
}

need_plus.h

#ifndef need_plus
#define need_plus
void need_plus_print();
#endif

main.c

#include "invoke_plus.h"
#include "need_plus.h"

int main()
{
	invoke_plus_print();
	need_plus_print();
}

Makefile

.PHONY: all clean print
	#指定依赖的文件及路径
main_source=src/main.o
lib_source =static_lib_src/plus.o static_lib_src/invoke_plus.o
another_lib_source=another_static_lib_src/need_plus.o

	#gcc中每一个include的路径都需要写一个 -I   ,在.c文件编译为.o文件时候需要
CFLAGS=-I another_static_header -I static_lib_header

	#生成文件的路径
main_dest=build/Debug/
lib_dest=lib/

	#库的名字
static_arch_lib=libStaticArch.a
another_arch_lib=libAnother.a


all:$(static_arch_lib) $(another_arch_lib) main.exe
	#将每个静态库使用一个target进行打包
$(static_arch_lib): $(lib_source)
	ar -rcs $(lib_dest)$@ $?
	rm -rf $?

$(another_arch_lib):$(another_lib_source)
	ar -rcs $(lib_dest)$@ $?
	rm -rf $?

	#打包成exe	
main.exe:$(main_source)	$(static_arch_lib) $(another_arch_lib)
	gcc $< $(lib_dest)/$(static_arch_lib) $(lib_dest)/$(another_arch_lib) -o $(main_dest)$@ 
	rm -rf $<
	
#COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c   
#OUTPUT_OPTION = -o $@         
%.o:%.c
	$(COMPILE.c) $< $(OUTPUT_OPTION) 
	    
clean:
	rm -rf  *.o src/*.o another_static_lib_src/*.o lib/*  *.exe src/*.exe lib/*.exe build/Debug/*.exe 

在这里插入图片描述

生成的结构

生成的项目结构

6-2动态库

需要使用gcc将.0文件打包,然后链接
gcc -c xxx.c -o xxx.o
打成动态库
gcc -fPIC -shared  xxx.o  -o libxxx.so
进行链接
gcc -L .  main.o libxxx.so -o xxx.exe

6-2-1.头文件和源文件,在同级目录

文件结构
在这里插入图片描述
main.c

#include "invoke_sub.h"

int main()
{
    sub_method();
}

subtraction.c

int sub(int first,int second)
{
    return first-second;
}

subtraction.h

#ifndef subtraction
#define subtraction
int sub(int,int);
#endif

invoke_sub.c

#include "subtraction.h"
#include <stdio.h>
void sub_method()
{
    printf("resulte = %d",sub(9,3));
}

invoke_sub.h

#ifndef invoke_sub
#define invoke_sub
void sub_method();
#endif

Makefile

.PHONY:clean all
	#动态库的依赖,写成.o会触发pattern rule 
shared_lib_source=subtraction.o invoke_sub.o
	#  main	
main_source=main.o
	#定义lib的名字
shared_lib=libshared_lib.so


all:$(shared_lib) main.exe

	#编译动态库文件
$(shared_lib):$(shared_lib_source)
	gcc -fPIC -shared $? -o $@
	rm -rf $^

	#使用动态库文件和main.o进行链接
main.exe:$(main_source) $(shared_lib)
	gcc -L . $(shared_lib) $< -o $@      #-L 表示添加lib的加载路径
	rm -rf $<

#gcc -shared -fPIC -o libmyhello.so hello.o
#gcc -o hello main.c -L. -lmyhello
clean:
	rm -rf *.o *.exe

在这里插入图片描述

6-2-2.头文件和源文件,不在同一目录

在.c-->.o的时候需要include路径
CFLAGS=-I another_static_header -I static_lib_header -I share_lib_header

文件结构
在这里插入图片描述
还是上面的源文件,仅仅改一下文件的位置,并且跟原来的文件一起编译
Makefile

.PHONY: all clean print
#定义编译器变量
cc=gcc      #编译器
CFLAGS=-I another_static_header -I static_lib_header -I share_lib_header   #包含路径,就是include的查找路径,用在.c->.o


#定义prerequires的文件
	#main
main_source=src/main.o
	#静态库
lib_source =static_lib_src/plus.o static_lib_src/invoke_plus.o
another_lib_source=another_static_lib_src/need_plus.o
	#动态库
shared_lib_source=share_lib_src/subtraction.o share_lib_src/invoke_sub.o

#定义库名
	#静态库
static_arch_lib=libStaticArch.a
another_arch_lib=libAnother.a
	#动态库
shared_lib=libshared_lib.so

#定义编译后文件的路径
main_dest=build/Debug/
lib_dest=lib/

	# 写rule
all:$(static_arch_lib) $(another_arch_lib) $(shared_lib) main.exe
	#静态库
$(static_arch_lib): $(lib_source)
	ar -rcs $(lib_dest)$@ $?
	rm -rf $?
	
$(another_arch_lib):$(another_lib_source)
	ar -rcs $(lib_dest)$@ $?
	rm -rf $?

	#动态库
$(shared_lib):$(shared_lib_source)
	gcc -fPIC -shared $? -o $(lib_dest)$@
	rm -rf $^

#将全部文件链接为可执行文件
main.exe:$(main_source)	$(static_arch_lib) $(another_arch_lib) $(shared_lib)
	gcc $< $(addprefix $(lib_dest),$(filter-out $<,$?)) -o $(addprefix $(main_dest),$@)  
	cp lib/$(shared_lib) build/Debug/$(shared_lib)
	rm -rf $<
#由于lib有多个,使用函数$(addprefix)将lib的名字和保存路径和在一起,因为第一个prerequires是main.o使用函数$(filterout)去除,
#由于动态库在程序运行的时候需要被加载,
#要么放到系统指定路径,
#要么在环境变量LD_LIBRARY_PATH添加路径(linux下修改/etc/ld.so.conf),
#要么放在exe的同级目录,这里选择的cp到同级目录

#COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c   
#OUTPUT_OPTION = -o $@         
%.o:%.c
	$(COMPILE.c) $< $(OUTPUT_OPTION) 
#就是默认pattern rule,将.c编译为.o
clean:
	rm -rf  *.o src/*.o another_static_lib_src/*.o lib/*  *.exe src/*.exe lib/*.exe build/Debug/*

在这里插入图片描述
在这里插入图片描述

6-2-3.动态库 依赖 动态库

需要将依赖的动态库先编译好,然后写在参数上。
gcc -fPIC -shared $? needed_shared_lib  -o $(lib_dest)$@

在这里插入图片描述

need_share_lib.c
#include "subtraction.h"
#include <stdio.h>
void needSub()
{
    printf("print in need_share_lib: result = %d \n",sub(9,6));
}
need_share_lib.h
#ifndef need_shared_lib
#define need_shared_lib

void needSub();

#endif 
main.c
#include "invoke_plus.h"
#include "need_plus.h"
#include "invoke_sub.h"
#include "need_share_lib.h"

int main()
{
	invoke_plus_print();
	need_plus_print();
	sub_method();
	needSub();
}
Makefile
.PHONY: all clean print

cc=gcc
CFLAGS=-I another_static_header -I static_lib_header -I share_lib_header -I shareLib_need_sharedLib_header


main_source=src/main.o

lib_source =static_lib_src/plus.o static_lib_src/invoke_plus.o
another_lib_source=another_static_lib_src/need_plus.o

shared_lib_source=share_lib_src/subtraction.o share_lib_src/invoke_sub.o
need_share_lib_source=shareLib_need_shareLib_src/need_share_lib.o         #新的动态库的依赖


static_arch_lib=libStaticArch.a
another_arch_lib=libAnother.a

shared_lib=libshared_lib.so
need_share_lib=libneed_share_lib.so                                       #定义新的动态库的名字


main_dest=build/Debug/
lib_dest=lib/


all:$(static_arch_lib) $(another_arch_lib) $(shared_lib) $(need_share_lib) main.exe

$(static_arch_lib): $(lib_source)
	ar -rcs $(lib_dest)$@ $?
	rm -rf $?

$(another_arch_lib):$(another_lib_source)
	ar -rcs $(lib_dest)$@ $?
	rm -rf $?


$(shared_lib):$(shared_lib_source)
	gcc -fPIC -shared $? -o $(lib_dest)$@
	rm -rf $^
	
	#编译新的动态库,需要添加依赖的动态库进行编译$(lib_dest)$(shared_lib)
$(need_share_lib):$(need_share_lib_source)
	gcc -fPIC -shared $? $(lib_dest)$(shared_lib) -o $(lib_dest)$@
	rm -rf $^

main.exe:$(main_source)	$(static_arch_lib) $(another_arch_lib) $(shared_lib) $(need_share_lib)
	gcc $< $(addprefix $(lib_dest),$(filter-out $<,$?)) -o $(addprefix $(main_dest),$@)  
	cp lib/$(shared_lib)  build/Debug/$(shared_lib)
	cp lib/$(need_share_lib) build/Debug/
	rm -rf $<



#COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c   
#OUTPUT_OPTION = -o $@         
%.o:%.c
	$(COMPILE.c) $< $(OUTPUT_OPTION) 
	    
clean:
	rm -rf  *.o src/*.o another_static_lib_src/*.o lib/*  *.exe src/*.exe lib/*.exe build/Debug/*

在这里插入图片描述
生成的结构
在这里插入图片描述

6-3.静态库和动态库相互依赖

6-3-1.静态库依赖动态库

仅仅修改一下上面的代码

invoke_plus.c

#include "plus.h"
#include "subtraction.h"

#include <stdio.h>

void invoke_plus_print()
{
	int result=plus(2,3);
	printf("print in invoke_plus : result = %d",result);
}

void invoke_sub_dll()
{
	printf("print in invoke_plus,invoke shared lib , result = %d\n",sub(8,1));
}

invoke_plus.h

#ifndef invoke_plush
#define invoke_plush
void invoke_plus_print();
void invoke_sub_dll();
#endif

main.c

#include "invoke_plus.h"


int main()
{
	invoke_sub_dll();
}
Makefile可以使用上面的,
结构也是一样的。

在这里插入图片描述

6-3-2.动态库依赖静态库

在上面的基础上修改一下代码
由于是动态库依赖静态库,需要将静态库的路径写到编译参数
gcc -fPIC -shared $? needed_static_lib -o $(lib_dest)$@

invoke_sub.c

#include "subtraction.h"
#include <stdio.h>
#include "plus.h"

void sub_method()
{
    printf("resulte = %d\n",sub(9,3));
}
//动态库中调用静态库的方法plus_method
void share_lib_invoke_static_lib()
{
    printf("in share lib invoke static lib , result = %d \n",plus_method(1,2));
}

invoke_sub.h

#ifndef invoke_sub
#define invoke_sub
void sub_method();
void share_lib_invoke_static_lib();
#endif

Makefile,需要在动态库编译的时候,添加静态库的依赖

.PHONY: all clean print

cc=gcc
CFLAGS=-I another_static_header -I static_lib_header -I share_lib_header -I shareLib_need_sharedLib_header


main_source=src/main.o

lib_source =static_lib_src/plus.o static_lib_src/invoke_plus.o
another_lib_source=another_static_lib_src/need_plus.o

shared_lib_source=share_lib_src/subtraction.o share_lib_src/invoke_sub.o
need_share_lib_source=shareLib_need_shareLib_src/need_share_lib.o        


static_arch_lib=libStaticArch.a
another_arch_lib=libAnother.a

shared_lib=libshared_lib.so
need_share_lib=libneed_share_lib.so                                      


main_dest=build/Debug/
lib_dest=lib/


all:$(static_arch_lib) $(another_arch_lib) $(shared_lib) $(need_share_lib) main.exe

$(static_arch_lib): $(lib_source)
	ar -rcs $(lib_dest)$@ $?
	rm -rf $?

$(another_arch_lib):$(another_lib_source)
	ar -rcs $(lib_dest)$@ $?
	rm -rf $?

	#由于这个动态库调用了另一个静态库,需要将静态库生成后的库路径添加进来 $(lib_dest)$(static_arch_lib)
$(shared_lib):$(shared_lib_source)
	gcc -fPIC -shared $? $(lib_dest)$(static_arch_lib) -o $(lib_dest)$@
	rm -rf $^
	
	
$(need_share_lib):$(need_share_lib_source)
	gcc -fPIC -shared $? $(lib_dest)$(shared_lib) -o $(lib_dest)$@
	rm -rf $^

main.exe:$(main_source)	$(static_arch_lib) $(another_arch_lib) $(shared_lib) $(need_share_lib)
	gcc $< $(addprefix $(lib_dest),$(filter-out $<,$?)) -o $(addprefix $(main_dest),$@)  
	cp lib/$(shared_lib)  build/Debug/$(shared_lib)
	cp lib/$(need_share_lib) build/Debug/
	rm -rf $<



#COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c   
#OUTPUT_OPTION = -o $@         
%.o:%.c
	$(COMPILE.c) $< $(OUTPUT_OPTION) 
	    
clean:
	rm -rf  *.o src/*.o another_static_lib_src/*.o lib/*  *.exe src/*.exe lib/*.exe build/Debug/*
目录结构没有改变

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值