Makefile——Linux下C/C++编译方法

news2024/11/27 2:25:44

目录

  • 1. C
    • 1.1 编译C
    • 1.2 创建静态库
    • 1.3 创建动态库
  • 2. C++
  • 3. Makefile
    • 3.1 变量
    • 3.2 常用函数
    • 3.3 makefile编译文件

1. C

linux下常见的C语言项目相关的文件如下图所示。
在这里插入图片描述

1.1 编译C

通常使用GCC来编译C文件。编译过程为源文件.c文件 -> 预编译成.i文件 -> 编译成汇编语言.s -> 汇编成.o文件 -> 链接成可执行文件。编译命令为gcc -参数 .c -o 输出文件名称

  1. 预处理:将头文件拷贝进.c文件内容中,执行预编译命令。采用gcc -E命令
gcc -E [.c源文件] -o [输出文件名.i]
  1. 编译成汇编:将c语言代码编译为对应的汇编指令。采用gcc -S命令
gcc -S [.c源文件] -o [输出文件名.s]
  1. 编译成目标文件:二进制文件
gcc -c [.c源文件] [.c源文件] [...] -o [文件名]
  1. 编译成可执行文件:
gcc [.c源文件] [.c源文件] [...] -o [输出文件名]
gcc [.c源文件] [.c源文件] [...] -o [输出文件名] -l[库名] -L[库所在路径]

1.2 创建静态库

程序库是已写好的、供使用的可复用代码,每个程序都要依赖很多基础的底层库。从本质上,库是一种可执行代码的二进制形式。静态库可以在编译c项目时,将引用的库一起链接到可执行文件中,可执行文件在运行时不再需要库的支持,但可执行文件会变大。

  1. 将库的.c源文件编译成.o目标文件
gcc -c [.c] -o [自定义文件名] 
gcc -c [.c] [.c] ...
  1. 将.o目标文件编译成静态库
ar -r [lib自定义库名.a] [.o] [.o] ...
  1. 将C程序和静态库链接,编译成可执行文件。库名为lib***.a的***。
gcc [.c] -o [输出文件名] -l[库名] -L[库所在路径]

1.3 创建动态库

动态库在程序编译时不会链接到目标代码中,而是在程序运行时才被调用,可执行文件比静态链接的可执行文件要小。不同的程序可以共享相同的动态库。

  1. 将库的.c源文件编译成.o目标文件(要加入-fpic选项)
gcc -c -fpic [.c/.cpp][.c/.cpp]... 
  1. 将.o目标文件编译成动态库
gcc -shared [.o][.o]... -o [lib自定义库名.so]

#将1和2合并为一步
gcc -fpic -shared [.c源文件] [.c源文件] [...] -o lib[库名].so
  1. 将C程序和动态库链接,编译成可执行文件。库名为lib***.so的***。
gcc [.c/.cpp] -o [自定义可执行文件名]  -l[库名] -L[库路径] -Wl,-rpath=[库路径]

2. C++

编译C++的流程与编译C几乎一致,只不过用的时g++命令。将上述编译.c的gcc改为g++即可编译cpp文件。静态库与动态库同理。

3. Makefile

makefile是自动化编译的一款工具。实际中C/C++工程项目可能十分庞大,直接用手一条一条的敲gcc/g++效率极低。在makefile文件中编写编译流程可以简化编译工作。

  • make 会在当前目录下找到一个名字叫 Makefile 或 makefile 的文件
  • 如果找到,它会找文件中第一个目标文件(target),并把这个文件作为最终的目标文件
  • 如果 target 文件不存在,或是 target 文件依赖的 .o 文件(prerequities)的文件修改时间要比 target 这个文件新,就会执行后面所定义的命令 command 来生成 target 这个文件
  • 如果 target 依赖的 .o 文件(prerequisties)也存在,make 会在当前文件中找到 target 为 .o 文件的依赖性,如果找到,再根据那个规则生成 .o 文件
#makefile格式
targets : prerequisties
[tab键]command

targets为生成的目标文件;
prerequisties为为了生成targets目标而所需的依赖目标文件;
conmmand为需要运行的命令

为了避免 target 和 Makefile 同级目录下 文件/文件夹 重名的这种情况,我们可以使用一个特殊的标记 .PHONY 来显式地指明一个目标是 “伪目标”,如下例中的clean

.PHONY : clean

3.1 变量

  1. 变量定义用:=
cpp := src/main.cpp 
obj := objs/main.o
  1. 使用变量()或{}
cpp := src/main.cpp 
obj := objs/main.o

$(obj) : ${cpp} #cpp中的字符串代表的依赖文件,obj为生成的目标文件
	@g++ -c $(cpp) -o $(obj)  
	#等价于g++ -c src/main.cpp -o objs/main.o
compile : $(obj) #compile为伪目标,可执行make compile命令
  1. 预定义变量:
    $@: 目标(target)的完整名称
    $<: 第一个依赖文件(prerequisties)的名称
    $^: 所有的依赖文件(prerequisties),以空格分开,不包含重复的依赖文件
cpp := src/main.cpp 
obj := objs/main.o

$(obj) : ${cpp}
	@g++ -c $< -o $@
	#等价于g++ -c src/main.cpp -o objs/main.o
	@echo $^
	#执行shell命令echo,打印出cpp的内容

compile : $(obj)
.PHONY : compile
  1. 特殊符号:\为续行符,*通配符(匹配任意字符串,可用与目录名和文件名中),%通配符(匹配任意字符串,并将匹配到的字符串作为变量使用)

3.2 常用函数

函数执行格式通常为$(fn, arguments) or ${fn, arguments}

  1. shell:调用shell命令,返回shell命令执行结果,使用格式为
    $(shell <command> <arguments>)
# shell 指令,src 文件夹下找到 .cpp 文件
cpp_srcs := $(shell find src -name "*.cpp") 
# shell 指令, 获取计算机架构
HOST_ARCH := $(shell uname -m)
  1. subst:把字串 <text> 中的 <from> 字符串替换成 <to>,使用格式为
    $(subst <from>,<to>,<text>)
cpp_srcs := $(shell find src -name "*.cpp")
cpp_objs := $(subst src/,objs/,$(cpp_objs)) 
  1. patsubst:从 text 中取出 patttern(其中%为通配符), 替换成 replacement,使用格式为 $(patsubst <pattern>,<replacement>,<text>)
cpp_srcs := $(shell find src -name "*.cpp") #shell指令,src文件夹下找到.cpp文件
cpp_objs := $(patsubst %.cpp,%.o,$(cpp_srcs)) #cpp_srcs变量下cpp文件替换成 .o文件
  1. foreach:把字串<list>中的元素逐一取出来,执行<text>包含的表达式,使用格式为 $(foreach <var>,<list>,<text>)
library_paths := /lib \
                 /usr/local/lib64
#每一个元素前面加上-I
I_flag := $(foreach item,$(library_paths),-I$(item))
#等价于
I_flag := $(include_paths:%=-I%)
  1. dir:从文件路径+文件名字符串序列中取出目录部分,使用格式为
    $(dir <names…>)
$(dir src/foo.c hacks)    # 返回值是“src/ ./”。
  1. notdir:与dir函数相反,去除目录部分,只保留文件名
#嵌套使用,先用shell中的find命令寻找lib开头的文件,然后去掉这些文件的目录前缀
libs   := $(notdir $(shell find /usr/lib -name lib*))
  1. filter:从字符串序列中,过滤出满足条件的
libs    := $(notdir $(shell find /usr/lib -name lib*))
a_libs  := $(filter %.a,$(libs)) #过滤出静态库
so_libs := $(filter %.so,$(libs))  #过滤出动态库
  1. basename:去掉文件名后缀
libs    := $(notdir $(shell find /usr/lib -name lib*))
#去掉后缀和lib前缀,得到库名
a_libs  := $(subst lib,,$(basename $(filter %.a,$(libs))))
so_libs := $(subst lib,,$(basename $(filter %.so,$(libs))))
  1. filter-out:去除不要的字符串
objs := objs/add.o objs/minus.o objs/main.o
cpp_objs := $(filter-out objs/main.o, $(objs))

3.3 makefile编译文件

编译选项:
-m64: 指定编译为 64 位应用程序
-std=: 指定编译标准,例如:-std=c++11、-std=c++14
-g: 包含调试信息
-w: 不显示警告
-O: 优化等级,通常使用:-O3
-I: 加在头文件路径前
fPIC: (Position-Independent Code), 产生的没有绝对地址,全部使用相对地址,代码可以被加载到内存的任意位置,且可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的

链接选项:
-l: 加在库名前面
-L: 加在库路径前面
-Wl,<选项>: 将逗号分隔的 <选项> 传递给链接器
-rpath=: “运行” 的时候,去找的目录。运行的时候,要找 .so 文件,会从这个选项里指定的地方去找

cpp_srcs := $(shell find src -name *.cpp)
cpp_objs := $(patsubst src/%.cpp,objs/%.o,$(cpp_srcs))

include_dirs :=/home/include
I_options := $(include_dirs:%=-I%)
compile_options := -g -O3 -w $(I_options)

lib_dirs := /home/lib #库路径
link_libs := xxx      #库名
L_options := $(lib_dirs:%=-L%)
l_options := $(link_libs:%=-l%)
link_options := $(l_options) $(L_options) $(I_options)

#每个.cpp生成一个对应的目标文件
objs/%.o : src/%.cpp
	#创建文件夹,@表示make的时候不打印make信息
	@mkdir -p $(dir $@)
	@g++ -c $^ -o $@ $(compile_options)

workspace/exec : $(cpp_objs)
	@mkdir workspace/exec
	@g++ $^ -o $@ $(link_options)
	
# 输入make run即可生成run伪目标
run : workspace
	@./$<
	
# 输入make clean即可生成clean伪目标
clean :
	@rm -rf objs workspace/exec

debug :
	@echo $(as_files)

.PHONY : debug run clean

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

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

相关文章

【mfc/VS2022】计图实验:绘图工具设计知识笔记2

按钮添加处理程序 1.类视图找到对应类右击&#xff0c;类向导 2. 找到对应的的按钮id 如何将画出的两个相交的圆都显示出来&#xff0c;而不是重叠&#xff08;如下图&#xff09;隐藏了一条圆弧 问题如图&#xff1a; 因为矩形和圆心其实是个背景色的封闭图形&#xff0c;所…

ggplot2 -- geom_linerange 函数的简单使用

brief 需要三个参数确定一个直线&#xff0c;x轴位置&#xff0c;y轴起始位置&#xff0c;y轴结束位置。 有别于一些垂直辅助线&#xff0c;可以实现柱状图&#xff0c;瓷砖图等等。 example 实现柱状图 library(tidyverse)tibble(theta seq(from 0, to 1, by .1),prio…

【一周安全资讯1014】交通运输部发布《公路工程设施支持自动驾驶技术指南》;多地网信办对违反数据安全法规企业作出行政处罚

要闻速览 1.交通运输部发布《公路工程设施支持自动驾驶技术指南》 2.数据泄漏被传输境外后擅自删库&#xff01;某科技公司被上海市网信办依法处罚 3.浙江省网信办对杭州某科技公司未履行数据安全保护义务依法作出行政处罚 4.超140亿元资金失窃&#xff1f;印度一支付网关服务…

【Java】HIS医院信息化管理系统源码(SaaS模式多医院)

【Java】HIS医院信息化管理系统源码&#xff08;SaaS应用&#xff09;&#xff0c;系统采用主流成熟技术开发&#xff0c;B/S架构&#xff0c;软件结构简洁、代码规范易阅读&#xff0c;SaaS应用&#xff0c;全浏览器访问&#xff0c;前后端分离&#xff0c;多服务协同&#xf…

百度智能云-身份证验证(完整版-直接用)

百度云网址: https://cloud.baidu.com 身份验证的技术文档: 技术代码: 导入依赖: <dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp</artifactId><version>3.12.13</version><scope>compile<…

操作系统学习——进程调度

三种不同的调度 进程调度的两种基本方式 非剥夺方式&#xff1a;一旦吧处理机分配给某个进程后&#xff0c;便让他一直运行&#xff0c;知道进程完成或者发生某事件而阻塞&#xff0c;才把处理机转给另一个进程。 剥夺方式&#xff1a;某个进程运行时&#xff0c;如果有中断或…

flutter app开发环境搭建

Flutter是一个跨终端、多设备的应用界面开发工具&#xff0c;其支持web端、移动端、桌面端以及嵌入式不同应用场景的应用开发&#xff0c;其使用dart语言作为开发语言&#xff0c;本文主要描述Flutter开发环境搭建。 如上所示&#xff0c;从Flutter官方网站下载最新版本的Flutt…

AP8851H 降压恒压DC电源芯片 5V12V 零功耗快充应用

1&#xff0c;产品描述 AP8851H 一款宽电压范围降压型 DC-DC 电源管理芯片&#xff0c;内部集成使能 开关控制、基准电源、误差放大器、过 热保护、限流保护、短路保护等功能&#xff0c; 非常适合在宽输入电压范围具有优良 的负载和线性调整度。 AP8851H 芯片包含每周期的峰值…

iOS开发- CMMotionManager 开发

文章目录 一、CMMotionManager1.1 push方式1.2pull 方式 二、设备运动类型1. attitude2. rotationRate3. gravity4. userAcceleration5. magneticField & heading iOS 中常见传感器如下所示: 类型作用环境光传感器感应光照强度距离传感器感应靠近设备屏幕的物体磁力计传感器…

千兆光模块和万兆光模块的适用场景有哪些

随着数字化和物联网的普及&#xff0c;对网络速度和带宽的要求也越来越高。千兆光模块和万兆光模块是两种常见的光模块&#xff0c;在不同的应用场景中&#xff0c;它们各具优势。下面我们来探讨一下千兆光模块和万兆光模块的主要适用场景。 首先是企业网络。千兆光模块常用于…

环形海尔贝克Halbach磁体阵列

环形海尔贝克阵列是一种特殊形状的磁体结构&#xff0c;它的设计思路是通过将形状相同磁化方向不同的多个磁体组合而成一个圆环形磁体&#xff0c;以增强工作面或中心磁场的均匀性和稳定性。使用Halbach阵列结构的永磁电机较传统永磁电机具有更接近正弦分布的气隙磁场&#xff…

【LeetCode热题100】--105.从前序与中序遍历序列构造二叉树

105.从前序与中序遍历序列构造二叉树 二叉树前序遍历顺序&#xff1a;根左右 二叉树中序遍历顺序&#xff1a;左根右 只要我们在中序遍历中定位到根节点&#xff0c;那么我们就可以分别知道左子树和右子树中的节点数目。由于同一颗子树的前序遍历和中序遍历的长度显然是相同的…

实际开发精品贴-1- Winhex使用,给SD卡烧录bin文件

资料获取 Winhex中文破解版本 由于是订阅用户,所以也支持作者帮忙下载,可直接联系我本人 点击下载 教学开始 由于是订阅用户,文章会非常详细 解压我分享的文件,右键点击图标,以管理员方式打卡 -1-你的SD卡插入读卡器,并且初始化SD卡 -2-点击第一步的地方 -3-点击第…

数据结构--哈希表(Hash Table)

1. 哈希表简介 哈希表&#xff08;Hash Table&#xff09;&#xff1a;也叫做散列表。是根据关键码值&#xff08;Key Value&#xff09;直接进行访问的数据结构。 哈希表通过「键 key 」和「映射函数 Hash(key) 」计算出对应的「值 value」&#xff0c;把关键码值映射到表中一…

阿里企业邮箱能发开发信吗?群发邮件技巧?

阿里企业邮箱如何群发营销邮件&#xff1f;邮箱发开发信的方法&#xff1f; 对于许多企业而言&#xff0c;开发信是一种重要的沟通工具&#xff0c;用于与客户、合作伙伴和供应商建立联系。在本文中&#xff0c;蜂邮EDM将探讨阿里企业邮箱是否支持发送开发信&#xff0c;以及如…

通讯网关软件025——利用CommGate X2Modbus实现Modbus RTU访问DDE数据源

本文介绍利用CommGate X2Modbus实现Modbus RTU访问DDE数据源。CommGate X2MODBUS是宁波科安网信开发的网关软件&#xff0c;软件可以登录到网信智汇(http://wangxinzhihui.com)下载。 【案例】如下图所示&#xff0c;实现上位机通过Modbus RTU来获取DDE数据源的数据。 【解决方…

推荐5款各种原因导致很少人知道的小软件

​ 很多软件用起来很好用&#xff0c;但是由于这样那样的原因&#xff0c;一直没什么知名度&#xff0c;但是不代表它们不好用&#xff0c;我的任务就是把这些宝藏分享给大家。 1.图像编辑——GIMP ​ GIMP是一款免费的开源图像编辑器&#xff0c;可以用于创建和修改图像&…

word写论文遇到数字和文字中间空格删不掉

一、如何删除&#xff1f; 1、选中需要有数字和汉字那段文字 2、点击段落下拉 3、找到中文版式 4、将【自动调整中文与数字的间距】取消勾选&#xff08;不要勾选&#xff09; 5、点击确定即可删除啦

众和策略:小盘和大盘的关系?

在股票商场上&#xff0c;股票能够被分为小盘股和大盘股两类。那么&#xff0c;二者之间有什么联络呢&#xff1f;这篇文章将从多个视点来分析小盘和大盘的联络。 商场表现 首要&#xff0c;让我们看看两者在商场表现上的差异。大盘股是市值较大的股票&#xff0c;一般在首要股…

探寻蓝牙的未来:从蓝牙1.0到蓝牙5.4,如何引领无线连接革命?

►►►蓝牙名字的来源 这要源于一个小故事&#xff0c;公元940-985年&#xff0c;哈洛德布美塔特(Harald Blatand)&#xff0c;后人称Harald Bluetooth&#xff0c;统一了整个丹麦。他的名字“Blatand”可能取自两个古老的丹麦词语。“bla”意思是黑皮肤的&#xff0c;而“tan…