body, table{font-family: 微软雅黑} table{border-collapse: collapse; border: solid gray; border-width: 2px 0 2px 0;} th{border: 1px solid gray; padding: 4px; background-color: #DDD;} td{border: 1px solid gray; padding: 4px;} tr:nth-child(2n){background-color: #f8f8f8;}

Linux 下文件编译与调试

gcc/g++编译器

对于.c格式的 C文件,可以采用gcc或g++编译
对于 .cc、.cpp格式的C++文件,应该采用g++进行编译
常用的选项:
-c  表示编译源文件
-o  表示输出目标文件
-g  表示在目标文件中产生调试信息,用于gdb调试
-D  <宏定义> 编译时将宏定义传入进去
-Wall  打开所有类型的警告。
1. gcc编译过程:预编译->编译->汇编->链接
(1)预处理:预处理器将对源文件中的宏进行展开。
(2)编译:gcc将c文件编译成 汇编文件。
(3)汇编:汇编器as将汇编文件编译成机器码。
(4)链接:将目标文件和外部符号进行连接,得到一个可执行二进制文件。
//test.c
#include <stdio.h>
#define NUMBER (1+2)
int main()
{
   int x = NUMBER;
   return 0;
}
(1)预处理: gcc –E test.c -o test.i  
我们用 cat 查看 test.i 的内容如下:int  main()  int x=(1+2);  return 0;我们可以看到,文件中宏定义NUMBER出现的位置被(1+2)替换掉了,其它的内容保持不变。


预处理阶段:对包含的头文件(#include)和宏定义(#define、#ifdef等)进行处理

(2)编译:gcc -S test.i –o test.s 通过 cat test.s 查看 test.s 的内容为代码。
编译阶段:检查代码规范性、语法错误等,在检查无误后把代码翻译成汇编语言
(3)汇编:as test.s -o test.o  利用as将汇编文件编译成机器码。得到输出文件为 test.o。test.o 中为目标机器上的二进制文件. 用 nm 查看文件中的符号: nm test.o 输出如下:0000000000000000 T main。既然已经是二进制目标文件了,能不能执行呢?试一下 ./test.o,提示 cannotexecute binary file.T表示这个符号属于代码。
//test.o 得先加一个执行权限
(4)链接: gcc test.o –o test  ,将所有的.o文件链接起来生产可执行程序。

链接阶段:将.s的文件以及库文件整合起来链接为可执行程序


gcc所支持后缀名:
gcc常用选项:
gcc库选项:
gcc警告选项:
file 文件名        看对应文件类型
gcc -v            显示编译器版本
//test1.c
#include<stdio.h>
int main()
{
        #ifdef meihao
        printf("define meihao\n");
        #else
        printf("not define meihao\n");
        #endif
        printf("main exit\n");
}
gcc -E test1.c -o test1.i
gcc -E test1.c -o test1.i -D meihao
函数库分为静态库和动态库

静态库是目标文件.a 的归档文件(格式为libname.a)。如果在编译某个程序时链接静态库,则链接器将会搜索静态库并直接拷贝该程序的可执行二进制文件到当前文件中;
静态库将会整合到程序中,在程序执行时不用加载静态库。 因此,静态库会使你的程序臃肿并且难以升级,但比较容易部署。而动态库会使你的程序轻便易于升级但难以部署。

动态库(格式为 libname.so[.主版本号.次版本号.发行号])。在程序编译时并不会被链接到目标代码中,而是在程序运行时才被载入。
动态库只在执行时才被链接使用,不是直接编译为可执行文件,并且一个动态库可以被多个程序使用故可称为共享库。

创建静态库:
>gcc -c add.c    //编译add.c源文件生成add.o目标文件
>ar -crsv libadd.a add.o  //对目标文件*.o进行归档,生成lib*.a,此处lib要写;命令参数:
c 创建一个库。不管库是否存在,都将创建。
r 代替库中现有的文件或者插入新的文件
s 写入一个目标文件索引到库中,或者更新一个存在的目标文件索引
v 输出详细信息
 a - add.o
>su
#cp ./libadd.a /lib     //拷贝到标准程序设计库
>gcc main.c -w -o main -ladd
>./main 1 2
 sum=3

>gcc -c add.c
>ar -crsv libadd.a add.o
 a - add.o

>gcc main.c -w -o main -L./ -ladd  //不要忘记-L后面的那个./ ;即在库文件的搜索路径中添加当前路径   -ladd表示链接库文件libadd.a/.so 
>./main 1 2
 sum=3

创建动态库:
>gcc -fPIC -Wall -c add.c  //编译,允许发出警告,生成使用相对地址的位置无关的目标代码
>gcc -shared -o libadd.so add.o  //生成库文件libadd.so
>su 
#cp ./libadd.so /lib
#exit  //拷贝到 /lib 库中
>gcc main.c -w -o main -ladd
>./main 1 2
 sum=3

在运行main前,需要注册动态库的路径。
方法有3种:
▶修改/etc/ld.so.conf
▶修改LD_LIBRARY_PATH环境变量
库放在当前目录
>export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/meihao
>gcc main.c -o main -ladd -L/home/meihao

将库文件拷贝到/lib或者/usr/lib下(系统默认搜索库路径)。

//add.c
int add(int a,int b)
{
        return a+b;
}
//main.c
#include<stdio.h>
#include<stdlib.h>
void main(int argc,char* argv[])
{
        if(argc!=3)
        {
                printf("error args\n");
                return;
        }
        int i=atoi(argv[1]);
        int j=atoi(argv[2]);
        printf("sum=%d\n",add(i,j));
}



程序调试

gdb常用命令
Linux 包含了一个叫gdb的调试程序。gdb可以用来调试 C 和 C++ 程序。在程序编译时用 -g 选项可打开调试选项,表示在目标文件中产生调试信息,用于gdb调试;
>gcc test1.c -Wall -g -o test  //(—g和—o要挨在一起)(—g和—c要挨在一起)
>gdb ./test
l   //显示所要调试的代码;(l  函数名)显示文件中定义的函数代码
b     //(b  main )表示在main函数那加一个断点(keep永久断点),也可以是数字(b n);
r     //表示运行;运行到断点;
p 变量名    //查看变量值也可以 (p  &变量名)查看变量地址;
n   //下一步不进入函数   相当于Windows的F10            
s   //表示单步进入函数, 相当于Windows的F11

1、先打断点,运行起来
2、一步一步往下走,n
3、c程序一直往下走
4、s进入函数
c   //运行到最后                                                       
    (continue)
q    //退出                     
相当于Windows的Shift+F5        (quit)
set args 1 2   //调试中向main入口传递两个参数
show args   //显示刚才设置的参数
info b    //查看刚才所设断点
x   //是用来检查内存情况(x  /20xb  要查看变量地址)  bt   //进入调用堆栈;
d  断点号   //删除断点
tb n   //设置临时断点,下次运行r会消失
>gcc test2.c -Wall -g -o test2
// int数据,一个数据占4个字节,32位
//test1.c
#include<stdio.h>
#include<stdlib.h>
int add(int a,int b)
{
        return a+b;
}
int main(int argc, char **argv)
{
        if(3!=argc)
        {       
                printf("error argcs\n");
                return -1;
        }
        int sum;
        sum=add((atoi(argv[1])),(atoi(argv[2])));
        printf("sum=%d\n",sum);
        return 1;
}
//test2.c
#include<stdio.h>
int main()
{
        int a[4]={1,2,3,4};
        printf("a[1]=%d\n",a[1]);
        return 1;
}

命令 x 是用来检查内存情况,英文是examine含义,使用方法 x /20xb 变量首地址,其中20x代表16进制的长度,b代表字节的含义

core dumped

>ulimit  -c  unlimited
>gcc test3.c -w -o test3
>gdb ./test3 core
//l 输出错误行代码,bt 打开调用栈查看自己错误行代码, q 退出;
//test3.c
#include<stdio.h>
int add(int a,int b)
{
        return a+b;
}
int main(int argc,char **argv)
{
        int i,j,sum;
        i=atoi(argv[1]);
        j=atoi(argv[2]);
        sum=add(i,j);
        printf("sum=%d\n",sum);
}
gcc对代码进行优化通过选项“-On”来控制优化级别(n是整数)。不同的优化级别对应不同的优化处理工作。如使用优化选项“-O1”主要进行线程跳转和延迟退栈两种优化。使用优化选项“-O2”除了完成所有“-O1”级别的优化之外,还要进行一些额外的调整工作,如处理其指令调度等。选项“-O3”则还包括循环展开或其他一些与处理器特性相关的优化工作。虽然优化选项可以加速代码的运行速度,但对于调试而言将是一个很大的挑战。因为代码在经过优化之后,原先在源程序中声明和使用的变量很可能不再使用,控制流也可能会突然跳转到意外的地方,循环语句也有可能因为循环展开而变得到处都有,所有这些对调试来讲都是不好的。所以在调试的时候最好不要使用任何的优化选项,只有当程序在最终发行的时候才考虑对其进行优化。
通常用的是-O2

LINUX下文件编译的更多相关文章

  1. 嵌入式之:Linux下文件编译过程

    本文主要三个部分:1.GNU GCC简介 2.C/C++交叉编译器arm-elf-gcc 3.make文件,用于工程管理 部分一:GNU GCC简介: 该编译器基本功能: (1)输出预处理后的文件(展 ...

  2. dos2unix,去掉Linux下文件中的^M

    Windows系统下使用VS2010编写好的CPP文件,想放到Linux上进行编译.发现Linux上文件中的每行代码末尾都跟着^M这个符号. 为什么同一份文件在windows上和Linux上显示的不一 ...

  3. ACE-6.1.0 linux 下的编译与安装步骤

    ACE-6.1.0 linux 下的编译与安装步骤  引用至http://www.cnblogs.com/liangxiaxu/archive/2013/03/07/2948417.html 1.从  ...

  4. linux 下文件误删恢复

    linux 下文件误删恢复 0x01 事件背景 某天晚上写代码的时候,本来想删除当前目录下一个叫xxx的文件夹 rm -rdf ./xxx/*, 结果光顾着和人说话,一不留神手贱把命令敲成了rm -r ...

  5. FFmpeg在Linux下安装编译过程

    转载请把头部出处链接和尾部二维码一起转载,本文出自:http://blog.csdn.net/hejjunlin/article/details/52402759 今天介绍下FFmpeg在Linux下 ...

  6. Linux下nginx编译安装教程和编译参数详解

    这篇文章主要介绍了Linux下nginx编译安装教程和编译参数详解,需要的朋友可以参考下 一.必要软件准备1.安装pcre 为了支持rewrite功能,我们需要安装pcre 复制代码代码如下: # y ...

  7. linux下将编译错误输出到一个文本文件

    linux下将编译错误输出到一个文本文件 command > filename 把把标准输出重定向到一个新文件中 command > > filename 把把标准输出重定向到一个文 ...

  8. 从四个问题透析Linux下C++编译&链接

    摘要:编译&链接对C&C++程序员既熟悉又陌生,熟悉在于每份代码都要经历编译&链接过程,陌生在于大部分人并不会刻意关注编译&链接的原理.本文通过开发过程中碰到的四个典型 ...

  9. Linux下文件的三种时间戳

    Linux下文件的三种时间标记 三种时间对应关系表 column column column 访问时间 Access atime 修改时间 Modify mtime 状态改动时间 Change cti ...

随机推荐

  1. VS2015 查看类之间的继承关系

    ---恢复内容开始--- 1. 右击项目名称,单击"查看"菜单下的"查看类图"菜单: 2.生成的类图如下:

  2. curl -windows下接口通讯

    1,下载curl -----url命令传输工具 2,配置curl环境变量 3,在cmd环境中使用   举例:curl -G http://xxxxxxx.com?+参数 使用:curl -G &quo ...

  3. GPS校时器,GPS时钟装置,NTP网络时间服务器

    GPS校时器,GPS时钟装置,NTP网络时间服务器 GPS校时器,GPS时钟装置,NTP网络时间服务器 GPS校时器,GPS时钟装置,NTP网络时间服务器 GPS校时器,GPS时钟装置,NTP网络时间 ...

  4. 安装好的虚拟机,外部通过ssh工具连接,报connection failed

    今天,新装了一台ubuntu虚拟机,安装成功以后,准备利用Xshell从外部访问linux,以减少切换,但是,在连接时,总是会报:connection failed. 于是,写下这篇随笔,以增加记忆且 ...

  5. 【转1】Appium 1.6.3 在Xcode 8, iOS 10.2(模拟器)测试环境搭建 经验总结

    Appium 1.6.3 在Xcode 8, iOS 10.2(模拟器)测试环境搭建 经验总结 关于 Appium 1.6.3 在Xcode 8, 10.2 的iOS模拟器上的问题很多,本人也差点放弃 ...

  6. 如何继承Date对象?由一道题彻底弄懂JS继承。

    前言 见解有限,如有描述不当之处,请帮忙及时指出,如有错误,会及时修正. ----------长文+多图预警,需要花费一定时间---------- 故事是从一次实际需求中开始的... 某天,某人向我寻 ...

  7. I2S协议

    (一)I2S总线概述: 音响数据的采集.处理和传输是多媒体技术的重要组成部分.众多的数字音频系统已经进入消费市场,例如数字音频录音带.数字声音处理器.对于设备和生产厂家来说,标准化的信息传输结构可以提 ...

  8. OGG的孩子-有损音频编码opus

    Opus是一个有损声音编码的格式,由Xiph.Org基金会开发,之后由互联网工程任务组(IETF)进行标准化,目标用希望用单一格式包含声音和语音, 取代Speex和Vorbis,且适用于网络上低延迟的 ...

  9. js压缩文件读取处理

    1.引入必须依赖库jszip+jsutils=>>>建议使用以下版本,其他版本的jszip会报错 <!--zip文件读取--> <script src=" ...

  10. 在HTML页面中加载js文件和css文件的方法

    1.在HTML页面加载js文件的方法: function loadScriptFile(filePath){ var script = document.createElement("scr ...