【Makefile语法 01】程序编译与执行

目录

一、编译原理概述

二、编译过程分析

三、编译动静态库

四、执行过程分析


一、编译原理概述

make: 一个GCC工具程序,它会读 makefile 脚本来确定程序中的哪个部分需要编译和连接,然后发布必要的命令。它读出的脚本(叫做 makefile 或 Makefile)定义了文件关系和依赖关系。

# 查看GCC默认头文件搜索路径

echo | gcc -v -x c -E -
#include <stdio.h>

int main()
{
    printf("hello, world\n");
    return 0;
}

hello 程序的生命周期是从一个源程序(或者说源文件)开始的,即程序员通过编辑器创建并保存的文本文件,文件名是 hello.c。源程序实际上就是一个由值 0 和 1组成的位(又称为比特)序列,8 个位被组织成一组,称为字节。每个字节表示程序中的某些文本字符。

大部分计算机使用 ASCII 标准来表示文本字符:

  • 用一个唯一的单字节大小的整数值息来表示每个字符
  • hello.c 程序是以字节序列的方式储存在文件中的

hello.c 的表示方法说明了一个基本思想:系统中所有的信息——包括磁盘文件、内存中的程序、内存中存放的用户数据以及网络上传送的数据,都是由一串比特表示的。

二、编译过程分析

hello 程序的生命周期从一个高级 C 语言程序开始。

为了在系统上运行 hello.c 程序,每条 C 语句都必须被其他程序转化为一系列的低级机器语言指令。

然后这些指令按照一种称为可执行目标程序的格式打好包,并以二进制磁盘文件的形式存放起来。

GCC 编译器读取源程序文件 hello.c,并把它翻译成一个可执行目标文件 hello。这个翻译过程可分为四个阶段完成,如下图所示:

执行这四个阶段的程序(预处理器、编译器、汇编器和链接器)一起构成了编译系统(compilation system)。

# 预处理 Preprocessing
# -E 选项告诉编译器只进行预处理操作
# -o 选项把预处理的结果输出到指定文件

(base) [root@localhost 01_test]# vim hello.c 
(base) [root@localhost 01_test]# cat hello.c 
#include <stdio.h>

int main()
{
    printf("hello, world\n");
    return 0;
}
(base) [root@localhost 01_test]# gcc -E hello.c -o hello.i
(base) [root@localhost 01_test]# ls
hello.c  hello.i
(base) [root@localhost 01_test]#
# 生成汇编语言 Generating Assembly Language
# -S 选项告诉编译器,进行预处理和编译成汇编语言操作

(base) [root@localhost 01_test]# gcc -S hello.i -o hello.s
(base) [root@localhost 01_test]# ls
hello.c  hello.i  hello.s
(base) [root@localhost 01_test]# cat hello.s
        .file   "hello.c"
        .section        .rodata
.LC0:
        .string "hello, world"
        .text
        .globl  main
        .type   main, @function
main:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        movl    $.LC0, %edi
        call    puts
        movl    $0, %eax
        popq    %rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE0:
        .size   main, .-main
        .ident  "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-44)"
        .section        .note.GNU-stack,"",@progbits
(base) [root@localhost 01_test]# 
# 源程序编译为目标程序 Source File to Object File
# -c 选项告诉编译器,将源代码或汇编代码翻译成二进制机器代码

(base) [root@localhost 01_test]# ls
hello.c  hello.i  hello.s
(base) [root@localhost 01_test]# gcc -c hello.s -o hello.o
(base) [root@localhost 01_test]# ls
hello.c  hello.i  hello.o  hello.s
(base) [root@localhost 01_test]# cat hello.o
ELF>�@@
UH����]�hello, worldGCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-44)zRx
P                                                                 A�C
��      hello.cmainputs


�������� .symtab.strtab.shstrtab.rela.text.data.bss.rodata.comment.note.GNU-stack.rela.eh_frame @�0
90b.B�W�R@
�
        �0a(base) [root@localhost 01_test]# 
# 可执行文件生成 Executable
# -o 选项告诉编译器生成可执行文件

(base) [root@localhost 01_test]# ls
hello.c  hello.i  hello.o  hello.s
(base) [root@localhost 01_test]# gcc hello.o -o hello
(base) [root@localhost 01_test]# ls
hello  hello.c  hello.i  hello.o  hello.s
(base) [root@localhost 01_test]# ./hello 
hello, world
(base) [root@localhost 01_test]#
# 我们也可以直接将源代码生成可执行文件
# 可以单个源文件生成可执行文件,也可以多个源文件生成可执行文件

(base) [root@localhost 01_test]# gcc hello.c -o hello
(base) [root@localhost 01_test]# ls
hello  hello.c
(base) [root@localhost 01_test]# ./hello
hello, world
(base) [root@localhost 01_test]#

源文件.c文件 -> 预编译成.i文件 -> 编译成汇编语言.s -> 汇编成.o文件 -> 链接成可执行文件。

三、编译动静态库

# 创建一个静态库 Create a Static Lib

# 编译成 .o 文件
gcc -c [.c] -o [自定义文件名] 
gcc -c [.c] [.c] ...

# 编静态库
ar -r [lib自定义库名.a] [.o] [.o] ...

# 链接成可执行文件
gcc [.c] [.a] -o [自定义输出文件名]
gcc [.c] -o [自定义输出文件名] -l[库名] -L[库所在路径]


(base) [root@localhost 02_test]# vim add.c
(base) [root@localhost 02_test]# vim minus.c
(base) [root@localhost 02_test]# cat add.c
int add(int a, int b) {
    return a + b;
}
(base) [root@localhost 02_test]# cat minus.c
int minus(int a, int b) {
    return a - b;
}
(base) [root@localhost 02_test]# vim main.c
(base) [root@localhost 02_test]# cat main.c
#include <stdio.h>

int add(int a, int b);
int minus(int a, int b);

int main() {
    int a = 10;
    int b = 5;
    printf("a + b = %d\n", add(a, b));
    printf("a - b = %d\n", minus(a, b));
    return 0;
}
(base) [root@localhost 02_test]# gcc -c add.c -o add.o
(base) [root@localhost 02_test]# gcc -c minus.c -o minus.o
(base) [root@localhost 02_test]# ar -r mymathlib.a add.o minus.o
ar: 正在创建 mymathlib.a
(base) [root@localhost 02_test]# gcc main.c mymathlib.a -o math.exe
(base) [root@localhost 02_test]# ./math.exe 
a + b = 15
a - b = 5
(base) [root@localhost 02_test]#
# 创建一个动态库 Create a Shared Lib

# 编译成二进制 .o 文件
gcc -c -fpic [.c/.cpp][.c/.cpp]... 

# 编动态库
gcc -shared [.o][.o]... -o [lib自定义库名.so]

# 链接库到可执行文件
gcc [.c/.cpp] -o [自定义可执行文件名]  -l[库名] -L[库路径]

# 告诉编译器动态库的位置
# 1. 安装,不建议往系统库添加头文件
# 2. 添加环境变量,重启后无效
# 3. 配置 /etc/ld.so.conf.d 文件,永久有效
# 4. 建立软链接,永久有效


(base) [root@localhost 02_test]# gcc -c -fpic add.c minus.c 
(base) [root@localhost 02_test]# ls
add.c  add.o  main.c  minus.c  minus.o
(base) [root@localhost 02_test]# gcc -shared add.o minus.o -o libmymathlib.so
(base) [root@localhost 02_test]# ls
add.c  add.o  libmymathlib.so  main.c  minus.c  minus.o
(base) [root@localhost 02_test]# gcc main.c -o math -lmymathlib -L.
(base) [root@localhost 02_test]# ls
add.c  add.o  libmymathlib.so  main.c  math  minus.c  minus.o
(base) [root@localhost 02_test]# ./math
./math: error while loading shared libraries: libmymathlib.so: cannot open shared object file: No such file or directory
(base) [root@localhost 02_test]# pwd
/root/gitee/Test/Make_Learn/02_test
(base) [root@localhost 02_test]# rm math
rm:是否删除普通文件 "math"?y
(base) [root@localhost 02_test]# gcc main.c -o math -lmymathlib -L/root/gitee/Test/Make_Learn/02_test
(base) [root@localhost 02_test]# ./math
./math: error while loading shared libraries: libmymathlib.so: cannot open shared object file: No such file or directory
(base) [root@localhost 02_test]# ln -s ./libmymathlib.so /lib64/libmymathlib.so
(base) [root@localhost 02_test]# ./math 
./math: error while loading shared libraries: libmymathlib.so: cannot open shared object file: Error 40
(base) [root@localhost 02_test]# pwd
/root/gitee/Test/Make_Learn/02_test
(base) [root@localhost 02_test]# ls /lib64/libmymathlib.so 
ls: 无法访问/lib64/libmymathlib.so: 符号连接的层数过多
(base) [root@localhost 02_test]# rm -rf /lib64/libmymathlib.so 
(base) [root@localhost 02_test]# ln -s /root/gitee/Test/Make_Learn/02_test/libmymathlib.so /lib64/libmymathlib.so
(base) [root@localhost 02_test]# ./math 
a + b = 15
a - b = 5
(base) [root@localhost 02_test]#

四、执行过程分析

第一步:

  • shell 等待我们输入一个命令
  • 当我们在键盘上输入字符串"./hello"(注意这里是编译好的可执行目标文件)后
  • shell 程序将字符逐一读入寄存器
  • 再把它存放到内存中

第二步:

  • 当我们在键盘上敲回车键时,shell 程序就知道我们已经结束了命令的输人
  • 然后 shell 执行一系列指令来加载可执行的 hello 文件
  • 这些指令将 hello 目标文件中的代码和数据从磁盘复制到主存
  • 数据包括最终会被输出的字符串"hello,world\n"

第三步:

  • 一旦目标文件 hello 中的代码和数据被加载到主存
  • 处理器就开始执行 hello 程序的 main 程序中的机器语言指令
  • 这些指令将 "hello,world\n" 字符串中的字节从主存复制到寄存器文件
  • 再从寄存器文件中复制到显示设备,最终显示在屏幕上

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

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

相关文章

Java异常的处理 try-catch-finally

目录 什么是异常通过if-else处理异常用if-else堵漏洞的缺点 try-catch例第一种处理第二种处理第三种处理第四种处理 try-catch-finally例 System.exit(0);//终止当前的虚拟机执行 什么是异常 Exception&#xff1a;在程序的运行过程中&#xff0c;发生了不正常的现象&#xff0…

【Larry】英语学习笔记语法篇——换一种方式理解词性

目录 一、换一种方式理解词性 1、名词、形容词、副词&#xff0c;这就是一切 2、词性之间的修饰关系 3、介词其实很简单 形容词属性的介词短语 副词属性的介词短语 ①修饰动词 ②修饰形容词 ③修饰其他副词 一、换一种方式理解词性 1、名词、形容词、副词&#xff0c…

Mysql Day03

多表设计 一对多 在多的一方添加外键约束&#xff0c;关联另外一方主键 一对一 任意一方添加外键约束&#xff0c;关联另外一方主键 多对多 建立第三张中间表&#xff0c;中间表至少包含两个外键&#xff0c;分别关联两方主键 idstu_idcourse_id 1 11 2 12313421524 案…

【Linux】构建模块

&#x1f525;博客主页&#xff1a;PannLZ &#x1f38b;系列专栏&#xff1a;《Linux系统之路》 &#x1f94a;不要让自己再留有遗憾&#xff0c;加油吧&#xff01; 文章目录 构建第一个模块1模块的makefile2内核树内构建3内核树外构建 构建第一个模块 可以在两个地方构建模…

C++——二叉树

引入 map和set特性需要先铺垫二叉搜索树&#xff0c;而二叉搜索树也是一种树形结构 二叉搜索树的特性了解&#xff0c;有助于更好的理解map和set的特性 1.二叉搜索树的概念及优缺点 1.1二叉搜索树的概念 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或…

网络编程-Socket套接字

目录 1.网络编程 1.1定义与图解 1.2基本概念 &#xff08;1&#xff09;发送端和接收端 &#xff08;2&#xff09;请求和响应 &#xff08;3&#xff09;客户端和服务端 2.Socket套接字 2.1定义 2.2分类 &#xff08;1&#xff09;流套接字 &#xff08;2&#xff…

无人机图像识别技术研究及应用,无人机AI算法技术理论,无人机飞行控制识别算法详解

在现代科技领域中&#xff0c;无人机技术是一个备受瞩目的领域。随着人们对无人机应用的需求在不断增加&#xff0c;无人机技术也在不断发展和改进。在众多的无人机技术中&#xff0c;无人机图像识别技术是其中之一。 无人机图像识别技术是利用计算机视觉技术对无人机拍摄的图像…

黄金交易策略(Nerve Knife):反趋势锁定单的处理机制

锁定单是由大趋势反转之后原来的趋势单转变而来的&#xff0c;会在趋势再次反转时变为趋势单或者转入保留单&#xff0c;也有很大概率在趋势识别到转变之前就被减仓减掉了。 完整EA&#xff1a;Nerve Knife.ex4黄金交易策略_黄金趋势ea-CSDN博客 一、锁定单怎么样来的&#xf…

Git分支常用指令

目录 1 git branch 2 git branch xx 3 git checkout xx 4 git checkout -b xx 5 git branch -d xx 6 git branch -D xx 7 git merge xx(含快进模式和冲突解决的讲解) 注意git-log: 1 git branch 作用&#xff1a;查看分支 示例&#xff1a; 2 git branch xx 作用&a…

[day0] 借着“ai春晚”开个场

1 文思ai笔记-新的开始 今天是2024年2月29日&#xff0c;也是传统农历的除夕夜。早起在ai圈看到一个比较新奇的消息&#xff0c;ai春晚今日举办&#xff0c;竟然有一点小小的激动。这些年确实好久没看过春晚了&#xff0c;自己对于春晚的映像还停留在“白云黑土”、“今天&…

RocketMQ客户端实现多种功能

目录 RocketMQ客户端基本流程 消息确认机制 1、消息生产端采用消息确认加多次重试的机制保证消息正常发送到RocketMQ 单向发送 同步发送 异步发送 2、消息消费者端采用状态确认机制保证消费者一定能正常处理对应的消息 3、消费者也可以自行指定起始消费位点 广播消息 …

Java多线程:`Thread`类

&#x1f451;专栏内容&#xff1a;Java⛪个人主页&#xff1a;子夜的星的主页&#x1f495;座右铭&#xff1a;前路未远&#xff0c;步履不停 目录 一、Thread的常见构造方法二、Thread 的常见属性三、Thread的常用方法1、start方法2、中断一个线程Ⅰ、通过共享标记Ⅱ、调用in…

大模型基础架构的变革:剖析Transformer的挑战者(下)

上一篇文章中&#xff0c;我们介绍了UniRepLKNet、StripedHyena、PanGu-π等有可能会替代Transformer的模型架构&#xff0c;这一篇文章我们将要介绍另外三个有可能会替代Transformer的模型架构&#xff0c;它们分别是StreamingLLM、SeTformer、Lightning Attention-2&#xff…

蓝桥杯省赛模板构建——uart

打开CubeMX 串口的发送是跟调试器放一起的&#xff0c;通过PA9和PA10来接收发送 选择异步通讯 波特率配置为9600 打开串口中断&#xff0c;因为单片机接收数据需要用到中断 生成代码 添加底层驱动代码 打开在main.h打开uart定义 uart时钟配置&#xff0c;由于uart是用PCLK时钟…

STM32的ADC电压采集

时间记录&#xff1a;2024/2/9 一、ADC相关知识点 &#xff08;1&#xff09;STM32的ADC时钟不要超过14MHz&#xff0c;不然结果的准确率将下降 &#xff08;2&#xff09;ADC分为规则组和注入组&#xff0c;规则组相当于正常运行的程序&#xff0c;注入组相当于中断可以打断…

飞天使-linux操作的一些技巧与知识点8-zabbix6.0 容器搭建

文章目录 安装docker安装步骤mysql下载镜像安装zabbix 使用zabbix非host模式创建 测试效果 安装docker 1. 配置官方 yum 源$ sudo yum install -y yum-utils $ sudo yum-config-manager \--add-repo \https://download.docker.com/linux/centos/docker-ce.repo2. 安装 Docker$ …

CSGO游戏搬砖项目靠谱吗?是不是骗人的

很多地方都在大肆宣扬说CSGO游戏搬砖项目有二三十个点的利润&#xff0c;但我觉得他们看待问题太片面了&#xff0c;没有从全局上去分析这个项目。 这些人为了能割到小白的韭菜真是无所不用其极&#xff0c;什么牛都能吹得出来&#xff01;至少要实事求是吧&#xff0c;这不睁…

应用ANN+SMOTE+Keras Tuner算法进行信用卡交易欺诈侦测

目录 SMOTE&#xff1a; ANN&#xff1a;ANN(MLP) 三种预测-CSDN博客 Keras Tuner&#xff1a;CNN应用Keras Tuner寻找最佳Hidden Layers层数和神经元数量-CSDN博客 数据&#xff1a; 建模&#xff1a; SMOTE Sampling&#xff1a; Keras Tuner&#xff1a; SMOTE&…

【洛谷题解】B2056 求整数的和与均值

题目链接&#xff1a;求整数的和与均值 - 洛谷 题目难度&#xff1a;入门 涉及知识点&#xff1a;求和&#xff0c;平均值 题意&#xff1a; 输入样例&#xff1a; 4 344 222 343 222 输出样例&#xff1a; 1131 282.75000 分析&#xff1a;直接累加&#xff0c;再求平…

【Boost】:http_server模块(六)

http_server模块 一.安装cpp-httplib库二.基本使用服务器 一.安装cpp-httplib库 可以自己写一个http服务器&#xff0c;但比较麻烦&#xff0c;这里直接使用库。 在gitee上搜索cpp-httplib&#xff0c;任意找一个即可&#xff08;建议使用0.7.15版本&#xff09;。例如&#xf…