Linux基础环境开发工具gcc/g++ make/Makefile git

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 hello

gcc默认生成的二进制程序,是动态链接的,这点可以通过 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文件

  • 20
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值