嵌入式Linux+GCC培训_第1页
嵌入式Linux+GCC培训_第2页
嵌入式Linux+GCC培训_第3页
嵌入式Linux+GCC培训_第4页
嵌入式Linux+GCC培训_第5页
已阅读5页,还剩83页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、嵌入式Linux GCC培训主讲老师: 欧阳坚GCC是什么? GCC: GNU Compiler Collection; GCC支持多种硬件平台和操作系统,能编译多种语言(C, C+, Java, Ada95, Objective C, .etc); GCC与G+的关系: GCC用于编译多种语言编写的程序,主要是C; G+用于编译C+程序,以GCC为基础,编译过程中加入了C+的支持库,参数与GCC基本一致; 可以利用GCC编译C+程序,但是需要在参数中加入引用的C+库,比如libstdc+ (如gcc -o out lstdc+ main.cc)。可执行程序的生成过程 预处理(Preproce

2、ssing):分析各种预处理命令,如#define, #include, #if等; 编译(Compilation): 根据输入文件产生汇编语言的程序; 汇编(Assembly): 将汇编语言输入,产生扩展名为.o的目标文件; 链接(Linking):以.o目标文件,库文件作为输入,生成可执行文件;源程序文件(.h, .c, .cc, .etc)经预处理的文件(.i, .ii)汇编语言文件(.s)目标文件(.o)可执行程序(.out)GCC支持的文件类型 C文件. cC源代码 .hC头文件 C+文件 file.hh, file.hC+头文件 file.C, file.cc, file.cxx等

3、C+源文件 预处理后的文件 file.i预处理后的C源文件 file.ii预处理后的C+源文件 编译后的文件 .o目标代码 (obj) .s汇编代码文件 file.a目标文件库GCC编译选项命令行:gcc options infile -E不生成文件,只输出预处理结果(输出终端) -S只预处理和编译,把文件编译成为汇编代码greet.s -c预处理,编译和汇编,生成.o的obj文件 ( greet.o ) -o file输出名为file的可执行文件名 (缺省为a.out) -O -O2优化编译 -g: 产生可用于调试的输出 -Wall提示更多警告信息 -Wstrict-prototypes如果

4、函数的声明或定义没有指出参 数类型,编译器就发出警告. -Wl,option 将option作为选项传递给linker, option 逗号分割, 如:-Wl,-soname,libmymath.so.1与库和路径相关选项 -I dir 在dir这个目录寻找被include的文件 -L dir 在dir这个目录寻找被-l的库 -l name 链接库文件名为libname.a 或libname.so的库 -fpic或或-fPIC 产生位置无关的目标代码,以构造共 享库(shared library) -static 禁止与共享库链接,若没有,则优先 选择共享库链接 -shared 产生共享库,在

5、创建共享函数库时使用示例与宏相关的选项 -Dmacro: 相当于在源程序中使用 #define macro 1 -Dmacro=value -Umacro: 取消宏的定义3. GCC编译过程3.1 GCC编译过程 典型的编译过程 test.c 预处理 test.i 编译 test.s 汇编test.o 连接 test$ cat test.c (查看程序源代码) #include int main(int argc, char *argv) printf(hello worldn); return 0; $ gcc o test test.c (编译连接程序)$ ./test (执行test程序

6、)3.2 预处理预编译命令: $ gcc -o test.i -E test.c或者 $ cpp -o test.i test.c 这里cpp不是值c plus plus,而是the C Preprocessor)执行结果: 生成预处理后的文件test.i, 该文件包含了test.c需要的所有的类型和函数申明。原理:读取c源程序,对伪指令和特殊符号进行处理。包括宏,条件编译,包含的头文件,以及一些特殊符号。基本上是一个替换的过程。Hello.c#include int main(void) printf(“hellon”);预处理命令gcc E hello.c gcc E hello.c o

7、hello.i注释这一行看看预处理的结果注意#include的作用和用途-E表示做预处理-o 表示预处理的输出存于hello.i文件中,而不是屏幕上#define用法#include #define AA 100int main(void) AA BB printf(“hellon”);预处理命令gcc E hello.c DBB=hellogcc E hello.c DBB=“printf(”hello”);”gcc E hello.c DBB (等效于-DBB=1)注释这一行看看预处理的结果-D表示在命令行中传入宏定义-DBB=后面是一个宏的定义,可以加双引号。#define带参数#inc

8、lude #define AA(a,b) a = bint main(void) AA(int a, 1); BB; printf(“hellon”);预处理命令gcc E hello.c DBB=hellogcc E hello.c DBB=“printf(”hello”);”注释这一行看看预处理的结果-D表示在命令行中传入宏定义-DBB=后面是一个宏的定义,可以加双引号。展开就成了: int a = 1; AA宏带两个参数 #ifdef #if defined #if !defined #ifndef #elif defined #elif !defined #else #if #elif

9、 #endif -E D”AA=100”#define带参数#include #ifdef AAaa#elif defined BBbb#elif defined CCcc#elseother#endifint main(void) printf(“hellon”);#ifdef AA 等效于#if defined AA表示当定义了宏AA表示除此之外的情况表示否则定义了宏CC的情况gcc E hello.c DAA=1aaint main(void) printf(“hellon”);gcc E hello.c DBB=1bbint main(void) printf(“hellon”);gc

10、c E hello.c DCC=1ccint main(void) printf(“hellon”);gcc E hello.cotherint main(void) printf(“hellon”);#if使用#define带参数#include #if AAaa#elif BBbb#elif CCcc#elseother#endifint main(void) printf(“hellon”);#if AA 表示AA非零的情况也就是AA除了0其它数字都为真表示除此之外的情况#elif BB 表示BB非零的情况#elif表示否则如果gcc E hello.c DAA=1aaint main(

11、void) printf(“hellon”);gcc E hello.c DAA=0otherint main(void) printf(“hellon”);gcc E hello.c DBB=1bbint main(void) printf(“hellon”);gcc E hello.c DBB=0otherint main(void) printf(“hellon”);gcc E hello.c DCC=1ccint main(void) printf(“hellon”);gcc E hello.c DCC=0otherint main(void) printf(“hellon”);gcc

12、 E hello.cotherint main(void) printf(“hellon”);#的用法 在函数式宏定义中, #运算符用于创建字符串,#运算符后面应该跟一个形参(中间可以有空格或Tab),例如: #define STR(s) # s char *p = STR(helloworld) 结果变成: char *p = “helloworld”#的用法 在宏定义中可以用#运算符把前后两个预处理Token连接成一个预处理Token,和#运算符不同,#运算符不仅限于函数式宏定义,变量式宏定义也可以用。例如: #define FOO(a) foo#a int a = FOO(bar); i

13、nt b = FOO(); 预处理之后变成: int a = foobar; int b = foo;预处理头文件xxx.h #ifndef HEADER_FILENAME #define HEADER_FILENAME /* body of header */ #endif 当xxx.h被多次包含的时候。有三个头文件和一个C文件 common.h file2.h file3.h main.ccommon.h#ifndef _COMMON_H_#define _COMMON_H_static int test(void) printf(“hellon”);#endif 如果没有写上红色部分的,

14、是什么情况。file1.h file1.h文件内容如下 #include “common.h” file2.h文件内容如下 #include “common.h”main.c main.c内容如下 #include #include “file1.h” #include “file2.h” int main(void) test(); gcc o main main.c#include 和” ”区别 #include #include “common.h”常用的#debug宏定义 int main() printf(“here 1n”); printf(“here 2n”); printf(“

15、here 3n”); 开发阶段太多printf如何在开发阶段加入printf,在程序发布的时候去掉printf呢常用的#debug宏定义 int main() debug(“here 1n”); debug(“here 2n”); debug(“here 3n”); #ifdef DEBUG #if 0 #define debug printf #else #define debug(var ) printf( #var ) #endif #else #define debug(var ) #endif常用的#debug宏定义 int main() printf(“here %s %s %dn

16、”, _FILE_, _func_, _LINE_); printf(“here %s %s %dn”, _FILE_, _func_, _LINE_); printf(“here %s %s %dn”, _FILE_, _func_, _LINE_); 太多printf不好区分如何打出printf的时候也打出行号,函数,文件之类的星系3.3 编译及优化编译命令: $ gcc -o test.s -S test.i (-S编译选项) $ gcc -o test.s -S test.i (-S编译选项) $ cc1 -o test.s test.i (cc1为C语言真正编译器)结果: 生成汇编文

17、件test.s, test.s中包含了AT&T的x86汇编代码。作用: 通过词法和语法分析,确认所有指令符合语法规则(否则报编译错),之后翻译成对应的中间码,在linux中被称为RTL(Register Transfer Language),通常是平台无关的,这个过程也被称为编译前端。编译后端对RTL树进行裁减,优化,得到在目标机上可执行的汇编代码。gcc采用as作为其汇编器,所以汇编码是AT&T格式的,而不是Intel格式,所以在用gcc编译嵌入式汇编时,也要采用AT&T格式。3.4 汇编汇编命令: $ gcc -o test.o -c test.s $ as -o

18、test.o test.s执行结果: 生成目标机器指令文件test.o(可以通过objdump查看汇编指令)原理: 把汇编语言代码翻译成目标机器指令, 用file test.o 可以看到test.o是一个relocatable的ELF文件,通常包含.text .rodata代码段和数据段。可用readelf -r test.o查看需要relocation的部分。3.5 链接执行命令: $ gcc -o test test.o执行结果: 生成可执行文件test (可用objdump查看) 原理: 将在一个文件中引用的符号同在另外一个文件中该符号的定义链接起来,使得所有的这些目标文件链接成为一个能

19、被操作系统加载到内存的执行体。(如果有不到的符号定义,或者重复定义等,会报链接错)。用file test 可以看到test是一个executable的ELF文件。 3.6 执行执行过程 $ ./test课堂项目(建立一个目录) 在src目录中 test1.c test2.c test5.c 在include目录中创建test1.h test2.h test5.h文件。 在src目录中创建main.c文件 然后main.c调用test1.c到test5.c里面的函数。 建立obj目录存放目标文件 任务1:编译test1.c test2.c test5.c,编译的test1.o test2.o t

20、est5.o放于obj目录中 任务2:编译main.c放于obj目录中 任务3:编译所有的目标文件形成main文件。 任务4:写出build.sh脚本,自动编译和执行main程序 任务5:打包整个程序文件夹 任务4:学员之间通过网络相互使用build.sh编译对方的程序。GCC常用编译选项预编译选项 -DMACRO定义“MACRO” 宏为字符串“1” -DMACRO=DEF 定义“MACRO” 宏为字符串“DEF” -UMACRO取消对“MACRO” 宏的定义 -E 只运行C 预编译器cpp编译选项-c只编译并生成object文件-S只预处理和编译,把文件编译成为汇编代码greet.s-g生成

21、可被gdb使用的标准调试信息-ggdb生成只被gdb使用的扩展调试信息-mXXX针对“XXX”CPU进行优化,如“XXX”可以是486、586等-o FILE生成指定的输出文件名“FILE”-O0 不进行代码优化-O 或 -O1进行一般的代码优化,减少执行代码大小和执行的时间-O2 比 -O1进行更多的代码优化,一般在内核编译中会使用-O3 比 -O2 更进一步优化-w不生成任何警告信息-Wall生成所有级别的警告信息-Werror把所有的警告当成错误,并中止编译过程搜索目录(头文件和库文件) -IDIRECTORY除缺省情况外,指定其它头文件搜索路径“DIRECTORY” -LDIRECTO

22、RY除缺省情况外,指定其它函数库搜索路径“DIRECTORY” -lLIBRARY确定链接时需要的其它函数库“LIBRARY” -shared 生成支持动态共享库的执行文件 -static不支持动态共享库,把函数库中内容静态链接到执行文件中 -MM输出源文件的依赖关系 -fPIC产生位置无关代码(英文缩写为PIC),一般创建共享库时需要静态库与动态库 创建函数库 分类: 静态库: 在编译过程中将库函数代码直接加入到生成的可执行程序中,程序运行过程中不需要利用库函数。 共享库: 编译时,只是在生成的可执行程序中简单指定需要使用的库函数信息,程序运行过程中需要利用库函数。 动态库: 共享库的一种变

23、化形式,目前大都采用共享库的方式。 命名: 静态库: 前缀lib+库名+.a (libm.a, libstdc+.a等) 共享库: 前缀lib+库名+.so+版本号 (libm.so.6, libc.so.6)创建静态库 静态函数库是一组目标文件(*.o)的集合 创建步骤:gcc -c test1.c test2.c (生成test1.o, test2.o)ar -cr libtest.a test1.o test2.o (生成函数库libtest.a) ar函数说明:用途:创建和修改库函数,或从库函数提取目标文件举例:ar -rs lib-name list-of-files (将列表中的目

24、标文件加入到库中,并产生索引文件)ar -ds lib-name list-of-files (将列表中列出的目标文件从库中删除,并产生索引文件)ar -x lib-name list-of-files (不修改库文件,从库中提取列表中列出的目标文件)创建静态库示例源码创建静态库的方法:arcaculation.c#include int main(void) int x = 5 ; int y = 3 ; printf (x + y = %3dn, add(x, y) ); printf (x - y = %3dn, minus(x, y) ); printf (x * y = %3dn,

25、multiply(x, y) ); printf (x % y = %3dn, mod(x, y) ); return 1;add_minus.cint add(int x, int y) int result; result = x + y; return result;int minus(int x, int y) int result; result = x - y; return result;multiply_mod.cint multiply(int x, int y) int result; result = x * y; return result;int mod(int x,

26、 int y) int result; result = x % y; return result;创建静态库示例操作命令一个容易忽略的顺序问题 静态库不能先于原程序链接,这是因为开始时还没有任何 未定义的符号,库中的内容不会被链入,所以应该注意将静 态库的使用(-l选项)都写在最后静态库练习 任务1: 讲上述的练习的test1.c, test2.c test5.c打包成libtest.a放于lib目录中。 任务2: 然后使用libtest.a来编译main程序 任务3: 写编译脚本文件。做包含include lib demos的SDK 任务4: 打包整个SDK 任务5: 把SDK通过网络发布

27、给对方。 任务5: 对方使用SDK和自带的例子测试和使用SDK和自己的例子测试。创建、使用共享库示例 vicknec$ gcc -fPIC -c add_minus.c vicknec$ gcc -fpic -c multiply_mod.c vicknec$ gcc -shared -fpic -o libalg.so add_minus.o multiply_mod.o vicknec$ gcc -o cacul -lalg caculation.c /usr/bin/ld: cannot find -lalg collect2: ld returned 1 exit status vic

28、knec$ gcc -o cacul -L. -lalg caculation.c vicknec$ ./cacul ./cacul: error while loading shared libraries: libalg.so: cannot open shared object file: No such file or directory创建共享库步骤 创建共享库 gcc -c -fPIC test1.cgcc -c -fPIC test2.cgcc -shared -fPIC -o libtest.so test1.o test2.o 编译使用了共享库的程序gcc -o main L

29、dir -ltest main.c共享库系统自动动态加载问题 1.拷贝动态库文件到/lib或/usr/lib去 $ cp libalg.so /usr/lib or $cp libalg.so /lib 2.改变环境变量LD_LIBRARY_PATH$ LD_LIBRARY_PATH=$PWD $ export LD_LIBRARY_PATH应用程序自身完成动态加载 可以在自己的程序中使用 dlopen()。该函数将打 开一个新库,并把它装入内存。 dlopen() 在 dlfcn.h 中定义,并在 dl 库中实现。检查库依赖关系 函数库之间的相互引用 ldd的使用:用于查看库函数之间的依赖性

30、vicknec gcc-lab$ cd /usr/libvicknec lib$ ldd libtiff.so libjpeg.so.62 = /usr/lib/libjpeg.so.62 (0 x4004c000) libz.so.1 = /usr/lib/libz.so.1 (0 x4006b000) libc.so.6 = /lib/i686/libc.so.6 (0 x40079000) /lib/ld-linux.so.2 = /lib/ld-linux.so.2 (0 x80000000)应用程序自身完成动态加载示例#include #include int main(void)

31、int x = 5 ; int y = 3 ; void * handle; int ( *dl_add )( int, int ); int ( *dl_mod )( int, int ); handle = dlopen( /usr/lib/libalg.so, RTLD_LAZY ); dl_add = dlsym( handle, add ); dl_mod = dlsym( handle, mod ); printf (x + y = %3dn, dl_add( x, y ) ); printf (x % y = %3dn, dl_mod( x, y ) ); dlclose( ha

32、ndle ); return 1;总结:动态共享库的好处 1.动态共享库是共享的,节省了物理开销。 2.库版本更新容易,运行时调用,库更新后不用重新链接。 3.允许用户在运行时再确定调用哪个库。使得在程序中添加或者删除一个模块时,都不需要在编译时指定库。 注意,如果动态共享库无法加载,可能是路径的问题,或是依赖的问题。ar option option c Create a file option d Delete a file from the archive option p Print a list of files in the archive option q Append files

33、 to the archive option r Insert new files in the archive by replacing if a file already exists in the archive option t Displaying contents of an archive option x Extracting files from an archiveranlib Utility The “ranlib” command is used to create indexentries inside an archive file. 示例: $ranlib sta

34、tic-lib-name等价于 $ar s static-lib-namenm Utility used to list symbols used in an object file. 示例: $ nm -s libcommon.a $ nm -s a.out 另外: a option with the nm command also shows the debug symbols. objdump Utility -f Displaying Header Information -h Displaying Section Headers -d Disassembling a File -a

35、Displaying Information about Library Files size Utility The size utility displays sizes of each section in an object file. 示例:rootboota# size a.out text data bss dec hex filename 1015 232 24 1271 4f7 a.out strings Utility The strings utility displays printable strings in an object file. By default i

36、t displays strings only in initialized and loaded sections of the object file. ldd Utility The ldd utility is very useful in finding out the dependencies of an executable on shared libraries. 示例:rootboota# ldd a.out libc.so.6 = /lib/i686/libc.so.6 (0 x4002c000) /lib/ld-linux.so.2 =/lib/ld-linux.so.2

37、 (0 x40000000) rootboota# make和Makefile的关系 make和Makefile的关系就像演员和剧本的关系 make是系统的一个程序(/usr/bin/make) Makefile是规则的文件 make就是去解析Makefile的文件来执行相关的命令 Makefile有三种命名形式: Makefile, makefile, GNUMakefile3.7 一个简单的Makefile格式all: hello echo “Begin to build hello“hello: echo “Display hello”clean: xxxxrm -rf *.o hell

38、o注意符号的用途, 表示后面的命令不要显示出来第一个target第二个target第三个target红色的xxxx表示键盘上的Tab键,而不是空白,任何命令必须以Tab键开始。 make (在上述Makefile中,make和make all 操作一样,因为all是第一个target) make all make hello make clean3.7 一个简单的Makefile格式myname = Saifall: hello echo “myname is: $(myname)” echo “Begin to build hello“hello: echo “Display hello”clean: rm -rf *.o hello变量myname使用$( )表示一个简单的C程序(hello.c和foo1.c)#include /* hello.c */extern int foo1(void);int main(void) foo1();#include /* foo1.c */int foo1(void) printf(“print foo1n”);3.7 通常的Makefile格式all: hello echo Finish to buil

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论