服务间的依赖和springboot 模块依赖间的依赖有很大的区别

可以把多个模块组合成较大的模块,而不必了解模块内;每个模块都有严格规定的接口,其中包括由入口和出口;内聚:概念、形式、优劣顺序;概念、衡量一个模块内部各个元素彼此结合的紧密程度;块内联系耦合性可读性可修改性公用性评分功能组合顺;概念、衡量不同模块彼此间互相依赖(连接)的紧密程;低低较低一般较高高高好好较好较好一般不好坏好好较;耦合形式可读性可维护性扩散错误的
可以把多个模块组合成较大的模块,而不必了解模块内部构造的知识; 每个模块都有严格规定的接口,其中包括由入口和出口形成的控制连接、由参数和共享的公用数据形成的数据连接以及由模块间的服务支持形成的功能连接。 内聚:概念、形式、优劣顺序 概念、衡量一个模块内部各个元素彼此结合的紧密程度,如果一个模块的内聚度大,模块的独立性则会提高 形式:功能内聚、顺序内聚、通信内聚、步骤内聚、时间内聚、逻辑内聚、偶然内聚 优劣顺序: 块内联系 耦合性 可读性 可修改性 公用性 评分 功能组合 顺序组合 通信组合 过程组合 时间组合 逻辑组合 偶然组合
耦合:概念、方式、 概念、衡量不同模块彼此间互相依赖(连接)的紧密程度;块间联系越小,模块的独立性则会越高,耦合度就会降低。 方式:简单耦合、数据耦合、控制耦合、公共耦合、内容耦合 优劣顺序: 低 低 较低 一般 较高 高 高 好 好 较好 较好 一般 不好 坏 好 好 较好 较好 不好 坏 坏 好 较好 不好 不好 坏 坏 坏 10 9 7 5 3 1 0
耦合形式可读性可维护性扩散错误的能力公用性简单耦合数据耦合控制耦合公共耦合内容耦合好好一般最坏最坏好好不好坏最坏弱弱一般强最强好好不好最坏最坏 结构设计工具:H图、HIPO图 H图、在软件总体设计阶段最常用的工具之一,用来描绘软件的层次结构,结构图中的每个方框代表一个模块,方框中的文字简要说明模块的功能,方框间的连线表示模块的调用关系。层次图适合于在自顶而下设计软件的过程中使用。
6 HIPO图:由两部分组成,在H图的基础上增加IPO图,并且对每个方框进行编号,使其具有可跟踪性。编号规则如下:最顶层方框不编号,第一层中各模块的编号依次为1.0,2.0,3.0,??;如果模块2.0还有下层模块,那么下层模块的编号依次为2.1,2.2,2.3,??;如果模块2.2又有下层模块,则下一层各模块的编号根据上面的规律依次为2.2.1,2.2.2,2.2.3,??,依次类推。
第六章 详细设计 详细设计:概念、目标、任务 概念:也叫程序设计,但不同于编码或编制程序。在此阶段要决定各个模块的实现过程和算法,并精确表达这些算法。 目标:确定应该怎样具体地实现所要求的系统,具体地说,实现对目标系统的精确描述,从而在编码阶段可以把这个描述直接翻译成用某种程序设计语言书写的程序。
不仅仅是逻辑上正确地实现每个模块的功能,更重要的是设计出的处理过程应该尽可能简明易懂。 任务:细化总体设计的体系流程图,绘出程序结构图。 为每个功能模块选定算法。 确定模块使用的数据组织(结构)。 确定模块的接口细节、用户界面,及模块间的调度关系。 描述每个模块的流程逻辑。(程序流程图) 编写详细设计文档。主要包括细化的系统结构图及逐个模块的描述,如功能、接口、数据组织、控制逻辑等。 结构化程序设计:要点、基本控制结构 要点: 采用自顶向下逐步求精的设计方法。 采用顺序、选择、循环三种基本结构组成程序的控制结构。 尽量使用单入口/单出口的控制结构,减少传递参量(数)的个数。 尽量少用或不用GoTo语句。 提高模块的内聚度,降低模块间的耦合度 基本控制结构:程图、N-S图、PAD图 详细设计工具:程序流程序流程图:程序流程图是使用最广泛的一种算法表达工具。它具有简单、直观、易于掌握的优点,是历史最悠久、使用最广泛的描述过程设计的工具 它包括顺序型、选择型、先判定型循环、后判定型循环、多种情况选择型 N-S图:每一个N-S图开始于一个大的矩形,表示它所描述的模块,该矩形的内部被分成不同的部分,分别表示不同的子处理过程,这些子处理过程又可进一步分解成更小的部分。 N-S图有下述特点:
7 ? 功能域(一个特定控制结构的作用域)明确,可以从盒图上一眼就看出来。 ? 不可能任意转移控制。 ? 很容易确定局部和全程数据的作用域。 ? 很容易表现嵌套关系,也可以表示模块的层次结构。 PAD图:即问题分析图,是Problem Analysis Diagram的英文缩写。它用二维树形结构的图来表示程序的控制流。 用户界面:组成、设计原则、设计流程 组成:墙纸、标签、视窗、菜单、对话框、数据输入界面 设计原则: 1.易用性原则2.规范性原则3.帮助原则4.合理性原则5.美观与协调性原则6.菜单位置原则7.独特性原则8.快捷方式的组合原则9. 排错性考虑原则 设计流程:结构设计:结构设计是界面设计的骨架。通过对用户研究和任务分析,制定出产品的整体架构。 交互设计:交互设计的目的是使产品让用户能简单使用。任何产品功能的实现都是通过人和机器的交互来完成的。 视觉设计:在结构设计的基础上,参照目标群体的心理模型和任务达成进行视觉设计。包括色彩、字体、页面等。视觉设计要达到用户愉悦使用的目的。 模块设计的基本内容:1 程序描述.2 功能3 性能.4 输入项.5 输出项6 算法.7 流程逻辑8 用户界面8 接口.9 存储分配10 注释设计.11 限制条件.12 测试计划13 尚未解决的问题 七、数据工程 1.数据工程: 1)数据源:① 矢量地图数据;② 遥感影像数据(航空象片);③ 现状实测数据(验收数据);④ 统计调查数据;⑤ 档案数据(扫描件);⑥ 各种文字报告和立法文件等;⑦ 三维建模数据;⑧ 运行数据。 2)内容:如何组织各种来源的数据;如何评估已有的各种数据;如何处理已有数据;数据如何进库;数据如何更新。 2.代码设计: 1)原则:遵守相关标准、应具有可扩展性和一定的柔性、唯一性、系统化,能够满足整个系统要求、尽量短,减少存储空间,便于记忆和应用、逻辑性强,能直接反映实体的某些属性、采用不易引起误解的符号、同类代码应该等长 2)方法及其特点: 顺序编码: 方法:从1开始按顺序为实体编码 特点:简单实用、容易管理、不表示实体间的逻辑关系 分组编码: 方法:将实体对象分组,组内按顺序编码 特点:组内留有一定的备用代码、组间只能由代码的顺序号区别 分类编码: 方法:代码的不同位数表示不同的含义,将实体对象按类别进行编码。 特点:实体分类明确、代码记忆方便、有足够的扩展空间、 表意编码: 方法:利用实体原有属性直接编码 特点:直观、容易理解、处理不方便、 3.数据评价: 1)内容:数据的目前状态、数据的标准性、数据可用性、数据的原始性、数据的可替代性、数据的一致性 4.数据处理及入库: 1)内容:数据采集、数据分类、数据格式转换、坐标系统转换、数据分层组织、拓扑关系处理、属性数据添加、地图切片 2)方法:通过已有平台入库:要求数据满足一定的格式。通过应用系统维护模块入库:针对特定的数据格式开发。 八、工程实施: 1.系统实施:
8 1)任务:准备工作 、程序的编写与测试、系统的安装与培训、 2)流程:
2.程序设计风格: 1)概念: 程序设计风格指一个人编制程序时所表现出来的特点、习惯及逻辑思路等。 2)良好风格的表现: 源程序文档化(恰当的标识符、适当的注解和舒适的视觉组织)。
3.软件测试: 1)概念:软件测试是指对一个完成了全部或部分功能的计算机程序在正式使用前的检测,以确保该程序能按预定的方式正确地运行。 2)目标:以最少的时间和人力,系统地发现软件中潜藏的错误或缺陷,以便改正后把一个高质量的软件系统交给用户使用。 3)原则:应当把“尽早地和不断地进行软件测试”作为软件开发者的座右铭。测试用例应由测试输入数据和对应的预期输出结果这两部分组成。 程序员应避免检查自己的程序。在设计测试用例时,应包括合理的输入条件和不合理的输入条件。充分注意测试中的群集现象。严格执行测试计划,排除测试的随意性。应当对每一个测试结果做全面检查。妥善保存测试计划、测试用例、出错统计和最终分析报告、为维护提供方便。 测试应贯穿于软件定义与开发的整个期间。 4)过程:计划阶段:根据需求说明书,制定测试进度。设计阶段:依据程序设计说明书,按照一定规范化的方法进行软件结构划分和设计测试用例。执行阶段:输入测试用例,得到测试结果。总结阶段:对比测试的结果和代码的预期结果,分析错误原因,找到并解决错误。 4.单元测试: 1)概念:单元测试又称模块测试,是针对软件设计的最小单位 ─ 程序模块,进行正确性检验的测试工作。其目的在于发现各模块内部可能存在的各种差错。单元测试需要从程序的内部结构出发设计测试用例。多个模块可以平行地独立进行单元测试。 2)内容:模块接口;局部数据结构;重要的执行通路;出错处理;边界条件。 3)桩程序:被测模块所调用模块的模拟。作用是返回被测模块所需的信息。 4)驱动程序:被测模块的上级调用模块的模拟。其功能比上级调用模块简单得多,只完成接受测试数据,以上级模块调用被测模块的格式驱动被测模块,接受被测模块的测试结果并输出。 5.集成测试: 1)概念:集成测试又称组装测试或联合测试,是在单元测试的基础上,将所有模块按照设计要求组装成为系统后而进行的测试,以期发现在模块连接中可能出现的问题。 2)集成方式:一次性组装方式:先分别测试每个模块,再把所有模块按设计要求放在一起结合成所要的程序,这种方法称为非渐增式测试方法。 增殖式组装方式:把下一个要测试的模块同已经测试好的那些模块结合起来进行测试,测试完以后再把下一个应该测试的模块结合进来测试。这 9 种每次增加一个模块的方法称为渐增式测试,这种方法实际上同时完成单元测试和集成测试。 3)内容(关注点): 自顶向下集成:从主控制模块开始,沿着程序的控制层次向下移动,逐渐把各个模块结合起来。在把附属于(及最终附属于)主控制模块的那些模块组装到程序结构中去时,或者使用深度优先的策略,或者使用宽度优先的策略。 深度优先:先组装在软件结构的一条主控制通路上的所有模块。选择一条主控制通路取决于应用的特点,并且有很大任意性。 宽度优先:沿软件结构水平地移动,把处于同一个控制层次上的所有模块组装起来。
自底向上集成:从软件结构的最低层模块开始逐个组装和测试。
6.确认测试: 1)概念:确认测试又称有效性测试,也称为验收测试。它的目标是验证软件的有效性。 有效性:如果软件的功能和性能如同用户所合理期待的那样,软件就是有效的。 2)内容:功能测试:测试软件系统的功能是否正确,其依据是需求文档,如《产品需求规格说明书》。由于正确性是软件最重要的质量因素,所以功能测试必不可少。健壮性测试:测试软件系统在异常情况下能否正常运行的能力。健壮性有两层含义:一是容错能力,二是恢复能力。 7.基本概念: 1)Alpha测试:在开发者的指导下,用户在开发者的场所进行测试。开发者负责记录发现的错误和使用中遇到的问题。总之,Alpha测试是在受控的环境中进行的。 2)Beta测试:最终用户在开发者不能控制的环境中一个或多个客户场所进行测试。用户记录在测试过程中遇到的一切问题,并且定期把这些问题报告给开发者。接收到在Beta测试期间报告的问题之后,开发者对软件产品进行必要的修改,并最终向客户发布最终的软件产品。 3)静态测试:不运行被测程序本身,仅通过分析或检查源程序的语法、结构、过程、接口等来检查程序的正确性。静态测试主要包括代码检查、静态结构分析。 4)动态测试:设计测试用例,通过运行来检测程序的正确性。根据测试用例的设计方法不同,又分为两种测试方法,即黑盒测试和白盒测试。 5)白盒测试:也称结构测试或逻辑驱动测试,它是按照程序内部的结构测试程序,通过测试来检测产品内部动作是否按照设计规格说明书的规 10 三亿文库包含各类专业文献、文学作品欣赏、专业论文、高等教育、幼儿教育、小学教育、中学教育、生活休闲娱乐、外语学习资料、gis工程复习93等内容。 
 11页 免费 GIS复习 6页 2财富值如要投诉违规内容,请到百度文库投诉中心;如要提出功能问题或意见建议,请点击此处进行反馈。 GIS工程复习 隐藏&& 1. GIS 工程的...  3页 5财富值 GIS软件工程期末考试复习题... 暂无评价 6页 免费如要投诉违规内容,请到百度文库投诉中心;如要提出功能问题或意见建议,请点击此处进行反馈。 ...  GIS工程复习要点_理学_高等教育_教育专区。《GIS工程》复习要点 GIS 工程复习要点第一章 (无) 第二章 (1)OSI 网络分层模型与 DRAPA 分层模型的对应关系。 (2...  GIS软件工程复习_工学_高等教育_教育专区。一、名词解释 1、软件危机:落后的软件生产方式无法满足迅速增长的计算机软件需求,从而导致软件开发与维护过程中 出现一系列...  GIS 工程复习要点第二章 一.OSI 网络分层模型与 DRAPA 分层模型的对应关系。 二.常用协议所所述的层次 三.常用的组件技术 1.组件定义:现代软件的承载体,类比于...  《软件工程与GIS设计》复习资料_工学_高等教育_教育专区 暂无评价|0人阅读|0次下载|举报文档 《软件工程与GIS设计》复习资料_工学_高等教育_教育专区。《软件...  复习提纲 1. GIS 工程的定义及特点 2. GIS 应用模式有哪些?各有什么特点? 3. GIS 软件平台的类别、特点及发展趋势 4. GIS 工程设计的内容 5. 应用型 GIS...  GIS工程综合练习_工学_高等教育_教育专区。一、 练习范围 1. 教材的每章的书后练习. 2. 课堂的补充内容 二、 练习实例 1. 软件工程 答:软件工程是一个过程...javaWeb应用不同模块之间存在依赖关系时是依赖service还是依赖dao? - 知乎1被浏览54分享邀请回答还没有回答参考:http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/
参考:/questions//makefile-how-to-write-dependency-properly/13159
--------------------------------------------补充--------------------------------------------
隔了一段时间之后回过头来看这里提到的问题,其实很简单,我们先来看依赖关系
首先要明确的是,A.obj一定依赖于A.cpp和A.h,其他依赖就看A.cpp和A.h中的#include ""指令
SportsCar.obj:&SportsCar.cpp&SportsCar.h Car.h // 因为SportsCar.h中有#include "Car.h"
Car.obj: Car.cpp Car.h Engine.h // 因为Car.h中有#include "Engine.h"
Engine.obj: Engine.cpp Engine.h Gas.h // 因为Engine.cpp中有#include "Gas.h"
Gas.obj: Gas.cpp Gas.h
我最开始比较疑惑的就是既然SportsCar.h有#include "Car.h",那么不相当于SportsCar.h中也有#include "Engine.h"了么,为什么SportsCar.obj不依赖于Engine.h呢?也就是说,如果Engine.h更新了(比如说添加了一些代码或者删除了一些代码),SportsCar.obj会更新吗?换句话说,这样的间接依赖,我们需要写到Makefile中吗?
对于问题&SportsCar.obj会更新吗&,答案是:不会(其实你做个实验试试修改一下Engine.h就知道了),仔细看依赖关系,如果Engine.h有更新,那么make程序检测到Engine.h更新之后会重新生成Engine.obj、Car.obj,但是由于SportsCar.obj并不依赖于Engine.h,所以SportsCar.obj不会重新生成
对于问题&这样的间接依赖,我们需要写到Makefile中吗&,答案是:如果你确定是&间接依赖&而不是&直接依赖&,那就不用写到Makefile中,如果是直接依赖,那就必须写到Makefile中。
好,首先先确定什么是间接依赖和直接依赖:一句话,模块A的代码使用了模块B的API,那么模块A就直接依赖于模块B,如果模块B的代码使用了模块C的API,那么模块A就间接依赖于模块C(间接依赖是不用写到Makefile中的)。
这里需要一点定义:什么叫模块A使用了模块B的API?我姑且举几个例子:A中使用了B(以及B的组成部分,对于C++中的class而言,B的组成部分包括B的Class name、Member function name以及Member data name以及在B中定义的constant names、Member class names及Member class的组成部分)的名字的地方,都叫A使用了B的API。
比如:Car直接依赖于Engine,因为Car调用了Engine的API(Car.h在line 9使用了Engine这个名字,Car.cpp在line 10使用了consumeGas()这个member function),但是Car是间接依赖于Gas,因为Car.cpp和Car.h中都没有出现Gas的API,所以在Makefile中,Car.obj只依赖于Engine.h而不依赖于Gas.h
再比如:SportsCar直接依赖于Car,但是SportsCar是间接依赖于Engine,因为SportsCar.cpp和SportsCar.h中没有出现Engine的API,所以在Makefile中SportsCar.obj只依赖于Car.h而不依赖于Engine.h
好现在我们对代码做一些改动,首先给Engine添加一个member function(注意同时修改Engine.h和Engine.cpp):
void Engine::doSomething()
cout && "Engine do something" &&
然后在SportsCar.cpp中修改drive(),如下:
void SportsCar::drive()
cout && "SportsCar drive" &&
Car::drive();
engine.doSomething();
然后重新nmake这个程序并运行,得到如下结果:
然后删除Engine的doSomething(),同时更新Engine.h和Engine.cpp,重新nmake这个程序,你会发现SportsCar.obj没有被更新(原因很简单,Makefile中SportsCar.obj不依赖于Engine.h,所以make程序不会去更新SportsCar.obj),并且在链接的时候报错undefined reference to Engine::doSomething
问题在哪儿?对,因为修改SportsCar::drive()之后,SportsCar已经直接依赖Engine了,原因就是SportsCar::drive()中出现了Engine::doSomething(),根据我们前面说的,其实就是SportsCar中使用了Engine的API,从而SportsCar从间接依赖Engine变为了直接依赖Engine,所以这时候就必须在Makefile中令SportsCar.obj依赖于Engine.h,并且(我建议)在SportsCar.cpp中写上#include "Engine.h"(尽管你不写也没关系,但是我建议还是写上,为了依赖关系看起来更明显)。
这个问题还算好的,好歹linker还给了一个报错让你知道出了问题。像之前提到的那个问题(&说明&的第5条)本质上跟这个一样,但是那个问题,无论linker还是compiler都不会报错,而你最后就莫名其妙的得到了一个错误的程序逻辑和错误的运行结果。可见在Makefile中正确的写上依赖关系的重要性。
好,现在可以得出一个结论了:
如果模块A的代码中出现了模块B的API,那么我们说模块A直接依赖于模块B。
如果A不直接依赖于模块C,但是模块B直接依赖于模块C,那么我们说模块A间接依赖于模块C。
如果模块A直接依赖于模块B,那么在出现模块B的API的文件中一定要有#include "B.h"指令,不要利用间接#include的特性。(有一个例外,那就是你在设计一个C++的class X的时候,一般是把声明放在X.h中,把实现放在X.cpp中,那么这里的建议是:X.cpp只有一条#include指令,也就是#include "X.h",其他所有的#include指令都放到X.h中,这样可以便于写Makefile的时候查看各个模块的依赖关系。这里有个demo可以参考,比较典型:)
在Makefile中A.obj依赖于B.h当且仅当模块A直接依赖于模块B
--------------------------------------------之前--------------------------------------------
如果A.cpp包含了A.h,E.h,F.h,而A.h又包含了B.h、C.h,那么在Makefile中,A.obj就依赖于A.cpp, A.h, E.h, F.h, B.h, C.h,如果你发现某个文件(比如X.h)更新了,但是在rebuild project的时候与其相关联的文件(比如Y.cpp)没有被recompile,那么你就要好好检查是不是Makefile中Y.obj没有关联X.h,否则就可能导致下面类似的逻辑错误(而且很难debug)
事实上,A.obj依赖于XXX.h的充要条件是:A.cpp直接或者间接包含了XXX.h,并且A.cpp中有代码使用了XXX.h中声明的东西,并且XXX.h在你开发的过程中可能被修改(也就是说用#include ""指令包含的文件,因为一般#include &&都用于那些库的头,而库的头在你开发的过程中一般是不会被修改的)。但是你在实际写Makefile的时候,你很难无遗漏地判断A.cpp中是否有代码使用了XXX.h中声明的东西,尤其是当代码量很大,工程很复杂的时候,这更难办到。所以最保险的办法就是:检查A.cpp和A.h中的#include ""指令,然后在Makefile中令A.obj依赖于所有这些指令包含的头文件,并且做到,如果你要使用一个头文件中声明的内容,就直接包含这个头文件,而不要利用间接包含这个特性,避免你漏掉某个依赖关系,从而给你写Makefile打下一个良好的基础。
------------------------------------------------------
我一直以为,如果一个A.cpp文件中有多少条 #include "xxx.h"指令,在写Makefile的时候A.obj的依赖项除了A.cpp之外,就是A.cpp之内所有的 xxx.h
比如,如果A.cpp中有 #include "A.h" #include "B.h" #include "C.h",那么在Makefile中就有:A.obj: A.cpp A.h B.h C.h
下面的例子是说明了,上面的想法是错误的
环境:Windows + Microsoft Visual Studio NMAKE.exe\CL.exe\LINK.exe
文件组织(加粗字体的是文件夹):
  testproject
    src
    include
    Makefile
src中包含文件:Car.cpp,&SportsCar.cpp, Engine.cpp, Gas.cpp, main.cpp
include中包含文件:Car.h, SportsCar.h, Engine.h, Gas.h
概要:Car有一个Engine,SportsCar是Car的子类,Car.drive()调用Engine.consumeGas(),Engine.consumeGas()调用Gas.burn(),SportsCar.drive()重写了Car.drive()
  通过下面的代码,在Makefile的第29行可以看到,SportsCar.obj只依赖于SportsCar.cpp和SportsCar.h,因为SportsCar.cpp只有一条#include "SportsCar.h"的指令
  但是,你可以尝试下面的步骤,就会发现问题所在
  1、打开VS2013 开发人员命令提示,切换到,testproject的根目录,执行nmake,生成bin\test.exe
  2、输入bin\test.exe,可以看到输出结果如下
  3、删除Car.h的第8、9行,删除Car.cpp的第10行,保存
  4、再次输入nmake,生成新的bin\test.exe,可以看到,Car.obj和main.obj被重新生成了,因为这2者都依赖于Car.h,其中Car.obj还依赖于Car.cpp,并且链接
    也没有问题。输入bin\test.exe可以看到结果如下
  5、发现奇怪的地方没?没发现?好吧。
    首先,第3步修改了Car.h之后,其实很显然,按C++的语义来讲,SportsCar.cpp第10行已经是错误的了,Car都没有了Engine,作为Car的子类,SportsCar从哪儿来的Engine?(注意SportsCar.h中并没有定义Engine)。但是由于Makefile中并没有写上SportsCar.obj依赖于Car.h的关系,所以SportsCar.cpp就没有被重新编译,SportsCar.obj也没有被重新生成。这时候SportsCar.obj已经是陈旧的了。
    其次,既然SportsCar.obj已经是陈旧的了,不符合C++的语义了。为什么在第3步之后,还能链接生成bin\test.exe?原因很简单,链接的时候SportsCar.obj对Engine.obj的链接仍然是合法的,因为Engine.consumeGas()仍然存在。另外,SportsCar.obj对Car.obj的链接也是合法的,因为Car的constructor和destructor都没有变,链接的时候,linker主要要检查的就是SportsCar.obj对Car.obj中方法的调用,也就是对Car的constructor和destructor的调用,因为在生成和销毁SportsCar对象的时候会用到这两者,显然,Car的constructor和destructor都存在,所以linker认为这是没有问题的,继而生成了bin\test.exe。
    所以就造成了上面奇怪的运行结果:Car都没有了Engine,作为Car的子类,SportsCar&平白无故&地有了一个Engine(注意SportsCar.h中并没有定义Engine)
  6、结论:如果A.cpp包含了X.h,X.h又包含了Y.h,Y.h又包含了Z.h,那么在写Makefile的时候,A.obj依赖的对象不仅有A.cpp, X.h,而且还有Y.h和Z.h(当然,对于库的头文件就不用写进Makefile了,这里说的头文件都是你自己在开发的时候写的头文件,也就是用#include ""指令包含的头文件。除非你有必要去修改库的头文件,才需要把库的头文件依赖也放进你的Makefile里)
&  实际上,一般来讲,假设A.cpp包含了B.h,那么很可能A.cpp中会直接用到B这个类的某些function,比如说,在A中可能有诸如B.xxx()的调用,如果B.h包含了比如说X.h,但是A.cpp中没有代码直接用到了X,从而X.h的修改并不会导致A.cpp中的语义出错(因为A中没有代码直接对X进行使用,试想,如果SportsCar.cpp中没有直接使用Engine.consumeGas(),还会出现第5步中的情况么?就不会了!也就是说,如果A.cpp通过B.h间接包含了一个头文件X.h,但是在A.cpp中没有直接使用X.h中的内容,那么对X.h的修改就不会对A.cpp产生影响,A.cpp也不用重新编译。但是对X.h的修改会对那些直接使用了X.h中内容的文件产生影响(比如说B.cpp如果有代码直接使用了X.h中的内容,那么X.h的修改就会导致B.cpp的重新编译,这个我们显然是要在Makefile中写上B.obj依赖于X.h的,所以是没有问题的)。),那么实际上Makefile中也不一定非要让A.obj依赖于X.h。
  所以,上面的结论,准确来讲应该是:如果A.cpp包含了X.h,X.h又包含了Y.h,Y.h又包含了Z.h,并且A中的代码不仅对X进行了直接的使用,而且还对Y, Z进行了直接的使用,那么在写Makefile的时候,A.obj依赖的对象不仅有A.cpp, X.h,而且还有Y.h和Z.h。
  当然,如果你为了以防万一也不嫌麻烦的话,还是按照第6步给出的方法写Makefile吧
  我去stackoverflow问了一下,见
  大概是说msbuild可以解决这个问题,gcc也有-MM选项可以自动生成Makefile中的dependency,但是CL貌似没有这个功能
  我的想法是,一般来说还是按照,A.cpp以及A.h中有几个#include "",A.obj就有几个依赖关系,也就是说,A.cpp有几个#include "",在Makefile中A.obj就依赖这几个header,如果出现步骤5所述的问题的时候,才按上面所说的思路去查找Makefile的错误。
  这也是为什么Makefile中第26行,Car.obj依赖于Engine.h的原因
# compiler
LINK = link
# libraries
HEADER_PATH = /I include
EHSC = /EHsc
COMPILATION_ONLY = /c
C_OUT = /Fo:
L_OUT = /OUT:
# compiler & linker debug option, to disable debug, replace '/Zi' & '/DEBUG' with empty strings
C_DEBUG = /Zi
L_DEBUG = /DEBUG
# C_DEBUG =
# L_DEBUG =
bin\test.exe: bin obj obj\main.obj obj\Car.obj obj\SportsCar.obj obj\Engine.obj obj\Gas.obj
$(LINK) $(L_DEBUG) $(L_OUT)bin\test.exe obj\main.obj obj\Car.obj obj\SportsCar.obj obj\Engine.obj obj\Gas.obj
obj\main.obj: src\main.cpp include\Car.h include\SportsCar.h
$(CC) $(C_DEBUG) $(EHSC) $(HEADER_PATH) $(COMPILATION_ONLY) src\main.cpp $(C_OUT)obj\main.obj
obj\Car.obj: src\Car.cpp include\Car.h include\Engine.h
$(CC) $(C_DEBUG) $(EHSC) $(HEADER_PATH) $(COMPILATION_ONLY) src\Car.cpp $(C_OUT)obj\Car.obj
obj\SportsCar.obj: src\SportsCar.cpp include\SportsCar.h
$(CC) $(C_DEBUG) $(EHSC) $(HEADER_PATH) $(COMPILATION_ONLY) src\SportsCar.cpp $(C_OUT)obj\SportsCar.obj
obj\Engine.obj: src\Engine.cpp include\Engine.h include\Gas.h
$(CC) $(C_DEBUG) $(EHSC) $(HEADER_PATH) $(COMPILATION_ONLY) src\Engine.cpp $(C_OUT)obj\Engine.obj
obj\Gas.obj: src\Gas.cpp include\Gas.h
$(CC) $(C_DEBUG) $(EHSC) $(HEADER_PATH) $(COMPILATION_ONLY) src\Gas.cpp $(C_OUT)obj\Gas.obj
.PHONY: clean
-rmdir /s /q bin
-rmdir /s /q obj
-del *.pdb
1 #include "SportsCar.h"
2 #include "Car.h"
3 #include &iostream&
5 using namespace
7 int main()
Car *car = new Car();
car-&drive();
car = new SportsCar();
car-&drive();
1 #ifndef CAR_H
2 #define CAR_H
4 #include "Engine.h"
6 class Car
8 protected:
10 public:
virtual void drive();
virtual ~Car();
15 #endif // CAR_H
1 #include "Car.h"
3 #include &iostream&
5 using namespace
7 void Car::drive()
cout && "Car drive" &&
engine.consumeGas();
13 Car::~Car()
// do nothing
SportsCar.h
1 #ifndef SPORTSCAR_H
2 #define SPORTSCAR_H
4 #include "Car.h"
6 class SportsCar : public Car
void drive();
13 #endif // SPORTSCAR_H
SportsCar.cpp
1 #include "SportsCar.h"
3 #include &iostream&
5 using namespace
7 void SportsCar::drive()
cout && "SportsCar drive" &&
Car::drive();
1 #ifndef ENGINE_H
2 #define ENGINE_H
4 class Engine
void consumeGas();
11 #endif // ENGINE_H
Engine.cpp
1 #include "Engine.h"
2 #include "Gas.h"
4 #include &iostream&
6 using namespace
8 void Engine::consumeGas()
cout && "Engine consuming gas" &&
1 #ifndef GAS_H
2 #define GAS_H
4 class Gas
void burn();
11 #endif // GAS_H
1 #include "Gas.h"
3 #include &iostream&
5 using namespace
7 void Gas::burn()
cout && "Gas burning" &&
阅读(...) 评论()

我要回帖

更多关于 maven 模块依赖找不到 的文章

 

随机推荐