1.Linux编译器-gcc/g++使用
1. 预处理(进行宏替换)
预处理功能主要包括宏定义,文件包含,条件编译,去注释等。
预处理指令是以#号开头的代码行。
实例: gcc –E hello.c –o hello.i
选项“-E”,该选项的作用是让 gcc 在预处理结束后停止编译过程。
选项“-o”是指目标文件,后面是编译好的文件名 “.i”文件为已经过预处理的C原始程序。
[wws@hcss-ecs-d531 ~]$ vim hello.c
[wws@hcss-ecs-d531 ~]$ gcc -E hello.c -o hello.i
[wws@hcss-ecs-d531 ~]$ cat hello.i
2.编译(生成汇编)
在这个阶段中,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,gcc 把代码翻译成汇编语言。
用户可以使用“-S”选项来进行查看,该选项只进行编译而不进行汇编,生成汇编代码。
实例: gcc –S hello.i –o hello.s
[wws@hcss-ecs-d531 ~]$ gcc -S hello.i -o hello.s
[wws@hcss-ecs-d531 ~]$ vim hello.s
3.汇编(生成机器可识别代码)
汇编阶段是把编译阶段生成的“.s”文件转成目标文件
在此可使用选项“-c”就可看到汇编代码已转化为“.o”的二进制目标代码了
实例: gcc –c hello.s –o hello.o
[wws@hcss-ecs-d531 ~]$ gcc -c hello.s -o hello.o
[wws@hcss-ecs-d531 ~]$ vim hello.o
4.连接(生成可执行文件或库文件)
在成功编译之后,就进入了链接阶段。
实例: gcc hello.o –o hello
生成可执行文件hello
函数库
我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实“printf”函数的呢?
最后的答案是:系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函数“printf”了,而这也就是链接的作用.
函数库一般分为静态库和动态库两种。
1.静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为“.a”
2.动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为“.so”,如前面所述的 libc.so.6 就是动态库。gcc 在编译时默认使用动态库。完成了链接之后,gcc 就可以生成可执行文件,如下所示。 gcchello.o –o hellogcc默认生成的二进制程序,是动态链接的,这点可以通过 file 命令验证。
gcc -o code_static code.s -static 用static选项链接静态库
yum install -y glibc-static 安装静态库C
yum install -y libstdc++-static C++静态库
2. Linux项目自动化构建工具-make/Makefile
makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。
make是一条命令,makefile是一个文件,两个搭配使用,完成项目自动化构建。
makefile使用
首先先创建两个文件 code.c makefile
-bash-4.2$ ll
total 8
-rw-r--r-- 1 wws wws 81 Aug 19 11:20 code.c
-rw-rw-r-- 1 wws wws 64 Aug 19 11:19 makefile
-bash-4.2$ ll
total 8
-rw-r--r-- 1 wws wws 81 Aug 19 11:20 code.c
-rw-rw-r-- 1 wws wws 64 Aug 19 11:19 makefile
-bash-4.2$ vim code.c
-bash-4.2$ vim makefile
//编译生成可执行程序code
-bash-4.2$ make
gcc -o code code.c
-bash-4.2$ ll
total 20
-rwxrwxr-x 1 wws wws 8360 Aug 19 11:26 code
-rw-r--r-- 1 wws wws 81 Aug 19 11:20 code.c
-rw-rw-r-- 1 wws wws 64 Aug 19 11:19 makefile
-bash-4.2$ ./code
hello Makefile!
//删除code
-bash-4.2$ make clean
rm -f code
-bash-4.2$ ll
total 8
-rw-r--r-- 1 wws wws 81 Aug 19 11:20 code.c
-rw-rw-r-- 1 wws wws 64 Aug 19 11:19 makefile
makefile原理
我们先了解一下各行代码作用
1.code(目标文件 要生成的文件):code.c (依赖文件列表 可以有多个文件)
gcc -o code code.c
依赖关系:
(Tab键)依赖方法
2. .PHONY(声明一个伪目标):clean(伪目标名称)
clean:(依赖文件列表为空)
rm -f code (要生成clean文件,就要执行它的依赖方法。但它的依赖方法不会生成文件,只是执行了删除文件的操作)
了解了这些我们看看几个问题
1.为什么make 就可以直接生成code文件呢?
(1)makefile文件会被make从上到下扫描,第一个目标名是缺省形成的。执行其他组的依赖关系和依赖方法,make+目标名。
把clean放第一个位置也可以make 默认执行。但不建议
2.PHONY:clean 有什么作用?
让目标文件的依赖方法每次都可执行。
-bash-4.2$ ll total 8 -rw-r--r-- 1 wws wws 81 Aug 19 11:20 code.c -rw-rw-r-- 1 wws wws 64 Aug 19 11:19 makefile -bash-4.2$ make gcc -o code code.c -bash-4.2$ make make: `code' is up to date. -bash-4.2$ make make: `code' is up to date. -bash-4.2$ make make: `code' is up to date.
可以看到code:code.c 执行一次就不能执行了。
当我们给code加上.PHONY后,
-bash-4.2$ vim makefile -bash-4.2$ make gcc -o code code.c -bash-4.2$ make gcc -o code code.c -bash-4.2$ make clean rm -f code -bash-4.2$ make clean rm -f code -bash-4.2$ make clean rm -f code
3.可以看到code:code.c可以被多次执行了,但为什么clean: 也可以被多次执行呢?
让我们先修改一下makefile文件
首先我们要明白什么时候要重新编译文件,当然是文件内容被修改的时候。
根据对比code.c 和 code的Mtime(Modify)就可以判断文件内容有没有被修改。
.PHONY就是忽略Mtime时间的对比,来让目标文件的依赖方法每次都可执行。
stat 查看文信息
-bash-4.2$ ll total 20 -rwxrwxr-x 1 wws wws 8360 Aug 19 12:32 code -rw-r--r-- 1 wws wws 81 Aug 19 11:20 code.c -rw-rw-r-- 1 wws wws 63 Aug 19 12:32 makefile //stat 查看文件的详细信息 -bash-4.2$ stat code.c File: ‘code.c’ Size: 81 Blocks: 8 IO Block: 4096 regular file Device: fd01h/64769d Inode: 1703942 Links: 1 Access: (0644/-rw-r--r--) Uid: ( 1000/ wws) Gid: ( 1000/ wws) //Access 文件最近访问时 Access: 2024-08-19 11:23:32.023200919 +0800 //Modify 最新文件内容被修改的时间 Modify: 2024-08-19 11:20:19.100243259 +0800 //Change 最新文件属性被修改的时间 Change: 2024-08-19 11:20:19.102243300 +0800 Birth: - -bash-4.2$ stat code File: ‘code’ Size: 8360 Blocks: 24 IO Block: 4096 regular file Device: fd01h/64769d Inode: 1703940 Links: 1 Access: (0775/-rwxrwxr-x) Uid: ( 1000/ wws) Gid: ( 1000/ wws) Access: 2024-08-19 12:32:42.882419012 +0800 Modify: 2024-08-19 12:32:42.882419012 +0800 Change: 2024-08-19 12:32:42.882419012 +0800 Birth: -
让我们修改code.c文件的内容(因为文件属性也包含文件大小,内容改变,文件属性也会改变,所以Ctime和Mtime会一起改变)
-bash-4.2$ vim code.c -bash-4.2$ stat code.c File: ‘code.c’ Size: 180 Blocks: 8 IO Block: 4096 regular file Device: fd01h/64769d Inode: 1703950 Links: 1 Access: (0644/-rw-r--r--) Uid: ( 1000/ wws) Gid: ( 1000/ wws) Access: 2024-08-19 12:38:49.429946666 +0800 Modify: 2024-08-19 12:38:49.429946666 +0800 Change: 2024-08-19 12:38:49.431946707 +0800 Birth: - -bash-4.2$ stat code File: ‘code’ Size: 8360 Blocks: 24 IO Block: 4096 regular file Device: fd01h/64769d Inode: 1703940 Links: 1 Access: (0775/-rwxrwxr-x) Uid: ( 1000/ wws) Gid: ( 1000/ wws) Access: 2024-08-19 12:32:42.882419012 +0800 Modify: 2024-08-19 12:32:42.882419012 +0800 Change: 2024-08-19 12:32:42.882419012 +0800 Birth: -
可以看到code.c的Mtime的时间在code Mtime的后面,说明code的内容已经不是最新的,就可以make 重新编译。
-bash-4.2$ make gcc -o code code.c -bash-4.2$ stat code File: ‘code’ Size: 8360 Blocks: 24 IO Block: 4096 regular file Device: fd01h/64769d Inode: 1703940 Links: 1 Access: (0775/-rwxrwxr-x) Uid: ( 1000/ wws) Gid: ( 1000/ wws) Access: 2024-08-19 12:41:24.546132682 +0800 Modify: 2024-08-19 12:41:24.546132682 +0800 Change: 2024-08-19 12:41:24.546132682 +0800 Birth: -
最后回到为什么clean:可以重复执行,就是因为clean:的依赖方法rm没有时间概念,所以可以重复执行。
4.我们想输出1111,但不想输出echo "1111"(echo 和字符间的空格不能省),怎么关闭命令回显呢?
可以用前加@关闭
-bash-4.2$ make echo "1111" 1111 echo "1111" 1111 echo "1111" 1111 echo "1111" 1111 gcc -o code code.c
-bash-4.2$ make 1111 1111 1111 1111 gcc -o code code.c
虽然看着只是用了一行代码就实现了对code.c的编译,其实展开来说这是一个递归实现的过程。
(2)make解析makefile时,如果code所依赖的code.o文件不存在,那么make会在当前文件中找目标为code.o文件的依赖性,以此类推,直到如找到再自下而上生成code(这有点像一个堆栈的过程)
-bash-4.2$ vim makefile -bash-4.2$ make gcc -E code.c -o code.i gcc -S code.i -o code.s gcc -c code.s -o code.o gcc code.o -o code -bash-4.2$ ll total 48 -rwxrwxr-x 1 wws wws 8360 Aug 20 10:37 code -rw-r--r-- 1 wws wws 180 Aug 19 12:59 code.c -rw-rw-r-- 1 wws wws 16978 Aug 20 10:37 code.i -rw-rw-r-- 1 wws wws 1680 Aug 20 10:37 code.o -rw-rw-r-- 1 wws wws 538 Aug 20 10:37 code.s -rw-rw-r-- 1 wws wws 205 Aug 20 10:37 makefile -bash-4.2$ ./code hello Makefile! hello Makefile! hello Makefile! hello Makefile! -bash-4.2$ make clean rm -f code.i code.s code.o code -bash-4.2$ ll total 8 -rw-r--r-- 1 wws wws 180 Aug 19 12:59 code.c -rw-rw-r-- 1 wws wws 205 Aug 20 10:37 makefile
makefile语法
1.% 通配符 $<
%.c 把当前目录中后缀.c文件放入依赖文件列表
$< :将依赖文件列表的文件一个一个交给gcc -c 配合 %.o生成同名的.o文件
2.定义变量名
我们可以给目标文件 依赖文件列表定义变量名。
$( ) 用来标记里面内容是变量名,不是文件。
3.$^ $@
$^:代表依赖文件列表
$@:代表目标文件
(3)make默认只生成一个可执行程序
-bash-4.2$ ll total 12 -rw-rw-r-- 1 wws wws 112 Aug 20 11:40 code.c -rw-rw-r-- 1 wws wws 181 Aug 20 12:13 makefile -rw-rw-r-- 1 wws wws 51 Aug 20 12:12 test.c -bash-4.2$ make gcc code.c -o code -bash-4.2$ ll total 24 -rwxrwxr-x 1 wws wws 8360 Aug 20 12:03 code -rw-rw-r-- 1 wws wws 112 Aug 20 11:40 code.c -rw-rw-r-- 1 wws wws 181 Aug 20 12:13 makefile -rw-rw-r-- 1 wws wws 51 Aug 20 12:12 test.c
可以看到上面这种写法只生成了一个可执行程序,怎么才能生成两个呢?
我们可以用原理(2),让make默认生成all目标文件,生成all又需要实现依赖文件列表$(bin1) $(bin2) , 实现后all文件什么都不用做,就可以同时生成多个可执行程序。-bash-4.2$ make gcc code.c -o code gcc test.c -o test -bash-4.2$ ll total 36 -rwxrwxr-x 1 wws wws 8360 Aug 20 12:13 code -rw-rw-r-- 1 wws wws 112 Aug 20 11:40 code.c -rw-rw-r-- 1 wws wws 181 Aug 20 12:13 makefile -rwxrwxr-x 1 wws wws 8360 Aug 20 12:13 test -rw-rw-r-- 1 wws wws 51 Aug 20 12:12 test.c
补充:回车/换行 缓冲区
首先回车和换行是同一个东西吗?
回车是把光标移动到一行的开头位置,换行是把光标从当前位置向下移一格,到下一行。平时我们写程序\n 就是先进行回车再进行换行。
这与缓冲区有什么关系呢?
这两段代码生成的程序有什么不同吗?
很明显,第二段代码输出hello后不会换行。但除此以外第一段代码hello是一开始就会输出,但第二段代码会先等2秒再输出。
编译器肯定是自上而下来读代码,printf("hello")后hello去哪了?
其实它是被存在缓冲区了,只不过\n可以立刻输出缓冲区的内容,立刻输出hello。第二段代码没有\n,只能等代码结束或者缓冲区满后输出。如果我们想让第二段代码缓冲区内容立刻输出,有什么办法吗?
可以加上fflush(stdout)可以立即将缓冲区内容刷新到输出设备。
注意下面代码输出 i 后进行\r回车操作,下一次输出时就会覆盖原位置内容。
但如果覆盖完后,后面还有上次留下的内容,就会连同新内容一起输出。
比如说上面输出10,经过回车操作,下次输出的9会覆盖1的位置,但后面0仍存在,导致后面一直有0。
-2%d 输出两位并左对齐进行解决
3.Linux上git的简单使用
1.git clone 同步仓库
复制仓库链接
git clone
-bash-4.2$ git clone https://gitee.com/laiyue-ang/gitee_test.git
Cloning into 'gitee_test'...
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (5/5), done.
remote: Total 5 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (5/5), done.
-bash-4.2$ ll
total 24
-rwxrwxr-x 1 wws wws 8552 Aug 20 21:12 code
-rw-rw-r-- 1 wws wws 195 Aug 20 21:12 code.c
drwxrwxr-x 3 wws wws 4096 Aug 23 10:06 gitee_test //git仓库
-rw-rw-r-- 1 wws wws 89 Aug 20 19:46 makefile
2.git add 将文件填入暂存区
git status 命令用于显示当前仓库的状态。
1.工作目录的状态,包括哪些文件已被修改但尚未提交,哪些文件被新创建但未被跟踪(未添加到暂存区),以及哪些文件被删除但尚未从 Git 中删除。
2.提交的状态,显示哪些更改已经被暂存(准备提交),哪些更改还在工作目录中待处理。
3.当前所在的分支。
-bash-4.2$ cd gitee_test
-bash-4.2$ ls -al
total 24
drwxrwxr-x 3 wws wws 4096 Aug 23 10:06 .
drwx------ 5 wws wws 4096 Aug 23 10:06 ..
drwxrwxr-x 8 wws wws 4096 Aug 23 10:16 .git
-rw-rw-r-- 1 wws wws 270 Aug 23 10:06 .gitignore
-rw-rw-r-- 1 wws wws 954 Aug 23 10:06 README.en.md
-rw-rw-r-- 1 wws wws 1315 Aug 23 10:06 README.md
-bash-4.2$ touch test.c
-bash-4.2$ ll
total 8
-rw-rw-r-- 1 wws wws 954 Aug 23 10:06 README.en.md
-rw-rw-r-- 1 wws wws 1315 Aug 23 10:06 README.md
-rw-rw-r-- 1 wws wws 0 Aug 23 10:17 test.c
//显示当前仓库的状态
-bash-4.2$ git status
# On branch master
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# test.c
nothing added to commit but untracked files present (use "git add" to track)
//添加到暂存区
-bash-4.2$ git add test.c
3.git commit -m "" 提交暂存区中的更改
git commit -m " "用于提交暂存区中的更改,并附上一个提交信息。双引号内的内容是提交信息的描述。
-bash-4.2$ git commit -m "第一次提交"
//ip地址 25是文件夹名称
[master 258e71f] 第一次提交
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 test.c
-bash-4.2$ ls -al
total 24
drwxrwxr-x 3 wws wws 4096 Aug 23 10:17 .
drwx------ 5 wws wws 4096 Aug 23 10:37 ..
drwxrwxr-x 8 wws wws 4096 Aug 23 10:37 .git
-rw-rw-r-- 1 wws wws 270 Aug 23 10:06 .gitignore
-rw-rw-r-- 1 wws wws 954 Aug 23 10:06 README.en.md
-rw-rw-r-- 1 wws wws 1315 Aug 23 10:06 README.md
-rw-rw-r-- 1 wws wws 0 Aug 23 10:17 test.c
-bash-4.2$ cd .git
-bash-4.2$ ll
total 48
drwxrwxr-x 2 wws wws 4096 Aug 23 10:06 branches
-rw-rw-r-- 1 wws wws 16 Aug 23 10:37 COMMIT_EDITMSG
-rw-rw-r-- 1 wws wws 268 Aug 23 10:06 config
-rw-rw-r-- 1 wws wws 73 Aug 23 10:06 description
-rw-rw-r-- 1 wws wws 23 Aug 23 10:06 HEAD
drwxrwxr-x 2 wws wws 4096 Aug 23 10:06 hooks
-rw-rw-r-- 1 wws wws 336 Aug 23 10:19 index
drwxrwxr-x 2 wws wws 4096 Aug 23 10:06 info
drwxrwxr-x 3 wws wws 4096 Aug 23 10:06 logs
drwxrwxr-x 11 wws wws 4096 Aug 23 10:37 objects
-rw-rw-r-- 1 wws wws 107 Aug 23 10:06 packed-refs
drwxrwxr-x 5 wws wws 4096 Aug 23 10:06 refs
-bash-4.2$ tree ./objects
./objects
├── 25
│ ├── 8e71faf534add8afe42bf5e88440936aa69f7f//test.c位置
│ └── 9148fa18f9fb7ef58563f4ff15fc7b172339fb
├── 2d
│ └── 5ccf81edf9d9f9578c41f8b2a4110657ddc8df
├── 3f
│ └── 86c0d12b09bace072229aa7db4ac3b7a85417c
├── 6f
│ └── 3f67da11058ebd2e861d41a6a441aa42d52936
├── 80
│ └── e5d64921976fbad64fd69f228054885ded9499
├── 8e
│ └── 2edac5f5d7121216dc874c5d1180c3ba1609eb
├── e6
│ └── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391
├── info
└── pack
4.git push 提交到远程仓库
-bash-4.2$ git push
warning: push.default is unset; its implicit value is changing in
Git 2.0 from 'matching' to 'simple'. To squelch this message
and maintain the current behavior after the default changes, use:
git config --global push.default matching
To squelch this message and adopt the new behavior now, use:
git config --global push.default simple
See 'git help config' and search for 'push.default' for further information.
(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode
'current' instead of 'simple' if you sometimes use older versions of Git)
Username for 'https://gitee.com': 18553792819
Password for 'https://18553792819@gitee.com':
Everything up-to-date
5.git log 获取提交记录
-bash-4.2$ git log
commit 9eea2d72ad6673f512f6393880bba12bbe4b25e7
Author: @laiyue-ang <3190290400@qq.com>
Date: Fri Aug 23 10:46:59 2024 +0800
修改test.c
commit 258e71faf534add8afe42bf5e88440936aa69f7f
Author: @laiyue-ang <3190290400@qq.com>
Date: Fri Aug 23 10:37:39 2024 +0800
第一次提交
commit 3f86c0d12b09bace072229aa7db4ac3b7a85417c
Author: 莱月昂 <13998474+laiyue-ang@user.noreply.gitee.com>
Date: Fri Aug 23 02:00:23 2024 +0000
Initial commit
补充:.gitignore
文件用于指定哪些文件和目录应该被 Git 忽略,不进行版本控制。你可以在.gitignore文件中列出要忽略的文件和目录,每行一个规则。
*.d会忽略所有以.d结尾的文件。push时不接收.d文件