写一个小工具来可视化VisualStudio中项目之间的依赖关系(1.针对sln中的信息)

本篇主要对问题进行分析,尝试对项目间依赖关系进行解析,但只是解析出了.sln中的信息。对于完整的工具,详见下一篇

目标

Visual Studio 中,一个“解决方案”(.sln)包含多个“项目”(.vcxproj)。
而项目之间有依赖关系:
在这里插入图片描述
当对一个项目进行生成时,它总会先确保其所依赖的项目先被生成。这样整体就会以一个正确的顺序生成。

当项目变多时,我期望能用一个图来可视化这些关系以便观察。但我暂时还没找到特别方便的工具。


不过,想了一下,其实这样的工具不难实现,我在之前的博客《为代码文件的include关系生成Mermaid图》《为代码中的类继承关系生成Mermaid图》都做了类似的东西。这次的区别只在于——所谓的“关系”变为了“项目间依赖关系”。

而“项目间依赖关系”的数据一定是保存在文件中的,我想应该是.sln文件或.vcxproj文件,他们都是可阅读的文本文件,而非不可阅读的二进制文件。因此我可以对其进行解析。

因此,本篇的目标是完成这样的小工具。大体步骤如下:

  1. 研究“项目间依赖关系”的信息如何从代码上获取
  2. 解析出“项目间依赖关系”并生成Mermaid图

找到“项目间依赖关系”信息存在哪里

对于这个问题,有多种方法解决,例如:

  1. 查阅官方文档。优点是权威,缺点是不一定能找到,花费的时间长短也不一定。
  2. 先有一个自己的假设,比如 .sln文件或 .vcxproj文件中写了一个项目依赖的项目的名字 。然后通过 ”字符串搜索“ 的方式来找到具体的位置。当自己有假设时这个方法的优点就是快。但缺点是不稳定,因为假设不一定对,而”字符串搜索“的结果也可能有歧义。
  3. 通过实验比较指定项目依赖项的“前”与“后”,文件之间的差异

此时我决定采用第3种。因为构建这样一个实验是相对简单的,而且通过实验一定能知道结果。
(当然并不是说这三种方法是互斥的,它们其实也可以结合,比如从 2 和 3 方法中获得思路并最后在官方文档中求证)


我做了小实验(详细操作见【附录:实验细节】)之后发现,在指定了一个项目的依赖项目之后,.sln会添加内容:
(下图中test2项目依赖testProjA项目)
在这里插入图片描述
又经过对更复杂的工程的.sln文件进行比对后,我得出结论:

.sln中,每一个项目都以Project后跟一系列项目的数据的一行做开头,以EndProject这一行做结尾。在其中 ProjectSection(ProjectDependencies) = postProject 一行之后跟着数行其依赖的项目所对应的编码,然后以EndProjectSection结束。

写成代码的话就是:

Project("{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}") = "项目A的名字", "项目A的.vcxproj文件", "{项目A的编码}"
	ProjectSection(ProjectDependencies) = postProject
		{项目A的所依赖的第1个项目的编码} = {项目A的所依赖的第1个项目的编码}
		{项目A的所依赖的第2个项目的编码} = {项目A的所依赖的第2个项目的编码}
		{项目A的所依赖的第3个项目的编码} = {项目A的所依赖的第3个项目的编码}
	EndProjectSection
EndProject

编写代码

在上一步分析出格式之后,“解析出依赖关系”变成了一个纯字符串处理的问题。

我的思路大概是这样:

  1. 以“行”为单位读取.sln文件内容
  2. 将行按项目来分割,标准是:以Project为开头的行起始,以EndProject的行结束。这些行的内容对应存储为一个ProjectInfo
  3. 解析出ProjectInfo项目的名字。和项目的编码。
  4. 遍历每一个ProjectInfo,找到 ProjectSection(ProjectDependencies) = postProject 一行,然后对接下来的每一行读取其编码,只需要比对其他ProjectInfo中的编码就可以知道其依赖项目的名字了。重复此操作直到 EndProjectSection
  5. 将上一步得到的依赖关系按照 Mermaid 的格式输出出来

具体代码如下:

#include <iostream>
#include<vector>
using namespace std;

//一个项目所对应的信息
struct ProjectInfo
{
    //读取到的每一行信息
    vector<string> lines;

    //项目名字
    string Name;
    //项目编码
    string Code;

    //所依赖的项目
    vector<ProjectInfo* >DependProjects;
};

//从字符串中分割得到信息的辅助函数
vector<string> StringSplitter(string source, char startChar, char endChar)
{
    vector<string> result;
    string current;
    bool working = false;
    for (int i = 0; i < source.size(); i++)
    {
        if (working)
        {
            if (source[i] == endChar)
            {
                result.push_back(current);
                current.clear();
                working = false;
            }
            else
                current.push_back(source[i]);
        }          
        else if (source[i] == startChar)
            working = true;        
    }

    return result;
}

int main()
{
    //.sln文件的路径
    const string slnFile = "D:/Temp/renderdoc.sln";

    //读取文件
    FILE* file;
    {
        fopen_s(&file, slnFile.c_str(), "r");
        if (!file)
        {
            cout << "打开文件失败" << endl;
            return -1;
        }
    }

    //读取所有的项目信息
    vector<ProjectInfo> projects;
    {
        ProjectInfo* CurrentProject = nullptr;//当前正在添加信息的项目

         //读取每一行
        char buff[1024];
        while (fgets(buff, 1024, file) != nullptr)
        {
            string line = buff;

            if (line.find("Project") == 0)//如果找到"Project"且是在开头,则说明是新项目
            {
                projects.push_back(ProjectInfo());
                CurrentProject = &projects[projects.size() - 1];
            }

            if (CurrentProject != nullptr)//如果当前项目不为空,则添加此行到项目信息中
                CurrentProject->lines.push_back(line);
            
            if (line.find("EndProject") == 0)//如果找到"EndProject"且是在开头,则说明项目结束
                CurrentProject = nullptr;
        }
    }

    //遍历每一个项目找到其名字与编号
    for (ProjectInfo& p : projects)
    {
        //Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "renderdocshim", "renderdocshim\renderdocshim.vcxproj", "{6DEE3F12-F2F8-42CA-865A-578D0FD11387}"
        auto SubStrs = StringSplitter(p.lines[0],'\"', '\"');
        
        p.Name = SubStrs[1];

        p.Code = StringSplitter(SubStrs[3], '{', '}')[0];
    }

    //遍历每一个项目找到其依赖的项目
    for (ProjectInfo& p : projects)
    {
        bool DependenciesLines = false;

        for (auto line : p.lines)
        {
            if (DependenciesLines)
            {
                if (line.find("EndProjectSection") != string::npos)//如果找到"EndProjectSection"则结束写依赖的项目
                    DependenciesLines = false;
                else    //这是一条表示依赖的行
                {
                    //依赖的项目的编码
                    string DpdProjCode = StringSplitter(line, '{', '}')[0];

                    //找到依赖的项目
                    for (ProjectInfo& other : projects)
                        if (other.Code == DpdProjCode)
                            p.DependProjects.push_back(&other);
                }
            }

            if (line.find("ProjectSection(ProjectDependencies) = postProject") != string::npos)//如果找到"ProjectSection(ProjectDependencies) = postProject"则开始写依赖的项目
                DependenciesLines = true;
        }
    }

    //画Mermaid图
    for (auto p : projects)
    {
        for (auto d : p.DependProjects)
            cout << p.Name << "-->" << d->Name << endl;
    }
}

测试

我对 baldurk/renderdoc/renderdoc.sln测试后结果如下:

renderdoc
crash_generation_server
crash_generation_client
exception_handler
breakpad_common
NV
renderdoccmd

发现问题:原来信息不止存于sln,还存于vcxproj

我发现在上一个测试中,依赖的信息明显比在VisualStudio的IDE中看到的少。

观察后发现,在IDE中能看到一些依赖关系,例如:
在这里插入图片描述
但是在.sln文件中这些依赖关系并不能看到:

Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qrenderdoc", "qrenderdoc\qrenderdoc_local.vcxproj", "{A14A6AE5-02B1-35FE-BE59-B3E7C273B40B}"
EndProject

看来.sln中并不包含所有的依赖信息。

我假设.vcxproj中也有信息,并也以“项目的编码”的形式来指定其依赖的项目。
因此在qrenderdoc_local.vcxproj中对其所依赖的项目version(代码257FD75C-4D17-4A23-A754-23BFD85887A0)进行搜索,发现可以找到:
在这里插入图片描述
很明显:
.vcxproj的格式是xml,其ProjectReference节点中指明了其依赖的项目。

看来,当前的代码需要扩展。内容就放在之后吧。
(下一篇:《写一个小工具来可视化VisualStudio中项目之间的依赖关系(2.补全vcxproj中的信息)》

附录:实验细节

1. 创建解决方案与项目

在这里插入图片描述
这会为我创建一个解决方案test2.sln和一个同名的工程test2.vcxproj
在这里插入图片描述

2. 在解决方案下创建新项目

右键解决方案,选择新建项目
在这里插入图片描述
在这里插入图片描述
随后解决方案将有两个项目了
在这里插入图片描述

3. 复制此时的文件夹,作为【改动前版本】

注意保存当前的工程文件(比如关闭VisualStudio,会提示保存)

然后复制
在这里插入图片描述

4. 做操作,指定依赖关系

打开解决方案的属性面板
在这里插入图片描述
指定:test2依赖于testProjA
在这里插入图片描述
然后点确定应用

5. 复制此时的文件夹,作为【改动后版本】

注意保存当前的工程文件(比如关闭VisualStudio,会提示保存)

然后复制
在这里插入图片描述

6. 比较【改动前版本】与【改动后版本】

我这里使用 Meld 作为工具来比较:
在这里插入图片描述
结果:
在这里插入图片描述
改动不止一个,不过由于只有.sln是可阅读的文本文件,因此只能从其入手:

幸运的是,这里面确实有想要的信息:
在这里插入图片描述
可以推断出,每个项目都对应一个编码,比如testProjA对应82C67BD6-F17D-442B-B964-5067771F555E,而test2想要指定其依赖于testProjA时将用编码来指代。
在这里插入图片描述

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1.项目代码均经过功能验证ok,确保稳定可靠运行。欢迎下载体验!下载完使用问题请私信沟通。 2.主要针对各个计算机相关专业,包括计算机科学、信息安全、数据科学与大数据技术、人工智能、通信、物联网等领域的在校学生、专业教师、企业员工。 3.项目具有丰富的拓展空间,不仅可作为入门进阶,也可直接作为毕设、课程设计、大作业、初期项目立项演示等用途。 4.当然也鼓励大家基于此进行二次开发。在使用过程,如有问题或建议,请及时沟通。 5.期待你能在项目找到乐趣和灵感,也欢迎你的分享和反馈! 【资源说明】 基于C#实现的图书馆管理系统源码+项目说明+sln解决方案.zip 基本需求 图书馆管理系统的管理层次可划分为了五个部分:图书信息维护,读者信息管理,图书借阅管理,信息查询,管理员信息管理。能够实现以下功能。 进行新书入库的信息录入及现有图书信息查询、增加、修改以及删除。 能够实现对读者基本信息的查询、注册、修改和删除管理。 能够进行读者借阅图书的信息管理功能。 能够进行借阅信息的查询功能。 系统功能 系统的功能分析: 图书管理涉及图书信息、读者信息、图书借阅等多种数据管理。从管理的角度可将图书管理系统分为三类:图书信息管理、系统用户管理、读者数据管理。 图书信息管理包括图书增加、借还、查询信息等操作。 系统用户管理包括系统用户类别和用户数据管理。 读者数据管理包括读者类别管理和个人数据的录入、查询、修改和删除。 具体功能如下 对所有用户开放的图书查询。 查询及编辑借阅者个人部分信息。 借阅者查看个人借阅情况信息。 根据借阅情况对数据库进行操作。 根据还书情况对数据库进行操作。 查询及统计各种信息。 维护图书信息。 维护工作人员和管理员信息
【资源说明】 基于C++和QT开发的仿Windows端QQ影音视频播放器源码+sln解决方案+项目说明+注释.zip 使用C++ Qt开发的Windows端视频播放器,界面高仿QQ影音, 如下图 主要功能 支持mp4、avi、flv等视频文件的播放 支持网络流播放,例如http, rtsp, rtmp等网络流 支持选择多个文件循环播放 支持打开目录进行播放 双击全屏播放 支持倍速播放,可进行0.5~~2倍速播放 # 分支说明 main分支:使用libvlc为播放组件 player_SDL分支:使用SDL FFmpeg做解码转换播放 # 开发环境 main分支:win11 x64、vs2022 qt6.3 player_SDL分支:win11/win10 vs2019 Qt5.15.2 x64 VS2019 Qt开发环境的配置可以参考这篇博客:https://mingshiqiang.blog.csdn.net/article/details/108015209 # 编译方法 本项目只能进行x64编译,不支持x86编译 1 vs2019/vs2022打开QQMediaPlayerCopy.sln 右键项目属性---> Qt ---> 如下图 ![qqq](https://user-images.githubusercontent.com/42860254/159120393-2b091a49-4058-493d-8dfb-1b086aec4295.png) 2 下载依赖的sdk 链接:https://pan.baidu.com/s/10uXf3976ihfZyyLrrTtGOA 提取码:hmhn 下载后,解压,将sdk_package放到QQMediaPlayerCopy.vcxproj同级目录 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载使用,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可直接用于毕设、课设、作业等。 欢迎下载,沟通交流,互相学习,共同进步!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值