gcc和make浅析(转载)

  参考资料:

  https://blog.csdn.net/sfuncc/article/details/80185007

      https://blog.csdn.net/yc461515457/article/details/50907393

  在做计网实验的时候用到、了解了两个工具:gcc和make。gcc就是UNIX系统下常用的C语言编译器,在Mac上也有类似的工具:clang,调用clang的命令可以是cc,CC,gcc(自己试验的结果,好像都是调用了clang,存疑),一般是cc就可以。make - GNU make utility to maintain groups of programs,主要就是用来编译链接大型的C语言家族程序了。使用的时候在目录里创建一个Makefile文件,然后直接在commandline里输入make回车,就可以自动进行编译。为了深入了解这两个大杀器,我找到了这两篇文章。讲的十分详细,言简意赅。下面是其中两篇的镜像(仅供学习)。

 

如果你还没装编译环境或自己不确定装没装,不妨先执行

sudo apt-get install build-essential

如果你需要编译 Fortran 程序,那么还需要安装 gfortran(或 g77)

sudo apt-get install gfortran

注:针对Linux系统下,Mac上利用Xcode安装的commandline tools自带了一堆工具,其实就包含了很多Unix的程序,效果相似。

编译简单的 C 程序

C 语言经典的入门例子是 Hello World,下面是一示例代码:

#include <stdio.h> 
int 
main(void) 
{ 
printf("Hello, world!\n");
return 0;
}

我们假定该代码存为文件‘hello.c’。要用 gcc 编译该文件,使用下面的命令:(Mac上使用cc即可)

$ gcc -g -Wall hello.c -o hello

该命令将文件‘hello.c’中的代码编译为机器码并存储在可执行文件 ‘hello’中。机器码的文件名是通过 -o 选项指定的。该选项通常作为命令行中的最后一个参数。如果被省略,输出文件默认为 ‘a.out’。

注意到如果当前目录中与可执行文件重名的文件已经存在,它将被覆盖。

选项 -Wall 开启编译器几乎所有常用的警告──强烈建议你始终使用该选项。编译器有很多其他的警告选项,但 -Wall 是最常用的。默认情况下GCC 不会产生任何警告信息。当编写 C 或 C++ 程序时编译器警告非常有助于检测程序存在的问题。

本例中,编译器使用了 -Wall 选项而没产生任何警告,因为示例程序是完全合法的。

选项 "-g" 表示在生成的目标文件中带调试信息,调试信息可以在程序异常中止产生core后,帮助分析错误产生的源头,包括产生错误的文件名和行号等非常多有用的信息。

要运行该程序,输入可执行文件的路径如下:

$ ./hello
Hello, world!

这将可执行文件载入内存,并使 CPU 开始执行其包含的指令。 路径 ./ 指代当前目录,因此 ./hello 载入并执行当前目录下的可执行文件 ‘hello’。  

捕捉错误

如上所述,当用 C 或 C++ 编程时,编译器警告是非常重要的助手。为了说明这一点,下面的例子包含一个微妙的错误:为一个整数值错误地指定了一浮点数控制符‘%f’。

#include <stdio.h> 

int main (void) 
{ 
printf ("Two plus two is %f\n", 4);
return 0;
}

一眼看去该错误并不明显,但是它可被编译器捕捉到,只要启用了警告选项 -Wall。

编译上面的程序‘bad.c’,将得到如下的消息:

$ gcc -Wall -o bad bad.c
main.c: 在函数‘main’中:
main.c:5: 警告: 格式‘%f’需要类型‘double’,但实参 2 的类型为‘int

这表明文件 ‘bad.c’第 6 行中的格式字符串用法不正确。GCC 的消息总是具有下面的格式 文件名:行号:消息。编译器对错误与警告区别对待,前者将阻止编译,后者表明可能存在的问题但并不阻止程序编译。

本例中,对整数值来说,正确的格式控制符应该是 %d。

如果不启用 -Wall,程序表面看起来编译正常,但是会产生不正确的结果:

$ gcc bad.c -o bad
$ ./bad
Two plus two is 0.000000

显而易见,开发程序时不检查警告是非常危险的。如果有函数使用不当,将可能导致程序崩溃或产生错误的结果。开启编译器警告选项 -Wall 可捕捉 C 编程时的多数常见错误。

编译多个源文件

一个源程序可以分成几个文件。这样便于编辑与理解,尤其是程序非常大的时候。这也使各部分独立编译成为可能。

下面的例子中我们将程序 Hello World 分割成 3 个文件:‘hello.c’,‘hello_fn.c’和头文件‘hello.h’。这是主程序‘hello.c’:

#include "hello.h" 
int 
main(void) 
{ 
hello ("world");
return 0;
}

在先前例子的‘hello.c’中,我们调用的是库函数 printf,本例中我们用一个定义在文件‘hello_fn.c’中的函数 hello 取代它。

主程序中包含有头文件‘hello.h’,该头文件包含函数 hello 的声明。我们不需要在‘hello.c’文件中包含系统头文件‘stdio.h’来声明函数 printf,因为‘hello.c’没有直接调用 printf。

文件‘hello.h’中的声明只用了一行就指定了函数 hello 的原型。

void hello (const char * name);

函数 hello 的定义在文件‘hello_fn.c’中:

#include <stdio.h> 
#include "hello.h" 

void 
hello (const char * name) 
{ 
printf ("Hello, %s!\n", name);
}

语句 #include "FILE.h" 与 #include <FILE.h> 有所不同:前者在搜索系统头文件目录之前将先在当前目录中搜索文件‘FILE.h’,后者只搜索系统头文件而不查看当前目录。

要用gcc编译以上源文件,使用下面的命令:

$ gcc -Wall hello.c hello_fn.c -o newhello

本例中,我们使用选项 -o 为可执行文件指定了一个不同的名字 newhello。注意到头文件‘hello.h’并未在命令行中指定。源文件中的的 #include "hello.h" 指示符使得编译器自动将其包含到合适的位置。

要运行本程序,输入可执行文件的路径名:

$ ./newhello
Hello, world!

源程序各部分被编译为单一的可执行文件,它与我们先前的例子产生的结果相同。


 

分割线:这篇文章的后面部分讲的比较深入,关于Makefile文件和其他链接编译操作,我没有截取。接下来是另一篇参考资料里关于Makefile的讲解:


 

从头讲一门工具总是显得很难,我们先从一个小项目切入。

我这里找了一超轻量级的项目:tinyhttpd。
tinyhttpd全文代码仅有502行,用来学习http server非常不错。通过它,你可以了解到http服务器的本质。
https://sourceforge.net/projects/tinyhttpd/
https://download.csdn.net/download/sfuncc 解压出来

makefile的由来  

  makefile,make+file,makefile就是make程序的配置文件。makefile可以看成是加强版的shell,shell里面能用的命令,在makefile里也可以。Makefile书写规则,如下图。由target+dependencis组合称为一个执行单元。

[编译命令 "gcc -o ....."前,一定摁下一个TAB键。别敲空格,没用的。。。]

看看tinyhttpd的makefil是怎么写的,一样的风格,没有冗余,简单明了。

  • -W: 关闭编译警告
  • -Wall: 打开编译警告
  • -lpthread:l指link,链接pthread库
  • -o: o指output,输出目标

  把’-lsocket’删了,因为这个程序有点老,1999年写的,现在默认有了socket这个库。保存退出,make编译即可。如上面说的规则,tinyhttpd的makefile中有3个执行单元,分别是all,httpd和clean。

分析别人的程序,先找到它的执行顺序。makefile是解释执行的,从上往下。

 ①make先找到第一个规则all
 ②all需要httpd。httpd没有或被修改?跳到③:后面的③④⑤都不会执行。
 ③httpd需要httpd.c,httpd.c没有或被修改? 执行⑤:报错No rule to make target ‘httpd’

 ⑥clean不需要别人,他就默认不会执行。除非命令行用:make clean。
 
不知道我讲清楚执行流程没有。
有点印象的话,我们把客户端程序(simpleclient.c)也加进去编译。

更进一步

①②③的效果是一样的。都是基于上一步跟进的,编写的复杂度也增加,也越来越像你到的牛逼的、华丽的makefile。

posted @ 2019-11-15 09:46  思念殇千寻  阅读(1614)  评论(0编辑  收藏  举报