vs2017 项目开发 解决方案下的多个项目

写在前面:本文仅对vs的项目开发做一个简单的整理,只求可以使用,不深入探讨内部机制。如果想要深入了解,可以查看下文给出的博客连接。
最后一个章节,“一个规范的工程目录”,记录了创建一个多项目工程的完整操作。

vs的文件夹路径

参考博客VS2017的C++开发心得(四)VS的文件夹路径以及项目生成步骤
一个vs解决方案下,可以有多个项目。总会有一个同名项目。例如,下图中,解决方案SolutionTest下,目前只有一个项目SolutionTest。
解决方案资源管理器

一个vs解决方案下有以下若干文件夹/文件夹:

  1. 解决方案文件,名为 [解决方案名称].sln,双击即可打开该解决方案。
  2. 项目文件夹。一个解决方案下可以有多个项目,每个项目有一个对应文件夹。解决方案目录下总会有一个同名项目。包含属于该项目的源码 .h,.cpp等文件。包含项目相关的配置文件*.vcxproj等。包含对应的编译的生成结果,*.obj文件,在其中对应的Debug或者Release目录下。
  3. Debug文件夹,生成时选择Debug x86则会生成这个文件夹。生成对应的exe文件。
  4. Release文件夹,生成时选择Release x86则会生成这个文件夹生成对应的exe文件。
  5. x64文件夹。里面可以有Debug、Release两个子文件夹,同样是生成时选择Debug x64,或者Release x64 则会生成对应的文件夹。生成对应的exe文件。
  6. .vs文件夹,暂时无需关心
    解决方案文件夹

参考C++编译与链接(1)-编译与链接过程
vs的项目生成大致分为三步:预处理、编译、链接和生成
一 、预处理
C++的预处理是指在C++程序源代码被编译之前,由预处理器对C++程序源代码进行的处理。这个过程并不对程序的源代码进行解析。
这里的预处理器(preprocessor)是指真正的编译开始之前由编译器调用的一个独立程序。
预处理器主要负责以下几处

  1. 宏的替换
  2. 删除注释
  3. 处理预处理指令,如#include头文件的展开,#ifdef

二、编译
当点击vs菜单的 生成-编译,或者ctrl+f7后,则会对当前单个文件进行编译操作。当生成解决方案时,vs会先对每个cpp进行编译。
编译时,首先对单个源码文本文件进行语法检查有没有语法错误-error 或者警告-warning。写代码时,编译器给出的标红也就是这种情况。
vs把每个cpp生成一个对应的.obj文件,默认放在每个项目(注意,是项目而非解决方案)目录下的,对应的debug或者release文件夹下。
这里借用上文VS2017的C++开发心得(四)VS的文件夹路径以及项目生成步骤中的一张图
在这里插入图片描述
三、链接和生成
可以理解为,以main函数所在的cpp文件为入口,进行搜索,将相关的*.obj文件链接成可执行文件*.exe,存储在解决方案文件夹下的相关文件夹中(如Debug)。多个.obj文件下有同名变量的问题,则会在这一步暴露出来。

vs的路径宏

仍然参考VS2017的C++开发心得(四)VS的文件夹路径以及项目生成步骤
路径宏很大的作用是可以根据你的配置名去选择不同的文件夹下面的资源。而且重要的是,可以选择相对路径而非绝对路径,从而便于整个项目进行迁移。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
常用到的宏,有$(SolutionDir)解决方案目录,和$(Configuration) Debug或Release

头文件的路径

主要参考VS2017的C++开发心得(六)头文件的路径问题与属性管理器
当引用头文件时,有两种写法

#include <iostream>
#include "iostream"

两种写法都是合法的,不同之处在于,两种写法优先从不同的路径搜索"iostream"这个文件。
包含目录
项目右键-属性管理器-VC++目录-包含目录,这儿就是使用#include<>`时的默认搜索路径。

对于#include ""这种写法,其默认搜索路径则是在对应的同一个项目文件夹下。

多项目开发

主要参考[VS2017的C++开发心得(九)DLL动态链接——多项目开发(https://blog.csdn.net/luoyu510183/article/details/83999548)
多项目开发的主旨是尽可能的实现代码的模块化,减少对其它项目的依赖性,最好能够独立实现它设计的功能。
例如,要开发一个Windows窗体程序,实现医学影像数据的采集、处理和显示,那么,可以在解决方案下创建三个项目。一个项目用于,连接医疗影像设备,采集图像数据;一个项目是图像处理操作;还有一个项目用于窗体的UI。这样将几类功能鲜明地分割开,减少项目之间的耦合性,也更容易实现代码复用。

多项目的创建

在原来的解决方案里,添加一个新C++项目Project2。
在这里插入图片描述
右键解决方案,添加》新建项目》空项目,在Project2的项目属性中把配置类型改成动态库
在这里插入图片描述
解决方案下多项目
如上图所示,现在解决方案SolutionTest下,有两个项目。SolutionTest项目处于高亮状态,这是它作为启动项目的标识。为了了解启动项目,可以查看解决方案属性页:
解决方案属性页
单启动项目:
按f5,或者按ctrl+f10的时候调用的项目。
多个启动项目:
适用于多进程间(不是多线程间)的调试,即多个exe之间的通信调试。一般开发很少见,服务器程序比较常用,一个ex用于监听网络请求,一个exe发送请求。此处不做深究。

要注意的是,调试的时候只会生成启动项目,也就是项目SolutionTest,Project2是默认不生成的。生成-生成解决方案,这种方法固然会生成所有项目,但是vs进行生成的顺序,是按照项目添加的先后顺序的。为了保证SolutionTest调用的Project2项目是最新的,需要手动设置项目的生成顺序。

同样是在解决方案属性页里,添加项目依赖项即可:
输出目录 宏

设定项目SolutionTest依赖于项目Project2,则Project2会先于SolutionTest生成。生成顺序错误的话,可能会导致无法找到xx.lib的错误,因为需要用到的lib并没有在这个项目之前生成出来。
项目之间的循环依赖 如a依赖b,b依赖c,c依赖a,是不被允许的,vs中也无法进行这种设置。

解决方案的生成

在Project2当中,新建了一个类DataProcessor,用于数据处理。
将Project2设置为配置类型 动态库(.dll),上文已经提到过。

写完以后,这个DataProcessor类只能在当前项目Project2中被其他cpp文件引用,还少了一步把函数接口导出到dll的导出列表里面。导出到dll的导出列表以后,别的项目才能根据函数名去dll中找到这个函数的位置。这一步的操作就要介绍下如何利用宏定义来完成DLL的函数导出和导入切换:

首先给Project2加上一个预处理器定义,也就是一个编译前的宏定义PROJECT2(宏定义全部大写)
在这里插入图片描述
然后修改DataProcessor类的代码如下

//DataProcessor.h
#pragma once
#ifdef PROJECT2
#define PROCESS_API _declspec(dllexport)
#else
#define PROCESS_API _declspec(dllimport)
#endif

class PROCESS_API DataProcessor
{
public:
	double ProcessDouble(double d);
private:
};
//DataProcessor.cpp
#include "DataProcessor.h"

double DataProcessor::ProcessDouble(double d)
{
	return d * 2;
}

现在解释下为什么要在Project2里加上一个PROJECT2的项目标识宏定义。首先,dll的导出和导入的关键字区分在于__declspec()的括号里面是dllexport(导出)还是dllimport(导入)。在本项目中我需要告诉VS这个函数是导出的,在其他项目中需要告诉VS这个函数是从别的dll里面导入的。但是不管哪个项目,使用的都是DataProcessor.h这个头文件,这时宏定义作为编译开关的作用就体现出来了。

在Project2的项目生成中,由于我们定义了PROJECT2的宏定义,所以CRYPT_API是被定义为__declspec(dllexport)。在SolutionTest项目中引用头文件DataProcessor.h时,SolutionTest中并没有定义PROJECT2的宏定义,所以CRYPT_API被定义为__declspec(dllimport)。这样就做到了同一份header不同的声明。

在此之后,需要在SolutionTest项目中配置Project2的头文件路径和lib路径。
首先,SolutionTest项目右键——属性——C/C++——常规——附加包含目录,添加头文件所在的路径,这里我用宏 $(SolutionDIr),指定到了解决方案目录
在这里插入图片描述
也就是这个位置:
在这里插入图片描述
然后要设置lib文件的路径。因为生成时选择64位 x64,所以生成的.lib文件会出现在解决方案目录下的x64\Debug,或者x64\Release下。
SolutionTest项目右键——属性——链接器——常规——附加库目录,设置lib文件所在的路径,同样用到了宏$(SolutionDir)x64$(Configuration)
在这里插入图片描述
此后,还要告诉vs,SolutionTest这个项目用到了哪些库 .lib,SolutionTest项目右键——属性——链接器——输入——附加依赖项,这里添加Project2.lib即可
在这里插入图片描述
在main.cpp中测试一下,运行成功

//main.cpp
#include "Project2/DataProcessor.h"

int main()
{
	double d1, d2;
	DataProcessor p;
	d1 = 1;	
	d2 = p.ProcessDouble(d1);	//d2=2
	return 0;
}

最终的解决方案资源管理器界面:
在这里插入图片描述
解决方案文件夹:
在这里插入图片描述
在这里插入图片描述

一种规范的工程目录

注意:在vs的解决方案资源管理器界面,是解决方案的逻辑层级,不代表具体存储在硬盘中的物理位置

解决方案的创建

首先 创建一个SolutionTest2解决方案,如下图所示:
在这里插入图片描述
创建完成后,解决方案文件夹如下图:
在这里插入图片描述

用多个文件夹进行管理

为了便于代码维护,在服务器上存储,所以在解决方案目录下新建几个文件夹Include,Int,Lib,Output,Source,分别用来存储头文件、.obj文件,.lib文件,exe和dll文件,以及.cpp文件。

将项目重新添加至解决方案

在文件资源管理器中,将原来的SolutionTest2文件夹拖到Source目录下。为了在vs中更新这个项目的信息,所以,先在解决方案资源管理器中1.项目SolutionTest右键-移除;2 解决方案SolutionTest右键-添加-现有项目,选择刚才迁移到硬盘中的文件SolutionTest2.vcxproj。如下图:
在这里插入图片描述
最终解决方案目录如下图所示:
在这里插入图片描述
为此项目添加main.cpp。默认路径已经改成了解决方案文件夹\Source\SolutionTest,直接添加即可,如下图所示:
在这里插入图片描述

添加新的项目

在vs里新建一个项目DataProcessor。解决方案"SolutionTest"右键-添加-新建项目,路径选择解决方案目录下的source文件夹,如下图所示:
在这里插入图片描述
如上文提到的,DataProcessor项目右键-属性-配置属性-常规-配置类型-选择动态库(.dll)
添加一个类NumProcessor。项目DataProcessor右键-添加-新建项-头文件,目录选择include文件夹下的DataProcessor项目文件夹(如果没有,就自己创建),如下图所示:
在这里插入图片描述
类似的,添加NumProcess.cpp文件,在Source文件夹下的DataProceeor项目文件夹下

设置项目依赖关系

SolutionTest是main函数的入口,将会依赖于其他项目。
解决方案"SolutionTest"右键-属性-启动项目-选择单启动项目SolutionTest2
解决方案"SolutionTest"右键-属性-项目依赖项-选择项目SolutionTest2-勾选依赖于DataProcessor

设置目标文件名

规范起见,分别对于Debug模式下的每一个项目,设置:项目右键-属性-常规-目标文件名,设置宏 ( P r o j e c t N a m e ) D 对 于 R e l e a s e 模 式 , 默 认 的 已 经 是 (ProjectName)D 对于Release模式,默认的已经是 (ProjectName)DRelease(ProjectName),所以不作修改
在这里插入图片描述

include

Include文件夹。它的下级目录为各个项目的名字。每个项目文件夹存放对应项目的头文件。
要为每个项目指定这个头文件的目录。举个例子:项目SolutionTest2右键-属性-C/C+±附加包含目录,在此处添加路径 用宏来表示:$(SolutionDir)Include\。对于现有的两个项目,要分别进行这个操作。在Debug和Release模式下,也要分别设置一次(以64位 x64为例)。以下各个目录的设置同理,也需要这样分别设置
在这里插入图片描述

int

Int文件夹,intermedia,中间过程,存储
.obj格式的目标文件等。文件夹的组织形式位,int文件夹下有debug,release两个文件夹,每一个目录又下辖以各个项目名命名的子文件夹。类似的,对于每个项目,分别对于Debug/Release,设置 项目右键-属性-常规-中间目录,添加宏 $(SolutionDir)Int\$(Configuration)\$(ProjectName)\

lib

lib文件夹,存储.lib、.exp文件。
如下图所示,分为Commonlib通用库,Debug模式下的lib,Release模式下的lib三个子文件夹:
在这里插入图片描述

类似的,对于每个项目,分别对于Debug/Release,设置 项目右键-属性-链接器-高级-导入库,设置宏 $(SolutionDir)lib\$(Configuration)\$(TargetName).lib
在这里插入图片描述

source

Source文件夹,各个项目所在的位置。新建项目时也要选择位置在这个文件夹。
在这里插入图片描述

output

Output文件夹,存储最终生成的.exe,.dll,.pdb,.itk文件。
由于此项目只考虑x64,所以Output文件夹下仅有x64一个文件夹,x64下有Debug,Release两个文件夹
在这里插入图片描述
类似的,对于每个项目,分别对于Debug/Release,设置 项目右键-属性-常规-输出目录,设置宏 $(SolutionDir)Output\$(Platform)\$(Configuration)\
在这里插入图片描述

预处理器定义

对于除了启动项目之外的每个项目,对于本项目来说也就是DataProcessor项目。分别对于Debug/Release,设置 项目右键-属性-C/C+±预处理器,添加预处理器定义 为[大写项目名称]_EXPORT,如下图
在这里插入图片描述
然后在对应项目的头文件中,添加如下代码,从而使得其对于本项目来说是导出(dllexport),对于其他项目来说是导入(dllimport)

#ifdef DATAPROCESSOR_EXPORT
#define DATAPROCESSOR_API _declspec(dllexport)
#else
#define DATAPROCESSOR_API _declspec(dllimport)
#endif

为启动项目设置库

需要为启动项目设置库(lib)目录。
对于启动项目,也就是本工程中的SolutionTest2,分别对于Debug,Release,设置 项目右键-属性-链接器-常规-附加库目录,添加宏 $(SolutionDir)lib\$(Configuration)\,和$(SolutionDir)lib\Commonlib\,如下图:
在这里插入图片描述
还要告诉vs,SolutionTest2这个项目用到了哪些库 .lib。分别对于Debug,Release模式,设置:SolutionTest2项目右键——属性——链接器——输入——附加依赖项,添加对应的DataProcessorD.lib(Debug模式下)或者DataProcessor.lib(Release模式下),如下图:
在这里插入图片描述

完整代码

#pragma once
//DataProcessor.h
#pragma once
#ifdef DATAPROCESSOR_EXPORT
#define DATAPROCESSOR_API _declspec(dllexport)
#else
#define DATAPROCESSOR_API _declspec(dllimport)
#endif

namespace DATAPROCESSOR	//每个项目内,类、变量、函数的声明,都用命名空间包含起来,避免重名
{
	class DATAPROCESSOR_API NumProcessor
	{
	public:
		double ProcessDouble(double d);
	private:
	};
}
//DataProcessor.cpp
#include "DataProcessor/NumProcessor.h"

using namespace DATAPROCESSOR;	//注意 使用本项目的命名空间

double NumProcessor::ProcessDouble(double d)
{
	return d * 2;
}
//main.cpp
#include "DataProcessor/NumProcessor.h"
using namespace DATAPROCESSOR;

int main()
{
	double d1, d2;
	NumProcessor np;
	d1 = 1;
	d2 = np.ProcessDouble(d1);	//d2=2
	return 0;
}

经测试运行通过,代码见百度云:
链接:https://pan.baidu.com/s/1IWPIAB6qjMMRrX0NMsSVNw
提取码:nzf2

03-20
<think>嗯,用户想了解Visual Studio 2017的下载和使用介绍。首先,我需要整理现有的引用资料。根据引用[1],VS2017支持多种语言,比如C#、C++、Python等,安装过程需要下载Visual Studio Installer。引用[3]提到首次安装要确保运行Hello World成功,所以安装后的验证步骤很重要。引用[4]指出社区版是免费的,适合个人开发者,用户需要选择正确的版本。 接下来,用户可能需要详细的步骤指导。应该分下载和安装两部分。下载部分要说明访问官网或通过Gitee下载,选择Community 2017版本。安装时注意勾选所需的工作负载,比如.NET桌面开发C++,这会影响功能是否可用。安装后的创建项目步骤,引用[1]和[4]都提到了创建项目和文件结构,可能需要解释命名空间和快捷键的使用。 用户可能遇到的问题,比如安装失败或项目无法运行,需要给出解决方案,如检查系统要求或重新安装组件。另外,相关问题的生成要考虑用户可能进一步的需求,比如版本区别、C++环境配置和扩展插件推荐。需要确保所有信息准确,引用正确的来源,比如引用[2]提到支持的语言,引用[4]的下载步骤。 最后,回答要结构清晰,分步骤说明,确保用户能一步步跟着操作。同时,语言要简洁,避免技术术语过多,让新手也能理解。检查是否有遗漏的信息,比如系统要求或常见问题,确保覆盖用户可能的所有疑问。</think>### Visual Studio 2017 下载及使用介绍 #### 1. **下载步骤** - **官方下载**: 访问 [Visual Studio 官网](https://visualstudio.microsoft.com/zh-hans/vs/older-downloads/),选择 **Community 2017** 版本(免费使用)[^4]。 - 若官网无法访问,可通过第三方平台(如 Gitee)下载安装包[^3]。 - **安装程序**: 下载完成后运行 `Visual Studio Installer`,选择需要的工作负载(如 `.NET桌面开发`、`使用C++的桌面开发` 等)[^2]。 #### 2. **安装注意事项** - **系统要求**:Windows 7 SP1 及以上系统,4GB 以上内存,建议预留 20GB 硬盘空间[^3]。 - **组件选择**:根据开发需求勾选对应组件(如 C#、Python、C++ 等)[^2]。 #### 3. **首次使用** 1. **创建项目**: 打开 Visual Studio 2017,点击 `文件` → `新建` → `项目`,选择模板(如 `控制台应用`、`类库` 等)[^1]。 2. **编写代码**: - C# 示例: ```csharp using System; class Program { static void Main() { Console.WriteLine("Hello World!"); } } ``` - C++ 示例: ```cpp #include <iostream> int main() { std::cout << "Hello World!"; return 0; } ``` 3. **编译运行**: 按 `F5` 调试运行,或 `Ctrl + F5` 直接运行。 #### 4. **常用功能** - **快捷键**: - `Ctrl + S` 保存,`Ctrl + Z` 撤销,`F12` 转到定义。 - **调试工具**: 使用断点(点击代码行左侧)和 `即时窗口` 查看变量值。 #### 5. **常见问题** - **安装失败**:检查网络连接或通过 `Visual Studio Installer` 修复安装。 - **项目无法运行**:确保已安装对应语言的工作负载(如未安装 C++ 组件则无法编译 C++ 代码)[^2]。 --- ###
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值