【Linux】gcc与make、makefile

文章目录

  • 1 gcc/g++
    • 1.1 预处理
    • 1.2 编译
    • 1.3 汇编
    • 1.4 链接
      • 1.4.1 静态链接
      • 1.4.2 动态链接
  • 2 make和makefile
    • 2.1 依赖关系
    • 2.2 依赖方法
    • 2.3 伪目标
  • 3 总结

1 gcc/g++

在这里插入图片描述
当我们创建一个文件,并向里面写入代码,此时,我们该如何使我们的代码能够运行起来呢?

如果是在windows的vs下,只需要点击运行就行了,现在在Linux下,该如何运行?

我们需要使用gcc编译器来编译已经写好的test.c源文件

编译之后,会在当前目录之下生成可执行程序,运行可执行程序即可

在这里插入图片描述
使用红框中的命令gcc test.c -o test 就完成了对源文件的编译。

之后,生成了可执行程序test.

运行test即可执行我们的可执行程序。

补充:c语言的程序用gcc编译,c++的程序用g++编译

  • 格式:
    gcc - 选项 源文件名 -o 目标文件名
  • 选项:
    -E 从当前文件开始,在预处理完成之后停止, 生成的文件后缀一般加i
    -S 从当前文件开始,在编译完成之后停止, 生成的文件后缀一般加s
    -c 从当前文件开始,在汇编完成之后停止, 生成的文件后缀一般加o

1.1 预处理

预处理的作用:

  1. 去除注释
  2. 展开头文件
  3. 处理条件编译
  4. 进行宏替换

命令: gcc -E 文件名.c -o 文件名.i

在这里插入图片描述
左边是test.c文件,右边是test.i文件(预处理文件)
在这里插入图片描述

1.2 编译

命令: gcc -S 文件名.i -o 文件名.s
功能:将预处理文件编译成汇编语言
在这里插入图片描述

在这里插入图片描述

1.3 汇编

命令: gcc -c 文件名.s -o 文件名.o
功能:将编译生成的.s文件中的内容转变成机器能识别的二进制机器码。
在这里插入图片描述
可以通过od命令查看.o文件
将二进制机器码以十六进制的形式显示出来。
在这里插入图片描述

1.4 链接

到这一步时候,我们的文件是,o的汇编文件。

这里有一个问题:我们写的程序中,使用到了printf()函数,但是我们并没有写printf()函数的实现方法和定义等,为什么执行程序的时候不会报错?

因为我们使用了库函数

printf()函数很明显是库函数。假设我们不包含<stdio.h>头文件,我们的程序必然会报错。

我们包了<stdio.h>文件之后就能使用了吗?

也不是,因为我们知道.h只是一个头文件,相当于有一个函数的声明,但是没有函数的具体定义,函数的具体定义肯定是一个文件。

假设库的创建者写了1000个函数,分为两个文件。其中,函数的实现叫做c和定义叫做c.h。

库的创建者不想给我们看函数的具体实现。所以对这个库进行的封装。但是他必须提供库的使用方法,所以又把头文件给了我们,提供给我们具体的使用方法。

我们通过头文件得知使用方法之后,在我们的c程序执行到库函数时候,就会链接到库中的库函数。库函数也是.o目标文件,将我们自己的程序和库函数链接到一起,就会生成可执行程序.exe。

那么,该如何找到库呢?

在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找。

链接的库分为静态库和动态库。

1.4.1 静态链接

在这里插入图片描述

  1. 当我们的函数执行到库函数的时候,跳转到链接的库函数,将库函数中该函数的实现拷贝到当前程序文件中。
  2. 再此之后再生成可执行文件。

静态链接的指令gcc 文件名.o -o 文件名 -static

在这里插入图片描述

1.4.2 动态链接

在这里插入图片描述

  1. 当执行到库函数时,跳转到动态库中,找到该函数的.o文件,去链接标准库中库函数的.o文件。
  2. 链接完之后再跳转回来。

在这里插入图片描述
在这里插入图片描述
通过ldd命令可以查看a.out链接的动态库。
图中的红框就是我们链接的动态库c

库的名称为去掉前缀去掉后缀,图中就是去掉前缀lib,去掉后缀.so,最后得到c

通过file指令查看文件的属性
在这里插入图片描述
黄色框中说明这是一个动态链接,链接的是动态库。

动态链接和静态链接的区别是什么?
在这里插入图片描述
通过上图可以看出静态链接比动态链接之后的文件大很多。

这是因为动态链接是直接跳转,而静态链接是将静态库中的内容拷贝到文件中

总结

  • 静态库或者动态库一个系统只有一个,所有使用系统的用户都在使用同一个库。
  • 静态链接后的可执行程序不会受到静态库升级或者被删除的影响,而动态库会受到影响。
  • 系统为了我们编程,提供了标准库的头文件.h,和动静态库.so/.a,头文件是为了告诉我们怎么使用库函数,动静态库中提供了库函数的具体实现方法。

2 make和makefile

make 是方法,makefile是文件

创建makefile文件
在这里插入图片描述
写入makefile文件
在这里插入图片描述

效果
在这里插入图片描述
从上面的操作中,我们可以看到,以前我们每次编译文件,都需要输入gcc等一系列命令。现在只需要使用make,就自动编译成功了。

  • makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
  • 一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作。

接下来分步解析。

2.1 依赖关系

什么是依赖关系?
a:b -----> 叫做a依赖b,有了b的存在才会有a的存在。

在makefile中,gcc编译的时候有哪些依赖关系呢?

在这里插入图片描述

2.2 依赖方法

依赖关系解决的谁以来谁的问题

依赖方法解决的是怎样依赖的问题

在这里插入图片描述
红框的内容就是依赖方法

在makefile中依赖关系和依赖方法是必须写的,并且必须是一一对应的

2.3 伪目标

在makefile中同样是可以删除文件的。

在这里插入图片描述
执行情况
在这里插入图片描述
其中,.PHONY:clean 这句话中.PHONY就是伪目标,clean被.PHONY修饰的

  • 被.PHONY修饰的对象就是一个伪目标。
  • 伪目标总是被执行。

如何理解伪目标总是被执行这句话?

首先理解什么文件不是总被执行。

在这里插入图片描述
可以看到,在执行第一次make的时候,可以正常执行;执行第二次make的时候就不能了。

为什么呢?

在这里插入图片描述

在使用stat命令之后,可以看到一个文件的ACM时间,分别是图上所示。

我们使用ll命令显示的就是文件的内容修改时间

在这里插入图片描述

可以看到test.c文件的最后一次被修改时间比test的最后一次被修改时间早。

这就意味着:可执行文件如果再次执行,其实内容是没有改变的。

如果test.c文件在test文件之后又被修改过,那么Modify时间应该比test文件的时间晚,这样再次编译的时候才会有效果。而如果test.c的时间比test时间早,说明test.c文件没有被修改过。因此也就没有再次编译的必要。

这是编译器为了更高效的举动。

验证
在这里插入图片描述
从上面可以知道,make不是总被执行,那么。伪目标是总被执行的,怎么验证?

在这里插入图片描述
只要执行make clean 就一直会执行,不会出现阻碍。

而clean正是被.PHONY修饰的伪目标

在这里插入图片描述

执行:
在这里插入图片描述
发现给make加上伪目标之后,make也总是被执行。

**clean:**之后没有东西,说明依赖关系也可以为空

3 总结

  1. 编译链接分为:预处理、编译、汇编、链接四个部分。使用到的命令如下:
    在这里插入图片描述
  • .c文件预处理变成.i文件
  • .i文件编译变成.s文件
  • .s文件汇编变成.o文件
  • .o文件链接变成可执行程序

其中,链接分为动态链接和静态链接。
静态链接将静态库中的.o程序拷贝到我们的程序,执行静态链接需要到系统默认的路径usr/lib中去找静态库,如果找不到就会报链接错误。

如果使用的是第三方库,需要用特定的方法链接到库。

  1. makefile中有:依赖关系,依赖方法和伪目标。
    其中,依赖关系和依赖方法是一一对应的。
    依赖关系也可以为空。

伪目标.PHONY表示总是执行

没有伪目标的文件通过判断文件的Modify时间来决定是否编译:

  1. 如果.c文件的Modify时间于可执行文件 ---- 不执行
  2. 如果.c文件的Modify时间于可执行文件 ---- 执行

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

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

相关文章

Vivado Repository IP Catalog 释疑

Vivado软件自带了一个IP核仓库&#xff0c;可以在IP Catalog界面查看。 在IP目录界面&#xff0c;依次给出了每个IP核的Name(名称)&#xff0c;Interface(接口)&#xff0c;State(状态)&#xff0c;License(许可证)和VLNV&#xff08;标识符&#xff09;。 Interface表示IP核的…

C++指针(五)完结篇

个人主页&#xff1a;PingdiGuo_guo 收录专栏&#xff1a;C干货专栏 前言 相关文章&#xff1a;C指针&#xff08;一&#xff09;、C指针&#xff08;二&#xff09;、C指针&#xff08;三&#xff09;、C指针&#xff08;四&#xff09;万字图文详解&#xff01; 本篇博客是介…

c++0305习题

一、求下面表达式的值 1&#xff0e;0 2&#xff0e;-1 3&#xff0e;1 4&#xff0e;&#xff08;1&#xff09;1 &#xff08;2&#xff09;3.2 &#xff08;3&#xff09;0 &#xff08;4&#xff09;7.0 5.&#xff08;1&#xff09;0&#xff08;2&#xff09;300.005&a…

[力扣 Hot100]Day49 二叉树的最近公共祖先

题目描述 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个节点 p、q&#xff0c;最近公共祖先表示为一个节点 x&#xff0c;满足 x 是 p、q 的祖先且 x 的深度尽可能大&#xff08;一个节点也可以…

服务器与文件内数据的 LENGTH_IN_CHAR 参数不匹配

导入数据库数据的时候出现这个 怎么解决&#xff1a;重建数据库实例 下面是达梦的工具 使用DM数据库配置助手 新建、删除实例 新建实例时的配置需要注意的选项 主要是字符集、大小写、和VARCHAR类型以字符为单位 出现【LENGTH_IN_CHAR 参数不匹配】勾选【VARCHAR类型以字…

NUC980开发板CAN开发笔记

一、内核开启CAN CAN 设置 NUC980 系列带有2个CAN(Controller Area Network), 可以分别独立设置。 请按以下的说明来使能CAN功能. 每个CAN可以单独的开关. CAN0有多组管脚可以选择, 需要一并设置。 使用者也可以设置CAN的唤醒功能。步骤如下&#xff1a; 进入 NUC980-linux-4.…

Linux系统安装及简单操作

目录 一、Linux系统安装 二、Linux系统启动 三、Linux系统本地登录 四、Linux系统操作方式 五、Linux的七种运行级别&#xff08;runlevel&#xff09; 六、shell 七、命令 一、Linux系统安装 场景1&#xff1a;直接通过光盘安装到硬件上&#xff08;方法和Windows安装…

1.初学docker

这是在centos7上的基本操作用法。 一、基本操作 # 安装yum源 yum install -y yum-utils # 配置yum源 yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo # 安装docker yum install -y docker-ce-cli containerd.io docker-buildx-plu…

计算机网络-数据链路层

一、认识以太网 "以太网" 不是⼀种具体的网络&#xff0c;而是一种技术标准; 既包含了数据链路层的内容, 也包含了⼀些物理 层的内容。 例如&#xff1a;规定了网络拓扑结构&#xff0c;访问控制方式&#xff0c;传输速率等; 例如&#xff1a;以太网中的网线必须使用…

mysql的trace追踪SQL工具,进行sql优化

trace是MySQL5.6版本后提供的SQL跟踪工具&#xff0c;通过使用trace可以让我们明白optimizer&#xff08;优化器&#xff09;如何选择执行计划。 注意&#xff1a;开启trace工具会影响mysql性能&#xff0c;所以只适合临时分析sql使用&#xff0c;用完之后请立即关闭。 测试数…

MQ高可用相关设置

文章目录 前言MQ如何保证消息不丢失RabbitMQRocketMQKafkaMQ MQ如何保证顺序消息RabbitMQRocketMQKafka MQ刷盘机制/集群同步RabbitMQRocketMQKafka 广播消息&集群消息RabbitMQRocketMQ MQ集群架构RabbitMQRocketMQKafka 消息重试RabbitMQRockeMqKafka 死信队列RocketMQKaf…

基于springboot实现中小企业财务管理系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现中小企业财务管理系统演示 摘要 自改革开放一来&#xff0c;我国的经济发展进入到了快速发展时期&#xff0c;大城市的经济水平不断提高&#xff0c;吸引了很多的人不愿千里来大城市奋斗。一个企业的发展离不开相关的规定流程。信息化到来的今天在我们的生活…

计算机网络(基础篇)复习笔记——体系结构/协议基础(持续更新中......)

目录 1 计算机网络基础相关技术Rip 路由更新操作 2 体系结构(OSI 7层, TCP/IP4层)应用层运输层网络层IPv4无分类域间路由选择 CIDRIPV6 数据链路层循环冗余校验CRC协议设备 物理层传输媒体信道复用技术宽带接入技术数据通信 3 网络局域网(以太网Ethernet) 4 通信过程编码:信道极…

uniapp让输入框保持聚焦状态,不会失去焦点

使用场景&#xff1a;当输入框还有发送按钮的时候&#xff0c;点击发送希望软键盘不消失&#xff0c;还可以继续输入&#xff0c;或者避免因输入图片标签造成的屏闪问题 多次尝试后发现一个很实用的方法&#xff0c;适用input输入框和editor输入框 解决办法&#xff1a;把cli…

operator-sdk入门(mac)

1. 安装operator-sdk brew install operator-sdk 2. 安装kubebuilder brew install kubebuilder 3.初始化一个operator脚手架 3.1 新建一个文件夹 redis-operator 3.2 执行初始化 operator-sdk init --domain lyl.com --repo github.com 参数介绍 可以通过operator-sdk --…

Windows下同一电脑配置多个Git公钥访问不同的账号

前言 产生这个问题的原因是我在Gitee码云上有两个账号,为了方便每次不用使用http模式推拉代码,于是我就使用了ssh的模式,起初呢我用两台电脑分别连接两个账号,用起来也相安无事,近段时时间台式机在家里,我在外地出差了,就想着把ssh公钥同时添加到不同的账号里,结果却发现不能用…

《探索自动驾驶技术的前景与挑战》

自动驾驶技术,作为现代科技的一大突破,正逐渐改变着我们的交通方式、生活方式以及整个社会结构。本文将围绕自动驾驶技术的现状、优势、局限性以及未来发展趋势展开探讨。 自动驾驶技术的现状概述 自动驾驶技术作为当今科技领域的一项前沿技术,已经取得了巨大的进展并在不同…

Python算法题集_在排序数组中查找元素的第一个和最后一个位置

Python算法题集_在排序数组中查找元素的第一个和最后一个位置 题34&#xff1a;在排序数组中查找元素的第一个和最后一个位置1. 示例说明2. 题目解析- 题意分解- 优化思路- 测量工具 3. 代码展开1) 标准求解【二分法两次左边界】2) 改进版一【二分法左右边界】3) 改进版二【第三…

linux安装ngnix完整步骤(支持centos/银河麒麟操作系统)

linux安装ngnix&#xff08;支持centos/银河麒麟操作系统&#xff09; 本次操作系统安装ngnix采用离线或在线安装方式&#xff0c;离线就是不联网环境&#xff0c;在线则是联网环境&#xff1b;支持centos7或centos8或国产操作系统&#xff08;银河麒麟高级服务器操作系统&…

VUE3项目学习系列--项目基础配置(四)

一、环境变量配置 项目开发过程中会经历开发环境、测试环境、生产环境三种状态&#xff0c;对与环境变量的配置需求不同&#xff0c;因此需要在项目中进行环境变量的配置。 1.在项目根目录下添加如下3个文件 .env.development.env.production.env.test 文件中输入对应的配置…