GCC编译动态和静态链接库
- 格式:doc
- 大小:28.50 KB
- 文档页数:5
gcc 编译器命令总结1. 三种常用格式i.gcc C源文件-o 目标文件名。
ii.gcc -o 目标文件名C源文件。
iii.gcc C源文件。
(目标文件名默认为:a.out)2. gcc 支持的一些源文件的后缀.c C语言源代码文件。
.a 是由目标文件构成的档案库文件。
.C .cc 或.cxx 是C++ 源代码文件。
.h 是程序所包含的头文件。
.i 是已经预处理过的C源代码文件。
.ii 是已经预处理的C++源代码文件。
.m 是Objective-C源代码文件。
.o 是编译后的目标文件。
.s 是汇编语言源代码文件。
.S 是经过预处理的汇编语言源代码文件。
3.gcc 常用参数-c 只激活预处理,编译和汇编,也就是只把程序做成obj文件。
-S 只激活预处理和编译,就是把文件编译成汇编代码。
-E 只激活预处理,不生成文件,需要把它重定向到一个输出文件里面。
-g 在可执行文件中包含调试信息。
-v 显示gcc 版本信息。
-o file 把输出文件输出到文件中。
-I dir 在头文件的搜索路径中添加dir 目录。
-L dir 在库文件的搜索路径列表中添加dir目录。
-static 链接静态库。
-library 连接名为library的库文件。
4.例子实质上,上述编译过程是分为四个阶段进行的,即预处理(也称预编译,Preprocessing)、编译(Compilation)、汇编 (Assembly)和连接(Linking)。
4.1 示例程序如下:#include <stdio.h>int main(void){printf("Hello World!\n");return 0;}这个程序,一步到位的编译指令是:gcc test.c -o test该命令结束后,在文件目下生成(可执行文件)test通过./test 可运行本程序。
4.2 预处理gcc -E test.c -o test.i 或gcc -E test.c可以输出test.i文件中存放着test.c经预处理之后的代码。
工程的编译、链接及基本的调试手段。
1. 工程的编译在计算机科学中,编译是将高级语言源代码转换为机器语言可执行文件的过程。
要进行工程的编译,我们需要先安装相应的编译器,例如C++工程需要安装Microsoft Visual C++或者GCC等等。
然后通过编译器的命令行或者IDE工具,对工程的源代码进行编译。
编译器会对代码进行语义分析、词法分析、语法分析等等操作,生成中间语言,再通过优化生成目标平台的可执行文件。
2. 工程的链接链接是将编译生成的目标文件、库文件和系统提供的标准库文件等连接起来的过程。
在编译过程中,编译器只检查代码的正确性,而在链接过程中,会根据符号表查找函数、变量等的定义,将它们链接到目标文件中。
链接可以分为静态链接和动态链接两种方式。
静态链接将库文件中的函数和变量复制到可执行文件中,使得可执行文件比较大。
而动态链接则将库文件作为独立的文件存在,可供程序使用。
动态链接更节省空间,但需要保证动态库的兼容性。
3. 基本的调试手段调试是程序开发中不可或缺的环节。
通过调试可以解决在编译、链接过程中产生的错误,还可以查看变量的值、函数的执行情况等,从而方便程序的开发和维护。
基本的调试手段包括:- 打印调试信息:在代码中插入打印语句,输出程序中变量的值,以及代码执行过程中的状态信息。
- 断点调试:在代码中设置断点,当程序执行到该断点时,会暂停程序的执行,允许程序员查看程序状态,并进行相应的调整。
- 单步调试:逐行执行代码,查看程序在每一行的执行情况,从而找出导致程序崩溃的原因。
以上是工程编译、链接及基本的调试手段的简单介绍。
在真正的开发过程中,还需要掌握更多的工具和技巧,以提高程序的质量和效率。
1、用于linux系统下编程的编译器概述GCC(GNU Compiler Collection,GNU编译器套装),是一套由GNU 开发的编程语言编译器。
它是一套GNU编译器套装以GPL 及LGPL 许可证所发行的自由软件,也是GNU计划的关键部分,亦是自由的类Unix及苹果电脑Mac OS X 操作系统的标准编译器。
GCC 原名为GNU C 语言编译器,因为它原本只能处理C语言。
GCC 很快地扩展,变得可处理C++。
之后也变得可处理Fortran、Pascal、Objective-C、Jav a, 以及Ada与其他语言。
历史GCC是由理查德·马修·斯托曼在1985年开始的。
他首先扩增一个旧有的编译器,使它能编译C,这个编译器一开始是以Pastel语言所写的。
Pastel是一个不可移植的Pascal语言特殊版,这个编译器也只能编译Pastel语言。
为了让自由软件有一个编译器,后来此编译器由斯托曼和Len Tower在1987年以C语言重写并成为GNU 专案的编译器。
GCC的建立者由自由软件基金会直接管理。
在1997年,一群不满GCC缓慢且封闭的创作环境者,组织了一个名为EGCS 〈Experimental/Enhanced GNU Compiler System〉的专案,此专案汇整了数项实验性的分支进入某个GCC专案的分支中。
EGCS比起GCC的建构环境更有活力,且EGCS最终也在1999年四月成为GCC的官方版本。
GCC目前由世界各地不同的数个程序设计师小组维护。
它是移植到中央处理器架构以及操作系统最多的编译器。
由于GCC已成为GNU系统的官方编译器(包括GNU/Linux家族),它也成为编译与建立其他操作系统的主要编译器,包括BSD家族、Mac OS X、NeXTSTEP 与BeOS。
GCC通常是跨平台软件的编译器首选。
有别于一般局限于特定系统与执行环境的编译器,GCC在所有平台上都使用同一个前端处理程序,产生一样的中介码,因此此中介码在各个其他平台上使用GCC编译,有很大的机会可得到正确无误的输出程序。
gcc链接文件语法在GCC编译器中,链接文件的语法可以通过以下几种方式来指定:1. 直接指定文件名:gcc file1.c file2.c -o output.这种方式将会编译并链接`file1.c`和`file2.c`这两个源文件,并将生成的可执行文件命名为`output`。
2. 使用通配符:gcc .c -o output.这种方式将会编译并链接当前目录下所有以`.c`为后缀的源文件,并将生成的可执行文件命名为`output`。
3. 使用对象文件:gcc file1.o file2.o -o output.如果你已经通过其他方式将源文件编译为对象文件(`.o`文件),你可以直接链接这些对象文件。
这种方式可以提高编译的效率。
4. 使用静态库:gcc file.c -L/path/to/library -lmylib -o output.如果你使用了外部的静态库,你需要通过`-L`选项指定静态库所在的路径,通过`-l`选项指定要链接的静态库的名称。
这个例子中,`-lmylib`将会链接名为`libmylib.a`的静态库。
5. 使用动态库:gcc file.c -L/path/to/library -lmylib -o output.如果你使用了外部的动态库,你同样需要通过`-L`选项指定动态库所在的路径,通过`-l`选项指定要链接的动态库的名称。
这个例子中,`-lmylib`将会链接名为`libmylib.so`的动态库。
需要注意的是,链接文件的顺序也很重要。
GCC将按照文件在命令行中出现的顺序进行链接,因此如果某个源文件依赖于另一个源文件中定义的函数或变量,那么被依赖的源文件应该出现在依赖它的源文件之前。
以上是关于GCC链接文件语法的一些基本介绍,具体的使用方法还可以根据实际情况进行调整和扩展。
gcc的使⽤简介与命令⾏参数说明(⼀) gcc的基本⽤法(⼆) 警告提⽰功能选项(三) 库操作选项(四) 调试选项(五) 交叉编译选项(⼀) gcc的基本⽤法使⽤gcc编译器时,必须给出⼀系列必要的调⽤参数和⽂件名称。
不同参数的先后顺序对执⾏结果没有影响,只有在使⽤同类参数时的先后顺序才需要考虑。
如果使⽤了多个 -L 的参数来定义库⽬录,gcc会根据多个 -L 参数的先后顺序来执⾏相应的库⽬录。
因为很多gcc参数都由多个字母组成,所以gcc参数不⽀持单字母的组合,Linux中常被叫短参数(short options),如 -dr 与 -d -r 的含义不⼀样。
gcc编译器的调⽤参数⼤约有100多个,其中多数参数我们可能根本就⽤不到,这⾥只介绍其中最基本、最常⽤的参数。
gcc最基本的⽤法是:gcc [options] [filenames]其中,options就是编译器所需要的参数,filenames给出相关的⽂件名称,最常⽤的有以下参数:-c只编译,不链接成为可执⾏⽂件。
编译器只是由输⼊的 .c 等源代码⽂件⽣成 .o 为后缀的⽬标⽂件,通常⽤于编译不包含主程序的⼦程序⽂件。
-o output_filename确定输出⽂件的名称为output_filename。
同时这个名称不能和源⽂件同名。
如果不给出这个选项,gcc就给出默认的可执⾏⽂件 a.out 。
-g产⽣符号调试⼯具(GNU的 gdb)所必要的符号信息。
想要对源代码进⾏调试,就必须加⼊这个选项。
-O对程序进⾏优化编译、链接。
采⽤这个选项,整个源代码会在编译、链接过程中进⾏优化处理,这样产⽣的可执⾏⽂件的执⾏效率可以提⾼,但是编译、链接的速度就相应地要慢⼀些,⽽且对执⾏⽂件的调试会产⽣⼀定的影响,造成⼀些执⾏效果与对应源⽂件代码不⼀致等⼀些令⼈“困惑”的情况。
因此,⼀般在编译输出软件发⾏版时使⽤此选项。
-O2⽐ -O 更好的优化编译、链接。
gccstatic静态编译选项提⽰错误:usrlibld:cannotfind-lc 在学习gcc静态库动态库编译的时候选⽤静态库编译时出错显⽰:/usr/lib/ld:cannot find -lc百度:/usr/lib/ld:cannot find -lc多处给的解决⽅案为:然⽽并不能解决问题,最终定位发现是静态编译的问题。
⽽且不⽌会出现这种情况:/usr/lib/ld:cannot find -lc/usr/lib/ld:cannot find -lgcc_s/usr/lib/ld:cannot find -lm等的错误,主要原因在静态编译时需要链接静调库。
如上命令:[xiaohexiansheng@centos6 app]$ gcc -static -I./libs main.c -o app -L./libs -lcrypto -lfunc如果在编译时去掉-static选项选⽤动态库编译则不会出现此种情况[xiaohexiansheng@centos6 app]$ gcc -I./libs main.c -o app -L./libs -lcrypto -lfunc[xiaohexiansheng@centos6 app]$ lsapp libs main.c⾮静态编译时ldd filename,显⽰如下,这是可执⾏程序所需的动态库,运⾏可执⾏程序时需要的动态库。
[xiaohexiansheng@centos6 app]$ ldd applinux-gate.so.1 => (0x004ad000)libcrypto.so => /usr/lib/libcrypto.so (0x03ad9000)libfunc.so => not foundlibc.so.6 => /lib/libc.so.6 (0x0052a000)libdl.so.2 => /lib/libdl.so.2 (0x0070c000)libz.so.1 => /lib/libz.so.1 (0x00713000)/lib/ld-linux.so.2 (0x00508000)静态编译时需要将所有的.a库链接到可执⾏⽂件中,所以需要libc静态库⽂件,在系统找查找glibc-static提⽰没有库⽂件。
动态链接库*.so的编译与使用- -动态库*.so在linux下用c和c++编程时经常会碰到,最近在网站找了几篇文章介绍动态库的编译和链接,总算搞懂了这个之前一直不太了解得东东,这里做个笔记,也为其它正为动态库链接库而苦恼的兄弟们提供一点帮助。
1、动态库的编译下面通过一个例子来介绍如何生成一个动态库。
这里有一个头文件:so_test.h,三个.c文件:test_a.c、t est_b.c、test_c.c,我们将这几个文件编译成一个动态库:libtest.so。
so_test.h:#include <stdio.h>#include <stdlib.h>void test_a();void test_b();void test_c();test_a.c:#include "so_test.h"void test_a(){printf("this is in test_a...\n");}test_b.c:#include "so_test.h"void test_b(){printf("this is in test_b...\n");}test_c.c:#include "so_test.h"void test_c(){printf("this is in test_c...\n");}将这几个文件编译成一个动态库:libtest.so$ gcc test_a.c test_b.c test_c.c -fPIC -shared -o libtest.so2、动态库的链接在1、中,我们已经成功生成了一个自己的动态链接库libtest.so,下面我们通过一个程序来调用这个库里的函数。
程序的源文件为:test.c。
test.c:#include "so_test.h"int main(){test_a();test_b();test_c();return 0;}l 将test.c与动态库libtest.so链接生成执行文件test:$ gcc test.c -L. -ltest -o testl 测试是否动态连接,如果列出libtest.so,那么应该是连接正常了$ ldd test./test 执行test,可以看到它是如何调用动态库中的函数的。
gcc编译参数在GCC中,编译参数用于指定编译器的行为和选项。
这些参数可以对代码进行优化、生成调试信息、链接不同的库等等。
以下是一些常用的GCC编译参数:1.优化参数:--O0:不进行优化--O1:进行基本优化--O2:进行更多优化--O3:进行最大优化--Os:进行优化以缩小代码尺寸2.调试参数:--g:生成调试信息- -ggdb:生成GDB可用的调试信息- -gdwarf:生成DWARF调试信息3.警告参数:- -Wall:开启所有警告- -Werror:将所有警告视为错误- -Wextra:开启额外的警告- -Wno-unused-parameter:忽略未使用的函数参数的警告4.标准库参数:- -std=c89:使用C89标准- -std=c99:使用C99标准- -std=c11:使用C11标准- -std=c++98:使用C++98标准- -std=c++11:使用C++11标准- -std=c++14:使用C++14标准- -std=c++17:使用C++17标准5.预处理参数:- -D<symbol>=<value>:定义宏- -U<symbol>:取消宏定义- -I<dir>:指定头文件路径6.链接参数:- -L<dir>:指定库文件路径- -l<library>:链接库文件- -shared:生成共享库- -static:生成静态库7.其他参数:--c:只编译,不链接- -o <output>:指定输出文件名- -Wl,<option>:传递选项给链接器- -Wp,<option>:传递选项给预处理器这只是一小部分常用的GCC编译参数,GCC还提供了许多其他参数用于更精细地控制编译过程。
可以通过运行`gcc --help`命令查看GCC支持的所有编译参数。
gcc -fPIC编译选项分析1、-fPIC 作用于编译阶段,在编译动态库时(.so文件)告诉编译器产生与位置无关代码(Position-Independent Code),若未指定-fPIC选项编译.so文件,则在加载动态库时需进行重定向。
2、64位编译器下编译生成动态库时,出现以下错误:/usr/lib64/gcc/x86_64-suse-linux/4.3/../../../../x86_64-suse-li nux/bin/ld: ../../CI/script/server/lib/libz.a(adler32.o): relocation R_X86_64_32 against `.text' can not be used when making a shared object; recompile with -fPIC../../CI/script/server/lib/libz.a: could not read symbols: Bad value原因:提示说需要-fPIC编译,然后在链接动态库的地方加上-fPIC的参数编译结果还是报错,需要把共享库所用到的所有静态库都采用-fPIC编译一遍,才可以成功的在64位环境下编译出动态库。
3、为何在32位的编译器下编译,就不会报错呢?对于我们的32位环境来说, 编译时是否加上-fPIC, 都不会对链接产生影响, 只是一份代码的在内存中有几个副本的问题(而且对于静态库而言结果都是一样的).但在64位的环境下装载时重定位的方式存在一个问题就是在我们的64位环境下用来进行位置偏移定位的cpu指令只支持32位的偏移, 但实际中位置的偏移是完全可能超过64位的,所以在这种情况下编译器要求用户必须采用fPIC的方式进行编译的程序才可以在共享库中使用。
GCC常⽤命令详解GCC(GNU Compiler Collection)是Linux下最常⽤的C语⾔编译器,是GNU项⽬中符合ANSI C标准的编译系统,能够编译⽤C、C++和Object C等语⾔编写的程序。
同时它可以通过不同的前端模块来⽀持各种语⾔,如Java、Fortran、Pascal、Modula-3和Ada等。
穿插⼀个玩笑: GNU意思是GNU’s not Unix⽽⾮⾓马。
然⽽GNU还是⼀个未拆分的连词,这其实是⼀个源于hacker的幽默:GNU是⼀个回⽂游戏,第⼀个字母G是凑数的,你当然可以叫他做ANU或者BNU。
下⾯开始。
⼀.CC编译程序过程分四个阶段◆预处理(Pre-Processing)◆编译(Compiling)◆汇编(Assembling)◆链接(Linking)Linux程序员可以根据⾃⼰的需要让GCC在编译的任何阶段结束转去检查或使⽤编译器在该阶段的输出信息,或者对最后⽣成的⼆进制⽂件进⾏控制,以便通过加⼊不同数量和种类的调试代码来为今后的调试做好准备。
如同其他的编译器,GCC也提供了灵活⽽强⼤的代码优化功能,利⽤它可以⽣成执⾏效率更⾼的代码。
GCC提供了30多条警告信息和三个警告级别,使⽤它们有助于增强程序的稳定性和可移植性。
此外,GCC还对标准的C和C++语⾔进⾏了⼤量的扩展,提⾼程序的执⾏效率,有助于编译器进⾏代码优化,能够减轻编程的⼯作量。
⼆.简单编译命令我们以Hello world程序来开始我们的学习。
代码如下:/* hello.c */#include <stdio.h>int main(void){printf ("Hello world!\n");return 0;}1. 执⾏如下命令:$ gcc -o hello hello.c运⾏如下: $ ./hello输出: Hello,world!2. 我们也可以分步编译如下:(1) $ gcc –E hello.c -o hello.i//预处理结束//这时候你看⼀下hello.i ,可以看到插进去了很多东西。
简述gcc命令的选项GCC是GNU Compiler Collection的缩写,是一款开源的编译器,支持多种编程语言,包括C、C++、Objective-C、Fortran、Ada等。
GCC命令的选项非常多,可以根据不同的需求进行选择,下面将对GCC命令的选项进行简述。
1. 常用选项(1)-c:只编译不链接,生成目标文件。
(2)-o:指定输出文件名。
(3)-g:生成调试信息。
(4)-Wall:开启所有警告信息。
(5)-Werror:将警告信息视为错误。
(6)-O:优化选项,包括-O0、-O1、-O2、-O3等级别。
(7)-I:指定头文件搜索路径。
(8)-L:指定库文件搜索路径。
(9)-l:指定链接的库文件名。
2. 预处理选项(1)-E:只进行预处理,输出预处理结果。
(2)-D:定义宏。
(3)-U:取消定义宏。
(4)-I:指定头文件搜索路径。
(5)-M:输出依赖关系。
3. 编译选项(1)-S:只编译不汇编,生成汇编代码。
(2)-fPIC:生成位置无关代码。
(3)-fno-strict-aliasing:关闭严格别名规则。
(4)-fno-omit-frame-pointer:不省略函数栈帧指针。
(5)-fno-common:禁止共享数据段。
(6)-fno-builtin:禁用内建函数。
(7)-fno-stack-protector:禁用栈保护。
4. 链接选项(1)-shared:生成共享库。
(2)-static:生成静态库。
(3)-nostdlib:不使用标准库。
(4)-nodefaultlibs:不使用默认库。
(5)-Wl:传递参数给链接器。
(6)-rpath:指定运行时库搜索路径。
5. 其他选项(1)-v:显示编译器版本信息。
(2)-dumpversion:显示编译器版本号。
(3)-dumpmachine:显示编译器目标机器。
(4)-print-search-dirs:显示搜索路径。
(5)-print-libgcc-file-name:显示libgcc文件路径。
如何在vc中使⽤mingw编译出来的动态库和静态库
mingw编译出来的静态库后缀名为.a,编译出来的动态库的导⼊库后缀名为.dll.a,⽽在windows下后缀名为.lib的库可能是静态库也可能是动态库的导⼊库。
mingw编译出来的动态库的导⼊库可以直接在vc中直接使⽤,例如
#pragma comment(lib, "libx264.dll.a")
这样你就不需要⽣成⼀个.lib后缀的动态库的导⼊库了,⽹上也有如何从.dll⽣成.lib的⽅法。
如果链接了动态库的导⼊库libpthread.dll.a,你发布的应⽤程序就要带上pthread的dll。
使⽤静态库的好处是发布的应⽤程序组件模块⾥不需要带上相关的dll,如果要使⽤mingw编译出来的静态库,可以如下:
#pragma comment(lib, "libx264.a")
但是仅仅链接这么⼀个静态库是不够的,你还需要链接
libgcc.a
libmingwex.a
你可能还需要链接libmsvcrt.a
否则会报⼀堆错误:error LNK2001: ⽆法解析的外部符号
上⾯的这些库在C:\MinGW\lib⽬录或⼦⽬录下⾯可以找到。
链接这些库的原因是mingw使⽤的gcc编译器和vc编译器之间存在差异。
C语言编译过程详解C语言的编译链接过程是要把我们编写的一个C程序(源代码)转换成可以在硬件上运行的程序(可执行代码),需要进行编译和链接。
编译就是把文本形式源代码翻译为机器语言形式的目标文件的过程。
链接是把目标文件、操作系统的启动代码和用到的库文件进行组织形成最终生成可执行代码的过程。
过程图解如下:从图上可以看到,整个代码的编译过程分为编译和链接两个过程,编译对应图中的大括号括起的部分,其余则为链接过程。
一、编译过程编译过程又可以分成两个阶段:编译和汇编。
1、编译编译是读取源程序(字符流),对之进行词法和语法的分析,将高级语言指令转换为功能等效的汇编代码,源文件的编译过程包含两个主要阶段:第一个阶段是预处理阶段,在正式的编译阶段之前进行。
预处理阶段将根据已放置在文件中的预处理指令来修改源文件的内容。
如#include指令就是一个预处理指令,它把头文件的内容添加到.cpp文件中。
这个在编译之前修改源文件的方式提供了很大的灵活性,以适应不同的计算机和操作系统环境的限制。
一个环境需要的代码跟另一个环境所需的代码可能有所不同,因为可用的硬件或操作系统是不同的。
在许多情况下,可以把用于不同环境的代码放在同一个文件中,再在预处理阶段修改代码,使之适应当前的环境。
主要是以下几方面的处理:(1)宏定义指令,如#define a b。
对于这种伪指令,预编译所要做的是将程序中的所有a用b替换,但作为字符串常量的a则不被替换。
还有#undef,则将取消对某个宏的定义,使以后该串的出现不再被替换。
(2)条件编译指令,如#ifdef,#ifndef,#else,#elif,#endif等。
这些伪指令的引入使得程序员可以通过定义不同的宏来决定编译程序对哪些代码进行处理。
预编译程序将根据有关的文件,将那些不必要的代码过滤掉(3) 头文件包含指令,如#include "FileName"或者#include <FileName>等。
gcc编译命令GCC(GNUCompilerCollection)是一种功能强大的编译器,它可以把源代码编译成可执行代码。
它是GNU具链的一部分,可以编译多种编程语言,包括C、C++、Java、Fortran、Ada等。
GCC提供了一系列的编译命令用于编译源代码并生成可执行的文件。
GCC编译命令的基本格式是:gcc [options] filename其中filename为源代码文件的名称,options是可选的参数,用以指定编译过程中的不同选项。
例如:gcc -c hello.c在上面的命令中,“-c”选项用于指定只预处理,编译和汇编源文件,而不进行链接。
GCC提供了很多有用的参数供我们选择,可以根据不同的需求执行不同的操作。
下面我们将介绍一些常用的编译命令及其参数:1、-c选项:编译预处理和汇编源文件,但不进行链接;2、-o选项:指定编译后的可执行文件的名称,如果不指定则使用默认的名称;3、-g选项:编译的时候包含调试信息;4、-Wall选项:编译的时候显示所有可能的警告信息;5、-lm选项:链接数学库;6、-O选项:指定优化的程度,从0到3,数字越大优化的越多;7、-static选项:编译成静态库;8、-D选项:定义宏;9、-pedantic选项:启用严格模式,禁止异常语法。
另外,GCC也支持一些高级特性,比如OpenMP、Pthreads等,使用这些特性可以极大的提高源代码的执行效率。
关于GCC的编译命令还有很多其他参数和特性,这里只列举了一些常用的参数,使用者可以根据自己的需要设置不同参数,以获得更好的编译效果。
GCC是一款功能强大的编译器,它提供了一系列编译命令,可以编译各种编程语言,并支持多种高级特性。
使用者可以根据自己的需要设置不同参数,以获得更好的编译效果。
GCC使用手册作者:Clock1.前言GCC编译器的手册(GCC MANUAL)的英文版已经非常全面,并且结构也非常完善了,只是一直都没有中文的版本,我这次阅读了GCC编译器的主要内容,对手册的内容进行了结构性的了解,认为有必要对这次阅读的内容进行整理,为以后的工作做准备。
由于我对这个英文手册的阅读也仅仅是结构性的。
因此有很多地方并没有看,所以这篇文档的内容我也只能写出部分,对于以后需要详细了解的地方,会再往这篇文档中增添内容,需要增添的内容主要是编译器的各种开关。
2. GCC功能介绍GCC编译器完成从C、C++、objective-C等源文件向运行在特定CPU硬件上的目标代码的转换(这是任何一个编译器需要完成的任务)。
GCC能够处理的源文件分为C、C++、Objective-C、汇编语言等。
对于这些源文件,用他们的后缀名进行标示。
GCC能够处理的后缀有:a. *.c *.C (C语言)b. *.cxx *.cc (C++语言)c. *.m (面向对象的C)d. *.i (预处理后的C语言源文件)e. *.ii (预处理后的C++语言源文件)f. *.s *.S (汇编语言)h. *.h (头文件)目标文件可以是:a. *.o 编译连接后的目标文件b. *.a 库文件编译器把编译生成目标代码的任务分为以下4步:a.预处理,把预处理命令扫描处理完毕;b.编译,把预处理后的结果编译成汇编或者目标模块;c.汇编,把编译出来的结果汇编成具体CPU上的目标代码模块;d.连接,把多个目标代码模块连接生成一个大的目标模块;3. GCC开关GCC的运行开关共分为11类,这是类开关从11个方面控制着GCC程序的运行,以达到特定的编译目的。
3.1. 全局开关(OVERALL OPTIONS)全局开关用来控制在“GCC功能介绍”中的GCC的4个步骤的运行,在缺省的情况下,这4个步骤都是要执行的,但是当给定一些全局开关后,这些步骤就会在某一步停止执行,这产生中间结果,例如可能你只是需要中间生成的预处理的结果或者是汇编文件(比如拟的目的是为了看某个CPU上的汇编语言怎么写)。
c语言编译C语言是一种通用的高级编程语言,由美国计算机科学家丹尼斯·里奇于1972年在贝尔实验室开发。
C语言具有简洁、高效、可移植等特点,被广泛应用于系统软件、嵌入式软件、游戏开发、科学计算等领域。
C语言的编译过程是将源代码转换为可执行文件的过程,下文将详细介绍C语言的编译过程。
一、C语言的编译过程C语言的编译过程包括预处理、编译、汇编和链接四个阶段。
下面分别介绍这四个阶段的作用和实现方式。
1. 预处理预处理阶段是在编译之前进行的,其作用是将源代码中的预处理指令替换为实际的代码。
预处理指令以#号开头,包括#include、#define、#ifdef、#ifndef等指令。
预处理器将这些指令替换为实际的代码,生成一个新的源文件。
预处理后的源文件通常以.i作为扩展名。
2. 编译编译阶段是将预处理后的源代码转换为汇编代码的过程。
编译器将C语言源代码转换为一种称为中间代码的形式,中间代码是一种类似汇编语言的低级语言。
中间代码具有平台无关性,可以在不同的平台上进行优化和执行。
编译后的结果通常以.s作为扩展名。
3. 汇编汇编阶段是将编译生成的汇编代码转换为机器代码的过程。
汇编器将汇编代码转换为可执行的机器代码,并生成一个目标文件。
目标文件包括可执行代码、数据段、符号表等信息。
目标文件通常以.o 或.obj作为扩展名。
4. 链接链接阶段是将多个目标文件合并为一个可执行文件的过程。
链接器将目标文件中的符号和地址进行解析,生成一个可执行文件。
可执行文件包括操作系统可以直接执行的代码和数据,通常以.exe、.dll 或.so作为扩展名。
二、C语言编译器C语言编译器是将C语言源代码转换为可执行文件的工具,包括预处理器、编译器、汇编器和链接器四个部分。
C语言编译器可以在不同的平台上运行,生成可在目标平台上运行的可执行文件。
下面分别介绍常用的C语言编译器。
1. GCCGCC(GNU Compiler Collection)是一款开源的C语言编译器,由GNU组织开发。
动态链接库及静态链接库(window s下的.dll .lib和li nux下的.so .a)库有动态与静态两种,动态通常用.so为后缀,静态用.a为后缀。
例如:libhel lo.so libhel lo.a 为了在同一系统中使用不同版本的库,可以在库文件名后加上版本号为后缀,例如:libhel lo.so.1.0,由于程序连接默认以.so为文件后缀名。
所以为了使用这些库,通常使用建立符号连接的方式。
ln -s libhel lo.so.1.0 libhel lo.so.1ln -s libhel lo.so.1 libhel lo.so使用库当要使用静态的程序库时,连接器会找出程序所需的函数,然后将它们拷贝到执行文件,由于这种拷贝是完整的,所以一旦连接成功,静态程序库也就不再需要了。
然而,对动态库而言,就不是这样。
动态库会在执行程序内留下一个标记…指明当程序执行时,首先必须载入这个库。
由于动态库节省空间,linux下进行连接的缺省操作是首先连接动态库,也就是说,如果同时存在静态和动态库,不特别指定的话,将与动态库相连接。
现在假设有一个叫hel lo的程序开发包,它提供一个静态库lib hello.a 一个动态库l ibhel lo.so,一个头文件h ello.h,头文件中提供sayhe llo()这个函数/* hello.h */void sayhel lo();另外还有一些说明文档。
这一个典型的程序开发包结构1.与动态库连接linux默认的就是与动态库连接,下面这段程序testl ib.c使用hel lo库中的sayhe llo()函数/*testli b.c*/#includ e#includ eint main(){sayhel lo();return 0;}使用如下命令进行编译$gcc -c testli b.c -o testli b.o用如下命令连接:$gcc testli b.o -lhello -o testli b在连接时要注意,假设libh ello.o 和libhe llo.a都在缺省的库搜索路径下/usr/lib下,如果在其它位置要加上-L参数与与静态库连接麻烦一些,主要是参数问题。
linux gcc编译命令
GCC是 Linux系统下的一个很常用的开源编译器。
使用GCC编译
C/C++程序,大致需要按以下步骤进行:
1、准备工作:确定要编译的程序源码文件,源码文件通常以 .c
或 .cpp结尾。
2、编译阶段:使用GCC命令进行编译,编译完成后生成目标文件,
比如 a.out 或者带有其它后缀的文件名。
3、链接阶段:使用GCC将目标文件与静态库链接在一起,最终生成
可执行文件。
4、执行文件:使用./<文件名>命令运行可执行文件,查看其执行结果。
常用的GCC编译命令为:
1、gcc [选项参数] 源文件名 -o<输出文件名>,该命令可以进行编译,默认输出文件名为 a.out 。
2、gcc [选项参数] 源文件名 -c,该命令仅进行编译,不进行链接,源文件编译生成 .o 格式的文件。
3、gcc [选项参数] 源文件名 -S,该命令仅进行编译,不进行汇编,源文件编译生成 .s 格式的文件。
4、gcc [选项参数] 汇编文件名 -c,该命令进行汇编并编译,汇编
文件编译生成 .o 格式的文件。
5、gcc [选项参数] 目标文件名 -o<输出文件名>,该命令可以链接多个 .o 格式的文件,最终生成可执行文件。
6、gcc [选项参数] 动态库文件名 -shared -o<输出文件名>,该命令将多个 .o 格式的文件链接成动态库,最终生成动态库文件。
7、g++[选项参数]源文件名-o<。
我们通常把一些公用函数制作成函数库,供其它程序使用。函数库分为静态库和动态库两种。
静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。动态库在程
序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需
要动态库存在。本文主要通过举例来说明在Linux中如何创建静态库和动态库,以及使用它
们。
在创建函数库前,我们先来准备举例用的源程序,并将函数库的源程序编译成.o文件。
第1步:编辑得到举例的程序--hello.h、hello.c和main.c;
hello.c(见程序2)是函数库的源程序,其中包含公用函数hello,该函数将在屏幕上输出
"Hello XXX!"。hello.h(见程序1)为该函数库的头文件。main.c(见程序3)为测试库文件的
主程序,在主程序中调用了公用函数hello。
1. #ifndef HELLO_H
2. #define HELLO_H
3.
4. void hello(const char *name);
5.
6. #endif //HELLO_H
复制代码
程序1: hello.h
1. #include
2.
3. void hello(const char *name)
4. {
5. printf("Hello %s!\n", name);
6. }
复制代码
程序2: hello.c
1. #include "hello.h"
2.
3. int main()
4. {
5. hello("everyone");
6. return 0;
7. }
复制代码
程序3: main.c
第2步:将hello.c编译成.o文件;
无论静态库,还是动态库,都是由.o文件创建的。因此,我们必须将源程序hello.c通过g
cc先编译成.o文件。
在系统提示符下键入以下命令得到hello.o文件。
# gcc -c hello.c
#
我们运行ls命令看看是否生存了hello.o文件。
# ls
hello.c hello.h hello.o main.c
#
在ls命令结果中,我们看到了hello.o文件,本步操作完成。
下面我们先来看看如何创建静态库,以及使用它。
第3步:由.o文件创建静态库;
静态库文件名的命名规范是以lib为前缀,紧接着跟静态库名,扩展名为.a。例如:我们将
创建的静态库名为myhello,则静态库文件名就是libmyhello.a。在创建和使用静态库时,
需要注意这点。创建静态库用ar命令。
在系统提示符下键入以下命令将创建静态库文件libmyhello.a。
# ar crv libmyhello.a hello.o
#
我们同样运行ls命令查看结果:
# ls
hello.c hello.h hello.o libmyhello.a main.c
#
ls命令结果中有libmyhello.a。
第4步:在程序中使用静态库;
静态库制作完了,如何使用它内部的函数呢?只需要在使用到这些公用函数的源程序中包含
这些公用函数的原型声明,然后在用gcc命令生成目标文件时指明静态库名,gcc将会从静
态库中将公用函数连接到目标文件中。注意,gcc会在静态库名前加上前缀lib,然后追加
扩展名.a得到的静态库文件名来查找静态库文件。
在程序3:main.c中,我们包含了静态库的头文件hello.h,然后在主程序main中直接调用
公用函数hello。下面先生成目标程序hello,然后运行hello程序看看结果如何。
(# gcc -o hello main.c -L. -lmyhello??)
#gcc main.c libmyhello.a -o main
# ./hello
Hello everyone!
#
我们删除静态库文件试试公用函数hello是否真的连接到目标文件 hello中了。
# rm libmyhello.a
rm: remove regular file `libmyhello.a'? y
# ./hello
Hello everyone!
#
程序照常运行,静态库中的公用函数已经连接到目标文件中了。
我们继续看看如何在Linux中创建动态库。我们还是从.o文件开始。
第5步:由.o文件创建动态库文件;
动态库文件名命名规范和静态库文件名命名规范类似,也是在动态库名增加前缀lib,但其
文件扩展名为.so。例如:我们将创建的动态库名为myhello,则动态库文件名就是
libmyhello.so。用gcc来创建动态库。
在系统提示符下键入以下命令得到动态库文件libmyhello.so。
# gcc -shared -fPCI -o libmyhello.so hello.o
#
我们照样使用ls命令看看动态库文件是否生成。
# ls
hello.c hello.h hello.o libmyhello.so main.c
#
第6步:在程序中使用动态库;
在程序中使用动态库和使用静态库完全一样,也是在使用到这些公用函数的源程序中包含这
些公用函数的原型声明,然后在用gcc命令生成目标文件时指明动态库名进行编译。我们先
运行gcc命令生成目标文件,再运行它看看结果。
# gcc -o hello main.c -L. -lmyhello
# ./hello
./hello: error while loading shared libraries: libmyhello.so: cannot open shared
object file: No such file or directory
#
哦!出错了。快看看错误提示,原来是找不到动态库文件libmyhello.so。程序在运行时,
会在/usr/lib和/lib等目录中查找需要的动态库文件。若找到,则载入动态库,否则将提
示类似上述错误而终止程序运行。我们将文件libmyhello.so复制到目录/usr/lib中,再
试试。
# mv libmyhello.so /usr/lib
# ./hello
Hello everyone!
#
成功了。这也进一步说明了动态库在程序运行时是需要的。
我们回过头看看,发现使用静态库和使用动态库编译成目标程序使用的gcc命令完全一样,
那当静态库和动态库同名时,gcc命令会使用哪个库文件呢?抱着对问题必究到底的心情,
来试试看。
先删除除.c和.h外的所有文件,恢复成我们刚刚编辑完举例程序状态。
# rm -f hello hello.o /usr/lib/libmyhello.so
# ls
hello.c hello.h main.c
#
在来创建静态库文件libmyhello.a和动态库文件libmyhello.so。
# gcc -c hello.c
# ar cr libmyhello.a hello.o
# gcc -shared -fPCI -o libmyhello.so hello.o
# ls
hello.c hello.h hello.o libmyhello.a libmyhello.so main.c
#
通过上述最后一条ls命令,可以发现静态库文件libmyhello.a和动态库文件
libmyhello.so都已经生成,并都在当前目录中。然后,我们运行gcc命令来使用函数库
myhello生成目标文件hello,并运行程序 hello。
# gcc -o hello main.c -L. -lmyhello
# ./hello
./hello: error while loading shared libraries: libmyhello.so: cannot open shared
object file: No such file or directory
#