1、我们自己实现一个简单的配置文件
(1)C程序
还是之前的例子。
#include "config.h" //我们需要使用“配置文件”来生成config.h #ifdef WINDOWS # include <windows.h> #elif defined LINUX # include <sys/types.h> # include <sys/stat.h> # include <unistd.h> # include <fcntl.h> #endif int main(void) { /* 通用代码 */ int i = 0; while(1) { if(i>100) break; else i++; } #ifdef WINDOWS /* 平台相关代码:windows的操作文件的OS API */ HANDLE hfile = CreateFileA(".\file", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE \ | FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL); int dwRead = 0; WrieFile(hfile, &i, sizeof(i), &dwRead, 0); //将i写到file中 #elif defined LINUX /* 平台相关代码:Linux的操作文件的OS API */ int fd = open("./file", O_RDWR | O_CREAT, 0774); write(fd, &i, sizeof(i)); //将i写到file中 #endif return 0; }
(2)实现一个简单的配置文件,然后通过配置文件自动生成config.h
实现配置文件的方式有很多,不管是哪种做法,最终的目的都是为了生成一个config.h,并在config.h中定义相关的宏定义,以打开和关闭相应的条件编译。
配置文件有如下两种实现方式:
1)使用makefile文件来实现
在我们的这里的例子中,就是使用makefile来实现的,makefile就是一个配置文件。
后面讲Uboot的移植时,uboot的配置文件其实也是一个makefile。
(a)makefile文件到底是个啥?
makefile文件主要作用是用于管理C工程项目中的所有.c和.h,以便让编译器更好的去编译所有的文件。
不过我们还可以让makefile附带的生成config.h头文件,也就是说生成config.h并不是makefile的主要作用。
(b)如何得到makefile这个文件?
(a)自己手动写
(b)使用工具软件自动生成
我们这里举的makefile的例子是自己写的,但是实际开发中,大型c工程项目的makefile都是自动生成的。
(c)如何通过makefile文件得到config.h
后面再演示。
2)使用configure.in来实现
configure.in是一个典型的配置文件,同样的,这个配置文件的作用有很多,生成config.h只是其中的一个附带功能而已。
由于configure.in这种方式比较复杂,所以我们这里只简单提一下,后面的课程具体涉及到时,再来详细介绍这个文件。
(a)如何得到configure.in?
· 自己手动写
· 使用autotools工具链(包含好多工具),自动生成configure.in
对大型c工程来说,需要的configure.in会很复杂,自己手动写的话非常麻烦,所以都是使用autotools来自动生成的,不过由于我们几乎不需要自己制作配置文件,所以我们不需要掌握autotools的使用,我们只要能够修改别人制作好的configure.in就可以了。
(b)autotools自动生成configure.in的原理?
autotools工具会去自动扫描源码中所有的.c和.h,根据.c/.h中的条件编译情况,然后自动生成configure.in文件。
(c)如何利用configure.in得到config.h
有了configure.in这个配置文件后,在命令行执行./configure命令,该命令就回去处理configure.in文件,然后得到config.h。
前面说过,configure.in的作用很多,生成config.h只是其中的一个作用。
有关configure.in更多的内容,我们后面课程用到时再来具体介绍。
(3)使用makefile生成config.h
1)写一个makefile文件
Makefile:
all: gcc -o helloworld helloworld.c configure: #执行脚本文件config,config会创建congfig.h #如果传给脚本的参数是win,就往config.h中写入#define WINDOWS #如果传给脚本的参数是Linux,就往config.h中写入#define LINUX ./config win #./config linux clean: #执行脚本文件config,传入参数为clean #脚本文件会删除可执行文件helloworld和config.h ./config clean
使用make命令来执行Makefile文件。
(a)make all -f Makefile:编译helloworld.c,-f Makefile可以省略
(b)make Win:执行config脚本文件,创建config.h,然后在里面定义WINDOWS宏
(c)make Linux:执行config脚本文件,创建config.h,然后在里面定义LINUX宏
2)编写脚本文件config
config:
#!/bin/sh -e #如果config.h文件之前就存在,就使用原来的文件 touch config.h #清空文件内容 :>config.h #将pragma once输入config.h,防止头文件重复包含 # >: 会覆盖以前的内容 echo "#pragma once" > config.h #如果脚本文件参数为win,将#define WINDOWS追加到configh中,>>为追加 if [ "$1" = "win" ] ; then echo "#define WINDOWS" >> config.h fi #如果脚本文件参数为linux,将#define LINUX追加config.h if [ "$1" = "linux" ] ; then echo "#define LINUX" >> config.h fi
makefile会执行这个脚本文件,通过给脚本文件传递不同的参数,就可以让脚本做不同的事情。
疑问:我不会makefile和脚本怎么办?
(a)我们会专门的介绍makefile,我们这里介绍makefile其实非常简单。
(b)至于脚本,后面会有单独的课程来介绍。
2、我们如何对待配置文件
不管是makefile这种配置文件,还是configure.in这种配置文件,我们应该怎么正确的对待配置文件呢?
(1)我们需要自己制作配置文件吗
对于我们一般的C应用开发来说,写的C工程都不是很复杂,而且程序中基本都是通用代码,用不到条件编译,所以我们自己不需要制作配置文件。
除非你自己写的C工程非常复杂,有大量的条件编译,而且别人还需要下载你的源码然后去移植,此时你就必须提供配置文件,如果你不提供配置文件的话,别人几乎不可能去阅读你的源码,在源码中修改宏定义,以打开和关闭相应的条件编译。
其实制作配置文件并不难,网上也有相应的教程,不过我觉得没有必要自己制作,因为确实没有这种需求,如果真的遇到这种需求了,参照网络教程,你自己也可以制作配置文件。
对于Linux嵌入式开发来说,我们往往会下载、移植官方源码,为了方便我们操作,官方源码一定会提供配置文件给我们,所以在Linux嵌入式开发里面,我们更多的是阅读和修改别人所提供的配置文件,而不是自己制作配置文件。
(2)如何才能看懂配置文件
大家只需要跟着课程走,当后面课程涉及到配置文件时,你看我们是怎么阅读和修改配置文件的,你把我们所讲解的内容搞定了,其实配置文件也就基本搞懂了。
一定要记住我们是搞开发的,不是搞研究的,不要去专门的深入的研究配置文件,这样做对于开发来说价值不大。而且配置文件的原理也不难,也没有什么好深入研究的,就算你深入研究了,也不会对我们的实际开发带来更多收益,所以对于配置文件,大家就跟着我们的课程走就可以了。
修改配置文件时,如果你想把整个配置完全看明白的话,这是其实不可能的,因为大型c工程的配置文件会非常长,根本不可能全部看完而且还全部看明白。
对于我们来说,我们只要能把配置文件中的关键点看懂并修改正确,保证整个源码能够被正常编译通过,这就足够了,不过要做到这一点的话也不容易,因为你不知道应该看哪一点,修改哪一点,所以很依赖于经验,我们后面的课程就会介绍这样的经验。
3、总结一下,如何打开和关闭条件编译
打开、关闭条件编译,是靠定义和删除宏来实现的,所以打开和关闭条件编译,最终就演变为了“定义和删除宏”。
有三种方式:
(1)通过修改配置文件,从而决定定义哪些宏、删除哪些宏
不过一般只有大型工程才会使用配置文件这种方式,而且大型工程一般也不是我们自己写的,而是从官方下载的像Linux/安卓等的这种源码。
疑问:为什么大型工程才需要使用配置文件呢?
答:因为大型工程很复杂,要修改的内容太多了,只有配置文件这种方式是最合适的。
(2)直接修改.h/.c,在里面直接定义或者删除宏
这种方式最直接、最简单明了,不过工程变复杂之后,这种方式就不是很方便了,所以这种方式一般都只应用于我们自己写的小型工程上。
(3)还有一种方式,那就是通过IDE设置来定义和删除宏
前面没有介绍这种方式,这里需要补充一下。
直接修改.h/.c有一个缺点,那就是修改代码时手一抖,不小心把代码改错了,结果就把自己给坑了。
通过IDE设置来定义和删除宏的好处就是,可以不用修改代码。
通过IDE设置所定义的宏,对整个工程中所有的文件都是可见的。
通过定义这些宏,就可以对库中代码进行选择,只保留某系列芯片才需要的代码。
像这这种方式,一般常见于单片机开发中,不针对自己的应用代码,主要是针对官方提供的库、框架。
我们演示的例子,就是STM32标准库的例子。
疑问:为什么单片机的库、框架常使用这种方式?
答:因为单片机的库、框架源码一般比较简单,不需要那么多的配置,如果非给弄一个配置文件的话,反倒还把事搞复杂了,但是如果直接修改源码的话,很多人对源码又不是很熟悉,非常容易改错地方,所以人家才提供了这种这种方式,这种方式既简单,同时又规避了错改源码的风险。