tutorial - Visual Studio Solutions/Proyecto múltiple: cómo propagar de manera efectiva las propiedades de proyectos entre varios proyectos de C++
visual studio code ejemplos (5)
Estoy trabajando con una solución Visual Studio 2005 C ++ que incluye múltiples proyectos (alrededor de 30). En función de mi experiencia, a menudo resulta molesto mantener todas las propiedades de los proyectos (es decir, incluir ruta, vía de acceso lib, bibliotecas vinculadas, opciones de generación de código, ...), ya que a menudo tiene que hacer clic en cada proyecto para modificarlos La situación se vuelve aún peor cuando tiene múltiples configuraciones (depurar, liberar, liberar 64 bits, ...).
Ejemplos de vida real:
- Suponga que desea usar una nueva biblioteca, y necesita agregar la ruta de inclusión a esta biblioteca para todos los proyectos. ¿Cómo evitará tener que editar las propiedades de cada uno de cada proyecto?
- Supongamos que desea probar una nueva versión de la biblioteca (por ejemplo, la versión 2.1beta), de modo que necesita cambiar rápidamente las rutas de acceso include / biblioteca / biblioteca enlazada para un conjunto de proyectos.
Notas:
- Soy consciente de que es posible seleccionar varios proyectos a la vez, luego hago clic con el botón derecho y selecciono "propiedades". Sin embargo, este método solo funciona para propiedades que ya eran exactamente idénticas para los diferentes proyectos: no se puede usar para agregar una ruta de inclusión a un conjunto de proyectos que usaban diferentes rutas de inclusión.
- También sé que es posible modificar globalmente las opciones de entorno (Herramientas / Opciones / Proyecto Y soluciones / Directorios), sin embargo, no es tan satisfactorio, ya que no se puede integrar en un SCM.
- También sé que uno puede agregar "Configuraciones" a una solución. No ayuda, ya que crea otro conjunto de propiedades de proyecto para mantener
- Sé que Codegear C ++ Builder 2009 ofrece una respuesta viable a esta necesidad a través de los llamados "conjuntos de opciones" que pueden ser heredados por varios proyectos (utilizo Visual Studio y C ++ Builder, y todavía creo que C ++ Builder depende de ciertos aspectos en comparación a Visual Studio)
- Espero que alguien sugiera un "autconf" como CMake, sin embargo, ¿es posible importar archivos vcproj en dicha herramienta?
Como se sugiere, debería mirar las Hojas de propiedades (también conocidas como archivos .vsprops).
Escribí una breve introducción a esta característica aquí .
Sí, definitivamente sugeriría usar CMake . CMake es la mejor herramienta (creo que en realidad los he probado todos) y puede generar archivos de proyectos de Studio.
También tuve el problema de convertir archivos .vcproj existentes en CMakeLists.txt, y escribí un script de Ruby que se encarga de la mayor parte de la conversión. El script no maneja cosas como los pasos de post-compilación y demás, por lo que es necesario realizar ciertos ajustes, pero le ahorrará la molestia de extraer todos los nombres de los archivos de origen de los archivos .vcproj.
A menudo necesito hacer algo similar ya que me enlace a las bibliotecas de tiempo de ejecución estáticas. Escribí un programa para hacerlo por mí. Básicamente escanea todos los subdirectorios de cualquier ruta que le des e identifica cualquier archivo .vcproj que encuentre. Luego, uno a uno, los abre y los modifica y los guarda. Como solo lo uso en raras ocasiones, el camino está codificado, pero creo que podrás ajustarlo como quieras.
Otro enfoque es darse cuenta de que los archivos de Visual Studio Project son simplemente archivos XML y se pueden manipular con su clase XML favorita. He hecho algo con XmlDocument
C # para actualizar los directorios de inclusión cuando había XmlDocument
directorios de inclusión en los que no quería escribir. :)
Estoy incluyendo ambos ejemplos. Tendrá que modificarlos según sus propias necesidades, pero esto debería ayudarlo a comenzar.
Esta es la versión de C ++:
#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());
}
Esta es la versión de C #. Disfrutar...
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;
}
}
}
Creo que debe investigar los archivos de propiedades, es decir, * .vsprops (más antiguo) o * .props (último)
Necesita agregar manualmente el archivo de propiedades a cada proyecto, pero una vez hecho esto, tiene varios proyectos, pero uno. [Vs] props file. Si cambia las propiedades, todos los proyectos heredan la nueva configuración.
* Los archivos .vcxproj son archivos msbuild. Así que solo toma una propiedad que no desea en todos sus archivos de proyecto y la elimina. Luego póngalo en su hoja de propiedades. Luego, asegúrese de que todos los archivos de proyectos importen correctamente esa hoja de propiedades.
Esto puede ser increíblemente tedioso para cientos de archivos. Escribí una herramienta para hacer esto interactivo: