嵌入式Linux学习笔记 1-9 gcc

1. 一个C文件需要通过步骤变成一个可执行文件的?

        要通过预处理、编译、汇编、连接这四步。

        预处理: 处理包含“#”的那些命令。如“#include”、“define”宏定义展开、“ifdef”条件编译 等。最后输出到一个“.i”文件中等待进一步处理。file.c==>file.i

        编译:把C代码翻译成汇编代码。file.i==>file.s

        汇编:把汇编代码翻译成符合一定格式(ELF)的机器码。file.s==>file.o (即OBJ文件,目标文件)

        链接:链接就是将上步生成的OBJ文件和系统库中的OBJ文件、库文件链接起来。file.o ==> 应用程序

        (1)动态链接使用动态链接库进行链接,生成的程序在执行的时候需要加载所需的动态库才能运行。动态链接生成的程序体积较小,但是必须依赖所需的动态库,否则无法执行。ggc -o  默认为动态链接。

        (2)静态链接使用静态库进行链接,生成的程序包含程序运行所需要的全部库,可以直接运行,不过静态链接生成的程序体积较大。gcc -static -o 则为静态链接,产生的应用程序文件因包含静态库,所以占的存储空间会比较多。

2. gcc的使用方法:
gcc  [选项]   文件名

gcc常用选项:
  -v:查看gcc编译器的版本,显示gcc执行时的详细过程
  -o <file>                Place the output into <file>
                           指定输出文件名为file,这个名称不能跟源文件名同名
  -E                       Preprocess only; do not compile, assemble or link
                           只预处理,不会编译、汇编、链接
  -S                       Compile only; do not assemble or link
                           只编译,不会汇编、链接
  -c                       Compile and assemble, but do not link
                           编译和汇编,不会链接    
//==================================================

 当需要通过gcc得到一个应用程序时,可以用以下指令: 

gcc -c -o hello.o hello.c
gcc -o hello hello.o

gcc会对.c文件默认进行预处理操作,-c再来指明了编译、汇编,从而得到.o文件
再通过gcc -o hello hello.o将.o文件进行链接,得到可执行应用程序。

3. gcc编译的规范

        应该分别编译,最后链接,如果把所有的文件都用一条指令编译链接。若之后对其中某个文件进行了修改,若还是只用一条指令编译链接,再编译的话,就又会把编译过的文件再编译一遍,会很耗时。eg. gcc -o program a.c b.c 

        正确的做法是把分别编译最后链接。 这样就只需要重新编译修改过的文件,再将.o文件重新链接即可。

        eg. gcc -c -o a.o a.c       

              gcc -c -o b.o b.c

              gcc -o test  a.o b.o

4. Makefile的语法

(1) 作用     

  作用是组织和管理程序。

        规则:

                目标文件 依赖文件

                【TAB键】 + 命令

        注:当目标文件不存在,或某个依赖文件比目标文件“”,则执行“命令”。

//======================================================================== 

(2) 通配符

        当目标文件过多时,为了不一一罗列,我们需要使用通配符: %.o

        eg. %.o : %.c

                      gcc -c -o $@ $<

           $@ 表示目标文件
           $< 表示第1个依赖文件
           $^ 表示所有依赖文件

//=======================================================================

(3)假想目标:. PHONY  (格式  .PHONY: xxx)

PHONY 目标并非实际的文件名:只是在显式请求时执行命令的名字。有两种理由需要使用PHONY 目标:避免和同名文件冲突,改善性能。

如果编写一个规则,并不产生目标文件,则其命令在每次make 该目标时都执行。例如:
  clean:
  rm *.o temp
因为"rm"命令并不产生"clean"文件,则每次执行"make clean"的时候,该命令都会执行。如果目录中出现了"clean"文件,则规则失效了:没有依赖文件,文件"clean"始终是最新的,命令永远不会 执行;为避免这个问题,可使用".PHONY"指明该目标。如:
  .PHONY : clean
  这样执行"make clean"会无视"clean"文件存在与否。

已知phony 目标并非是由其它文件生成的实际文件,make 会跳过隐含规则搜索。这就是声明phony 目标会改善性能的原因,即使你并不担心实际文件存在与否。
  完整的例子如下:
  .PHONY : clean
  clean :
  rm *.o temp

//=======================================================================

(4)  即时变量、延时变量, export
简单变量(即时变量) :
A := xxx   # A的值即刻确定,在定义时即确定。(即前面的变量不能使用后面的变量,只能使用前面已定义好了的变量,定了就不能变了,不能反悔。)
B = xxx    # B的值使用到时才确定

:=   # 即时变量
=    # 延时变量
?=   # 延时变量, 如果是第1次定义才起效, 如果在前面该变量已定义则忽略这句
+=   # 附加, 它是即时变量还是延时变量取决于前面的定义

//=======================================================================

5. Makefile函数

a. $(foreach var,list,text)

        这个函数的意思是,把参数<list>;中的单词逐一取出放到参数<var>;所指定的变量中,然后再执行< text>;所包含的表达式。每一次<text>;会返回一个字符串,循环过程中,<text>;的所返回的每个字符串会以空格分隔,最后当整个循环结束时,<text>;所返回的每个字符串所组成的整个字符串(以空格分隔)将会是foreach函数的返回值。

        所以,<var>;最好是一个变量名,<list>;可以是一个表达式,而<text>;中一般会使用<var>;这个参数来依次枚举<list>;中的单词。举个例子:

        eg.    names := a b c d

                 files := $(foreach n,$(names),$(n).o)

        上面的例子中,$(name)中的单词会被挨个取出,并存到变量“n”中,“$(n).o”每次根据“$(n)”计算出一个值,这些值以空格分隔,最后作为foreach函数的返回,所以,$(files)的值是“a.o b.o c.o d.o”。

b. $(filter pattern...,text)           # 在text中取出符合patten格式的值

   

   $(filter-out pattern...,text)     # 在text中取出不符合patten格式的值

c. $(wildcard pattern)              # pattern定义了文件名的格式,
                                                  # wildcard取出其中存在的文件

d. $(patsubst pattern,replacement,$(var))  # 从列表中取出每一个变量 var
                                                                       # 如果符合pattern
                                                                        # 则替换为replacement

6. Makefile生成依赖

         当一个.c文件包含很多的头文件时,很难在依赖关系中将所有的头文件都列出来。如果不列出依赖的头文件来的话,当该头文件被修改了的话,重新编译的时候并不会认为.c文件更新了。因此吧所有的依赖都写入.d文件来代替自己逐个罗列。

gcc -M c.c // 打印出依赖

gcc -M -MF c.d c.c  // 把依赖写入文件c.d

gcc -c -o c.o c.c -MD -MF c.d  // 编译c.o, 把依赖写入文件c.d

gcc -c -o $@ $< -MD -MF .$@.d  //编译成目标文件,并生成目标文件的依赖文件,前面加“.”表示生成隐藏的.d文件。ls -a 表示显示隐藏文件。所以以后编译用这条指令就可以了,具有普遍意义。

7. 一个Makefile实例

objs = a.o b.o c.o 

/*为了不产生迭代的问题,故用了即时变量 :=*/
dep_files := $(patsubst %, .%.d, $(objs))  /*列表objsz中的变量,替换为.%.d字符串,再将其赋值给dep_files*/
dep_files := $(wildcard $(dep_files)) /*判断路径内是否包含有dep_files描述的的文件,如有则取出再赋值给dep_files*/

test: $(objs)
	gcc -o test $^ 

/*ifneq(ARG1,ARG2),ifnotequal判断变量depfiles是否为空,若非空则包含dep_files变量,即依赖文件 */
ifneq ($(dep_files),)
include $(dep_files)
endif

%.o : %.c
	gcc -c -o $@ $< -MD -MF .$@.d //编译且生成依赖文件,依赖文件为隐藏文件

clean:
	rm *.o test

distclean:
	rm $(dep_files) //移除依赖文件.d

.PHONY: clean  //假想目标clean 即使文件中有同名文件clean也不影响编译

8. CFLAGS

        CFLAGS 表示用于 C 编译器的选项。

eg.  CFLAGS = -Werror   //编译的时候都会把warning认为是error。

       CFLAGS = -Iinclude //指定include后面的路径为gcc寻找头文件的默认路径。

        


arm-linux-gcc  编译选项

  • -o  编译及链接,会生成一个exe可执行文件
  • -Wall  指定产生全部的警告信息 
  •  -O/-O2/-O3   数字越高,代表优化的更多,可以使生成的执行文件的提高执行效率
  • -c 编译不链接,会生成一个*.obj文件,若后面加了-o,则表示指定输出文件名称
  • -static   静态链接,生成的文件会非常大, 好处在于不需要动态链接库,也可以运行
  • -S 只激活预处理和编译,就是指把文件编译成为汇编代码

例如:
arm-linux-gcc -c -o  led.o led.c   :编译不链接

arm-linux-gcc   -o  led  led.c       :编译以及链接

arm-linux-ld    连接选项

  • -Ttext 0x00000000              指代码段头地址为0x00000000
  • -T链接脚本                          指使用链接脚本来进行更复杂的地址设置,包括了代码段,数据段,bss段等
  • -o                                        后面指的将多个文件连接在一起,生成一个obj文件,上面的名称是led_elf。
  •  -pie                    生成动态链接地址段,一般在新版uboot里会看到

arm-linux-objcopy   复制选项,支持格式转换

  • -O binary     用来指定生成文件按照后面的格式来输出,其中binary是指生成二进制(.bin)文件。     
  • -S                 不从源文件中复制重定位信息和符号信息到目标文件中去

arm-linux-objdump   反编译选项 

  • -D                反编译所有段
  • -b binary     指定反编译目标文件格式
  • -m ram       指定反编译目标文件所需的架构,这里是ram架构

转载自:https://www.cnblogs.com/lifexy/p/7065175.html


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值