为了防止无良网站的爬虫抓取文章,特此标识,转载请注明文章出处。LaplaceDemon/ShiJiaqi。

http://www.cnblogs.com/shijiaqi1066/p/6065410.html

gcc命令

gcc 选项 参数

选项:

  • -o:指定生成的输出文件的文件名;
  • -E:仅执行编译预处理;
  • -S:将C代码转换为汇编代码;
  • -wall:显示警告信息;
  • -c:仅执行编译操作,不进行连接操作。
  • -D FOO=X:在命令行定义预处理宏FOO,其值为X。
  • -I dir:添加头文件(.h)搜索路径
  • -L dir:添加库文件搜索路径。
  • -static:指定链接库为链接静态库。
  • -l, -library:指定链接库文件名。
  • -g:在可执行程序中包含标准调试信息。
  • -ggdb:产生调试信息,仅供gnu识别。
  • -O 数字:指定代码优化的级别为N,0<=N<=3。 该选项不能与-g选项联合使用;
  • -ansi:支持ANSI/ISO C的标准语法。
  • -pedantic:允许发出ANSI/ISO C标准所列出的所有警告。
  • -pedantic -errors:允许发出ANSI/ISO C标准所列出的所有错误。
  • -traditional:支持K&R C语法。
  • -w:关闭所有警告。
  • -Wall:允许发出gcc能提供的所有有用的警告。
  • -werror:把所有警告转换为错误,在警告发生时中止编译过程。
  • -shared:编译动态链接库(共享函数库)。

参数:C代码的源文件。

现在有一个简单的main可执行程序。

#include <stdio.h>

int main(void) {
    printf("Hello World!\n");
    ;
}

简单编译

1. 无选项编译

gcc test.c

经过该命令,代码被编译成a.out可执行程序。

[root@localhost HelloWorld]# ./a.out
hello world!!!

2. 指定输出文件名

编译命令:

gcc test.c -o test

将代码编译可执行文件test。-o选项用来指定输出文件的文件名。

[root@localhost HelloWorld]# ./test
hello world!!!

编译的四个阶段

在使用gcc编译命令之前,一定要先了解程序的编译过程。

整个编译被分为四个过程:

  • 预处理(也称预编译,Pre-Processing)
  • 编译(Compilation)
  • 汇编 (Assembly)
  • 连接(Linking)

预处理阶段:执行预处理指令,源文件会被修改。如#include指令就是一个预处理指令,它把头文件的内容添加到 .c/.cpp 文件中。该阶段文件从.c 处理成 .i。但本质还是C代码。

编译阶段:该阶段会把C代码翻译成等价的中间代码或汇编代码,并优化。

汇编阶段:该阶段把汇编代码翻译成目标机器指令。

链接阶段:该阶段把相关联的目标文件相互连接。也就是将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个可执行的统一整体。

链接被分为两种:

静态链接:

在这种链接方式下,函数的代码将从其所在地静态链接库中被拷贝到最终的可执行程序中。这样该程序在被执行时这些代码将被装入到该进程的虚拟地址空间中。静态链接库实际上是一个目标文件的集合,其中的每个文件含有库中的一个或者一组相关函数的代码。

动态链接:

多个程序可以公用一份函数内存。程序在编译中不依赖外部函数库,只在运行时寻找相应库,动态链接,执行。

相应的,这里涉及到一个重要概念即库函数。

库函数也被分为静态库与动态库。

静态库是把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不需要库文件了。静态库的后缀一般为“.a”。

动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时链接文件加载库。动态库的后缀一般为“.so”。

例如,stdio.h中的printf,其具体实现位于动态库libc.so.6。在没有特别指定时,gcc命令会去/usr/lib下查找。也就是链接到libc.so.6库函数。

详解gcc命令

1. 预处理

gcc -E test.c -o test.i

可以打开test.i文件,该文件依然是C代码,只是加入了很多其他代码。

2. 编译

gcc -S test.i -o test.s

可以打开test.s文件,查看汇编代码,注意,这依然是文本文件。

        .file   "test.c"
        .section        .rodata
.LC0:
        .string "hello world!!!"
        .text
        .globl  main
        .type   main, @function
main:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset
        .cfi_offset , -
        movq    %rsp, %rbp
        .cfi_def_cfa_register
        movl    $.LC0, %edi
        call    puts
        movl    $, %eax
        popq    %rbp
        .cfi_def_cfa ,
        ret
        .cfi_endproc
.LFE0:
        .size   main, .-main
        .ident  "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-4)"
        .section        .note.GNU-stack,"",@progbits

3. 汇编

例:

gcc -c test.s -o test.o 或 gcc -c test.s

-c选项,将C代码或汇编代码编译成二进制文件。该过程会自动包含预处理,编译,汇编,但不执行链接过程。若源文件名为abc.c则默认输出为abc.o,文件名不变。

这里的test.o就无法用vim或者其他文本程序打开了,因为这已经是二进制程序了。

4. 链接

gcc test.o -o test

经过链接后,代码即可执行。

[root@localhost HelloWorld]# ./test
hello world!!!

5. 多个程序文件编译

一般程序都是以多个源文件的形式组成的。需要把多个文件编译成二进制文件,然后将编译多个文件然后链接在一起。

例:源文件为test1.c与test2.c。

可以使用:

gcc test1.c test2.c -o test

该语句本质上由如下语句组成:

gcc -c test1.c -o test1.o

gcc -c test1.c -o test2.o

gcc test1.o test2.o -o test

6.警告检查

-pedantic  以ANSI/ISO C标准列出的所有警告。

-Wall        显示所有的警告信息。

-Werror    要求GCC将所有的警告当成错误进行处理。

7. 定义宏

#include <stdio.h>

int main(void){
#ifdef HELLO
    printf("HELLO defined!,HELLO = %d\n",HELLO);
#else
    printf("HELLO is not define!\n");
#endif
    ;
}

使用编译选项 -D 来定义宏的值。

gcc -DHELLO=100 hello.c -o hello

宏被定义为100。

[root@localhost HelloWorld]# ./hello
HELLO defined!,HELLO = 100

gcc hello.c -o hello

不定义宏的值。
[root@localhost HelloWorld]# ./hello
HELLO is not define!

8. 链接库文件

动态库和静态库的使用方法是一样的,同一个库如果同时存在动态库和静态库,优先链接动态库,

gcc中关于库的参数有:
-L:指定搜寻库的目录。如指定当前目录 gcc -L 。
 
-l(小写L):指定要链接的库的名称。
例:加入库的名称是libmylib.a。则可以使用 gcc -l mylib,即去头去尾。
 
--static    组织在链接时使用动态库。该选项用于当同时存在动态库与静态库时,强制使用静态库。
--shared   生成动态库。
--static-libgcc  链接静态libgcc库
--shared-libgcc 链接动态libgcc库

9. 编译生成静态库

静态库即.a文件。静态库的名字一般为libxxxx.a,其中xxxx是该lib的名称。

静态函数库实际上就是简单的一个普通的目标文件的集合。.a文件就是是.o文件的集合。

使用ar命令就可以让一组.o文件生成.a文件。Ar是archiver的缩写。

格式:ar rcs my_library.a file1.o file2.o

例:已经存在a.o, b.o, c.o,组合生成 libmylib.a 。

ar rcs libmylib.a a.o b.o c.o 

使用ar命令对静态库新增.o

ar -r libhello.a new_hello.o

10. 编译生成动态库

动态库即.so文件。动态库的名字一般为libxxxx.so.major.minor,xxxx是该lib的名称,major是主版本号, minor是副版本号

动态库必须由gcc编译生成。

例:a.c, b.c两个文件,生成 libmylib.so 。

gcc --shared a.c b.c -fPIC -o libmylib.so

PIC的意思是“位置无关代码”(Position Independent Code)。

安装动态链接库(共享函数库)

方法一:其实简单的方法就是拷贝so文件到指定的标准的目录(如,/usr/lib),然后运行ldconfig。

若不执行ldconfig会引发 "error while loading shared libraries...."异常,无法运行。

方法二:使用ldconfig动态添加so文件位置。

例:ldconfig /usr/zhsoft/lib

方法三:若没有权限去做这件事情,例如你不能修改/usr/lib目录,可以通过修改环境变量来实现使用函数库。

将so所在目录导入到环境变量LD_LIBRARY_PATH中,即可。

export LD_LIBRARY_PATH=$(pwd)

接着即可运行,不需要使用ldconfig命令。

11. 查看可执行程序和动态链接库的依赖

例:查看动态链接库的依赖。

[root@localhost hello]# ldd ./libhello.so
linux-vdso.so. => (0x00007fffd57fe000)
libc.so. => /lib64/libc.so. (0x00007fdf76ac9000)
/lib64/.so. (0x00007fdf77094000)

例:查看ls命令的依赖。

[root@localhost hello]# ldd /usr/bin/ls
linux-vdso.so. => (0x00007ffc85712000)
libselinux.so. => /lib64/libselinux.so. (0x00007f27f4262000)
libcap.so. => /lib64/libcap.so. (0x00007f27f405d000)
libacl.so. => /lib64/libacl.so. (0x00007f27f3e53000)
libc.so. => /lib64/libc.so. (0x00007f27f3a91000)
libpcre.so. => /lib64/libpcre.so. (0x00007f27f3830000)
liblzma.so. => /lib64/liblzma.so. (0x00007f27f360a000)
libdl.so. => /lib64/libdl.so. (0x00007f27f3406000)
/lib64/.so. (0x00007f27f448e000)
libattr.so. => /lib64/libattr.so. (0x00007f27f3201000)
libpthread.so. => /lib64/libpthread.so. (0x00007f27f2fe4000)

12. 代码优化 

-O 数字,数字指定代码优化的级别为,级别分0,1,2,3 。

-O1 告诉编译器进行第一级优化,通常提高优化级别会使得程序运行的更快,但是编译的时间会变长,用调试工具调试程序变得更加困难,使用更高的级别优化代码,使得产生的机器代码难以理解。

编译实战

1. 源码

hello.h

#ifndef HELLO_H
#define HELLO_H 

void hello(const char *name); 

#endif

hello.c

# include <stdio.h>
void hello(const char *name) {
    printf("Hello %s!\n", name);
}

main.c

# include "hello.h"
int main() {
     hello("everyone");
     ;
 }

2. 手动多文件编译

gcc hello.c main.c -o hello

gcc -c hello.c
gcc -c main.c
gcc hello.o main.o -o hello

3. 生成并使用静态链接库

使用ar命令生成.a文件。

gcc -c hello.c    #生成hello.o
ar rcs libhello.a hello.o    #生成libhello.a
gcc main.c -L. -lhello -o hello    # -L. 表示链接库目录为当前目录,-l表示链接库名称为libhello

执行

./hello

4. 生成并使用动态链接库

方法一:

#生成so文件
gcc -shared hello.c -fPIC -o libhello.so

#安装
mv libhello.so /usr/lib
ldconfig

#执行
./hello

方法二:

#安装
ldconfig /root/workspace-c/GCC/hello/build

#执行
./hello

方法三:

#安装
export LD_LIBRARY_PATH=$(pwd)

#执行
./hello

编译中一些文件路径的注意点

  1. gcc命令使用-l选项指定链接库的名称。-L选项指定链接库所在目录。
  2. .h 文件是编译过程必不可少的。.h 文件需要在链接阶段被使用。.h 文件路径不需要与相关的 .a 或 .o 在一起。事实上,该文件是由#include时候指定目录的
  3. 使用-I参数可以添加.h文件搜索的路径。

静态库链接时搜索路径顺序:

  1. ld会去找GCC命令中的参数 -L
  2. 再找gcc的环境变量LIBRARY_PATH
  3. 再找内定目录 /lib /usr/lib /usr/local/lib 这是当初compile gcc时写在程序内的

动态链接时、执行时搜索路径顺序:

  1. 编译目标代码时指定的动态库搜索路径;
  2. 环境变量LD_LIBRARY_PATH指定的动态库搜索路径;
  3. 配置文件/etc/ld.so.conf中指定的动态库搜索路径;
  4. 默认的动态库搜索路径/lib;
  5. 默认的动态库搜索路径/usr/lib。

有关环境变量:

  • LIBRARY_PATH环境变量:指定程序静态链接库文件搜索路径。
  • LD_LIBRARY_PATH环境变量:指定程序动态链接库文件搜索路径。

代码中动态使用动态链接库(无需安装)

使用ldopen函数,略。

为了防止无良网站的爬虫抓取文章,特此标识,转载请注明文章出处。LaplaceDemon/ShiJiaqi。

http://www.cnblogs.com/shijiaqi1066/p/6065410.html

gcc的使用的更多相关文章

  1. VSCode调试go语言出现:exec: "gcc": executable file not found in %PATH%

    1.问题描述 由于安装VS15 Preview 5,搞的系统由重新安装一次:在用vscdoe编译go语言时,出现以下问题: # odbcexec: "gcc": executabl ...

  2. GCC学习(1)之MinGW使用

    GCC学习(1)之MinGW使用 因为后续打算分享一些有关GCC的使用心得的文章,就把此篇当作一个小预热,依此来了解下使用GNU工具链(gcc.gdb.make等)在脱离IDE的情况下如何开发以及涉及 ...

  3. 使用 GCC 和 GNU Binutils 编写能在 x86 实模式运行的 16 位代码

    不可否认,这次的标题有点长.之所以把标题写得这么详细,主要是为了搜索引擎能够准确地把确实需要了解 GCC 生成 16 位实模式代码方法的朋友带到我的博客.先说一下背景,编写能在 x86 实模式下运行的 ...

  4. [异常解决] How to build a gcc toolchain for nRF51 on linux (very detailed!!!)

    1.Install gcc-arm-none-eabi https://devzone.nordicsemi.com/tutorials/7/This link shows that developm ...

  5. CentOS 6.6 升级GCC G++ (当前最新版本为v6.1.0) (完整)

    ---恢复内容开始--- CentOS 6.6 升级GCC G++ (当前最新GCC/G++版本为v6.1.0) 没有便捷方式, yum update....   yum install 或者 添加y ...

  6. GCC 预处理、编译、汇编、链接..

    1简介 GCC 的意思也只是 GNU C Compiler 而已.经过了这么多年的发展,GCC 已经不仅仅能支持 C 语言:它现在还支持 Ada 语言.C++ 语言.Java 语言.Objective ...

  7. 用gcc进行程序的编译

    在Linux系统上,一个档案能不能被执行看的是有没有可执行的那个权限(x),不过,Linux系统上真正认识的可执行文件其实是二进制文件(binary program),例如/usr/bin/passw ...

  8. gcc/linux内核中likely、unlikely和__attribute__(section(""))属性

    查看linux内核源码,你会发现有很多if (likely(""))...及if (unlikely(""))...语句,这些语句其实是编译器的一种优化方式,具 ...

  9. Ubuntu 14.04 LTS 下升级 gcc 到 gcc-4.9、gcc-5 版本

    如果没记错的话,阿里云ECS上的Ubuntu也是LTS版本. 如果还在使用较旧版本的Ubuntu,或者是Ubuntu LTS,那么我们是很难体验新版gcc的.怎么办呢? 我们或许可以自己去编译用旧版本 ...

  10. 低版本GCC程序向高版本移植的兼容性问题

    将低版本gcc编译过的程序移植到高版本GCC时, 可能会出现一些兼容性问题. 原因是, 为了适应新的标准,一些旧的语法规则被废弃了. 关于这方面的一些具体资料可从该处查询. 这里只是自己遇到的其中一个 ...

随机推荐

  1. eclipse 项目报错问题

    所有的问题在windoes-->show view--->Problems里查看

  2. viedeo

    http://download.farsight.com.cn/download/Android.htm

  3. uva 11468 Substring

    题意:给你 k 个模板串,然后给你一些字符的出现概率,然后给你一个长度 l ,问你这些字符组成的长度为 l 的字符串不包含任何一个模板串的概率. 思路:AC自动机+概论DP 首先用K个模板构造好AC自 ...

  4. php 实现文件下载,兼容IE、Firefox、Chrome等浏览器

    一.下载任意文件: Header ( "Content-type: application/octet-stream" ); $ua = $_SERVER ["HTTP_ ...

  5. java ee@ Myeclipse 2015 stable 1.0 完美破解方法

    Myeclipse 2015 stable 1.0 完美破解方法 破解步骤: 使用以前的注册机算号,版本选择Blue即可,后续可解锁Spring高级功能,即Bling的所有功能全部具备 1.1 进入m ...

  6. 远程测试mysql数据库3306端口报错

    错误现象:[root@localhost ~]# telnet 192.168.10.130 3306Trying 192.168.10.130...Connected to 192.168.10.1 ...

  7. mysql登陆报错(ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2))

    部署mysql版本信息 version: 5.6.21 具体现象: mysql服务能够正常启动如下: [root@localhost ~]# service mysqld restart Shutti ...

  8. hdoj 4325 Flowers【线段树+离散化】

    Flowers Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Sub ...

  9. Android最新锁屏病毒分析及解锁

    一.情况简介   从去年开始PC端的敲诈者类病毒在不断的爆发,今年年初的时候手机上也开始出现了敲诈者之类的病毒,对这类病毒很无语也是趋势,因为很多时候病毒的产生是和金钱利益相关的.前天去吾爱破解论坛病 ...

  10. 安卓开发21:深入理解Handler

    Handler相关说明: 主要接受子线程发送的数据, 并用此数据配合主线程更新UI. 解释:安卓的UI线程(即OnCreate函数创建的线程)是线程非安全的.也就是说,在UI线程中,使用sleep这样 ...