一、背景
在 VS 的项目属性里,常见几处看似相似的配置项:
VC++ 目录:包含目录、库目录
C/C++:附加包含目录
链接器:附加库目录、附加依赖项
我在配置 OpenCV 时,尝试两种方案:
只在 VC++ 目录里配置包含目录和库目录,再在链接器中配置附加依赖项,程序可以运行。
改为在 C/C++ 里配置“附加包含目录”、在“链接器”里配置“附加库目录 + 附加依赖项”,同样可以运行。
这两种都能成功,但它们的语义、作用范围与维护性并不相同。本文讲清楚它们的区别,并给出推荐做法。
二、各配置项的作用与区别
1. VC++ 目录
本质
这页的“包含目录/库目录”是在修改一组 MSBuild 宏:$(IncludePath)、$(LibraryPath)、$(ExecutablePath) 等。等于给编译器/链接器提供“默认的搜索路径”。
层级与“全局可见”
这些宏可以在多个层级被定义或叠加:工具集、Windows SDK、用户级属性表、项目/共享属性表。
构建时,会使用最终合成的宏值:编译器从 IncludePath 里找头文件,链接器从 LibraryPath 里找库。
为什么说“可见性差”
改动常发生在用户级属性表或环境变量,不写进项目文件,代码仓库里看不见,团队不易感知。
属性页里显示的是宏名而非最终路径;要知道真正生效的路径,需要展开宏并追踪多层继承,排查成本高。
对应关系(直观记忆)
VC++ 目录 → 包含目录:叠加到 $(IncludePath) → 默认头文件搜索路径(对应编译器的 INCLUDE)
VC++ 目录 → 库目录:叠加到 $(LibraryPath) → 默认库搜索路径(对应链接器的 LIB)
VC++ 目录 → 可执行文件目录:叠加到 $(ExecutablePath) → VS 查找编译工具的路径
2. C/C++ → 附加包含目录
作用:告诉编译器“本项目额外到哪些目录找头文件”。
只影响编译阶段,不处理库或符号实现。
3. 链接器 → 附加库目录
作用:告诉链接器“到哪些目录去找 .lib 文件”。
只是路径,不等于已经链接某个库。
4. 链接器 → 附加依赖项
作用:列出“要链接的具体库文件名”,例如 opencv_world4xx.lib 或分模块库名。
链接器会到“附加库目录”(以及默认库路径)里寻找这些文件并装入。
与“附加库目录”的区别:一个是“去哪找”,一个是“找哪些”。
三、为什么两种配置都能跑
先看构建的三个阶段:编译(找头文件)→ 链接(找库并装入实现)→ 运行(找 DLL)。
1. 方案 A(在 VC++ 目录里配包含/库目录,在“链接器→附加依赖项”里列出库名)
编译阶段:编译器通过“默认的头文件搜索路径集合”找到 OpenCV 的头文件。
链接阶段:链接器通过“默认的库文件搜索路径集合”找到 .lib;再根据“附加依赖项”里列出的库名,把这些库装入最终程序。
这里的“默认集合”来自你在 VC++ 目录里对包含目录/库目录的设置。
2. 方案 B(在 C/C++ 里配“附加包含目录”,在“链接器”里配“附加库目录 + 附加依赖项”)
编译阶段:为当前项目明确添加“额外的头文件搜索路径”,让编译器能找到 OpenCV 的头文件。
链接阶段:为当前项目明确添加“额外的库文件搜索路径”,并给出“需要链接的库清单”,让链接器把相应库装入最终程序。
这些设置直接体现在本项目的配置里,可一目了然地看到“去哪找”和“找哪些”。
3. 结论
两种方案都会让编译器找到头文件、让链接器找到并装入需要的库,因此都能跑。
但方案 B 更推荐:配置更直观(清楚区分头文件路径、库路径、库清单)、作用范围更可控(只影响当前项目/当前配置)、迁移与协作更省心(项目文件或共享属性表里一眼能看到并随仓库提交)。
四、总结
编译看“附加包含目录”(找头文件)
链接看“附加库目录 + 附加依赖项”(去哪找库 + 找哪些库)
运行看“DLL 是否在 PATH 或 exe 同目录”
VC++ 目录是“默认路径宏”的旧式入口,能用但不推荐作为日常放第三方库的地方。将配置放在 C/C++ 与 链接器页面,更清晰、更稳、更易迁移。