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.amain.o : main.cpp@g++ -c $^ -o $@ $(compile_flags)use_add : main.o@g++ $^ -o $@ $(linking_flags)all : static_lib use_addclean :@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.somain.o : main.cpp@g++ -c $^ -o $@ $(compile_flags)use_add : main.o @g++ $^ -o $@ $(linking_flags)all : dynamic_lib use_addclean :@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/%.cppg++ -c $^ -o $@ $(compile_flags)libstatic.a : $(lib_objs)ar -r $@ $^static_lib : libstatic.amain.o : main.cpp g++ -c $^ -o $@ $(compile_flags)test : main.o $(lib_objs)g++ $^ -o $@ all : static_lib testclean :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/%.cppg++ -c $^ -o $@ $(compile_flags)libstatic.a : $(lib_objs)ar -r $@ $^static_lib : libstatic.amain.o : main.cpp g++ -c $^ -o $@ $(compile_flags)test : main.og++ $^ -o $@ $(linking_flags)all : static_lib testclean :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/%.cppg++ -c $^ -o $@ $(compile_flags)libdynamic.so : $(lib_objs)g++ -shared $^ -o $@dynamic_lib : libdynamic.somain.o : main.cpp g++ -c $^ -o $@ $(compile_flags)test : main.o $(lib_objs)g++ $^ -o $@ all : dynamic_lib testclean :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/%.cppg++ -c $^ -o $@ $(compile_flags)libdynamic.so : $(lib_objs)g++ -shared $^ -o $@dynamic_lib : libdynamic.somain.o : main.cpp g++ -c $^ -o $@ $(compile_flags)test : main.o g++ $^ -o $@ $(linking_flags)all : dynamic_lib testclean :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 ./libsource/%.o : source/%.cppg++ -c $^ -o $@ $(compile_flags)libstatic.a : $(lib_objs) ar -r $@ $^ static_lib : libstatic.amain.o : main.cppg++ -c $^ -o $@ $(compile_flags) test : main.o g++ $^ -o $@ $(linking_flags)all : static_lib testclean :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/%.cppg++ -c $^ -o $@ $(compile_flags)libdynamic.so : $(lib_objs)g++ -shared $^ -o $@dynamic_lib : libdynamic.somain.o : main.cppg++ -c $^ -o $@ $(compile_flags) test : main.o g++ $^ -o $@ $(linking_flags)all : dynamic_lib testclean :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 ./libsource/%.o : source/%.cppg++ -c $^ -o $@ $(compile_flags)libdynamic.so : $(lib_objs)g++ -shared $^ -o $@dynamic_lib : libdynamic.somain.o : main.cppg++ -c $^ -o $@ $(compile_flags) test : main.o g++ $^ -o $@ $(linking_flags)all : dynamic_lib testclean :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 ./includesource/%.o : source/%.cppg++ -c $^ -o $@ $(compile_flags)ar -x lib/libadd.alibstatic.a : $(lib_objs) add.oar -r $@ $^ static_lib : libstatic.amain.o : main.cppg++ -c $^ -o $@ $(compile_flags) test : main.o libstatic.ag++ $^ -o $@ all : static_lib testclean :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/%.cppg++ -c $^ -o $@ $(compile_flags)ar -x lib/libadd.alibdynamic.so : $(lib_objs) add.og++ -shared $^ -o $@dynamic_lib : libdynamic.somain.o : main.cppg++ -c $^ -o $@ $(compile_flags) test : main.o g++ $^ -o $@ $(linking_flags)all : dynamic_lib testclean :rm -rf *.o source/*.o *.a *.so test

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

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

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

相关文章

GEE必须会教程—曾“几何”时(Geometry类型)

几何图形组成了世界万物&#xff0c;在数学史具有重要地位&#xff0c;将几何图形迁移到地理空间信息的处理上&#xff0c;我们我们得到就是研究区域的边界范围&#xff0c;因此&#xff0c;在学习矢量数据和栅格数据之前&#xff0c;我们有必要了解几何图形在GEE上的编辑。 1…

C语言——结构体——(第21篇)

坚持就是胜利 文章目录 一、结构体类型的声明1、结构的基础知识2、结构的声明3、结构成员的类型 二、结构体变量的定义和初始化结构体中包含结构体 三、结构体成员访问问题一&#xff1a;t.name "张三"&#xff0c;对吗&#xff1f;问题二&#xff1a;set_Stu(s);应…

C#与VisionPro联合开发——跳转页面

1、跳转页面并打开相机 From1 所有代码展示 using System; using System.IO; using System.Windows.Forms; //引入VisionPro命名空间 using Cognex.VisionPro;namespace ConnectCamera {public partial class Form1 : Form {public Form1() {InitializeComponent();}CogAcqFif…

Java核心-核心类与API(3)

话接上回&#xff0c;继续核心类与API的学习&#xff0c;这次介绍一下枚举类以及与系统、交互有关的类&#xff0c;需要了解并能使用即可。 一、枚举类 1、概述 枚举也称穷举&#xff0c;简单理解就是把所有可能一一列举出来&#xff08;穷尽所有可能&#xff09;。枚举是一…

前端学习——JS学习

文章目录 1. 定义变量&#xff0c;关键字 var、let、const2. 定义变量&#xff0c;数据类型3. 数组变量的操作4. 对象的操作5. JSON 字符串 1. 定义变量&#xff0c;关键字 var、let、const 这里主要是对var、let做比较 /** 1. var存在变量提升、let不存在变量提升 **/ cons…

【C语言基础】:操作符详解(一)

文章目录 操作符详解1. 操作符的分类2. 二进制和进制转换2.1 什么是二进制、八进制、十进制、十六进制2.1.1 二进制和进制转换2.1.2 二进制转十进制2.2.3 二进制转八进制2.2.4 二进制转十六进制 3. 源码、反码、补码4. 移位操作符4.1 左移操作符4.2 右移操作符 5. 位操作符&…

【域适应论文汇总】未完结

文章目录 DANN&#xff1a;Unsupervised Domain Adaptation by Backpropagation (2015)TADA&#xff1a;Transferable Attention for Domain Adaptation&#xff08;2019 AAAI&#xff09;1 局部注意力迁移&#xff1a;Transferable Local Attention2 全局注意力迁移&#xff1…

调度服务看门狗配置

查看当前服务器相关的sqlserver服务 在任务栏右键&#xff0c;选择点击启动任务管理器 依次点击&#xff0c;打开服务 找到sqlserver 相关的服务&#xff0c; 确认这些服务是启动状态 将相关服务在看门狗中进行配置 选择调度服务&#xff0c;双击打开 根据上面找的服务进行勾…

打开 Camera app 出图,前几帧图像偏暗、偏色该怎样去避免?

1、问题背景 使用的安卓平台&#xff0c;客户的应用是要尽可能快的获取到1帧图像效果正常的图片。 但当打开 camera 启动出流后&#xff0c;前3-5帧图像是偏暗、偏色的&#xff0c;如下图所示&#xff0c;是抓取出流的前25帧图像&#xff0c; 前3帧颜色是偏蓝的&#xff0c;…

vue2和vue3 setup beforecreate create生命周期时间比较

创建一个vue程序&#xff0c;vue3可以兼容Vue2的写法&#xff0c;很流畅完全没问题 写了一个vue3组件 <template><div></div> </template><script lang"ts"> import {onMounted} from vue export default{data(){return {}},beforeCr…

操作符详解3

✨✨ 欢迎大家来到莉莉的博文✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 前面我们已经讲过算术操作符、赋值操作符、逻辑操作符、条件操作符和部分的单目操作 符&#xff0c;今天继续介绍一部分。 目录 1.操作符的分类 2…

【软件测试面试】要你介绍项目-如何说?完美面试攻略...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、测试面试时&am…

QtRVSim F扩展实现(一):解码阶段

跟踪解码流程可以发现&#xff0c;解码主要是读取 instruction.cpp 里存储的指令集数组进行解码的。 那么对于实现 F 扩展指令集&#xff0c;第一步能成功读取识别新指令&#xff0c;就需要从这里入手。 解码部分代码&#xff1a; static inline const struct InstructionMa…

12. Springboot集成Dubbo3(三)Dubbo-Admin

目录 1、前言 2、安装 2.1、下载Dubbo-admin 2.2、修改配置 2.3、编译前端 2.4、访问 2.5、加载自己的服务 2.6、服务测试 2.7、其他 3、小结 1、前言 Dubbo Admin是用于管理Dubbo服务的基于Web的管理工具。Dubbo Admin提供了一个用户友好的界面&#xff0c;用于在分…

C/C++暴力/枚举/穷举题目持续更新(刷蓝桥杯基础题的进!)

目录 前言 一、百钱买百鸡 二、百元兑钞 三、门牌号码&#xff08;蓝桥杯真题&#xff09; 四、相乘&#xff08;蓝桥杯真题&#xff09; 五、卡片拼数字&#xff08;蓝桥杯真题&#xff09; 六、货物摆放&#xff08;蓝桥杯真题&#xff09; 七、最短路径&#xff08;蓝…

二蛋赠书十六期:《高效使用Redis:一书学透数据存储与高可用集群》

很多人都遇到过这么一道面试题&#xff1a;Redis是单线程还是多线程&#xff1f;这个问题既简单又复杂。说他简单是因为大多数人都知道Redis是单线程&#xff0c;说复杂是因为这个答案其实并不准确。 难道Redis不是单线程&#xff1f;我们启动一个Redis实例&#xff0c;验证一…

【Java程序设计】【C00262】基于Springboot的会员制医疗预约服务管理系统(有论文)

基于Springboot的会员制医疗预约服务管理系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的会员制医疗预约服务管理信息系统&#xff0c;本系统分为三种角色&#xff1a;管理员、医生和会员&#xff1b; 在系统…

Web3 基金会推出去中心化之声计划:投入高额 DOT 和 KSM ,助力去中心化治理

作者&#xff1a;Web3 Foundation Team 编译&#xff1a;OneBlock 原文&#xff1a;https://medium.com/web3foundation/decentralized-voices-program-93623c27ae43 Web3 基金会为 Polkadot 和 Kusama 创建了去中心化之声计划&#xff08;Decentralized Voices Program&…

【生活】浅浅记录

各位小伙伴们好鸭&#xff0c;今天不是技术文章&#xff0c;浅浅记录一下最近几个月的收获&#x1f60a; 新的一年&#xff0c;一起努力&#xff0c;加油加油&#xff01;

vue3(vite)+electron打包踩坑记录(1)

vue3(vite)electron打包踩坑记录 - 打包vue 第一步 编译vue 使用vite构建vue&#xff0c;package.json如下 {"name": "central-manager","private": true,"version": "0.0.0","type": "commonjs",&q…