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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot 项目集成camunda流程引擎

使用camunda开源工作流引擎有&#xff1a;通过docker运行、使用springboot集成、部署camunda发行包、基于源代码编译运行等多种方式。 其中&#xff0c;通过源代码编译运行的方式最为复杂&#xff0c;具体参考&#xff1a;https://lowcode.blog.csdn.net/article/details/1362…

个人博客系列-前端部署-创建框架(4)

项目环境介绍 Vue3 Vite TypeScript 服务器&#xff1a;阿里云contos node版本&#xff1a;v18.18.2 npm版本&#xff1a;v10.2.4 执行下面一行命令&#xff0c;创建vue3框架 npm create vuelatest修改端口&#xff1a;9528&#xff0c; 此步骤可以忽略&#xff08;使用默…

云呐矿井智能化运维工是什么?智能机器人运维岗位

煤矿智能运维是指利用先进的信息技术和自动控制&#xff0c;在煤矿生产过程中对煤矿设备进行监测、维护和管理。其职责和工作任务主要包括: 工作环境:  面对复杂的地质条件和极端的气候环境&#xff0c;煤矿智能运维工程师往往需要在地下煤矿、监测中心等环境中工作。因此&a…

MCU多核异构通信原理

摘要&#xff1a; 本文结合瑞萨RZ/G2L 多核处理器&#xff0c;给大家讲述一下多核异构设计及通信的原理。 随着电子技术的不断发展&#xff0c;以及市场需求的日益增长&#xff0c;嵌入式系统不仅要求执行复杂的控制任务&#xff0c;还需要实时地采集和处理数据。 为了满足这…

游戏配置内存“瘦身”策略

背景 游戏配置数据绝对是游戏服务器进程的内存大头,有些游戏服务器单纯数据配置的容量就超过一个G。因此,这部分内存优化也就放在首要位置了。 优化策略 在《服务器进程如何降低内存》一文中,我们讲述了可以通过“优化游戏配置缓存”来降低游戏服务器进程的内存使用量。本…

基于协同过滤算法的体育商品推荐系统

摘要 本文深入探讨了基于协同过滤算法的体育商品推荐系统的构建方法及其在电子商务中的重要性。首先&#xff0c;介绍了协同过滤算法的基本原理&#xff0c;包括用户-商品矩阵、相似度度量和推荐生成。其次&#xff0c;探讨了协同过滤算法在体育商品推荐中的两种主要应用方式&a…

sql-labs第46关(order by盲注脚本)

一、环境 网上有自己找 二、解释 order by 注入我们看他的true和false来进行注入出来 二、实操 让我们用sort 看看源码 最终我们的id是放到order by后面了 如果我们直接用列去排序 ?sortusername/password username&#xff1a; password&#xff1a; 可以看到顺序是不…

IO进程线程:通信

1.定义互斥锁 #include<myhead.h>int num520;//临界资源//1.创建一个互斥锁变量 pthread_mutex_t mutex;//定义任务&#xff11;函数 void *task1(void *arg) {printf("11111111111111\n");//3.获取锁资源pthread_mutex_lock(&mutex);num1314;sleep(3);pr…

数据结构与算法:红黑树讲解

关于红黑树&#xff0c; 这篇讲的更详细易懂。 https://www.cnblogs.com/jakelin/p/14324966.html 一颗平衡的二叉搜索树的任意节点平均查找效率为树的高度h&#xff0c;即O(lgn)。 但是如果二叉搜索树的失去平衡&#xff08;元素全在一侧&#xff09;&#xff0c;搜索效率就…

牛客周赛 Round 33 解题报告 | 珂学家 | 思维场

前言 整体评价 感觉这场更偏思维&#xff0c;F题毫无思路&#xff0c;但是可以模拟骗点分, E题是dij最短路. A. 小红的单词整理 类型: 签到 w1,w2 input().split() print (w2) print (w1)B. 小红煮汤圆 思路: 模拟 可以从拆包的角度去构建模拟 注意拆一包&#xff0c;可以…

如何增加层次厚度?

Q 老师&#xff0c;我在做一个斧头武器&#xff0c;如何在平面上增加厚度和层次呢&#xff1f; A 选中这几个线&#xff0c;点连接就会出现中线&#xff0c;把中线稍作调整即可~

Springboot+vue的社区医疗综合服务平台(有报告)。Javaee项目,springboot vue前后端分离项目

演示视频&#xff1a; Springbootvue的社区医疗综合服务平台&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot vue前后端分离项目 项目介绍&#xff1a; 本文设计了一个基于Springbootvue的前后端分离的社区医疗综合服务平台&#xff0c;采用M&#xff08;m…

数据分析这么卷吗!AI几分钟做完我半天的工作,这让人怎么办!

随着AI技术的飞速发展&#xff0c;人工智能领域正在经历一场前所未有的革命。无论是ChatGPT还是谷歌的巴德&#xff0c;以及国内诸如文心一言、ChatGLM等产品的涌现&#xff0c;都在不断地证明着这一点。这些技术不仅在推动着各行业的发展&#xff0c;更在不断地改变着我们的生…

Redis如何修改key名称

点击上方蓝字关注我 近期出现过多次修改Redis中key名字的场景&#xff0c;本次简介一下如何修改Redis中key名称的方法。 1. 命令行方式修改在Redis中&#xff0c;可以使用rename命令来修改Key的名称。这个命令的基本语法如下&#xff1a; RENAME old_key new_key 在这里&#…

详细分析Pandas中的Series对象(附Demo)

目录 1. 问题所示2. 基本知识3. API Demo4. 示例Demo5. 彩蛋 1. 问题所示 从实战上手基础知识 一开始遇到这个Bug&#xff1a; TypeError: unsupported operand type(s) for -: str and float后面经了解执行减法运算时发生了错误&#xff0c;其中一个操作数是字符串类型&…

继承(extends)

继承[extends] 继承的好处继承的示意图继承的使用细节JVM的内存&#xff1a;继承的内存布局 继承的好处 1&#xff09;提高代码的复用性 2&#xff09;代码的扩展性和维护性提高了 继承的示意图 继承的使用细节 1&#xff09;子类继承了所有属性和方法&#xff0c;非私有的…

liunx前后端分离项目部署

文章目录 1、nginx的安装和自启动2.nginx负载均衡3.前后端项目部署-后端部署4.前后端项目部署-前端部署 1、nginx的安装和自启动 yum -y install gcc zlib zlib-devel pcre-devel openssl openssl-devel1.安装我们nginx所需要的依赖 wget http://nginx.org/download/nginx-1.…

线程池的常用实现及执行流程

线程池 线程池线程池接口线程池参数线程池分类动态数目线程池固定数目线程池单例线程池任务调度线程池 线程池的执行流程 线程池 线程池接口 线程池参数 1、corePoolSize&#xff1a;核心线程数&#xff0c;线程池中最少线程&#xff0c;核心线程不会被回收。 2、maximumPoo…

做接口测试的流程一般是怎么样的?UI功能6大流程、接口测试8大流程这些你真的全会了吗?

在讲接口流程测试之前&#xff0c;首先需要给大家申明下&#xff1a;接口测试对于测试人员而言&#xff0c;非常非常重要&#xff0c;懂功能测试接口测试&#xff0c;就能在企业中拿到一份非常不错的薪资。 这么重要的接口测试&#xff0c;一般也是面试笔试必问。为方便大家更…

自定义搭建管理系统

最近使用自己搭建的脚手架写了一个简易管理系统&#xff0c;使用webpackreactantd&#xff0c;搭建脚手架参考&#xff1a; 使用Webpack5搭建项目&#xff08;react篇&#xff09;_babel-preset-react-app-CSDN博客 搭建的思路&#xff1a; 1. 基建布局&#xff0c;使用antd的…