注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

老狗的博客

尽管每一步都很微小,但我确认我在进步

 
 
 

日志

 
 
关于我
sky

认真生活,努力工作 热爱技术,关注DB,存储,分布式,中间层,java,c++,php

网易考拉推荐

程序编译[c++ vs java] && 调试  

2012-07-12 08:22:12|  分类: 默认分类 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

c++的编译过程

c++的编译以cc或者cpp为单位

1. 预处理
gcc -E  test.cc
预处理阶段输入是代码的文本文件,.h 或者cc 或者 cpp
预处理阶段输出是后缀为ii的文件
预处理阶段进行 头文件的展开,宏的替换等

2. 编译
gcc -S test.cc
编译阶段输入是后缀为ii的文件
编译输出是.s文件
编译阶段做的事情就是将 文本形式的程序 转化为 文本形式的汇编代码

3. 汇编
gcc -c test.cc
汇编阶段输入是.s文件
汇编阶段输出是.o文件
汇编阶段做的事情就是将 文本形式的 汇编代码 转化为二进制形式

4. 连接
连接阶段输入是.o文件
链接阶段输出时.so或者.a,或者是可执行程序
链接阶段做的事情就是重新定位 编译单元中的 全局变量 和 函数

编译示例

test.cc

#include <stdio.h>

int main()
{
printf("hello,world\n");
return 0;
}

[liud@db-sf-rd00.db01.baidu.com myapp]$ g++ test.cc -o test -save-temps
[liud@db-sf-rd00.db01.baidu.com myapp]$ ls -al
总用量 52
drwxrwxr-x 2 liud liud 4096 7月 12 22:18 .
drwxrwxr-x 4 liud liud 4096 7月 12 22:09 ..
-rwxrwxr-x 1 liud liud 7093 7月 12 22:18 test
-rw-rw-r-- 1 liud liud 72 7月 12 22:10 test.cc
-rw-rw-r-- 1 liud liud 20704 7月 12 22:18 test.ii
-rw-rw-r-- 1 liud liud 1592 7月 12 22:18 test.o
-rw-rw-r-- 1 liud liud 930 7月 12 22:18 test.s


处理逻辑如下:

test.cc---->预处理---->test.ii---->编译----->test.s----->汇编----->test.o(目标文件)----->链接----->test

相关工具

g++实质是个空壳,其调用了其他预处理,汇编,链接程序,如下:
cc1plus: 预处理,编译
as: 汇编
collect2: 链接
ar : 打包目标文件为静态链接库
ld:  多个目标文件被链接为动态链接库
 
nm
 功能:列出object目标文件的符号(symbole)
For each symbol, nm shows:
The symbol value,hexadecimal by default.
he symbol type:
"A" The symbol's value is absolute, and will not be changed by further linking.
"B" The symbol is in the uninitialized data section (known as BSS).
"C" The symbol is common.  Common symbols are uninitialized data.   When  linking,  multiple  common
               symbols  may  appear  with the same name.  If the symbol is defined anywhere, the common symbols
               are treated as undefined references.
"D" The symbol is in the initialized data section.
"G" The symbol is in an initialized data section for small objects.  Some object file formats permit
               more efficient access to small data objects, such as a global int variable as opposed to a large
               global array.
 "I" The symbol is an indirect reference to another symbol.  This is a GNU  extension  to  the  a.out
               object file format which is rarely used.
 "N" The symbol is a debugging symbol.
 "R" The symbol is in a read only data section.
 "S" The symbol is in an uninitialized data section for small objects.
"T" The symbol is in the text (code) section.
"U" The symbol is undefined.
 "V" The symbol is a weak object.  When a weak defined symbol is linked with a normal defined symbol,
               the normal defined symbol is used with no error.  When a weak undefined symbol is linked and the
               symbol is not defined, the value of the weak symbol becomes zero with no error.
头文件的互相包含问题
什么是头文件的互相包含?
a.h->b.h a.h依赖于b.h, 也可以说a.h包含b.h
b.h->a.h b.h依赖于a.h, 也可以说b.h包含a.h
编译问题:
情况1: b.cc包含b.h
这个时候对b.cc进行预处理,会展开b.h,以及a.h, 但是展开过程会进行检查,遇到了环就不再展开,这个时候会形成如下依赖关系
b.cc -> b.h -> a.h
替换后,b.cc从上到下得部分为a.h-b.h-b.cc, 那如果a.h中的某些在b.h中声明的部分就会报错
情况2:a..cc包含a.h
总结:
在编程的过程中,一般是由简单模块到复杂模块的过程,比如a是b的子模块,但是a又用到了b的某些功能或者成员,
这个时候,要将a.h定义成自依赖的,b.h包含a.h, 这样才能解决问题
make

make命令读取makefile的依赖进行编译

make -C dir
执行动作:首先cd到dir,读取makefile,执行编译动作,然后回到当前目录

make规则

target : prerequisites
command

如果一行太长,可以用\进行分割
make支持三种通配符:* 和 ? 以及 [...]

target :           【可以是label,可以是可执行文件,也可以是object文件等】
prerequisites: 【产生target所需要的文件】
command:      【任意的shell命令,必须以tab键开始】
如果command由多个命令组成,则可以分成多行,如果两个命令有依赖关系,则需要写在一行,如下:
cd ../test; make
cp ../test/libprocess.so .

命令加@的区别则为是否将命令打印出来,默认打印,加上@则不在打印
命令前加-的区别是命令执行错误,则继续执行,默认不再继续执行

makefile中主要包含了五个东西:
1. 显式规则
2. 隐晦规则
3. 变量定义
4. 文件指示和注释
5. 注释,makefile只有行注释,和unix的shell脚本一样,其注释用#字符

自动变量:
$@: 代表规则中的目标文件名
$^ : 规则的所有依赖文件
$<: 规则的第一个依赖文件
$?: 依赖文件中比目标文件更新的文件列表

如果我们要定义标签作为目标,因为标签不是一个文件,我们必须设定它是一个伪目标
.PHONY : clean
clean: 
rm *.o *.tmp

run:
        for case in "$(allcase)";do ./$${case};done;
如果用到美元符号,则用两个$$符号进行替代

多目标最常用的用法
<targets ...>: <target-pattern>: <prereq-patterns ...>
commands
objects := "a.o b.o c.o"
$(objects) : %.o : %.cc
gcc -o $@ $<
自动推到如下:
a.o: a.cc
gcc -o a.o a.cc
b.o: b.cc
gcc -o b.o b.cc
c.o: c.cc
gcc -o c.o c.cc

CFLAGS : 需要传递给c编译器的一系列开关参数
CXXFLAGS : 需要传递给c++编译器的一系列开关参数
cc is for compiling C files, while cxx is for compiling C++ files
g++ 编译选项

-c : option says not
           to run the linker.  Then the output consists of object files output by the assembler.
完成预处理,编译,汇编步骤,输出.o文件,而不进行链接

-pipe
           Use pipes rather than temporary files for communication between the various stages of compilation.
使用Linux的pipe功能,将预处理,编译,汇编,链接,每一步骤的输出指向下一个步骤的输入,而不输出中间 文件
-o file
           Place output in file file.  This applies regardless to whatever sort of output is being produced,
           whether it be an executable file, an object file, an assembler file or preprocessed C code.
            将输出放入文件中,这个选项不管输出的类型是什么,不管是可执行文件,目标文件,汇编文件,或者预处理文件
-pedantic
Issue all the warnings demanded by strict ISO C and ISO C++; reject all programs that use forbidden exten-
           sions, and some other programs that do not follow ISO C and ISO C++.  For ISO C, follows the version of the
           ISO C standard specified by any -std option used.
发出所有ISO C和ISO c++要求的所有警告,拒绝使用了禁止的扩展的项目,和一些不遵守ISO c或者c++的项目,可以通过-std选项 指定需要遵守的ISO c标准

-std=standard
   "c++98"
               The 1998 ISO C++ standard plus amendments.
           "gnu++98"
               The same as -std=c++98 plus GNU extensions.  This is the default for C++ code.
-shared
           Produce a shared object which can then be linked with other objects to form an executable.  Not all
           systems support this option.  For predictable results, you must also specify the same set of options
           that were used to generate code (-fpic, -fPIC, or model suboptions) when you specify this option.[1]
           产生一个可以shared的目标文件,这个目标文件可以和其他的目标文件进行连接以形成可执行文件

 -static
           On systems that support dynamic linking, this prevents linking with the shared libraries.  On other
           systems, this option has no effect.
           对于支持动态连接的系统,这个选项阻止和shared libraries进行连接,在其他系统上,这个选项没有效果

 -fPIC
           If supported for the target machine, emit position-independent code, suitable for dynamic linking
           and avoiding any limit on the size of the global offset table.  This option makes a difference on
           the m68k and the SPARC.
            这个选项产生位置无关代码,适合于动态连接

-Wall
           Turns on all optional warnings which are desirable for normal code..
            打开所有可选的警告

-Werror
           Make all warnings into errors.
           让所有的warning成为错误

-fstrict-aliasing: 
Allows the compiler to assume the strictest aliasing rules applicable to the language being compiled. For C (and C++), this activates optimizations based on the type of expressions. In particular, an object of one type is assumed never to reside at the same address as an object of a different type, unless the types are almost the same. For example, an "unsigned int" can alias an "int", but not a "void*" or a "double". A character type may alias any other type. 

 Pay special attention to code like this:
//这样的代码 不会出问题
 union a_union {
 int i;
 double d;
 };
 int f() {
  { 
 a_union t;
 t.d = 3.0;
 return t.i;
 } 

 The practice of reading from a different union member than the one most recently written to (called "type-punning") is common. Even with -fstrict-aliasing, type-punning is allowed, provided the memory is accessed through the union type. So, the code above will work as expected. However, this code might not:
//如果这样的代码开启了fstrict-aliasing编译参数,进行-O1以上的优化,则会出问题 
 int f() { 
 a_union t; 
 int* ip; 
 t.d = 3.0;
 ip = &t.i; 
 return *ip; 
 } 

 Every language that wishes to perform language-specific alias analysis should define a function that com- putes, given an "tree" node, an alias set for the node. Nodes in different alias sets are not allowed to alias. For an example, see the C front-end function "c_get_alias_set". Enabled at levels -O2, -O3, -Os.


-g  
Produce debugging information in the operating system<E2><80><99>s native format (stabs, COFF, XCOFF, o
           r DWARF).  GDB can work with this debugging information.
           产生debug信息,GDB可以利用这些debug信息

 -finline-functions
           Integrate all simple functions into their callers.  The compiler heuristically decides which func-
           tions are simple enough to be worth integrating in this way.

           If all calls to a given function are integrated, and the function is declared "static", then the
           function is normally not output as assembler code in its own right.

           Enabled at level -O3.
           把所有简单的函数集成到调用者内,编译器启发性的决定哪些函数可以进行集成

    -D name
           Predefine name as a macro, with definition 1.
    -D name=definition
           Predefine name as a macro, with definition definition.  The contents of definition are tokenized and
           processed as if they appeared during translation phase three in a #define directive.  In particular,
           the definition will be truncated by embedded newline characters.

           If you are invoking the preprocessor from a shell or shell-like program you may need to use the
           shell<E2><80><99>s quoting syntax to protect characters such as spaces that have a meaning in the shell
           syntax.
            预定义name为宏,如同#define宏一样

-W               
         编译器的警告设置参数,拥有众多的选项,下面举一些常用的例子:
      -Woption 让编译器给出option指定的编译警告,常用的一些如下:
           unused-function: 遇到仅声明过但尚未定义的静态函数时发出警告。
                   unused-parameter: 从未用过的函数参数的警告。
                   unused-variable: 在本地声明但从未用过的变量的警告。
                   unused-value: 经计算但从未用过的值得警告。
                   return-type: 对函数返回类型不当的警告。
                   uninitialized:在初始化之前就使用自动变量。
                   float-equal:   比较两个浮点数是否相等。

-pg      
           在程序中加入剖分信息给gprof使用(profiler)

 -I dir
           Add the directory dir to the list of directories to be searched for header files
           将目录添加到头文件目录里列表中 

 -L.
           Normally the files found this way are library files---archive files whose members are object files
           指明library file的路径
           库的概念:库是为了方便服用代码二产生的,一堆cc产生了一段.o目标文件,如果管理这些目标文件,
方便复用,把几个.o的文件打包到一起也就有了库,本质上来说,一个库是.o的集合
        二进制在链接库的时候,会自动的从库的.o中查找函数定义,完成链接过程
      静态库通常为.a后缀:静态库在链接的时候,会将二进制程序使用到的.o都包含进去
      动态库为.so后缀:动态库在链接的时候,只会将二进制程序使用到的符号信息导入到了程序中,需要程序在运行的
时候去动态加载,就是你通过nm看到的

-lobjc
           You need this special case of the -l option in order to link an Objective-C program.
          选项指明要连接的库的名字,不如库名为libmysqlclient.a ,则-lmysqlclient

  -Wl,option
           Pass option as an option to the linker.  If option contains commas, it is split into multiple
           options at the commas.
           将option传递给linker,如果option包含commas,它将被拆分成多个选项
           大家经常可以看到:-Wl,-e,so_main,相应的具体含义可以man ld来进行查询,比如这里的-e,指的是设置so的
          入口为so_main
 

    -ggdb
           Produce debugging information for use by GDB.  This means to use the most expressive format available (DWARF
           2, stabs, or the native format if neither of those are supported), including GDB extensions if at all possible.

ar
 c   Create the archive.  The specified archive is always created if it did not exist, when you request an update.
           But a warning is issued unless you specify in advance that you expect to create it, by using this modifier.
s   Write an object-file index into the archive, or update an existing one, even if no other change  is  made  to
           the archive.  You may use this modifier flag either with any operation, or alone.  Running ar s on an archive
           is equivalent to running ranlib on it.
 r   Insert the files member... into archive (with replacement). This operation differs from q in that any  previ-
           ously existing members are deleted if their names match those being added.
ar rcs libxxx.a *.o
//可以用此命令为测试库打包一个.a文件,以便测试用来链接

gcc
SYNOPSIS
       gcc [-c│-S│-E] [-std=standard]
           [-g] [-pg] [-Olevel]
           [-Wwarn...] [-pedantic]
           [-Idir...] [-Ldir...]
           [-Dmacro[=defn]...] [-Umacro]
           [-foption...] [-mmachine-option...]
           [-o outfile] infile...
注意infile可以在-L -o -I之前或者之后,但是一定在-l之前,务必注意

ldd
 ldd - print shared library dependencies
ldd prints the shared libraries required by each program or shared library specified on the command line.
ldd可以将程序所依赖的库打印出来

LD_DEBUG
LD_DEBUG是个有趣的环境变量, 设置了以后,每执行一条命令,就会将这条命令的相关信息展示出来
[root@hebe21 /]# export LD_DEBUG="help"
[root@hebe21 /]# ls
Valid options for the LD_DEBUG environment variable are:

  libs        display library search paths
  reloc       display relocation processing
  files       display progress for input file
  symbols     display symbol table processing
  bindings    display information about symbol binding
  versions    display version dependencies
  all         all previous options combined
  statistics  display relocation statistics
  unused      determined unused DSOs
  help        display this help message and exit

To direct the debugging output into a file instead of standard output
a filename can be specified using the LD_DEBUG_OUTPUT environment variable.


c++ 调试[gdb]
1. 添加源代码目录
-d: gdb -d  ./src,默认采用PATH环境变量
(gdb) dir ~/src

2. 调用函数
(gdb) call func(10)

3. 打印变量表达式
print v1 + 1

4. 传递参数
方式1:
set args --defaults-file=../etc/my.cnf
方式2:
gdb --args ./programe arg1 arg2
就这样直接写参数就好
如果想查看参数,可以使用命令show args

5. stack trace
bt打印栈信息,有助于查看函数调用情况

6. 绑定进程
gdb --pid xxx

执行以后马上退出,避免了gdb过长时间
gdb -x ./debug -p xxx
cat ./debug
print a
print b
q

7. 设置断点 
b file.c:222

8. 跳到其他栈去查看变量等
frame 2

9. 查看当前源文件
list
list [linenumber]
以当前文件linenumber为中心,展示10行
可以通过set listsize 20设置list每次显示的行数
list firstline, lastline 展示firstline到lastline中间的代码

10. 重复上面的命令
 enter

11. whatis
查看变量类型

12. 调试core
gdb -c core ./redis-server
注意要加上程序文件,否则无法显示具体的一些信息

13. 显示宏
info macro N
注意在编译的时候,需要
gcc -gdwarf-2 -g3  -o test_macro test_macro.c
-gdwarf-2: 指的是debug的信息形式以dwarf-2的形式
 
g3: debug信息的level, g3包括一些多余的信息,这些信息有宏信息等
如果不用g3这个参数,将无法使用info macro N来查看宏定义

14. 多线程编译
info threads: 显示当前可调用的所有县城
thread id: 切换到指定id的线程

set scheduler-locking off|on:off所有线程执行,on,只有当前执行线程执行


15. 显示目前的所有断点
info break

16. 删除某个断点
delete n

17. 显示负责结构体的结构
pt 结构体名

18. 打印数组
print h@10, 显示 h后面的10个元素

19. pwd
显示当前工作目录

20.quit
退出gdb

21. so调试
so调试必须在so加载完成后,才能设置断点
比如说
a.c->server
b.c->libstr.so
server.c通过dlopen打开so进行使用,则如果
gdb server, 则这个时候程序还没有加载so,如果在b.c的文件内设置断点,则会
提示问题

22. until
1. 跳出循环
2. until [breakpoint] 运行到某个位置

23. 打印变量类型
whatis [变量]

24. finish

25. 设置断点
break方式
break function_name
break file:linenumber
watch方式
watch [expr]
当expr值改变的时候,停下来

26. 调试后台daemon
后台daemon往往为了避免和终端关联,需要fork几次,所以需要跟踪子进程
set follow-fork-mode child

java命令执行

 执行一个class: 

java [-options] class [args...]

options:
-cp <class search path of directories and zip/jar files>

系统对于core文件的限制
ulimit -c:如果是0,则说明core文件生成被关闭
ulimit -c unlimited
ulimit -c 50240

backtrace的使用

void
nc_stacktrace(int skip_count)
{
void *stack[64];
char **symbols;
int size, i, j;
//backtrace获取调用线程的 堆栈的地址列表,64指定了获取的最大层数
size = backtrace(stack, 64);

//将对应的地址列表解析为字符串
symbols = backtrace_symbols(stack, size);
if (symbols == NULL) {
return;
}
skip_count++; /* skip the current frame also */

for (i = skip_count, j = 0; i < size; i++, j++) {
printf("[%d] %s\n", j, symbols[i]);
}

free(symbols);
}

gcc -o tback ./t_back.c -g -rdynamic


[0] ./tback(test2+0xe) [0x4008d0]
[1] ./tback(test1+0xe) [0x4008e0]
[2] ./tback(main+0xe) [0x4008ff]
[3] /lib64/libc.so.6(__libc_start_main+0xf4) [0x3b3c01e144]
[4] ./tback [0x400779][0] ./tback(test2+0xe) [0x4008d0]
[1] ./tback(test1+0xe) [0x4008e0]
[2] ./tback(main+0xe) [0x4008ff]
[3] /lib64/libc.so.6(__libc_start_main+0xf4) [0x3b3c01e144]
[4] ./tback [0x400779]
[ xxxtest]$ addr2line -e ./tback 0x4008ff
/data1/liudong2/mywork/test/./t_back.c:53
rdynamic 指定链接的时候指示连接器把所有符号(而不仅仅只是程序已使用到的外部符号)都添加到动态符号表(即.dynsym表)里,以便那些通过 dlopen() 或 backtrace() (这一系列函数使用.dynsym表内符号)这样的函数使用。
http://www.tuicool.com/articles/EvIzUn
  评论这张
 
阅读(965)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018