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. Linux系统编程:简单文件IO操作

    使用Linux的文件API,经常看见一个东西,叫做文件描述符. 什么是文件描述符? (1)文件描述符其实实质是一个数字,这个数字在一个进程中表示一个特定的含义,当我们open打开一个文件时,操作系统在 ...

  2. jQuery 遍历函数(八)

    函数 描述 .add() 将元素添加到匹配元素的集合中. .andSelf() 把堆栈中之前的元素集添加到当前集合中. .children() 获得匹配元素集合中每个元素的所有子元素. .closes ...

  3. Redis锁构造

    单线程与隔离性 Redis是使用单线程的方式来执行事务的,事务以串行的方式运行,也就是说Redis中单个命令的执行和事务的执行都是线程安全的,不会相互影响,具有隔离性. 在多线程编程中,对于共享资源的 ...

  4. vue2.0 资源文件assets和static的区别

    资源文件处理 在我们的项目结构里,有两个资源文件的路径,分别是:src/assets 和 static/.那这两个到底有什么区别呢? Webpacked 资源 为了回答这个问题,我们首先需要理解web ...

  5. switchery按钮使用

    1.先引入switchery.css 和 switchery.js 2.绘制 checkbox按钮 : a.静态页面写法  未选中时 <input type="checkbox&quo ...

  6. CSS基础知识(概念、块级元素、行内元素、选择器)

    1.CSS概念 全称为Cascading Style Sheets(层叠样式表),支持专有的文件 - 扩展名为".css" 作用:将HTML的结构(HTML标签即html)与样式( ...

  7. 在HTML页面中获取当前项目根路径的方法

    在HTML页面获取项目根路径的方法: function getRootPath(){ var curPageUrl = window.document.location.href; var rootP ...

  8. 使用socket搭建一个网络聊天室

    #服务器端import socket import threading #创建一个TCP端 sock = socket.socket(socket.AF_INET, socket.SOCK_STREA ...

  9. JS原型、原型链深入理解

    原型是JavaScript中一个比较难理解的概念,原型相关的属性也比较多,对象有”prototype”属性,函数对象有”prototype”属性,原型对象有”constructor”属性. 一.初识原 ...

  10. 学习笔记-使用cmd命令行创建nodejs项目

    使用cmd命令行创建nodejs项目 1)在DOS下cd 进入到你想要创建项目的路径. 2)mkdir sing (创建一个sing文件夹) 3)cd sing  4) npm init (初始化工程 ...