· 说明
本文是在前任的基础上总结完善而成的,中间走了不少弯路,希望后来人能够大树乘凉~~~
特别感谢以下两篇博文:
yyhero1 - VS项目属性的一些配置项的总结(important)
平台:Visual Studio 2013 , Windows 10 OS
*功能:本文实现了 VS 在同一解决方案下动态库,静态库,可执行文件的生成与调用
项目下载:MultiProj项目
· 配置过程描述
我们最终希望的多工程目录是这样的:
用思维导图表示是这样的:
VS工程下是这样的
这样做的好处是:
- 工作目录结构清晰
- 制作安装包时我们只需将 MultiProj/Bin/Release/ 目录下的所有文件打包即可
- 发布和转移源码的时候我们可以打包除 Temp 目录以外 MultiProj 下面的所有文件和目录(如果不需要执行档,也可不包括Bin)
· 详细步骤
1、打开 VS
2、新建一个空的解决方案
3、新建 4 个文件夹
这样做的好处是易于管理项目~~
4、分别建立各自文件架下的工程
5、书写源代码
--------------------------------- MathFuncsDll 工程代码 -----------------------------------
< stdafx.h > (下文不再写此部分)
// stdafx.h : 标准系统包含文件的包含文件,
#pragma once
#include "targetver.h"
#define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的信息
// Windows 头文件:
#include <windows.h>
// TODO: 在此处引用程序需要的其他头文件
< stdafx.cpp > (下文不再写此部分)
// stdafx.cpp : 只包括标准包含文件的源文件
#include "stdafx.h"
// TODO: 在 STDAFX.H 中
// 引用任何所需的附加头文件,而不是在此文件中引用
< targetver.h > (下文不再写此部分)
#pragma once
// 包括 SDKDDKVer.h 将定义可用的最高版本的 Windows 平台。
// 如果要为以前的 Windows 平台生成应用程序,请包括 WinSDKVer.h,并将
// WIN32_WINNT 宏设置为要支持的平台,然后再包括 SDKDDKVer.h。
#include <SDKDDKVer.h>
< dllmain.cpp > (下文不再写此部分)
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "stdafx.h"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
< MathFuncsDll.h >
// MathFuncsDll.h
#ifdef MATHFUNCSDLL_EXPORTS
#define MATHFUNCSDLL_API __declspec(dllexport)
#else
#define MATHFUNCSDLL_API __declspec(dllimport)
#endif
namespace MathFuncs
{
// This class is exported from the MathFuncsDll.dll
class MyMathFuncs
{
public:
// Returns a + b
static MATHFUNCSDLL_API double Add(double a, double b);
// Returns a - b
static MATHFUNCSDLL_API double Subtract(double a, double b);
// Returns a * b
static MATHFUNCSDLL_API double Multiply(double a, double b);
// Returns a / b
// Throws const std::invalid_argument& if b is 0
static MATHFUNCSDLL_API double Divide(double a, double b);
};
}
< MathFuncsDll.cpp >
// MathFuncsDll.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include "MathFuncsDll.h"
#include <stdexcept>
using namespace std;
namespace MathFuncs
{
double MyMathFuncs::Add(double a, double b)
{
return a + b;
}
double MyMathFuncs::Subtract(double a, double b)
{
return a - b;
}
double MyMathFuncs::Multiply(double a, double b)
{
return a * b;
}
double MyMathFuncs::Divide(double a, double b)
{
if (b == 0)
{
throw invalid_argument("b cannot be zero!");
}
return a / b;
}
}
--------------------------------- MathSquare 工程代码 -----------------------------------
< square.cpp >
#include <iostream>
using namespace std;
int main(){
cout << "Pls enter two number : \n";
int a, b;
cin >> a >> b;
cout << a + b << endl;
return 0;
}
------------------------------- MathAverageLib 工程代码 ----------------------------------
-
< MathOperator.h >
#pragma once
class MathOperator
{
public:
MathOperator();
~MathOperator();
int getAverage(int a, int b, int c);
};
< MathOperator.cpp >
#include "stdafx.h"
#include "MathOperator.h"
MathOperator::MathOperator()
{
}
MathOperator::~MathOperator()
{
}
int MathOperator::getAverage(int a, int b, int c){
return ( a + b + c) / 3;
}
--------------------------------- Main 工程代码 -----------------------------------
< main.cpp >
#include <iostream>
#include <windows.h>
#include "MathOperator.h"
#include "MathFuncsDll.h"
using namespace std;
int main()
{
///test dll
double a = 7.4;
int b = 99;
cout << "a + b = " <<
MathFuncs::MyMathFuncs::Add(a, b) << endl;
cout << "a - b = " <<
MathFuncs::MyMathFuncs::Subtract(a, b) << endl;
cout << "a * b = " <<
MathFuncs::MyMathFuncs::Multiply(a, b) << endl;
cout << "a / b = " <<
MathFuncs::MyMathFuncs::Divide(a, b) << endl;
try
{
cout << "a / 0 = " <<
MathFuncs::MyMathFuncs::Divide(a, 0) << endl;
}
catch (const invalid_argument &e)
{
cout << "Caught exception: " << e.what() << endl;
}
/// test lib
MathOperator mo;
std::cout << "The average of 2, 4, 6 is: " << mo.getAverage(2, 4, 6) << std::endl;
///test exe
WinExec("\"MathSquare.exe\"", 1);
system("pause");
return 0;
}
部分代码讲解
6、更改各种文件的生成路径
首先看一下项目设置中可以使用的宏,常用的有:
宏名称 | 含义 |
---|---|
$(ConfigurationName) | Debug或者Release |
$(IntDir) | 编译器使用的中间目录,产出obj二进制文件 |
$(OutDir) | 链接器使用的输出目录 |
$(ProjectDir) | 项目目录 |
$(ProjectName) | 项目名字 |
$(SolutionDir) | 解决方案目录 |
$(TargetDir) | 目标输出文件所在的目录 |
$(TargetExt) | 目标输出的扩展名 |
$(TargetFileName) | 目标输出文件名,包括扩展名 |
$(TargetName) | 目标输出名,不包括扩展名 |
$(TargetPath) | 目标输出文件的全路径名 |
上面建立的 4 个工程要分别单独设置,每个工程又要分 Debug 和 Release 两种情况,所以要注意!!!
--------------------------------- MathFuncsDll 属性设置 -----------------------------------
> 全局配置:
- 配置属性 - 常规 - 输出目录:
$(SolutionDir)\Temp\Link\$(ProjectName)\$(ConfigurationName)
- 配置属性 - 常规 - 中间目录:
$(SolutionDir)\Temp\Compile\$(ProjectName)\$(ConfigurationName)
> Release 模式:
- 配置属性 - 生成事件 - 后期生成事件 - 命令行:
copy $(TargetPath) $(SolutionDir)\Bin\$(ConfigurationName)\;
copy $(TargetDir)$(TargetName).lib $(SolutionDir)\Lib\;
> Debug 模式:
- 配置属性 - 链接器 - 高级 - 导入库:
$(TargetDir)$(TargetName)_d.lib
- 配置属性 - 生成事件 - 后期生成事件 - 命令行:
copy $(TargetPath) $(SolutionDir)\Bin\$(ConfigurationName)\;
copy $(TargetDir)$(TargetName)_d.lib $(SolutionDir)\Lib\;
看不清楚的话看这里:
----------------------------------- MathSquare 属性设置 -----------------------------------
> 全局配置:
- 配置属性 - 常规 - 输出目录(同上)
- 配置属性 - 常规 - 中间目录(同上)
- 配置属性 - 生成事件 - 后期生成事件 - 命令行:
copy $(TargetDir)$(TargetName).exe $(SolutionDir)\Bin\$(ConfigurationName);
------------------------------- MathAverageLib 属性设置 ----------------------------------
> 全局配置:
- 配置属性 - 常规 - 输出目录(同上)
- 配置属性 - 常规 - 中间目录(同上)
- 配置属性 - 生成事件 - 后期生成事件 - 命令行:
copy $(TargetDir)$(TargetName).lib $(SolutionDir)\Lib\;
---------------------------------- Main 属性设置 -----------------------------------
> 全局配置:
- 配置属性 - 常规 - 输出目录(同上)
- 配置属性 - 常规 - 中间目录(同上)
- 配置属性 - 生成事件 - 后期生成事件 - 命令行:
copy $(TargetPath) $(SolutionDir)\Bin\$(ConfigurationName);
7、添加引用
大功告成!!! Ctrl + F5 运行即可~~
· 失败总结
- 是否正确建立工程
- 时否正确配置相关属性
- 是否模糊了 release 和 debug 下的配置
- 是否写正确后处理事件
- 源代码是都书写正确
- …
· 复制快道
// 输出目录
$(SolutionDir)\Temp\Link\$(ProjectName)\$(ConfigurationName)
// 中间目录
$(SolutionDir)\Temp\Compile\$(ProjectName)\$(ConfigurationName)
// DLL Release 命令
copy $(TargetPath) $(SolutionDir)\Bin\$(ConfigurationName)\;
copy $(TargetDir)$(TargetName).lib $(SolutionDir)\Lib\;
// DLL Debug 命令
copy $(TargetPath) $(SolutionDir)\Bin\$(ConfigurationName)\;
copy $(TargetDir)$(TargetName)_d.lib $(SolutionDir)\Lib\;
$(TargetDir)$(TargetName)_d.lib
// EXE 命令
copy $(TargetDir)$(TargetName).exe $(SolutionDir)\Bin\$(ConfigurationName);
// LIB 命令
copy $(TargetDir)$(TargetName).lib $(SolutionDir)\Lib\;
// MAIN 命令
copy $(TargetPath) $(SolutionDir)\Bin\$(ConfigurationName);