VS 多工程之间管理与调用(超详细)

· 说明

本文是在前任的基础上总结完善而成的,中间走了不少弯路,希望后来人能够大树乘凉~~~

特别感谢以下两篇博文:

yyhero1 - VS项目属性的一些配置项的总结(important)

演练:创建和使用动态链接库 (C++)

平台:Visual Studio 2013 , Windows 10 OS

*功能:本文实现了 VS 在同一解决方案下动态库,静态库,可执行文件的生成与调用

项目下载:MultiProj项目


· 配置过程描述

我们最终希望的多工程目录是这样的:

这里写图片描述

用思维导图表示是这样的:

链接: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);

· 联系作者

邮箱: [email protected]

猜你喜欢

转载自blog.csdn.net/qq_34719188/article/details/80956749
VS