当前位置:  开发笔记 > 编程语言 > 正文

Visual Studio解决方案/多项目:如何在多个C++项目中有效地传播项目属性

如何解决《VisualStudio解决方案/多项目:如何在多个C++项目中有效地传播项目属性》经验,为你挑选了3个好方法。

我正在使用包含多个项目(大约30个)的Visual Studio 2005 C++解决方案.根据我的经验,维护项目的所有属性(即包括路径,lib路径,链接库,代码生成选项......)经常变得很烦人,因为你经常需要点击每个项目才能修改它们.当您有多个配置(Debug,Release,Release 64 bits,...)时,情况会变得更糟.

真人生活的例子:

假设您要使用新库,并且需要将此库的包含路径添加到所有项目.您将如何避免编辑每个项目的属性?

假设您要测试驱动新版本的库(比如版本2.1beta),以便您需要快速更改一组项目的包含路径/库路径/链接库?

笔记:

我知道可以一次选择多个项目,然后右键单击并选择"属性".但是,此方法仅适用于已针对不同项目完全相同的属性:您无法使用它来向使用不同包含路径的项目集添加包含路径.

我也知道可以全局修改环境选项(工具/选项/项目和解决方案/目录),但它不能令人满意,因为它无法集成到SCM中

我也知道可以在解决方案中添加"配置".它没有帮助,因为它使另一组项目属性得以维护

我知道代码集C++ Builder 2009通过所谓的"选项集"为这种需求提供了一个可行的解决方案,它可以被几个项目继承(我同时使用Visual Studio和C++ Builder,我仍然认为C++ Builder在某些方面存在争议到Visual Studio)

我希望有人会建议像CMake这样的"autconf",但是有可能将vcproj文件导入到这样的工具中吗?

quamrana.. 31

我认为您需要调查属性文件,即*.vsprops(较旧)或*.props(最新)

需要添加属性手动档到每一个项目,但是一旦这样做了,你有多个项目,但一个.[VS]道具文件.如果更改属性,则所有项目都将继承新设置.



1> quamrana..:

我认为您需要调查属性文件,即*.vsprops(较旧)或*.props(最新)

需要添加属性手动档到每一个项目,但是一旦这样做了,你有多个项目,但一个.[VS]道具文件.如果更改属性,则所有项目都将继承新设置.



2> Jere.Jones..:

我经常需要做类似的事情,因为我链接到静态运行时库.我写了一个程序来为我做.它基本上扫描你给它的任何路径的所有子目录,并ids它找到的任何.vcproj文件.然后一个接一个地打开它们修改它们并保存它们.由于我很少使用它,路径是硬编码的,但我认为你可以根据自己的喜好调整它.

另一种方法是认识到Visual Studio Project文件只是XML文件,可以使用您喜欢的XML类进行操作.XmlDocument当有很多我不想输入的包含目录时,我已经使用C#来更新include目录了.:)

我包括两个例子.您需要根据自己的需要对其进行修改,但这些应该可以帮助您入门.

这是C++版本:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using boost::regex;
using boost::filesystem::path;
using namespace std;

vector GetFileList(path dir, bool recursive, regex matchExp);
void FixProjectFile(path file);
string ReadFile( path &file );
void ReplaceRuntimeLibraries( string& contents );
void WriteFile(path file, string contents);

int _tmain(int argc, _TCHAR* argv[])
{
    boost::timer stopwatch;
    boost::filesystem::path::default_name_check(boost::filesystem::native);
    regex projFileRegex("(.*)\\.vcproj");
    path rootPath("D:\\Programming\\Projects\\IPP_Decoder");

    vector targetFiles = GetFileList(rootPath, true, projFileRegex);
    double listTimeTaken = stopwatch.elapsed();

    std::for_each(targetFiles.begin(), targetFiles.end(), FixProjectFile);

    double totalTimeTaken = stopwatch.elapsed();
    return 0;
}

void FixProjectFile(path file) {
    string contents = ReadFile(file);
    ReplaceRuntimeLibraries(contents);
    WriteFile(file, contents);
}

vector GetFileList(path dir, bool recursive, regex matchExp) {
    vector paths;
    try {
        boost::filesystem::directory_iterator di(dir);
        boost::filesystem::directory_iterator end_iter;
        while (di != end_iter) {
            try {
                if (is_directory(*di)) {
                    if (recursive) {
                        vector tempPaths = GetFileList(*di, recursive, matchExp);
                        paths.insert(paths.end(), tempPaths.begin(), tempPaths.end());
                    }
                } else {
                    if (regex_match(di->string(), matchExp)) {
                        paths.push_back(*di);
                    }
                }
            }
            catch (std::exception& e) {
                string str = e.what();
                cout << str << endl;
                int breakpoint = 0;
            }
            ++di;
        }
    }
    catch (std::exception& e) {
        string str = e.what();
        cout << str << endl;
        int breakpoint = 0;
    }
    return paths;
}

string ReadFile( path &file ) {
//  cout << "Reading file: " << file.native_file_string() << "\n";
    ifstream infile (file.native_file_string().c_str(), ios::in | ios::ate);
    assert (infile.is_open());

    streampos sz = infile.tellg();
    infile.seekg(0, ios::beg);

    vector v(sz);
    infile.read(&v[0], sz);

    string str (v.empty() ? string() : string (v.begin(), v.end()).c_str());

    return str;
}

void ReplaceRuntimeLibraries( string& contents ) {
    regex releaseRegex("RuntimeLibrary=\"2\"");
    regex debugRegex("RuntimeLibrary=\"3\"");
    string releaseReplacement("RuntimeLibrary=\"0\"");
    string debugReplacement("RuntimeLibrary=\"1\"");
    contents = boost::regex_replace(contents, releaseRegex, releaseReplacement);
    contents = boost::regex_replace(contents, debugRegex, debugReplacement);
}

void WriteFile(path file, string contents) {
    ofstream out(file.native_file_string().c_str() ,ios::out|ios::binary|ios::trunc); 
    out.write(contents.c_str(), contents.length());
}

这是C#版本.请享用...

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IO;

namespace ProjectUpdater
{
    class Program
    {
        static public String rootPath = "D:\\dev\\src\\co\\UMC6\\";
        static void Main(string[] args)
        {
            String path = "D:/dev/src/co/UMC6/UMC.vcproj";
            FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
            XmlDocument xmldoc = new XmlDocument();
            xmldoc.Load(fs);
            XmlNodeList oldFiles = xmldoc.GetElementsByTagName("Files");
            XmlNode rootNode = oldFiles[0].ParentNode;
            rootNode.RemoveChild(oldFiles[0]);

            XmlNodeList priorNode = xmldoc.GetElementsByTagName("References");
            XmlElement filesNode = xmldoc.CreateElement("Files");
            rootNode.InsertAfter(filesNode, priorNode[0]);

            DirectoryInfo di = new DirectoryInfo(rootPath);
            foreach (DirectoryInfo thisDir in di.GetDirectories())
            {
                AddAllFiles(xmldoc, filesNode, thisDir.FullName);
            }


            List allDirectories = GetAllDirectories(rootPath);
            for (int i = 0; i < allDirectories.Count; ++i)
            {
                allDirectories[i] = allDirectories[i].Replace(rootPath, "$(ProjectDir)");
            }
            String includeDirectories = "\"D:\\dev\\lib\\inc\\ipp\\\"";
            foreach (String dir in allDirectories) 
            {
                includeDirectories += ";\"" + dir + "\"";
            }

            XmlNodeList toolNodes = xmldoc.GetElementsByTagName("Tool");
            foreach (XmlNode node in toolNodes)
            {
                if (node.Attributes["Name"].Value == "VCCLCompilerTool") {
                    try
                    {
                        node.Attributes["AdditionalIncludeDirectories"].Value = includeDirectories;
                    }
                    catch (System.Exception e)
                    {
                        XmlAttribute newAttr = xmldoc.CreateAttribute("AdditionalIncludeDirectories");
                        newAttr.Value = includeDirectories;
                        node.Attributes.InsertBefore(newAttr, node.Attributes["PreprocessorDefinitions"]);
                    }

                }
            }
            String pathOut = "D:/dev/src/co/UMC6/UMC.xml";
            FileStream fsOut = new FileStream(pathOut, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
            xmldoc.Save(fsOut);

        }
        static void AddAllFiles(XmlDocument doc, XmlElement parent, String path) {
            DirectoryInfo di = new DirectoryInfo(path);
            XmlElement thisElement = doc.CreateElement("Filter");
            thisElement.SetAttribute("Name", di.Name);
            foreach (FileInfo fi in di.GetFiles())
            {
                XmlElement thisFile = doc.CreateElement("File");
                String relPath = fi.FullName.Replace(rootPath, ".\\");
                thisFile.SetAttribute("RelativePath", relPath);
                thisElement.AppendChild(thisFile);
            }
            foreach (DirectoryInfo thisDir in di.GetDirectories())
            {
                AddAllFiles(doc, thisElement, thisDir.FullName);
            }
            parent.AppendChild(thisElement);
        }
        static List GetAllDirectories(String dir)
        {
            DirectoryInfo di = new DirectoryInfo(dir);
            Console.WriteLine(dir);

            List files = new List();
            foreach (DirectoryInfo subDir in di.GetDirectories())
            {
                List newList = GetAllDirectories(subDir.FullName);
                files.Add(subDir.FullName);
                files.AddRange(newList);
            }
            return files;
        }
        static List GetAllFiles(String dir)
        {
            DirectoryInfo di = new DirectoryInfo(dir);
            Console.WriteLine(dir);

            List files = new List();
            foreach (DirectoryInfo subDir in di.GetDirectories())
            {
                List newList = GetAllFiles(subDir.FullName);
                files.AddRange(newList);
            }
            foreach (FileInfo fi in di.GetFiles())
            {
                files.Add(fi.FullName);
            }
            return files;
        }
    }
}



3> Xavier Nodet..:

如建议的那样,你应该看一下Property Sheets(又名.vsprops文件).
我在这里写了一篇非常简短的介绍.

推荐阅读
殉情放开那只小兔子
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有