原创博文,转载请注明出处。

GCC的编译过程分为预处理、生成汇编代码、生成目标代码和链接成可执行文件等4个步骤。

使用vim编写C 文件 : [lining@localhost program]$ vim hello.c 这样就会在program文件夹生成hello.c文件

编译C代码:使用如下命令“gcc 代码文件名”  如: [lining@localhost program]$ gcc hello.c 这样就会生成二进制可执行文件名称位a.out。

如果需要指定输出的文件名称,使用 “gcc -o 代码文件名” 如:[lining@localhost program]$ gcc -o hello hello.c 这样就会生存名称为hello的可执行文件。

[lining@localhost program]$ gcc -v -o hello hello.c 使用参数v可以显示GCC的工作整个过程。

编译C ++代码:与编译C 代码类似,只不过要把gcc换成g++。

使用GCC控制编译过程:

  1、预处理

该步骤完成宏和include展开工作。在GCC 中使用参数E可控制GCC完成预处理。

[lining@localhost program]$ gcc -E -o hello.pre.c hello.c 可通过查看hello.pre.c文件内容验证

2、生成汇编代码

编译器将预处理生成的代码进行处理,并根据编译参数进行优化,最后生成汇编代码。使用参数S。

[lining@localhost program]$ gcc -S hello.c 将生成名为hello.s的汇编代码。

  3、生成目标代码

目标代码生成阶段是把中间代码变换成特定机器上的绝对指令代码、可重定位的指令代码或汇编指令代码。GCC中使用参数c完成预编译、生成汇编代码和生成目标代码。

[lining@localhost program]$ gcc -c hello.c 将生成名为hello.o的目标代码。

  4、链接生成最终可执行代码

这一步相当与前面的程序编译。

  补充知识 :gcc -shared -fPIC -o 1.so 1.c

   这里有一个-fPIC参数,PIC就是position independent code,PIC使.so文件的代码段变为真正意义上的共享.

   如果不加-fPIC,则加载.so文件的代码段时,代码段引用的数据对象需要重定位, 重定位会修改代码段的内容,这就造成每个使用这个.so文件代码段的进程在内核里都会生成这个.so文件代码段的copy.每个copy都不一样,取决于 这个.so文件代码段和数据段内存映射的位置.不加fPIC编译出来的so,是要再加载时根据加载到的位置再次重定位的.(因为它里面的代码并不是位置无关代码)

   如果你的.so被多个应用程序共同使用,那么它们必须每个程序维护一份so的代码副本了.(因为so被每个程序加载的位置都不同,显然这些重定位后的代码也不同,当然不能共享)

我们总是用fPIC来生成so,也从来不用fPIC来生成a. fPIC与动态链接可以说基本没有关系,libc.so一样可以不用fPIC编译,只是这样的so必须要在加载到用户程序的地址空间时重定向所有表目.

          比如我们使用C在扩展python的时候 最好使用gcc -shared -fPIC -o来生成.so文件供python调用。

GNU Make项目管理

Make按照一定的规则对项目的源文件进行编译,并生成可执行的二进制文件。在使用gcc编译项目文件时,由于项目源文件代码很多,每次修改任何一个源代码文件都要重新编译和链接。

Make通过读入配置好的文本文件,并根据文本文件中预先定义的规则和步骤,完成代码的编译和链接工作,最终生成所需要的项目文件。这个文本文件在缺省情况下文件名为makefile或Makefile。Make程序的命令形式是 “make[选项]、[目标]...”,可通过make -h 查看所支持选项。

Make 在进行项目编译时会读makefile文件,比较该目标所依赖的源文件额日期和时间,以确定要编译的代码和相关的编译规则。当用户输入make命令后,Make将首先搜索该目录下是否存在makefile。如果没找到,则搜索名为makefile的文件,最后查找名为Makefile的文件。用户可通过 -f参数来指定makefile配置文件。

makefile的语法

  makefile文件由一组依赖关系和规则构成。每个依赖关系由一个目标(即将要创建的文件)和一组该目标所依赖的源文件组成。makefile的内容包含5个部分:显式规则,隐式规则,变量定义,指令和注释。

这里主要介绍变量和指令这两个主要的部分。

变量:区分大小写,与C/C++不同,定义变量不需要先声明。在定义变量后,如果要引用该变量,可以使用$(变量名)的形式访问该变量。

对上面的hello.c 编写带有变量定义的makefile

CC = gcc
hello : hello.c
$(CC) -o hello hello.c    //这儿需要注意,第二行的开头是tab字符,如果使用空格会在make命令下出现提示

完成编辑后,将其保存为makefile文件。在shell命令下输入make命令,编辑文件。

makefile中有一些预先设定的变量:

                     $@   表示当前规则中的目标文件名

$?     新修改过的依赖文件列表

$*      不包含扩展名的目标文件名

$<      当前规则中的第一个依赖文件名

$%     当目标文件为库文件时,该变量为库文件名;如果不是库文件,该变量为空值

$^      当前规则中的所有文件列表

AR     归档程序名称,默认为AR

ARFLAGS      归档程序选项

CC      C编译器命令名,默认为CC

CFLAGS     C编译器编译参数

   基于依赖关系的指定区:

依赖关系定义了最终应用程序里的每个文件与源文件之间的关系。规则的写法如下

目标(可能存在多个目标)... :空格或tab键 依赖条件(可能存在多个依赖条件,以空格或tab隔开)...

  举例如下:

myapp:    main.o .o .o
main.o: main.c a.h
.o: .c a.h b.h
.o: .c b.h c.h

它表示目标myapp依赖于main.o,2.o和3.o, 而main.o依赖于 main.c和a.h,等等。如果你没有指定目标的名字作为make命令的一个参数,make命令将第一个目标定义为all。

myapp:    main.o .o .o
gcc -o myapp main.o .o .o
main.o: main.c a.h
gcc -c main.c
.o: .c a.h b.h
gcc -c .c
.o: .c b.h c.h
gcc -c .c

当我们执行make -f makefile1(我们把创建的第一个makefile自定义命名),首先会检查其他的依赖关系,最终确定需要有一个文件main.c。在这里我们令头文件都是空文件,我们可以用touch命令来创建它们:

[lining@localhost program]$ touch a.h
[lining@localhost program]$ touch b.h
[lining@localhost program]$ touch c.h

   #include <stdlib.h>
#include <stdio.h>
#include "a.h"
extern void function_two();
extern void function_three();
void main()
{
function_two();
function_three();
printf("%s\n","This is a test");
}

2.c 和3.c

/* 2.c */
#include "a.h"
#include "b.h"
void function_two(){
}
/* 3.c */
#include "b.h"
#include "c.h"
void function_three(){
}

然后执行make命令:make -f makefile1生成目标文件myapp,再执行如下命令:

[lining@localhost program]$ ./myapp
This is a test
如果我们使用变量将使得我们在以后的维护过程中更加方面,我们把上面的makefile文件改造

CC=gcc
CFLAGS1=-o
CFLAGS2=-c
myapp: main.o .o .o
$(CC) $(CFLAGS1) $@ main.o .o .o
main.o: main.c a.h
$(CC) $(CFLAGS2) main.c
.o: .c a.h b.h
$(CC) $(CFLAGS2) .c
.o: .c b.h c.h
$(CC) $(CFLAGS2) .c
clean:
rm main.o
rm .o
rm .o

使用 clean 可将中间生成的文件做必要的清理,这样目标就没有依赖关系了。在正常情况下,如果没有告诉Make执行clean命令(make -f makefile1 clean),clean将永远不被执行。

Make在makefile中没有指明具体处理规则时会采用惯例来处理。例如,将后缀.c的文件编译为.o文件,也就说说我们不必写出将后缀.c的文件编译为.o文件的规则,Make命令就自动识别并执行。常见的隐含规则如下:

C 程序编译: .o文件自动由同名的.c文件生成,编译命令为: $(CC) -c $(CPPFLAGS) $(CFLAGS)

C++程序编译: .o文件自动由同名的.c文件或.cc文件生成,编译命令为:$(CXX) -c $(CPPFLAGS) $(CFLAGS)

  Pascal程序编译: .o文件自动由同名的.p生成,编译命令为:$(PC) -c $(PFLAGS)

makefile的模式规则:

Make支持编写模式规则来定义用户自己的隐含规则。相比于一般的规则,模式规则在形式上只是含有“%”的通配符(其功能类似于shell中的“*”)。如果确定了依赖关系中的“%”模式,Make就会按要求去匹配当前目录下的所有文件名,一旦找到符合规则的文件,Make就会执行该规则下的命令。如

%.o : %.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@

该模式规则表示当前目录下的所有以.c结尾的文件编译成以.o结尾的目标文件。宏$<将被扩展为起始文件的名字。而$@将被替换成生成的目标文件。

关于调试的知识将在以后的章节中介绍。

linux 编程技术No.1前期准备工作的更多相关文章

  1. linux 编程技术

    linux 编程技术No.1前期准备工作 GCC的编译过程分为预处理.生成汇编代码.生成目标代码和链接成可执行文件等4个步骤. 使用vim编写C 文件 : [lining@localhost prog ...

  2. linux脚本编程技术

    linux脚本编程技术 一.什么是脚本 脚本是一个包含一系列命令序列的可执行(777)文本文件.当运行这个脚本文件时,文件中包含的命令序列将得到自动执行. 二.脚本编程 #!/bin/sh 首行固定格 ...

  3. 深入理解linux网络技术内幕读书笔记(三)--用户空间与内核的接口

    Table of Contents 1 概论 1.1 procfs (/proc 文件系统) 1.1.1 编程接口 1.2 sysctl (/proc/sys目录) 1.2.1 编程接口 1.3 sy ...

  4. 初识B/S结构编程技术

    B/S结构编程语言 ASP(Active Server Page 动态服务器页面)技术 微软早期推出的B/S编程技术,出现在JSP和ASP.NET之前,PHP当时也很不稳定.ASP之前,动态网站使用G ...

  5. Linux编程之给你的程序开后门

    这里说的"后门"并不是教你做坏事,而是让你做好事,搭建自己的调试工具更好地进行调试开发.我们都知道,当程序发生异常错误时,我们需要定位到错误,有时我们还想,我们在不修改程序的前提下 ...

  6. Sikuli:创新的图形化编程技术

    Sikuli是一种使用截图进行UI自动化测试的技术.Sikuli包括sikul脚本,基于Jython的API以及sikuli IDE.Sikuli可以实现任何你可以在显示器上看到ui对象的自动化,你可 ...

  7. 笔记整理--Linux编程

    linux c编程open() read() write()函数的使用方法及实例 | 奶牛博客 - Google Chrome (2013/8/31 17:56:10) 今天把文件IO操作的一些东东整 ...

  8. Windows完成端口与Linux epoll技术简介

    收藏自:http://www.cnblogs.com/cr0-3/archive/2011/09/09/2172280.html WINDOWS完成端口编程1.基本概念2.WINDOWS完成端口的特点 ...

  9. 掌握Linux编程的10个步骤

    Linux 编程经典书籍推荐 Denis 2008年10月17日 浏览:84168 成为一名精通 Linux 程序设计的高级程序员一直是不少朋友孜孜以求的目标.根据中华英才网统计数据,北京地区 Lin ...

随机推荐

  1. (一)AngularJS获取贴纸Hello World

    一旦项目使用JQuery原创javascript,最近参加了一个项目,需要使用AngularJS.RequireJS比较框架,如汰渍. 这里写一些博客,记录自己的学习过程,虽然冠以原来的名字,资料,加 ...

  2. (转).net webconfig使用IConfigurationSectionHandler自定section

    自定义配置结构 (使用IConfigurationSectionHandler) 假设有以下的配置信息,其在MyInfo可以重复许多次,那么应如何读取配置呢?这时就要使用自定义的配置程序了.<m ...

  3. WebService返回DataTable问题

    今天做项目时,想在WebService中返回DataTable,在单位没成功,看网上有人说datable在.net1.1中是没有序列化的,不能直接在webservice中返回,可以返回dataset. ...

  4. Cocos2d-x 3.2 大富翁游戏项目开发-第五部分 单机游戏-级别选择ScrollView

    于MenuScene.cpp 点击单机游戏后会调用 Director::getInstance()->pushScene(MapChooseScene::createScene()); 进入到关 ...

  5. VC各种方法获得的窗口句柄

    AfxGetMainWnd AfxGetMainWnd获取窗口句柄本身 HWND hWnd = AfxGetMainWnd()->m_hWnd; GetTopWindow 功能:子窗体z序(Z序 ...

  6. 华为机试 之 joseph环

    一:首先科普一下约瑟夫问题的数学方法 (1)  不管是用list实现还是用vector实现都有一个共同点:要模拟整个游戏过程,不仅程序写起来比較烦,并且时间复杂度高达O(nm),当n,m很大(比如上百 ...

  7. java OutOfMorryError (replaceAll)

    最近在使用string类中的replaceAll函数时碰到这个错误,由于string长度比较长,文本文档9M多,可以增加jvm的内存大小解决. 下面是一篇对OutOfMorryError错误的一些处理 ...

  8. CSharp设计模式读书笔记(18):中介者模式(学习难度:★★★☆☆,使用频率:★★☆☆☆)

    中介者模式(Mediator Pattern):用一个中介对象(中介者)来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互,中介者模式又称为 ...

  9. 【百度地图API】多家地图API内存消耗对比测验(带源码)

    原文:[百度地图API]多家地图API内存消耗对比测验(带源码) 任务描述: 啊,美妙的春节结束了.酸奶小妹和妈妈的山西平遥之旅也宣告成功!距离平遥古城7km,有一个同样身为“世界文化遗产”的寺庙,叫 ...

  10. poj 2828 线段树

    http://poj.org/problem?id=2828 学到的思维: 1.变化的或者后来的优先影响前面的,那么从最后一个往前看,最后一个就成了 确定的, 而且后来的也能够确定----假设从前往后 ...