Linux从入门到精通(九)——Linux编程

news2024/12/23 17:47:56

文章篇幅较长,建议先收藏,防止迷路

文章跳转
Linux从入门到精通(八)——Linux磁盘管理go
Linux从入门到精通(九)——Linux编程go
Linux从入门到精通(十)——进程管理go
Linux从入门到精通(十一)——计划任务go
Linux从入门到精通(十二)——shell编程go

目录

  • Linux编程
    • 1. vi的工作方式
    • 2. 进入和退出vi
      • 2.1 进入vi
      • 2.2 退出vi
    • 3. vi的编辑命令
      • 3.1 移动光标
      • 3.2 文本操作(命令方式下)
    • 4. 定义快捷键
    • 5. gcc编译器
      • 5.1 安装(c语言中文网)
        • 5.1.1 快速安装
        • 5.1.2 手动安装
      • 5.2 gcc 编译过程
        • 5.2.1 预处理阶段
        • 5.2.2 编译阶段
        • 5.2.3 汇编阶段
        • 5.2.4 链接阶段
      • 5.3 gcc所支持的后缀名
      • 5.4 gcc 常用编译选项
      • 5.5 库文件的创建
    • 6. gdb调试器
      • 6.1 gdb 基本用法
      • 6.2 gdb 常用命令
    • 7. make 工程管理

Linux编程

1. vi的工作方式

三种方式:命令方式、插入方式、末行方式

  • 命令方式:用户一进入vi就进入命令方式,在该模式中任何键入的字符都被看成vi的命令,键入后立即执行。
  • 插入方式:当用户需要输入文本时,使用某个命令,进入插入方式,才可开始输入文本。
  • 末行方式:在命令方式中键入:就进入末行方式,在末行方式中输入命令,例如W(写)和回车,就可将编辑的内容存入文件。

三种工作方式之间转换:

  1. 在操作系统提示符下键入vi ,进入命令方式。
    1. 命令方式 --> 插入方式,键入编辑命令,如插入命令i、 添加命令a、建立新行命令o等 。
    2. 命令方式 --> 末行方式,只需键入:, 每次只执行一条,执行完毕立即回到命令方式。
    3. 不论在什么方式,只要键入esc键,就可回到命令方式。
  2. 插入方式和末行方式之间不能直接切换,必须通过命令方式。
  3. 在命令方式,用两个ZZ (大写) 可以退出vi
  4. 在末行方式用qq !,还可以用wq

2. 进入和退出vi

2.1 进入vi

  1. vi [filename]
    • 这是编辑一个新文件或编辑一个已存在文件的方法。
    • 如果是新文件,系统会创建一个名为filename的文件。
    • 如果你需要对一个存在的文件进行修改,系统会把文件的内容读入vi使用缓存区供你编辑,完成后用相关命令写入源文件或写入另一个新的文件。
  2. vi
    • 这是编辑一一个 新的文件的方法。
    • 在编辑完成后必须用相关命令写入一个新的文件,杏则一切编辑的动作都无效。

进入vi后光标停留在文件的第一行行首,如希望停留在其他行,可以使用如下的命令:

  • vi +n [filename]: 进入vi后光标位于第n行
  • vi十[filename] :进入vi后光标位置为文件尾
  • vi +/string [filename]:进入vi后当前光标位置为字符串string所在行的首行。

2.2 退出vi

  1. 以原有的文件名保存编辑动作并退出。

    在末行方式下退出,用以下命令:

    :wq (保存并退出等价于:w 接 :q)
    :x
    

    在命令方式下退出,用两个大写ZZ即可。

  2. 以新文件名保存,必须进入末行方式,使用:

    :w newfile (保存到新文件)
    :q (退出)
    
  3. 不保存所做过的一切编辑动作,在末行方式下退出:

    :q!
    

3. vi的编辑命令

3.1 移动光标

  1. 行号:

    vi的工作是在文本缓冲区中实现的,为了帮助用户观看, 可为文本的行设置一个行号, 放在文本的左侧(行首前) 可以用末行命令set来设置和取消:

    :set number (:set nu)
    :set nonumber (:set nonu)
    
  2. 按字符移动:

    四个带箭头的方向键:各自按方向移动一个字符k、j、h、l:各自按上下左右移动一个字符。

  3. 按行移动:

    home # 光标移动到本行行首 
    0 # 行首
    ^ # 第一个非空白字符
    $或end # 光标移动到本行行尾
    - # 光标移动到上一行的行首
    [行号]G # 跳转到指定行,不指定具体行号跳到文件的最后一行
    gg # 首行
    
  4. 按字移动光标:

    • w和W:将光标移动到下一个字的字首

    • e和E:将光标移动到下一个字的字尾

    • b和B:将光标移动到前一个字的字首

  5. 按句移动光标:

    • (:将光标移动到上一个句子的开头

    • ):将光标移动到下一个 句子的开头

  6. 屏幕滚动:

    • ctrl+u :将屏幕向文件头方向翻滚半屏
    • ctrl+d: 将屏幕向文件尾方向翻滚半屏
    • ctrl+b:将屏幕向文件头方向翻滚一整屏
    • ctrl+f :将屏幕向文件尾方向翻滚一整屏

3.2 文本操作(命令方式下)

  1. 文本的插入:

    • i:插入当前字符前。
    • I:插入当前行头
    • a:插入当前字符后
    • A:插入当前行尾
    • o:插入当前行的下一行
    • O:插入当前行的上一行
  2. 文本的删除:

    • x:删除光标处的字符
    • nx:删除光标位置起的右n个字符
    • X:删除光标前的字符
    • nX:删除光标位置前的左n个字符
    • dd:删除当前行
    • ndd:删除当前行起的n行
    • D或d$:删除光标起到行尾的内容
    • d0:删除光标起前一个字符到行首的内容
    • dw:删除一个单词
    • ndw:删除n个单词
  3. 恢复删除:

    • u: 撤销上一次的编辑动作(可多次)
    • U:撤销在本行所有的编辑动作
    • .:再次执行刚执行过的命令
  4. 修改文本:

    • c 或 c$:改变光标位置起到行尾的内容
    • nC:改变光标位置起的n行内容。
    • cc:改变当前行的内容。
    • ncc:改变当前行起n行的内容。
  5. 文本替换:

    文本替换是用新的文本替换原有的文本。

    命令:rR

    • rx:用x字符替换光标位置的字符
    • nrx:用x字符替换光标位置起的n个字符
    • R:进入替换模式,结束后按esc回到命令模式
  6. 复制与粘贴:

    • yy 和 Y:复制当前行。
    • nyy 和 nY:复制当前行以下n行。
    • dd:剪切当前行。
    • ndd:剪切当前行以下n行。
    • p、P:粘贴在当前光标所在行下或行上。
  7. 移动多行:

    :n1,n2 m k # 从n1行到n2行的文本移动到k行处,其中m是移动命令
    
  8. 搜索和替换:

    • /string:向前搜索指定字符串。

      搜索时忽略大小写:set ic

    • ?string:向后搜索指定字符串。

    • n,N:向前向后搜索该字符串。

    • :%s/oldstr/newstr/g:全文替换指定字符串

    • :n1,n2s/oldstr/newstr/g:在n1行到n2行的范围内替换指定字符串。

4. 定义快捷键

:map 快捷键 命令 # 定义快捷键
:unmap 快捷键 # 删除快捷键

[例1]:

# 设置ctrl+O为注释当前行:
:map ^O I#<esc>		# ^使用ctrl+v
# 设置ctrl+D为取消当前行注释:
:map ^D 0x

:unmap ^O
:unmap ^D

5. gcc编译器

​ GNU CC (简称为 gcc)是GNU项目中符 合ANSIC标准的编译系统,能够编译用 C、C++和ObjectC等语言编写的程序。 gcc不仅功能强大,而且可以编译如 C、 C++、Object C、Java、 Fortran、 Pascal Modula-3和 Ada等多种语言,而且gcc又是一个交叉平台 编译器,它能够在当前CPU平台上为多种不同体系结构的硬件平台开发软件,因此尤其适合在嵌入式领域的开发编译。

5.1 安装(c语言中文网)

​ 由于 Linux 操作系统的自由、开源,在其基础上衍生出了很多不同的 Linux 操作系统,如 CentOS、Ubuntu、Debian 等。这些 Linux 发行版中,大多数都默认装有 GCC 编译器(版本通常都较低)。

​ 如果不清楚当前使用的 Linux 发行版是否已经装有 GCC 编译器,或者忘记了已安装 GCC 的版本号,可以打开命令行窗口(Terminal)并执行如下指令:

[root@VM-24-17-centos linux5]# gcc --version
gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-4)
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

​ 如果没有安装:

bash: /usr/bin/gcc: No such file or directory

5.1.1 快速安装

​ 要知道,每个 Linux 发行版都有自己的软件包管理工具,比如 CentOS 系统的 yum 包管理器、Ubuntu 系统的 apt 包管理器等等,并且大多数 Linux 发行版都提供有 GCC 编译器的二进制软件包。因此,我们可以直接“傻瓜式”地安装 GCC 编译器(以 yum 为例):

yum -y install gcc
yum -y install gcc-c++

通过执行这 2 条指令,就可以在 CentOS 系统中利用 gcc 命令来执行 C 语言程序,利用 g++ 命令来执行 C++ 程序。

注意:切勿认为 gcc 只能用来编译 C 语言程序,g++ 只能用于编译 C++ 程序,这是不对的。

​ 需要注意的是,采用此方式安装的 GCC 编译器,版本通常较低。以我当前使用的 Centos 6.5 系统为例,通过执行以上 2 条指令,其安装的是 GCC 版本为 4.4.7,而当下 GCC 编译器已经迭代至 10.0.1 版本。

​ 这意味着,如果读者使用此方式安装 GCC 编译器,需要查看 GCC 编译器的版本(通过gcc --version指令)是否符合自己的需求。举个例子,如果读者想编译 C++11 标准下的 C++ 程序,则至少要安装 4.8 版本的 GCC 编译器,低版本的 GCC 编译器是不支持 C++11 标准的。

总的来说,如果读者对 GCC 编译器的版本没有要求,则推荐使用此安装方式;反之,如果读者需要安装指定版本的 GCC 编译器,则需要使用接下来介绍的安装方法。

5.1.2 手动安装

此方式需要耗费的时间较长(几个小时),但支持安装指定版本的 GCC 编译器,并适用于大多数 Linux 发行版(不同之处会有额外提示);同时,如果读者想对已安装的 GCC 编译器进行版本升级,也可以使用此方式。

​ 和使用 yum 自动安装 GCC 编译器不同,手动安装 GCC 编译器需要提前到 GCC 官网下载指定版本的 GCC 源码安装包,读者可直接点击GCC源码包进行下载。值得一提的是,每个版本中都包含 2 种格式的压缩包,分别为 tar.gz 和 tar.xz,只是压缩格式不同,本节以 tar.gz 压缩包教大家安装 GCC 编译器。

这里以在 CentOS 系统上安装 10.1.0 最新版本的 GCC 编译器为例,下载的是 gcc-10.1.0.tar.gz 源码压缩包,整个安装过程如下:

  1. 以源码的方式安装 GCC 编译器,即手动编译 GCC 编译器的源码,需要当前系统中存在一个可用的编译器,我们可以用旧版本的 GCC 编译器来编译安装新版本的 GCC 编译器。

    如果读者所用的操作系统已安装有旧版本的 GCC 编译器,则无需另行安装;反之,读者需要先运行如下命令,安装一个旧版本的 GCC 编译器:

    yum install -y glibc-static libstdc++-static
    yum install -y gcc gcc-c++
    

    再次强调,不同 Linux 发行版的软件管理器也有所不同,比如 yum 仅适用于 CentOS、RedHat、Fedora 发行版;而 Ubuntu 系统需使用 apt 完成安装。

    其中,第一行指令用于安装编译 C 和 C++ 代码所需的静态链接库;第二行指令用于安装编译 C 和 C++ 代码的 gcc 和 g++ 指令。

  2. 找到下载好的 gcc-10.1.0.tar.gz 安装包,将其解压至 /usr/local/ 目录下,解压命令为:

    [root@bogon local]# tar -xf gcc-10.1.0.tar.gz -C /usr/local/
    

    由此,在 usr/local/ 目录下,就生成了一个新的名为 gcc-10.1.0 的目录(也就是文件夹)。

  3. 紧接着执行如下指令,下载安装 GCC 所需要的依赖包(如 gmp、mpfr、mpc 等):

    [root@bogon local]# cd /usr/local/gcc-10.1.0
    [root@bogon gcc-10.1.0]# ./contrib/download_prerequisites
    

    注意,一定观察此命令的执行结果,保证其确实是将 gmp、mpfr、mpc 等依赖包成功下载下来,才能继续执行下面的安装步骤。

  4. 完成以上准备工作之后,就正式进入安装 GCC 编译器的环节。首先,我们需要手动创建一个目录,用于存放编译 GCC 源码包生成的文件。执行如下命令:

    [root@bogon local]# mkdir gcc-build-10.1.0
    [root@bogon local]# cd gcc-build-10.1.0
    

    由此,我们在 /usr/local 目录下手动创建了名为 gcc-build-10.1.0 的目录文件,并进入到该目录中。

  5. 同时,由于 GCC 编译器支持多种编程语言的编译,而实际情况中我们可能只需要编译 1~2 种编程语言,因此需要对其进行必要的配置。通过执行如下指令,可以配置 GCC 支持编译 C 和 C++ 语言:

    [root@bogon gcc-build-10.1.0]# ../gcc-10.1.0/configure --enable-checking=release --enable-languages=c,c++ --disable-multilib
    

    有关 configure 后跟的各个参数的含义,读者仅需要了解 --enable-languages 用于设定 GCC 编译器支持编译的编程语言的类别,例如 c、c++、java、objc、obj-c++、go 等。

  6. 在第 4 步创建好 makefile 文件之后,接下来就可以使用 make 命令来编译 GCC 源程序:

    [root@bogon gcc-build-10.1.0]# make
    

    注意,编译过程是非常耗时的(本机耗时 6 小时完成编译),因此如果读者选用此方式安装 GCC,则在执行 make 命令时一定要安排合适的时间。

  7. 最后,执行如下命令安装 gcc:

    [root@bogon gcc-build-10.1.0]# make install
    

    由此就成功安装了 10.1.0 版本的 GCC 编译器。需要注意的是,如果此时读者直接执行 gcc --version,则 gcc 版本仍会显示之前安装的版本。操作系统重启之后,GCC 版本就会自行更正过来。

5.2 gcc 编译过程

#include <stdio.h>
int main(){
    puts("hello,world!");
	return 0;
}

gcc编译过程分为4个步骤:

  1. 预处理( Pre-Processing )
  2. 编译 ( Compiling )
  3. 汇编 (Assembling )
  4. 链接 ( Linking )

5.2.1 预处理阶段

-E:预处理的主要作用是通过预处理的内建功能对一些可预处理资源进行等价替换,最常见的可预处理资源有:文件包含、条件编译、布局控制、宏处理等。

gcc的选项,-E可以使编译器在预处理结束时就停止编译,生成.i文件(作用:把头文件嵌入)

gcc -E -o [目标文件] [编译文件]

# 例如
gcc -E -o hello.i hello.c

5.2.2 编译阶段

gcc的选项,-S,生成.s文件(作用:检查代码的规范性、是否有语法错误等,以确定代码实际要做的工作,在检查无误后,就开始把代码翻译成汇编语言。)

.s是汇编语言原始程序

gcc -S -o hello.s hello.c

hello.s可以直接执行。

5.2.3 汇编阶段

gcc选项,-c,汇编阶段是把编译阶段生成的.S文件 转换成 二进制目标代码(.o目标文件)

gcc -c hello.s -o hello.o

5.2.4 链接阶段

完成了链接之后,gcc就可以生成可执行文件,其命令格式如下。

gcc hello.o -o hello

运行该可执行文件即可:

./hello

5.3 gcc所支持的后缀名

后缀名所对应语言后缀名所对应语言
.cC原始程序.s/S汇编语言原始程序
.C/.cc/.cxxC++原始程序.h预处理文件(头文件)
.mObject-C原始程序.o目标文件
.i已经经过预处理的C原始程序.a/so编译后的库文件
.ii已经经过预处理的C++

5.4 gcc 常用编译选项

  1. 常用选项:

    选项含义
    -c只编译汇编不链接,生成目标文件.o
    -S只编译不链接,生成汇编代码
    -E只进行预处理,不做其他处理
    -g在可执行程序中包含标准调试信息,加了这个才可以gdb调试该文件。
    -o file将file文件指定为输出文件
    -v打印出编译器内部编译各过程的命令行信息和编译器的版本
    -I dir指明头文件所在位置,在头文件的搜索路径列表中添加dir目录
    默认情况下标准头文件存放位置:/usr/include
  2. 库相关选项:

    选项含义
    -static进行静态编译,即链接静态库,禁止链接动态库
    -shared1. 可以生成动态库文件
    2. 进行动态编译,尽可能地链接动态库,只有当没有动态库时,才会链接同名的静态库。
    -L dir指明库文件所在位置,在库文件的搜索路径列表中添加dir目录
    -l name指定库文件名称,链接名为libname.a(静态库)或者libname.so(动态库)的库文件。若两个库都存在,则根据编译方法(-static/-shared)进行链接。
    -fPIC(-fpic)生成使用相对地址的位置无关的目标代码( Position Independent Code ) 。
    然后通常使用gcc的-static 选项从该PIC 目标文件生成动态库文件

    默认情况下库文件的存放位置:/usr/lib/lib

  3. 警告和出错选项:

    选项含义
    -ansi支持符合ANSI标准的C程序
    -w关闭所有警告信息
    -Wall允许发出gcc提供的所有有用的报警信息
  4. 优化选项:

    选项含义
    -O编译优化,使得编译后的代码执行效率更高
    -O2数字越大, 编译优化的效果越好

    gcc可以对代码进行优化,它通过编译选项-On来控制优化代码的生成,其中n是一个代表优化级别的整数。

    对于不同版本的gcc来讲,n的取值范围及其对应的优化效果可能并不完全相同,比较典型的范围是从0变化到2或3。

    通常情况下,数字越大,会起到更好的优化效果,但整个编译链接的过程会变慢。

5.5 库文件的创建

  1. 库文件的分类:

    • 静态库文件:

      指编译链接时,把库文件的代码全部加入到可执行文件中,生成的可执行文件变大,运行时不再需要库文件,后缀一般a

    • 动态库文件:

      编译链接时,没有把库文件的代码加入到可执行文件中,在执行的时候去访问库文件,节省系统开销,生成的文件也小,后缀一般.so

  2. 静态库文件的创建(见例2):

    1. 编写源代码:xxx.c

    2. 编译成一个目标文件:xxx.o

    3. 执行命令,产生静态库文件:

      ar -cr libxxx.a xxx.o
      
  3. 动态库文件的创建(见例3):

    1. 编写源代码:xxx.c

    2. 执行命令,产生动态库文件:

      gcc -shared -fpic -o libxxx.so xxx.c
      
      # -shared: 生成共享库
      # -fpic: 产生位置无关代码
      

【例子1】:

头文件方式调用

./test.c

#include <stdio.h> //这个是在/usr/lib中找的
#include "mytest.h" //这个是在当前目录找的
int main(){
 mytest();
 printf("hello!\n");
 return 0;
}

./mytest.h(头文件)

#include <stdio.h>
void mytest(){
 printf("mytest() 头文件方式调用!\n");
} 

【例2】

静态库文件方式调用:

./test.c

#include <stdio.h>
int main(){
 Mytest();
 printf("hello!\n");
 return 0;
}

./mytest.c

#include <stdio.h>
void mytest(){
 printf("mytest() 静态库方式调用!\n");
} 

执行:

# 编译
gcc -c mytest.c -o mytest.o

# 生成静态库文件
ar -cr -o libmytest.a mytest.o

编译:

gcc test.c -o test -L ./ -l libmytest.a # 错误
# 指明库文件名称时,要使用简写形式,例如:
# -l libmytest.a 简写为:-lmytest
# 即:
[root@VM-24-17-centos linux5]# gcc test.c -o test -L ./ -lmytest
test.c: In function ‘main’:
test.c:3:5: warning: implicit declaration of function ‘mytest’ [-Wimplicit-function-declaration]
  mytest();
  ^~~~~~

[root@VM-24-17-centos linux5]# ./test 
mytest() 静态库方式调用!
hello!

【例3】

动态库文件方式调用:

# 生成动态库文件
gcc -shared -fpic -o libmytest.so mytest.c
# 编译
gcc test.c -o test -L ./ -lmytest

./test
# 此时执行./test,会报错:
./test: error while loading shared libraries: libmytest.so: cannot open shared object file: No such file or directory
# 因为默认库文件在/usr/lib或者/lib中,而动态库文件是在运行时访问,在执行./test的时候,默认库文件放置位置是找不到刚刚生成的动态库的,所以运行前必须把动态库文件复制到/usr/lib目录
cp libmytest.so  /usr/local/lib
./test
# 如果还报错:
vim /etc/ld.so.conf
add/usr/lib
sudo ldconfig # 刷新即可

6. gdb调试器

​ GDB是GNU开源组织发布的一个强大的Linux下的程序调试工具,它是一种强大的命令行调试工具。。一个合格的调试器需要有以下几项基本功能:

  • 能够运行程序,设置所有能影响程序运行的参数;
  • 能够让程序让指定的条件下停止。
  • 能够在程序停止时检查所有参数的情况。
  • 能够根据指定条件改变程序的运行。

6.1 gdb 基本用法

​ 需要调试的程序,在编译时要使用调试选项。在默认的情况下,调试符号不会编译到程序中。调试之后,不需要重新编译程序。

gdb [可执行文件名]
出现
(gdb)#这里可以输入调试命令

注意:可执行文件编译的时候,必须加入参数-g,才可以使用gdb

6.2 gdb 常用命令

进入gdb调试界面后,可以输入以下命令:

  • list:显示程序内容,默认一次显示10行,如需继续,继续回车即可或者继续list

  • list函数名:显示函数对应内容

  • list行号:显示该行周围的源代码

  • Set listsize 行数:设置显示代码的行数

  • Show listsize:显示当前listsize的设置

  • listfirst,last:显示first和list之间的内容

  • next:执行一行源代码但不进入函数内部

  • step:执行一行源代码并进入函数内部。

  • continue:继续运行,到下一个断点停止

  • run:执行当前被调试的程序。

  • quit:退出gdb 。

  • break n:在第n行设置断点,这将使程序执行到这里时被挂起。

  • break n 条件:当条件满足是,在该行断点生效。

    break 12 if i==12
    
  • break 函数名:在函数的起始位置设置断点,这将使程序执行到这里时被挂起。

  • info break:显示断点信息。

  • Delete n:去除第n号断点

  • Disable n:暂停使用第n号断点

  • Enable n:启动第n号断点

  • Break :从后向前清除断点

  • print 变量名:显示变量的值

  • file 文件名:如果直接执行gdb,没有跟文件名,可以通过这个调入想要调试的可执行文件。

  • kill:终止正在调试的程序

  • watch:使你能监视一个变量的值而不管它何时被改变。

  • make使你能不退出gdb,就可以重新产生可执行文件。

  • shell:使你能不离开 gdb 就执行UNIX shell命令

  • Ctrl+c:发信号量中断当前操作

注意:

所有命令均可以使用命令的首字母来执行,例如list可以用l执行。

7. make 工程管理

问题:有多个源文件的时候,如何生成一个可执行文件?

方法1:

gcc -Wall -o mytest test1.c test2.c test3.c
# -Wall 允许发出gcc提供的所有有用的报警信息

方法2:

gcc -Wall -c test1.c
gcc -Wall -c test2.c
gcc -Wall -c test3.c
gcc -o mytest test1.o test2.o test3.o

可以发现是比较繁琐的,这时候就引入了make工程管理:

​ Make工程管理器是Linux下的一个“自动编译管理器”,“自动”是指它能够根据文件的时间戳,自动发现更新过的文件而减少程序编译的工作量。能够通过读入Makefile文件的内容来执行大量的编译工作,用户只需要编写一次简单的编译语句即可。Make工具大大提高了实际项目的工作效率,几乎所有Linux下的项目编程都会涉及它。

即:通过Makefile 文件,制定编译规则,根据时间戳,判断文件是否进行过修改。

Makefile编译规则格式:

目标名称: 依赖文件(一般是.o文件,如果没有,就会找对应的.c文件,)
<tab>命令

执行格式:

make 目标名称(如果省略,自动找第一个目标执行)

例如:

all: main.o foo1.o foo2.o
	# 虽然没有.o文件,但是会自动根据依赖文件是.c,就会根据.c文件自动生成对应名字的.o目标文件
	gcc main.o foo1.o foo2.o -o all
# 伪目标:不需要依赖文件,只执行命令
clean:
	rm -f *.o
make all

此时我们如果修改了foo1.c,按以前的方法,还需要重新编译,但是引入make工程管理,只需再次make就会自动编译。

make clean # 执行尾目标

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

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

相关文章

教程一 Energy 构建简单的Windows、Linux、MacOSX桌面应用

Golang的Energy使用命令行工具安装开发环境&#xff0c;并运行一个应用。 环境安装 Energy 命令行工具 使用命令行工具自动安装Energy框架的所有依赖(CEF)&#xff0c;支持Window、Linux、MacOSX 安装过程从网络下载CEF和Energy库 获取命令行工具 一、预编译命令行工具 下载地…

银行业国产数据库现状

数据库发展历程 数据库经历了单机数据库、集中式数据库、非关系型数据库、新型数据库四阶段。 单机数据库&#xff1a;单机数据库就是只能运行在单机上&#xff0c;不提供网络功能的数据库。 集中式数据库&#xff1a;数据库是一种经典、传统的数据库结构&#xff0c;多台机…

js内容整理

js内容整理 定时器 JavaScript 提供定时执行代码的功能&#xff0c;叫做定时器&#xff08;timer&#xff09;&#xff0c;主要由setTimeout()和setInterval()这两个函数来完成。 setTimeout() setTimeout函数用来指定某个函数或某段代码&#xff0c;在多少毫秒之后执行。它…

公益是书籍是什么,公益书籍变现模式有哪些

最近&#xff0c;我看到很多人在朋友圈里做公益书籍。 什么是公益书籍&#xff0c;公益书籍又是怎么进行变现的呢&#xff1f; 公益书籍主要是借助公益的逻辑&#xff0c;分发给各种家长。家长每次根据书单给孩子选择相应的书&#xff0c;15元左右就能拿到一套。 公益书籍实…

Linux进程地址空间

哪有明知明天会死今天就会上吊的傻瓜&#xff1f; -要乐观喔 本次博客的分享呢可能比较抽象&#xff0c;博主尽力画图分析&#xff0c;力图给老铁阐明清楚。 目录 ⚽一、进程地址空间区域划分 &#x1f453;Ⅰ区域划分 &#x1f453;Ⅱ虚拟地址和物理地址 ⚽二、页表和映…

科技云报道:发布分布式云战略,中国电子云吹响冲锋号角

科技云报道原创。 过去三年&#xff0c;中国电子云一直牢牢抓住业界的目光&#xff0c;不仅因为“国家队”的身份光环&#xff0c;更因实打实的成绩令人侧目。 据悉&#xff0c;中国电子云核心产品中心云CECSTACK&#xff0c;起步可达3000节点规模&#xff0c;最大可支撑每秒…

一文搞懂堆外内存(模拟内存泄漏)

一、前言 平时编程时&#xff0c;在 Java 中创建对象&#xff0c;实际上是在堆上划分了一块区域&#xff0c;这个区域叫堆内内存。 使用这 -Xms -Xmx 来指定新生代和老年代空间大小的初始值和最大值&#xff0c;这初始值和最大值也被称为 Java 堆的大小&#xff0c;即 堆内内…

2022亚太C题赛题分享

是否全球变暖&#xff1f; 加拿大的49.6C创造了地球北纬50以上地区的气温新纪录&#xff0c;一周内数百人死于高温&#xff1b;美国加利福尼亚州死亡谷是54.4C&#xff0c;这是有史以来地球上记录的最高温度&#xff1b;科威特53.5C&#xff0c;甚至在阳光下超过70多个C&#x…

模板进阶模板分离编译的问题与解决

&#x1f9f8;&#x1f9f8;&#x1f9f8;各位大佬大家好&#xff0c;我是猪皮兄弟&#x1f9f8;&#x1f9f8;&#x1f9f8; 文章目录一、模板参数1.非类型模板参数比如库中的array2.类型模板参数二、模板参数的特化1.全特化2.偏特化&#xff08;半特化&#xff09;三、模板的…

RTSP 和 RTMP原理 通过ffmpeg实现将本地摄像头推流到RTSP服务器

RTSP 和 RTMP原理 & 通过ffmpeg实现将本地摄像头推流到RTSP服务器 文章目录RTSP 和 RTMP原理 & 通过ffmpeg实现将本地摄像头推流到RTSP服务器一、流媒体&#xff1a;RTSP 和 RTMP0、参考资料1、RTSP 和 RTMP的工作原理1&#xff09;RTSP工作原理2&#xff09;RTMP工作原…

计算机组成原理期末复习第三章-3(唐朔飞)

计算机组成原理期末复习第三章-3&#xff08;唐朔飞&#xff09; ✨欢迎关注&#x1f5b1;点赞&#x1f380;收藏⭐留言✒ &#x1f52e;本文由京与旧铺原创&#xff0c;csdn首发&#xff01; &#x1f618;系列专栏&#xff1a;java学习 &#x1f4bb;首发时间&#xff1a;&am…

C树和森林的研究学习随记【一】

文章目录树与森林树结构初识树基本的相关概念森林二叉树(Binary Tree)满二叉树【饱满】完全二叉树【少了叶子的满二叉树】总结树和森林的转换快速转换技巧森林转化为二叉树分辨二叉树的五大性质树与森林 树是一种的数据结构。顾名思义&#xff0c;类似于我们生活中的树一样。【…

C++11标准模板(STL)- 算法(std::stable_sort)

定义于头文件 <algorithm> 算法库提供大量用途的函数&#xff08;例如查找、排序、计数、操作&#xff09;&#xff0c;它们在元素范围上操作。注意范围定义为 [first, last) &#xff0c;其中 last 指代要查询或修改的最后元素的后一个元素。 将范围内的元素排序&#…

m基于Simulink的高速跳频通信系统抗干扰性能分析

目录 1.算法描述 2.仿真效果预览 3.MATLAB部分代码预览 4.完整MATLAB程序 1.算法描述 信道为Rayleigh衰落信道下的性能分析和Nakagami-m衰落信道下的性能分析。本课题我们采用的仿真参数如下&#xff1a; simulink仿真模型如下所示&#xff1a; 跳频是最常用的扩频方式之一…

Hadoop笔记-01概述

文章目录1 什么是大数据&#xff1f;1.1 大数据计算模式及代表产品1.2 云计算与物联网1.2.1 云计算1.2.1.1 虚拟化1.2.1.2 分布式存储1.2.1.3 分布式计算1.2.1.4 多租户1.3 物联网1.3.1 识别和感知技术1.3.2 网络与通信技术1.3.3 数据挖掘与融合技术1.4 大数据与云计算、物联网…

正态分布,二维正态分布,卡方分布,学生t分布——概率分布学习 python

目录 基本概念 概率密度函数(PDF: Probability Density Function) 累积分布函数(CDF: Cumulative Distribution Function) 核密度估计&#xff08;(kernel density estimation&#xff09; 1.正态分布 概率密度函数&#xff08;pdf&#xff09; 正态分布累积分布函数(CD…

山东大学软件学院操作系统课程设计(2021秋季,nachos)实验6

一、实验内容 二、源码分析 1. 理解nachos单线程地址映射机制 Machine::Run()中调用Machine::OneInstruction(Instruction *instr)逐条执行可执行文件中的指令&#xff0c;执行指令过程中和获取下一条指令时如果访问内存&#xff0c;通过machine->ReadMem(…)/WriteMem(……

嵌入式开发学习之--用蜂鸣器来传递摩斯码

本篇文章致力于从开发的角度思考问题&#xff0c;而不是搞学术的东西。 文章目录前言一、项目概况1.1、项目需求1.2、项目来源1.3、项目开发环境1.4、项目意义二、开发步骤2.1、了解什么是摩斯码2.2、构建项目流程图2.3、找到合适的模板2.4、增加文件2.5、添加代码2.6、读入数据…

学生HTML个人网页作业作品 (水果商城HTML+CSS)

&#x1f380; 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

通过写循环判断对称数:将一个整型数逆置,我们判断逆置后的整型数如果和最初的数相等,那么它就是对称数,如果不相等,就不是对称数

将一个整型数逆置&#xff0c;我们判断逆置后的整型数如果和 最初的数相等&#xff0c;那么它就是对称数&#xff0c;如果不相等&#xff0c;就不是对称数#include <stdio.h>int main() {int i,j0;scanf("%d",&i);int ki;//备份写在scanf之后while(i){jj*1…