makefile如何减小可执行文件的大小(没有用到的函数不参与链接)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/LEON1741/article/details/88681531

一、问题

在linux下玩makefile玩的多了,发现一个问题。程序总是越编越大,换句话说就是程序编译出来的可执行文件总是在不停的增大,特别是加入了外部的静态库之后,程序文件显著增大,造成程序下载耗时增大,甚至造成程序空间溢出,FLASH不够用。

我分析了一下,虽然所引用的静态库本身确实很大,但是我的程序中只用到了其中几个函数,按理来说,它只取这几个函数进行链接,链接之后的可执行文件不应该那么大才对,肯定是哪里没有设置好。我记得在windows下的KEIL或者IAR就不会这样,它们里面有一个设置选项,可以指定“没有使用的函数不参与链接”之类的,那么makefile里面难道没有类似的功能吗?于是,一番百度和CSDN之后,轻松搞定!

二、原理

下文引自网络博客:

因为GCC链接操作以section作为最小的处理单元,一个section中可以包含很多个function,而一个section中只要有一个function被引用,该section就会被加入链接,最终生成可执行文件。

换句话说就是,在缺省情况下,某个.c程序中的所有function,实际上都会编译成同一个section。那么,只要你的代码中用到这个.c生成的.o的其中任何一个function,系统就会将这整个section进行链接。这就导致,我们在引用外部静态库时,不管你是引用其中一个函数,还是引用全部的函数,你最终编译链接出来的可执行文件都一样大,系统并不会自动根据你所引用的函数个数的多少而动态的调整链接方式。

三、办法

那么,要怎么修改呢?方法也很简单,两个步骤即可:

  • 编译时:使用"-ffunction-sections"和"-fdata-sections"将每个function/data创建为一个sections,sections名与function/data名保持一致。

  • 链接时:采用"-Wl, -gc-sections"申明,告诉系统去掉那些没用用到的section。

四、示例

main.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int fun_0()
{
printf(“this is a test function. %s: %d\n”, FUNCTION, LINE);
return 0;
}

int fun_1()
{
printf(“this is a test function. %s: %d\n”, FUNCTION, LINE);
return 0;
}

int fun_2()
{
printf(“this is a test function. %s: %d\n”, FUNCTION, LINE);
return 0;
}

int fun_3()
{
printf(“this is a test function. %s: %d\n”, FUNCTION, LINE);
return 0;
}

int fun_4()
{
printf(“this is a test function. %s: %d\n”, FUNCTION, LINE);
return 0;
}

int fun_5()
{
printf(“this is a test function. %s: %d\n”, FUNCTION, LINE);
return 0;
}

int fun_6()
{
printf(“this is a test function. %s: %d\n”, FUNCTION, LINE);
return 0;
}

int main()
{
fun_0();

<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52

makefile

optimized:
	gcc -ffunction-sections -fdata-sections -c main.c
	gcc -Wl,-gc-sections -o test_optimized main.o

normal:
gcc -c main.c
gcc -o test_normal main.o

clean:
-@rm *.o test_normal test_optimized

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

运行结果对比:

leon@Ubuntu:~/studytest/z_mydesign/section_test2$ make normal 
gcc -c main.c
gcc -o test_normal main.o
leon@Ubuntu:~/studytest/z_mydesign/section_test2$ make optimized 
gcc -ffunction-sections -fdata-sections -c main.c
gcc -Wl,-gc-sections -o test_optimized main.o
leon@Ubuntu:~/studytest/z_mydesign/section_test2$ ll
总用量 44
drwxrwxr-x 2 leon leon 4096 3月  20 14:02 ./
drwxrwxr-x 5 leon leon 4096 3月  20 13:45 ../
-rw-rw-r-- 1 leon leon  496 3月  20 14:02 main.c
-rw-rw-r-- 1 leon leon 3696 3月  20 14:02 main.o
-rw-rw-r-- 1 leon leon  206 3月  20 13:50 Makefile
-rwxrwxr-x 1 leon leon 8896 3月  20 14:02 test_normal*
-rwxrwxr-x 1 leon leon 8432 3月  20 14:02 test_optimized*

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

可以看出,优化后的bin文件,减少了 8896-8432=464 bytes。

五、注意

请注意:
1)使用了section选项,当函数被声明了,但是函数没有被调用,函数体不实现也编译ok,但是函数体不能重复定义;
2)一但使用-Wl,-gc-sections选项之后,将无法使用gdb调试。也无法使用gprof工具;

                                </div>
            <link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-095d4a0b23.css" rel="stylesheet">
                </div>
### 回答1: 这是一个由头文件greeting.h、自定义函数文件greeting.c、主函数文件myapp.c构成的C程序。根据这三个文件的依赖关系,需要编写一个makefile文件。 makefile文件的内容如下: ``` myapp: myapp.o greeting.o gcc -o myapp myapp.o greeting.o myapp.o: myapp.c greeting.h gcc -c myapp.c greeting.o: greeting.c greeting.h gcc -c greeting.c ``` makefile文件中,第一行指定了目标文件myapp,它依赖于myapp.o和greeting.o两个文件。第二行指定了如何生成myapp文件,即使用gcc命令将myapp.o和greeting.o链接在一起。第三行指定了如何生成myapp.o文件,即使用gcc命令将myapp.c编译成myapp.o文件。第四行指定了如何生成greeting.o文件,即使用gcc命令将greeting.c编译成greeting.o文件。 这样,当我们在命令行中执行make命令时,make会根据makefile文件中的规则,自动编译生成myapp可执行文件。 ### 回答2: 本文介绍如何在C语言中编写一个由头文件greeting.h、自定义函数文件greeting.c、主函数文件myapp.c 构成的程序,并根据这三个文件的依赖关系编写makefile文件。 首先需要编写greeting.h头文件,该文件定义greeting.c所需的函数原型和宏定义。例如: ```C #ifndef GREETING_H #define GREETING_H void hello(); void bye(); #define GREETING "Hello World!" #endif ``` 然后编写greeting.c文件,该文件定义了在头文件中声明的函数。例如: ```C #include <stdio.h> #include "greeting.h" void hello() { printf("%s\n", GREETING); } void bye() { printf("Goodbye!\n"); } ``` 最后编写主函数文件myapp.c,该文件调用并使用定义在greeting.c中的函数。例如: ```C #include "greeting.h" int main() { hello(); bye(); return 0; } ``` 接下来编写makefile文件,makefile编译器的重要配置文件,其作用是将源文件编译可执行文件。该文件主要完成三个任务:指定编译器、指定依赖关系、定义规则。例如: ```makefile CC=gcc all: myapp greeting.o: greeting.c greeting.h $(CC) -c greeting.c myapp.o: myapp.c greeting.h $(CC) -c myapp.c myapp: greeting.o myapp.o $(CC) -o myapp greeting.o myapp.o clean: rm -rf *.o myapp ``` 这个makefile文件分为四部分,第一部分是指定编译器,第二部分是规定了all,它代表需要编译的目标。第三部分是指定依赖关系。每一个目标可能会依赖多个源文件、头文件和其他依赖,这部分就是定义了依赖关系。第四部分是定义规则。规则是如何生成目标的具体指令,该部分是定义了如何生成目标文件和可执行文件。如果需要执行清理操作,则可以通过最后的部分来执行清理指令。 完成这些步骤后,执行make命令即可自动生成可执行文件。在命令行中进入程序文件所在的目录,输入make命令即可生成可执行文件myapp。 本文通过一个简单的程序示例介绍了如何编写C程序,并编写makefile自动编译程序的方法。学习这些内容后,读者将能够更好地掌握C语言编程的基本技巧。 ### 回答3: 首先,让我们来分析一下题目中三个文件的作用: greeting.h:这个头文件主要包含了我们的函数声明,在myapp.c中需要用到这些函数。 greeting.c:这个文件包含了我们自己定义的一些函数,是实现我们的程序功能的核心文件。 myapp.c:这是我们的主函数文件,程序的入口点,我们需要在这个文件中调用greeting.c中定义的函数。 根据以上分析,我们可以得到这样一个makefile文件: ```Makefile CC=gcc CFLAGS=-I. all: myapp greeting.o: greeting.c greeting.h $(CC) -c -o greeting.o greeting.c $(CFLAGS) myapp: myapp.c greeting.o $(CC) -o myapp myapp.c greeting.o $(CFLAGS) clean: rm -f *.o myapp ``` 在这个makefile文件中,我们使用了变量CC和CFLAGS,分别表示编译C代码时使用的编译器和编译选项。我们使用all作为默认目标,这个目标会生成我们的可执行文件myapp。在生成myapp之前,我们需要先编译greeting.o这个中间文件,这个文件是由greeting.c和greeting.h所编译而成的。最后,我们需要将myapp.c和greeting.o一起编译成最终的可执行文件myapp。 通过这样的makefile文件,我们可以方便地管理我们的工程,而且当我们的代码量增大时,可以避免手动编译链接带来的麻烦。使用make可以自动判断哪些文件需要重新编译,只编译需要更新的文件,从而提高编译的效率。 总结一下,makefile文件主要用于管理我们的工程,自动化编译链接,从而减少手动操作的时间和出错的概率。编写好Makefile文件之后,只需要在终端输入make命令,就可以自动编译我们的程序,生成可执行文件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值