您的位置:新葡亰496net > 电脑系统 > Linux系统平台下关于GCC编译及使用的方法,关于

Linux系统平台下关于GCC编译及使用的方法,关于

发布时间:2019-09-23 03:49编辑:电脑系统浏览(105)


     

     

     

    编译: 第一步、是进行预编译,使用-E参数可以让GCC在预处理结束后停止编译过程:
    gcc -E hello.c -o hello.i
    预处理的宏定义插入到hello.i中

    今天偶然看到这篇文章,做个入门了解还是不错的。

    编译:

    编译:

    Linux下的C编程实战(一)

    第二步、是将hello.i编译为目标代码,这可以通过使用-c参数来完成:
    gcc -c hello.i -o hello.o
    也可以通过源文件直接生成
    gcc -c hello.c


    第一步、是进行预编译,使用-E参数可以让GCC在预处理结束后停止编译过程:

    第一步、是进行预编译,使用-E参数可以让GCC在预处理结束后停止编译过程:

    ――开发平台搭建

    第三步、是将生成的目标文件链接成可执行文件:
    gcc hello.o -o hello
    也可以通过源文件直接生成
    gcc -o hello hello.c

    前一阵子在QQ上和朋友聊天的时候,总会看到有人说Linux上的应用程序开发是高手才可以完成的,而且这种“迷信”在目前似乎还很普遍。然而,情况并不是这样的,从程序库的支持方面,Linux平台为用户级应用程序的开发提供了很多功能强大且丰富的程序库,而且它们大部分是跨平台的(Boost、OpenGL、STL、Qt、Java等)和基于POSIX标准的(glibc等),同时Linux内核还为驱动程序的开发提供了功能完备的内核接口,从开发工具方面,Linux提供了功能强大的编译器GCC和调试器GDB,借助它们的帮助,我们可以很轻松的在Linu x上开发出可移植性的应用程序。既然如此,“迷信”又源于何来呢?我想,一方面由于详细介绍Linux各种开发的书籍较少,各种Linux应用在国内仍不普及,另一方面则是由于很多人在安装好一个Linux后,苦于找不到一个得心应手的IDE环境,从而感到不知所措,毕竟,我们很多人都习惯了写好程序后,按下F5,剩下的任务就让IDE全权代理了。其实想在Linux下如此这般当然也没问题。既然说到了IDE,就让我们从它开始吧,相信选择一个好的IDE环境是你整个学习过程的一个不错的开始。

    gcc -E hello.c -o hello.i

    gcc -E hello.c -o hello.i

     

    警告:
    1、-pedantic 选项,那么使用了扩展语法的地方将产生相应的警告信息
    2、-Wall 使用它能够使GCC产生尽可能多的警告信息
    3、-Werror,它要求GCC将所有的警告当成错误进行处理

     

    预处理的宏定义插入到hello.i中

    预处理的宏定义插入到hello.i中

    .GCC编译器

    库依赖:
    1、Linux下的大多数函数都默认:
    头文件放到/usr/include/目录下
    而库文件则放到/usr/lib/目录下
    2、GCC在编译时必须有自己的办法来查找所需要的头文件和库文件。
    -I选项可以向GCC的头文件搜索路径中添加新的目录。
    例如,如果在/home/yy/include/目录下有编译时所需要的头文件,为了让GCC能够顺利地找到它们,就可以使用-I选项:
    gcc -o test test.c -I /home/yy/include


    第二步、是将hello.i编译为目标代码,这可以通过使用-c参数来完成:

    第二步、是将hello.i编译为目标代码,这可以通过使用-c参数来完成:

           GCC是Linux平台下最重要的开发工具,它是GNU的C和C 编译器,其基本用法为:

    -L选项向GCC的库文件搜索路径中添加新的目录
    例如,如果在/home/yy/lib/目录下有链接时所需要的库文件libfoo.so,为了让GCC能够顺利地找到它,可以使用下面的命令
    gcc -o test test.c -L /home/yy/lib -lfoo

     

    gcc -c hello.i -o hello.o

    gcc -c hello.i -o hello.o

    gcc [options] [filenames]

    值得好好解释一下的是-l选项,它指示GCC去连接库文件libfoo.so。
    Linux下的库文件在命名时有一个约定,那就是应该以lib三个字母开头,由于所有的库文件都遵循了同样的规范,因此在用-l选项指定链接的库文件名时可以省去lib三个字母,也就是说GCC在对-lfoo进行处理时,会自动去链接名为libfoo.so的文件。

    工欲善其事 必先利其器——IDE篇

    也可以通过源文件直接生成

    也可以通过源文件直接生成

    options为编译选项,GCC总共提供的编译选项超过100个,但只有少数几个会被频繁使用,我们仅对几个常用选项进行介绍。

    -static选项,强制使用静态链接库
    如果在/home/yy/lib/目录下有链接时所需要的库文件libfoo.so和libfoo.a
    为了让GCC在链接时只用到静态链接库,可以使用下面的命令:
    gcc -o  test  test.c  -L /home/yy/lib  -static  -lfoo

    其实Linux下有许多功能强大的IDE环境,因为从某种意义上说,Linux是专为开发者准备的操作系统,这个东西当然少不了,在这里为读者介绍一些比较常用的IDE。

    gcc -c hello.c

    gcc -c hello.c

    假设我们编译一输出“Hello World”的程序:

    编译成动态库:

    KDevelop

    第三步、是将生成的目标文件链接成可执行文件:

    第三步、是将生成的目标文件链接成可执行文件:

    Linux系统平台下关于GCC编译及使用的方法,关于Linux操作系统下GCC的使用方法说明。/* Filename:helloworld.c */

    g   -fPIC  -shared  -o libfunc.so  func.cpp

    这是一个用Qt开发的IDE,其主要支持的语言是C / C ,

    gcc hello.o -o hello

    gcc hello.o -o hello

    main()

    -fPIC参数
    表示编译为位置独立的代码,用于编译共享库。目标文件需要创建成位置无关码,概念上就是在可执行程序装载它们的时候,它们可以放在可执行程序的内存里的任何地方。

    Eclipse

    也可以通过源文件直接生成

    也可以通过源文件直接生成

    {

    选项-O可以告诉GCC同时减小代码的长度和执行时间,其效果等价于-O1。
    在这一级别上能够进行的优化类型虽然取决于目标处理器,但一般都会包括线程跳转(Thread Jump)和延迟退栈(Deferred Stack Pops)两种优化。

    近年来,eclipse可以说发展极为迅速,它不仅是一个以java为主的开发平台,其功能强大的插件体系结构使得它可以被当作各种应用程序来使用。作为各种插件的载体,eclipse提供了完整的GUI接口,用户完全可以借助eclipse来只关心自己想做的工作。

    gcc -o hello hello.c

    gcc -o hello hello.c

        printf("Hello World"n");

    选项-O2告诉GCC除了完成所有-O1级别的优化之外,同时还要进行一些额外的调整工作,如处理器指令调度等。

    Emacs

    警告:

    警告:

    }

    选项-O3则除了完成所有-O2级别的优化之外,还包括循环展开和其它一些与处理器特性相关的优化工作。

    VIM

    1、-pedantic 选项,那么使用了扩展语法的地方将产生相应的警告信息

    1、-pedantic 选项,那么使用了扩展语法的地方将产生相应的警告信息

    最简单的编译方法是不指定任何编译选项:

    通常来说,数字越大优化的等级越高,同时也就意味着程序的运行速度越快。


    2、-Wall 使用它能够使GCC产生尽可能多的警告信息

    2、-Wall 使用它能够使GCC产生尽可能多的警告信息

    gcc helloworld.c

    许多Linux程序员都喜欢使用-O2选项,因为它在优化长度、编译时间和代码大小之间,取得了一个比较理想的平衡点。

    山高月晓 水落石出——IDE后台的故事 GCC篇

    3、-Werror,它要求GCC将所有的警告当成错误进行处理

    3、-Werror,它要求GCC将所有的警告当成错误进行处理

    它会为目标程序生成默认的文件名a.out,我们可用-o编译选项来为将产生的可执行文件指定一个文件名来代替a.out。例如,将上述名为

    time ./test 查看程序执行时间

    前面我们简要介绍了一些IDE环境,其中所有C/C 相关程序的编译都是由GCC来完成的,而IDE只不过起到了一个收集编译信息和为我们的项目生成makefile等作用(后面我们会提到)。出于目前Linux开发的特点,C仍是系统开发的主流语言。所以,对GCC有一个全面的了解是很有必要的,一旦IDE不能满足你的需求,我们要有手工打造程序的能力,而且出于学习的目的,我们往往不需要IDE生成的那些复杂的文件,为一个Hello world生成2M多的文件显然是多余的。

    库依赖:

    库依赖:

    helloworld.c的C程序编译为名叫helloworld的可执行文件,需要输入如下命令:

    优化虽然能够给程序带来更好的执行性能,但在如下一些场合中应该避免优化代码:

    GCC的全称是GNU Compiler Collection,从这个名字我们不难看出,GCC代表着一个编译器的集合,目前GCC可以支持C, C , Objective-C, Objective-C , Fortran, Java, and Ada等语言。但是出于一般性考虑,我们这里只讨论GCC中的C/C 部分。

    1、Linux下的大多数函数都默认:

    1、Linux下的大多数函数都默认:

    gcc –o helloworld helloworld.c

    程序开发的时候优化等级越高,消耗在编译上的时间就越长,因此在开发的时候最好不要使用优化选项,只有到软件发行或开发结束的时候,才考虑对最终生成的代码进行优化。

    目前GCC的最新发布版是4.0.0,但是这个版本由于使用了新技术和新的编码规范,很多旧的代码都需要修改才可以通过编译,所以并不推荐使用这个版本。而相对稳定的新版本目前是3.4.4,大家可以到GNU的主页上更新下载。那么究竟GCC强大在哪里,如何使用?下面我就通过几个简单而实际的例子带你看看GCC提供的强大功能。

    头文件放到/usr/include/目录下

    头文件放到/usr/include/目录下

    -c选项告诉GCC仅把源代码编译为目标代码而跳过汇编和连接的步骤;

    资源受限的时候一些优化选项会增加可执行代码的体积,如果程序在运行时能够申请到的内存资源非常紧张(如一些实时嵌入式设备),那就不要对代码进行优化,因为由这带来的负面影响可能会产生非常严重的后果。


    而库文件则放到/usr/lib/目录下

    而库文件则放到/usr/lib/目录下

    -S 编译选项告诉GCC 在为C代码产生了汇编语言文件后停止编译。GCC 产生的汇编语言文件的缺省扩展名是.s,上述程序运行如下命令:

    跟踪调试的时候在对代码进行优化的时候,某些代码可能会被删除或改写,或者为了取得更佳的性能而进行重组,从而使跟踪和调试变得异常困难。
    加速:
    新葡亰496net,使用管道代替编译中临时文件,
    -pipe 加速编译
    gcc -pipe foo.c -o foo

     

    2、GCC在编译时必须有自己的办法来查找所需要的头文件和库文件。

    2、GCC在编译时必须有自己的办法来查找所需要的头文件和库文件。

    gcc –S helloworld.c

    GCC常用选项
    -c 通知GCC取消链接步骤,即编译源码并在最后生成目标文件;

    通过Helloworld的编译熟悉GCC的基本使用方法

    -I选项可以向GCC的头文件搜索路径中添加新的目录。

    -I选项可以向GCC的头文件搜索路径中添加新的目录。

    将生成helloworld.c的汇编代码,使用的是AT&T汇编。用emacs打开汇编代码如下图:

    -Dmacro 定义指定的宏,使它能够通过源码中的#ifdef进行检验;

    似乎为所有新语言提供一个Hello World样本程序已经成为了一种不成文的标准,人们通过它来认识语言的一些基本要素。在这里,我们使用一个Hello World来看看如何用GCC生成可执行文件。

    例如,如果在/home/xiaowp/include/目录下有编译时所需要的头文件,为了让GCC能够顺利地找到它们,就可以使用-I选项:

    例如,如果在/home/xiaowp/include/目录下有编译时所需要的头文件,为了让GCC能够顺利地找到它们,就可以使用-I选项:

     

    -E 不经过编译预处理程序的输出而输送至标准输出;

    1 #include<stdio.h>
    2 
    3 int main()
    4 {
    5     printf("hello world!rn");
    6     return 0;
    7 }
    

    gcc -o test test.c -I /home/xiaowp/include

    gcc -o test test.c -I /home/xiaowp/include

    -E选项指示编译器仅对输入文件进行预处理。当这个选项被使用时,预处理器的输出被送到标准输出(默认为屏幕)而不是储存在文件里。

    -g3 获得有关调试程序的详细信息,它不能与-o选项联合使用;

    把上面的文件存成helloworld.c,之后打开控制台,输入如下的命令

    -L选项向GCC的库文件搜索路径中添加新的目录

    -L选项向GCC的库文件搜索路径中添加新的目录

    -O选项告诉GCC对源代码进行基本优化从而使得程序执行地更快;而-O2选项告诉GCC产生尽可能小和尽可能快的代码。使用-O2选项编译的速度

    -Idirectory 在包含文件搜索路径的起点处添加指定目录;

    gcc helloworld.c –o helloworld

    例如,如果在/home/xiaowp/lib/目录下有链接时所需要的库文件libfoo.so,为了让GCC能够顺利地找到它,可以使用下面的命令

    例如,如果在/home/xiaowp/lib/目录下有链接时所需要的库文件libfoo.so,为了让GCC能够顺利地找到它,可以使用下面的命令

    比使用-O时慢,但产生的代码执行速度会更快。

    -llibrary 提示链接程序在创建最终可执行文件时包含指定的库;

    如果一切正常的话,你的控制台上应该没有任何输出。用ls查看你的工作目录,你会发现目录下多了一个名为helloworld的可执行文件,之后,执行

    gcc -o test test.c -L /home/xiaowp/lib -lfoo

    gcc -o test test.c -L /home/xiaowp/lib -lfoo

    -g选项告诉GCC产生能被GNU调试器使用的调试信息以便调试你的程序,可喜的是,在GCC里,我们能联用-g和-O (产生优化代码)。

    -O、-O2、-O3 将优化状态打开,该选项不能与-g选项联合使用;

    ./hellworld

    值得好好解释一下的是-l选项,它指示GCC去连接库文件libfoo.so。

    值得好好解释一下的是-l选项,它指示GCC去连接库文件libfoo.so。

    -pg选项告诉GCC在你的程序里加入额外的代码,执行时,产生gprof用的剖析信息以显示你的程序的耗时情况。

    -S 要求编译程序生成来自源代码的汇编程序输出;

    就会看到这个程序的输出了

    Linux下的库文件在命名时有一个约定,那就是应该以lib三个字母开头,由于所有的库文件都遵循了同样的规范,因此在用-l选项指定链接的库文件名时可以省去lib三个字母,也就是说GCC在对-lfoo进行处理时,会自动去链接名为libfoo.so的文件。

    Linux下的库文件在命名时有一个约定,那就是应该以lib三个字母开头,由于所有的库文件都遵循了同样的规范,因此在用-l选项指定链接的库文件名时可以省去lib三个字母,也就是说GCC在对-lfoo进行处理时,会自动去链接名为libfoo.so的文件。

    3.GDB调试器

    -v 启动所有警报;

    很简单不是吗?但是学过计算机的朋友都应该知道,程序的编译过程要分为下图所示的过程而GCC的强大之处就在于它允许你在上面所示的任何一个过程中停下来查看中间结果,并对其加以控制。

    -static选项,强制使用静态链接库

    -static选项,强制使用静态链接库

           GCC用于编译程序,而Linux的另一个GNU工具gdb则用于调试程序。gdb是一个用来调试C和C 程序的强力调试器,我们能通过它进行一

    -Wall 在发生警报时取消编译操作,即将警报看作是错误;

    1. 预处理

    如果在/home/xiaowp/lib/目录下有链接时所需要的库文件libfoo.so和libfoo.a

    如果在/home/xiaowp/lib/目录下有链接时所需要的库文件libfoo.so和libfoo.a

    系列调试工作,包括设置断点、观查变量、单步等。

    -Werror 在发生警报时取消编译操作,即把报警当作是错误;

    首先是预处理过程,GCC的-E选项可以让GCC在预处理后停止编译,并向标准输出打印预处理过后的文件。下面的-o用于指定输出文件的文件名。

    为了让GCC在链接时只用到静态链接库,可以使用下面的命令:

    为了让GCC在链接时只用到静态链接库,可以使用下面的命令:

    其最常用的命令如下:

    -w 禁止所有的报警。  

    gcc –E hellowrold.c –o helloworld.cpp

    gcc -o test test.c -L /home/xiaowp/lib -static -lfoo

    gcc -o test test.c -L /home/xiaowp/lib -static -lfoo

    file:装入想要调试的可执行文件。

    静态链接

    下面是helloworld.cpp的一部分的内容,我们看到,文件已经包含了stdio.h中的内容。

    选项-O可以告诉GCC同时减小代码的长度和执行时间,其效果等价于-O1。

    选项-O可以告诉GCC同时减小代码的长度和执行时间,其效果等价于-O1。

    kill:终止正在调试的程序。

      在这种连接方式下,函数的代码将直接拷贝到最终的可执行文件中。该程序被执行时候,会被装入该进程的虚拟地址空间中。静态链接库实际上是一个或若干目标文件。 

    如果我们想执行下一步的编译过程,可以继续使用GCC的-x <language type>选项,该选项用于显示指定文件的后缀名(而不是让编译器根据后缀来自行判断)。我们比较常用的language type有如下几种,(如果读者想获得更为完整参数说名,请参考GCC manual):

    在这一级别上能够进行的优化类型虽然取决于目标处理器,但一般都会包括线程跳转(Thread Jump)和延迟退栈(Deferred Stack Pops)两种优化。

    在这一级别上能够进行的优化类型虽然取决于目标处理器,但一般都会包括线程跳转(Thread Jump)和延迟退栈(Deferred Stack Pops)两种优化。

    list:列表显示源代码。

    动态链接

    l         c c-header c-cpp-output

    选项-O2告诉GCC除了完成所有-O1级别的优化之外,同时还要进行一些额外的调整工作,如处理器指令调度等。

    选项-O2告诉GCC除了完成所有-O1级别的优化之外,同时还要进行一些额外的调整工作,如处理器指令调度等。

    next:执行一行源代码但不进入函数内部。

      这种方式下,函数的代码被放到称作动态连接库或共享对象的某个目标文件中。链接程序此时的工作只是在生成的可执行文件中,记录下共享对象的名字以及少量关键信息。动态连接库可以被多个进程共享,在运行时候内存中只有一个实例。 

    l         c c -header c -cpp-output

    选项-O3则除了完成所有-O2级别的优化之外,还包括循环展开和其它一些与处理器特性相关的优化工作。

    选项-O3则除了完成所有-O2级别的优化之外,还包括循环展开和其它一些与处理器特性相关的优化工作。

    step:执行一行源代码而且进入函数内部。

    二者比较

    l         assembler assembler-with-cpp

    通常来说,数字越大优化的等级越高,同时也就意味着程序的运行速度越快。

    通常来说,数字越大优化的等级越高,同时也就意味着程序的运行速度越快。

    run:执行当前被调试的程序

      使用动态链接能够使可执行文件较小,并且当共享对象被多个进程使用时节省内存。但有时候系统运行改变或升级,不能保证动态连接库一定可用、有效。

    另外,下表列出了常用的GCC后缀名

    许多Linux程序员都喜欢使用-O2选项,因为它在优化长度、编译时间和代码大小之间,取得了一个比较理想的平衡点。

    许多Linux程序员都喜欢使用-O2选项,因为它在优化长度、编译时间和代码大小之间,取得了一个比较理想的平衡点。

    quit:终止gdb

    新葡亰496net 1

    文件后缀

    注释

    .c

    需要经过预处理的C代码文件

    .i

    不需要经过预处理的C代码文件

    .ii

    不需要经过预处理的C 代码文件

    .h

    需要被预编译的C, C , Objective-C头文件

    .cc .cp .cxx .cpp .CPP .c .C

    需要被预处理的C 程序文件

    .hh .H

    需要被预编译的C 头文件

    .s

    汇编代码文件

    .S

    需要被预处理的汇编文件

    time ./test 查看程序执行时间

    time ./test 查看程序执行时间

    watch:监视一个变量的值

     

    优化虽然能够给程序带来更好的执行性能,但在如下一些场合中应该避免优化代码:

    优化虽然能够给程序带来更好的执行性能,但在如下一些场合中应该避免优化代码:

    break:在代码里设置断点,程序执行到这里时挂起

     

    程序开发的时候优化等级越高,消耗在编译上的时间就越长,因此在开发的时候最好不要使用优化选项,只有到软件发行或开发结束的时候,才考虑对最终生成的代码进行优化。

    程序开发的时候优化等级越高,消耗在编译上的时间就越长,因此在开发的时候最好不要使用优化选项,只有到软件发行或开发结束的时候,才考虑对最终生成的代码进行优化。

    make:不退出gdb而重新产生可执行文件

    当然,你也可以省略掉language type的部分,这时候GCC会根据文件的后缀名自行判断,就像你没有使用该选项一样。

    资源受限的时候一些优化选项会增加可执行代码的体积,如果程序在运行时能够申请到的内存资源非常紧张(如一些实时嵌入式设备),那就不要对代码进行优化,因为由这带来的负面影响可能会产生非常严重的后果。

    资源受限的时候一些优化选项会增加可执行代码的体积,如果程序在运行时能够申请到的内存资源非常紧张(如一些实时嵌入式设备),那就不要对代码进行优化,因为由这带来的负面影响可能会产生非常严重的后果。

    shell:不离开gdb而执行shell

    下面继续我们的编译过程

    跟踪调试的时候在对代码进行优化的时候,某些代码可能会被删除或改写,或者为了取得更佳的性能而进行重组,从而使跟踪和调试变得异常困难。

    跟踪调试的时候在对代码进行优化的时候,某些代码可能会被删除或改写,或者为了取得更佳的性能而进行重组,从而使跟踪和调试变得异常困难。

    下面我们来演示怎样用GDB来调试一个求0 1 2 3 … 99的程序:

    2. 编译

    加速:

    加速:

    /* Filename:sum.c */

    如果我们想获得编译后的源文件可以使用-S选项,该选项让gcc只执行编译(生成汇编文件)而不进行汇编(生成目标文件),此时,我们可以用-o选项指定输出的汇编文件的名称。

    使用管道代替编译中临时文件,

    使用管道代替编译中临时文件,

    main()

    gcc –S helloworld.cpp –o hellowrld.S

    -pipe 加速编译

    -pipe 加速编译

    {

    3. 汇编

    gcc -pipe foo.c -o foo

    gcc -pipe foo.c -o foo

      int i, sum;

    另外,我们还可以使用GCC的-c选项来编译和汇编源文件而不链接,此时-o指定的输出文件就是编译后的目标文件名

    GCC常用选项

    GCC常用选项

     

    gcc –x c -c helloworld.cpp –o helloworld.o

    -c 通知GCC取消链接步骤,即编译源码并在最后生成目标文件;

    -c 通知GCC取消链接步骤,即编译源码并在最后生成目标文件;

     sum = 0;

    4. 链接

    -Dmacro 定义指定的宏,使它能够通过源码中的#ifdef进行检验;

    -Dmacro 定义指定的宏,使它能够通过源码中的#ifdef进行检验;

      for (i = 0; i < 100; i )

    最后,我们可以利用GCC来把我们刚才生成的.o文件链接成可执行程序

    -E 不经过编译预处理程序的输出而输送至标准输出;

    -E 不经过编译预处理程序的输出而输送至标准输出;

      {

    gcc helloworld.o –o helloworld

    -g3 获得有关调试程序的详细信息,它不能与-o选项联合使用;

    -g3 获得有关调试程序的详细信息,它不能与-o选项联合使用;

        sum   = i;

    这一次,我们使用了-o选项指定了可执行文件名,也就是说,根据输入文件类型的不同,-o有着不同的含义。

    -Idirectory 在包含文件搜索路径的起点处添加指定目录;

    -Idirectory 在包含文件搜索路径的起点处添加指定目录;

     }

    5. 函数库的链接和包含文件

    -llibrary 提示链接程序在创建最终可执行文件时包含指定的库;

    -llibrary 提示链接程序在创建最终可执行文件时包含指定的库;

     

    对于我们编写的任和一个程序,没有库函数的支持是不可想象的,而当我们要使用的头文件和函数库不在GCC默认的搜索路径下的时候(例如OpenGL、Qt、KDE、Boost等),我们就需要手工来告诉GCC他们的位置。

    -O、-O2、-O3 将优化状态打开,该选项不能与-g选项联合使用;

    -O、-O2、-O3 将优化状态打开,该选项不能与-g选项联合使用;

      printf("the sum of 1 2 ... is %d", sum);

    先来看头文件路径的指定。我们可以利用-I<dir_name>来指定我们希望GCC去搜索的头文件目录,例如我们要使用X11的程序,我们就要使用下面的选项

    -S 要求编译程序生成来自源代码的汇编程序输出;

    -S 要求编译程序生成来自源代码的汇编程序输出;

    }

    再来看库函数的设置:我们通过-L<dir_name>和-l<lib_name>两个命令行选项完成任务。其中-L用于告诉GCC在<dir_name>中去寻找函数库,而-l选项则告诉GCC使用用户指定的程序库。在Linux中,函数库的命名是遵循UNIX约定的,即lib{lib name},例如libsocket.so,所以当你需要告诉GCC使用这些库的时候,你就可以使用-lsocket选项。通常,这两个命令是结合在一起使用的,例如引用X11程序库的时候,我们可以这样:

    -v 启动所有警报;

    -v 启动所有警报;

    执行如下命令编译sum.c(加-g选项产生debug信息):

    –L/usr/X11R6/lib –lX11

    -Wall 在发生警报时取消编译操作,即将警报看作是错误;

    -Wall 在发生警报时取消编译操作,即将警报看作是错误;

    gcc –g –o sum sum.c

    另外,GCC在默认情况下使用共享库来链接程序,而当你想链接静态库的时候,一定要使用-static选项,例如-lncurses -static

    -Werror 在发生警报时取消编译操作,即把报警当作是错误;

    -Werror 在发生警报时取消编译操作,即把报警当作是错误;

    在命令行上键入gdb sum并按回车键就可以开始调试sum了,再运行run命令执行sum,屏幕上将看到如下内容:

    在这一部分的最后,我们对编译时用到的GCC常用命令做一个简要的总结

    -w 禁止所有的报警。

    -w 禁止所有的报警。

     

     

    第一步、是进行预编译,使用-E参数可以让GCC在预处理结束后停止编译过程: gcc -E hello.c -o hello.i 预处理的宏定义插入到hello.i中 第...

    第一步、是进行预编译,使用-E参数可以让GCC在预处理结束后停止编译过程: gcc -E hello.c -o hello.i 预处理的宏定义插入到hello.i中 第...

    list命令:

    命令

    list命令用于列出源代码,对上述程序两次运行list,将出现如下画面(源代码被标行号):

    说明

     

    -x <language type>

    根据列出的源程序,如果我们将断点设置在第5行,只需在gdb 命令行提示符下键入如下命令设置断点:(gdb) break 5,执行情况如下图:

    显示指定输入文件的格式

     

    -c

    这个时候我们再run,程序会停止在第5行,如下图:

    编译和汇编源文件,但不链接,输出为.o文件格式

     

    -S

    设置断点的另一种语法是break <function>,它在进入指定函数(function)时停住。

    编译源文件,但不汇编,输出为.S文件格式

    相反的,clear用于清除所有的已定义的断点,clear <function>清除设置在函数上的断点,  clear <linenum>则清除设置在指定行上的断点

    -E

    只对源文件进行预处理,并不编译,输出为经过预处理的源代码

    watch命令:

    我们可以利用上面的-x和-c / –S / –E的组合来控制GCC的整个编译过程,其中-x用于告诉GCC我们从哪里开始,而-c / -S / -E用来告诉GCC在那里结束。

    watch命令用于观查变量或表达式的值,我们观查sum变量只需要运行watch sum:

    -o output-file

     

    用来指定输出文件,该选项可以指定很多种输出文件,例如:可执行文件、目标文件、汇编文件或者是预处理过的程序代码等,这要根据具体的命令行参数而定。当然,GCC还提供了默认的-o选项,其中,默认的可执行文件是a.out,目标文件是<file_name>.o,汇编文件是<file_name>.s,预编译头文件的格式是<file_name>.suffix.gch

    watch <expr>为表达式(变量)expr设置一个观察点,一量表达式值有变化时,程序会停止执行。

    -I<dir name>

    要观查当前设置的watch,可以使用info watchpoints命令。

    告诉GCC在<dir name>中去寻找头文件

    next、step命令:

    -L<dir name>

    next、step用于单步执行,在执行的过程中,被watch变量的变化情况将实时呈现(分别显示Old value和New value),如下图:

    告诉GCC在<dir name>中去寻找库文件

     

    -l<lib name>

    next、step命令的区别在于step遇到函数调用,会跳转到到该函数定义的开始行去执行,而next则不进入到函数内部,它把函数调用语句当作

    使用名为lib<lib name>.so的程序库

    一条普通语句执行。

    -static

    4.Make

    通知GCC链接静态库

    make是所有想在Linux系统上编程的用户必须掌握的工具,对于任何稍具规模的程序,我们都会使用到make,几乎可以说不使用make的程序不具

     

    备任何实用价值。

     

    在此,我们有必要解释编译和连接的区别。编译器使用源码文件来产生某种形式的目标文件(object files),在编译过程中,外部的符号参考

    上面,我们提到了关于GCC编译的常用命令,这里另外补充一些帮助性的常用命令,他们可以让你对GCC的基本配置和使用作一个了解。

    并没有被解释或替换(即外部全局变量和函数并没有被找到)。因此,在编译阶段所报的错误一般都是语法错误。而连接器则用于连接目标文

    命令

    说明

    -v

    向标准错误打印编译GCC时使用的命令和预处理器和编译器的编本,如果你在升级GCC时举棋不定,那么不妨在你的控制台上使用这个选项,看看厂商的配置

    --help

    向标准输出打印GCC命令行选项的描述。如果把这个命令和-v结合起来,--help则会同时打印被GCC调用的进程的命令行描述。如果把-Wextra和—help结合起来,那么,那些没有文档描述的命令行选项也会被显示出来。

    --target-help

    向标准输出打印每一个工具的特定命令行选项的描述

    --version

    现实GCC的版本和版权信息

    件和程序包,生成一个可执行程序。在连接阶段,一个目标文件中对别的文件中的符号的参考被解释,如果有符号不能找到,会报告连接错误

     

     

    编译和连接的一般步骤是:第一阶段把源文件一个一个的编译成目标文件,第二阶段把所有的目标文件加上需要的程序包连接成一个可执行文

    在这部分的最后,我们来谈一谈关于构建软件时链接参数的设定问题。在上面的第5部分我们已经提到了,函数库的使用是需要-L和-l一起配合来使用的,但实际上,往往一个像样的程序需要很多库的支持,例如,如果你需要编写一个GTK程序,我们需要下面的链接参数:

    件。这样的过程很痛苦,我们需要使用大量的gcc命令。

    -L/usr/lib -L/usr/X11R6/lib -lgtk -lgdk -rdynamic -lgmodule -lglib -ldl -lXi -lXext -lX11 –lm,看上去有些吓人,你可能会问,我如何知道需要这些呢,如果我想编写KDE的程序呢,还有OpenGL呢?其实,情况比你想象的要好很多,在/usr/bin目录下,有很多名为xxx-config的脚本,它们的作用就是向用户显示编译链接程序时使用的参数的。这些脚本可以接受一些参数,比较常用的有—libs用于列出链接特定程序时使用的程序库,另外--cflags用于生成头文件的包含目录,也就是上面我们提到的-I参数。于是,对于GTK程序,我们可以使用下面的命令来编译:

    而make则使我们从大量源文件的编译和连接工作中解放出来,综合为一步完成。GNU Make的主要工作是读进一个文本文件,称为makefile。这

    gcc gtksource.c `gtk-config –libs --cflags`

    个文件记录了哪些文件(目的文件,目的文件不一定是最后的可执行程序,它可以是任何一种文件)由哪些文件(依靠文件)产生,用什么命

    当然,为每一种程序写一个config显然不是一个好办法,目前新的开发包都使用pkg-config这个脚本来生成链接参数。你可以使用pkg-config –list-all查看pkg-config支持的所有链接参数

    令来产生。Make依靠此makefile中的信息检查磁盘上的文件,如果目的文件的创建或修改时间比它的一个依靠文件旧的话,make就执行相应的

    当你在上面这份列表中查到了自己想要程序包时,就可以使用下面的命令来编译程序了

    命令,以便更新目的文件。

    gcc <source file>.suffix `pkg-config <pkg name> --libs --cflags`

    假设我们写下如下的三个文件,add.h用于声明add函数,add.c提供两个整数相加的函数体,而main.c中调用add函数:

     

    /* filename:add.h */

     

    extern int add(int i, int j);

    让GCC帮助你更好的工作

     

    上面我们简单介绍了GCC的常用命令行选项,其实GCC的功能比上面提到的那些要丰富得多,GCC对代码的警告、优化、调试等方面提供了丰富的支持,下面我们就从一些例子来看看GCC提供的这些功能。

     

    1. 对问题代码提出警告

    /* filename:add.c */

    GCC对程序代码提供了完整的检查功能,由于C/C 语言本身的特点,很多错误都是程序员无意间犯下的,例如使用了未定义的变量、在bool表达式中使用了=而不是==等等问题,利用GCC提供的代码检查功能,我们可以让编译器为我们找到这些问题,避免运行时发生灾难。

    int add(int i, int j)

    首先,我们来看一个“问题代码”

    {

     1 /* test_warning.c We use this file to check the warning facilities provided by GCC*/
     2 
     3 #include <stdio.h>
     4 #include <stdlib.h>
     5 
     6 
     7 void main() {        /* main should return int*/
     8 
     9     int a, b;
    10 
    11     long long l = 2.2; /* long long type is GNU extension, not standard ANSI / ISO type*/
    12 
    13     miss_decl();    /* We call an undeclared function*/
    14 
    15     if (a = 0)       /* May be we want == here instead of =*/
    16 
    17         printf (“a really equals to 0?/n”);
    18 
    19     if (b != 0)      /* We used uninitialized variables*/
    20 
    21         /* %d and “We should put b here” don’t match*/
    22 
    23 printf(“We make a mistake again! b = %d/n”, “We should put b here”);
    24 
    25 };
    26 
    27 
    28 void miss_decl() {
    29 
    30     /* /* This type of annotation is prohibited*/
    31 
    32     printf(“We should put the declaration before it’s been used!/n”);
    33 
    34 }
    

      return i j;

    上面这些代码故意制造了很多编程中出现的常见问题,接下来,我们就用这段代码来检测一下GCC提供的各种常用的警告设施。

    };

    首先,我们不使用任何警告设施编译上面的程序

     

    gcc test_warning.c –o test_warning

     

    默认情况下,GCC会给出输出,其中GCC识别出了main函数不标准(warning)以及使用了未声明的函数(error)两个问题,但是其他的GCC并未察觉。

    /* filename:main.c */

    1.  利用-pedantic找出不符合ANSI / ISO标准的代码

    #include "add.h"

    执行下面的命令:gcc –pedantic test_warning.c –o test_warning

    main()

    可以看到,这次GCC以警告的形式报告了代码中long long的使用,但是要说明的是我们并不能依赖这个选项来保证我们的代码完全符合ANSI / ISO标准,因为该选项只报告ANSI C要求编译器进行检察的内容。另外,你还可以使用-pedantic-errors让GCC把所有的警告都变成错误。

    {

    1. 利用-Wformat检查printf中的参数不匹配问题

      int a, b;

    执行下面的命令:gcc –Wformat test_warning.c –o test_warning

      a = 2;

    1. 利用-WComment找出注释中的错误

      b = 3;

    执行下面的命令:gcc –WComment test_warning.c –o test_warning

      printf("the sum of a b is %d", add(a b));

    1. 利用-Wparentheses查找bool表达式中的=错误

    };

    执行下面的命令:gcc –Wparentheses test_warning.c –o test_warning

     

    1. 用-Wuninitialized查找未初始化变量的使用

    怎样为上述三个文件产生makefile呢?如下:

    执行下面的命令:gcc –O –Wuninitialized test_warning.c –o test_warning


    值得说明的是,在使用这个选项的时候,一定要配合上-O(后面我们会提到)选项

    test : main.o add.o

    1. 利用-Wimplicit-function-declaration / -Werror-implicit-function-declaration检查未声明函数的使用

    gcc main.o add.o -o test

    执行下面的命令:gcc -Wimplicit-function-declaration test_warning.c –o test_warning

     

    另外-Werror-implicit-function-declaration和-Wimplicit-function-declaration作用是类似的,只是如果你使用了未声明的函数,前者会把它认为是一个错误。

    main.o : main.c add.h

    7. 如果你只是想对你的代码进行全面的检查,你大可不必把上面的选项一并列出来,GCC提供了-Wall选项,含义就是列出所有代码中的警告

    gcc -c main.c -o main.o

    执行下面的命令:gcc –Wall test_warning.c –o test_warning

     

    8. 如果你想走另一个极端,也就是不想让gcc输出任何警告,那么使用-w选项,该选项禁止所有的警告

    add.o : add.c add.h

    执行下面的命令:gcc –w test_warning.c –o test_warnin

    gcc -c add.c -o add.o

    <输出结果>


    对于上面所有的选项,你都可以把它们和-Werror选项一起使用,这样就可以把所有的警告都变成错误。另外,如果你只是想对代码进行检查而并不执行编译的话,可使用-fsyntax-only选项,像下面的命令这样

    (注意分割符为TAB键)

    gcc –fsyntax-only test_warning.c

    上述makefile利用add.c和add.h文件执行gcc -c add.c -o add.o命令产生add.o目标代码,利用main.c和add.h文件执行gcc -c main.c -o

    基本上来说,我们常用的一些警告选项就是这些,而其中-Wall更是我们极为常用的功能。

    main.o命令产生main.o目标代码,最后利用main.o和add.o文件(两个模块的目标代码)执行gcc main.o add.o -o test命令产生可执行文件

    2. 优化选项

    test。

    这一部分的内容可以分成两部分,一部分是让编译器对代码进行分析后,进行的代码优化,另一部分是我们可以为编译器制定一些关于硬件的信息,让他生成对硬件结合的更好的代码,而我们之所以要用源代码来编译程序,很多情况下,是出于这方面的原因。

    我们可在makefile中加入变量,另外。环境变量在make过程中也被解释成make的变量。这些变量是大小写敏感的,一般使用大写字母。Make变

    首先来看代码优化,从代码的整体优化上,GCC提供了下面的选项

    量可以做很多事情,例如:

    -O –O1

    i) 存储一个文件名列表;

    这两个选项的含义是一样的,GCC将执行减少代码尺寸和执行时间的优化,对于那些会严重影响编译时间的优化选项,这个级别的优化并不会执行。

    ii) 存储可执行文件名;

    -O2

    iii) 存储编译器选项。

    在这一级别GCC将会提供所有支持的优化,但这其中并不包括以空间换时间的优化手段,例如编译器不会使用循环展开和函数内联。和-O相比,该选项进一步加快了编译时间和生成代码的性能。

    要定义一个变量,只需要在一行的开始写下这个变量的名字,后面跟一个=号,再跟变量的值。引用变量的方法是写一个$符号,后面跟(变量

    -O3

    名)。我们把前面的makefile 利用变量重写一遍(并假设使用-Wall -O –g编译选项):    

    除了-O2提供的优化选项外,还指定了-finline-functions,-funswitch-loops和-fgcse-afer-reload选项,目的只有一个就是全力执行代码优化。

    OBJS = main.o add.o

    -Os

    CC = gcc

    这个选项是专门用来优化代码尺寸的,-Os打开了所有-O2级别中不会显著增长代码尺寸的优化选项

    CFLAGS = -Wall -O -g

    -O0

       

    该选项代表不执行优化

    test : $(OBJS)

    在这里要说明的是,尽管GCC提供了1~3和s这4个整体优化选项,但从实际的优化效果上来看,往往O3优化出来的程序的效率并不是最高的,而大部分情况下我们都在使用-O2,如果你希望获得最高的效率利益,那么不妨这4个选项都试试。另外,其实这些选项只不过是GCC提供的很多单方面优化的一个组合,如果你想了解更为具体的优化内容,可以去查看GCC手册,出于篇幅限制,这里不细谈了。最后要记住的一点是,如果你的程序是用于高精度数值计算的,那么记住不要使用上面任何的优化选项。

    $(CC) $(OBJS) -o test

    下面来看基于硬件优化,由于这部分和计算机硬件相关,这里仅用Intel的CPU做一些说明:

       

    对于所有为Intel和AMD x86-64提供的优化选项都是用m开头的,下面写一些常用的选项:

    main.o : main.c add.h

    -march

    $(CC) $(CFLAGS) -c main.c -o main.o

    该选项用来指定CPU的类型,常用的有i386 / i486 / i586 / pentium-mmx / i686 / pentium2 / pentium3 / pentium-m / pentium4 / prescott / k6 / athlon / athlon-4 / k8等等,读者可以根据自己的情况进行指定。

       

    -mfpmath

    add.o : add.c add.h

    该选项用于指定浮点运算单元的类型。包括

    $(CC) $(CFLAGS) -c add.c -o add.o

    387

    makefile 中还可定义清除(clean)目标,可用来清除编译过程中产生的中间文件,例如在上述makefile文件中添加下列代码:

    使用标准的数学协处理器

    clean:

    sse

    rm -f *.o

    使用SSE指令集提供的标量浮点运算。在Pentium3 / Athlon-4以及更新的芯片上支持这个特性。另外,在pentium4以及AMD x86-64处理器上,SSE2还可以进行双精度浮点计算。

    运行make clean时,将执行rm -f *.o命令,删除所有编译过程中产生的中间文件。

    sse,387

    不管怎么说,自己动手编写makefile仍然是很复杂和烦琐的,而且很容易出错。因此,GNU也为我们提供了Automake和Autoconf来辅助快速自动

    混合使用387数学协处理器和SSE指令集,该选项可以充分的利用CPU的浮点寄存器和xmm寄存器,但是该选项还处在试验阶段。

    产生makefile,读者可以参阅相关资料。

    -malign-double

    ――开发平台搭建 .GCC编译器 GCC是Linux平台下最重要的开发工具,它是GNU的C和C 编译器,其基本用法为: gcc [op...

        该选项使得GCC把double / long double / long long类型的变量在4字节或2字节地址上对齐,

        在Pentium级的CPU上,这会使得代码的执行速度更快,当然带来的代价是需要更多的内存来执行程序。-mmmx –msse –msse2 –msse3 –m3dnow

    这些选项用来启动内置函数直接使用这些处理器扩展指令的功能。在编译3D或多媒体程序的时候,使用他们是非常有效的。

     

     

    3. 对调试的支持

        当程序出错的时候,我们可以在Visual Studio中轻松的进行调试,而在Linux中,一旦出现Segmentation Fault,似乎我们除了用眼睛去看代码就没有更好的选择了,其实情况不然,用GCC向程序加入一些适当的调试信息,我们可以利用GDB去调试程序。在这里,我们介绍最为常用的-g和-ggdb选项。

        先来看-g。该选项可以利用操作系统的“原生格式(native format)”生成调试信息。GDB可以直接利用这个信息。尽管我们可以把-O和-g放在一起使用,但是,这种做法是极为不推荐的。

        如果你想用GDB来调试程序,那么你可以使用-ggdb来让GCC为GDB生成更为丰富的调试信息,但是,此时你就不能用其他的调试器来进行调试了。

        最后要说明的是,上面这两个选项都可以接受一个输出调试信息的级别,默认的级别是2。如果你指定1级(-g1),那么GCC会生成最少的调试信息,这包括函数和全局变量的描述信息,但是对于局部变量和行号等信息,在这个级别是不会输出的。另外一个级别是3级(-g3),在这一级别上,GCC会为程序中的所有宏定义和符号生成调试信息。

    小结

        通过这篇文章,希望能过对想学习Linux开发中用到的一些基本的技术和知识有一个了解,并且能够自己动手开始做些试验性的工作,其实,这里还有很多问题没有谈到,例如利用GDB进行调试、利用make管理工程、利用autoconf为程序生成配置脚本、利用CVS管理程序源文件等等,这些问题有待在今后的文章中和读者一起交流。

     

    本文由新葡亰496net发布于电脑系统,转载请注明出处:Linux系统平台下关于GCC编译及使用的方法,关于

    关键词: