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

news2025/4/4 10:21:03

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

现有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静态库动态库的构建和链接之工程实用篇

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1470180.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构-二分搜索树(Binary Search Tree)

一,简单了解二分搜索树 树结构: 问题:为什么要创造这种数据结构 1,树结构本身是一种天然的组织结构,就好像我们的文件夹一样,一层一层的. 2,树结构可以更高效的处理问题 二,二分搜索树的基础 1、二叉树 2,二叉树的重要特性 满二叉树 总结: 1. 叶子结点出现在二叉树的最…

Python习题详解

练习&#xff1a; 1&#xff0c;计算100以内奇数的和 #计算100以内所有奇数的和 sum 0 # n 1 # while n < 100: # # sum sum n # sum n # # n n 2 # n 2 # print(sum) n 99 #求偶数时n 100 while n > 0:sum n# n n - 2n - 2 print(sum)2&#xff0c;打印直…

【多线程】多线程案例——单例模式详解(包含懒汉模式,饿汉模式)

单例模式 &#x1f334;饿汉模式&#x1f38d;懒汉模式&#x1f338;单线程版&#xff08;线程不安全&#xff09;&#x1f338;多线程版&#x1f338;多线程版(改进) ⭕总结 单例模式是校招中最常考的 设计模式之⼀. 啥是设计模式? 设计模式好⽐象棋中的 “棋谱”. 红⽅当头…

AtCoder ABC342 A-D题解

华为出的比赛&#xff1f; 好像是全站首个题解哎&#xff01; 比赛链接:ABC342 Problem A: 稍微有点含金量的签到题。 #include <bits/stdc.h> using namespace std; int main(){string S;cin>>S;for(int i0;i<s.size();i){if(count(S.begin(),S.end(),S[i…

多维时序 | Matlab实现基于VMD-DBO-GRU、VMD-GRU、GRU的多变量时间序列预测

多维时序 | Matlab实现基于VMD-DBO-GRU、VMD-GRU、GRU的多变量时间序列预测 目录 多维时序 | Matlab实现基于VMD-DBO-GRU、VMD-GRU、GRU的多变量时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 Matlab实现基于VMD-DBO-GRU、VMD-GRU、GRU的多变量时间序列预测…

书生·浦语大模型实战营第六节课作业

基础作业 python run.py --datasets ceval_gen --hf-path /root/model/Shanghai_AI_Laboratory/internlm2-chat-7b/ --tokenizer-path /root/model/Shanghai_AI_Laboratory/internlm2-chat-7b/ --tokenizer-kwargs padding_sideleft truncationleft trust_remote_codeTrue --m…

嵌入式软件分层设计的思想分析

“嵌入式开发&#xff0c;点灯一路发” 那今天我们就以控制LED闪烁为例&#xff0c;来聊聊嵌入式软件分层: ——————————— | | | P1.1 |-----I<|--------------<| | | | P2.1 |-------------/ ---------…

Seata分布式事务实战AT模式

目录 分布式事务简介 典型的分布式事务应用场景 两阶段提交协议(2PC) 2PC存在的问题 什么是Seata&#xff1f; Seata的三大角色 Seata AT模式的设计思路 一阶段 二阶段 Seata快速开始 Seata Server&#xff08;TC&#xff09;环境搭建 db存储模式Nacos(注册&配…

HTB-Bizness

一、信息收集 访问ip自动跳转域名&#xff0c;host绑定域名后访问 目录爆破 有一个登录目录&#xff0c;访问发现是apahce ofbiz登录页面 发现存在漏洞 二、漏洞利用 在github上找到了图形化利用工具 使用工具反弹shell 得到flag 三、权限提升 从本地利用python开启http服务…

远程连接服务器及可视化方法(Win和Linux)

1.win端 1、通过SSH连接至服务器 在window下&#xff0c;打开命令行提示符&#xff08;快捷键winr后输入cmd回车&#xff09; 在命令行中输入 ssh 服务器上的用户名192.168.50.204回车并输入服务器上的用户登录密码 至此&#xff0c;已成功通过SSH连接至服务器。 2、通过…

复旦大学EMBA联合澎湃科技:共议科技迭代 创新破局

1月18日&#xff0c;由复旦大学管理学院、澎湃新闻、厦门市科学技术局联合主办&#xff0c;复旦大学EMBA项目、澎湃科技承办的“君子知道”复旦大学EMBA前沿论坛在厦门成功举办。此次论坛主题为“科技迭代 创新破局”&#xff0c;上海、厦门两地的政策研究专家、科学家、科创企…

集合的并发修改异常问题

使用迭代器遍历集合时&#xff0c;同时在删除集合中的数据&#xff0c;程序就会出现并发修改异常的错误。 import java.util.ArrayList; import java.util.Iterator; import java.util.List;public class _Exception {public static void main(String[] args) {List<String…

【GAD】DOMINANT个人解读/学习

SDM2019&#xff0c;这是一篇图异常检测领域的经典方法. 问题定义 在本文中&#xff0c;我们使用手写体来表示集合&#xff08;例如&#xff0c; V \mathcal{V} V&#xff09;&#xff0c;粗体小写字母&#xff08;例如&#xff0c; x \mathbf{x} x&#xff09;来表示向量&…

优化测试稳定性的失败重试工具:pytest-rerunfailures详解!

一.前言 笔者在执行自动化测试用例时&#xff0c;会发现有时候用例失败并非代码问题&#xff0c;而是由于服务正在发版&#xff0c;导致请求失败&#xff0c;从而降低了自动化用例的稳定性&#xff0c;最后还要花时间定位到底是自身case的原因还是业务逻辑问题&#xff0c;还是…

安全测试:史上最全的攻防渗透信息收集方法、工具!

信息收集的意义 信息收集对于渗透测试前期来说是非常重要的。正所谓&#xff0c;知己知彼百战不殆&#xff0c;信息收集是渗透测试成功的保障&#xff0c;只有我们掌握了目标网站或目标主机足够多的信息之后&#xff0c;才能更好地进行渗透测试。 信息收集的方式可以分为两种…

如何利用EXCEL批量插入图片

目录 1.excel打开目标表格&#xff1b; 2.点开视图-宏-录制宏&#xff0c;可以改宏的名字或者选择默认&#xff1b; 3.然后点开视图-宏-查看宏 4.点编辑进去 5.修改代码&#xff1a; &#xff08;1&#xff09;打开之后会显示有一堆代码 &#xff08;2&#xff09;将这个…

git之分支管理

一.理解分支 我们看下面这张图片&#xff1a; 在版本回退⾥&#xff0c;你已经知道&#xff0c;每次提交&#xff0c;Git都把它们串成⼀条时间线&#xff0c;这条时间线就可以理解为是⼀个分⽀。截⽌到⽬前&#xff0c;只有⼀条时间线&#xff0c;在Git⾥&#xff0c;这个分⽀…

SpringBootRest服务调用

目录 RestTemplate 依赖配置 自定义RestTemplate webCilent 依赖配置 自定义webCilent springboot中有两种方式实现Rest远程服务调用&#xff0c;分别是RestTemplate与webCilent。下面分别介绍一下这两种方式。 RestTemplate 依赖配置 RestTemplate是Spring Framework提供的…

使用GPT生成python图表

首先&#xff0c;生成一脚本&#xff0c;读取到所需的excel表格 import xlrddata xlrd.open_workbook(xxxx.xls) # 打开xls文件 table data.sheet_by_index(0) # 通过索引获取表格# 初始化奖项字典 awards_dict {"一等奖": 0,"二等奖": 0,"三等…

从Unity到Three.js(outline 模型描边功能)

指定模型高亮功能&#xff0c;附带设置背景颜色&#xff0c;获取随机数方法。 百度查看说是gltf格式的模型可以携带PBR材质信息&#xff0c;如果可以这样&#xff0c;那就完全可以在blender中配置好材质导出了&#xff0c;也就不需要像在unity中调整参数了。 import * as THRE…