SylixOS Makefile结构分析
SylixOS的工程主要有BASE、BSP、APP等,不同工程会有相应的Makefile模板来控制编译参数,下面以BASE工程为例,分析整个Makefile的工作原理。这里先给出整个BASE工程的Makefile结构,然后再逐步讲解。
+----------------+ +----------------+
| libsylixos | +------->+ mktemp |
+----------------+ | +----------------+
| mktemp +-----------+ | application.mk |
+----------------+ +----------------+
+----------------+ | libsylixos.mk +------------+ | arch.mk |
| SylixOS BASE | +----------------+ | +----------------+
+----------------+ +------>+ Makefile | | | bsp.mk |
| libsylixos | | +----------------+ | +----------------+
+----------------+ | | | common.mk |
| libcextern | | | +----------------+
+----------------+ | | | gcc.mk |
| config.mk | | | +----------------+
+----------------+ | +------>+ library.mk |
| Makefile +----+ +----------------+
+----------------+ | +---------->+ libsylixos.mk |
| | +----------------+
| | | header.mk |
| +----------------+ | +----------------+
| | libcextern | | | end.mk |
| +----------------+ | +----------------+
| | libcextern.mk +--------+
| +----------------+
+------>+ Makefile |
+----------------+
在SylixOS BASE下面,除了libsylixos
内核源码外,还可选择一些组件一起编译,如图上面的c
库。无论是libsylixos、library、app、或者bsp
,原理都是一样的,所以这里以libsylixos
编译过程详细说明Makefile
工作流程。先给出SylixOS BASE
的目录结构图:
base
目录下的Makefile
是最顶层的,其内容如下:
这里会一次编译libsylixos
和libcextern
两个工程,下面主要针对libsylixos
讲解。libsylixos
目录结构如下图:
由x86_base
的Makefile
会调用到libsylixos
的Makefile
,其Makefile
主要内容包含在如下几行:
首先设置了模板路径到libsylixos/SylixOS/mktemp
目录下,包含了libsylixos/SylixOS/mktemp/header.mk
模板和当前目录下的libsylixos.mk
,对于header.mk
后面会讲,libsylixos.mk
的主要内容是填充了所要编译的源文件并包含了libsylixos/SylixOS/mktemp/libsylixos.mk
,对于libsylixos/SylixOS/mktemp/libsylixos.mk
包含了libsylixos/SylixOS/mktemp/common.mk
。整个Makefile
的包含过程如下:
+--+mktemp/gcc.mk
|
+--------+mktemp/header.mk+---+
| |
| +--+mktemp/arch.mk
|
|
+-----+libsylixos Makefile+---------------+libsylixos.mk+----------+mktemp/libsylixos.mk+-------+mktemp/common.mk
| |
| | +--+make all
x86_base Makefile+-----+ | |
| +--------+mktemp/end.mk+------+
| |
+-----+libcextern Makefile +--+make clean
这里面文件确实挺多,我们先抓住主框架来读,然后再讲解每个文件的作用。既然是Makefile
,那么必然要有目标,我们先找到目标,然后顺藤摸瓜。在mktemp/end.mk
文件内容如下,
这里面包含了两个目标,分别是all
和clean
。由于目标all
依赖于TARGETS
,所以再看看哪里有TARGETS
的说明,既然是目标,那么针对不同工程如base、bsp或app
应该会存在差异,所以就放在了各自的mktemp
模板中,这里对应的便是mktemp/libsylixos.mk
,在该文件最后有对TARGETS
的赋值。有了目标,那么再找找源文件,源文件一定和工程相关,所以在工程的libsylixos.mk
中(注意:libsylixos.mk和mktemp/libsylixos.mk
不是一个文件),在该文件中包含了所有要编译的源文件。
现在目标和源都有了,再看看文件如何编译及编译参数,主要从mktemp/gcc.mk,mktemp/arch.mk,mktemp/common.mk,mktemp/libsylixos.mk
几个文件分析:
arch.mk
主要设置了针对不同工程的编译参数,如-PIC,-shared
等等gcc.mk
这里面设置了优化等级及调试等级,及一些编译器内建库的链接common.mk
对于common.mk
告知Makefile
,针对目标所需依赖如何进行编译,主要部分如下:
mktem/libsylixos.mk
,前面几个文件已经将准备工作做好了,mktemp/libsylixos.mk
就根据自身工程属性选用上面提供的编译参数,然后制定目标及依赖项,有了目标和依赖项之后,就会按照上面common.mk
中的规则去编译文件了。
讲述完整个Makefile工作流程之后,这里再介绍两个小细节:
-
在工程目录下的
libsylixos.mk
中,除了设置了源码集合外,还可以单独指定某一文件按照指定编译参数去编译,一旦这里指定了,即使在mktemp/common.mk
中有统配符指定,也会优先使用libsylixos.mk
中的 -
依赖项设定。我们知道
Makefile
一个最大的好处就是会根据依赖项是否更新来决定是否重新编译目标文件。如果一个工程是第一次编译,那么所有文件都需要重新编译,这没什么好说的。对于整个过程已经编译过,现在只修改了其中的一些文件,要想Makefile
只编译修改过的文件就要设置好依赖项,举个简单例子:
main.o: main.c
.....
all: main.o
.....
这里面的main.o
依赖于main.c
,所以当main.c
修改时就会重新编译main.c
,生成新的main.o
,那么问题来了,对于一个.c
文件包含了很多头文件,如果头文件修改了,那么这些对应的.c
也需要重新编译,这依赖项如果每一个都人工填写也太麻烦了,所以这里需要编译器帮忙,在编译文件时,加入-M
系列参数,及可生成对应文件的依赖关系,名字为xxx.d
。以_BitmapLib.d
文件内容为例,内容如下图:
从图中可以看到,_BitmapLib.o
所依赖的文件有很多,要是人工去查找填写,那可有得麻烦了。在mktemp/common.mk
中,是将所有依赖项文件都包含进来了,这样对于一个目标,一旦有依赖发生了变化,就会重新编译目标文件,而依赖没发生变化的目标无需重新编译。再次强调,我们说的Makefile
会自动根据依赖是否变化来决定是否重新生成目标,这没毛病,但是依赖项Makefile
可不会帮我们自动生成的,是借助gcc
的-M
系列编译参数生成的。