目录
三、Linux项目自动化构建工具-make/Makefifile
一、gcc/g++
任何一段C/C++程序转变为可执行程序都要经历编译链接。
编译分为预处理,编译,汇编,三个过程
头文件的包含 #include
#define定义符号的替换
注释删除
文本操作
将C/C++语言代码翻译成了汇编代码
语法分析
词法分析
语义分析
符号汇总
把汇编指令翻译成了二进制指令
形成符号表
-E 只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面-S 编译到汇编语言不进行汇编和链接-c 编译到目标代码-o 文件输出到 文件-static 此选项对生成的文件采用静态链接-g 生成调试信息。GNU 调试器可利用该信息。-shared 此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库.-O0-O1-O2-O3 编译器的优化选项的4个级别,-O0表示没有优化,-O1为缺省值,-O3优化级别最高-w 不生成任何警告信息。-Wall 生成所有警告信息
gcc只能用来编译c语言,g++既可编译c语言又可编译c++
编译的三个过程gcc选项可以简化为ESc 与之所对应的形成文件的后缀是iso
可以使用idd或者file命令查看动静态库信息
- [WW@VM-8-14-centos testFork]$ ls
- a.out test.c
- [WW@VM-8-14-centos testFork]$ ldd a.out
- linux-vdso.so.1 => (0x00007ffcf94ae000)
- /$LIB/libonion.so => /lib64/libonion.so (0x00007feb24e95000)
- libc.so.6 => /lib64/libc.so.6 (0x00007feb249ae000)
- libdl.so.2 => /lib64/libdl.so.2 (0x00007feb247aa000)
- /lib64/ld-linux-x86-64.so.2 (0x00007feb24d7c000)
首先要明确一点
Linux下动态库的后缀是.so 静态库的后缀是.a
Windows下动态库.dll 静态库后缀是.lib
我们可以看到gcc默认是以动态库的方式进行编译
正如每次写C语言或者C++时都要引用头文件,.h文件只是包含函数或者其它变量的声明
具体的实现方法在动静态库中,我们引用的stdio.h中也是同样的
动态链接:将库中我要的方法地址填入到我的可执行程序中,建立关联节省资源
静态链接:将库中方法的实现,拷贝到可执行程序中,占用较多资源
- [WW@VM-8-14-centos testFork]$ gcc -o test_static test.c -static
- [WW@VM-8-14-centos testFork]$ ls
- a.out test.c test_static
- [WW@VM-8-14-centos testFork]$ gcc -o test_dynamic test.c
- [WW@VM-8-14-centos testFork]$ ls -als
- total 884
- 4 drwxrwxr-x 2 WW WW 4096 Aug 1 09:36 .
- 4 drwxrwxr-x 4 WW WW 4096 Aug 1 08:58 ..
- 12 -rwxrwxr-x 1 WW WW 8456 Aug 1 09:01 a.out
- 4 -rw-rw-r-- 1 WW WW 180 Aug 1 09:01 test.c
- 12 -rwxrwxr-x 1 WW WW 8456 Aug 1 09:36 test_dynamic
- 848 -rwxrwxr-x 1 WW WW 866248 Aug 1 09:36 test_static
我们会发现两中编译方式产生的文件体积差距明显,基本相差100倍。
我们的机器可能会因为没有静态库而导致链接失败
动态链接必须使用动态库,静态链接必须使用静态库
Makefile 文件描述了 Linux 系统下 C/C++ 工程的编译规则,它用来自动化编译 C/C++ 项目。一旦写编写好 Makefile 文件,只需要一个 make 命令,整个工程就开始自动编译,不再需要手动执行 GCC 命令。
一个中大型 C/C++ 工程的源文件有成百上千个,它们按照功能、模块、类型分别放在不同的目录中,Makefile 文件定义了一系列规则,指明了源文件的编译顺序、依赖关系、是否需要重新编译等。
我们在编写一个工程时会将每一个源文件进行编译,每次都要输入gcc或者g++命令,十分繁琐,当我们改动一个文件时可能需要重新编译这些文件,十分的繁琐。我们使用makefile就可以轻松解决这个问题了。
make是一个命令,makefile是一个文件
- Stack:Stack.c test.c
- gcc -o Stack -g Stack.c test.c
-
- .PHONY:clean
- clean:
- rm -f Stack
这是我们简单编写的一个makefile,makefile从上往下扫描,遇到第一个目标就停止
想要执行其它目标,可以使用make +目标名
.PHONY是一个伪目标,它是总是被执行的,可以将编译命令设置为伪目标,重复生成可执行程序。
当我们重复make时会出现以下情况
- [WW@VM-8-14-centos test]$ make
- make: `Stack' is up to date.
它是怎么确定我们的文件是最新的呢?
我们知道文件有acm时间,源文件的修改时间一定是早于可执行文件的修改时间的,因为源文件编译之后才会生成可执行文件。也就是说可执行文件的修改时间是最晚的。它可以通过判断修改时间来确认可执行程序是否是最新的。
在Linux下安装软件, 一个通常的办法是下载到程序的源代码, 并进行编译, 得到可执行程序.但是这样太麻烦了, 于是有些人把一些常用的软件提前编译好, 做成软件包(可以理解成windows上的安装程序)放在一个服务器上, 通过包管理器可以很方便的获取到这个编译好的软件包, 直接进行安装.软件包和软件包管理器, 就好比 "App" 和 "应用商店" 这样的关系.yum(Yellow dog Updater, Modifified)是Linux下非常常用的一种包管理器. 主要应用在Fedora, RedHat,Centos等发行版上.
yum就好比手机上的应用市场,yum可以用来搜索,下载,安装 软件 同时解决依赖关系
yum三板斧
- zinnia-tomoe-ja.x86_64 0.06-22.el7 epel
- zinnia-tomoe-zh_CN.x86_64 0.06-22.el7 epel
- zinnia-utils.x86_64 0.06-22.el7 epel
- zipios++.x86_64 0.1.5.9-9.el7 epel
- zipios++-devel.x86_64 0.1.5.9-9.el7 epel
- zlib.i686 1.2.7-20.el7_9 updates
- zlib-ada.x86_64 1.4-0.5.20120830CVS.el7 epel
- zlib-ada-devel.x86_64 1.4-0.5.20120830CVS.el7 epel
- zlib-devel.i686 1.2.7-20.el7_9 updates
- zlib-static.i686 1.2.7-20.el7_9 updates
- zlib-static.x86_64 1.2.7-20.el7_9 updates
- zmap.x86_64 2.1.1-1.el7 epel
- znc.x86_64 1.8.2-1.el7 epel
- znc-devel.x86_64 1.8.2-1.el7 epel
- znc-modperl.x86_64 1.8.2-1.el7 epel
- znc-modpython.x86_64 1.8.2-1.el7 epel
- znc-modtcl.x86_64 1.8.2-1.el7 epel
- zopfli.x86_64 1.0.1-1.el7 epel
- zork.x86_64 1.0.3-1.el7 epel
- zsh.x86_64 5.0.2-34.el7_8.2 os
- zsh-html.x86_64 5.0.2-34.el7_8.2 os
- zsh-lovers.noarch 0.9.0-1.el7 epel
- zsh-syntax-highlighting.noarch 0.7.1-1.el7 epel
- zstd.x86_64 1.5.2-1.el7 epel
- zulucrypt.x86_64 5.0.1-1.el7 epel
- zulucrypt-console.x86_64 5.0.1-1.el7 epel
- zulucrypt-devel.x86_64 5.0.1-1.el7 epel
- zulucrypt-doc.noarch 5.0.1-1.el7 epel
- zulucrypt-libs.x86_64 5.0.1-1.el7 epel
- zvbi.x86_64 0.2.35-1.el7 epel
- zvbi-devel.x86_64 0.2.35-1.el7 epel
- zvbi-fonts.noarch 0.2.35-1.el7 epel
- zziplib.i686 0.13.62-12.el7 os
- zziplib.x86_64 0.13.62-12.el7 os
- zziplib-devel.i686 0.13.62-12.el7 os
- zziplib-devel.x86_64 0.13.62-12.el7 os
- zziplib-utils.x86_64
yum list 列出所有可安裝的软件清单命令
sudo yum install -y sl
- [WW@VM-8-14-centos test]$ sudo yum install -y sl
- [sudo] password for WW:
- Loaded plugins: fastestmirror, langpacks
- Repository epel is listed more than once in the configuration
- Determining fastest mirrors
- epel | 4.7 kB 00:00:00
- extras | 2.9 kB 00:00:00
- os | 3.6 kB 00:00:00
- updates | 2.9 kB 00:00:00
- (1/7): epel/7/x86_64/updateinfo | 1.1 MB 00:00:00
- (2/7): epel/7/x86_64/group_gz | 97 kB 00:00:00
- (3/7): os/7/x86_64/group_gz | 153 kB 00:00:00
- (4/7): extras/7/x86_64/primary_db | 247 kB 00:00:00
- (5/7): os/7/x86_64/primary_db | 6.1 MB 00:00:00
- (6/7): updates/7/x86_64/primary_db | 16 MB 00:00:00
- (7/7): epel/7/x86_64/primary_db | 7.0 MB 00:00:01
- Resolving Dependencies
- --> Running transaction check
- ---> Package sl.x86_64 0:5.02-1.el7 will be installed
- --> Finished Dependency Resolution
-
- Dependencies Resolved
-
- ===========================================================================================================================================================================================
- Package Arch Version Repository Size
- ===========================================================================================================================================================================================
- Installing:
- sl x86_64 5.02-1.el7 epel 14 k
-
- Transaction Summary
- ===========================================================================================================================================================================================
- Install 1 Package
-
- Total download size: 14 k
- Installed size: 17 k
- Downloading packages:
- sl-5.02-1.el7.x86_64.rpm | 14 kB 00:00:00
- Running transaction check
- Running transaction test
- Transaction test succeeded
- Running transaction
- Installing : sl-5.02-1.el7.x86_64 1/1
- Verifying : sl-5.02-1.el7.x86_64 1/1
-
- Installed:
- sl.x86_64 0:5.02-1.el7
-
- Complete!
安装软件一般需要root权限所以加上sudo
这样就安装好了sl,我们运行一下
sl就是一个小火车
移除软件
我们可以尝试将sl软件删除
- [WW@VM-8-14-centos test]$ sudo yum remove sl
- Loaded plugins: fastestmirror, langpacks
- Repository epel is listed more than once in the configuration
- Resolving Dependencies
- --> Running transaction check
- ---> Package sl.x86_64 0:5.02-1.el7 will be erased
- --> Finished Dependency Resolution
-
- Dependencies Resolved
-
- ===========================================================================================================================================================================================
- Package Arch Version Repository Size
- ===========================================================================================================================================================================================
- Removing:
- sl x86_64 5.02-1.el7 @epel 17 k
-
- Transaction Summary
- ===========================================================================================================================================================================================
- Remove 1 Package
-
- Installed size: 17 k
- Is this ok [y/N]: y
- Downloading packages:
- Running transaction check
- Running transaction test
- Transaction test succeeded
- Running transaction
- Erasing : sl-5.02-1.el7.x86_64 1/1
- Verifying : sl-5.02-1.el7.x86_64 1/1
-
- Removed:
- sl.x86_64 0:5.02-1.el7
-
- Complete!
这样就把sl删除了
我们再运行就会出现以下情况,找不到文件或目录
- [WW@VM-8-14-centos test]$ sl
- -bash: /usr/bin/sl: No such file or directory
git是一个版本控制工具。
Git 是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目。
Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。
Git 与常用的版本控制工具 CVS, Subversion 等不同,它采用了分布式版本库的方式,不必服务器端软件支持。
git三板斧
预备:
git clone你的仓库链接
git add 文件名 #添加代码到本地仓库
git commit -m "提交日志" #提交代码到本地仓库
git push 提交代码到远端仓库
- [WW@VM-8-14-centos test]$ git add 8.1
- [WW@VM-8-14-centos test]$ git commit -m "PID相关内容练习"
- [main f2a1509] PID相关内容练习
- 6 files changed, 30 insertions(+)
- create mode 100755 8.1/testFork/a.out
- create mode 100644 8.1/testFork/test.c
- create mode 100755 8.1/testFork/test_dynamic
- create mode 100755 8.1/testFork/test_static
- create mode 100755 8.1/testPID/a.out
- create mode 100644 8.1/testPID/test.c
- [WW@VM-8-14-centos test]$ 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': 你的代码托管平台账号
- Password for 'https://@gitee.com': 密码
- Counting objects: 11, done.
- Delta compression using up to 2 threads.
- Compressing objects: 100% (10/10), done.
- Writing objects: 100% (10/10), 349.59 KiB | 0 bytes/s, done.
- Total 10 (delta 2), reused 0 (delta 0)
- remote: Powered by GITEE.COM [GNK-6.3]
- To https://gitee.com/wang_wei15144991472/test.git
- cf85611..f2a1509 main -> main
其它情况:第一次使用需要配置用户名和邮箱
- git config --global user.email 你的邮箱
- git config --global user.name 你的用户名
有时候无法提交,可能是版本冲突,你的本地代码与云端的代码有差异
git只会记录变化的部分,这时无脑git pull
GDB是一个由GNU开源组织发布的、UNIX/LINUX操作系统下的、基于命令行的、功能强大的程序调试工具。 对于一名Linux下工作的c++程序员,gdb是必不可少的工具;
gdb是一个命令行下的调试器
gcc和g++默认形成的可执行程序是release版本的,所以无法直接被调试
我们在编译时使用-g选项,将程序编译为debug版本
- [WW@VM-8-14-centos test]$ readelf -S Stack
- There are 35 section headers, starting at offset 0x3670:
-
- Section Headers:
- [Nr] Name Type Address Offset
- Size EntSize Flags Link Info Align
- [ 0] NULL 0000000000000000 00000000
- 0000000000000000 0000000000000000 0 0 0
- [ 1] .interp PROGBITS 0000000000400238 00000238
- 000000000000001c 0000000000000000 A 0 0 1
- [ 2] .note.ABI-tag NOTE 0000000000400254 00000254
- 0000000000000020 0000000000000000 A 0 0 4
- [ 3] .note.gnu.build-i NOTE 0000000000400274 00000274
- 0000000000000024 0000000000000000 A 0 0 4
- [ 4] .gnu.hash GNU_HASH 0000000000400298 00000298
- 000000000000001c 0000000000000000 A 5 0 8
- [ 5] .dynsym DYNSYM 00000000004002b8 000002b8
- 00000000000000d8 0000000000000018 A 6 1 8
- [ 6] .dynstr STRTAB 0000000000400390 00000390
- 0000000000000064 0000000000000000 A 0 0 1
- [ 7] .gnu.version VERSYM 00000000004003f4 000003f4
- 0000000000000012 0000000000000002 A 5 0 2
- [ 8] .gnu.version_r VERNEED 0000000000400408 00000408
- 0000000000000020 0000000000000000 A 6 1 8
- [ 9] .rela.dyn RELA 0000000000400428 00000428
- 0000000000000018 0000000000000018 A 5 0 8
- [10] .rela.plt RELA 0000000000400440 00000440
- 00000000000000c0 0000000000000018 AI 5 23 8
- [11] .init PROGBITS 0000000000400500 00000500
- 000000000000001a 0000000000000000 AX 0 0 4
- [12] .plt PROGBITS 0000000000400520 00000520
- 0000000000000090 0000000000000010 AX 0 0 16
- [13] .text PROGBITS 00000000004005b0 000005b0
- 0000000000000572 0000000000000000 AX 0 0 16
- [14] .fini PROGBITS 0000000000400b24 00000b24
- 0000000000000009 0000000000000000 AX 0 0 4
- [15] .rodata PROGBITS 0000000000400b30 00000b30
- 000000000000008a 0000000000000000 A 0 0 8
- [16] .eh_frame_hdr PROGBITS 0000000000400bbc 00000bbc
- 0000000000000074 0000000000000000 A 0 0 4
- [17] .eh_frame PROGBITS 0000000000400c30 00000c30
- 00000000000001f4 0000000000000000 A 0 0 8
- [18] .init_array INIT_ARRAY 0000000000601e10 00001e10
- 0000000000000008 0000000000000008 WA 0 0 8
- [19] .fini_array FINI_ARRAY 0000000000601e18 00001e18
- 0000000000000008 0000000000000008 WA 0 0 8
- [20] .jcr PROGBITS 0000000000601e20 00001e20
- 0000000000000008 0000000000000000 WA 0 0 8
- [21] .dynamic DYNAMIC 0000000000601e28 00001e28
- 00000000000001d0 0000000000000010 WA 6 0 8
- [22] .got PROGBITS 0000000000601ff8 00001ff8
- 0000000000000008 0000000000000008 WA 0 0 8
- [23] .got.plt PROGBITS 0000000000602000 00002000
- 0000000000000058 0000000000000008 WA 0 0 8
- [24] .data PROGBITS 0000000000602058 00002058
- 0000000000000004 0000000000000000 WA 0 0 1
- [25] .bss NOBITS 000000000060205c 0000205c
- 0000000000000004 0000000000000000 WA 0 0 1
- [26] .comment PROGBITS 0000000000000000 0000205c
- 000000000000002d 0000000000000001 MS 0 0 1
- [27] .debug_aranges PROGBITS 0000000000000000 00002089
- 0000000000000060 0000000000000000 0 0 1
- [28] .debug_info PROGBITS 0000000000000000 000020e9
- 0000000000000448 0000000000000000 0 0 1
- [29] .debug_abbrev PROGBITS 0000000000000000 00002531
- 00000000000001c5 0000000000000000 0 0 1
- [30] .debug_line PROGBITS 0000000000000000 000026f6
- 000000000000013d 0000000000000000 0 0 1
- [31] .debug_str PROGBITS 0000000000000000 00002833
- 0000000000000160 0000000000000001 MS 0 0 1
- [32] .symtab SYMTAB 0000000000000000 00002998
- 0000000000000858 0000000000000018 33 59 8
- [33] .strtab STRTAB 0000000000000000 000031f0
- 0000000000000336 0000000000000000 0 0 1
- [34] .shstrtab STRTAB 0000000000000000 00003526
- 0000000000000148 0000000000000000 0 0 1
- Key to Flags:
- W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
- L (link order), O (extra OS processing required), G (group), T (TLS),
- C (compressed), x (unknown), o (OS specific), E (exclude),
- l (large), p (processor specific)
我们使用readelf命令可以发现Stack以-g选项编译后程序中出现了debug信息
list :以默认形式显示代码
quit:退出gdb
r:开始调试,如果没有设置断点,就直接运行结束
b + 行号:给特定的行号打断点
info b:查看断点
d:删除断点
n:逐过程
s:逐语句
p + 变量名:打印变量内容
bt:查看函数调用堆栈
finish:将当前函数跑完
display:设置长显示
undisplay:取消长显示
until:跳转到指定行
c:运行到下一个断点停下来
显示代码
- (gdb) l 0
- 1 #include"Stack.h"
- 2
- 3 void test1()
- 4 {
- 5 ST st;
- 6 StackInit(&st);
- 7 printf("%d \n", StackSize(&st));
- 8 StackPush(&st, 1);
- 9 StackPush(&st, 2);
- 10 StackPush(&st, 3);
- (gdb)
- 11 StackPush(&st, 4);
- 12 StackPush(&st, 5);
- 13 printf("%d \n", StackSize(&st));
- 14 while (!StackEmpty(&st))
- 15 {
- 16 printf("%d ", StackTop(&st));
- 17 StackPop(&st);
- 18 }
- 19
- 20 printf("%d \n", StackSize(&st));
- (gdb)
- 21 StackDestroy(&st);
- 22
- 23
- 24 }
- 25
- 26 int main()
- 27 {
- 28 test1();
- 29 return 0;
- 30 }
- (gdb)
- Line number 31 out of range; test.c has 30 lines.
设置断点,查看断点
- Line number 31 out of range; test.c has 30 lines.
- (gdb) b 3
- Breakpoint 1 at 0x40098a: file test.c, line 3.
- (gdb) info b
- Num Type Disp Enb Address What
- 1 breakpoint keep y 0x000000000040098a in test1 at test.c:3
调用堆栈
- (gdb) bt
- #0 test1 () at test.c:6
- #1 0x0000000000400a9c in main () at test.c:28
打印变量内容
- (gdb) p st
- $1 = {a = 0x400ab0 <__libc_csu_init>, top = 4195760, capacity = 0}
以上就是今天要讲的内容。