Visual Studio Solutions / Multiple Projekt: Wie effektiv Projekteigenschaften unter mehreren C ++ Projekte propagieren

StackOverflow https://stackoverflow.com/questions/111631

Frage

ich mit einer Visual Studio 2005 C ++ Lösung arbeite, die mehrere Projekte (etwa 30). Basierend auf meiner Erfahrung, wird es oft ärgerlich alle Eigenschaften der Projekte zu erhalten (dh umfasst Pfad, lib Pfad, verknüpft Libs, Code-Generierung Optionen, ...), wie Sie oft jedes Projekt, um klicken, um modifizieren. Die Situation wird noch schlimmer, wenn Sie mehrere Konfigurationen (Debug, Veröffentlichung, Ausgabe 64 Bit, ...) haben.

Beispiele aus der Praxis:

  • Angenommen, Sie eine neue Bibliothek verwenden möchten, benötigen Sie den Include-Pfad zu dieser Bibliothek zu allen Projekten hinzuzufügen. Wie werden Sie vermeiden, um die Eigenschaften eines jeden eines jeden Projekts bearbeiten zu müssen?
  • Angenommen, Sie eine neue Version der Bibliothek fahren testen wollen (Version 2.1beta sagen), so dass Sie schnell die Pfade / Bibliothekspfad / verknüpften Bibliothek für eine Reihe von Projekten gehören ändern müssen?

Weitere Informationen:

  • Ich bin mir bewusst, dass es möglich ist, mehrere Projekte gleichzeitig zu wählen, dann einen Rechtsklick machen und wählen Sie „Eigenschaften“. Jedoch nur diese Methode funktioniert für Eigenschaften, die bereits waren genau gleich für die verschiedene Projekte. Sie nicht verwenden können, um auf einen Pfad zu einem Satz von Projekt enthalten hinzufügen, die verschiedenen Include-Pfad wurden mit
  • Ich weiß auch, dass es möglich ist global die Umgebungs-Optionen (Extras / Optionen / Projekt und Lösungen / Verzeichnisse) zu ändern, aber es ist nicht so befriedigend ist, da sie nicht in ein SCM
  • integriert werden können
  • Ich weiß auch, dass man „Konfigurationen“, um eine Lösung hinzufügen. Es ist nicht hilft, da sie einen weiteren Satz von Projekteigenschaften macht zu halten
  • Ich weiß, dass codegear C ++ Builder 2009 eine tragfähige Antwort auf diese Notwendigkeit bietet durch so genannte „Optionsgruppen“, die von mehreren Projekten vererbt werden kann (verwende ich Visual Studio und C ++ Builder, und ich C ++ Builder Felsen immer noch denkt, dass auf bestimmten Aspekte wie zu Visual Studio verglichen)
  • Ich gehe davon aus, dass jemand ein „autconf“ wie CMake vorschlagen, ist es jedoch möglich, Dateien in ein solches Werkzeug zu importieren vcproj?
War es hilfreich?

Lösung

Ich glaube, Sie müssen Eigenschaften Dateien untersuchen, dh *. vsprops (ältere) oder * .props (spätestens)

Sie müssen die Eigenschaftsdatei manuell zu jedem Projekt hinzuzufügen, aber sobald das erledigt ist, haben Sie mehrere Projekte, sondern eins. [Vs] Requisiten Datei. Wenn Sie die Eigenschaften ändern, werden alle Projekte übernehmen die neuen Einstellungen.

Andere Tipps

Ich brauche oft etwas Ähnliches zu tun, da ich zu den statischen Laufzeitbibliotheken verknüpfen. Ich schrieb ein Programm, es zu tun für mich. Es scannt grundsätzlich alle Unterverzeichnisse von Welchen Weg auch immer Sie es geben und IDs keine VCPROJ Dateien, die es findet. Dann eins nach dem anderen, öffnet er sie ändert sie und speichert sie. Da ich es nur selten verwenden, wird der Weg es hart codiert, aber ich denke, Sie in der Lage sein werde, es zu justieren, wie Sie möchten.

Ein weiterer Ansatz ist zu erkennen, dass Visual Studio Projektdateien sind einfach XML-Dateien und können mit Ihrer Lieblings-XML-Klasse manipuliert werden. Ich habe für die Aktualisierung der Verzeichnisse enthalten etwas mit C # 's XmlDocument gemacht, wenn es gab A LOT von Include-Verzeichnisse, die ich nicht geben wollte.)

Ich bin mit beiden Beispielen. Sie müssen sie an die eigenen Bedürfnisse ändern, aber diese sollten Sie beginnen.

Dies ist die C ++ Version:

 
#include <stdio.h>
#include <tchar.h>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
#include <boost/filesystem/convenience.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/regex.hpp>
#include <boost/timer.hpp>

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

vector<path> 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<path> 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<path> GetFileList(path dir, bool recursive, regex matchExp) {
    vector<path> 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<path> 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<char> 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());
}

Dies ist die C # -Version. Genießen Sie ...

 
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<String> 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<String> GetAllDirectories(String dir)
        {
            DirectoryInfo di = new DirectoryInfo(dir);
            Console.WriteLine(dir);

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

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

Wie bereits angedeutet, sollten Sie auf Property Sheets aussehen (aka .vsprops-Dateien).
Ich schrieb eine sehr kurze Einführung in diese Funktion .

Ja, ich würde auf jeden Fall empfehlen die Verwendung CMake . CMake ist das beste Werkzeug (ich glaube, ich habe sie wirklich versucht alle), die Studio-Projektdateien erzeugen kann.

Ich hatte auch die Frage der Umwandlung bestehende VCPROJ Dateien in CMakeLists.txt, und ich schrieb einen Rubin -script , die sich um den größten Teil der Umwandlung stattfindet. Das Skript verarbeitet nicht Dinge wie Post-Build-Schritte und so, so dass einige Optimierungen notwendig ist, aber es wird Ihnen die Mühe sparen alle Quelldateinamen aus den VCPROJ Dateien zu ziehen.

*. Vcxproj Dateien sind msbuild Dateien. So nehmen Sie nur eine Eigenschaft, die Sie wollen nicht in allen Projektdateien und löschen. Dann legen Sie es in Ihrem Eigenschaftsblatt. Dann stellen Sie sicher, alle Projekte richtig, dass die Karteikarte Dateien importieren.

Das kann unglaublich langweilig sein für Hunderte von Dateien. Ich schrieb ein Werkzeug macht diese interaktiv:

https://github.com/chris1248/MsbuildRefactor

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top