gcc常见选项(zz)

前三章:
要点
 
1。强烈推荐使用-Wall选项;
注:Warning 的显示格式: file:line-number:message
 
2。编译选项
-o 文件名:直接产生可执行文件
-c 文件名:只编译为.o的库文件,不链接 (.c => .o )
 
在将多个.o连接为一个可执行文件时,仅使用-o指定可执行文件名即可,不需要使用
-Wall选项,因为链接是一个明确的过程(unambiguous),只有successed或者fail
两种结果。
 
incidentally [InsI5dentElI] adv. 附带地, 顺便提及(学单词一个:)
 
分两步处理:
每个.c文件编译为.o,然后通过linker连接为一个可执行文件;
这样每次只编译修改过的.c文件,可以缩短整体编译时间:
An object file contains machine code where any references to the memory addresses of functions(orvariables)in other files are left undefined.This allows source files to be compiled without direct reference to each other.The linker fills in these missing addresses when it produces the executable.
 
3。连接解析顺序:
在类unix的系统中,编译器和链接器是通过在命令行中从左向右的顺序检索各个文件。这就意味着:
含有函数定义的.o文件要放在那些调用该函数的.o文件的右边。
This means that the object file which contains the definition of a function should appear after any files which call that function.
 
4。库的连接
A library is a collection of precompiled object files which can be linked into programs. Libraries are typically stored in special archive files with the extension‘.a’, referred to as static libraries.They are created from object files with a separate tool, the GNU archiver ar, and used by the linker to resolve references to functions at compile-time.
 
-l参数:指定欲链接的库名称
比如我们相连接标准库目录(/usr/lib, /lib)下的数学库libm.a,那么我们可以这样指定:
-lm (具体见下面的解释)
 
In general, the compiler option ‘-lNAME’ will attempt to link object
files with a library file ‘libNAME.a’ in the standard library directories.
Additional directories can specified with command-line options and environment
variables, to be discussed shortly. A large program will typically
use many ‘-l’ options to link libraries such as the math library, graphics
libraries and networking libraries.
 
5。其他的一些编译选项
5.1 -I,-L
假如程序中使用的头文件路经和链接时使用的.a路径不是缺省的系统路径(如下)
By default, gcc searches the following directories for header files:
/usr/local/include/
/usr/include/
and the following directories for libraries:
/usr/local/lib/
/usr/lib/
 
则,需要利用 -I 来指定头文件的include路径
需要利用 -L 来指定.a文件的库文件路径
(注:不要在文件include中使用绝对路径来避免这个问题,因为这样对移植后的编译不利)
 
同时,也可以利用环境变量来解决搜索路径的问题(Environment variables)
对于include 问题:
Additional directories can be added to the include path using the environment
variable C_INCLUDE_PATH (for C header files) or CPLUS_INCLUDE_PATH (for C++ header files).
举例:
$ C_INCLUDE_PATH=/opt/gdbm-1.8.3/include
$ export C_INCLUDE_PATH
这样这个头文件路经就被添加到了环境变量中了(利用export使得其他模块也可见该变量)
 
同样的添加库文件路经:
additional directories can be added to the link path using the environment variable LIBRARY_PATH.
举例:
$ LIBRARY_PATH=/opt/gdbm-1.8.3/lib
$ export LIBRARY_PATH
 
那么,想指定多个路径可以采用下面的格式:
dir1:dir2:dir3:......
其中每一个单独的路径用 : 隔开;
一个点 . 表示当前路径
举例:
$ C_INCLUDE_PATH=.:/opt/gdbm-1.8.3/include:/net/include (含三个路径)
$ LIBRARY_PATH=.:/opt/gdbm-1.8.3/lib:/net/lib (含三个路径)
5.2 静态库和共享库(static libraries and shared libraries.)
库有两种方式存在,
Static libraries are the ‘.a’ files seen earlier.
Shared libraries are handled with a more advanced form of linking, which makes the executable file smaller. They use the extension ‘.so’,which stands for shared object.
 
[ 短语:in preference to 优先于... ]
 
.so的文件是动态链接并执行的。
当我们指定一个路径下的库文件名时,假如此时同时存在xxx.a和xxx.so的两个库形式,那么
优先选择.so链接。(共享库优先
 
当执行函数动态链接.so时,如果此文件不在缺省目录下‘/usr/local/lib’ and ‘/usr/lib’.
那么就需要指定环境变量LD_LIBRARY_PATH (方式和上面include,lib path相同)
 
假如现在需要在已有的环境变量上添加新的路径名,则采用如下方式:
LD_LIBRARY_PATH=NEWDIRS:$LD_LIBRARY_PATH.(newdirs是新的路径串)
 
(注:gnu系统可以自动添加在 /etc/ld.so.conf文件中来实现环境变量的设置)
 
-static
使用该选项可以强制编译器生成静态库文件
 
6. C语言标准
-ansi
the compiler option‘-ansi’ disables those GNU extensions which conflict with the ANSI/ISO standard.
 
-pedantic
The command-line option ‘-pedantic’ in combination with ‘-ansi’ will
cause gcc to reject all GNU C extensions, not just those that are incompatible
with the ANSI/ISO standard. This helps you to write portable
programs which follow the ANSI/ISO standard.
 
-std
The specific language standard used by GCC can be controlled with the‘-std’ option.
包含有:
‘-std=c89’ or ‘-std=iso9899:1990’-- The original ANSI/ISO C language standard
‘-std=iso9899:199409’-- The ISO C language standard with ISO Amendment 1, published
in 1994.
‘-std=c99’ or ‘-std=iso9899:1999’-- The revised ISO C language standard,
published in 1999 (ISO/IEC9899:1999).
‘-std=gnu89’ and ‘-std=gnu99’. -- for GNU extensions
 
 
7.关于warning -Wall的具体选项
以下的一些编译选项都是包含在Wall中的一些具体项目,可以单独使用。
‘-Wcomment’ This option warns about nested comments.
‘-Wformat’ This option warns about the incorrect use of format strings in functions
such as printf and scanf, where the format specifier does not agree with the
type of the corresponding function argument.
‘-Wunused’ This option warns about unused variables.
‘-Wimplicit’ This option warns about any functions that are used without being declared.
‘-Wreturn-type’ This option warns about functions that are defined without a return
type but not declared void. It also catches empty return statements in
functions that are not declared void.
 
8. 其他的一些warn编译选项(不包含在Wall中的)
‘-W’ This is a general option similar to ‘-Wall’ which warns about a selection of
common programming errors, such as functions which can return without a value
(also known as “falling off the end of the function body”), and comparisons
一般情况下,-W 和 -Wall同时使用
‘-Wconversion’ This option warns about implicit type conversions that could cause
unexpected results.
‘-Wshadow’ This option warns about the redeclaration of a variable name in a scope where
it has already been declared.
‘-Wcast-qual’ This option warns about pointers that are cast to remove a type qualifier,
such as const.
‘-Wwrite-strings’ This option implicitly gives all string constants defined in the program
a const qualifier, causing a compile-time warning if there is an attempt
to overwrite them.
‘-Wtraditional’ This option warns about parts of the code which would be interpreted
differently by an ANSI/ISO compiler and a “traditional” pre-ANSI
compiler.(5)
上面的这些warn选项都仅仅产生warn,而不会停止编译过程,下面的选项可以将warn视为error并停止编译
‘-Werror’ changes the default behavior by converting warnings into errors, stopping
the compilation whenever a warning occurs.
between signed and unsigned values.


一般情况下,-W 和 -Wall同时使用
‘-Wconversion’ This option warns about implicit type conversions that could cause
unexpected results.
‘-Wshadow’ This option warns about the redeclaration of a variable name in a scope where
it has already been declared.
‘-Wcast-qual’ This option warns about pointers that are cast to remove a type qualifier,
such as const.
‘-Wwrite-strings’ This option implicitly gives all string constants defined in the program
a const qualifier, causing a compile-time warning if there is an attempt
to overwrite them.
‘-Wtraditional’ This option warns about parts of the code which would be interpreted
differently by an ANSI/ISO compiler and a “traditional” pre-ANSI
compiler.(5)
上面的这些warn选项都仅仅产生warn,而不会停止编译过程,下面的选项可以将warn视为error并停止编译
‘-Werror’ changes the default behavior by converting warnings into errors, stopping
the compilation whenever a warning occurs.
 
 
第四章:使用预处理器 ( Using the preprocessor )
GCC的预处理器 cpp属于GCC包的一部分;在原文件被编译之前,GCC会使用cpp将所有的宏扩展。
 
4.1定义宏(macro)
有两种定义的宏的方式:1:其他原文件中;2:在GCC的命令行中使用 -Dxxx
当这些宏被定义后(#define xxx)
在系统中使用时:#ifdef xxx 就会被预处理器扩展为有效代码;
 
在系统中已经定义了一些系统命名空间内的宏,都是以 __ 开头的(两条下划线)
使用命令:$ cpp -dM /dev/null 可以查看到所有的预定义宏
 
(注:在这些宏中,有一些是GCC系统级的宏,它们都不是以__开头,这些非标准的宏可以使用
GCC的编译选项 -ansi 使其无效)
(其实,利用-Dxxx来定义xxx,就是将xxx赋值为1 )
 
4.2 定义有值宏
也是利用 -Dxxx = value的方式来定义
 
假如利用-DNAME="" (空)来定义一个宏,则这个宏也被视为被定义的,但是如果按值展开的话,
则为空;
 
4.3 预处理源文件
 
The ‘-E’ option causes gcc to run the preprocessor, display the expanded
output, and then exit without compiling the resulting source code.
可以利用 -E选项来查看预处理器的工作过程
 
可以利用 -save-temps选项来保存预处理器的处理过程日志到临时文件xxxx.i;
 
The preprocessed system header files usually generate a lot of output.
This can be redirected to a file, or saved more conveniently using the gcc
‘-save-temps’ option:
$ gcc -c -save-temps hello.c
After running this command, the preprocessed output will be available
in the file ‘hello.i’. The ‘-save-temps’ option also saves ‘.s’ assembly
files and ‘.o’ object files in addition to preprocessed ‘.i’ files.
 
第五章:Compiling for debugging
一个可执行文件中并不保存任何与其源文件中相关的函数以及变量信息在其中,可执行文件
只是机器码的集合。
这样的话,如果系统运行过程中出现错误,我们也不能定位错误。
利用 -g 编译选项,可以将这些信息保存在执行文件中,使得我们可以利用gdb工具调试;
保存的信息有:函数名,变量名(及其所有引用)以及它们的相应行号,这些信息都保存
在叫做符号表的东东中;
 
5.1 Core文件
When a program exits abnormally the operating system can write out a core file,
usually named ‘core’, which contains the in-memory state of the program at the
time it crashed.
 
当我们运行程序发生错误时,假如提示信息中包含‘core dumped’错误信息时,操作系统
已经产生了一个叫做core的文件到当前目录(或者/var/coredumps/下)
 
(注:In the GNU Bash shell the command ulimit -c controls the maximum
size of core files. If the size limit is zero, no core files are produced.
命令$ ulimit -c unlimited 使得任何大小的core文件都可以生成,但是这些设置只在
当前shell有效)
 
使用命令 $ gdb EXECUTABLE-FILE CORE-FILE 来分析
 
 
第六章:优化编译
 
6.1 Source-level optimization 代码级优化
在此只介绍两种:common subexpression eliminationfunction inlining.
 
Common subexpression elimination:(CSE)
只要优化开关打开,这种优化都会进行,进行这种优化既可以提高速度,又可以减少
代码大小,例如:
x = cos(v)*(1+sin(u/2)) + sin(w)*(1-sin(u/2))
可以写成:
t = sin(u/2)
x = cos(v)*(1+t) + sin(w)*(1-t)
(利用中间变量减少运算次数)
 
function inlining:
 
6.2 Speed-space tradeoffs 速度-空间权衡
 
6.2.1 Loop unrolling
例如:
for (i = 0; i < 8; i++)
{
y[i] = i;
}
很多的时间花费在判断上,可以改写为:
y[0] = 0;
y[1] = 1;
y[2] = 2;
y[3] = 3;
y[4] = 4;
y[5] = 5;
y[6] = 6;
y[7] = 7;
这样可以达到最快的执行速度(没有判断语句,同时可以利用流水线),但是空间也增大了
另外一例:
for (i = 0; i < n; i++)
{
y[i] = i;
}
可以重新写成:
for (i = 0; i < (n % 2); i++)
{
y[i] = i;
}
for ( ; i + 1 < n; i += 2) /* no initializer */
{
y[i] = i;
y[i+1] = i+1;
}
The first loop handles the case i = 0 when n is odd, and the second loop
handles all the remaining iterations. Note that the second loop does
not use an initializer in the first argument of the for statement, since
it continues where the first loop finishes. The assignments in the second
loop can be parallelized, and the overall number of tests is reduced by a
factor of 2 (approximately). Higher factors can be achieved by unrolling
more assignments inside the loop, at the cost of greater code size.
 
6.3 scheduling
When scheduling is enabled, instructions must be arranged so that
their results become available to later instructions at the right time, and to
allow for maximum parallel execution. Scheduling improves the speed of
an executable without increasing its size, but requires additional memory
and time in the compilation process itself (due to its complexity).
 
6.4 优化等级
优化等级分为:0 - 3
编译选项为: -Olevel
各等级含义如下:
 
‘-O0’ or no ‘-O’ option (default)不优化
At this optimization level GCC does not perform any optimization
and compiles the source code in the most straightforward way
possible. Each command in the source code is converted directly
to the corresponding instructions in the executable file, without
rearrangement. This is the best option to use when debugging a
program
.
The option ‘-O0’ is equivalent to not specifying a ‘-O’ option.
‘-O1’ or ‘-O’
This level turns on the most common forms of optimization that
do not require any speed-space tradeoffs. With this option the
resulting executables should be smaller and faster than with ‘-O0’.
The more expensive optimizations, such as instruction scheduling,
are not used at this level.
Compiling with the option ‘-O1’ can often take less time than compiling
with ‘-O0’, due to the reduced amounts of data that need to
be processed after simple optimizations.
‘-O2’ This option turns on further optimizations, in addition to those
used by ‘-O1’. These additional optimizations include instruction
scheduling
. Only optimizations that do not require any speed-space
tradeoffs are used, so the executable should not increase in size. The
compiler will take longer to compile programs and require more
memory than with ‘-O1’. This option is generally the best choice
for deployment of a program, because it provides maximum optimization
without increasing the executable size. It is the default
optimization level for releases of GNU packages.
‘-O3’ This option turns on more expensive optimizations, such as function
inlining, in addition to all the optimizations of the lower levels
‘-O2’ and ‘-O1’. The ‘-O3’ optimization level may increase the speed
of the resulting executable, but can also increase its size. Under
some circumstances where these optimizations are not favorable,
this option might actually make a program slower.
‘-funroll-loops’
This option turns on loop-unrolling, and is independent of the other
optimization options. It will increase the size of an executable.
Whether or not this option produces a beneficial result has to be
examined on a case-by-case basis.
‘-Os’ This option selects optimizations which reduce the size of an executable.
The aim of this option is to produce the smallest possible
executable, for systems constrained by memory or disk space. In
some cases a smaller executable will also run faster, due to better
cache usage.
 
注:For most purposes it is satisfactory to use ‘-O0’ for debugging, and
‘-O2’ for development and deployment.
 
“optimizations may not necessarily make a program faster in every case.”
 
第七章:编译C++程序
GCC是一个真正的C++编译器,其直接将C++代码编译为汇编代码。
 
1。利用g++而不是gcc命令;
(注:C++ source code should be given one of the valid C++ file extensions ‘.cc’,
‘.cpp’, ‘.cxx’ or ‘.C’ rather than the ‘.c’ extension used for C programs.)
 
2。C++标准库模板
The C++ standard library ‘libstdc++’ supplied with GCC provides a wide
range of generic container classes such as lists and queues, in addition to
generic algorithms such as sorting。
 
3。Explicit template instantiation
To achieve complete control over the compilation of templates with g++
it is possible to require explicit instantiation of each occurrence of a template,
using the option ‘-fno-implicit-templates’.
 
第八章:平台相关的选项
利用 -m 选项来确定不同的开发平台
 
 
获得GCC的帮助文档:
$ gcc -v --help
$ gcc -v --help 2>&1 | more
获得GCC的版本号:
$ gcc --version
(注:The ‘-v’ option can also be used to display detailed information about the
exact sequence of commands used to compile and link a program)
 
第十章:编译器相关的工具
 
1。 ar工具 Creating a library with the GNU archiver
The GNU archiver ar combines a collection of object files into a single
archive file, also known as a library.
ar工具可以将要发布的多个.o文件组装成一个.a的库文件
例如:将hello_fn.o和bye_fn.o生成 libhello.a的命令行:
$ ar cr libhello.a hello_fn.o bye_fn.o
其中The option ‘cr’ stands for “create and replace”.
 
利用 选项 t 可以查看.a文件中所包含的所有.o的信息
$ ar t libhello.a
hello_fn.o
bye_fn.o
 
2。程序性能测试工具-gprof
To use profiling, the program must be compiled and linked with the ‘-pg’
profiling option:
$ gcc -Wall -c -pg collatz.c
$ gcc -Wall -pg collatz.o
编译和链接的时候添加选项 -pg ,才能使用gprof测试程序性能
 
然后运行编译通过的程序,才能产生gprof需要的文件 gmon.out(在当前目录下)
然后执行:
$ gprof a.out (假设可执行文件是缺省生成的)
 
3。程序覆盖测试工具- gcov
The GNU coverage testing tool gcov analyses the number of times each
line of a program is executed during a run. This makes it possible to
find areas of the code which are not used, or which are not exercised
in testing.
When combined with profiling information from gprof the
information from coverage testing allows efforts to speed up a program to
be concentrated on specific lines of the source code.
 
编译和链接必须使用相关选项,才可以使用gcov工具。
例如:
$ gcc -Wall -fprofile-arcs -ftest-coverage cov.c
其中
‘-ftest-coverage’ adds instructions for counting the number of times
individual lines are executed,
‘-fprofile-arcs’ incorporates instrumentation code for each branch of
the program. Branch instrumentation records how frequently
different paths are taken through‘if’ statements and
other conditionals.
运行通过编译的程序,产生供gcov使用的文件:
分别带有后缀:‘.bb’‘.bbg’ and ‘.da’在当前目录下
然后运行
$ gcov cov.c (注意:是源代码文件
这样会产生一个带有标注的源文件的副本文件,后缀为 .gcov
在该文件中,标注了每一行代码的执行次数,标注为‘######’的语句为
未被执行到的语句。
可以通过命令:
grep ’######’ *.gcov 查找到所有未被执行到的语句
 
第十一章:编译器工作过程
 
Compilation is a multi-stage process involving several
tools, including the GNU Compiler itself (through the gcc or g++ frontends),
the GNU Assembler as, and the GNU Linker ld. The complete
set of tools used in the compilation process is referred to as a toolchain.
 
toolchain的定义见此:)
 
调用GCC的内部过程如下:
• preprocessing (to expand macros) 预处理
• compilation (from source code to assembly language) 编译
• assembly (from assembly language to machine code) 汇编
• linking (to create the final executable) 链接
 
详细描述如下:
1。preprocessing:
举例:第一步GCC会调用如下命令
 
$ cpp hello.c > hello.i
 
生成中间文件 hello.i(如果是C++文件的话,就是 hello.ii)
这种中间文件不会保存到磁盘上的,除非添加了编译选项-save-temps
 
2。compilation:
第二步:调用gcc(或者g++)生成汇编文件而不是.o文件(使用了-S选项)
 
$ gcc -Wall -S hello.i
 
这样就生成了基于x86 CPU的汇编文件 hello.s
 
3.assembly:
The purpose of the assembler is to convert assembly language into machine
code and generate an object file. When there are calls to external
functions in the assembly source file, the assembler leaves the addresses
of the external functions undefined, to be filled in later by the linker.
第三步调用
 
$ as hello.s -o hello.o
 
4。linking:
The final stage of compilation is the linking of object files to create an
executable. In practice, an executable requires many external functions
from system and C run-time (crt) libraries. Consequently, the actual link
commands used internally by GCC are complicated.
 
第四步调用
$ gcc hello.o
 
其实在GCC内部的这一步调用如下:
$ ld -dynamic-linker /lib/ld-linux.so.2 /usr/lib/crt1.o
/usr/lib/crti.o /usr/lib/gcc-lib/i686/3.3.1/crtbegin.o
-L/usr/lib/gcc-lib/i686/3.3.1 hello.o -lgcc -lgcc_eh
-lc -lgcc -lgcc_eh /usr/lib/gcc-lib/i686/3.3.1/crtend.o
/usr/lib/crtn.o(非常复杂)
 
第十二章:测试编译后文件的工具
 
1。Identifying files 鉴别文件 - file 命令
举例:
$ file a.out
a.out: ELF 32-bit LSB executable, Intel 80386,
version 1 (SYSV), dynamically linked (uses shared
libs), not stripped
 
最后一个not stripped表示该文件含符号表(可以利用命令strip去除符号表
 
2。查看符号表工具 - nm
举例:

vides maximum optimization
without increasing the executable size. It is the default
optimization level for releases of GNU packages.

‘-O3’ This option turns on more expensive optimizations, such as function
inlining, in addition to all the optimizations of the lower levels
‘-O2’ and ‘-O1’. The ‘-O3’ optimization level may increase the speed
of the resulting executable, but can also increase its size. Under
some circumstances where these optimizations are not favorable,
this option might actually make a program slower.
‘-funroll-loops’
This option turns on loop-unrolling, and is independent of the other
optimization options. It will increase the size of an executable.
Whether or not this option produces a beneficial result has to be
examined on a case-by-case basis.
‘-Os’ This option selects optimizations which reduce the size of an executable.
The aim of this option is to produce the smallest possible
executable, for systems constrained by memory or disk space. In
some cases a smaller executable will also run faster, due to better
cache usage.
 
注:For most purposes it is satisfactory to use ‘-O0’ for debugging, and
‘-O2’ for development and deployment.
 
“optimizations may not necessarily make a program faster in every case.”
 
第七章:编译C++程序
GCC是一个真正的C++编译器,其直接将C++代码编译为汇编代码。
 
1。利用g++而不是gcc命令;
(注:C++ source code should be given one of the valid C++ file extensions ‘.cc’,
‘.cpp’, ‘.cxx’ or ‘.C’ rather than the ‘.c’ extension used for C programs.)
 
2。C++标准库模板
The C++ standard library ‘libstdc++’ supplied with GCC provides a wide
range of generic container classes such as lists and queues, in addition to
generic algorithms such as sorting。
 
3。Explicit template instantiation
To achieve complete control over the compilation of templates with g++
it is possible to require explicit instantiation of each occurrence of a template,
using the option ‘-fno-implicit-templates’.
 
第八章:平台相关的选项
利用 -m 选项来确定不同的开发平台
 
 
获得GCC的帮助文档:
$ gcc -v --help
$ gcc -v --help 2>&1 | more
获得GCC的版本号:
$ gcc --version
(注:The ‘-v’ option can also be used to display detailed information about the
exact sequence of commands used to compile and link a program)
 
第十章:编译器相关的工具
 
1。 ar工具 Creating a library with the GNU archiver
The GNU archiver ar combines a collection of object files into a single
archive file, also known as a library.
ar工具可以将要发布的多个.o文件组装成一个.a的库文件
例如:将hello_fn.o和bye_fn.o生成 libhello.a的命令行:
$ ar cr libhello.a hello_fn.o bye_fn.o
其中The option ‘cr’ stands for “create and replace”.
 
利用 选项 t 可以查看.a文件中所包含的所有.o的信息
$ ar t libhello.a
hello_fn.o
bye_fn.o
 
2。程序性能测试工具-gprof
To use profiling, the program must be compiled and linked with the ‘-pg’
profiling option:
$ gcc -Wall -c -pg collatz.c
$ gcc -Wall -pg collatz.o
编译和链接的时候添加选项 -pg ,才能使用gprof测试程序性能
 
然后运行编译通过的程序,才能产生gprof需要的文件 gmon.out(在当前目录下)
然后执行:
$ gprof a.out (假设可执行文件是缺省生成的)
 
3。程序覆盖测试工具- gcov
The GNU coverage testing tool gcov analyses the number of times each
line of a program is executed during a run. This makes it possible to
find areas of the code which are not used, or which are not exercised
in testing.
When combined with profiling information from gprof the
information from coverage testing allows efforts to speed up a program to
be concentrated on specific lines of the source code.
 
编译和链接必须使用相关选项,才可以使用gcov工具。
例如:
$ gcc -Wall -fprofile-arcs -ftest-coverage cov.c
其中
‘-ftest-coverage’ adds instructions for counting the number of times
individual lines are executed,
‘-fprofile-arcs’ incorporates instrumentation code for each branch of
the program. Branch instrumentation records how frequently
different paths are taken through‘if’ statements and
other conditionals.
运行通过编译的程序,产生供gcov使用的文件:
分别带有后缀:‘.bb’‘.bbg’ and ‘.da’在当前目录下
然后运行
$ gcov cov.c (注意:是源代码文件
这样会产生一个带有标注的源文件的副本文件,后缀为 .gcov
在该文件中,标注了每一行代码的执行次数,标注为‘######’的语句为
未被执行到的语句。
可以通过命令:
grep ’######’ *.gcov 查找到所有未被执行到的语句
 
第十一章:编译器工作过程
 
Compilation is a multi-stage process involving several
tools, including the GNU Compiler itself (through the gcc or g++ frontends),
the GNU Assembler as, and the GNU Linker ld. The complete
set of tools used in the compilation process is referred to as a toolchain.
 
toolchain的定义见此:)
 
调用GCC的内部过程如下:
• preprocessing (to expand macros) 预处理
• compilation (from source code to assembly language) 编译
• assembly (from assembly language to machine code) 汇编
• linking (to create the final executable) 链接
 
详细描述如下:
1。preprocessing:
举例:第一步GCC会调用如下命令
 
$ cpp hello.c > hello.i
 
生成中间文件 hello.i(如果是C++文件的话,就是 hello.ii)
这种中间文件不会保存到磁盘上的,除非添加了编译选项-save-temps
 
2。compilation:
第二步:调用gcc(或者g++)生成汇编文件而不是.o文件(使用了-S选项)
 
$ gcc -Wall -S hello.i
 
这样就生成了基于x86 CPU的汇编文件 hello.s
 
3.assembly:
The purpose of the assembler is to convert assembly language into machine
code and generate an object file. When there are calls to external
functions in the assembly source file, the assembler leaves the addresses
of the external functions undefined, to be filled in later by the linker.
第三步调用
 
$ as hello.s -o hello.o
 
4。linking:
The final stage of compilation is the linking of object files to create an
executable. In practice, an executable requires many external functions
from system and C run-time (crt) libraries. Consequently, the actual link
commands used internally by GCC are complicated.
 
第四步调用
$ gcc hello.o
 
其实在GCC内部的这一步调用如下:
$ ld -dynamic-linker /lib/ld-linux.so.2 /usr/lib/crt1.o
/usr/lib/crti.o /usr/lib/gcc-lib/i686/3.3.1/crtbegin.o
-L/usr/lib/gcc-lib/i686/3.3.1 hello.o -lgcc -lgcc_eh
-lc -lgcc -lgcc_eh /usr/lib/gcc-lib/i686/3.3.1/crtend.o
/usr/lib/crtn.o(非常复杂)
 
第十二章:测试编译后文件的工具
 
1。Identifying files 鉴别文件 - file 命令
举例:
$ file a.out
a.out: ELF 32-bit LSB executable, Intel 80386,
version 1 (SYSV), dynamically linked (uses shared
libs), not stripped
 
最后一个not stripped表示该文件含符号表(可以利用命令strip去除符号表
 
2。查看符号表工具 - nm
举例:
$ nm a.out
08048334 t Letext
08049498 ? _DYNAMIC
08049570 ? _GLOBAL_OFFSET_TABLE_
........
080483f0 T main
08049590 b object.11
0804948c d p.3
U printf@GLIBC_2.0
 
其中: T表示该函数在此文件中有定义
U表示未定义的函数(需要link的外部函数)
所以,nm最常用的地方在于,查看这个文件中是否包含某函数的定义
 
3。寻找所需的动态链接库工具 - ldd
 
例如:
$ gcc -Wall hello.c
$ ldd a.out
libc.so.6 => /lib/libc.so.6 (0x40020000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
 
给命令同样可以用于动态链接库本身,来查找其所需要的链接库
 

 

pkg-config的用法 (zz)

pkg-config的用法

pkg-config

pkg-config程序是干什么用的?简单的说就是向用户向程序提供相应库的路径、版本号等信息的程序。
譬如说我们运行以下命令:
pkg-config 查看gcc的CFLAGS参数
$pkg-config --libs --cflags opencv
会显示如下信息:
-I/usr/include/opencv -lcxcore -lcv -lhighgui -lcvaux
各位看官,你看这不就是我们用gcc编译连接时CFLAGS的参数吗?
因此当我们需要编译连接某个库时,我们只需要把上面那行加入gcc 的参数里面即可。
这也是configure的作用,它会检查你需要的包,产生相应的信息。
pkg-config从哪儿知道这些信息的呢?它是从包名为xxx.pc这个文件中查找到的。拿上面那个例子说,它是从opencv.pc这个文件中查知的。
pkg-config 又怎么会知道opencv.pc这个文件呢?
下面我们看一下pkg-config是怎样工作的。
缺省情况下,pkg-config首 先在prefix/lib/pkgconfig/中查找相关包(譬如opencv)对应的相应的文件(opencv.pc)。在linux上上述路径名为 /usr/lib/pkconfig/。若是没有找到,它也会到PKG_CONFIG_PATH这个环境变量所指定的路径下去找。若是没有找到,它就会报 错,例如:
Package opencv was not found in the pkg-config search path.
Perhaps you should add the directory containing `opencv.pc'
to the PKG_CONFIG_PATH environment variable
No package 'opencv' found

设置环境变量PKG_CONFIG_PATH方法举例如下:
export PKG_CONFIG_PATH=/cv/lib:$PKG_CONFIG_PATH

================================================================
查看一个.pc文件的内容:
[root@yx pkgconfig]# cat glib-2.0.pc
prefix=/usr
exec_prefix=/usr
libdir=/lib
includedir=/usr/include
configexecincludedir=/usr/lib/glib-2.0/include

glib_genmarshal=glib-genmarshal
gobject_query=gobject-query
glib_mkenums=glib-mkenums

Name: GLib
Description: C Utility Library
Version: 2.12.3
Libs: -L${libdir} -lglib-2.0
Cflags: -I${includedir}/glib-2.0 -I${configexecincludedir}

[root@yx pkgconfig]# pwd
/usr/lib/pkgconfig

可见.pc文件 是对其的库文件路径,头文件路径,版本号,Cflags等一些参数进行封装。

再来看看第一个Gtk+程序里的
`pkg-config --cflags --libs gtk+-2.0`意思:
`pkg-config --cflags --libs gtk+-2.0` 是pkg-config从路径/usr/lib/pkgconfig
/gtk+-2.0.pc中提取出来的用于编译用的。

[root@yx pkgconfig]# cat gtk+-2.0.pc
prefix=/usr
exec_prefix=/usr
libdir=/usr/lib
includedir=/usr/include
target=x11

gtk_binary_version=2.10.0
gtk_host=i686-redhat-linux-gnu

Name: GTK+
Description: GIMP Tool Kit (${target} target)
Version: 2.10.4
Requires: gdk-${target}-2.0 atk cairo
Libs: -L${libdir} -lgtk-${target}-2.0
Cflags: -I${includedir}/gtk-2.0

显然,出可以自己来指定为:-L/usr/lib -lgtk-{target}-2.0 -I/usr/include/gtk-2.0
下面来看一下{target}该是多少:

[root@yx lib]# ls gt
gthumb/ gtk-2.0/ gtkhtml/
gtk/ gtk-sharp-2.0/ gtkmm-2.4/

[root@yx lib]# ls gtk-2.0/
2.10.0 2.4.0 immodules include modules

[root@yx lib]# ls gtk-sharp-2.0/
gconfsharp-schemagen.exe

[root@yx lib]# pwd
/usr/lib
所以认为-lgtk-{target}-2.0中的{target}该是空字符:
-lgtk-{target}-2.0====>-lgtk--2.0

At Last So:(理论大致上:)

-L/usr/lib -lgtk-{target}-2.0 -I/usr/include/gtk-2.0 ====>
-L/usr/lib -lgtk--2.0 -I/usr/include/gtk-2.0
而实际上更多些:
对比pkg-config对gtk+-2.0看实际效果:

[yuxu@yx base]$ pkg-config --cflags --libs gtk+-2.0
-I/usr/include/gtk-2.0 -I/usr/lib/gtk-2.0/include -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/pango-1.0 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/freetype2 -I/usr/include/libpng12 -L/lib -lgtk-x11-2.0 -lgdk-x11-2.0 -latk-1.0 -lgdk_pixbuf-2.0 -lm -lpangocairo-1.0 -lpango-1.0 -lcairo -lgobject-2.0 -lgmodule-2.0 -ldl -lglib-2.0
后面还有很多的路径哦。

 

zz PKG_CONFIG_PATH, pkg-config, configure

总结configure,pkg-config和PKG_CONFIG_PATH zz

我想大家都在linux下用源码安装过软件,源码安装软件的第一步是啥?下载源码,没错,小王,你太有才了..

其实真正的第一步是./configure.似曾相识哦。没错,那么我也时常见过pkg-config及pkg_config_path.这几这到底啥关系呢,这就是今天的主题。

1.什么是configure

configure会根据传入的配置项目检查程序编译时所依赖的环境以及对程序编译安装进行配置,最终生成编译所需的Makefile文件供程序Make读入使用进而调用相关编译程式(通常调用编译程序都是gcc)来编译最终的二进制程序。而configure脚本在检查相应依赖环境时(例:所依赖软件的版本、相应库版本等),通常会通过pkg-config的工具来检测相应依赖环境。

2.什么是pkg-config

pkg-config用来检索系统中安装库文件的信息,典型的是用作库的编译和连接。一般来说,如果库的头文件不在/usr/include目录中,那么在编译的时候需要用-I参数指定其路径。由于同一个库在不同系统上可能位于不同的目录下,用户安装库的时候也可以将库安装在不同的目录下,所以即使使用同一个库,由于库的路径的不同,造成了用-I参数指定的头文件的路径和在连接时使用-L参数指定lib库的路径都可能不同,其结果就是造成了编译命令界面的不统一。可能由于编译,连接的不一致,造成同一份程序从一台机器copy到另一台机器时就可能会出现问题。
pkg-config 就是用来解决编译连接界面不统一问题的一个工具。基本思想:pkg-config是通过库提供的一个.pc文件获得库的各种必要信息的,包括版本信息、编译和连接需要的参数等。需要的时候可以通过pkg-config提供的参数(–cflags, –libs),将所需信息提取出来供编译和连接使用。这样,不管库文件安装在哪,通过库对应的.pc文件就可以准确定位,可以使用相同的编译和连接命令,使得编译和连接界面统一。它提供的主要功能有:

<1> 检查库的版本号。如果所需库的版本不满足要求,打印出错误信息,避免连接错误版本的库文件。
<2> 获得编译预处理参数,如宏定义,头文件的路径。
<3> 获得编译参数,如库及其依赖的其他库的位置,文件名及其他一些连接参数。
<4> 自动加入所依赖的其他库的设置。

在默认情况下,每个支持 pkg-config 的库对应的.pc文件在安装后都位于安装目录中的lib/pkgconfig目录下.新软件一般都会安装.pc文件,没有可以自己创建,并且设置环境变量PKG_CONFIG_PATH寻找.pc文件路径,否则怎么找得到呢。使用pkg-config工具提取库的编译和连接参数有两个基本的前提:

<1> 库本身在安装的时候必须提供一个相应的.pc文件。不这样做的库说明不支持pkg-config工具的使用。
<2> pkg-config必须知道要到哪里去寻找此.pc 文件。

3.PKG_CONFIG_PATH.

上边的第二个基本条件就是设置这个环境变量了。环境变量PKG_CONFIG_PATH是用来设置.pc文件的搜索路径的,pkg-config按照设置路径的先后顺序进行搜索,直到找到指定的.pc 文件为止。这样,库的头文件的搜索路径的设置实际上就变成了对.pc文件搜索路径的设置。在安装完一个需要使用的库后,比如Glib,一是将相应的.pc文件,如glib-2.0.pc拷贝到/usr/lib/pkgconfig目录下,二是通过设置环境变量PKG_CONFIG_PATH添加glib-2.0.pc文件的搜索路径。
这样设置之后,使用Glib库的其它程序或库在编译的时候pkg-config就知道首先要到/opt/gtk/lib/pkgconfig这个目录中去寻找glib-2.0.pc了(GTK+和其它的依赖库的.pc文件也将拷贝到这里,也会首先到这里搜索它们对应的.pc文件)。之后,通过pkg-config就可以把其中库的编译和连接参数提取出来供程序在编译和连接时使用。另外还需要注意的是:环境变量的这种设置方式只对当前的终端窗口有效。如果到了没有进行上述设置的终端窗口中,pkg-config将找不到新安装的glib-2.0.pc文件、从而可能使后面进行的安装(如Glib之后的Atk的安装)无法进行。
  在我们采用的安装方案中,由于是使用环境变量对GTK+及其依赖库进行的设置,所以当系统重新启动、或者新开一个终端窗口之后,如果想使用新安装的GTK+库,需要如上面那样重新设置PKG_CONFIG_PATH和LD_LIBRARY_PATH环境变量。
  这种使用GTK+的方法,在使用之前多了一个对库进行设置的过程。虽然显得稍微繁琐了一些,但却是一种最安全的使用GTK+库的方式,不会对系统上已经存在的使用了GTK+库的程序(比如GNOME桌面)带来任何冲击。

 

GCC 命令行详解 zz

GCC 命令行详解 -L 指定库的路径 -l 指定需连接的库名

1。gcc包含的c/c++编译器
gcc,cc,c++,g++,gcc和cc是一样的,c++和g++是一样的,(没有看太明白前面这半句是什
么意思:))一般c程序就用gcc编译,c++程序就用g++编译

2。gcc的基本用法
gcc test.c这样将编译出一个名为a.out的程序
gcc test.c -o test这样将编译出一个名为test的程序,-o参数用来指定生成程序的名


3。为什么会出现undefined reference to 'xxxxx'错误?
首先这是链接错误,不是编译错误,也就是说如果只有这个错误,说明你的程序源码本
身没有问题,是你用编译器编译时参数用得不对,你没

有指定链接程序要用到得库,比如你的程序里用到了一些数学函数,那么你就要在编译
参数里指定程序要链接数学库,方法是在编译命令行里加入-lm。

4。-l参数和-L参数
-l参数就是用来指定程序要链接的库,-l参数紧接着就是库名,那么库名跟真正的库文
件名有什么关系呢?
就拿数学库来说,他的库名是m,他的库文件名是libm.so,很容易看出,把库文件名的
头lib和尾.so去掉就是库名了。

好了现在我们知道怎么得到库名了,比如我们自已要用到一个第三方提供的库名字叫lib
test.so,那么我们只要把libtest.so拷贝到/usr/lib

里,编译时加上-ltest参数,我们就能用上libtest.so库了(当然要用libtest.so库里
的函数,我们还需要与libtest.so配套的头文件)。

放在/lib/usr/lib/usr/local/lib里的库直接用-l参数就能链接了,但如果库文件
没放在这三个目录里,而是放在其他目录里,这时我们

只用-l参数的话,链接还是会出错,出错信息大概是:“/usr/bin/ld: cannot find
-lxxx”,也就是链接程序ld在那3个目录里找不到

libxxx.so,这时另外一个参数-L就派上用场了,比如常用的X11的库,它放在/usr/X11R
6/lib目录下,我们编译时就要用-L/usr/X11R6/lib -

lX11参数,-L参数跟着的是库文件所在的目录名。再比如我们把libtest.so放在/aaa/bb
b/ccc目录下,那链接参数就是-L/aaa/bbb/ccc -ltest

另外,大部分libxxxx.so只是一个链接,以RH9为例,比如libm.so它链接到/lib/libm.s
o.x,/lib/libm.so.6又链接到/lib/libm-2.3.2.so,

如果没有这样的链接,还是会出错,因为ld只会找libxxxx.so,所以如果你要用到xxxx
库,而只有libxxxx.so.x或者libxxxx-x.x.x.so,做一

个链接就可以了ln -s libxxxx-x.x.x.so libxxxx.so

手工来写链接参数总是很麻烦的,还好很多库开发包提供了生成链接参数的程序,名字
一般叫xxxx-config,一般放在/usr/bin目录下,比如

gtk1.2的链接参数生成程序是gtk-config,执行gtk-config --libs就能得到以下输出"-
L/usr/lib -L/usr/X11R6/lib -lgtk -lgdk -rdynamic

-lgmodule -lglib -ldl -lXi -lXext -lX11 -lm",这就是编译一个gtk1.2程序所需的g
tk链接参数,xxx-config除了--libs参数外还有一个参


数是--cflags用来生成头文
件包含目录的,也就是-I参数,在下面我们将会讲到。你可以试试执行gtk-config
--libs --cflags,看看输出结果。
现在的问题就是怎样用这些输出结果了,最笨的方法就是复制粘贴或者照抄,聪明的办
法是在编译命令行里加入这个`xxxx-config --libs --

cflags`,比如编译一个gtk程序:gcc gtktest.c `gtk-config --libs --cflags`这样
就差
不多了。注意`不是单引号,而是1键左边那个键。

除了xxx-config以外,现在新的开发包一般都用pkg-config来生成链接参数,使用方法
跟xxx-config类似,但xxx-config是针对特定的开发包

,但pkg-config包含很多开发包的链接参数的生成,用pkg-config --list-all命令可以
列出所支持的所有开发包,pkg-config的用法就是pkg

-config pagName --libs --cflags,其中pagName是包名,是pkg-config--list-all里
列出名单中的一个,比如gtk1.2的名字就是gtk+,pkg-

config gtk+ --libs --cflags的作用跟gtk-config --libs --cflags是一样的。比如:
gcc gtktest.c `pkg-config gtk+ --libs --cflags`



5。-include和-I参数
-include用来包含头文件,但一般情况下包含头文件都在源码里用#include xxxxxx实现
,-include参数很少用。-I参数是用来指定头文件目录

,/usr/include目录一般是不用指定的,gcc知道去那里找,但是如果头文件不在/usr/i
nclude里我们就要用-I参数指定了,比如头文件放

在/myinclude目录里,那编译命令行就要加上-I/myinclude参数了,如果不加你会得到
一个"xxxx.h: No such file or directory"的错误。-I

参数可以用相对路径,比如头文件在当前目录,可以用-I.来指定。上面我们提到的--cf
lags参数就是用来生成-I参数的。

6。-O参数
这是一个程序优化参数,一般用-O2就是,用来优化程序用的,比如gcc test.c -O2,优
化得到的程序比没优化的要小,执行速度可能也有所提

高(我没有测试过)。

7。-shared参数
编译动态库时要用到,比如gcc -shared test.c -o libtest.so

8。几个相关的环境变量
PKG_CONFIG_PATH:用来指定pkg-config用到的pc文件的路径,默认是/usr/lib/pkgconf
ig,pc文件是文本文件,扩展名是.pc,里面定义开发

包的安装路径,Libs参数和Cflags参数等等。
CC:用来指定c编译器。
CXX:用来指定cxx编译器。
LIBS:跟上面的--libs作用差不多。
CFLAGS:跟上面的--cflags作用差不多。
CC,CXX,LIBS,CFLAGS手动编译时一般用不上,在做configure时有时用到,一般情况
下不用管。
环境变量设定方法:export ENV_NAME=xxxxxxxxxxxxxxxxx

9。关于交叉编译
交叉编译通俗地讲就是在一种平台上编译出能运行在体系结构不同的另一种平台上,比
如在我们地PC平台(X86 CPU)上编译出能运行在sparc

CPU平台上的程序,编译得到的程序在X86 CPU平台上是不能运行的,必须放到sparc
CPU平台上才能运行。
当然两个平台用的都是linux。

这种方法在异平台移植和嵌入式开发时用得非常普遍。

相对与交叉编译,我们平常做的编译就叫本地编译,也就是在当前平台编译,编译得到
的程序也是在本地执行。

用来编译这种程序的编译器就叫交叉编译器,相对来说,用来做本地编译的就叫本地编
译器,一般用的都是gcc,但这种gcc跟本地的gcc编译器

是不一样的,需要在编译gcc时用特定的configure参数才能得到支持交叉编译的gcc。

为了不跟本地编译器混淆,交叉编译器的名字一般都有前缀,比如sparc-xxxx-linux-gn
u-gcc,sparc-xxxx-linux-gnu-g++ 等等

10。交叉编译器的使用方法
使用方法跟本地的gcc差不多,但有一点特殊的是:必须用-L和-I参数指定编译器用spar
c系统的库和头文件,不能用本地(X86)
的库(头文件有时可以用本地的)。
例子:
sparc-xxxx-linux-gnu-gcc test.c -L/path/to/sparcLib -I/path/to/sparcInclude