问题1:将静态库编译成动态库

2023-11-11

一、描述

(1) 多个同事间合作开发一个软件项目,每个人负责一部分模块开发,商定好彼此的对外接口,编程实现后,最后需要将所有人的开发代码编译链接到一起,生成一个最终目标文件;
(2)由于多人开发,若全部采用源文件编译,编译时文件数量众多,编写Makefile复杂难维护;
(3)由于多人开发,存在同名文件冲突的问题;


二、解决方案

(1)为了解决编译时,源文件众多,Makefile文件复杂的问题,每个开发人员负责自己源代码编译,独立生成一个静态库文件(libxxx.a);
(2)为了解决多人开发的源文件同名问题,每个开发人员负责自己的源文件编译,独立生成一个静态库文件(libxxx.a);
(3)一个软件项目产品交付是共享库(libxxx.so)时,将各个开发人员编译生成的静态库链接生成动态库即可;


三、注意事项

(1)由于交付的共享库,则各个开发人员编译静态库时,添加位置无关的编译选项(-fPIC);

# compile options
CFLAGS = -std=c++11 
CFLAGS += -fPIC

(2)将静态库文件当作普通的编译生成目标文件(xxx.o),直接链接静态库文件生成动态库文集,由于链接器识别问题,静态库中有部分文件有可能不会编译到动态库中,造成编译生成的动态库不可用;
(3)为了解决链接器识别问题,链接静态库文件时,添加查找静态库文件包含目标文件选项(–whole-archive),链接找到静态库包含的所有目标文件,将其链接生成动态库文件;通过这种方式生成的动态库文件完整得到保证;

# 选项说明
`--whole-archive`

For each archive mentioned on the command line after the `--whole-archive` option, include every object file in the archive in the link, rather than searching the archive for the required object files. This is normally used to turn an archive file into a shared library, forcing every object to be included in the resulting shared library. This option may be used more than once.

`--no-whole-archive`

Turn off the effect of the `--whole-archive` option for subsequent archive files.

# 参考资料
[Using LD, the GNU linker](https://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_mono/ld.html)

# 示例
$(GXX) $(CFLAGS) $(PFLAGS)  -Wl,--whole-archive $(STATIC_LIBS) -Wl,--no-whole-archive -o $(SHARE_LIBRARY)

(4)链接生成动态库,需要添加共享选项(-shared);


四、示例

(1) 开发一个小型工具库,其中包含日志库、进程管理库、程序运行时间统计库;

# 目录结构
# src目录下存放源代码,test目录下存放测试代码
.
├── bin
├── build.sh
├── libs
├── src
│   ├── log
│   │   ├── liblog.a
│   │   ├── Makefile
│   │   ├── messages.cpp
│   │   ├── messages.h
│   │   └── messages.o
│   ├── Makefile
│   ├── process
│   │   ├── libprocess.a
│   │   ├── Makefile
│   │   ├── process_manage.cpp
│   │   ├── process_manage.h
│   │   └── process_manage.o
│   └── run_time
│       ├── librun_time.a
│       ├── Makefile
│       ├── run_time.cpp
│       ├── run_time.h
│       └── run_time.o
└── test
    ├── environment.sh
    ├── main.cpp
    ├── main.o
    ├── Makefile
    └── test_exec

(2) log库Makefile文件(src/log/Makefile)

# header file directroy
INC_DIR = .
INCS = $(patsubst %, -I%, $(INC_DIR))

# source file directory
SRC_DIR = .
SRCS = $(foreach dir, $(SRC_DIR), $(wildcard $(dir)/*.cpp))

# object files
OBJS = $(patsubst %.cpp, %.o, $(SRCS))

# compile tool
GXX = g++

# compile options
CFLAGS = -std=c++11 
CFLAGS += -fPIC

WFLAGS =  -Wall -Wshadow -Wunused-value -Wextra -Waddress
WFLAGS += -Wno-implicit-fallthrough -Werror=return-type

# compile target
TARGET = liblog.a

# --------------------------------------------------------
# compile rules
# default compile target
default: all

$(OBJS) : %.o : %.cpp
	$(GXX) $(CFLAGS) $(WFLAGS) $(INCS) -c $< -o $@


all: $(TARGET)

$(TARGET) : $(OBJS)
	ar rcs $(TARGET) $(OBJS)
	ranlib $(TARGET)
	mkdir -p ../../bin/self_utility/include/log
	cp *.h ../../bin/self_utility/include/log

# delete compile objects
.PHONY: clean
clean:
	rm -rf $(TARGET) $(OBJS)
	rm -rf ../../bin/self_utility/include/log

(3) 进程管理库Makefile文件(src/process/Makefile)

# header file directroy
INC_DIR = . ../log
INCS = $(patsubst %, -I%, $(INC_DIR))

# source file directory
SRC_DIR = .
SRCS = $(foreach dir, $(SRC_DIR), $(wildcard $(dir)/*.cpp))

# object files
OBJS = $(patsubst %.cpp, %.o, $(SRCS))

# compile tool
GXX = g++

# compile options
CFLAGS = -std=c++11 
CFLAGS += -fPIC

WFLAGS =  -Wall -Wshadow -Wunused-value -Wextra -Waddress
WFLAGS += -Wno-implicit-fallthrough -Werror=return-type

# compile target
TARGET = libprocess.a

# --------------------------------------------------------
# compile rules
# default compile target
default: all

$(OBJS) : %.o : %.cpp
	$(GXX) $(CFLAGS) $(WFLAGS) $(INCS) -c $< -o $@


all: $(TARGET)

$(TARGET) : $(OBJS)
	ar rcs $(TARGET) $(OBJS)
	ranlib $(TARGET)
	mkdir -p ../../bin/self_utility/include/process
	cp *.h ../../bin/self_utility/include/process

# delete compile objects
.PHONY: clean
clean:
	rm -rf $(TARGET) $(OBJS)
	rm -rf ../../bin/self_utility/include/process

(3) 程序运行时间统计库Makefile(src/run_time/Makefile)

# header file directroy
INC_DIR = .
INCS = $(patsubst %, -I%, $(INC_DIR))

# source file directory
SRC_DIR = .
SRCS = $(foreach dir, $(SRC_DIR), $(wildcard $(dir)/*.cpp))

# object files
OBJS = $(patsubst %.cpp, %.o, $(SRCS))

# compile tool
GXX = g++

# compile options
CFLAGS = -std=c++11 
CFLAGS += -fPIC

WFLAGS =  -Wall -Wshadow -Wunused-value -Wextra -Waddress
WFLAGS += -Wno-implicit-fallthrough -Werror=return-type

# compile target
TARGET = librun_time.a

# --------------------------------------------------------
# compile rules
# default compile target
default: all

$(OBJS) : %.o : %.cpp
	$(GXX) $(CFLAGS) $(WFLAGS) $(INCS) -c $< -o $@


all: $(TARGET)

$(TARGET) : $(OBJS)
	ar rcs $(TARGET) $(OBJS)
	ranlib $(TARGET)
	mkdir -p ../../bin/self_utility/include/run_time
	cp *.h ../../bin/self_utility/include/run_time

# delete compile objects
.PHONY: clean
clean:
	rm -rf $(TARGET) $(OBJS)
	rm -rf ../../bin/self_utility/include/run_time

(4) 链接静态库生成动态库Makefile(src/Makefile)

# compile file directory
SUB_DIR = log process run_time

# object files
OBJS = $(foreach dir, $(SUB_DIR), $(wildcard $(dir)/*.a))

# compile tool
GXX = g++

# compile options
CFLAGS = -std=c++11 
CFLAGS += -fPIC -shared

WFLAGS =  -Wall -Wshadow -Wunused-value -Wextra -Waddress
WFLAGS += -Wno-implicit-fallthrough -Werror=return-type

# compile target
TARGET = ../bin/self_utility/libself_utility.so

# --------------------------------------------------------
# compile rules
# default compile target
default: all

lib: 
	@for dir in $(SUB_DIR); do \
	 $(MAKE) -C $$dir -j32;      \
	done

all: $(TARGET)

$(TARGET) : lib
	mkdir -p ../bin/self_utility
	$(GXX) $(CFLAGS) $(WFLAGS) -Wl,--whole-archive \
	$(OBJS) -Wl,--no-whole-archive -o $(TARGET)
	

# delete compile objects
.PHONY: clean
clean:
	rm -rf ../bin/self_utility
	@for dir in $(SUB_DIR); do \
	 $(MAKE) -C $$dir clean; \
	done
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

问题1:将静态库编译成动态库 的相关文章

随机推荐

  • 几种网络通信协议

    应用层 HTTP Hypertext Transfer Protocol 超文本传输协议 显示网页 DNS Domain Name System 域名系统 FTP File Transfer Protocol 文件传出协议 SFTP SSH
  • BAPI_GOODSMVT_CREATE物料凭证创建…

    BAPI GOODSMVT CREATE可以实现物料凭证创建和部分冲销 全部冲销可以使用BAPI GOODSMVT CANCEL CALL FUNCTION BAPI GOODSMVT CREATE EXPORTING GOODSMVT H
  • Caffe中Solver解析

    1 Solver的初始化 shared ptr
  • QT中默认不选中Shadow build设置方法

    在使用qt开发的时候 每次创建工程 都会默认选中shadow build影子构建 作用是把编译生成的文件与源文件放在不同的目录 这样源码目录就相对整洁 但是这也会带来个问题 感觉超级鸡肋 就是经常修改了代码之后点运行 跑的还是修改之前的程序
  • 使用VMware Workstation Player虚拟机安装Linux系统

    下载安装 VMware Workstation Player 首先下载并安装 VMware Workstation Player VMware Workstation是一款非常强大的虚拟机软件 有pro专业版和player免费版 我们个人使
  • Java线程协作的两种方式

    介绍 Java中线程协作的最常见的两种方式 利用Object wait Object notify 和使用Condition 方法一 Object中的wait notify notifyAll方法定义如下 public final nati
  • 基于域名的恶意网站检测

    基于域名的恶意网站检测 0x00 数据来源 0x01 基于网页内容的判别方法 0x02 基于域名数据的判别方法 0x03 参考文献 0x00 数据来源 根据老师给的 300w 域名列表爬到的相应 DNS 响应数据 0x01 基于网页内容的判
  • 【翻译】 2.6 中的 4K 堆栈 [发布于 2004 年 5 月 12 日,作者:corbet

    传统上 Linux 内核在大多数架构上都使用 8KB 内核堆栈 该堆栈必须满足系统调用可能产生的任何调用序列 以及可能同时调用的任何 硬或软 中断处理程序的需要 实际上 在稳定的内核中 堆栈溢出的情况几乎闻所未闻 内核开发人员早已学会避免使
  • 【Docker教程(一)】WSL2、Docker以及docker-compose安装及环境配置

    一 如何安装WSL2 二 如何安装和配置docker 三 如何安装docker compose 四 如何基于ip代理池获取代理ip 注意 先安装WSL2 再安装docker和docker compose 参考资料 软件下载及安装教程 a d
  • JavaScript循环语句和分支语句

    JavaScript中的分支语句 1 if分支语句 2 if else语句 3 if else if else语句 4 switch语句 注 if语句可以单独存在 else语句不能单独存在 else找离自己最近的同一级别的if搭配成对 在i
  • linux创建711文件,linux权限---【600,644,700,755,711,666,777】,644711

    linux权限 600 644 700 755 711 666 777 644711 chmod命令详解 使用权限 所有使用者 使用方式 chmod cfvR help version mode file 说明 Linux Unix 的档案
  • 用streamlit,几行代码就可以拥有漂亮图表!

    大家注意 因为微信最近又改了推送机制 经常有小伙伴说错过了之前被删的文章 比如前阵子冒着风险写的爬虫 再比如一些限时福利 错过了就是错过了 所以建议大家加个星标 就能第一时间收到推送 大家好 我是爱搞事情的了不起 之前我们爬过懂车帝的车型评
  • c语言报告 列主元lu分解,求助:求个R语言的选主元LU分解。

    推荐答案 上善若水666 来自团队 乐于助人2018 04 21 采纳率 57 等级 50 已帮助 96万人 可以 这是数值分析书上的定理 就是存在排列矩阵P 对换矩阵的乘积 使得PA LU 这个定理说明先对A进行对换矩阵的行得到PA 然后
  • 【面试题】1、总结面试题1

    1 Java语言有哪些特点 1 面向对象 Java是一种面向对象的语言 支持封装 继承和多态等面向对象的特性 Java特别强调类和对象的关系 要求所有代码都必须位于类中 和Java一样很流行的Python也是面向对象的语言 但它对面向对象的
  • PVE虚拟化平台之安装Ubuntu Desktop系统

    PVE虚拟化平台之安装Ubuntu Desktop系统 一 Ubuntu介绍 1 1 Ubuntu简介 1 2 Ubuntu版本 1 3 ubuntu命名规则 二 上传镜像到PVE 2 1 检查PVE环境 2 2 上传镜像到PVE 三 新建
  • ARM软件测试库STL( Software Test libraries )介绍

    原文链接 https www arm com zh TW products development tools embedded and software software test libraries Faster Safety Comp
  • XXL-JOB 分布式定时任务调度平台

    文章目录 1 概述 2 使用 1 概述 首先我们要知道什么是XXL JOB 官方简介 XXL JOB是一个分布式任务调度平台 其核心设计目标是开发迅速 学习简单 轻量级 易扩展 现已开放源代码并接入多家公司线上产品线 开箱即用 XXL JO
  • JavaScript/ES6中的Object

    记录Object构造函数的一些静态方法 Object是编程中常见的一种构造函数 创建一个对象包装器 为什么说是创建了一个对象包装器 Object构造器会根据传入的参数的类型 将参数包装成具体的对象 如有数字对象 boolean对象 字符串对
  • 程序设计模式23+1种定义+UML图(有部分分析和联用)

    程序设计模式这门课已经学完了 复习的时候做了一个这样的汇总 希望可以给后来学习这门课的同学一些帮助 设计模式的分类 根据目的 模式是用来做什么的 可分为创建型 Creational 结构型 Structural 和行为型 Behaviora
  • 问题1:将静态库编译成动态库

    一 描述 1 多个同事间合作开发一个软件项目 每个人负责一部分模块开发 商定好彼此的对外接口 编程实现后 最后需要将所有人的开发代码编译链接到一起 生成一个最终目标文件 2 由于多人开发 若全部采用源文件编译 编译时文件数量众多 编写Mak