• 一点开发环境设计经验


    开发环境设计是个简单,却又非常不简单的事,当然结果也就是天壤之别。

    比如我曾经混过的一个外包项目,竟然需要每个开发人员除了要从SVN下载应用源码外,还要一份Nuclear操作系统副本。编译的时候,自然也就要先编译操作系统了。搞个bug,要忍受跟SVN磨叽一两个钟头,花半个钟将代码加入SourceInsight,修改几行代码后,再跟编译器折腾个把钟,然后再SVN……就这样,日复一日,年复一年。当然,现实没那么夸张,但我给那些开发人员做个了统计,证实每天花不少于2小时在编译、版本管理等。当然,必要的编译、版本管理等工作也是需要时间的,但绝不应该那么多。试想一下,源码缩减到只有几兆,数十兆,或是百来兆,那下载一次代码的时间则能在数分钟内完成;将操作系统,平台做成库文件提供,应用开发人员只编译应用部分并链接库文件,则几分钟就能做完一次版本编译。如此一来,节约下来的时间相对客观。更重要的是,人的心情会变好~~

    另一个直接受开发环境影响的,就是代码层次结构了。想一想,看到一个C, C++的源文件的开始是十几,数十行#include,外加几个编译选项宏的时候会不会疯掉。然后呢,Makefile里又是一堆-I路径。我最怕这个了,找个编译错误都能有经历千山万水的成就感。很多时候,得将些头文件,和头文件的内容进行挪移,甚至另起炉灶(这招太损,但既然都这么搞,也只能入乡随俗)。

    https://files.cnblogs.com/files/hhao020/cshell_prj.re0.001.rar

    编译前:
    1. vob/xxx_prj/
    1.1............build/
    1.2............cmd/
    1.3............tools/
    1.4............export/
    1.5............cshell/
    1.5.1.................export/
    1.5.2.................inc/
    1.6............userapp/
    1.6.1.................export/
    1.7.2.................inc/

    编译后:
    1. vob/xxx_prj/
    1.0............bin/
    1.0.1..............linux.i32
    1.0.2..............linux.i64
    1.1............build/
    1.2............cmd/
    1.3............tools/
    1.4............export/
    1.5............cshell/
    1.5.1.................export/
    1.5.2.................inc/
    1.5.3.................bin/
    1.5.3.1.....................linux.i32/
    1.5.3.2.....................linux.i64/
    1.6............userapp/
    1.6.1.................export/
    1.6.2.................inc/
    1.6.3.................bin/
    1.6.3.1.....................linux.i32/
    1.6.3.2.....................linux.i64/

    相对编译前,编译后的各级源码目录下多了个bin目录,里面包含多个子目标。通常来说,一个项目下会生成针对不同功能板卡的多个可执行文件,因此项目根目录应当包含多个userapp目录,而不同硬件、版本的板块,则在bin目录下使用不同的目标类型存放编译结果。

    这里特别的东西,就是export目录,承担着开发环境设计的画龙点睛之重担。几乎肯定的,export极少被开发环境设计者认识。这是个很悲哀的事,一旦在项目开始时擦肩而过,几乎只能永远错过了。而随之带来的,就是项目开发成本和维护成本攀升,软件越做越复杂。我讲这个,时常被人反驳,代码多了,自然越来越复杂。

    扯淡!你见过土豪因为钱多了而花钱烦恼么?我们做程序的没钱,代码就是财富,项目开展一段时间后,代码多了只应该使一切更容易,因为此时隐藏问题,目标更清晰,还有了更多可用的,可靠的组件,工具。

    子目录export什么来头?它里面存放的,是可以供模块外引用的头文件,如宏,变量和函数的声明。与export对应的,是模块内头文件inc目录,存放的都是些模块内使用的头文件。如此一来,C语言的程序,从某种意义上就有了面向对象的public和private接口特征。外部模块是不能越过编译限制来访问inc的头文件的,这一点可以通过makefile来控制。版本管理者则可以在无需理解源码的前提下,通过编译来发现错误的引用,而他所要做的,就是确保makefile不被未授权的修改。我以前做的比较绝,版本编译前,强行重新生成各模块的makefile(从标准模块库复制)。这样一来,任何想突破规则的改动,都会被编译器抱怨。

    开发环境设计,另一个要点是,避免大量的#include<xxx.h>。这个不是那么绝对,但如果项目是新的,就应该避免应用模块用;如果只是个新模块,则应该采取设置边界edger.c来隔绝。要做到避免系统头文件,项目根目录export应该提供至少两个组件:prj_type.h和sal_os.h。在我做到项目里,它们会被命名成zType_Def.h和salOS.h。zType_Def.h包含了一些基础类型的定义,如byte_t, word_t, dword_t, lword_t,平台特定的zMsg_t, zHandle_t,甚至一些方便变成的宏定义MAX,_STR等等。这里只有一个原则,就是一切都必须跟操作系统无关。salOS.h则是一些系统头文件提供内容的封装,比如memset被重新定义成zMemset,time被重新定义成zTime,等等。当然,salOS也是跟操作系统无关的,salOS里可以出现#include<xxx>引用系统头文件,但限定为通用的系统头文件。如ws_sock.h这类特定系统的头文件,则不可以暴露在salOS.h里面,必须在salNet.c等模块里进行封装后,在salOS.h中提供操作系统无关的接口函数。

    zType_Def是必须强制被所欲应用程序引用的,salOS则根据应用的情况决定。但不管咋样,这两个文件都是软硬件无关的。换句话说,当我们开发一个给嵌入式目标板使用的程序时,有机会在Linux一类的系统上进行大部分功能的调试工作。当然,大多时候光有type和salOS是不够的,还需要个salHW。salHW是具体目标系统相关的,实现对真实硬件接口的一个横向封装,而在模拟环境下提供一套基本的硬件行为模拟。salOS和salHW所对应的实现,需要存放在不同的子目录。这样,通过makefile可以很容易的控制具体需要编译、链接哪个。

    我相当反对应用程序开发者直接使用printf,malloc等一类系统函数,在一个稍微大一点点的项目,它们总是会带来灾难。比如,我刚开始做移动核心网时,出现了无法关闭的一两个打印。这是电信运营商眼里是绝不容许的,幸好,很快等到一个计划中的版本升级,否则那一年的无故障运行时间,就不可能达成5个9了。有了type和salOS等头文件,在应付打印,内存泄漏等问题,就容易多了(这点以后聊)。

    说了半天,都是防范滥用头文件问题,但没说过如何防范头文件烂设计问题。确实,很多开发人员偷懒,把所有东西都扔到export目录,inc目录总是空空的。说实话,哥拿这类人真没什么办法,也只有空想者拿刀砍人!

  • 相关阅读:
    浅谈 java 比较器
    浅谈lambda表达式
    使用DateLocaleConverter和SimpleDateFormat实现字符串转换成日期
    myeclipse中运行tomcat报错java.lang.NoClassDefFoundError
    《谁说菜鸟不会数据分析》读书笔记(1)
    撰写报告要点
    分析报告_问题界定篇
    数据分析报告
    kaggle入门之Titanic生存预测
    pandas基础
  • 原文地址:https://www.cnblogs.com/hhao020/p/5013048.html
Copyright © 2020-2023  润新知