嵌入式Linux编译C/C++的几种方式

发布于:2023-10-25 ⋅ 阅读:(80) ⋅ 点赞:(0)

引言

源文件需要经过编译才能生成可执行文件。在 Windows 下进行开发时,只需要点几个按钮即可编译,集成开发环境(比如 VSCode)已经将各种编译工具的使用封装好了。Linux 下也有很优秀的集成开发工具,但是更多的时候是直接使用编译工具;即使使用集成开发工具,也需要掌握一些编译选项。本文将介绍Linux下常用的C/C++编译方式:GCC编译器和Makefile。

GCC编译器

介绍

GCC 编译器是 Linux 系统下最常用的 C/C++ 编译器,大部分 Linux 发行版中都会默认安装。GCC 编译器通常以gcc命令的形式在终端(Shell)中使用。GCC最初代表“GNU C Compiler”,当时只支持C语言。 后来又扩展能够支持更多编程语言,包括 C++、Fortran 和 Java 等。 因此,GCC也被重新定义为“GNU Compiler Collection”,成为历史上最优秀的编译器, 其执行效率与一般的编译器相比平均效率要高 20%~30%。

GCC 编译过程

一个 C/C++文件要经过预处理(preprocessing)、编译(compilation)、汇编(assembly)和链接(linking)等 4 步才能变成可执行文件。

常用编译选项

-E:预处理,开发过程中想快速确定某个宏可以使用“-E -dM”
-c:把预处理、编译、汇编都做了,但是不链接
-o:指定输出文件
-I:指定头文件目录
-L:指定链接时库文件目录
-1:指定链接哪一个文件

怎么编译多个文件

  • 一起编译、链接:
gcc -o test main.c sub.c
  • 分开编译,统一链接:
gcc -c -o main.o main.c
gcc -c -o sub.o sub.c
gcc -o test main.o sub.o

制作、使用动态库:

制作、编译:

gcc -c -o main.o main.c
gcc -c -o sub.o sub.c
gcc -shared -o libsub.so sub.o sub2.o sub3.o(可以使用多个.o 生成动态库)
gcc -o test main.o -lsub -L /libsub.so/所在目录/

运行:
1、先把 libusb.so 放到 PC 或板子上的/lib 目录,然后就可以运行 test 程序。
2、如果不想把 libusb.so 放到/lib,也可以放在某个目录比如/a,然后如下执行:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/a 
./test

制作、使用静态库

gcc -c -o main.o main.c
gcc -c -o sub.o sub.c
ar crs libsub.a sub.o sub2.o sub3.o(可以使用多个.o 生成静态库)
gcc -o test main.o libsub.a (如果.a 不在当前目录下,需要指定它的绝对或相对路径)

运行:
不需要把静态库 libsub.a 放到板子上。

很有用的选项

gcc -E main.c // 查看预处理结果,比如头文件是哪个
gcc -E -dM main.c > 1.txt // 把所有的宏展开,存在 1.txt 里
gcc -Wp,-MD,abc.dep -c -o main.o main.c // 生成依赖文件 abc.dep,后面 Makefile 会用

Makefile

介绍

在一个工程中,源文件可能不计其数,并且它们按类型、功能、模块分别放在若干个目录中。Makefile定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至可以进行更复杂的功能操作。这使得Makefile就像一个Shell脚本一样,可以执行操作系统的命令。
在Makefile中,可以定义各种规则来控制编译过程。例如,可以指定哪些文件需要编译,哪些文件不需要编译,哪些文件需要重新编译,以及这些文件的依赖关系等。Makefile还可以定义变量来控制编译选项,例如指定编译器、编译选项、链接库等。
Makefile的编写需要遵循一定的语法规则。它由一系列规则组成,每个规则由一个目标(target)和一组依赖项(dependencies)组成。目标指定了需要生成的文件或执行的操作,依赖项则指定了生成目标所需的文件或操作。在规则下方可以定义命令来执行相应的操作,例如编译源代码、链接库等。
Makefile的编写可以根据具体的项目需求和开发环境进行调整和优化。它可以帮助开发人员自动化编译过程,提高编译效率,并减少出错的可能性。
会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力。

Makefile 规则与示例

规则

一个简单的 Makefile 文件包含一系列的“规则”,其样式如下:

目标(target)…: 依赖(prerequiries)…
<tab>命令(command)

如果“依赖文件”比“目标文件”更加新,那么执行“命令”来重新生成“目标文件”。
命令被执行的 2 个条件:依赖文件比目标文件新,或是 目标文件还没生成。
目标(target)通常是要生成的文件的名称,可以是可执行文件或 OBJ 文件,也可以是一个执行的动作名称,诸如`clean’。
依赖是用来产生目标的材料(比如源文件),一个目标经常有几个依赖。
命令是生成目标时执行的动作,一个规则可以含有几个命令,每个命令占一行。
注意:每个命令行前面必须是一个 Tab 字符,即命令行第一个字符是 Tab。这是容易出错的地方。
通常,如果一个依赖发生了变化,就需要规则调用命令以更新或创建目标。但是并非所有的目标都有依赖,例如,目标“clean”的作用是清除文件,它没有依赖。规则一般是用于解释怎样和何时重建目标。make 首先调用命令处理依赖,进而才能创建或更新目标。当然,一个规则也可以是用于解释怎样和何时执行一个动作,即打印提示信息。

Makefile 的 函数

函数调用的格式如下:

$(function arguments)

这里function是函数名,arguments是该函数的参数。参数和函数名之间是用空格或 Tab 隔开,如果有多个参数,它们之间用逗号隔开。这些空格和逗号不是参数值的一部分。
常用函数:

  • $(foreach v
  • ar,list,text)
    简单地说,就是 for each var in list, change it to text。
    对 list 中的每一个元素,取出来赋给 var,然后把 var 改为 text 所描述的形式。
    例子:
objs := a.o b.o
dep_files := $(foreach f, $(objs), .$(f).d) // 最终 dep_files := .a.o.d .b.o.d
  • $(wildcard pattern)
    pattern 所列出的文件是否存在,把存在的文件都列出来。
    例子:
src_files := $( wildcard *.c) // 最终 src_files 中列出了当前目录下的所有.c 文件

通用 Makefile 的解析

make 命令的使用

执行 make 命令时,它会去当前目录下查找名为“Makefile”的文件,并根据它的指示去执行操作,生成第一个目标。
我们可以使用“-f”选项指定文件,不再使用名为“Makefile”的文件,比如:

make -f Makefile.build

我们可以使用“-C”选项指定目录,切换到其他目录里去,比如:

make -C a/ -f Makefile.build

更多精彩,欢迎关注
抖音号:《物联网知识》

公众号:《物联网知识》

B站:《跋扈洋》

CSDN:《跋扈洋》

本文含有隐藏内容,请 开通VIP 后查看