Makefile静态库动态库的构建和链接之工程实用篇

静态库和动态库的构建和链接

现有C++工程目录结构如下:
在这里插入图片描述
add.h

int add(int a, int b);

add.cpp

#include "add.h"

int add(int a, int b)
{
    return a+b;
}

main.cpp

#include <iostream>
#include "add.h"

int main()
{
	std::cout << add(1, 2) << std::endl;
	return 0;
}

静态库的构建和链接

一个可以构建静态库的Makefile:

compile_flags := -g -O3 -std=c++11 -I ./
linking_flags := -l add -L ./

add.o : add.cpp
	@g++ -c $^ -o $@ $(compile_flags)

libadd.a : add.o
	@ar -r $@ $^

static_lib : libadd.a

main.o : main.cpp
	@g++ -c $^ -o $@ $(compile_flags)

use_add : main.o
	@g++ $^ -o $@ $(linking_flags)

all : static_lib use_add

clean :
	@rm -rf *.o *.a *.so use_add

执行make all命令即可在当前目录下生成静态库libadd.a和可执行文件use_add。
通过ldd use_add命令查看可执行程序依赖的动态链接库,打印如下:

linux-vdso.so.1 (0x00007ffdf311f000)
libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fcf0fce3000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fcf0faf1000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fcf0f9a2000)
/lib64/ld-linux-x86-64.so.2 (0x00007fcf0feff000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fcf0f987000)

动态库的构建和链接

一个可以构建动态库的Makefile:

compile_flags := -g -O3 -w -fPIC -I ./
linking_flags := -l add -L ./ -Wl,-rpath=./

add.o : add.cpp
	@g++ -c $^ -o $@ $(compile_flags)

libadd.so : add.o
	@g++ -shared $^ -o $@

dynamic_lib : libadd.so

main.o : main.cpp
	@g++ -c $^ -o $@ $(compile_flags)

use_add : main.o 
	@g++ $^ -o $@ $(linking_flags)

all : dynamic_lib use_add

clean :
	@rm -rf *.o *.a *.so use_add

执行make all命令即可在当前目录下生成静态库libadd.so和可执行文件use_add。
通过ldd use_add命令查看可执行程序依赖的动态链接库,打印如下:

linux-vdso.so.1 (0x00007ffd9dbc7000)
libadd.so => ./libadd.so (0x00007fc2e382d000)
libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fc2e3618000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc2e3426000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fc2e32d7000)
/lib64/ld-linux-x86-64.so.2 (0x00007fc2e3839000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fc2e32bc000)

发现比链接静态库时多了一个libadd.so依赖库。

工程实践

包含子目录的工程

现有C++工程目录结构如下:
在这里插入图片描述
add.h和add.cpp同上。
subtract.h

int subtract(int a, int b);

subtract.cpp

#include "subtract.h"

int subtract(int a, int b)
{
    return a-b;
}

main.cpp

#include <iostream>
#include "add.h"
#include "subtract.h"

int main()
{
	std::cout << add(1, 2) << std::endl;
	std::cout << subtract(1, 2) << std::endl;
	return 0;
}

静态库的构建和链接

一个可以构建静态库的Makefile:(通过源文件构建可执行文件)

lib_srcs := $(shell find ./source -name "*.cpp")
lib_objs := $(lib_srcs:.cpp=.o)

compile_flags := -g -O3 -std=c++11 -I ./include
linking_flags := -l static -L ./

source/%.o : source/%.cpp
	g++ -c $^ -o $@ $(compile_flags)

libstatic.a : $(lib_objs)
	ar -r $@ $^

static_lib : libstatic.a

main.o : main.cpp 
	g++ -c $^ -o $@ $(compile_flags)

test : main.o $(lib_objs)
	g++ $^ -o $@ 

all : static_lib test

clean :
	rm -rf *.o source/*.o *.a *.so test

或者(通过链接静态库构建可执行文件)

lib_srcs := $(shell find ./source -name "*.cpp")
lib_objs := $(lib_srcs:.cpp=.o)

compile_flags := -g -O3 -std=c++11 -I ./include
linking_flags := -l static -L ./

source/%.o : source/%.cpp
	g++ -c $^ -o $@ $(compile_flags)

libstatic.a : $(lib_objs)
	ar -r $@ $^

static_lib : libstatic.a

main.o : main.cpp 
	g++ -c $^ -o $@ $(compile_flags)

test : main.o
	g++ $^ -o $@ $(linking_flags)

all : static_lib test

clean :
	rm -rf *.o source/*.o *.a *.so test

动态库的构建和链接

一个可以构建动态库的Makefile:(通过源文件构建可执行文件)

lib_srcs := $(shell find ./source -name "*.cpp")
lib_objs := $(lib_srcs:.cpp=.o)

compile_flags := -g -O3 -w -fPIC  -I ./include
linking_flags := -l dynamic -L ./ -Wl,-rpath=./

source/%.o : source/%.cpp
	g++ -c $^ -o $@ $(compile_flags)

libdynamic.so : $(lib_objs)
	g++ -shared $^ -o $@

dynamic_lib : libdynamic.so

main.o : main.cpp 
	g++ -c $^ -o $@ $(compile_flags)

test : main.o $(lib_objs)
	g++ $^ -o $@ 

all : dynamic_lib test

clean :
	rm -rf *.o source/*.o *.a *.so test

或者(通过链接静态库构建可执行文件)

lib_srcs := $(shell find ./source -name "*.cpp")
lib_objs := $(lib_srcs:.cpp=.o)

compile_flags := -g -O3 -w -fPIC  -I ./include
linking_flags := -l dynamic -L ./ -Wl,-rpath=./

source/%.o : source/%.cpp
	g++ -c $^ -o $@ $(compile_flags)

libdynamic.so : $(lib_objs)
	g++ -shared $^ -o $@

dynamic_lib : libdynamic.so

main.o : main.cpp 
	g++ -c $^ -o $@ $(compile_flags)

test : main.o 
	g++ $^ -o $@ $(linking_flags)

all : dynamic_lib test

clean :
	rm -rf *.o source/*.o *.a *.so test

既构建库又链接库的工程

现有C++工程目录结构如下:
在这里插入图片描述
其中libadd.a和libadd.so可以通过上面的方法生成。

  1. 构建静态库(libstatic.a)并链接静态库(libadd.a):
    Makefile会优先链接动态库,因此可以移除libadd.so来确保链接到libadd.a。
lib_srcs := $(shell find ./source -name "*.cpp")
lib_objs := $(lib_srcs:.cpp=.o)

compile_flags := -g -O3 -std=c++11 -I ./include
linking_flags := -l static -L ./ -l add -L ./lib

source/%.o : source/%.cpp
	g++ -c $^ -o $@ $(compile_flags)

libstatic.a : $(lib_objs) 
	ar -r $@ $^ 

static_lib : libstatic.a

main.o : main.cpp
	g++ -c $^ -o $@ $(compile_flags) 

test : main.o 
	g++ $^ -o $@ $(linking_flags)

all : static_lib test

clean :
	rm -rf *.o source/*.o *.a *.so test
  1. 构建动态库(libdynamic.so)并链接静态库(libadd.a):
lib_srcs := $(shell find ./source -name "*.cpp")
lib_objs := $(lib_srcs:.cpp=.o)

compile_flags := -g -O3 -w -fPIC  -I ./include
linking_flags := -l add -L lib -l dynamic -L ./ -Wl,-rpath=./

source/%.o : source/%.cpp
	g++ -c $^ -o $@ $(compile_flags)

libdynamic.so : $(lib_objs)
	g++ -shared $^ -o $@

dynamic_lib : libdynamic.so

main.o : main.cpp
	g++ -c $^ -o $@ $(compile_flags) 

test : main.o 
	g++ $^ -o $@ $(linking_flags)

all : dynamic_lib test

clean :
	rm -rf *.o source/*.o *.a *.so test
  1. 构建静态库(libstatic.a)并链接动态库(libadd.so):
    Makefile写法同1。
  2. 构建动态库(libdynamic.so)并链接动态库(libadd.so):
lib_srcs := $(shell find ./source -name "*.cpp")
lib_objs := $(lib_srcs:.cpp=.o)

compile_flags := -g -O3 -std=c++11 -I ./include
linking_flags := -l dynamic -L ./ -l add -L ./lib

source/%.o : source/%.cpp
	g++ -c $^ -o $@ $(compile_flags)

libdynamic.so : $(lib_objs)
	g++ -shared $^ -o $@

dynamic_lib : libdynamic.so

main.o : main.cpp
	g++ -c $^ -o $@ $(compile_flags) 

test : main.o 
	g++ $^ -o $@ $(linking_flags)

all : dynamic_lib test

clean :
	rm -rf *.o source/*.o *.a *.so test

通过ldd命令查看依赖库,可以看到除了系统库外还需依赖libdynamic.so和libadd.so:

linux-vdso.so.1 (0x00007fff42cc6000)
libdynamic.so => ./libdynamic.so (0x00007f7d8b239000)
libadd.so => ./libadd.so (0x00007f7d8b234000)
libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f7d8b01f000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f7d8ae2d000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f7d8acde000)
/lib64/ld-linux-x86-64.so.2 (0x00007f7d8b245000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f7d8acc3000)
  1. 把静态库libadd.a以及source合为另一个大的静态库:
    先通过ar -x 命令将libadd.a解压为add.o,目前LZ尚未发现其他便捷做法。
lib_srcs := $(shell find ./source -name "*.cpp")
lib_objs := $(lib_srcs:.cpp=.o)

compile_flags := -g -O3 -std=c++11 -I ./include

source/%.o : source/%.cpp
	g++ -c $^ -o $@ $(compile_flags)
	ar -x lib/libadd.a

libstatic.a : $(lib_objs) add.o
	ar -r $@ $^ 

static_lib : libstatic.a

main.o : main.cpp
	g++ -c $^ -o $@ $(compile_flags) 

test : main.o libstatic.a
	g++ $^ -o $@ 

all : static_lib test

clean :
	rm -rf *.o source/*.o *.a *.so test
  1. 把静态库libadd.a以及source合为另一个大的动态库:
    先通过ar -x 命令将libadd.a解压为add.o,目前LZ尚未发现其他便捷做法。
lib_srcs := $(shell find ./source -name "*.cpp")
lib_objs := $(lib_srcs:.cpp=.o)

compile_flags := -g -O3 -w -fPIC  -I ./include
linking_flags := -l dynamic -L ./ -Wl,-rpath=./

source/%.o : source/%.cpp
	g++ -c $^ -o $@ $(compile_flags)
	ar -x lib/libadd.a

libdynamic.so : $(lib_objs) add.o
	g++ -shared $^ -o $@

dynamic_lib : libdynamic.so

main.o : main.cpp
	g++ -c $^ -o $@ $(compile_flags) 

test : main.o 
	g++ $^ -o $@ $(linking_flags)

all : dynamic_lib test

clean :
	rm -rf *.o source/*.o *.a *.so test

另外,linux系统下无法将动态库合入动态库或者静态库当中。
欢迎阅读LZ的其他博文:CMake静态库动态库的构建和链接之工程实用篇

  • 16
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

给算法爸爸上香

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值