首页 /  技术专区  /  C 宽屏模式 >

条件编译——配置文件实现

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标准库的例子。

疑问:为什么单片机的库、框架常使用这种方式?

答:因为单片机的库、框架源码一般比较简单,不需要那么多的配置,如果非给弄一个配置文件的话,反倒还把事搞复杂了,但是如果直接修改源码的话,很多人对源码又不是很熟悉,非常容易改错地方,所以人家才提供了这种这种方式,这种方式既简单,同时又规避了错改源码的风险。



头像
0/200
图片验证码