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://www.hqwc.cn/news/491703.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

openssl3.2 - crypto-mdebug被弃用后, 内存泄漏检查的替代方法

文章目录 openssl3.2 - crypto-mdebug被弃用后, 内存泄漏检查的替代方法概述笔记查看特性列表openssl3.2编译脚本 - 加入enable-crypto-mdebug看看有没有替代内存诊断的方法?main.cppmy_openSSL_lib.hmy_openSSL_lib.c备注备注END openssl3.2 - crypto-mdebug被弃用后, 内存泄…

TransformerEncoder影评测试

import os import keras import tensorflow as tf from keras import layers import numpy as np#加载数据 def load_data(data_dir):"""data_dir&#xff1a;train的目录或test的目录输出&#xff1a;X&#xff1a;评论的字符串列表y&#xff1a;标签列表&…

再探二分法

推荐阅读 智能化校园&#xff1a;深入探讨云端管理系统设计与实现&#xff08;一&#xff09; 智能化校园&#xff1a;深入探讨云端管理系统设计与实现&#xff08;二&#xff09; 文章目录 推荐阅读二分查找题目思路解法左闭右闭式写法左闭右开式写法 二分查找 题目 给定一个…

【Flutter/Android】运行到安卓手机上一直卡在 Running Gradle task ‘assembleDebug‘... 的终极解决办法

方法步骤简要 查看你的Flutter项目需要什么版本的 Gradle 插件&#xff1a; 下载这个插件&#xff1a; 方法一&#xff1a;浏览器输入&#xff1a;https://services.gradle.org/distributions/gradle-7.6.3-all.zip 方法二&#xff1a;去Gradle官网找对应的版本&#xff1a;h…

编码后的字符串lua

-- 长字符串 local long_string "你好你好你好你好你好你好你好你好" local encoded_string "" for i 1, #long_string do local char_code string.byte (long_string, i) encoded_string encoded_string .. char_code .. "," end encoded_…

[RCTF2015]EasySQL1 题目分析与详解

一、题目介绍&#xff1a; 1、题目来源&#xff1a; BUUCTF网址 2、题目介绍&#xff1a; 拿到flag。 二、解题思路&#xff1a; 我们发现题目首页有登录和注册账号两个选项&#xff0c;我们首先尝试注册账号&#xff0c;尝试注册username为admin的账号&#xff0c;输入密码…

RTSP协议

参考 本人也是初学&#xff0c;主要是为了初步了解该协议&#xff0c;便于后续开发中使用。RTSP RTSP服务端源码 B站新手向 函数 strdup() 概念 RTSP RTSP协议以客户服务器方式工作&#xff0c;&#xff0c;如&#xff1a;暂停/继续、后退、前进等。它是一个多媒体播放控制…

nginx.conf配置文件详解、案例,Nginx常用命令与模块

目录 一、Nginx常用命令 二、Nginx涉及的文件 2.1、Nginx 的默认文件夹 2.2、Nginx的主配置文件nginx.conf nginx.conf 配置的模块 2.2.1、全局块&#xff1a;全局配置&#xff0c;对全局生效 2.2.2、events块&#xff1a;配置影响 Nginx 服务器与用户的网络连接 2.2.3…

【计算机网络】1.4 接入网和物理媒体

1.4 接入网和物理媒体 问题&#xff1a;怎样将端系统和边缘路由器连接&#xff1f; 答&#xff1a;有线方式&#xff08;住宅接入网络、单位接入网络等&#xff09;或无线方式&#xff08;无线接入网络&#xff09;。 有线接入方式 光纤同轴混合网是基于已有的有线电视网开发的…

YOLOv9尝鲜测试五分钟极简配置

pip安装python包&#xff1a; pip install yolov9pip在https://github.com/WongKinYiu/yolov9/tree/main中下载好权重文件yolov9-c.pt。 运行下面代码&#xff1a; import yolov9model yolov9.load("yolov9-c.pt", device"cpu") # load pretrained or c…

【机器人学导论笔记】三、操作臂正运动学

3.1 概述 操作臂正运动学研究操作臂的运动特性&#xff0c;主要涉及与运动有关的几何参数和时间参数。本章中&#xff0c;只研究静止状态下操作臂连杆的位置和姿态。 处理这些复杂的几何参数需要一些步骤&#xff1a;首先需要在操作臂的每个连杆上分别固接一个连杆坐标系&…

linux---安使用nginx

目录 一、编译安装Nginx 1、关闭防火墙&#xff0c;将安装nginx所需要软件包传到/opt目录下 ​编辑2、安装依赖包 3、创建运行用户、组 4、编译安装nginx 5、创建软链接后直接nginx启动 ​编辑 6、创建nginx自启动文件 ​编辑6.1 重新加载配置、设置开机自启并开启服务…