Linux gcc和make学习

文章目录

    • GCC
      • gcc的安装
      • gcc的工作流程
    • makefile
      • makefile的规则
      • 工作原理
      • 自动生成
      • makefile的变量
        • 自定义变量
        • 预定义变量
        • 自动变量
      • 模式匹配
      • 函数
        • wildcard函数
        • patsubst函数
      • 伪声明

GCC

gcc全程是(GNU compiler collection CNU编译器套件),是由GNU开发的编程语言编辑器,它包含有gcc、g++,但是不仅限于这两种编译器;gcc不仅可以编译c/c++,还可以编译其他的语言包括java等,gcc可以实现跨不同的硬件平台编译,也就是交叉编译,比如在a平台可以编译b平台上的程序,常用支持linux、windows等。

gcc的安装

# 安装必须有管理员程序
# ubuntu
$ sudo apt update # 更新本地下载列表,获取最新的下载地址
$ sudo apt install gcc g++# centos
$ sudo yum update
$ sudo yum install gcc g++
# 查看gcc版本
$ gcc -v
$ gcc --version$ g++ -v

gcc的工作流程

gcc编译器对程序的编译主要分为4个阶段:预编译(预处理)、编译和优化、汇编、链接,gcc的编译器可以将这4个步骤合并成一个,下面分别介绍这四个步骤做了什么事情

  • 预编译(预处理):在这个阶段主要做了三件事情:展开头文件、宏替换、去掉注释行,这一阶段由gcc的预处理器完成,最终得到的还是源文件,文本格式。
  • 编译:这个阶段需要调用gcc编译器对文件进行编译,最终得到一个汇编文件
  • 汇编:这个阶段需要调用gcc的汇编器对文件进行汇编,最终得到一个二进制文件
  • 链接:这个阶段需要调用gcc的链接器对程序需要调用的库进行链接,得到一个可以执行的文件

分步完成:比如有一个为file.c的源文件(麻烦版)

预处理 gcc -E file.c -o file.i
编译 gcc -S file.i -o file.s
汇编 gcc -c file.s -o file.o
链接 gcc file.o -o file
file.c
file.i
file.s
file.o
file可执行文件

一步到位:使用gcc file.c -o aa可以直接生成编译链接后的file的可执行文件aa,直接使用./aa就可以执行。

GCC用到的参数

  • -E:对文件进行预处理,不进行编译,生成的还是源文件
  • -S:对文件进行编译,生成一个汇编文件
  • -c:对文件进行汇编,生成一个二进制文件
  • -o:用来指定生成的文件的名称
  • -I:指定include包含文件的搜索目录

makefile

  • 一般来说,使用gcc的命令行进行程序的编译在单个文件下是非常方便的,但是在实际的应用中,一个工程总不会是由单个文件构成的,往往是由多个文件构成的,当工程的文件逐渐增多,甚至非常庞大,使用GCC进行编译就会变得力不从心,这个时候可以使用make构造工具来完成这个艰巨的任务。
  • make是一个解释makefile中指令的命令工具。make工具在构造项目的时候需要加载一个makefile的文件,makefile关系到整个工程的编译规则,当一个工程中的源文件不计其数,按照类型、功能、模块划分在若干目录中时,这些文件之间存在着各种的依赖关系,makefile可以定义一系列的规则来指定哪一些文件需要先编译,哪一些文件需要后编译,哪一些文件需要重新编译等。
  • mekefile类似于一个shell脚本,所以也可以执行操作系统的一些命令。
  • 使用makefile可以自动化编译,极大的提高了软件开发的效率
  • makefile文件有两种命名的方式makefileMakefile,构建的时候在哪一个目录下执行make命令,哪一个目录的makefile文件就会被加载,因此一个项目中可以有多个makefile文件,分别存放在不同的项目目录中。
# 比如当前目录下有以下文件:add.c,clean,dic.c,head.h,main.c,makefile,sub.c
# 如果是使用gcc来对文件进行编译可以执行一下命令,生成app可执行命令
$ gcc *.c -o app
# 如果使用make命令可以直接
$ make
# 如果编译完成,可以直接使用以下命令删掉所有的编译文件
$ make clean

makefile的规则

# 每条规则的语法格式为:
target1,target2,... : depend1.depend2,...command............

每一条规则都有三个部分组成:目标(target)、依赖(depend)、命令(command)

  • 命令(command):当前这条规则的动作,一般情况下这个动作都是一个shell命令;动作可以是一个也可以是多个,每个命令前都必须有一个Tab缩进并且独占一行

  • 依赖(depend):规则所必须的依赖条件,如果规则不需要任何依赖,那么依赖可以为空;当前的规则可以是其规则的某一个目标,这就形成了规则之间的嵌套;依赖可以有多个

  • 目标(target):规则中的目标,目标与命令是对应的;规则中可以有多个命令,多条命令可以生成多个目标,所以目标可以有多个;通过规则中的命令值执行一个动作,不生成任何文件,这样的目标叫做伪目标

    举一个不太恰当的比喻,目标、依赖、命令的关系就好像是用材料做蛋糕的关系:目标就是我们要做的蛋糕,依赖就是做蛋糕原材料,命令就是用原材料做蛋糕的具体步骤,一个语法正确的规则,往往是一条shell命令对依赖关系的处理得到目标的过程。

# 规则中的嵌套关系
# 规则1
app:a.o b.o c.ogcc a.o b.o c.o -o app
# 规则2
a.o:a.cgcc -c a.c -o a.o
# 规则3
b.o:b.cgcc -c b.c -o b.o
# 规则4
c.0:c.cgcc -c c.c -o c.o

工作原理

  • 在调用make命令编译程序的时候,make会首先找到makefile文件的第1个规则,分析并执行相关的动作。但是需要注意的是,很多时候要执行的动作(命令)中的以来关系是不存在的,如果使用的以来关系不存在这个动作也不会被执行。
  • 遇到以上的情况,首先会将需要的依赖关系生成出来,以此类推,直到makefile的第一条规则的所有的依赖关系都被生成,第一条命令就可以基于这些依赖生成对应的目标,make任务也就结束了。
  • 换句话说,makefile的后续的规则,都是为了第一条命令来服务的。
  • 如果想要执行单条规则,可以使用make 目标名来执行单条规则。

情况1:依赖存在,但是目标不存在

  • 直接根据依赖生成目标

情况2:目标和依赖都不存在,目标时间戳>依赖时间戳,属于正常情况,不执行
情况3:依赖的时间戳>目标的时间戳,make重新生成目标

自动生成

make有自动推导能力,不会完全依赖与makefile。换句话说,make有一些隐藏的默认规则,这些规则就算不编写在makefile,make也会自动执行对应的规则,生产目标文件。

有的时候,我们可以不使用默认的规则生成目标,比如在编译一个多文件的程序中,如果只使用一条规则对多文件进行编译,当我们修改其中的一个文件时,通过make构建工具还是会把整个的文件全部编译一次,如果文件的数量很多,就会非常消耗时间;但是如果我们把默认规则都列举出来,就可以进行分步编译,当只修改其中一两个文件是,不需要对全部的依赖文件都编译一次,可以大大的提高编译的效率。

如果文件有修改,只编译修改的东西,可以加快编译的速度,只编译对应修改的以来关系的链条

makefile的变量

makefile的变量分为三种:自定义变量、预定义变量和自动变量

自定义变量

用户自己定义的变量叫做用户自定义变量,makefile的变量是没有类型的,直接创建变量的名字然后给其赋值即可

# 正确的定义自定义变量
变量名=变量值

在给makefile的变量赋值之后,可以使用$(变量的名字)来将变量的值取出来

# 用户自定义变量
# 定义一个变量
obj=a.o b.o c.o
# 规则1
app:$(obj)gcc $(obj) -o app
预定义变量

makefile中有一些已经定义的变量,用户可以直接使用这些变量,不用进行定义,在某一些条件下,makefile会使用这些预定义的值进行编译,这些预定义变量的名字一般都是大写,经常采用的预定义变量如下表所示:

在这里插入图片描述

  • CC:默认值为 cc ,是gcc的意思,一般用来编译c程序
  • CXX:默认值为 g++,一般用来编译c++程序
  • CFLAGS:c语言编译器的编译选项,没有默认值,要用户自己赋值
# 预定义变量
# 定义变量
target=app
obj=a.o b.o c.o
CFLAGS=-O3 # 代码优化(有四种优化级别分别是0-3)
# 规则1
$(target):$(obj)$(CC) $(obj) -o $(target) $(CFLAGS)
自动变量

自动变量用来代表这些规则中的目标文件和依赖关系,并且它们只能在规则的命令中使用

在这里插入图片描述

  • $@:表示目标文件的名称。包括扩展名
  • $^:在依赖项中,所有不重复的依赖文件,这些文件直接以空格分开
  • $<:在依赖项中的第一个依赖文件的名称
# 自动变量
# 定义变量
target=app
obj=a.o b.o c.o# 规则1
$(target):$(obj)gcc $^ -o $@

模式匹配

通过一个公式来代表若干满足条件的规则,用于精简makefile

以下代码中可以使用通配符%来匹配名字

# 规则中的嵌套关系
# 规则1
app:a.o b.o c.ogcc a.o b.o c.o -o app
# 规则2
a.o:a.cgcc -c a.c -o a.o
# 规则3
b.o:b.cgcc -c b.c -o b.o
# 规则4
c.0:c.cgcc -c c.c -o c.o
# 规则中的嵌套关系
# 规则1
app:a.o b.o c.ogcc a.o b.o c.o -o app
%.o:%.cgcc -c $< -o $@

函数

makefile中有很多函数并且所有的函数都具有返回值,makefile中的函数写法如下:$(函数名 参数1,参数2,参数3,...)

wildcard函数

这个函数的主要作用是获取指定目录下指定类型的文件名,其返回值是以空格分割的,指定目录下所有符合条件的文件名列表

# 函数原型
$(wildcard PATTERN...)参数:指定某个目录,搜索这个路径下指定类型的文件,可以指定多个目录,每一个路径之间用空格隔开# 返回值:得到若干文件的文件列表,文件名之间使用空格间隔
# 搜索三个不同目录下的.c源格式文件
src=$(wildcard *.c ./sub/*.c /home/robin/b/*.c)
patsubst函数

这个函数的功能是按照孩子定的模式替换指定的文件名的后缀

# 有三个参数,参数之间用逗号隔开
$(patsubst pattern,replacement.text)# pattern:模式字符串。需要指出要被替换的文件名的后缀是什么,文件名和路径不需要关心,使用 % 即可,如 %.c
# replacement:模式字符串,致命pattern中的后缀最终要被替换为什么;还是使用 % 表示路径和名字,指定新的后缀名即可,比如 %.o
# text:该参数中存储要被替换的原始数据
# 返回值:返回被替换过后的字符串
# 把变量src中所有文件名的后缀从.c替换为.o
src=a.c b.c c.c
obj=$(patsubst %.c,%.o,$(src))

使用函数搜索当前的目录下的c文件,并且修改名字

# 规则中的嵌套关系
# 规则1
app:a.o b.o c.ogcc a.o b.o c.o -o app
%.o:%.cgcc -c $< -o $@
target=app
src=$(whilecard *.c)# 搜索当前目录下所有的.c文件
obj=$(patsubst %.c,%.o,$(src))
$(target):$(obj)gcc $^ -o $@%.o:%.cgcc -c $<

伪声明

target=app
src=$(whilecard *.c)# 搜索当前目录下所有的.c文件
obj=$(patsubst %.c,%.o,$(src))
$(target):$(obj)gcc $^ -o $@%.o:%.cgcc -c $<# 这是一条伪声明,没有依赖,也不生成文件(伪目标)
clean:rm $(obj) $(target)

对伪目标的声明,以避免make对文件的时间戳进行检测,需要使用.PHONY关键字,声明方式为.PHONY:伪文件名称

# 最终版
target=app
src=$(whilecard *.c)# 搜索当前目录下所有的.c文件
obj=$(patsubst %.c,%.o,$(src))
$(target):$(obj)gcc $^ -o $@%.o:%.cgcc -c $<# 这是一条伪声明,没有依赖,也不生成文件(伪目标)
.PHONY:clean
clean:-rm $(obj) $(target) # 加-表示即使第一条命令执行失败,后面的命令也要继续执行...

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

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

相关文章

想要精通算法和SQL的成长之路 - 分割数组的最大值

想要精通算法和SQL的成长之路 - 分割数组的最大值 前言一. 分割数组的最大值1.1 二分法 前言 想要精通算法和SQL的成长之路 - 系列导航 一. 分割数组的最大值 原题链接 首先面对这个题目&#xff0c;我们可以捕获几个关键词&#xff1a; 非负整数。非空连续子数组。 那么我…

线性排序:如何根据年龄给100万用户数据排序?

文章来源于极客时间前google工程师−王争专栏。 桶排序、计数排序、基数排序时间复杂度是O(n)&#xff0c;所以这类排序算法叫作线性排序。 线性的原因&#xff1a;三个算法是非基于比较的排序算法&#xff0c;都不涉及元素之间的比较操作。 三种排序对排序的数据要求苛刻&am…

CCF CSP认证 历年题目自练Day30

题目一 试题编号&#xff1a; 202203-1 试题名称&#xff1a; 未初始化警告 时间限制&#xff1a; 1.0s 内存限制&#xff1a; 512.0MB 问题描述&#xff1a; 题目背景 一个未经初始化的变量&#xff0c;里面存储的值可能是任意的。因此直接使用未初始化的变量&#xff0c;比…

太强了,真的太强了!

国庆之后gpt4上线了很多强大的功能&#xff0c;有超级强大的数据分析和挖掘的功能&#xff0c;有可以比肩AI绘图神器Midjourney的绘图功能&#xff08;前面写了一篇泰酷辣&#xff01;目前最强的AI绘画神器&#xff01;文生图模型 DALLE 3来啦&#xff01;&#xff09;&#xf…

Python正则表达式

正则表达式 当处理文本数据时&#xff0c;正则表达式是一种强大的工具&#xff0c;它允许我们根据特定的模式来匹配、搜索和处理字符串。 正则表达式由一系列字符和特殊字符组成&#xff0c;用于描述文本模式。这些模式可以包含普通字符&#xff08;如字母、数字和标点符号&a…

【TensorFlow2 之012】TF2.0 中的 TF 迁移学习

#012 TensorFlow 2.0 中的 TF 迁移学习 一、说明 在这篇文章中&#xff0c;我们将展示如何在不从头开始构建计算机视觉模型的情况下构建它。迁移学习背后的想法是&#xff0c;在大型数据集上训练的神经网络可以将其知识应用于以前从未见过的数据集。也就是说&#xff0c;为什么…

蓝桥杯 第 1 场算法双周赛 第1题 三带一 c++ map 巧解 加注释

题目 三带一【算法赛】https://www.lanqiao.cn/problems/5127/learning/?contest_id144 问题描述 小蓝和小桥玩斗地主&#xff0c;小蓝只剩四张牌了&#xff0c;他想知道是否是“三带一”牌型。 所谓“三带一”牌型&#xff0c;即四张手牌中&#xff0c;有三张牌一样&#…

CSS学习基础知识

CSS学习笔记 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevice-width,…

独立式三相无源逆变电源设计

摘要 面对全球日趋严重的能源危机问题&#xff0c;可再生能源的开发和利用得到了人们的高度重视。其中辐射到地球太阳能资源是十分富饶的&#xff0c;绿色清洁的太阳能不会危害我们的生存环境&#xff0c;因而受到了人们的广泛利用。光伏发电作为可再生能源被广泛的应用&#x…

RabbitMq启用TLS

Windows环境 查看配置文件的位置 选择使用的节点 查看当前节点配置文件的配置 配置TLS 将证书放到同配置相同目录中 编辑配置文件添加TLS相关配置 [{ssl, [{versions, [tlsv1.2]}]},{rabbit, [{ssl_listeners, [5671]},{ssl_options, [{cacertfile,"C:/Users/17126…

如何定制化跑腿小程序源码

跑腿小程序源码为您提供了一个强大的起点&#xff0c;但要创建一个成功的本地服务平台&#xff0c;您通常需要对源码进行定制化。这篇文章将介绍如何定制化跑腿小程序源码&#xff0c;包括添加新功能、修改界面和优化用户体验。 选择合适的跑腿小程序源码 首先&#xff0c;您…

Linux查看端口号及进程信息

Linux查看端口号及进程 Linux查看端口号 netstat netstat -tuln显示当前正在监听的端口号以及相关的进程信息 ss ss -tuln与netstat类似&#xff0c;ss也可以用于显示当前监听的端口以及相关信息 isof isof -i :端口号端口号替换为具体要查找的端口号&#xff0c;显示该端…

Leetcode 75——1768.交替合并字符串 解题思路与具体代码【C++】

一、题目描述与要求 1768. 交替合并字符串 - 力扣&#xff08;LeetCode&#xff09; 题目描述 给你两个字符串 word1 和 word2 。请你从 word1 开始&#xff0c;通过交替添加字母来合并字符串。如果一个字符串比另一个字符串长&#xff0c;就将多出来的字母追加到合并后字符…

DOSBox和MASM汇编开发环境搭建

DOSBox和MASM汇编开发环境搭建 1 安装DOSBox2 安装MASM3 编译测试代码4 运行测试代码5 调试测试代码 本文属于《 X86指令基础系列教程》之一&#xff0c;欢迎查看其它文章。 1 安装DOSBox 下载DOSBox和MASM&#xff1a;https://download.csdn.net/download/u011832525/884180…

MySQL操作合集

数据库的操作 创建数据库 create database [if not exists] db_name [character set utf8] [collate utf8_general_ci];查看所有数据库 show databases;查看数据库的创建语句 show create database db_name;修改数据库 alter database db_name character set utf8 colla…

Linux之open/close/read/write/lseek记录

一、文件权限 这里不做过多描述&#xff0c;只是简单的记录&#xff0c;因为下面的命令会涉及到。linux下一切皆是文件包括文本、硬件设备、管道、数据库、socket等。通过ls -l 命令可以查看到以下信息 drwxrwxrwx 1 root root 0 Oct 10 17:06 open -rwxrwxrwx 1 root roo…

内网渗透——隧道代理

文章目录 代理代理使用场景VPS建立隧道frpMSF木马生成监听开启frp服务端和客户端执行exe木马文件 代理 实验环境&#xff1a; 攻击机kali&#xff1a;192.168.188.133&#xff08;NAT模式&#xff09; 模拟的公网服务器&#xff08;本机&#xff09;&#xff1a;10.9.75.239 …

【数据库——MySQL(实战项目1)】(4)图书借阅系统——触发器

目录 1. 简述2. 功能代码2.1 创建两个触发器&#xff0c;分别在借出或归还图书时&#xff0c;修改借阅人表中的已借数目(附加&#xff1a;借阅人表的总借书数、图书表的借阅次数以及更新图书表的图书状态为(已借出/在架上))字段&#xff1b;2.2 创建触发器&#xff0c;当借阅者…

相似性搜索:第 3 部分--混合倒排文件索引和产品量化

接续前文&#xff1a;相似性搜索&#xff1a;第 2 部分&#xff1a;产品量化 SImilarity 搜索是一个问题&#xff0c;给定一个查询的目标是在所有数据库文档中找到与其最相似的文档。 一、介绍 在数据科学中&#xff0c;相似性搜索经常出现在NLP领域&#xff0c;搜索引擎或推…

Codeforces Round 903 (Div. 3)

D. Divide and Equalize Example input Copy 7 5 100 2 50 10 1 3 1 1 1 4 8 2 4 2 4 30 50 27 20 2 75 40 2 4 4 3 2 3 1 output Copy YES YES NO YES NO YES NONote The first test case is explained in the problem statement. 很重要很重要的知识点&a…