Linux Makefile编写之静态库

1 概述

  编译工具有很多(make/cmake/BJam)。如果不考虑跨平台的话,还是make比较方便。使用make编译需要编写Makefile。本文编写Makefile来生成C/C++静态库。

2 Makefile文件命名

Makefile文件首先是一个文本文件,Linux下默认有两种命名方式:

  • Makefile 这是最常用的命名方式
  • makefile 这是优先级高的命名方式

在工程目录下运行make命令,make程序先找makefile,如果没有makefile再找Makefile文件。也就是说如果makefile和Makefile两个文件都存在默认使用makefile。

其实Makefile的文件名可以是任意的,例如Buildfile,可以使用下面命令编译:

make -f BuildFile

本文使用make程序版本:

$make --version
GNU Make 4.2.1
Built for x86_64-pc-linux-gnu
Copyright (C) 1988-2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

3 MakeFile实例

这里以CppTest库代码为例,代码目录结构:

cpptest$ tree
.
├── Makefile
├── inc
│   ├── cpptest-assert.h
│   ├── cpptest-collectoroutput.h
│   ├── cpptest-compileroutput.h
│   ├── cpptest-htmloutput.h
│   ├── cpptest-output.h
│   ├── cpptest-source.h
│   ├── cpptest-suite.h
│   ├── cpptest-textoutput.h
│   ├── cpptest-time.h
│   └── cpptest.h
└── src
    ├── collectoroutput.cpp
    ├── compileroutput.cpp
    ├── config.h
    ├── htmloutput.cpp
    ├── missing.cpp
    ├── missing.h
    ├── source.cpp
    ├── suite.cpp
    ├── textoutput.cpp
    ├── time.cpp
    ├── utils.cpp
    ├── utils.h
    └── winconfig.h

2 directories, 24 files

Makefile文件如下:

PROJECT_NAME ?= cpptest

CC ?= gcc
CXX ?= g++
AR  ?= ar

CFLAGS := 
C++FLAGS := -std=c++11
LIBFLAGS := -rcD

PWD := $(shell pwd)
INCS :=  -I$(PWD)/inc
SRCDIR := $(PWD)/src
LIBDIR := $(PWD)/lib
LIBNAME := $(LIBDIR)/lib$(PROJECT_NAME).a

CSRC := $(wildcard $(SRCDIR)/*.c)
OBJS := $(patsubst %.c,%.o,$(CSRC))

CPPS := $(wildcard $(SRCDIR)/*.cpp)
CPPOBJS := $(patsubst %.cpp,%.o,$(CPPS))

all: $(OBJS) $(CPPOBJS) $(LIBDIR)
	$(AR) $(LIBFLAGS) $(LIBNAME) $(OBJS) $(CPPOBJS)  

$(OBJS): %.o:%.c
	$(CC) -c $(CFLAGS) $(INCS) $< -o $@

$(CPPOBJS): %.o:%.cpp
	$(CXX)  -c $(C++FLAGS) $(INCS) $< -o $@

$(LIBDIR):
	@mkdir $(LIBDIR) -p

.PHNOY:clean
clean:
	@rm -f $(OBJS) $(CPPOBJS)
	@rm -f $(LIBNAME)

编译结果:

cpptest$ make
g++  -c -std=c++11 -I/home/james/git/cpptest/inc /home/james/git/cpptest/src/utils.cpp -o /home/james/git/cpptest/src/utils.o
g++  -c -std=c++11 -I/home/james/git/cpptest/inc /home/james/git/cpptest/src/source.cpp -o /home/james/git/cpptest/src/source.o
g++  -c -std=c++11 -I/home/james/git/cpptest/inc /home/james/git/cpptest/src/time.cpp -o /home/james/git/cpptest/src/time.o
g++  -c -std=c++11 -I/home/james/git/cpptest/inc /home/james/git/cpptest/src/collectoroutput.cpp -o /home/james/git/cpptest/src/collectoroutput.o
g++  -c -std=c++11 -I/home/james/git/cpptest/inc /home/james/git/cpptest/src/textoutput.cpp -o /home/james/git/cpptest/src/textoutput.o
g++  -c -std=c++11 -I/home/james/git/cpptest/inc /home/james/git/cpptest/src/compileroutput.cpp -o /home/james/git/cpptest/src/compileroutput.o
g++  -c -std=c++11 -I/home/james/git/cpptest/inc /home/james/git/cpptest/src/htmloutput.cpp -o /home/james/git/cpptest/src/htmloutput.o
g++  -c -std=c++11 -I/home/james/git/cpptest/inc /home/james/git/cpptest/src/suite.cpp -o /home/james/git/cpptest/src/suite.o
g++  -c -std=c++11 -I/home/james/git/cpptest/inc /home/james/git/cpptest/src/missing.cpp -o /home/james/git/cpptest/src/missing.o
ar -rcD /home/james/git/cpptest/lib/libcpptest.a  /home/james/git/cpptest/src/utils.o /home/james/git/cpptest/src/source.o /home/james/git/cpptest/src/time.o /home/james/git/cpptest/src/collectoroutput.o /home/james/git/cpptest/src/textoutput.o /home/james/git/cpptest/src/compileroutput.o /home/james/git/cpptest/src/htmloutput.o /home/james/git/cpptest/src/suite.o /home/james/git/cpptest/src/missing.o

说明:

  • 编译生成静态库libcpptes.a文件放在lib目录下
  • 编译生成.o与源码在同一目录

3 代码分析

3.1 定义变量

PROJECT_NAME ?= cpptest

CC ?= gcc
CXX ?= g++
AR  ?= ar

说明:

  • 定义工程名,C/C++编译器名称和生成库程序名称。
  • ?=格式定义变量可以通过环境变量修改,例如工程名修改为CppTest需要在命令上执行命令: export PROJECT_NAME=CppTest
  • 编译器名称也可以修改,例如:export CC=arm-xilinx-linux-gnueabi-gcc,这样就可交叉编译了。

3.2 定义编译选项

CFLAGS := 
C++FLAGS := -std=c++11
LIBFLAGS := -rcD

说明:

  • 定义C/C++编译选项,C++使用C++11标准。
  • 定义生成库选项

3.3 定义路径

PWD := $(shell pwd)
INCS :=  -I$(PWD)/inc
SRCDIR := $(PWD)/src
LIBDIR := $(PWD)/lib
LIBNAME := $(LIBDIR)/lib$(PROJECT_NAME).a

说明:

  • 调用shell命令pwd获取当前路径PWD
  • 利用PWD定义include/src/lib路径
  • 定义生成库名称
  • 注意这里定义变量是通过:=来定义的,这种变量没法通过环境变量修改。

3.4 自动选择译源文件

CSRC := $(wildcard $(SRCDIR)/*.c)
OBJS := $(patsubst %.c,%.o,$(CSRC))

CPPS := $(wildcard $(SRCDIR)/*.cpp)
CPPOBJS := $(patsubst %.cpp,%.o,$(CPPS))

说明:

  • 调用函数wildcard扫描src下所有.c/.cpp文件
  • 调用函数patsubst通过源文件生成.o目标文件

3.5 编译依赖项

all: $(OBJS) $(CPPOBJS) $(LIBDIR)
	$(AR) $(LIBFLAGS) $(LIBNAME) $(OBJS) $(CPPOBJS)  

$(OBJS): %.o:%.c
	$(CC) -c $(CFLAGS) $(INCS) $< -o $@

$(CPPOBJS): %.o:%.cpp
	$(CXX)  -c $(C++FLAGS) $(INCS) $< -o $@

$(LIBDIR):
	@mkdir $(LIBDIR) -p

.PHNOY:clean
clean:
	@rm -f $(OBJS) $(CPPOBJS)
	@rm -f $(LIBNAME)

说明:

  • $(OBJS)依赖项编译.c文件为.o文件
  • $(CPPOBJS)依赖项编译.cpp文件为.o文件
  • $(LIBDIR)依赖项创建目录lib
  • all依赖项将.o文件生成lib文件。
  • clean依赖项删除编译生成.o和.a文件。

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

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

相关文章

Docker创建redis容器

Docker运行Redis 一&#xff1a;Docker安装Redis docker search redis二&#xff1a;Docker拉取镜像 下面两个命令看自己的需求 docker pull <镜像名称>&#xff1a;<版本号> #需要自己清楚自己需要什么般本的redisdocker pull redis #这个命令会自动下载最新…

C语言入门课程学习笔记3

C语言入门课程学习笔记3 第12课 - if 语句编程练习第13课 - switch 多分支选择语句第14课 - 程序中的循环结构第15课 - while 语句编程练习第16课 - do...while 与 for第17课 - break 与 continue 本文学习自狄泰软件学院 唐佐林老师的 C语言入门课程&#xff0c;图片全部来源于…

BUUCTF-Misc21

[GXYCTF2019]SXMgdGhpcyBiYXNlPw1 1.打开附件 是一个文本文档 里面有很多字符串 2.PuzzleSolver 用PuzzleSolver工具进行多组base64解码 3.得到flag 间谍启示录1 1.打开附件 是一个.iso文件 2.foremost 用foremost 分离文件 查看分离的文件 发现一个压缩包 3.运行 解压之…

Python | Leetcode Python题解之第47题全排列II

题目&#xff1a; 题解&#xff1a; class Solution:def permuteUnique(self, nums: List[int]) -> List[List[int]]:def dfs(x):if x len(nums) - 1:res.append(list(nums)) # 添加排列方案returndic set()for i in range(x, len(nums)):if nums[i] in dic: continue …

历史遗留问题-Oracle 19c RAC 安装时节点连接性问题

测试服务器的二节点数据库宕掉了&#xff0c;原因不明&#xff0c;需要产环境重新安装。我想上次在自己虚拟机安装实验过一次&#xff0c;应该一天能搞定&#xff0c;事实证明&#xff0c;你永远有学不完的bug&#xff01;&#xff01;&#xff01;&#xff01; 首先查看一下系…

算法基础:并查集详解

并查集 并查集&#xff0c;在一些有N个元素的集合应用问题中&#xff0c;我们通常是在开始时让每个元素构成一个单元素的集合&#xff0c;然后按一定顺序将属于同一组的元素所在的集合合并&#xff0c;其间要反复查找一个元素在哪个集合中。这一类问题近几年来反复出现在信息学…

Web前端开发之HTML_2

HTML5简介与基础骨架标题标签标签之段落、换行、水平线标签之图片标签之超文本链接标签之文本列表标签之有序列表列表标签之无序列表 1. HTML5简介与基础骨架 1.1 HTML5简介 HTML5是用来描述网页的一种语言&#xff0c;被称为超文本标记语言。用HTML5编写的文件&#xff0c;后…

伴游平台搭建重点,会用到哪些三方服务?

伴游平台搭建的重点在于确保用户的安全与体验&#xff0c;提供便捷的服务&#xff0c;同时维护平台的稳定运营。在搭建过程中&#xff0c;可能会用到以下三方服务&#xff1a; 身份验证与背景调查服务&#xff1a;由于伴游服务涉及到用户的个人安全和信任问题&#xff0c;因此需…

企业微信代开发应用登录操作

首先声明&#xff1a;企微的文档写得真烂&#xff01;&#xff01;&#xff01;有一些问题&#xff0c;官方情愿在问答区给用户一个个解答&#xff0c;也不愿意在文档写清楚&#xff0c;生怕自己工作量不饱和被优化。 概念说明 代开发应用&#xff0c;是相对于自建应用来说的。…

如何解决 IntelliJ IDEA 2024 启动总闪退问题?一站式解决方案!

&#x1f9e0; 如何解决 IntelliJ IDEA 2024 启动总闪退问题&#xff1f;一站式解决方案&#xff01; 文章目录 &#x1f9e0; 如何解决 IntelliJ IDEA 2024 启动总闪退问题&#xff1f;一站式解决方案&#xff01;摘要引言正文一级标题&#xff1a;检查和优化内存设置一级标题…

经验丰富也被裁了,失业快2年找不到工作?

前几天徐工说&#xff0c;他有个邻居&#xff0c;最近逮到他总是要跟他扯上几句。 原因是徐工一直是做嵌入式开发&#xff0c;而他一直做纯软件开发&#xff0c;具体不知道做后端还是前端。 他说&#xff0c;他至少有半年没上班了&#xff0c;之前在一家龙头物流公司上班。 碰上…

五年Python从业者,谈谈Python的一些优缺点

前言 Python它是作为年轻的血液&#xff0c;融入到编程语言这个大家庭里面&#xff0c;作为具有年轻人的蓬勃朝气的python&#xff0c;那它同时就会有年轻人的桀骜焦躁。 今天就来谈谈Python的一些优缺点。 先从优点说起&#xff0c;我是把它分为5部分。 1.简单————Pyth…

2024最新版JavaScript逆向爬虫教程-------基础篇之深入JavaScript运行原理以及内存管理

目录 一、JavaScript运行原理1.1 前端需要掌握的三大技术1.2 为什么要学习JavaScript1.3 浏览器的工作原理1.4 浏览器的内核1.5 浏览器渲染过程1.6 认识JavaScript引擎1.7 V8引擎以及JavaScript的执行过程1.8 V8引擎执行过程 二、JavaScript的执行过程2.1 初始化全局对象2.2 执…

【vue功能】多张图片合并

多张图片合并成一张图片 步骤一&#xff0c;多张图片上传步骤二&#xff0c;循环获取所有绘制图片的总高度new FileReader()方法作用new Image()方法作用介绍 步骤三&#xff0c;合并多张图片canvas.toDataURL()作用-dpr作用 步骤四&#xff0c;下载图片 步骤一&#xff0c;多张…

深入Linux下的GCC编译器:从入门到精通

目录标题 1、GCC编译器概述2、安装GCC3、GCC的基本使用4、高级功能4.1 多文件编译4.2 静态和动态链接4.3 什么是链接&#xff1f;4.4 静态链接优点缺点 4.5 动态链接优点缺点 4.6 实际应用4.7 编译优化 GCC&#xff08;GNU Compiler Collection&#xff09;是一款免费、开源的编…

从 Android 恢复已删除文件的 3 种简单方法

如何从 Android 恢复已删除的文件&#xff1f;毫不犹豫&#xff0c;有些人可能会认为从 Google 备份恢复 Android 文件太容易了。但是&#xff0c;如果删除的文件未同步到您的帐户或未备份怎么办&#xff1f;您错误的恢复可能会永久删除您想要的数据。因此&#xff0c;我们发布…

Maven 安装及配置教程(Windows)【安装】

文章目录 一、 下载1. 官网下载2. 其它渠道 二、 安装三、 配置四、 验证五、 本地仓储配置六、 配置镜像七、 配置JDK八、完整配置九、常用命令十、IDEA 中配置 Maven1. 配置当前项目2. 配置新建 / 新打开 项目 软件 / 环境安装及配置目录 一、 下载 1. 官网下载 安装地址&a…

【2024年最新】NodeMCU-ESP8266刷AT固件教程——适用于esp-12E和esp-12F

硬件图片 原理图 0、工具打包下载 工具包 密码:keduo 1、工具及固件下载 固件下载地址&#xff1a; 欢迎 | 安信可科技 (ai-thinker.com) 下载以下固件&#xff1a; 直接下载地址&#xff1a;AT 固件&#xff08;固件号&#xff1a;0781&#xff09; 下载以下工具&#xf…

【前端】vue数组去重的3种方法

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、数组去重说明二、Vue数组去重的3种方法 前言 随着开发语言及人工智能工具的普及&#xff0c;使得越来越多的人会主动学习使用一些开发工具&#xff0c;本文…

react09 hooks(useState)

react-09 hooks&#xff08;useState&#xff09; hooks组件&#xff08;函数组件动态化&#xff09; 其本质就是函数组件&#xff0c;引用一些hooks方法&#xff0c;用来在函数组件中进行例如状态管理&#xff0c;模拟类组件的生命周期等&#xff0c;只能运用到函数组件中 ho…