Akagi201
7/31/2014 - 6:30 AM

openwrt-makefile

## local repo git-src
* <https://forum.openwrt.org/viewtopic.php?id=46916>


## linux2.4内核的配置系统由3个部分组成:
1. Makefile: 分布在Linux内核源代码中的Makefile, 定义Linux内核的编译规则.
2. 配置文件(config.in): 给用户提供配置选择的功能.
3. 配置工具: 包括配置命令解释器和配置用户界面.

我们只对Makefile和配置文件进行讨论, 介绍如何使用配置系统, 内核开发者无须了解配置工具的原理.

## Makefile概述
Linux内核中的Makefile以及与Makefile直接相关的文件有:

1. 顶层Makefile: 是整个内核配置, 编译的总体控制文件. 有两个主要的任务: 产生vmlinux文件和内核模块(module). 为了达到此目的, 顶层Makefile递归的进入到内核的各个子目录这种, 分别调用位于这些子目录中的Makefile.
2. .config: 内核配置文件, 包含由用户选择的配置选项, 用来存放内核配置后的结果, 控制那些代码需要编译.
3. arch/*/Makefile: 位于各种CPU体系目录下的Makefile, 如: arch/arm/Makefile, 是针对特定平台的Makefile.
4. 各个子目录下的Makefile: 比如drivers/Makefile, 负责所在子目录下源代码的管理.
5. Rules.make: 规则文件, 被素有的Makefile使用. 他定义了所有Makefile共用的编译规则.

## 顶层Makefile中的变量
* 版本信息: `VERSION, PATCHLEVEL, SUBLEVEL, EXTRAVERSION, KERNELRELEASE`.
* CPU体系结构: `ARCH`.
* 路径信息: `TOPDIR, SUBDIRS`.
* 内核组成信息: `HEAD, CORE_FILES, NETWORKS, DRIVERS, LIBS`
* 编译信息: `CPP, CC, AS, LD, AR, CFLAGS, LINKFLAGS`
* 配置变量: `CONFIG_*`

## Rules.make变量
* `O_OBJS`, `L_OBJS`, `OX_OBJS`, `LX_OBJS`: 本目录下需要编译进linux内核vmlinux的目标文件列表, 其中, `OX_OBJS`和`LX_OBJS`中的"X"表明目标文件使用了`EXPORT_SYMBOL`输出符号.
* `M_OBJS`, `MX_OBJS`: 本目录下需要被编译成可装载模块的目标文件列表. 同样, `MX_OBJS`中的"X"表明目标文件使用了`EXPORT_SYMBOL`输出符号.
* `O_TARGET`, `L_TARGET`: 每个子目录下都有一个`O_TARGET`或`L_TARGET`, `Rules.make`首先从源代码编译生成`O_OBJS`和`OX_OBJS`中所有的目标文件, 然后使用`$(LD) -r`把他们链接成一个`O_TARGET`或`L_TARGET`. `O_TARGET`以`.o`结尾, 而`L_TARGET`以`.a`结尾.

## 配置文件
* 把新功能加入到Linux的配置选项中, 提供此项功能的说明, 让用户有机会选择此项功能, 这些都需要在`config.in`文件中用配置语言来编写配置脚本.
* 配置命令与解释脚本
```
make config, make oldconfig --> scripts/Configure
make menuconfig             --> scripts/Menuconfig
make xconfig                --> scripts/tkparse
```

* 以`make menuconfig`为例, 顶层Makefile调用`scripts/Configure`. 按照`arch/arm/config.in`来进行配置. 命令执行完后产生文件`.config`, 其中保存着配置信息. 下一次再做`make menuconfig`将产生新的`.config`文件, 原`.config`被改名为`.config.old`.

## 询问语句

```
bool    /prompt/ /symbol/
hex     /prompt/ /symbol/ /word/
int     /prompt/ /symbol/ /word/
string  /prompt/ /symbol/ /word/
tristate /prompt/ /symbol/
```

询问语句首先显示一串提示符 `/prompt/`, 等待用户输入, 并把输入的结果赋给`/symbol/`所代表的配置变量. 不同的询问语句的区别在于他们接受的输入数据类型不同, 比如`bool`接受布尔类型(y 或 n), hex接受16进制数据. 有些询问语句还有第三个参数`/word/`, 用来给出缺省值.

## 定义语句

```
define_bool /symbol/ /word/
define_hex /symbol/ /word/
define_int /symbol/ /word/
define_string /symbol/ /word/
define_tristate /symbol/ /word/
```
不同于询问语句等待用户输入, 定义语句显式的给配置变量`/symbol/`赋值`/word/`.

## 依赖语句
```
dep_bool /prompt/ /symbol/ /dep/ ...
dep_mbool /prompt/ /symbol/ /dep/ ...
dep_hex /prompt/ /symbol/ /word/ /dep/ ...
dep_int /prompt/ /symbol/ /word/ /dep/ ...
dep_string /prompt/ /symbol/ /word/ /dep/ ...
dep_tristate /prompt/ /symbol/ /dep/ ...
```

与询问语句类似, 依赖语句也是定义新的配置变量. 不同的是, 配置变量`/symbol/`的取值范围将依赖于配置变量列表`/dep/`.... 这就意味着: 被定义的配置变量所对应功能的取舍取决于依赖列表所对应功能的选择. 以`dep_bool`为例, 如果`/dep/`...列表的所有配置变量都取值y, 则显示`/prompt/`, 用户可输入任意的值给配置变量`/symbol/`, 但是只要有一个配置变量的取值为n, 则`/symbol/`被强制成n. 不同依赖语句的区别在于他们由依赖条件所产生的取值范围不同.

## 选择语句
```
choice  /prompt/ /word/ /word/
```
choice 语句首先给出一串选择列表, 供用户选择其中一种.

## if语句
```
if [/expr/]; then
/statement/
fi
if [/expr/]; then
/statement/
else
/statement/
fi
```
if语句对配置变量(或配置变量的组合)进行判断, 并作出不同的处理. 判断条件`/expr/`可以是单个配置变量或字符串, 也可以是带操作符的表达式. 操作符有: `=`, `!=`, `-o`, `-a`等.

## 菜单块(menu block)语句
```
mainmenu_option next_comment
comment '...'
...
endmenu
```
引入新的菜单. 在向内核增加新的功能后, 需要相应的增加新的菜单, 并在新菜单下给出此项功能的配置选项. Comment后带的注释就是新菜单的名称. 所有归属于此菜单的配置选项语句都写在comment和endmenu之间.

## Source语句
```
source /word/
```
`/word/`是文件名, `source`的作用是调入新的文件.