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. 解决myeclipse部署按钮不能点

    找到MyEclipse的工作路径(一般点开myeclipse是会显示),然后到这个目录中去“\.metadata\.plugins\org.eclipse.core.runtime\.settings ...

  2. 七行代码开始flask

    前言: 对于现有的企业接口服务实现方式来说,Java比较适用于大型的并发式的业务场景:而对一些低IO的且功能简单的数据接口来说,Python似乎更合适.近几年流行的Flask可以说是专为接口式开发而生 ...

  3. Pycharm使用总结

    1.代码整体向右移动 按住Win+TAB可以快速向右缩进一个tab 的距离,按住Shift + TAB反方向前进一个TAB距离 2.Model加入get,set 方法 在编辑框中右击,选择genera ...

  4. C#对象深度克隆

    有基础的开发者都应该很明白,对象是一个引用类型,例如: object b=new object(); object a=b; 那么a指向的是b的地址,这样在有些时候就会造成如果修改a的值,那么b的值也 ...

  5. HTML之前端操作div标签布局

    事例图片: div元素是用于分组HTML元素的块级元素 上图代码示例如下: <!DOCTYPE html> <html lang="en"> <hea ...

  6. Python多线程编程(第二篇)

    一.Python中的上下文管理器(contextlib模块) 上下文管理器的任务是:代码块执行前准备,代码块执行后收拾 1.如何使用上下文管理器: 如何打开一个文件,并写入"hello wo ...

  7. Maven教程(1)--maven的下载、安装与配置

    Maven下载 下载地址:http://maven.apache.org/download.cgi 下载后,解压得到 Maven目录分析: bin文件夹:含有mvn运行的脚本 boot文件夹:含有pl ...

  8. 在虚拟机中安装metasploit官方攻防模拟器

    首先我们要在windwos下载安装perl环境.下载地址: http://pan.baidu.com/s/1i3GLKAp 然后我们安装 点击next 我同意,next next next,然后他会安 ...

  9. Python 操作 GA API 指南

    因为需要写一个 Blog Feature 的缘故,所以接触了下 GA 的 Python API,发现 G 家的 API 不是那么直观,比较绕,但是,在使用过程中发现其实 G 家的 API 设计挺有意思 ...

  10. HDU 2639 Bone Collector II(01背包变形【第K大最优解】)

    Bone Collector II Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others ...