/****************************************************************************
|
**
|
** Copyright (C) 2016 The Qt Company Ltd.
|
** Contact: https://www.qt.io/licensing/
|
**
|
** This file is part of the Qt VS Tools.
|
**
|
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
** Commercial License Usage
|
** Licensees holding valid commercial Qt licenses may use this file in
|
** accordance with the commercial license agreement provided with the
|
** Software or, alternatively, in accordance with the terms contained in
|
** a written agreement between you and The Qt Company. For licensing terms
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
** information use the contact form at https://www.qt.io/contact-us.
|
**
|
** GNU General Public License Usage
|
** Alternatively, this file may be used under the terms of the GNU
|
** General Public License version 3 as published by the Free Software
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
** included in the packaging of this file. Please review the following
|
** information to ensure the GNU General Public License requirements will
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
**
|
** $QT_END_LICENSE$
|
**
|
****************************************************************************/
|
|
using EnvDTE;
|
using Microsoft.VisualStudio.VCProjectEngine;
|
using System;
|
using System.Collections.Concurrent;
|
using System.Collections.Generic;
|
using System.IO;
|
using System.Linq;
|
using System.Text;
|
using System.Text.RegularExpressions;
|
using System.Threading.Tasks;
|
using System.Windows.Forms;
|
using System.Xml;
|
using QtVsTools.Core.QtMsBuild;
|
|
namespace QtVsTools.Core
|
{
|
/// <summary>
|
/// QtProject holds the Qt specific properties for a Visual Studio project.
|
/// There exists at most one QtProject per EnvDTE.Project.
|
/// Use QtProject.Create to get the QtProject for a Project or VCProject.
|
/// </summary>
|
public class QtProject
|
{
|
private DTE dte;
|
private Project envPro;
|
private VCProject vcPro;
|
private MocCmdChecker mocCmdChecker;
|
private Array lastConfigurationRowNames;
|
private static Dictionary<Project, QtProject> instances = new Dictionary<Project, QtProject>();
|
private QtMsBuildContainer qtMsBuild;
|
|
public static QtVsTools.VisualStudio.IProjectTracker ProjectTracker { get; set; }
|
|
public static QtProject Create(VCProject vcProject)
|
{
|
return Create((Project)vcProject.Object);
|
}
|
|
public static QtProject Create(Project project)
|
{
|
QtProject qtProject = null;
|
if (project != null && !instances.TryGetValue(project, out qtProject)) {
|
qtProject = new QtProject(project);
|
instances.Add(project, qtProject);
|
}
|
return qtProject;
|
}
|
|
public static void ClearInstances()
|
{
|
instances.Clear();
|
}
|
|
private QtProject(Project project)
|
{
|
if (project == null)
|
throw new QtVSException(SR.GetString("QtProject_CannotConstructWithoutValidProject"));
|
envPro = project;
|
dte = envPro.DTE;
|
vcPro = envPro.Object as VCProject;
|
qtMsBuild = new QtMsBuildContainer(new VCPropertyStorageProvider());
|
}
|
|
public VCProject VCProject
|
{
|
get { return vcPro; }
|
}
|
|
public Project Project
|
{
|
get { return envPro; }
|
}
|
|
public static string GetRuleName(VCConfiguration config, string itemType)
|
{
|
if (config == null)
|
return string.Empty;
|
try {
|
return config.GetEvaluatedPropertyValue(itemType + "RuleName");
|
} catch (Exception e) {
|
System.Diagnostics.Debug.WriteLine(
|
e.Message + "\r\n\r\nStacktrace:\r\n" + e.StackTrace);
|
return string.Empty;
|
}
|
}
|
|
public static string GetRuleName(VCProject project, string itemType)
|
{
|
if (project == null)
|
return string.Empty;
|
var configs = project.Configurations as IVCCollection;
|
if (configs.Count == 0)
|
return string.Empty;
|
try {
|
var firstConfig = configs.Item(1) as VCConfiguration;
|
if (firstConfig == null)
|
return string.Empty;
|
return GetRuleName(firstConfig, itemType);
|
} catch (Exception e) {
|
System.Diagnostics.Debug.WriteLine(
|
e.Message + "\r\n\r\nStacktrace:\r\n" + e.StackTrace);
|
return string.Empty;
|
}
|
}
|
|
public string GetRuleName(string itemType)
|
{
|
return GetRuleName(vcPro, itemType);
|
}
|
|
public static bool IsQtMsBuildEnabled(VCProject project)
|
{
|
if (project == null)
|
return false;
|
try {
|
var configs = project.Configurations as IVCCollection;
|
if (configs.Count == 0)
|
return false;
|
var firstConfig = configs.Item(1) as VCConfiguration;
|
var ruleName = GetRuleName(firstConfig, QtMoc.ItemTypeName);
|
var qtMoc = firstConfig.Rules.Item(ruleName) as IVCRulePropertyStorage;
|
if (qtMoc == null)
|
return false;
|
} catch (Exception) {
|
return false;
|
}
|
return true;
|
}
|
|
public static bool IsQtMsBuildEnabled(Project project)
|
{
|
if (project == null)
|
return false;
|
return IsQtMsBuildEnabled(project.Object as VCProject);
|
}
|
|
private bool? isQtMsBuildEnabled = null;
|
public bool IsQtMsBuildEnabled()
|
{
|
if (!isQtMsBuildEnabled.HasValue) {
|
if (vcPro != null)
|
isQtMsBuildEnabled = IsQtMsBuildEnabled(vcPro);
|
else if (envPro != null)
|
isQtMsBuildEnabled = IsQtMsBuildEnabled(envPro);
|
else
|
return false;
|
}
|
return isQtMsBuildEnabled.Value;
|
}
|
|
public string ProjectDir
|
{
|
get
|
{
|
return vcPro.ProjectDirectory;
|
}
|
}
|
|
/// <summary>
|
/// Returns true if the ConfigurationRowNames have changed
|
/// since the last evaluation of this property.
|
/// </summary>
|
public bool ConfigurationRowNamesChanged
|
{
|
get
|
{
|
var ret = false;
|
if (lastConfigurationRowNames == null) {
|
lastConfigurationRowNames = envPro.ConfigurationManager.ConfigurationRowNames as Array;
|
} else {
|
var currentConfigurationRowNames = envPro.ConfigurationManager.ConfigurationRowNames as Array;
|
if (!HelperFunctions.ArraysEqual(lastConfigurationRowNames, currentConfigurationRowNames)) {
|
lastConfigurationRowNames = currentConfigurationRowNames;
|
ret = true;
|
}
|
}
|
return ret;
|
}
|
}
|
|
/// <summary>
|
/// Returns the file name of the generated ui header file relative to
|
/// the project directory.
|
/// </summary>
|
/// <param name="uiFile">name of the ui file</param>
|
public string GetUiGeneratedFileName(string uiFile)
|
{
|
var fi = new FileInfo(uiFile);
|
var file = fi.Name;
|
if (HelperFunctions.IsUicFile(file)) {
|
return QtVSIPSettings.GetUicDirectory(envPro)
|
+ "\\ui_" + file.Remove(file.Length - 3, 3) + ".h";
|
}
|
return null;
|
}
|
|
/// <summary>
|
/// Returns the moc-generated file name for the given source or header file.
|
/// </summary>
|
/// <param name="file">header or source file in the project</param>
|
/// <returns></returns>
|
private static string GetMocFileName(string file)
|
{
|
var fi = new FileInfo(file);
|
|
var name = fi.Name;
|
if (HelperFunctions.IsHeaderFile(fi.Name))
|
return "moc_" + name.Substring(0, name.LastIndexOf('.')) + ".cpp";
|
if (HelperFunctions.IsSourceFile(fi.Name))
|
return name.Substring(0, name.LastIndexOf('.')) + ".moc";
|
return null;
|
}
|
|
/// <summary>
|
/// Returns the file name of the generated moc file relative to the
|
/// project directory.
|
/// </summary>
|
/// The directory of the moc file depends on the file configuration.
|
/// Every appearance of "$(ConfigurationName)" in the path will be
|
/// replaced by the value of configName.
|
/// <param name="file">full file name of either the header or the source file</param>
|
/// <returns></returns>
|
private string GetRelativeMocFilePath(string file, string configName, string platformName)
|
{
|
var fileName = GetMocFileName(file);
|
if (fileName == null)
|
return null;
|
var mocDir = QtVSIPSettings.GetMocDirectory(envPro, configName, platformName, file)
|
+ "\\" + fileName;
|
if (HelperFunctions.IsAbsoluteFilePath(mocDir))
|
mocDir = HelperFunctions.GetRelativePath(vcPro.ProjectDirectory, mocDir);
|
return mocDir;
|
}
|
|
/// <summary>
|
/// Returns the file name of the generated moc file relative to the
|
/// project directory.
|
/// </summary>
|
/// The returned file path may contain the macros $(ConfigurationName) and $(PlatformName).
|
/// <param name="file">full file name of either the header or the source file</param>
|
/// <returns></returns>
|
private string GetRelativeMocFilePath(string file)
|
{
|
return GetRelativeMocFilePath(file, null, null);
|
}
|
|
/// <summary>
|
/// Marks the specified project as a Qt project.
|
/// </summary>
|
public void MarkAsQtProject()
|
{
|
vcPro.keyword = string.Format("{0}_v{1}",
|
Resources.qtProjectKeyword, Resources.qtProjectFormatVersion);
|
}
|
|
public static int GetFormatVersion(VCProject vcPro)
|
{
|
if (vcPro == null)
|
return 0;
|
if (vcPro.keyword.StartsWith(Resources.qtProjectKeyword,
|
StringComparison.InvariantCultureIgnoreCase)) {
|
return Convert.ToInt32(vcPro.keyword.Substring(6));
|
} else if (vcPro.keyword.StartsWith(Resources.qtProjectV2Keyword,
|
StringComparison.InvariantCultureIgnoreCase)) {
|
return 200;
|
} else {
|
return 0;
|
}
|
}
|
|
public static int GetFormatVersion(Project pro)
|
{
|
if (pro == null)
|
return 0;
|
return GetFormatVersion(pro.Object as VCProject);
|
}
|
|
public int FormatVersion { get { return GetFormatVersion(Project); } }
|
|
public string GetPropertyValue(string propName)
|
{
|
return GetPropertyValue(Project, propName);
|
}
|
|
public string GetPropertyValue(string configName, string platformName, string propName)
|
{
|
return GetPropertyValue(Project, configName, platformName, propName);
|
}
|
|
public static string GetPropertyValue(
|
EnvDTE.Project dteProject,
|
string propName)
|
{
|
var activeConfig = dteProject.ConfigurationManager?.ActiveConfiguration;
|
if (activeConfig == null)
|
return null;
|
return GetPropertyValue(
|
dteProject, activeConfig, propName);
|
}
|
|
public static string GetPropertyValue(
|
EnvDTE.Project dteProject,
|
EnvDTE.Configuration dteConfig,
|
string propName)
|
{
|
if (dteProject == null || dteConfig == null)
|
return null;
|
return GetPropertyValue(
|
dteProject.Object as VCProject,
|
dteConfig.ConfigurationName,
|
dteConfig.PlatformName,
|
propName);
|
}
|
|
public static string GetPropertyValue(
|
EnvDTE.Project dteProject,
|
string configName,
|
string platformName,
|
string propName)
|
{
|
return GetPropertyValue(
|
dteProject.Object as VCProject, configName, platformName, propName);
|
}
|
|
public static string GetPropertyValue(
|
VCProject vcProject,
|
string configName,
|
string platformName,
|
string propName)
|
{
|
var vcConfigs = vcProject.Configurations as IVCCollection;
|
if (vcConfigs == null)
|
return null;
|
var configId = string.Format("{0}|{1}",
|
configName, platformName);
|
var vcConfig = vcConfigs.Item(configId) as VCConfiguration;
|
if (vcConfig == null)
|
return null;
|
return GetPropertyValue(vcConfig, propName);
|
}
|
|
public static string GetPropertyValue(
|
VCConfiguration vcConfig,
|
string propName)
|
{
|
return vcConfig.GetEvaluatedPropertyValue(propName);
|
}
|
|
public void AddDefine(string define, uint bldConf)
|
{
|
foreach (VCConfiguration config in (IVCCollection)vcPro.Configurations) {
|
var compiler = CompilerToolWrapper.Create(config);
|
|
if (((!IsDebugConfiguration(config)) && ((bldConf & BuildConfig.Release) != 0)) ||
|
((IsDebugConfiguration(config)) && ((bldConf & BuildConfig.Debug) != 0))) {
|
compiler.AddPreprocessorDefinition(define);
|
}
|
}
|
}
|
|
public void AddModule(int id)
|
{
|
if (HasModule(id))
|
return;
|
|
var vm = QtVersionManager.The();
|
var versionInfo = vm.GetVersionInfo(Project);
|
if (versionInfo == null)
|
versionInfo = vm.GetVersionInfo(vm.GetDefaultVersion());
|
|
foreach (VCConfiguration config in (IVCCollection)vcPro.Configurations) {
|
|
var info = QtModules.Instance.Module(id);
|
if (FormatVersion >= Resources.qtMinFormatVersion_Settings) {
|
var config3 = config as VCConfiguration3;
|
if (config3 == null)
|
continue;
|
if (!string.IsNullOrEmpty(info.proVarQT)) {
|
var qtModulesValue = config.GetUnevaluatedPropertyValue("QtModules");
|
var qtModules = new HashSet<string>(
|
!string.IsNullOrEmpty(qtModulesValue)
|
? qtModulesValue.Split(';')
|
: new string[] { });
|
qtModules.UnionWith(info.proVarQT.Split(' '));
|
config3.SetPropertyValue(Resources.projLabelQtSettings, true,
|
"QtModules", string.Join(";", qtModules));
|
}
|
// In V3 project format, compiler and linker options
|
// required by modules are set by Qt/MSBuild.
|
continue;
|
}
|
|
var compiler = CompilerToolWrapper.Create(config);
|
var linker = (VCLinkerTool)((IVCCollection)config.Tools).Item("VCLinkerTool");
|
|
if (compiler != null) {
|
foreach (var define in info.Defines)
|
compiler.AddPreprocessorDefinition(define);
|
|
var incPathList = info.GetIncludePath();
|
foreach (var incPath in incPathList)
|
compiler.AddAdditionalIncludeDirectories(incPath);
|
}
|
if (linker != null) {
|
var moduleLibs = info.GetLibs(IsDebugConfiguration(config), versionInfo);
|
var linkerWrapper = new LinkerToolWrapper(linker);
|
var additionalDeps = linkerWrapper.AdditionalDependencies;
|
var dependenciesChanged = false;
|
if (additionalDeps == null || additionalDeps.Count == 0) {
|
additionalDeps = moduleLibs;
|
dependenciesChanged = true;
|
} else {
|
foreach (var moduleLib in moduleLibs) {
|
if (!additionalDeps.Contains(moduleLib)) {
|
additionalDeps.Add(moduleLib);
|
dependenciesChanged = true;
|
}
|
}
|
}
|
if (dependenciesChanged)
|
linkerWrapper.AdditionalDependencies = additionalDeps;
|
}
|
}
|
}
|
|
public void RemoveModule(int id)
|
{
|
foreach (VCConfiguration config in (IVCCollection)vcPro.Configurations) {
|
var compiler = CompilerToolWrapper.Create(config);
|
var linker = (VCLinkerTool)((IVCCollection)config.Tools).Item("VCLinkerTool");
|
|
var info = QtModules.Instance.Module(id);
|
if (compiler != null) {
|
foreach (var define in info.Defines)
|
compiler.RemovePreprocessorDefinition(define);
|
var additionalIncludeDirs = compiler.AdditionalIncludeDirectories;
|
if (additionalIncludeDirs != null) {
|
var lst = new List<string>(additionalIncludeDirs);
|
foreach (var includePath in info.IncludePath) {
|
lst.Remove(includePath);
|
lst.Remove('\"' + includePath + '\"');
|
}
|
compiler.AdditionalIncludeDirectories = lst;
|
}
|
}
|
if (linker != null && linker.AdditionalDependencies != null) {
|
var linkerWrapper = new LinkerToolWrapper(linker);
|
var vm = QtVersionManager.The();
|
var versionInfo = vm.GetVersionInfo(Project);
|
if (versionInfo == null)
|
versionInfo = vm.GetVersionInfo(vm.GetDefaultVersion());
|
|
var moduleLibs = info.GetLibs(IsDebugConfiguration(config), versionInfo);
|
var additionalDependencies = linkerWrapper.AdditionalDependencies;
|
var dependenciesChanged = false;
|
foreach (var moduleLib in moduleLibs)
|
dependenciesChanged |= additionalDependencies.Remove(moduleLib);
|
if (dependenciesChanged)
|
linkerWrapper.AdditionalDependencies = additionalDependencies;
|
}
|
}
|
}
|
|
public void UpdateModules(VersionInformation oldVersion, VersionInformation newVersion)
|
{
|
foreach (VCConfiguration config in (IVCCollection)vcPro.Configurations) {
|
var linker = (VCLinkerTool)((IVCCollection)config.Tools).Item("VCLinkerTool");
|
|
if (linker != null) {
|
if (oldVersion == null) {
|
var linkerWrapper = new LinkerToolWrapper(linker);
|
var additionalDependencies = linkerWrapper.AdditionalDependencies;
|
|
var libsDesktop = new List<string>();
|
foreach (var module in QtModules.Instance.GetAvailableModules()) {
|
if (HasModule(module.Id))
|
libsDesktop.AddRange(module.AdditionalLibraries);
|
}
|
var libsToAdd = libsDesktop;
|
|
var changed = false;
|
foreach (var libToAdd in libsToAdd) {
|
if (!additionalDependencies.Contains(libToAdd)) {
|
additionalDependencies.Add(libToAdd);
|
changed = true;
|
}
|
}
|
if (changed)
|
linkerWrapper.AdditionalDependencies = additionalDependencies;
|
}
|
|
if (newVersion.qtMajor >= 5) {
|
var compiler = CompilerToolWrapper.Create(config);
|
if (compiler != null)
|
compiler.RemovePreprocessorDefinition("QT_DLL");
|
continue;
|
}
|
|
if (oldVersion == null || newVersion.IsStaticBuild() != oldVersion.IsStaticBuild()) {
|
var compiler = CompilerToolWrapper.Create(config);
|
if (newVersion.IsStaticBuild()) {
|
if (compiler != null)
|
compiler.RemovePreprocessorDefinition("QT_DLL");
|
} else {
|
if (compiler != null)
|
compiler.AddPreprocessorDefinition("QT_DLL");
|
}
|
}
|
}
|
}
|
}
|
|
public bool HasModule(int id)
|
{
|
var foundInIncludes = false;
|
var foundInLibs = false;
|
|
var vm = QtVersionManager.The();
|
var versionInfo = vm.GetVersionInfo(Project);
|
if (versionInfo == null)
|
versionInfo = vm.GetVersionInfo(vm.GetDefaultVersion());
|
if (versionInfo == null)
|
return false; // neither a default or project Qt version
|
var info = QtModules.Instance.Module(id);
|
if (info == null)
|
return false;
|
|
foreach (VCConfiguration config in (IVCCollection)vcPro.Configurations) {
|
var compiler = CompilerToolWrapper.Create(config);
|
var linker = (VCLinkerTool)((IVCCollection)config.Tools).Item("VCLinkerTool");
|
|
if (compiler != null) {
|
if (compiler.GetAdditionalIncludeDirectories() == null)
|
continue;
|
var incPathList = info.GetIncludePath();
|
var includeDirs = compiler.GetAdditionalIncludeDirectoriesList();
|
foundInIncludes = (incPathList.Count > 0);
|
foreach (var incPath in incPathList) {
|
var fixedIncludeDir = FixFilePathForComparison(incPath);
|
if (!includeDirs.Any(dir =>
|
FixFilePathForComparison(dir) == fixedIncludeDir)) {
|
foundInIncludes = false;
|
break;
|
}
|
}
|
}
|
|
if (foundInIncludes)
|
break;
|
|
List<string> libs = null;
|
if (linker != null) {
|
var linkerWrapper = new LinkerToolWrapper(linker);
|
libs = linkerWrapper.AdditionalDependencies;
|
}
|
|
if (libs != null) {
|
var moduleLibs = info.GetLibs(IsDebugConfiguration(config), versionInfo);
|
foundInLibs = moduleLibs.All(moduleLib => libs.Contains(moduleLib));
|
}
|
}
|
return foundInIncludes || foundInLibs;
|
}
|
|
public void WriteProjectBasicConfigurations(uint type, bool usePrecompiledHeader)
|
{
|
WriteProjectBasicConfigurations(type, usePrecompiledHeader, null);
|
}
|
|
public void WriteProjectBasicConfigurations(uint type, bool usePrecompiledHeader, VersionInformation vi)
|
{
|
var configType = ConfigurationTypes.typeApplication;
|
var targetExtension = ".exe";
|
string qtVersion = null;
|
var vm = QtVersionManager.The();
|
if (vi == null) {
|
qtVersion = vm.GetDefaultVersion();
|
vi = vm.GetVersionInfo(qtVersion);
|
}
|
|
switch (type & TemplateType.ProjectType) {
|
case TemplateType.DynamicLibrary:
|
configType = ConfigurationTypes.typeDynamicLibrary;
|
targetExtension = ".dll";
|
break;
|
case TemplateType.StaticLibrary:
|
configType = ConfigurationTypes.typeStaticLibrary;
|
targetExtension = ".lib";
|
break;
|
}
|
|
foreach (VCConfiguration config in (IVCCollection)vcPro.Configurations) {
|
config.ConfigurationType = configType;
|
var compiler = CompilerToolWrapper.Create(config);
|
var linker = (VCLinkerTool)((IVCCollection)config.Tools).Item("VCLinkerTool");
|
var librarian = (VCLibrarianTool)((IVCCollection)config.Tools).Item("VCLibrarianTool");
|
|
if (linker != null) {
|
if ((type & TemplateType.ConsoleSystem) != 0)
|
linker.SubSystem = subSystemOption.subSystemConsole;
|
else
|
linker.SubSystem = subSystemOption.subSystemWindows;
|
|
linker.OutputFile = "$(OutDir)\\$(ProjectName)" + targetExtension;
|
} else {
|
librarian.OutputFile = "$(OutDir)\\$(ProjectName)" + targetExtension;
|
}
|
|
if ((type & TemplateType.PluginProject) != 0)
|
compiler.AddPreprocessorDefinition("QT_PLUGIN");
|
|
var isDebugConfiguration = false;
|
if (config.Name.StartsWith("Release", StringComparison.Ordinal)) {
|
compiler.SetDebugInformationFormat(debugOption.debugDisabled);
|
compiler.RuntimeLibrary = runtimeLibraryOption.rtMultiThreadedDLL;
|
} else if (config.Name.StartsWith("Debug", StringComparison.Ordinal)) {
|
isDebugConfiguration = true;
|
compiler.SetOptimization(optimizeOption.optimizeDisabled);
|
compiler.SetDebugInformationFormat(debugOption.debugEnabled);
|
compiler.RuntimeLibrary = runtimeLibraryOption.rtMultiThreadedDebugDLL;
|
}
|
|
compiler.SetTreatWChar_tAsBuiltInType(true);
|
|
if (linker != null)
|
linker.GenerateDebugInformation = isDebugConfiguration;
|
|
if (usePrecompiledHeader)
|
UsePrecompiledHeaders(config);
|
}
|
if ((type & TemplateType.PluginProject) != 0)
|
MarkAsDesignerPluginProject();
|
}
|
|
public void MarkAsDesignerPluginProject()
|
{
|
Project.Globals["IsDesignerPlugin"] = true.ToString();
|
if (!Project.Globals.get_VariablePersists("IsDesignerPlugin"))
|
Project.Globals.set_VariablePersists("IsDesignerPlugin", true);
|
}
|
|
public void AddUic4BuildStepMsBuild(
|
VCFileConfiguration config,
|
string description,
|
string outputFile)
|
{
|
var file = config.File as VCFile;
|
if (file != null)
|
file.ItemType = QtUic.ItemTypeName;
|
qtMsBuild.SetItemProperty(config, QtUic.Property.ExecutionDescription, description);
|
qtMsBuild.SetItemProperty(config, QtUic.Property.OutputFile, outputFile);
|
}
|
|
public void AddUic4BuildStepCustomBuild(
|
VCFileConfiguration config,
|
string description,
|
string outputFile)
|
{
|
//SetItemType(config, ItemType.CustomBuild);
|
var tool = HelperFunctions.GetCustomBuildTool(config);
|
if (tool != null) {
|
tool.AdditionalDependencies = Resources.uic4Command;
|
tool.Description = description;
|
tool.Outputs = "\"" + outputFile + "\"";
|
tool.CommandLine = "\"" + Resources.uic4Command + "\" -o \""
|
+ outputFile + "\" \"" + ProjectMacros.Path + "\"";
|
}
|
}
|
|
/// <summary>
|
/// This function adds a uic4 build step to a given file.
|
/// </summary>
|
/// <param name="file">file</param>
|
public void AddUic4BuildStep(VCFile file)
|
{
|
if (GetFormatVersion(vcPro) >= Resources.qtMinFormatVersion_Settings) {
|
file.ItemType = QtUic.ItemTypeName;
|
return;
|
}
|
|
CustomTool toolSettings =
|
IsQtMsBuildEnabled() ? CustomTool.MSBuildTarget : CustomTool.CustomBuildStep;
|
|
try {
|
var uiFile = GetUiGeneratedFileName(file.FullPath);
|
var uiBaseName = file.Name.Remove(file.Name.LastIndexOf('.'));
|
var uiFileMacro = uiFile.Replace(uiBaseName, ProjectMacros.Name);
|
var uiFileExists = GetFileFromProject(uiFile) != null;
|
string description = "Uic'ing " + ProjectMacros.FileName + "...";
|
|
foreach (VCFileConfiguration config in (IVCCollection)file.FileConfigurations) {
|
|
switch (toolSettings) {
|
case CustomTool.MSBuildTarget:
|
AddUic4BuildStepMsBuild(config, description, uiFileMacro);
|
break;
|
default:
|
AddUic4BuildStepCustomBuild(config, description, uiFileMacro);
|
break;
|
}
|
|
var conf = config.ProjectConfiguration as VCConfiguration;
|
var compiler = CompilerToolWrapper.Create(conf);
|
if (compiler != null && !uiFileExists) {
|
var uiDir = QtVSIPSettings.GetUicDirectory(envPro);
|
if (compiler.GetAdditionalIncludeDirectories().IndexOf(uiDir, StringComparison.Ordinal) < 0)
|
compiler.AddAdditionalIncludeDirectories(uiDir);
|
}
|
}
|
if (toolSettings == CustomTool.CustomBuildStep && !uiFileExists)
|
AddFileInFilter(Filters.GeneratedFiles(), uiFile);
|
} catch {
|
throw new QtVSException(SR.GetString("QtProject_CannotAddUicStep", file.FullPath));
|
}
|
}
|
|
/// <summary>
|
/// Surrounds the argument by double quotes.
|
/// Makes sure, that the trailing double quote is not escaped by a backslash.
|
/// Escapes all quotation mark characters in the argument
|
///
|
/// This must follow the format recognized by CommandLineToArgvW:
|
/// (https://docs.microsoft.com/en-us/windows/desktop/api/shellapi/nf-shellapi-commandlinetoargvw)
|
///
|
/// CommandLineToArgvW has a special interpretation of backslash characters when they are
|
/// followed by a quotation mark character ("). This interpretation assumes that any
|
/// preceding argument is a valid file system path, or else it may behave unpredictably.
|
///
|
/// This special interpretation controls the "in quotes" mode tracked by the parser. When
|
/// this mode is off, whitespace terminates the current argument. When on, whitespace is
|
/// added to the argument like all other characters.
|
///
|
/// * 2n backslashes followed by a quotation mark produce n backslashes followed by
|
/// begin/end quote. This does not become part of the parsed argument, but toggles the
|
/// "in quotes" mode.
|
///
|
/// * (2n) + 1 backslashes followed by a quotation mark again produce n backslashes
|
/// followed by a quotation mark literal ("). This does not toggle the "in quotes" mode.
|
///
|
/// * n backslashes not followed by a quotation mark simply produce n backslashes.
|
///
|
/// </summary>
|
private static string SafelyQuoteCommandLineArgument(string arg)
|
{
|
var quotedArg = new StringBuilder();
|
quotedArg.Append("\"");
|
|
// Split argument by quotation mark characters
|
// All argument parts except the last are followed by a quotation mark character
|
var argParts = arg.Split(new char[] { '\"' });
|
for (int i = 0; i < argParts.Length; ++i) {
|
var part = argParts[i];
|
quotedArg.Append(part);
|
|
// Duplicate backslashes immediately preceding quotation mark character
|
if (part.EndsWith("\\"))
|
quotedArg.Append(part.Reverse().TakeWhile(c => c == '\\').ToArray());
|
|
// Escape all quotation mark characters in argument
|
if (i < argParts.Length - 1)
|
quotedArg.Append("\\\"");
|
}
|
|
quotedArg.Append("\"");
|
return quotedArg.ToString();
|
}
|
|
public string GetDefines(VCFileConfiguration conf)
|
{
|
var defines = string.Empty;
|
var propsFile = conf.Tool as IVCRulePropertyStorage;
|
var projectConfig = conf.ProjectConfiguration as VCConfiguration;
|
var propsProject = projectConfig.Rules.Item("CL") as IVCRulePropertyStorage;
|
if (propsFile != null) {
|
try {
|
defines = propsFile.GetUnevaluatedPropertyValue("PreprocessorDefinitions");
|
} catch { }
|
}
|
if (string.IsNullOrEmpty(defines) && propsProject != null) {
|
try {
|
defines = propsProject.GetUnevaluatedPropertyValue("PreprocessorDefinitions");
|
} catch { }
|
}
|
|
if (string.IsNullOrEmpty(defines))
|
return string.Empty;
|
|
var defineList = defines.Split(
|
new char[] { ';' },
|
StringSplitOptions.RemoveEmptyEntries)
|
.ToList();
|
|
var preprocessorDefines = string.Empty;
|
var alreadyAdded = new List<string>();
|
var rxp = new Regex(@"\s|(\$\()");
|
foreach (var define in defineList) {
|
if (!alreadyAdded.Contains(define)) {
|
var mustSurroundByDoubleQuotes = rxp.IsMatch(define);
|
// Yes, a preprocessor definition can contain spaces or a macro name.
|
// Example: PROJECTDIR=$(InputDir)
|
|
if (mustSurroundByDoubleQuotes) {
|
preprocessorDefines += " ";
|
preprocessorDefines += SafelyQuoteCommandLineArgument("-D" + define);
|
} else {
|
preprocessorDefines += " -D" + define;
|
}
|
alreadyAdded.Add(define);
|
}
|
}
|
return preprocessorDefines;
|
}
|
|
private string GetIncludes(VCFileConfiguration conf)
|
{
|
var includeList = GetIncludesFromCompilerTool(CompilerToolWrapper.Create(conf));
|
|
var projectConfig = conf.ProjectConfiguration as VCConfiguration;
|
includeList.AddRange(GetIncludesFromCompilerTool(CompilerToolWrapper.Create(projectConfig)));
|
|
var propertySheets = projectConfig.PropertySheets as IVCCollection;
|
if (propertySheets != null) {
|
foreach (VCPropertySheet sheet in propertySheets)
|
includeList.AddRange(GetIncludesFromPropertySheet(sheet));
|
}
|
|
var includes = string.Empty;
|
var alreadyAdded = new List<string>();
|
foreach (var include in includeList) {
|
if (!alreadyAdded.Contains(include)) {
|
var incl = HelperFunctions.NormalizeRelativeFilePath(include);
|
if (incl.Length > 0)
|
includes += " " + SafelyQuoteCommandLineArgument("-I" + incl);
|
alreadyAdded.Add(include);
|
}
|
}
|
return includes;
|
}
|
|
private List<string> GetIncludesFromPropertySheet(VCPropertySheet sheet)
|
{
|
var includeList = GetIncludesFromCompilerTool(CompilerToolWrapper.Create(sheet));
|
var propertySheets = sheet.PropertySheets as IVCCollection;
|
if (propertySheets != null) {
|
foreach (VCPropertySheet subSheet in propertySheets)
|
includeList.AddRange(GetIncludesFromPropertySheet(subSheet));
|
}
|
return includeList;
|
}
|
|
private static List<string> GetIncludesFromCompilerTool(CompilerToolWrapper compiler)
|
{
|
try {
|
if (!string.IsNullOrEmpty(compiler.GetAdditionalIncludeDirectories())) {
|
var includes = compiler.GetAdditionalIncludeDirectoriesList();
|
return new List<string>(includes);
|
}
|
} catch { }
|
return new List<string>();
|
}
|
|
private static bool IsDebugConfiguration(VCConfiguration conf)
|
{
|
var tool = CompilerToolWrapper.Create(conf);
|
if (tool != null) {
|
return tool.RuntimeLibrary == runtimeLibraryOption.rtMultiThreadedDebug
|
|| tool.RuntimeLibrary == runtimeLibraryOption.rtMultiThreadedDebugDLL;
|
}
|
return false;
|
}
|
|
private string GetPCHMocOptions(VCFile file, CompilerToolWrapper compiler)
|
{
|
// As .moc files are included, we should not add anything there
|
if (!HelperFunctions.IsHeaderFile(file.Name))
|
return string.Empty;
|
|
var additionalMocOptions = "\"-f" + compiler.GetPrecompiledHeaderThrough().Replace('\\', '/') + "\" ";
|
//Get mocDir without .\\ at the beginning of it
|
var mocDir = QtVSIPSettings.GetMocDirectory(envPro);
|
if (mocDir.StartsWith(".\\", StringComparison.Ordinal))
|
mocDir = mocDir.Substring(2);
|
|
//Get the absolute path
|
mocDir = vcPro.ProjectDirectory + mocDir;
|
var fullPathGeneric = Path.Combine(
|
Path.GetDirectoryName(file.FullPath), "%(Filename)%(Extension)");
|
var relPathToFile = HelperFunctions.GetRelativePath(
|
mocDir, fullPathGeneric).Replace('\\', '/');
|
additionalMocOptions += "\"-f" + relPathToFile + "\"";
|
return additionalMocOptions;
|
}
|
|
|
void AddMocStepSetBuildExclusions(
|
VCFile sourceFile,
|
VCFileConfiguration workFileConfig,
|
VCFile mocFile)
|
{
|
var hasDifferentMocFilePerConfig =
|
QtVSIPSettings.HasDifferentMocFilePerConfig(envPro);
|
var hasDifferentMocFilePerPlatform =
|
QtVSIPSettings.HasDifferentMocFilePerPlatform(envPro);
|
|
var workFile = workFileConfig.File as VCFile;
|
var mocFileName = GetMocFileName(sourceFile.FullPath);
|
var mocableIsCPP = HelperFunctions.IsMocFile(mocFileName);
|
var vcConfig = workFileConfig.ProjectConfiguration as VCConfiguration;
|
var platform = vcConfig.Platform as VCPlatform;
|
var platformName = platform.Name;
|
|
if (hasDifferentMocFilePerPlatform && hasDifferentMocFilePerConfig) {
|
foreach (VCFileConfiguration mocConf
|
in (IVCCollection)mocFile.FileConfigurations) {
|
var projectCfg = mocConf.ProjectConfiguration as VCConfiguration;
|
if (projectCfg.Name != vcConfig.Name
|
|| (IsMoccedFileIncluded(sourceFile) && !mocableIsCPP)) {
|
if (!mocConf.ExcludedFromBuild)
|
mocConf.ExcludedFromBuild = true;
|
} else {
|
if (mocConf.ExcludedFromBuild != workFileConfig.ExcludedFromBuild)
|
mocConf.ExcludedFromBuild = workFileConfig.ExcludedFromBuild;
|
}
|
}
|
} else if (hasDifferentMocFilePerPlatform) {
|
foreach (VCFileConfiguration mocConf
|
in (IVCCollection)mocFile.FileConfigurations) {
|
var projectCfg = mocConf.ProjectConfiguration as VCConfiguration;
|
var mocConfPlatform = projectCfg.Platform as VCPlatform;
|
if (projectCfg.ConfigurationName != vcConfig.ConfigurationName)
|
continue;
|
|
var exclude = mocConfPlatform.Name != platformName
|
|| (IsMoccedFileIncluded(sourceFile) && !mocableIsCPP);
|
if (exclude) {
|
if (mocConf.ExcludedFromBuild != exclude)
|
mocConf.ExcludedFromBuild = exclude;
|
} else {
|
if (mocConf.ExcludedFromBuild != workFileConfig.ExcludedFromBuild)
|
mocConf.ExcludedFromBuild = workFileConfig.ExcludedFromBuild;
|
}
|
}
|
} else if (hasDifferentMocFilePerConfig) {
|
foreach (VCFileConfiguration mocConf
|
in (IVCCollection)mocFile.FileConfigurations) {
|
var projectCfg = mocConf.ProjectConfiguration as VCConfiguration;
|
var mocConfPlatform = projectCfg.Platform as VCPlatform;
|
if (platformName != mocConfPlatform.Name)
|
continue;
|
if (projectCfg.Name != vcConfig.Name
|
|| (IsMoccedFileIncluded(sourceFile))) {
|
if (!mocConf.ExcludedFromBuild)
|
mocConf.ExcludedFromBuild = true;
|
} else {
|
if (mocConf.ExcludedFromBuild != workFileConfig.ExcludedFromBuild)
|
mocConf.ExcludedFromBuild = workFileConfig.ExcludedFromBuild;
|
}
|
}
|
} else {
|
var moccedFileConfig = GetVCFileConfigurationByName(
|
mocFile,
|
workFileConfig.Name);
|
if (moccedFileConfig != null) {
|
var cppFile = GetCppFileForMocStep(sourceFile);
|
if (cppFile != null && IsMoccedFileIncluded(cppFile)) {
|
if (!moccedFileConfig.ExcludedFromBuild)
|
moccedFileConfig.ExcludedFromBuild = true;
|
} else if (moccedFileConfig.ExcludedFromBuild
|
!= workFileConfig.ExcludedFromBuild) {
|
moccedFileConfig.ExcludedFromBuild = workFileConfig.ExcludedFromBuild;
|
}
|
}
|
}
|
}
|
|
void AddMocStepCustomBuild(
|
VCFile sourceFile,
|
VCFileConfiguration workFileConfig,
|
VCFile mocFile,
|
string defines,
|
string includes,
|
string description)
|
{
|
var workFile = workFileConfig.File as VCFile;
|
var mocFileName = GetMocFileName(sourceFile.FullPath);
|
var mocableIsCPP = HelperFunctions.IsMocFile(mocFileName);
|
var vcConfig = workFileConfig.ProjectConfiguration as VCConfiguration;
|
|
workFile.ItemType = "CustomBuild";
|
|
VCCustomBuildTool tool = HelperFunctions.GetCustomBuildTool(workFileConfig);
|
string fileToMoc = null;
|
if (mocableIsCPP) {
|
fileToMoc = HelperFunctions.GetRelativePath(
|
vcPro.ProjectDirectory,
|
sourceFile.FullPath);
|
} else {
|
fileToMoc = ProjectMacros.Path;
|
}
|
if (tool == null)
|
throw new QtVSException(
|
SR.GetString("QtProject_CannotFindCustomBuildTool",
|
workFile.FullPath));
|
|
var dps = tool.AdditionalDependencies;
|
if (dps.IndexOf("\"" + Resources.moc4Command + "\"", StringComparison.Ordinal) < 0) {
|
if (dps.Length > 0 && !dps.EndsWith(";", StringComparison.Ordinal))
|
dps += ";";
|
tool.AdditionalDependencies = dps + "\""
|
+ Resources.moc4Command + "\";" + fileToMoc;
|
}
|
|
tool.Description = description;
|
|
var baseFileName = sourceFile.Name.Remove(sourceFile.Name.LastIndexOf('.'));
|
var outputMocFile = string.Empty;
|
var outputMocMacro = string.Empty;
|
|
var inputMocFile = ProjectMacros.Path;
|
if (mocableIsCPP)
|
inputMocFile = sourceFile.RelativePath;
|
var output = tool.Outputs;
|
var pattern = "(\"(.*\\\\" + mocFileName + ")\"|(\\S*"
|
+ mocFileName + "))";
|
var regExp = new Regex(pattern);
|
var matchList = regExp.Matches(tool.Outputs.Replace(ProjectMacros.Name, baseFileName));
|
if (matchList.Count > 0) {
|
if (matchList[0].Length > 0)
|
outputMocFile = matchList[0].ToString();
|
else if (matchList[1].Length > 1)
|
outputMocFile = matchList[1].ToString();
|
|
if (outputMocFile.StartsWith("\"", StringComparison.Ordinal))
|
outputMocFile = outputMocFile.Substring(1);
|
if (outputMocFile.EndsWith("\"", StringComparison.Ordinal))
|
outputMocFile = outputMocFile.Substring(0, outputMocFile.Length - 1);
|
var outputMocPath = Path.GetDirectoryName(outputMocFile);
|
var stringToReplace = Path.GetFileName(outputMocFile);
|
outputMocMacro =
|
outputMocPath
|
+ "\\"
|
+ stringToReplace.Replace(baseFileName, ProjectMacros.Name);
|
} else {
|
outputMocFile = GetRelativeMocFilePath(sourceFile.FullPath);
|
var outputMocPath = Path.GetDirectoryName(outputMocFile);
|
var stringToReplace = Path.GetFileName(outputMocFile);
|
outputMocMacro =
|
outputMocPath
|
+ "\\"
|
+ stringToReplace.Replace(baseFileName, ProjectMacros.Name);
|
if (output.Length > 0 && !output.EndsWith(";", StringComparison.Ordinal))
|
output += ";";
|
tool.Outputs = output + "\"" + outputMocMacro + "\"";
|
}
|
|
var newCmdLine = "\"" + Resources.moc4Command + "\" "
|
+ QtVSIPSettings.GetMocOptions(envPro)
|
+ " \"" + inputMocFile + "\" -o \""
|
+ outputMocMacro + "\"";
|
|
//Tell moc to include the PCH header if we are using precompiled headers in the project
|
var compiler = CompilerToolWrapper.Create(vcConfig);
|
if (compiler.GetUsePrecompiledHeader() != pchOption.pchNone)
|
newCmdLine += " " + GetPCHMocOptions(sourceFile, compiler);
|
|
var versionManager = QtVersionManager.The();
|
var versionInfo = VersionInformation.Get(versionManager.GetInstallPath(envPro));
|
var mocSupportsIncludes = (versionInfo.qtMajor == 4 && versionInfo.qtMinor >= 2)
|
|| versionInfo.qtMajor >= 5;
|
|
var strDefinesIncludes = defines + includes;
|
var cmdLineLength = newCmdLine.Length + strDefinesIncludes.Length + 1;
|
|
if (cmdLineLength > HelperFunctions.GetMaximumCommandLineLength()
|
&& mocSupportsIncludes) {
|
// Command line is too long. We must use an options file.
|
var mocIncludeCommands = string.Empty;
|
var mocIncludeFile = "\"" + outputMocFile + ".inc\"";
|
var redirectOp = " > ";
|
var maxCmdLineLength =
|
HelperFunctions.GetMaximumCommandLineLength()
|
- (mocIncludeFile.Length + 1);
|
|
var options = defines.Split(
|
new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList();
|
var matches = Regex.Matches(includes, "([\"])(?:(?=(\\\\?))\\2.)*?\\1");
|
foreach (Match match in matches) {
|
options.Add(match.Value);
|
includes = includes.Replace(
|
match.Value, string.Empty, StringComparison.Ordinal);
|
}
|
options.AddRange(
|
includes.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries));
|
|
// Since 5.2.0, MOC uses QCommandLineParser and parses the content of
|
// the moc_*.inc file differently. For example, "-I.\foo\bar" results
|
// in an error message, because the parser thinks it got an additional
|
// positional argument. Change the option into a format MOC understands.
|
if (versionInfo.qtMajor == 5 && versionInfo.qtMinor >= 2) {
|
for (var o = 0; o < options.Count; ++o)
|
options[o] = Regex.Replace(options[o], "\"(-I|-D)", "$1=\"");
|
}
|
|
var i = options.Count - 1;
|
for (; i >= 0; --i) {
|
if (options[i].Length == 0)
|
continue;
|
mocIncludeCommands +=
|
"echo " + options[i] + redirectOp + mocIncludeFile + "\r\n";
|
cmdLineLength -= options[i].Length + 1;
|
if (cmdLineLength < maxCmdLineLength)
|
break;
|
if (i == options.Count - 1) // first loop
|
redirectOp = " >> ";
|
}
|
strDefinesIncludes = "@" + mocIncludeFile;
|
for (var k = 0; k < i; ++k) {
|
if (options[k].Length > 0)
|
strDefinesIncludes += " " + options[k];
|
}
|
newCmdLine = mocIncludeCommands + newCmdLine + " " + strDefinesIncludes;
|
} else {
|
newCmdLine = newCmdLine + " " + strDefinesIncludes;
|
}
|
|
if (tool.CommandLine.Trim().Length > 0) {
|
var cmdLine = tool.CommandLine;
|
|
// remove the moc option file commands
|
{
|
var rex = new Regex("^echo.+[.](moc|cpp)[.]inc\"\r\n", RegexOptions.Multiline);
|
cmdLine = rex.Replace(cmdLine, string.Empty);
|
}
|
|
var m = Regex.Match(cmdLine, @"(\S*moc.exe|""\S+:\\\.*moc.exe"")");
|
if (m.Success) {
|
var start = m.Index;
|
var end = cmdLine.IndexOf("&&", start, StringComparison.Ordinal);
|
var a = cmdLine.IndexOf("\r\n", start, StringComparison.Ordinal);
|
if (a > -1 && (a < end || end < 0))
|
end = a;
|
if (end < 0)
|
end = cmdLine.Length;
|
tool.CommandLine = cmdLine.Replace(
|
cmdLine.Substring(start, end - start), newCmdLine);
|
} else {
|
tool.CommandLine = cmdLine + "\r\n" + newCmdLine;
|
}
|
} else {
|
tool.CommandLine = newCmdLine;
|
}
|
}
|
|
void AddMocStepMsBuildTarget(
|
VCFile sourceFile,
|
VCFileConfiguration workConfig,
|
string defines,
|
string includes,
|
string description)
|
{
|
var baseFileName = sourceFile.Name.Remove(sourceFile.Name.LastIndexOf('.'));
|
var outputMocFile = GetRelativeMocFilePath(sourceFile.FullPath);
|
var outputMocPath = Path.GetDirectoryName(outputMocFile);
|
var stringToReplace = Path.GetFileName(outputMocFile);
|
var outputMocMacro = outputMocPath + "\\"
|
+ stringToReplace.Replace(baseFileName, ProjectMacros.Name);
|
|
sourceFile.ItemType = QtMoc.ItemTypeName;
|
qtMsBuild.SetItemProperty(workConfig,
|
QtMoc.Property.InputFile, ProjectMacros.Path);
|
qtMsBuild.SetItemProperty(workConfig,
|
QtMoc.Property.OutputFile, outputMocMacro);
|
if (!HelperFunctions.IsSourceFile(sourceFile.FullPath)) {
|
qtMsBuild.SetItemProperty(workConfig,
|
QtMoc.Property.DynamicSource, "output");
|
} else {
|
qtMsBuild.SetItemProperty(workConfig,
|
QtMoc.Property.DynamicSource, "input");
|
}
|
qtMsBuild.SetItemProperty(workConfig,
|
QtMoc.Property.ExecutionDescription, description);
|
qtMsBuild.SetQtMocCommandLine(workConfig,
|
QtMoc.ToolExecName + " " + defines + " " + includes,
|
new VCMacroExpander(workConfig));
|
}
|
|
void AddMocStepToConfiguration(
|
VCFile sourceFile,
|
VCFileConfiguration workConfig,
|
CustomTool toolSettings)
|
{
|
var workFile = workConfig.File as VCFile;
|
var mocFileName = GetMocFileName(sourceFile.FullPath);
|
var mocableIsCPP = HelperFunctions.IsMocFile(mocFileName);
|
var vcConfig = workConfig.ProjectConfiguration as VCConfiguration;
|
var platform = vcConfig.Platform as VCPlatform;
|
var platformName = platform.Name;
|
|
var mocRelPath = GetRelativeMocFilePath(
|
sourceFile.FullPath,
|
vcConfig.ConfigurationName,
|
platformName);
|
string subfilterName = null;
|
if (mocRelPath.Contains(vcConfig.ConfigurationName))
|
subfilterName = vcConfig.ConfigurationName;
|
if (mocRelPath.Contains(platformName)) {
|
if (subfilterName != null)
|
subfilterName += '_';
|
subfilterName += platformName;
|
}
|
|
VCFile mocFile = null;
|
if (toolSettings == CustomTool.CustomBuildStep) {
|
mocFile = GetFileFromProject(mocRelPath);
|
if (mocFile == null) {
|
var fi = new FileInfo(VCProject.ProjectDirectory + "\\" + mocRelPath);
|
if (!fi.Directory.Exists)
|
fi.Directory.Create();
|
mocFile = AddFileInSubfilter(Filters.GeneratedFiles(), subfilterName,
|
mocRelPath);
|
}
|
if (mocFile != null) {
|
if (mocableIsCPP)
|
mocFile.ItemType = "None";
|
else
|
AddMocStepSetBuildExclusions(sourceFile, workConfig, mocFile);
|
}
|
}
|
|
VCFile cppPropertyFile = null;
|
if (mocableIsCPP)
|
cppPropertyFile = sourceFile;
|
else if (mocFile != null)
|
cppPropertyFile = GetCppFileForMocStep(sourceFile);
|
VCFileConfiguration defineIncludeConfig;
|
if (cppPropertyFile != null) {
|
defineIncludeConfig = GetVCFileConfigurationByName(
|
cppPropertyFile,
|
workConfig.Name);
|
} else {
|
// No file specific defines/includes
|
// but at least the project defines/includes are added
|
defineIncludeConfig = workConfig;
|
}
|
var defines = GetDefines(defineIncludeConfig);
|
var includes = GetIncludes(defineIncludeConfig);
|
var description = "Moc'ing %(Identity)...";
|
|
if (toolSettings == CustomTool.MSBuildTarget) {
|
AddMocStepMsBuildTarget(
|
sourceFile,
|
workConfig,
|
defines,
|
includes,
|
description);
|
} else {
|
AddMocStepCustomBuild(
|
sourceFile,
|
workConfig,
|
mocFile,
|
defines,
|
includes,
|
description);
|
}
|
}
|
|
public enum CustomTool { CustomBuildStep, MSBuildTarget };
|
|
/// <summary>
|
/// Adds a moc step to a given file for this project.
|
/// </summary>
|
/// <param name="file">file</param>
|
public void AddMocStep(VCFile file)
|
{
|
if (GetFormatVersion(vcPro) >= Resources.qtMinFormatVersion_Settings) {
|
file.ItemType = QtMoc.ItemTypeName;
|
if (HelperFunctions.IsSourceFile(file.FullPath)) {
|
foreach (VCFileConfiguration config in (IVCCollection)file.FileConfigurations) {
|
qtMsBuild.SetItemProperty(config, QtMoc.Property.DynamicSource, "input");
|
qtMsBuild.SetItemPropertyByName(config, "QtMocFileName", "%(Filename).moc");
|
}
|
}
|
return;
|
}
|
|
CustomTool toolSettings =
|
IsQtMsBuildEnabled() ? CustomTool.MSBuildTarget : CustomTool.CustomBuildStep;
|
|
try {
|
var mocFileName = GetMocFileName(file.FullPath);
|
if (mocFileName == null)
|
return;
|
|
var mocableIsCPP = HelperFunctions.IsMocFile(mocFileName);
|
|
VCFile sourceFile = file;
|
if (mocableIsCPP && toolSettings != CustomTool.MSBuildTarget) {
|
string cbtFullPath = Path.ChangeExtension(file.FullPath, ".cbt");
|
File.WriteAllText(cbtFullPath, string.Format(
|
"This is a dummy file needed to create {0}", mocFileName));
|
file = AddFileInSubfilter(Filters.GeneratedFiles(), null, cbtFullPath, true);
|
var mocFileItem = file.Object as ProjectItem;
|
if (mocFileItem != null)
|
HelperFunctions.EnsureCustomBuildToolAvailable(mocFileItem);
|
}
|
|
foreach (VCFileConfiguration config in (IVCCollection)file.FileConfigurations)
|
AddMocStepToConfiguration(sourceFile, config, toolSettings);
|
|
} catch {
|
throw new QtVSException(SR.GetString("QtProject_CannotAddMocStep", file.FullPath));
|
}
|
}
|
|
/// <summary>
|
/// Parses the given file to find an occurrence of a moc.exe generated file include. If
|
/// the given file is a header file, the function tries to find the corresponding source
|
/// file to use it instead of the header file. Helper function for AddMocStep.
|
/// </summary>
|
/// <param name="vcFile">Header or source file name.</param>
|
/// <returns>
|
/// Returns true if the file contains an include of the corresponding moc_xxx.cpp file;
|
/// otherwise returns false.
|
/// </returns>
|
public bool IsMoccedFileIncluded(VCFile vcFile)
|
{
|
var fullPath = vcFile.FullPath;
|
if (HelperFunctions.IsHeaderFile(fullPath))
|
fullPath = Path.ChangeExtension(fullPath, ".cpp");
|
|
if (HelperFunctions.IsSourceFile(fullPath)) {
|
vcFile = GetFileFromProject(fullPath);
|
if (vcFile == null)
|
return false;
|
|
fullPath = vcFile.FullPath;
|
var mocFile = "moc_" + Path.GetFileNameWithoutExtension(fullPath) + ".cpp";
|
|
#if TODO
|
// TODO: Newly created projects need a manual solution rescan if we access the
|
// code model too early, right now it fails to properly parse the created files.
|
|
// Try reusing the vc file code model,
|
var projectItem = vcFile.Object as ProjectItem;
|
if (projectItem != null) {
|
var vcFileCodeModel = projectItem.FileCodeModel as VCFileCodeModel;
|
if (vcFileCodeModel != null) {
|
foreach (VCCodeInclude include in vcFileCodeModel.Includes) {
|
if (include.FullName == mocFile)
|
return true;
|
}
|
return false;
|
}
|
}
|
|
// if we fail, we parse the file on our own...
|
#endif
|
CxxStreamReader cxxStream = null;
|
try {
|
var line = string.Empty;
|
cxxStream = new CxxStreamReader(fullPath);
|
while ((line = cxxStream.ReadLine()) != null) {
|
if (Regex.IsMatch(line, "#include *(<|\")" + mocFile + "(\"|>)"))
|
return true;
|
}
|
} catch { } finally {
|
if (cxxStream != null)
|
cxxStream.Dispose();
|
}
|
}
|
return false;
|
}
|
|
public bool HasMocStep(VCFile file, string mocOutDir = null)
|
{
|
if (file.ItemType == QtMoc.ItemTypeName)
|
return true;
|
|
if (HelperFunctions.IsHeaderFile(file.Name))
|
return CheckForCommand(file, "moc.exe");
|
|
if (HelperFunctions.IsSourceFile(file.Name)) {
|
return (HasCppMocFiles(file));
|
}
|
return false;
|
}
|
|
public static bool HasUicStep(VCFile file)
|
{
|
if (file.ItemType == QtUic.ItemTypeName)
|
return true;
|
return CheckForCommand(file, Resources.uic4Command);
|
}
|
|
private static bool CheckForCommand(VCFile file, string cmd)
|
{
|
if (file == null)
|
return false;
|
foreach (VCFileConfiguration config in (IVCCollection)file.FileConfigurations) {
|
var tool = HelperFunctions.GetCustomBuildTool(config);
|
if (tool == null)
|
return false;
|
if (tool.CommandLine != null && tool.CommandLine.Contains(cmd))
|
return true;
|
}
|
return false;
|
}
|
|
public void RefreshRccSteps()
|
{
|
Messages.Print("\r\n=== Update rcc steps ===");
|
var files = GetResourceFiles();
|
|
var vcFilter = FindFilterFromGuid(Filters.GeneratedFiles().UniqueIdentifier);
|
if (vcFilter != null) {
|
var filterFiles = GetAllFilesFromFilter(vcFilter);
|
var filesToDelete = new List<VCFile>();
|
foreach (VCFile rmFile in filterFiles) {
|
if (rmFile.Name.StartsWith("qrc_", StringComparison.OrdinalIgnoreCase))
|
filesToDelete.Add(rmFile);
|
}
|
foreach (var rmFile in filesToDelete) {
|
RemoveFileFromFilter(rmFile, vcFilter);
|
HelperFunctions.DeleteEmptyParentDirs(rmFile);
|
}
|
}
|
|
qtMsBuild.BeginSetItemProperties();
|
foreach (var file in files) {
|
Messages.Print("Update rcc step for " + file.Name + ".");
|
var options = new RccOptions(envPro, file);
|
UpdateRccStep(file, options);
|
}
|
qtMsBuild.EndSetItemProperties();
|
|
Messages.Print("\r\n=== " + files.Count + " rcc steps updated. ===\r\n");
|
}
|
|
public void RefreshRccSteps(string oldRccDir)
|
{
|
RefreshRccSteps();
|
UpdateCompilerIncludePaths(oldRccDir, QtVSIPSettings.GetRccDirectory(envPro));
|
}
|
|
public void UpdateRccStepMsBuild(
|
VCFileConfiguration vfc,
|
RccOptions rccOpts,
|
string filesInQrcFile,
|
string nameOnly,
|
string qrcCppFile)
|
{
|
var file = vfc.File as VCFile;
|
if (file != null)
|
file.ItemType = QtRcc.ItemTypeName;
|
qtMsBuild.SetItemProperty(vfc,
|
QtRcc.Property.ExecutionDescription, "Rcc'ing " + ProjectMacros.FileName + "...");
|
qtMsBuild.SetItemProperty(vfc,
|
QtRcc.Property.OutputFile, qrcCppFile.Replace(nameOnly, ProjectMacros.Name));
|
}
|
|
public void UpdateRccStepCustomBuild(
|
VCFileConfiguration vfc,
|
RccOptions rccOpts,
|
string filesInQrcFile,
|
string nameOnly,
|
string qrcCppFile)
|
{
|
var qrcFile = vfc.File as VCFile;
|
var rccOptsCfg = rccOpts;
|
var cmdLine = string.Empty;
|
|
var cbt = HelperFunctions.GetCustomBuildTool(vfc);
|
|
cbt.AdditionalDependencies = filesInQrcFile;
|
|
cbt.Description = "Rcc'ing " + ProjectMacros.FileName + "...";
|
|
cbt.Outputs = qrcCppFile.Replace(nameOnly, ProjectMacros.Name);
|
|
cmdLine += "\"" + Resources.rcc4Command + "\""
|
+ " -name \"" + ProjectMacros.Name + "\"";
|
|
if (rccOptsCfg == null)
|
rccOptsCfg = HelperFunctions.ParseRccOptions(cbt.CommandLine, qrcFile);
|
|
if (rccOptsCfg.CompressFiles) {
|
cmdLine += " -threshold " + rccOptsCfg.CompressThreshold;
|
cmdLine += " -compress " + rccOptsCfg.CompressLevel;
|
} else {
|
cmdLine += " -no-compress";
|
}
|
|
cbt.CommandLine = cmdLine + " \"" + ProjectMacros.Path + "\" -o " + cbt.Outputs;
|
}
|
|
public void UpdateRccStep(VCFile qrcFile, RccOptions rccOpts)
|
{
|
if (GetFormatVersion(vcPro) >= Resources.qtMinFormatVersion_Settings) {
|
qrcFile.ItemType = QtRcc.ItemTypeName;
|
return;
|
}
|
|
CustomTool toolSettings =
|
IsQtMsBuildEnabled() ? CustomTool.MSBuildTarget : CustomTool.CustomBuildStep;
|
|
var vcpro = (VCProject)qrcFile.project;
|
var dteObject = ((Project)vcpro.Object).DTE;
|
|
var qtPro = Create(vcpro);
|
var parser = new QrcParser(qrcFile.FullPath);
|
var filesInQrcFile = ProjectMacros.Path;
|
|
if (parser.parse()) {
|
var fi = new FileInfo(qrcFile.FullPath);
|
var qrcDir = fi.Directory.FullName + "\\";
|
|
foreach (var prfx in parser.Prefixes) {
|
foreach (var itm in prfx.Items) {
|
var relativeQrcItemPath = HelperFunctions.GetRelativePath(
|
vcPro.ProjectDirectory,
|
qrcDir + itm.Path);
|
filesInQrcFile += ";" + relativeQrcItemPath;
|
try {
|
var addedFile = qtPro.AddFileInFilter(
|
Filters.ResourceFiles(),
|
relativeQrcItemPath, true);
|
ExcludeFromAllBuilds(addedFile);
|
} catch { /* it's not possible to add all kinds of files */ }
|
}
|
}
|
}
|
|
var nameOnly = HelperFunctions.RemoveFileNameExtension(new FileInfo(qrcFile.FullPath));
|
var qrcCppFile = QtVSIPSettings.GetRccDirectory(envPro)
|
+ "\\" + "qrc_" + nameOnly + ".cpp";
|
|
try {
|
foreach (VCFileConfiguration vfc in (IVCCollection)qrcFile.FileConfigurations) {
|
switch (toolSettings) {
|
case CustomTool.MSBuildTarget:
|
UpdateRccStepMsBuild(
|
vfc,
|
rccOpts,
|
filesInQrcFile,
|
nameOnly,
|
qrcCppFile);
|
break;
|
default:
|
UpdateRccStepCustomBuild(
|
vfc,
|
rccOpts,
|
filesInQrcFile,
|
nameOnly,
|
qrcCppFile);
|
break;
|
}
|
}
|
if (toolSettings == CustomTool.CustomBuildStep)
|
AddFileInFilter(Filters.GeneratedFiles(), qrcCppFile, true);
|
} catch (Exception /*e*/) {
|
Messages.Print("*** WARNING (RCC): Couldn't add rcc step");
|
}
|
}
|
|
static public void ExcludeFromAllBuilds(VCFile file)
|
{
|
if (file == null)
|
return;
|
foreach (VCFileConfiguration conf in (IVCCollection)file.FileConfigurations) {
|
if (!conf.ExcludedFromBuild)
|
conf.ExcludedFromBuild = true;
|
}
|
}
|
|
bool IsCppMocFileCustomBuild(VCProject vcProj, VCFile vcFile, VCFile cppFile)
|
{
|
var mocFilePath = vcFile.FullPath;
|
var cppFilePath = cppFile.FullPath;
|
if (Path.GetDirectoryName(mocFilePath)
|
!= Path.GetDirectoryName(cppFilePath)) {
|
return false;
|
}
|
|
if (Path.GetFileNameWithoutExtension(mocFilePath)
|
!= Path.GetFileNameWithoutExtension(cppFilePath)) {
|
return false;
|
}
|
|
if (!string.Equals(Path.GetExtension(mocFilePath), ".cbt",
|
StringComparison.InvariantCultureIgnoreCase)) {
|
return false;
|
}
|
|
return true;
|
}
|
|
List<VCFile> GetCppMocOutputs(List<VCFile> mocFiles)
|
{
|
List<VCFile> outputFiles = new List<VCFile>();
|
foreach (var mocFile in mocFiles) {
|
foreach (VCFileConfiguration mocConfig
|
in (IVCCollection)mocFile.FileConfigurations) {
|
|
var cbtTool = HelperFunctions.GetCustomBuildTool(mocConfig);
|
if (cbtTool == null)
|
continue;
|
foreach (var output in cbtTool.Outputs.Split(new char[] { ';' })) {
|
string outputExpanded = output;
|
if (!HelperFunctions.ExpandString(ref outputExpanded, mocConfig))
|
continue;
|
string outputFullPath = "";
|
try {
|
outputFullPath = Path.GetFullPath(Path.Combine(
|
Path.GetDirectoryName(mocFile.FullPath),
|
outputExpanded));
|
} catch {
|
continue;
|
}
|
var vcFile = GetFileFromProject(outputFullPath);
|
if (vcFile != null)
|
outputFiles.Add(vcFile);
|
}
|
}
|
}
|
return outputFiles;
|
}
|
|
List<VCFile> GetCppMocFiles(VCFile cppFile)
|
{
|
List<VCFile> mocFiles = new List<VCFile>();
|
var vcProj = cppFile.project as VCProject;
|
if (vcProj != null) {
|
mocFiles.AddRange(from VCFile vcFile
|
in (IVCCollection)vcProj.Files
|
where vcFile.ItemType == "CustomBuild"
|
&& IsCppMocFileCustomBuild(vcProj, vcFile, cppFile)
|
select vcFile);
|
mocFiles.AddRange(GetCppMocOutputs(mocFiles));
|
}
|
return mocFiles;
|
}
|
|
bool IsCppMocFileQtMsBuild(VCProject vcProj, VCFile vcFile, VCFile cppFile)
|
{
|
foreach (VCFileConfiguration fileConfig in (IVCCollection)vcFile.FileConfigurations) {
|
string inputFile = qtMsBuild.GetPropertyValue(fileConfig, QtMoc.Property.InputFile);
|
HelperFunctions.ExpandString(ref inputFile, fileConfig);
|
if (HelperFunctions.PathIsRelativeTo(inputFile, cppFile.ItemName))
|
return true;
|
}
|
return false;
|
}
|
|
bool HasCppMocFiles(VCFile cppFile)
|
{
|
if (!IsQtMsBuildEnabled()) {
|
return File.Exists(Path.ChangeExtension(cppFile.FullPath, ".cbt"));
|
} else {
|
var vcProj = cppFile.project as VCProject;
|
if (vcProj != null) {
|
foreach (VCFile vcFile in (IVCCollection)vcProj.Files) {
|
if (vcFile.ItemType == "CustomBuild") {
|
if (IsCppMocFileCustomBuild(vcProj, vcFile, cppFile))
|
return true;
|
} else if (vcFile.ItemType == QtMoc.ItemTypeName) {
|
if (IsCppMocFileQtMsBuild(vcProj, vcFile, cppFile))
|
return true;
|
}
|
}
|
}
|
return false;
|
}
|
}
|
|
public void RemoveMocStep(VCFile file)
|
{
|
if (file.ItemType == QtMoc.ItemTypeName) {
|
RemoveMocStepQtMsBuild(file);
|
} else if (HelperFunctions.IsHeaderFile(file.Name)) {
|
if (file.ItemType == "CustomBuild")
|
RemoveMocStepCustomBuild(file);
|
} else {
|
foreach (VCFile vcFile in (IVCCollection)vcPro.Files) {
|
if (vcFile.ItemType == QtMoc.ItemTypeName) {
|
if (IsCppMocFileQtMsBuild(vcPro, vcFile, file)) {
|
RemoveMocStepQtMsBuild(vcFile);
|
}
|
} else if (vcFile.ItemType == "CustomBuild") {
|
if (IsCppMocFileCustomBuild(vcPro, vcFile, file)) {
|
RemoveMocStepCustomBuild(file);
|
return;
|
}
|
}
|
}
|
}
|
}
|
|
public void RemoveMocStepQtMsBuild(VCFile file)
|
{
|
if (HelperFunctions.IsHeaderFile(file.Name)) {
|
file.ItemType = "ClInclude";
|
} else if (HelperFunctions.IsSourceFile(file.Name)) {
|
file.ItemType = "ClCompile";
|
} else {
|
file.ItemType = "None";
|
}
|
}
|
|
/// <summary>
|
/// Removes the custom build step of a given file.
|
/// </summary>
|
/// <param name="file">file</param>
|
public void RemoveMocStepCustomBuild(VCFile file)
|
{
|
try {
|
if (!HasMocStep(file))
|
return;
|
|
if (HelperFunctions.IsHeaderFile(file.Name)) {
|
foreach (VCFileConfiguration config in (IVCCollection)file.FileConfigurations) {
|
var tool = HelperFunctions.GetCustomBuildTool(config);
|
if (tool == null)
|
continue;
|
|
var cmdLine = tool.CommandLine;
|
if (cmdLine.Length > 0) {
|
var rex = new Regex(@"(\S*moc.exe|""\S+:\\\.*moc.exe"")");
|
while (true) {
|
var m = rex.Match(cmdLine);
|
if (!m.Success)
|
break;
|
|
var start = m.Index;
|
var end = cmdLine.IndexOf("&&", start, StringComparison.Ordinal);
|
var a = cmdLine.IndexOf("\r\n", start, StringComparison.Ordinal);
|
if ((a > -1 && a < end) || (end < 0 && a > -1))
|
end = a;
|
if (end < 0)
|
end = cmdLine.Length;
|
|
cmdLine = cmdLine.Remove(start, end - start).Trim();
|
if (cmdLine.StartsWith("&&", StringComparison.Ordinal))
|
cmdLine = cmdLine.Remove(0, 2).Trim();
|
}
|
tool.CommandLine = cmdLine;
|
}
|
|
var reg = new Regex("Moc'ing .+\\.\\.\\.");
|
var addDepends = tool.AdditionalDependencies;
|
addDepends = Regex.Replace(addDepends,
|
@"(\S*moc.exe|""\S+:\\\.*moc.exe"")", string.Empty);
|
addDepends = addDepends.Replace(file.RelativePath, string.Empty);
|
tool.AdditionalDependencies = string.Empty;
|
tool.Description = reg.Replace(tool.Description, string.Empty);
|
tool.Description = tool.Description.Replace("MOC " + file.Name, string.Empty);
|
var baseFileName = file.Name.Remove(file.Name.LastIndexOf('.'));
|
var pattern = "(\"(.*\\\\" + GetMocFileName(file.FullPath)
|
+ ")\"|(\\S*" + GetMocFileName(file.FullPath) + "))";
|
string outputMocFile = null;
|
var regExp = new Regex(pattern);
|
tool.Outputs = tool.Outputs.Replace(ProjectMacros.Name, baseFileName);
|
var matchList = regExp.Matches(tool.Outputs);
|
if (matchList.Count > 0) {
|
if (matchList[0].Length > 0)
|
outputMocFile = matchList[0].ToString();
|
else if (matchList[1].Length > 1)
|
outputMocFile = matchList[1].ToString();
|
}
|
tool.Outputs = Regex.Replace(tool.Outputs,
|
pattern, string.Empty, RegexOptions.Multiline | RegexOptions.IgnoreCase);
|
tool.Outputs = Regex.Replace(tool.Outputs,
|
@"\s*;\s*;\s*", ";", RegexOptions.Multiline);
|
tool.Outputs = Regex.Replace(tool.Outputs,
|
@"(^\s*;|\s*;\s*$)", string.Empty, RegexOptions.Multiline);
|
|
if (outputMocFile != null) {
|
if (outputMocFile.StartsWith("\"", StringComparison.Ordinal))
|
outputMocFile = outputMocFile.Substring(1);
|
if (outputMocFile.EndsWith("\"", StringComparison.Ordinal))
|
outputMocFile = outputMocFile.Substring(0, outputMocFile.Length - 1);
|
HelperFunctions.ExpandString(ref outputMocFile, config);
|
}
|
var mocFile = GetFileFromProject(outputMocFile);
|
if (mocFile != null)
|
RemoveFileFromFilter(mocFile, Filters.GeneratedFiles());
|
}
|
} else {
|
foreach (var mocFile in GetCppMocFiles(file)) {
|
RemoveFileFromFilter(mocFile, Filters.GeneratedFiles());
|
}
|
}
|
} catch {
|
throw new QtVSException(SR.GetString("QtProject_CannotRemoveMocStep", file.FullPath));
|
}
|
}
|
|
public List<VCFile> GetResourceFiles()
|
{
|
var qrcFiles = new List<VCFile>();
|
|
foreach (VCFile f in (IVCCollection)VCProject.Files) {
|
if (HelperFunctions.IsQrcFile(f.Name))
|
qrcFiles.Add(f);
|
}
|
return qrcFiles;
|
}
|
|
/// <summary>
|
/// Returns the file if it can be found, otherwise null.
|
/// </summary>
|
/// <param name="filter">filter name</param>
|
/// <param name="fileName">relative file path to the project</param>
|
/// <returns></returns>
|
public VCFile GetFileFromFilter(FakeFilter filter, string fileName)
|
{
|
var vcfilter = FindFilterFromGuid(filter.UniqueIdentifier);
|
|
// try with name as well
|
if (vcfilter == null)
|
vcfilter = FindFilterFromName(filter.Name);
|
|
if (vcfilter == null)
|
return null;
|
|
try {
|
FileInfo fi = null;
|
if (Path.IsPathRooted(fileName))
|
fi = new FileInfo(fileName);
|
else
|
fi = new FileInfo(ProjectDir + "\\" + fileName);
|
|
foreach (VCFile file in (IVCCollection)vcfilter.Files) {
|
if (file.MatchName(fi.FullName, true))
|
return file;
|
}
|
} catch { }
|
return null;
|
}
|
|
/// <summary>
|
/// Returns the file (VCFile) specified by the file name from a given
|
/// project.
|
/// </summary>
|
/// <param name="fileName">file name (relative path)</param>
|
/// <returns></returns>
|
public VCFile GetFileFromProject(string fileName)
|
{
|
fileName = HelperFunctions.NormalizeRelativeFilePath(fileName);
|
|
var nf = fileName;
|
if (!HelperFunctions.IsAbsoluteFilePath(fileName))
|
nf = HelperFunctions.NormalizeFilePath(vcPro.ProjectDirectory + "\\" + fileName);
|
nf = nf.ToLower();
|
|
foreach (VCFile f in (IVCCollection)vcPro.Files) {
|
if (f.FullPath.ToLower() == nf)
|
return f;
|
}
|
return null;
|
}
|
|
/// <summary>
|
/// Returns the files specified by the file name from a given project as list of VCFile
|
/// objects.
|
/// </summary>
|
/// <param name="fileName">file name (relative path)</param>
|
/// <returns></returns>
|
public IEnumerable<VCFile> GetFilesFromProject(string fileName)
|
{
|
var fi = new FileInfo(HelperFunctions.NormalizeRelativeFilePath(fileName));
|
foreach (VCFile f in (IVCCollection)vcPro.Files) {
|
if (string.Equals(f.Name, fi.Name, StringComparison.OrdinalIgnoreCase))
|
yield return f;
|
}
|
}
|
|
private static List<VCFile> GetAllFilesFromFilter(VCFilter filter)
|
{
|
var tmpList = ((IVCCollection)filter.Files).Cast<VCFile>().ToList();
|
foreach (VCFilter subfilter in (IVCCollection)filter.Filters)
|
tmpList.AddRange(GetAllFilesFromFilter(subfilter));
|
return tmpList;
|
}
|
|
/// <summary>
|
/// Adds a file to a filter. If the filter doesn't exist yet, it
|
/// will be created. (Doesn't check for duplicates)
|
/// </summary>
|
/// <param name="filter">fake filter</param>
|
/// <param name="fileName">relative file name</param>
|
/// <returns>A VCFile object of the added file.</returns>
|
public VCFile AddFileInFilter(FakeFilter filter, string fileName)
|
{
|
return AddFileInFilter(filter, fileName, false);
|
}
|
|
public void RemoveItem(ProjectItem item)
|
{
|
foreach (ProjectItem tmpFilter in Project.ProjectItems) {
|
if (tmpFilter.Name == item.Name) {
|
tmpFilter.Remove();
|
return;
|
}
|
foreach (ProjectItem tmpItem in tmpFilter.ProjectItems) {
|
if (tmpItem.Name == item.Name) {
|
tmpItem.Remove();
|
return;
|
}
|
}
|
}
|
}
|
|
/// <summary>
|
/// Adds a file to a filter. If the filter doesn't exist yet, it
|
/// will be created.
|
/// </summary>
|
/// <param name="filter">fake filter</param>
|
/// <param name="fileName">relative file name</param>
|
/// <param name="checkForDuplicates">true if we don't want duplicated files</param>
|
/// <returns>A VCFile object of the added file.</returns>
|
public VCFile AddFileInFilter(FakeFilter filter, string fileName, bool checkForDuplicates)
|
{
|
return AddFileInSubfilter(filter, null, fileName, checkForDuplicates);
|
}
|
|
public VCFile AddFileInSubfilter(FakeFilter filter, string subfilterName, string fileName)
|
{
|
return AddFileInSubfilter(filter, subfilterName, fileName, false);
|
}
|
|
public VCFile AddFileInSubfilter(FakeFilter filter, string subfilterName, string fileName, bool checkForDuplicates)
|
{
|
try {
|
var vfilt = FindFilterFromGuid(filter.UniqueIdentifier);
|
if (vfilt == null) {
|
if (!vcPro.CanAddFilter(filter.Name)) {
|
// check if user already created this filter... then add guid
|
vfilt = FindFilterFromName(filter.Name);
|
if (vfilt == null)
|
throw new QtVSException(SR.GetString("QtProject_CannotAddFilter", filter.Name));
|
} else {
|
vfilt = (VCFilter)vcPro.AddFilter(filter.Name);
|
}
|
|
vfilt.UniqueIdentifier = filter.UniqueIdentifier;
|
vfilt.Filter = filter.Filter;
|
vfilt.ParseFiles = filter.ParseFiles;
|
}
|
|
if (!string.IsNullOrEmpty(subfilterName)) {
|
var lowerSubFilterName = subfilterName.ToLower();
|
var subfilterFound = false;
|
foreach (VCFilter subfilt in vfilt.Filters as IVCCollection) {
|
if (subfilt.Name.ToLower() == lowerSubFilterName) {
|
vfilt = subfilt;
|
subfilterFound = true;
|
break;
|
}
|
}
|
if (subfilterFound) {
|
// Do filter names differ in upper/lower case?
|
if (subfilterName != vfilt.Name) {
|
try {
|
// Try to rename the filter for aesthetic reasons.
|
vfilt.Name = subfilterName;
|
} catch {
|
// Renaming didn't work. We don't care.
|
}
|
}
|
}
|
if (!subfilterFound) {
|
if (!vfilt.CanAddFilter(subfilterName))
|
throw new QtVSException(SR.GetString("QtProject_CannotAddFilter", filter.Name));
|
|
#if !(VS2017 || VS2019 || VS2022)
|
// TODO: Enable once the freeze gets fixed in VS.
|
vfilt = (VCFilter)vfilt.AddFilter(subfilterName);
|
vfilt.Filter = "cpp;moc";
|
vfilt.SourceControlFiles = false;
|
#endif
|
}
|
}
|
|
if (checkForDuplicates) {
|
// check if file exists in filter already
|
var vcFile = GetFileFromFilter(filter, fileName);
|
if (vcFile != null)
|
return vcFile;
|
}
|
|
if (vfilt.CanAddFile(fileName))
|
return (VCFile)(vfilt.AddFile(fileName));
|
throw new QtVSException(SR.GetString("QtProject_CannotAddFile", fileName));
|
} catch {
|
throw new QtVSException(SR.GetString("QtProject_CannotAddFile", fileName));
|
}
|
}
|
|
/// <summary>
|
/// Removes a file from the filter.
|
/// This file will be deleted!
|
/// </summary>
|
/// <param name="file">file</param>
|
public void RemoveFileFromFilter(VCFile file, FakeFilter filter)
|
{
|
try {
|
var vfilt = FindFilterFromGuid(filter.UniqueIdentifier);
|
|
if (vfilt == null)
|
vfilt = FindFilterFromName(filter.Name);
|
|
if (vfilt == null)
|
return;
|
|
RemoveFileFromFilter(file, vfilt);
|
} catch {
|
throw new QtVSException(SR.GetString("QtProject_CannotRemoveFile", file.Name));
|
}
|
}
|
|
/// <summary>
|
/// Removes a file from the filter.
|
/// This file will be deleted!
|
/// </summary>
|
/// <param name="file">file</param>
|
public void RemoveFileFromFilter(VCFile file, VCFilter filter)
|
{
|
try {
|
filter.RemoveFile(file);
|
var fi = new FileInfo(file.FullPath);
|
if (fi.Exists)
|
fi.Delete();
|
} catch {
|
}
|
|
var subfilters = (IVCCollection)filter.Filters;
|
for (var i = subfilters.Count; i > 0; i--) {
|
try {
|
var subfilter = (VCFilter)subfilters.Item(i);
|
RemoveFileFromFilter(file, subfilter);
|
} catch {
|
}
|
}
|
}
|
|
public void MoveFileToDeletedFolder(VCFile vcfile)
|
{
|
var srcFile = new FileInfo(vcfile.FullPath);
|
|
if (!srcFile.Exists)
|
return;
|
|
var destFolder = vcPro.ProjectDirectory + "\\Deleted\\";
|
var destName = destFolder + vcfile.Name.Replace(".", "_") + ".bak";
|
var fileNr = 0;
|
|
try {
|
if (!Directory.Exists(destFolder))
|
Directory.CreateDirectory(destFolder);
|
|
while (File.Exists(destName)) {
|
fileNr++;
|
destName = destName.Substring(0, destName.LastIndexOf('.')) + ".b";
|
destName += fileNr.ToString("00");
|
}
|
|
srcFile.MoveTo(destName);
|
} catch (Exception e) {
|
Messages.DisplayWarningMessage(e, SR.GetString("QtProject_DeletedFolderFullOrProteced"));
|
}
|
}
|
|
public VCFilter FindFilterFromName(string filtername)
|
{
|
try {
|
foreach (VCFilter vcfilt in (IVCCollection)vcPro.Filters) {
|
if (vcfilt.Name.ToLower() == filtername.ToLower())
|
return vcfilt;
|
}
|
return null;
|
} catch {
|
throw new QtVSException(SR.GetString("QtProject_CannotFindFilter"));
|
}
|
}
|
|
public VCFilter FindFilterFromGuid(string filterguid)
|
{
|
try {
|
foreach (VCFilter vcfilt in (IVCCollection)vcPro.Filters) {
|
if (vcfilt.UniqueIdentifier != null
|
&& vcfilt.UniqueIdentifier.ToLower() == filterguid.ToLower()) {
|
return vcfilt;
|
}
|
}
|
return null;
|
} catch {
|
throw new QtVSException(SR.GetString("QtProject_CannotFindFilter"));
|
}
|
}
|
|
public VCFilter AddFilterToProject(FakeFilter filter)
|
{
|
try {
|
var vfilt = FindFilterFromGuid(filter.UniqueIdentifier);
|
if (vfilt == null) {
|
if (!vcPro.CanAddFilter(filter.Name)) {
|
vfilt = FindFilterFromName(filter.Name);
|
if (vfilt == null)
|
throw new QtVSException(SR.GetString("QtProject_ProjectCannotAddFilter", filter.Name));
|
} else {
|
vfilt = (VCFilter)vcPro.AddFilter(filter.Name);
|
}
|
|
vfilt.UniqueIdentifier = filter.UniqueIdentifier;
|
vfilt.Filter = filter.Filter;
|
vfilt.ParseFiles = filter.ParseFiles;
|
}
|
return vfilt;
|
} catch {
|
throw new QtVSException(SR.GetString("QtProject_ProjectCannotAddResourceFilter"));
|
}
|
}
|
|
public void AddDirectories()
|
{
|
try {
|
// resource directory
|
var fi = new FileInfo(envPro.FullName);
|
var dfi = new DirectoryInfo(fi.DirectoryName + "\\" + Resources.resourceDir);
|
dfi.Create();
|
} catch {
|
throw new QtVSException(SR.GetString("QtProject_CannotCreateResourceDir"));
|
}
|
AddFilterToProject(Filters.ResourceFiles());
|
}
|
|
public void Finish()
|
{
|
try {
|
var solutionExplorer = dte.Windows.Item(Constants.vsWindowKindSolutionExplorer);
|
if (solutionExplorer != null) {
|
var hierarchy = (UIHierarchy)solutionExplorer.Object;
|
var projects = hierarchy.UIHierarchyItems.Item(1).UIHierarchyItems;
|
|
foreach (UIHierarchyItem itm in projects) {
|
if (itm.Name == envPro.Name) {
|
foreach (UIHierarchyItem i in itm.UIHierarchyItems) {
|
if (i.Name == Filters.GeneratedFiles().Name)
|
i.UIHierarchyItems.Expanded = false;
|
}
|
break;
|
}
|
}
|
}
|
} catch { }
|
|
ProjectTracker?.AddProject(envPro);
|
}
|
|
public bool IsDesignerPluginProject()
|
{
|
var b = false;
|
if (Project.Globals.get_VariablePersists("IsDesignerPlugin")) {
|
var s = (string)Project.Globals["IsDesignerPlugin"];
|
try {
|
b = bool.Parse(s);
|
} catch { }
|
}
|
return b;
|
}
|
|
/// <summary>
|
/// Adds a file to a specified filter in a project.
|
/// </summary>
|
/// <param name="destName">name of the file in the project (relative to the project directory)</param>
|
/// <param name="filter">filter</param>
|
/// <returns>VCFile</returns>
|
public VCFile AddFileToProject(string destName, FakeFilter filter)
|
{
|
VCFile file = null;
|
if (filter != null)
|
file = AddFileInFilter(filter, destName);
|
else
|
file = (VCFile)vcPro.AddFile(destName);
|
|
if (file == null)
|
return null;
|
|
if (HelperFunctions.IsHeaderFile(file.Name)) {
|
foreach (VCConfiguration config in (IVCCollection)vcPro.Configurations) {
|
var compiler = CompilerToolWrapper.Create(config);
|
if (compiler == null)
|
continue;
|
|
var paths = compiler.GetAdditionalIncludeDirectoriesList();
|
var fi = new FileInfo(file.FullPath);
|
var relativePath = HelperFunctions.GetRelativePath(ProjectDir, fi.Directory.ToString());
|
var fixedRelativePath = FixFilePathForComparison(relativePath);
|
if (!paths.Any(p => FixFilePathForComparison(p) == fixedRelativePath))
|
compiler.AddAdditionalIncludeDirectories(relativePath);
|
}
|
}
|
return file;
|
}
|
|
/// <summary>
|
/// adjusts the whitespaces, tabs in the given file according to VS settings
|
/// </summary>
|
/// <param name="file"></param>
|
public void AdjustWhitespace(string file)
|
{
|
if (!File.Exists(file))
|
return;
|
|
// only replace whitespaces in known types
|
if (!HelperFunctions.IsSourceFile(file) && !HelperFunctions.IsHeaderFile(file)
|
&& !HelperFunctions.IsUicFile(file)) {
|
return;
|
}
|
|
try {
|
var prop = dte.get_Properties("TextEditor", "C/C++");
|
var tabSize = Convert.ToInt64(prop.Item("TabSize").Value);
|
var insertTabs = Convert.ToBoolean(prop.Item("InsertTabs").Value);
|
|
var oldValue = insertTabs ? " " : "\t";
|
var newValue = insertTabs ? "\t" : GetWhitespaces(tabSize);
|
|
var list = new List<string>();
|
var reader = new StreamReader(file);
|
var line = reader.ReadLine();
|
while (line != null) {
|
if (line.StartsWith(oldValue, StringComparison.Ordinal))
|
line = line.Replace(oldValue, newValue);
|
list.Add(line);
|
line = reader.ReadLine();
|
}
|
reader.Close();
|
|
var writer = new StreamWriter(file);
|
foreach (var l in list)
|
writer.WriteLine(l);
|
writer.Close();
|
} catch (Exception e) {
|
Messages.Print(SR.GetString("QtProject_CannotAdjustWhitespaces",
|
e.ToString()));
|
}
|
}
|
|
private static string GetWhitespaces(long size)
|
{
|
var whitespaces = string.Empty;
|
for (long i = 0; i < size; ++i)
|
whitespaces += " ";
|
return whitespaces;
|
}
|
|
/// <summary>
|
/// Copy a file to the projects folder. Does not add the file to the project.
|
/// </summary>
|
/// <param name="srcFile">full name of the file to add</param>
|
/// <param name="destFolder">the name of the project folder</param>
|
/// <param name="destName">name of the file in the project (relative to the project directory)</param>
|
/// <returns>full name of the destination file</returns>
|
public static string CopyFileToFolder(string srcFile, string destFolder, string destName)
|
{
|
var fullDestName = destFolder + "\\" + destName;
|
var fi = new FileInfo(fullDestName);
|
|
var replace = true;
|
if (File.Exists(fullDestName)) {
|
if (DialogResult.No == MessageBox.Show(SR.GetString("QtProject_FileExistsInProjectFolder", destName)
|
, SR.GetString("Resources_QtVsTools"), MessageBoxButtons.YesNo, MessageBoxIcon.Question)) {
|
replace = false;
|
}
|
}
|
|
if (replace) {
|
if (!fi.Directory.Exists)
|
fi.Directory.Create();
|
File.Copy(srcFile, fullDestName, true);
|
var attribs = File.GetAttributes(fullDestName);
|
File.SetAttributes(fullDestName, attribs & (~FileAttributes.ReadOnly));
|
}
|
return fi.FullName;
|
}
|
|
public static void ReplaceTokenInFile(string file, string token, string replacement)
|
{
|
var text = string.Empty;
|
try {
|
var reader = new StreamReader(file);
|
text = reader.ReadToEnd();
|
reader.Close();
|
} catch (Exception e) {
|
Messages.DisplayErrorMessage(
|
SR.GetString("QtProject_CannotReplaceTokenRead", token, replacement, e.ToString()));
|
return;
|
}
|
|
try {
|
if (token.ToUpper() == "%PRE_DEF%" && !Char.IsLetter(replacement[0]))
|
replacement = "_" + replacement;
|
|
text = text.Replace(token, replacement);
|
var writer = new StreamWriter(file);
|
writer.Write(text);
|
writer.Close();
|
} catch (Exception e) {
|
Messages.DisplayErrorMessage(
|
SR.GetString("QtProject_CannotReplaceTokenWrite", token, replacement, e.ToString()));
|
}
|
}
|
|
public void RepairGeneratedFilesStructure()
|
{
|
DeleteGeneratedFiles();
|
|
var files = new ConcurrentBag<VCFile>();
|
Task.WaitAll(
|
Task.Run(() =>
|
Parallel.ForEach(((IVCCollection)vcPro.Files).Cast<VCFile>(), file =>
|
{
|
var name = file.Name;
|
if (!HelperFunctions.IsHeaderFile(name) && !HelperFunctions.IsSourceFile(name))
|
return;
|
if (HelperFunctions.HasQObjectDeclaration(file))
|
files.Add(file);
|
})
|
)
|
);
|
|
qtMsBuild.BeginSetItemProperties();
|
foreach (var file in files) {
|
RemoveMocStep(file);
|
AddMocStep(file);
|
}
|
qtMsBuild.EndSetItemProperties();
|
}
|
|
public void TranslateFilterNames()
|
{
|
var filters = vcPro.Filters as IVCCollection;
|
if (filters == null)
|
return;
|
|
foreach (VCFilter filter in filters) {
|
if (filter.Name == "Form Files")
|
filter.Name = Filters.FormFiles().Name;
|
if (filter.Name == "Generated Files")
|
filter.Name = Filters.GeneratedFiles().Name;
|
if (filter.Name == "Header Files")
|
filter.Name = Filters.HeaderFiles().Name;
|
if (filter.Name == "Resource Files")
|
filter.Name = Filters.ResourceFiles().Name;
|
if (filter.Name == "Source Files")
|
filter.Name = Filters.SourceFiles().Name;
|
}
|
}
|
|
public static string CreateQrcFile(string projectDir, string className, string destName)
|
{
|
var fullDestName = projectDir + "\\" + destName;
|
|
if (!File.Exists(fullDestName)) {
|
FileStream s = null;
|
try {
|
s = File.Open(fullDestName, FileMode.CreateNew);
|
if (s.CanWrite) {
|
using (var sw = new StreamWriter(s)) {
|
s = null;
|
sw.WriteLine("<RCC>");
|
sw.WriteLine(" <qresource prefix=\"" + className + "\">");
|
sw.WriteLine(" </qresource>");
|
sw.WriteLine("</RCC>");
|
}
|
}
|
} finally {
|
if (s != null)
|
s.Dispose();
|
}
|
var attribs = File.GetAttributes(fullDestName);
|
File.SetAttributes(fullDestName, attribs & (~FileAttributes.ReadOnly));
|
}
|
|
var fi = new FileInfo(fullDestName);
|
return fi.FullName;
|
}
|
|
public void AddActiveQtBuildStep(string version, string defFile = null)
|
{
|
if (FormatVersion < Resources.qtMinFormatVersion_ClProperties)
|
return;
|
|
foreach (VCConfiguration config in (IVCCollection)vcPro.Configurations) {
|
var idlFile = "\"$(IntDir)/" + envPro.Name + ".idl\"";
|
var tblFile = "\"$(IntDir)/" + envPro.Name + ".tlb\"";
|
|
var tool = (VCPostBuildEventTool)((IVCCollection)config.Tools).Item("VCPostBuildEventTool");
|
var idc = "$(QTDIR)\\bin\\idc.exe \"$(TargetPath)\" /idl " + idlFile + " -version " + version;
|
var midl = "midl " + idlFile + " /tlb " + tblFile;
|
var idc2 = "$(QTDIR)\\bin\\idc.exe \"$(TargetPath)\" /tlb " + tblFile;
|
var idc3 = "$(QTDIR)\\bin\\idc.exe \"$(TargetPath)\" /regserver";
|
|
tool.CommandLine = idc + "\r\n" + midl + "\r\n" + idc2 + "\r\n" + idc3;
|
tool.Description = string.Empty;
|
|
var linker = (VCLinkerTool)((IVCCollection)config.Tools).Item("VCLinkerTool");
|
var librarian = (VCLibrarianTool)((IVCCollection)config.Tools).Item("VCLibrarianTool");
|
|
if (linker != null) {
|
linker.Version = version;
|
linker.ModuleDefinitionFile = defFile ?? envPro.Name + ".def";
|
} else {
|
librarian.ModuleDefinitionFile = defFile ?? envPro.Name + ".def";
|
}
|
}
|
}
|
|
private void UpdateCompilerIncludePaths(string oldDir, string newDir)
|
{
|
var fixedOldDir = FixFilePathForComparison(oldDir);
|
var dirs = new[] {
|
FixFilePathForComparison(QtVSIPSettings.GetUicDirectory(envPro)),
|
FixFilePathForComparison(QtVSIPSettings.GetMocDirectory(envPro)),
|
FixFilePathForComparison(QtVSIPSettings.GetRccDirectory(envPro))
|
};
|
|
var oldDirIsUsed = dirs.Any(dir => dir == fixedOldDir);
|
|
var incList = new List<string>();
|
foreach (VCConfiguration config in (IVCCollection)vcPro.Configurations) {
|
var compiler = CompilerToolWrapper.Create(config);
|
if (compiler == null)
|
continue;
|
var paths = compiler.AdditionalIncludeDirectories;
|
if (paths.Count == 0)
|
continue;
|
|
if (!oldDirIsUsed) {
|
for (var i = paths.Count - 1; i >= 0; --i) {
|
if (FixFilePathForComparison(paths[i]) == fixedOldDir)
|
paths.RemoveAt(i);
|
}
|
}
|
incList.Clear();
|
foreach (var path in paths) {
|
var tmp = HelperFunctions.NormalizeRelativeFilePath(path);
|
if (tmp.Length > 0 && !incList.Contains(tmp))
|
incList.Add(tmp);
|
}
|
var alreadyThere = false;
|
var fixedNewDir = FixFilePathForComparison(newDir);
|
foreach (var include in incList) {
|
if (FixFilePathForComparison(include) == fixedNewDir) {
|
alreadyThere = true;
|
break;
|
}
|
}
|
if (!alreadyThere)
|
incList.Add(HelperFunctions.NormalizeRelativeFilePath(newDir));
|
|
compiler.AdditionalIncludeDirectories = incList;
|
}
|
}
|
|
private static string FixFilePathForComparison(string path)
|
{
|
path = HelperFunctions.NormalizeRelativeFilePath(path);
|
return path.ToLower();
|
}
|
|
public void UpdateUicSteps(string oldUicDir, bool update_inc_path)
|
{
|
Messages.Print("\r\n=== Update uic steps ===");
|
var vcFilter = FindFilterFromGuid(Filters.GeneratedFiles().UniqueIdentifier);
|
if (vcFilter != null) {
|
var filterFiles = (IVCCollection)vcFilter.Files;
|
for (var i = filterFiles.Count; i > 0; i--) {
|
var file = (VCFile)filterFiles.Item(i);
|
if (file.Name.StartsWith("ui_", StringComparison.OrdinalIgnoreCase)) {
|
RemoveFileFromFilter(file, vcFilter);
|
HelperFunctions.DeleteEmptyParentDirs(file);
|
}
|
}
|
}
|
|
var updatedFiles = 0;
|
var j = 0;
|
|
var files = new VCFile[((IVCCollection)vcPro.Files).Count];
|
foreach (VCFile file in (IVCCollection)vcPro.Files)
|
files[j++] = file;
|
|
qtMsBuild.BeginSetItemProperties();
|
foreach (var file in files) {
|
if (HelperFunctions.IsUicFile(file.Name) && !IsUic3File(file)) {
|
AddUic4BuildStep(file);
|
Messages.Print("Update uic step for " + file.Name + ".");
|
++updatedFiles;
|
}
|
}
|
qtMsBuild.EndSetItemProperties();
|
if (update_inc_path)
|
UpdateCompilerIncludePaths(oldUicDir, QtVSIPSettings.GetUicDirectory(envPro));
|
|
Messages.Print("\r\n=== " + updatedFiles + " uic steps updated. ===\r\n");
|
}
|
|
private static bool IsUic3File(VCFile file)
|
{
|
foreach (VCFileConfiguration config in (IVCCollection)file.FileConfigurations) {
|
var tool = HelperFunctions.GetCustomBuildTool(config);
|
if (tool == null)
|
return false;
|
if (tool.CommandLine.IndexOf("uic3.exe", StringComparison.OrdinalIgnoreCase) > -1)
|
return true;
|
}
|
return false;
|
}
|
|
public bool UsePrecompiledHeaders(VCConfiguration config)
|
{
|
var compiler = CompilerToolWrapper.Create(config);
|
return UsePrecompiledHeaders(compiler);
|
}
|
|
private bool UsePrecompiledHeaders(CompilerToolWrapper compiler)
|
{
|
try {
|
compiler.SetUsePrecompiledHeader(pchOption.pchUseUsingSpecific);
|
var pcHeaderThrough = GetPrecompiledHeaderThrough();
|
if (string.IsNullOrEmpty(pcHeaderThrough))
|
pcHeaderThrough = "stdafx.h";
|
compiler.SetPrecompiledHeaderThrough(pcHeaderThrough);
|
var pcHeaderFile = GetPrecompiledHeaderFile();
|
if (string.IsNullOrEmpty(pcHeaderFile))
|
pcHeaderFile = ".\\$(ConfigurationName)/" + Project.Name + ".pch";
|
compiler.SetPrecompiledHeaderFile(pcHeaderFile);
|
return true;
|
} catch {
|
return false;
|
}
|
}
|
|
public bool UsesPrecompiledHeaders()
|
{
|
foreach (VCConfiguration config in vcPro.Configurations as IVCCollection) {
|
if (!UsesPrecompiledHeaders(config))
|
return false;
|
}
|
return true;
|
}
|
|
public static bool UsesPrecompiledHeaders(VCConfiguration config)
|
{
|
var compiler = CompilerToolWrapper.Create(config);
|
return UsesPrecompiledHeaders(compiler);
|
}
|
|
private static bool UsesPrecompiledHeaders(CompilerToolWrapper compiler)
|
{
|
try {
|
if (compiler.GetUsePrecompiledHeader() != pchOption.pchNone)
|
return true;
|
} catch { }
|
return false;
|
}
|
|
public string GetPrecompiledHeaderThrough()
|
{
|
foreach (VCConfiguration config in vcPro.Configurations as IVCCollection) {
|
var header = GetPrecompiledHeaderThrough(config);
|
if (header != null)
|
return header;
|
}
|
return null;
|
}
|
|
public static string GetPrecompiledHeaderThrough(VCConfiguration config)
|
{
|
var compiler = CompilerToolWrapper.Create(config);
|
return GetPrecompiledHeaderThrough(compiler);
|
}
|
|
private static string GetPrecompiledHeaderThrough(CompilerToolWrapper compiler)
|
{
|
try {
|
var header = compiler.GetPrecompiledHeaderThrough();
|
if (!string.IsNullOrEmpty(header))
|
return header.ToLower();
|
} catch { }
|
return null;
|
}
|
|
public string GetPrecompiledHeaderFile()
|
{
|
foreach (VCConfiguration config in vcPro.Configurations as IVCCollection) {
|
var file = GetPrecompiledHeaderFile(config);
|
if (!string.IsNullOrEmpty(file))
|
return file;
|
}
|
return null;
|
}
|
|
public static string GetPrecompiledHeaderFile(VCConfiguration config)
|
{
|
var compiler = CompilerToolWrapper.Create(config);
|
return GetPrecompiledHeaderFile(compiler);
|
}
|
|
private static string GetPrecompiledHeaderFile(CompilerToolWrapper compiler)
|
{
|
try {
|
var file = compiler.GetPrecompiledHeaderFile();
|
if (!string.IsNullOrEmpty(file))
|
return file;
|
} catch { }
|
return null;
|
}
|
|
public static void SetPCHOption(VCFile vcFile, pchOption option)
|
{
|
foreach (VCFileConfiguration config in vcFile.FileConfigurations as IVCCollection) {
|
var compiler = CompilerToolWrapper.Create(config);
|
compiler.SetUsePrecompiledHeader(option);
|
}
|
}
|
|
private static VCFileConfiguration GetVCFileConfigurationByName(VCFile file, string configName)
|
{
|
foreach (VCFileConfiguration cfg in (IVCCollection)file.FileConfigurations) {
|
if (cfg.Name == configName)
|
return cfg;
|
}
|
return null;
|
}
|
|
/// <summary>
|
/// Searches for the generated file inside the "Generated Files" filter.
|
/// The function looks for the given filename and uses the fileConfig's
|
/// ConfigurationName and Platform if moc directory contains $(ConfigurationName)
|
/// and/or $(PlatformName).
|
/// Otherwise it just uses the "Generated Files" filter
|
/// </summary>
|
/// <param name="fileName"></param>
|
/// <param name="fileConfig"></param>
|
/// <returns></returns>
|
private VCFile GetGeneratedMocFile(string fileName, VCFileConfiguration fileConfig)
|
{
|
if (QtVSIPSettings.HasDifferentMocFilePerConfig(envPro)
|
|| QtVSIPSettings.HasDifferentMocFilePerPlatform(envPro)) {
|
var projectConfig = (VCConfiguration)fileConfig.ProjectConfiguration;
|
var configName = projectConfig.ConfigurationName;
|
var platformName = ((VCPlatform)projectConfig.Platform).Name;
|
var generatedFiles = FindFilterFromGuid(Filters.GeneratedFiles().UniqueIdentifier);
|
if (generatedFiles == null)
|
return null;
|
foreach (VCFilter filt in (IVCCollection)generatedFiles.Filters) {
|
if (filt.Name == configName + "_" + platformName ||
|
filt.Name == configName || filt.Name == platformName) {
|
foreach (VCFile filtFile in (IVCCollection)filt.Files) {
|
if (HelperFunctions.PathIsRelativeTo(filtFile.FullPath, fileName))
|
return filtFile;
|
}
|
}
|
}
|
|
//If a project from the an AddIn prior to 1.1.0 was loaded, the generated files are located directly
|
//in the generated files filter.
|
var relativeMocPath = QtVSIPSettings.GetMocDirectory(
|
envPro,
|
configName,
|
platformName,
|
fileConfig.File as VCFile)
|
+ '\\' + fileName;
|
//Remove .\ at the beginning of the mocPath
|
if (relativeMocPath.StartsWith(".\\", StringComparison.Ordinal))
|
relativeMocPath = relativeMocPath.Remove(0, 2);
|
foreach (VCFile filtFile in (IVCCollection)generatedFiles.Files) {
|
if (HelperFunctions.PathIsRelativeTo(filtFile.FullPath, relativeMocPath))
|
return filtFile;
|
}
|
} else {
|
var generatedFiles = FindFilterFromGuid(Filters.GeneratedFiles().UniqueIdentifier);
|
foreach (VCFile filtFile in (IVCCollection)generatedFiles.Files) {
|
if (HelperFunctions.PathIsRelativeTo(filtFile.FullPath, fileName))
|
return filtFile;
|
}
|
}
|
return null;
|
}
|
|
public void RefreshQtMocIncludePath()
|
{
|
foreach (VCConfiguration config in (IVCCollection)vcPro.Configurations) {
|
var propsClCompile = config.Rules.Item("CL") as IVCRulePropertyStorage;
|
var ruleName = GetRuleName(config, QtMoc.ItemTypeName);
|
var propsQtMoc = config.Rules.Item(ruleName) as IVCRulePropertyStorage;
|
if (propsClCompile == null || propsQtMoc == null)
|
continue;
|
propsQtMoc.SetPropertyValue(QtMoc.Property.IncludePath.ToString(),
|
propsClCompile.GetUnevaluatedPropertyValue("AdditionalIncludeDirectories"));
|
}
|
}
|
|
public void RefreshQtMocDefine()
|
{
|
foreach (VCConfiguration config in (IVCCollection)vcPro.Configurations) {
|
var propsClCompile = config.Rules.Item("CL") as IVCRulePropertyStorage;
|
var ruleName = GetRuleName(config, QtMoc.ItemTypeName);
|
var propsQtMoc = config.Rules.Item(ruleName) as IVCRulePropertyStorage;
|
if (propsClCompile == null || propsQtMoc == null)
|
continue;
|
propsQtMoc.SetPropertyValue(QtMoc.Property.Define.ToString(),
|
propsClCompile.GetUnevaluatedPropertyValue("PreprocessorDefinitions"));
|
}
|
}
|
|
public void RefreshMocSteps()
|
{
|
// Ignore when using shared compiler properties
|
if (GetFormatVersion(vcPro) >= Resources.qtMinFormatVersion_ClProperties)
|
return;
|
|
var filesCollection = vcPro.Files as IVCCollection;
|
if (filesCollection == null)
|
return;
|
|
int progress = 0;
|
int progressTotal = filesCollection.Count;
|
var waitDialog = WaitDialog.StartWithProgress(SR.GetString("Resources_QtVsTools"),
|
SR.GetString("WaitDialogRefreshMoc"), progressTotal, progress++, delay: 5);
|
qtMsBuild.BeginSetItemProperties();
|
foreach (VCFile vcfile in filesCollection) {
|
RefreshMocStep(vcfile, false);
|
waitDialog.Update(SR.GetString("WaitDialogRefreshMoc"), progressTotal, progress++);
|
}
|
waitDialog.Stop();
|
|
waitDialog = WaitDialog.Start(SR.GetString("Resources_QtVsTools"),
|
SR.GetString("WaitDialogRefreshMoc"), delay: 2);
|
qtMsBuild.EndSetItemProperties();
|
waitDialog.Stop();
|
}
|
|
public void RefreshMocStep(VCFile vcfile)
|
{
|
RefreshMocStep(vcfile, true);
|
}
|
|
/// <summary>
|
/// Updates the moc command line for the given header or source file
|
/// containing the Q_OBJECT macro.
|
/// If the function is called from a property change for a single file
|
/// (singleFile = true) we may have to look for the according header
|
/// file and refresh the moc step for this file, if it contains Q_OBJECT.
|
/// </summary>
|
/// <param name="vcfile"></param>
|
private void RefreshMocStep(VCFile vcfile, bool singleFile)
|
{
|
var isHeaderFile = HelperFunctions.IsHeaderFile(vcfile.FullPath);
|
if (!isHeaderFile && !HelperFunctions.IsSourceFile(vcfile.FullPath))
|
return;
|
|
if (mocCmdChecker == null)
|
mocCmdChecker = new MocCmdChecker();
|
|
foreach (VCFileConfiguration config in (IVCCollection)vcfile.FileConfigurations) {
|
try {
|
string commandLine = "";
|
VCCustomBuildTool tool = null;
|
VCFile mocable = null;
|
var customBuildConfig = config;
|
if (isHeaderFile || vcfile.ItemType == QtMoc.ItemTypeName) {
|
mocable = vcfile;
|
if (vcfile.ItemType == "CustomBuild")
|
tool = HelperFunctions.GetCustomBuildTool(config);
|
} else {
|
var mocFileName = GetMocFileName(vcfile.FullPath);
|
var mocFile = GetGeneratedMocFile(mocFileName, config);
|
if (mocFile == null)
|
continue;
|
|
var mocFileConfig = GetVCFileConfigurationByName(mocFile, config.Name);
|
if (vcfile.ItemType == "CustomBuild")
|
tool = HelperFunctions.GetCustomBuildTool(mocFileConfig);
|
mocable = mocFile;
|
// It is possible that the function was called from a source file's property change, it is possible that
|
// we have to obtain the tool from the according header file
|
if ((vcfile.ItemType != "CustomBuild" || tool == null) && singleFile) {
|
var headerName = vcfile.FullPath.Remove(vcfile.FullPath.LastIndexOf('.')) + ".h";
|
mocFileName = GetMocFileName(headerName);
|
mocFile = GetGeneratedMocFile(mocFileName, config);
|
if (mocFile != null) {
|
mocable = GetFileFromProject(headerName);
|
customBuildConfig = GetVCFileConfigurationByName(mocable, config.Name);
|
if (mocable.ItemType == "CustomBuild")
|
tool = HelperFunctions.GetCustomBuildTool(customBuildConfig);
|
}
|
}
|
}
|
|
if (mocable.ItemType == "CustomBuild") {
|
if (tool != null)
|
commandLine = tool.CommandLine;
|
} else if (mocable.ItemType == QtMoc.ItemTypeName) {
|
commandLine = qtMsBuild.GenerateQtMocCommandLine(customBuildConfig);
|
} else {
|
continue;
|
}
|
|
if ((mocable.ItemType == "CustomBuild" && tool == null)
|
|| commandLine.IndexOf(
|
"moc.exe",
|
StringComparison.OrdinalIgnoreCase) == -1)
|
continue;
|
|
VCFile srcMocFile, cppFile;
|
if (vcfile.ItemType == QtMoc.ItemTypeName
|
&& HelperFunctions.IsSourceFile(vcfile.ItemName)) {
|
srcMocFile = cppFile = vcfile;
|
} else {
|
srcMocFile = GetSourceFileForMocStep(mocable);
|
cppFile = GetCppFileForMocStep(mocable);
|
}
|
if (srcMocFile == null)
|
continue;
|
var mocableIsCPP = (srcMocFile == cppFile);
|
|
var cppItemType = (cppFile != null) ? cppFile.ItemType : "";
|
if (cppFile != null && cppItemType != "ClCompile")
|
cppFile.ItemType = "ClCompile";
|
|
string pchParameters = null;
|
VCFileConfiguration defineIncludeConfig = null;
|
CompilerToolWrapper compiler = null;
|
if (cppFile == null) {
|
// No file specific defines/includes
|
// but at least the project defines/includes are added
|
defineIncludeConfig = config;
|
compiler = CompilerToolWrapper.Create(config.ProjectConfiguration as VCConfiguration);
|
} else {
|
defineIncludeConfig = GetVCFileConfigurationByName(cppFile, config.Name);
|
compiler = CompilerToolWrapper.Create(defineIncludeConfig);
|
}
|
|
if (compiler != null && compiler.GetUsePrecompiledHeader() != pchOption.pchNone)
|
pchParameters = GetPCHMocOptions(srcMocFile, compiler);
|
|
var outputFileName = QtVSIPSettings.GetMocDirectory(envPro) + "\\";
|
if (mocableIsCPP) {
|
outputFileName += ProjectMacros.Name;
|
outputFileName += ".moc";
|
} else {
|
outputFileName += "moc_";
|
outputFileName += ProjectMacros.Name;
|
outputFileName += ".cpp";
|
}
|
|
var newCmdLine = mocCmdChecker.NewCmdLine(commandLine,
|
GetIncludes(defineIncludeConfig),
|
GetDefines(defineIncludeConfig),
|
QtVSIPSettings.GetMocOptions(envPro), srcMocFile.RelativePath,
|
pchParameters,
|
outputFileName);
|
|
if (cppFile != null && cppItemType != "ClCompile")
|
cppFile.ItemType = cppItemType;
|
|
// The tool's command line automatically gets a trailing "\r\n".
|
// We have to remove it to make the check below work.
|
var origCommandLine = commandLine;
|
if (origCommandLine.EndsWith("\r\n", StringComparison.Ordinal))
|
origCommandLine = origCommandLine.Substring(0, origCommandLine.Length - 2);
|
|
if (newCmdLine != null && newCmdLine != origCommandLine) {
|
// We have to delete the old moc file in order to trigger custom build step.
|
var configName = config.Name.Remove(config.Name.IndexOf('|'));
|
var platformName = config.Name.Substring(config.Name.IndexOf('|') + 1);
|
var projectPath = envPro.FullName.Remove(envPro.FullName.LastIndexOf('\\'));
|
var mocRelPath = GetRelativeMocFilePath(srcMocFile.FullPath, configName, platformName);
|
var mocPath = Path.Combine(projectPath, mocRelPath);
|
if (File.Exists(mocPath))
|
File.Delete(mocPath);
|
if (mocable.ItemType == "CustomBuild") {
|
tool.CommandLine = newCmdLine;
|
} else {
|
qtMsBuild.SetQtMocCommandLine(
|
customBuildConfig, newCmdLine, new VCMacroExpander(config));
|
}
|
}
|
} catch {
|
Messages.Print("ERROR: failed to refresh moc step for " + vcfile.ItemName);
|
}
|
}
|
}
|
|
public void OnExcludedFromBuildChanged(VCFile vcFile, VCFileConfiguration vcFileCfg)
|
{
|
// Update the ExcludedFromBuild flags of the mocced file
|
// according to the ExcludedFromBuild flag of the mocable source file.
|
var moccedFileName = GetMocFileName(vcFile.Name);
|
if (string.IsNullOrEmpty(moccedFileName))
|
return;
|
|
var moccedFile = GetGeneratedMocFile(moccedFileName, vcFileCfg);
|
|
if (moccedFile != null) {
|
VCFile cppFile = null;
|
if (HelperFunctions.IsHeaderFile(vcFile.Name))
|
cppFile = GetCppFileForMocStep(vcFile);
|
|
var moccedFileConfig = GetVCFileConfigurationByName(moccedFile, vcFileCfg.Name);
|
if (moccedFileConfig != null) {
|
if (cppFile != null && IsMoccedFileIncluded(cppFile)) {
|
if (!moccedFileConfig.ExcludedFromBuild)
|
moccedFileConfig.ExcludedFromBuild = true;
|
} else if (moccedFileConfig.ExcludedFromBuild != vcFileCfg.ExcludedFromBuild) {
|
moccedFileConfig.ExcludedFromBuild = vcFileCfg.ExcludedFromBuild;
|
}
|
}
|
}
|
}
|
|
/// <summary>
|
/// Helper function for RefreshMocStep.
|
/// </summary>
|
/// <param name="file"></param>
|
/// <returns></returns>
|
private VCFile GetSourceFileForMocStep(VCFile file)
|
{
|
if (HelperFunctions.IsHeaderFile(file.Name))
|
return file;
|
var fileName = file.Name;
|
if (HelperFunctions.IsMocFile(fileName)) {
|
fileName = fileName.Substring(0, fileName.Length - 4) + ".cpp";
|
if (fileName.Length > 0) {
|
foreach (VCFile f in (IVCCollection)vcPro.Files) {
|
if (f.FullPath.EndsWith("\\" + fileName, StringComparison.Ordinal))
|
return f;
|
}
|
}
|
}
|
return null;
|
}
|
|
/// <summary>
|
/// Helper function for Refresh/UpdateMocStep.
|
/// </summary>
|
/// <param name="file"></param>
|
/// <returns></returns>
|
private VCFile GetCppFileForMocStep(VCFile file)
|
{
|
string fileName = file.Name;
|
if (fileName.EndsWith(".moc.cbt", StringComparison.OrdinalIgnoreCase))
|
fileName = fileName.Remove(fileName.LastIndexOf('.'));
|
if (HelperFunctions.IsHeaderFile(fileName) || HelperFunctions.IsMocFile(fileName)) {
|
fileName = fileName.Remove(fileName.LastIndexOf('.')) + ".cpp";
|
foreach (VCFile f in (IVCCollection)vcPro.Files) {
|
if (f.FullPath.EndsWith("\\" + fileName, StringComparison.Ordinal))
|
return f;
|
}
|
}
|
return null;
|
}
|
|
public void UpdateMocSteps(string oldMocDir)
|
{
|
Messages.Print("\r\n=== Update moc steps ===");
|
var orgFiles = new List<VCFile>();
|
var abandonedMocFiles = new List<string>();
|
var vcFilter = FindFilterFromGuid(Filters.GeneratedFiles().UniqueIdentifier);
|
if (vcFilter != null) {
|
var generatedFiles = GetAllFilesFromFilter(vcFilter);
|
for (var i = generatedFiles.Count - 1; i >= 0; i--) {
|
var file = generatedFiles[i];
|
string fileName = null;
|
if (file.Name.StartsWith("moc_", StringComparison.OrdinalIgnoreCase))
|
fileName = file.Name.Substring(4, file.Name.Length - 8) + ".h";
|
else if (HelperFunctions.IsMocFile(file.Name))
|
fileName = file.Name.Substring(0, file.Name.Length - 4) + ".cpp";
|
|
if (fileName != null) {
|
var found = false;
|
foreach (VCFile f in (IVCCollection)vcPro.Files) {
|
if (f.FullPath.EndsWith("\\" + fileName, StringComparison.OrdinalIgnoreCase)) {
|
if (!orgFiles.Contains(f) && HasMocStep(f, oldMocDir))
|
orgFiles.Add(f);
|
found = true;
|
}
|
}
|
if (found) {
|
RemoveFileFromFilter(file, vcFilter);
|
HelperFunctions.DeleteEmptyParentDirs(file);
|
} else {
|
// We can't find foo.h for moc_foo.cpp or
|
// we can't find foo.cpp for foo.moc, thus we put the
|
// filename moc_foo.cpp / foo.moc into an error list.
|
abandonedMocFiles.Add(file.Name);
|
}
|
}
|
}
|
}
|
|
UpdateCompilerIncludePaths(oldMocDir, QtVSIPSettings.GetMocDirectory(envPro));
|
qtMsBuild.BeginSetItemProperties();
|
foreach (var file in orgFiles) {
|
try {
|
RemoveMocStep(file);
|
AddMocStep(file);
|
} catch (QtVSException e) {
|
Messages.Print(e.Message);
|
continue;
|
}
|
Messages.Print("Moc step updated successfully for " + file.Name + ".");
|
}
|
qtMsBuild.EndSetItemProperties();
|
|
foreach (var s in abandonedMocFiles) {
|
Messages.Print("Moc step update failed for " + s +
|
". Reason: Could not determine source file for moccing.");
|
}
|
Messages.Print("\r\n=== Moc steps updated. Successful: " + orgFiles.Count
|
+ " Failed: " + abandonedMocFiles.Count + " ===\r\n");
|
|
CleanupFilter(vcFilter);
|
}
|
|
private void Clean()
|
{
|
var solutionConfigs = envPro.DTE.Solution.SolutionBuild.SolutionConfigurations;
|
var backup = new List<KeyValuePair<SolutionContext, bool>>();
|
foreach (SolutionConfiguration config in solutionConfigs) {
|
var solutionContexts = config.SolutionContexts;
|
if (solutionContexts == null)
|
continue;
|
|
foreach (SolutionContext context in solutionContexts) {
|
backup.Add(new KeyValuePair<SolutionContext, bool>(context, context.ShouldBuild));
|
if (envPro.FullName.Contains(context.ProjectName)
|
&& context.PlatformName == envPro.ConfigurationManager.ActiveConfiguration.PlatformName)
|
context.ShouldBuild = true;
|
else
|
context.ShouldBuild = false;
|
}
|
}
|
try {
|
envPro.DTE.Solution.SolutionBuild.Clean(true);
|
} catch (System.Runtime.InteropServices.COMException) {
|
// TODO: Implement some logging mechanism for exceptions.
|
}
|
|
foreach (var item in backup)
|
item.Key.ShouldBuild = item.Value;
|
}
|
|
private void CleanupFilter(VCFilter filter)
|
{
|
var subFilters = filter.Filters as IVCCollection;
|
if (subFilters == null)
|
return;
|
|
for (var i = subFilters.Count; i > 0; i--) {
|
var subFilter = subFilters.Item(i) as VCFilter;
|
var subFilterFilters = subFilter.Filters as IVCCollection;
|
if (subFilterFilters == null)
|
continue;
|
|
CleanupFilter(subFilter);
|
|
var filterOrFileFound = false;
|
foreach (var itemObject in subFilter.Items as IVCCollection) {
|
if (itemObject is VCFilter || itemObject is VCFile) {
|
filterOrFileFound = true;
|
break;
|
}
|
}
|
if (!filterOrFileFound)
|
filter.RemoveFilter(subFilter);
|
}
|
}
|
|
public bool isWinRT()
|
{
|
try {
|
var vcProject = Project.Object as VCProject;
|
var vcConfigs = vcProject.Configurations as IVCCollection;
|
var vcConfig = vcConfigs.Item(1) as VCConfiguration;
|
var appType = vcConfig.GetEvaluatedPropertyValue("ApplicationType");
|
if (appType == "Windows Store")
|
return true;
|
} catch { }
|
return false;
|
}
|
|
public bool PromptChangeQtVersion(string oldVersion, string newVersion)
|
{
|
var versionManager = QtVersionManager.The();
|
var viOld = versionManager.GetVersionInfo(oldVersion);
|
var viNew = versionManager.GetVersionInfo(newVersion);
|
|
if (viOld == null || viNew == null)
|
return true;
|
|
var oldIsWinRt = viOld.isWinRT();
|
var newIsWinRt = viNew.isWinRT();
|
|
if (newIsWinRt == oldIsWinRt || newIsWinRt == isWinRT())
|
return true;
|
|
var promptCaption = string.Format("Change Qt Version ({0})", Project.Name);
|
var promptText = string.Format(
|
"Changing Qt version from {0} to {1}.\r\n" +
|
"Project might not build. Are you sure?",
|
newIsWinRt ? "Win32" : "WinRT",
|
newIsWinRt ? "WinRT" : "Win32"
|
);
|
|
return (MessageBox.Show(
|
promptText, promptCaption, MessageBoxButtons.YesNo, MessageBoxIcon.Warning)
|
== DialogResult.Yes);
|
}
|
|
/// <summary>
|
/// Changes the Qt version of this project.
|
/// </summary>
|
/// <param name="oldVersion">the current Qt version</param>
|
/// <param name="newVersion">the new Qt version we want to change to</param>
|
/// <param name="newProjectCreated">is set to true if a new Project object has been created</param>
|
/// <returns>true, if the operation performed successfully</returns>
|
public bool ChangeQtVersion(string oldVersion, string newVersion, ref bool newProjectCreated)
|
{
|
newProjectCreated = false;
|
var versionManager = QtVersionManager.The();
|
var viNew = versionManager.GetVersionInfo(newVersion);
|
if (viNew == null) {
|
Messages.DisplayErrorMessage(SR.GetString("CannotChangeQtVersion"));
|
return false;
|
}
|
string vsPlatformNameNew = viNew.GetVSPlatformName();
|
|
var viOld = versionManager.GetVersionInfo(oldVersion);
|
string vsPlatformNameOld = null;
|
if (viOld != null)
|
vsPlatformNameOld = viOld.GetVSPlatformName();
|
|
var refreshMocSteps = (vsPlatformNameNew != vsPlatformNameOld);
|
var platformChanged = (vsPlatformNameNew != vsPlatformNameOld);
|
|
try {
|
if (platformChanged) {
|
if (!SelectSolutionPlatform(vsPlatformNameNew) || !HasPlatform(vsPlatformNameNew)) {
|
CreatePlatform(vsPlatformNameOld, vsPlatformNameNew, viOld, viNew, ref newProjectCreated);
|
refreshMocSteps = false;
|
UpdateMocSteps(QtVSIPSettings.GetMocDirectory(envPro));
|
}
|
}
|
var configManager = envPro.ConfigurationManager;
|
if (configManager.ActiveConfiguration.PlatformName != vsPlatformNameNew) {
|
var projectName = envPro.FullName;
|
envPro.Save(null);
|
dte.Solution.Remove(envPro);
|
envPro = dte.Solution.AddFromFile(projectName, false);
|
dte = envPro.DTE;
|
vcPro = envPro.Object as VCProject;
|
}
|
} catch {
|
Messages.DisplayErrorMessage(SR.GetString("CannotChangeQtVersion"));
|
return false;
|
}
|
|
// We have to delete the generated files because of major
|
// differences between the platforms or Qt-Versions.
|
if (platformChanged || viOld.qtPatch != viNew.qtPatch
|
|| viOld.qtMinor != viNew.qtMinor || viOld.qtMajor != viNew.qtMajor) {
|
DeleteGeneratedFiles();
|
Clean();
|
}
|
|
if (refreshMocSteps)
|
RefreshMocSteps();
|
|
SetQtEnvironment(newVersion);
|
UpdateModules(viOld, viNew);
|
versionManager.SaveProjectQtVersion(envPro, newVersion, vsPlatformNameNew);
|
return true;
|
}
|
|
public bool HasPlatform(string platformName)
|
{
|
foreach (VCConfiguration config in (IVCCollection)vcPro.Configurations) {
|
var platform = (VCPlatform)config.Platform;
|
if (platform.Name == platformName)
|
return true;
|
}
|
return false;
|
}
|
|
public bool SelectSolutionPlatform(string platformName)
|
{
|
foreach (SolutionConfiguration solutionCfg in dte.Solution.SolutionBuild.SolutionConfigurations) {
|
var contexts = solutionCfg.SolutionContexts;
|
for (var i = 1; i <= contexts.Count; ++i) {
|
SolutionContext ctx = null;
|
try {
|
ctx = contexts.Item(i);
|
} catch (ArgumentException) {
|
// This may happen if we encounter an unloaded project.
|
continue;
|
}
|
|
if (ctx.PlatformName == platformName
|
&& solutionCfg.Name == dte.Solution.SolutionBuild.ActiveConfiguration.Name) {
|
solutionCfg.Activate();
|
return true;
|
}
|
}
|
}
|
|
return false;
|
}
|
|
public void CreatePlatform(string oldPlatform, string newPlatform,
|
VersionInformation viOld, VersionInformation viNew, ref bool newProjectCreated)
|
{
|
try {
|
var cfgMgr = envPro.ConfigurationManager;
|
cfgMgr.AddPlatform(newPlatform, oldPlatform, true);
|
vcPro.AddPlatform(newPlatform);
|
newProjectCreated = false;
|
} catch {
|
// That stupid ConfigurationManager can't handle platform names
|
// containing dots (e.g. "Windows Mobile 5.0 Pocket PC SDK (ARMV4I)")
|
// So we have to do it the nasty way...
|
var projectFileName = envPro.FullName;
|
envPro.Save(null);
|
dte.Solution.Remove(envPro);
|
AddPlatformToVCProj(projectFileName, oldPlatform, newPlatform);
|
envPro = dte.Solution.AddFromFile(projectFileName, false);
|
vcPro = (VCProject)envPro.Object;
|
newProjectCreated = true;
|
}
|
|
// update the platform settings
|
foreach (VCConfiguration config in (IVCCollection)vcPro.Configurations) {
|
var vcplatform = (VCPlatform)config.Platform;
|
if (vcplatform.Name == newPlatform) {
|
if (viOld != null)
|
RemovePlatformDependencies(config, viOld);
|
SetupConfiguration(config, viNew);
|
}
|
}
|
|
SelectSolutionPlatform(newPlatform);
|
}
|
|
public static void RemovePlatformDependencies(VCConfiguration config, VersionInformation viOld)
|
{
|
var compiler = CompilerToolWrapper.Create(config);
|
var minuend = new HashSet<string>(compiler.PreprocessorDefinitions);
|
minuend.ExceptWith(viOld.GetQMakeConfEntry("DEFINES").Split(' ', '\t'));
|
compiler.SetPreprocessorDefinitions(string.Join(",", minuend));
|
}
|
|
public void SetupConfiguration(VCConfiguration config, VersionInformation viNew)
|
{
|
var compiler = CompilerToolWrapper.Create(config);
|
var ppdefs = new HashSet<string>(compiler.PreprocessorDefinitions);
|
ppdefs.UnionWith(viNew.GetQMakeConfEntry("DEFINES").Split(' ', '\t'));
|
compiler.SetPreprocessorDefinitions(string.Join(",", ppdefs));
|
|
var linker = (VCLinkerTool)((IVCCollection)config.Tools).Item("VCLinkerTool");
|
if (linker == null)
|
return;
|
|
linker.SubSystem = subSystemOption.subSystemWindows;
|
SetTargetMachine(linker, viNew);
|
}
|
|
private void DeleteGeneratedFiles()
|
{
|
var genFilter = Filters.GeneratedFiles();
|
var genVCFilter = FindFilterFromGuid(genFilter.UniqueIdentifier);
|
if (genVCFilter == null)
|
return;
|
|
var error = false;
|
error = DeleteFilesFromFilter(genVCFilter);
|
if (error)
|
Messages.Print(SR.GetString("DeleteGeneratedFilesError"));
|
}
|
|
private bool DeleteFilesFromFilter(VCFilter filter)
|
{
|
var error = false;
|
foreach (VCFile f in filter.Files as IVCCollection) {
|
try {
|
var fi = new FileInfo(f.FullPath);
|
if (fi.Exists && fi.Extension != ".cbt")
|
fi.Delete();
|
HelperFunctions.DeleteEmptyParentDirs(fi.Directory.ToString());
|
} catch {
|
error = true;
|
}
|
}
|
foreach (VCFilter filt in filter.Filters as IVCCollection)
|
error |= DeleteFilesFromFilter(filt);
|
return error;
|
}
|
|
public void RemoveGeneratedFiles(string fileName)
|
{
|
var fi = new FileInfo(fileName);
|
var lastIndex = fileName.LastIndexOf(fi.Extension, StringComparison.Ordinal);
|
var baseName = fi.Name.Remove(lastIndex, fi.Extension.Length);
|
string delName = null;
|
if (HelperFunctions.IsHeaderFile(fileName))
|
delName = "moc_" + baseName + ".cpp";
|
else if (HelperFunctions.IsSourceFile(fileName) && !fileName.StartsWith("moc_", StringComparison.OrdinalIgnoreCase))
|
delName = baseName + ".moc";
|
else if (HelperFunctions.IsUicFile(fileName))
|
delName = "ui_" + baseName + ".h";
|
else if (HelperFunctions.IsQrcFile(fileName))
|
delName = "qrc_" + baseName + ".cpp";
|
|
if (delName != null) {
|
foreach (var delFile in GetFilesFromProject(delName))
|
RemoveFileFromFilter(delFile, Filters.GeneratedFiles());
|
}
|
}
|
|
public void RemoveResFilesFromGeneratedFilesFilter()
|
{
|
var generatedFiles = FindFilterFromGuid(Filters.GeneratedFiles().UniqueIdentifier);
|
if (generatedFiles == null)
|
return;
|
|
var filesToRemove = new List<VCFile>();
|
foreach (VCFile filtFile in (IVCCollection)generatedFiles.Files) {
|
if (filtFile.FullPath.EndsWith(".res", StringComparison.OrdinalIgnoreCase))
|
filesToRemove.Add(filtFile);
|
}
|
foreach (var resFile in filesToRemove)
|
resFile.Remove();
|
}
|
|
static private void AddPlatformToVCProj(string projectFileName, string oldPlatformName, string newPlatformName)
|
{
|
var tempFileName = Path.GetTempFileName();
|
var fi = new FileInfo(projectFileName);
|
fi.CopyTo(tempFileName, true);
|
|
var myXmlDocument = new XmlDocument();
|
myXmlDocument.Load(tempFileName);
|
AddPlatformToVCProj(myXmlDocument, oldPlatformName, newPlatformName);
|
myXmlDocument.Save(projectFileName);
|
|
fi = new FileInfo(tempFileName);
|
fi.Delete();
|
}
|
|
static private void AddPlatformToVCProj(XmlDocument doc, string oldPlatformName, string newPlatformName)
|
{
|
var vsProj = doc.DocumentElement.SelectSingleNode("/VisualStudioProject");
|
var platforms = vsProj.SelectSingleNode("Platforms");
|
if (platforms == null) {
|
platforms = doc.CreateElement("Platforms");
|
vsProj.AppendChild(platforms);
|
}
|
var platform = platforms.SelectSingleNode("Platform[@Name='" + newPlatformName + "']");
|
if (platform == null) {
|
platform = doc.CreateElement("Platform");
|
((XmlElement)platform).SetAttribute("Name", newPlatformName);
|
platforms.AppendChild(platform);
|
}
|
|
var configurations = vsProj.SelectSingleNode("Configurations");
|
var cfgList = configurations.SelectNodes("Configuration[@Name='Debug|" + oldPlatformName + "'] | " +
|
"Configuration[@Name='Release|" + oldPlatformName + "']");
|
foreach (XmlNode oldCfg in cfgList) {
|
var newCfg = (XmlElement)oldCfg.Clone();
|
newCfg.SetAttribute("Name", oldCfg.Attributes["Name"].Value.Replace(oldPlatformName, newPlatformName));
|
configurations.AppendChild(newCfg);
|
}
|
|
var fileCfgPath = "Files/Filter/File/FileConfiguration";
|
var fileCfgList = vsProj.SelectNodes(fileCfgPath + "[@Name='Debug|" + oldPlatformName + "'] | " +
|
fileCfgPath + "[@Name='Release|" + oldPlatformName + "']");
|
foreach (XmlNode oldCfg in fileCfgList) {
|
var newCfg = (XmlElement)oldCfg.Clone();
|
newCfg.SetAttribute("Name", oldCfg.Attributes["Name"].Value.Replace(oldPlatformName, newPlatformName));
|
oldCfg.ParentNode.AppendChild(newCfg);
|
}
|
}
|
|
static private void SetTargetMachine(VCLinkerTool linker, VersionInformation versionInfo)
|
{
|
var qMakeLFlagsWindows = versionInfo.GetQMakeConfEntry("QMAKE_LFLAGS_WINDOWS");
|
var rex = new Regex("/MACHINE:(\\S+)");
|
var match = rex.Match(qMakeLFlagsWindows);
|
if (match.Success) {
|
linker.TargetMachine = HelperFunctions.TranslateMachineType(match.Groups[1].Value);
|
} else {
|
var platformName = versionInfo.GetVSPlatformName();
|
if (platformName == "Win32")
|
linker.TargetMachine = machineTypeOption.machineX86;
|
else if (platformName == "x64")
|
linker.TargetMachine = machineTypeOption.machineAMD64;
|
else
|
linker.TargetMachine = machineTypeOption.machineNotSet;
|
}
|
|
var subsystemOption = string.Empty;
|
var linkerOptions = linker.AdditionalOptions ?? string.Empty;
|
|
rex = new Regex("(/SUBSYSTEM:\\S+)");
|
match = rex.Match(qMakeLFlagsWindows);
|
if (match.Success)
|
subsystemOption = match.Groups[1].Value;
|
|
match = rex.Match(linkerOptions);
|
if (match.Success) {
|
linkerOptions = rex.Replace(linkerOptions, subsystemOption);
|
} else {
|
if (linkerOptions.Length > 0)
|
linkerOptions += " ";
|
linkerOptions += subsystemOption;
|
}
|
linker.AdditionalOptions = linkerOptions;
|
}
|
|
public void CollapseFilter(string filterName)
|
{
|
var solutionExplorer = (UIHierarchy)dte.Windows.Item(Constants.vsext_wk_SProjectWindow).Object;
|
if (solutionExplorer.UIHierarchyItems.Count == 0)
|
return;
|
|
dte.SuppressUI = true;
|
var projectItem = FindProjectHierarchyItem(solutionExplorer);
|
if (projectItem != null)
|
HelperFunctions.CollapseFilter(projectItem, solutionExplorer, filterName);
|
dte.SuppressUI = false;
|
}
|
|
private UIHierarchyItem FindProjectHierarchyItem(UIHierarchy hierarchy)
|
{
|
if (hierarchy.UIHierarchyItems.Count == 0)
|
return null;
|
|
var solution = hierarchy.UIHierarchyItems.Item(1);
|
UIHierarchyItem projectItem = null;
|
foreach (UIHierarchyItem solutionItem in solution.UIHierarchyItems) {
|
projectItem = FindProjectHierarchyItem(solutionItem);
|
if (projectItem != null)
|
break;
|
}
|
return projectItem;
|
}
|
|
private UIHierarchyItem FindProjectHierarchyItem(UIHierarchyItem root)
|
{
|
UIHierarchyItem projectItem = null;
|
try {
|
if (root.Name == envPro.Name)
|
return root;
|
|
foreach (UIHierarchyItem childItem in root.UIHierarchyItems) {
|
projectItem = FindProjectHierarchyItem(childItem);
|
if (projectItem != null)
|
break;
|
}
|
} catch {
|
}
|
return projectItem;
|
}
|
|
/// <summary>
|
/// Gets the Qt version of the project
|
/// </summary>
|
public string GetQtVersion()
|
{
|
return QtVersionManager.The().GetProjectQtVersion(envPro);
|
}
|
|
/// <summary>
|
/// Sets the Qt environment for the project's Qt version.
|
/// </summary>
|
public void SetQtEnvironment()
|
{
|
SetQtEnvironment(QtVersionManager.The().GetProjectQtVersion(envPro));
|
}
|
|
/// <summary>
|
/// Sets the Qt environment for the given Qt version.
|
/// </summary>
|
public void SetQtEnvironment(string qtVersion)
|
{
|
SetQtEnvironment(qtVersion, string.Empty);
|
}
|
|
/// <summary>
|
/// Sets the Qt environment for the given Qt version.
|
/// </summary>
|
public void SetQtEnvironment(string qtVersion, string solutionConfig, bool build = false)
|
{
|
if (string.IsNullOrEmpty(qtVersion))
|
return;
|
|
if (FormatVersion >= Resources.qtMinFormatVersion_Settings)
|
return;
|
|
string qtDir = null;
|
if (qtVersion != "$(QTDIR)")
|
qtDir = QtVersionManager.The().GetInstallPath(qtVersion);
|
HelperFunctions.SetEnvironmentVariableEx("QTDIR", qtDir);
|
try {
|
var propertyAccess = (IVCBuildPropertyStorage)vcPro;
|
var vcprj = envPro.Object as VCProject;
|
|
// Get platform name from given solution configuration
|
// or if not available take the active configuration
|
var activePlatformName = string.Empty;
|
if (string.IsNullOrEmpty(solutionConfig)) {
|
// First get active configuration cause not given as parameter
|
var activeConf = envPro.ConfigurationManager.ActiveConfiguration;
|
solutionConfig = activeConf.ConfigurationName + "|" + activeConf.PlatformName;
|
activePlatformName = activeConf.PlatformName;
|
} else {
|
activePlatformName = solutionConfig.Split('|')[1];
|
}
|
|
// Find all configurations for platform and set property for all of them
|
// This is to get QTDIR property set for all configurations same time so
|
// we can be sure it is set and is equal between debug and release
|
foreach (VCConfiguration conf in vcprj.Configurations as IVCCollection) {
|
var cur_platform = conf.Platform as VCPlatform;
|
if (cur_platform.Name == activePlatformName) {
|
var cur_solution = conf.ConfigurationName + "|" + cur_platform.Name;
|
// If the LocalDebuggerEnvironment property is defined, it
|
// will be stored in the .user file before the QTDIR property, which is an
|
// error because there is a dependency. To work around this, first remove
|
// the property and then add it after QTDIR is defined.
|
var debuggerEnv = string.Empty;
|
if (!build) {
|
debuggerEnv = propertyAccess.GetPropertyValue(
|
"LocalDebuggerEnvironment", cur_solution, "UserFile");
|
if (!string.IsNullOrEmpty(debuggerEnv)) {
|
var debugSettings = conf.DebugSettings as VCDebugSettings;
|
if (debugSettings != null) {
|
//Get original value without expanded properties
|
debuggerEnv = debugSettings.Environment;
|
}
|
propertyAccess.RemoveProperty(
|
"LocalDebuggerEnvironment", cur_solution, "UserFile");
|
}
|
}
|
propertyAccess.SetPropertyValue("QTDIR", cur_solution, "UserFile", qtDir);
|
if (!string.IsNullOrEmpty(debuggerEnv))
|
propertyAccess.SetPropertyValue(
|
"LocalDebuggerEnvironment", cur_solution, "UserFile", debuggerEnv);
|
}
|
}
|
|
} catch (Exception) {
|
Messages.Print(SR.GetString("QtProject_CannotAccessUserFile", vcPro.ItemName));
|
}
|
|
HelperFunctions.SetDebuggingEnvironment(envPro);
|
}
|
|
public class CppConfig
|
{
|
public VCConfiguration Config;
|
public IVCRulePropertyStorage Cpp;
|
|
public string GetUserPropertyValue(string pszPropName)
|
{
|
var vcProj = Config.project as VCProject;
|
var projProps = vcProj as IVCBuildPropertyStorage;
|
try {
|
return projProps.GetPropertyValue(pszPropName, Config.Name, "UserFile");
|
} catch (Exception e) {
|
System.Diagnostics.Debug.WriteLine(
|
e.Message + "\r\n\r\nStacktrace:\r\n" + e.StackTrace);
|
return string.Empty;
|
}
|
}
|
|
public void SetUserPropertyValue(string pszPropName, string pszPropValue)
|
{
|
var vcProj = Config.project as VCProject;
|
var projProps = vcProj as IVCBuildPropertyStorage;
|
try {
|
projProps.SetPropertyValue(pszPropName, Config.Name, "UserFile", pszPropValue);
|
} catch (Exception e) {
|
System.Diagnostics.Debug.WriteLine(
|
e.Message + "\r\n\r\nStacktrace:\r\n" + e.StackTrace);
|
}
|
}
|
|
public void RemoveUserProperty(string pszPropName)
|
{
|
var vcProj = Config.project as VCProject;
|
var projProps = vcProj as IVCBuildPropertyStorage;
|
try {
|
projProps.RemoveProperty(pszPropName, Config.Name, "UserFile");
|
} catch (Exception e) {
|
System.Diagnostics.Debug.WriteLine(
|
e.Message + "\r\n\r\nStacktrace:\r\n" + e.StackTrace);
|
}
|
}
|
}
|
|
public static IEnumerable<CppConfig> GetCppConfigs(VCProject vcPro)
|
{
|
return ((IVCCollection)vcPro.Configurations).Cast<VCConfiguration>()
|
.Select(x => new CppConfig
|
{
|
Config = x,
|
Cpp = x.Rules.Item("CL") as IVCRulePropertyStorage,
|
})
|
.Where(x => x.Cpp != null
|
&& x.Config.GetEvaluatedPropertyValue("ApplicationType") != "Linux");
|
}
|
|
public static IEnumerable<CppConfig> GetCppDebugConfigs(VCProject vcPro)
|
{
|
return GetCppConfigs(vcPro).Where(x => x.Cpp
|
.GetEvaluatedPropertyValue("PreprocessorDefinitions").Split(new char[] { ';' })
|
.Contains("QT_NO_DEBUG") == false);
|
}
|
|
public static bool IsQtQmlDebugDefined(VCProject vcPro)
|
{
|
return (GetCppDebugConfigs(vcPro).Where(x => x.Cpp
|
.GetEvaluatedPropertyValue("PreprocessorDefinitions").Split(new char[] { ';' })
|
.Contains("QT_QML_DEBUG") == false)
|
.Any() == false);
|
}
|
|
public static void DefineQtQmlDebug(VCProject vcPro)
|
{
|
var configs = GetCppDebugConfigs(vcPro).Where(x => x.Cpp
|
.GetEvaluatedPropertyValue("PreprocessorDefinitions").Split(new char[] { ';' })
|
.Contains("QT_QML_DEBUG") == false)
|
.Select(x => new
|
{
|
x.Cpp,
|
Macros = x.Cpp.GetUnevaluatedPropertyValue("PreprocessorDefinitions")
|
});
|
|
foreach (var config in configs) {
|
config.Cpp.SetPropertyValue("PreprocessorDefinitions",
|
string.Format("QT_QML_DEBUG;{0}", config.Macros));
|
}
|
}
|
|
public static void UndefineQtQmlDebug(VCProject vcPro)
|
{
|
var configs = GetCppDebugConfigs(vcPro).Where(x => x.Cpp
|
.GetEvaluatedPropertyValue("PreprocessorDefinitions").Split(new char[] { ';' })
|
.Contains("QT_QML_DEBUG") == true)
|
.Select(x => new
|
{
|
x.Cpp,
|
Macros = x.Cpp.GetUnevaluatedPropertyValue("PreprocessorDefinitions")
|
.Split(new char[] { ';' }).ToList()
|
});
|
|
foreach (var config in configs) {
|
config.Macros.Remove("QT_QML_DEBUG");
|
config.Cpp.SetPropertyValue("PreprocessorDefinitions",
|
string.Join(";", config.Macros));
|
}
|
}
|
|
public static bool IsQmlJsDebuggerDefined(VCProject vcPro)
|
{
|
foreach (var config in GetCppDebugConfigs(vcPro)) {
|
var qmlDebug = config.GetUserPropertyValue("QmlDebug");
|
if (string.IsNullOrEmpty(qmlDebug))
|
return false;
|
var debugArgs = config.GetUserPropertyValue("LocalDebuggerCommandArguments");
|
if (string.IsNullOrEmpty(debugArgs))
|
return false;
|
if (!debugArgs.Contains(qmlDebug))
|
return false;
|
}
|
return true;
|
}
|
|
public static void DefineQmlJsDebugger(VCProject vcPro)
|
{
|
var configs = GetCppDebugConfigs(vcPro)
|
.Select(x => new
|
{
|
Self = x,
|
QmlDebug = x.GetUserPropertyValue("QmlDebug"),
|
Args = x.GetUserPropertyValue("LocalDebuggerCommandArguments")
|
})
|
.Where(x => string.IsNullOrEmpty(x.QmlDebug) || !x.Args.Contains(x.QmlDebug));
|
|
foreach (var config in configs) {
|
|
config.Self.RemoveUserProperty("LocalDebuggerCommandArguments");
|
config.Self.RemoveUserProperty("QmlDebug");
|
config.Self.RemoveUserProperty("QmlDebugSettings");
|
|
config.Self.SetUserPropertyValue("QmlDebugSettings", "file:$(ProjectGuid),block");
|
config.Self.SetUserPropertyValue("QmlDebug", "-qmljsdebugger=$(QmlDebugSettings)");
|
|
config.Self.SetUserPropertyValue("LocalDebuggerCommandArguments",
|
string.Join(" ", new[] { config.Args, "$(QmlDebug)" }).Trim());
|
}
|
}
|
|
public static void UndefineQmlJsDebugger(VCProject vcPro)
|
{
|
var configs = GetCppDebugConfigs(vcPro)
|
.Select(x => new
|
{
|
Self = x,
|
QmlDebug = x.GetUserPropertyValue("QmlDebug"),
|
Args = x.GetUserPropertyValue("LocalDebuggerCommandArguments")
|
})
|
.Where(x => !string.IsNullOrEmpty(x.QmlDebug) && x.Args.Contains(x.QmlDebug));
|
|
foreach (var config in configs) {
|
|
config.Self.SetUserPropertyValue("QmlDebug", "##QMLDEBUG##");
|
var args = config.Self.GetUserPropertyValue("LocalDebuggerCommandArguments");
|
|
var newArgs = args.Replace("##QMLDEBUG##", "").Trim();
|
if (string.IsNullOrEmpty(newArgs))
|
config.Self.RemoveUserProperty("LocalDebuggerCommandArguments");
|
else
|
config.Self.SetUserPropertyValue("LocalDebuggerCommandArguments", newArgs);
|
|
config.Self.RemoveUserProperty("QmlDebug");
|
config.Self.SetUserPropertyValue("QmlDebugSettings", "false");
|
}
|
}
|
|
public bool QmlDebug
|
{
|
get
|
{
|
return IsQtQmlDebugDefined(vcPro) && IsQmlJsDebuggerDefined(vcPro);
|
}
|
set
|
{
|
bool enabled = (IsQtQmlDebugDefined(vcPro) && IsQmlJsDebuggerDefined(vcPro));
|
if (value == enabled)
|
return;
|
|
if (value) {
|
DefineQtQmlDebug(vcPro);
|
DefineQmlJsDebugger(vcPro);
|
} else {
|
UndefineQtQmlDebug(vcPro);
|
UndefineQmlJsDebugger(vcPro);
|
}
|
}
|
}
|
}
|
|
public class VCPropertyStorageProvider : IPropertyStorageProvider
|
{
|
string GetProperty(IVCRulePropertyStorage propertyStorage, string propertyName)
|
{
|
if (propertyStorage == null)
|
return "";
|
return propertyStorage.GetUnevaluatedPropertyValue(propertyName);
|
}
|
|
public string GetProperty(object propertyStorage, string itemType, string propertyName)
|
{
|
if (propertyStorage == null)
|
return "";
|
if (propertyStorage is VCFileConfiguration) {
|
return GetProperty(
|
(propertyStorage as VCFileConfiguration).Tool
|
as IVCRulePropertyStorage,
|
propertyName);
|
} else if (propertyStorage is VCConfiguration) {
|
var config = propertyStorage as VCConfiguration;
|
var ruleName = QtProject.GetRuleName(config, itemType);
|
return GetProperty(config.Rules.Item(ruleName)
|
as IVCRulePropertyStorage,
|
propertyName);
|
}
|
return "";
|
}
|
|
static bool SetProperty(
|
IVCRulePropertyStorage propertyStorage,
|
string propertyName,
|
string propertyValue)
|
{
|
if (propertyStorage == null)
|
return false;
|
if (propertyStorage.GetUnevaluatedPropertyValue(propertyName) != propertyValue)
|
propertyStorage.SetPropertyValue(propertyName, propertyValue);
|
return true;
|
}
|
|
public bool SetProperty(
|
object propertyStorage,
|
string itemType,
|
string propertyName,
|
string propertyValue)
|
{
|
if (propertyStorage == null)
|
return false;
|
if (propertyStorage is VCFileConfiguration) {
|
return SetProperty(
|
(propertyStorage as VCFileConfiguration).Tool
|
as IVCRulePropertyStorage,
|
propertyName,
|
propertyValue);
|
} else if (propertyStorage is VCConfiguration) {
|
var config = propertyStorage as VCConfiguration;
|
var ruleName = QtProject.GetRuleName(config, itemType);
|
return SetProperty(
|
config.Rules.Item(ruleName)
|
as IVCRulePropertyStorage,
|
propertyName,
|
propertyValue);
|
}
|
return false;
|
}
|
|
static bool DeleteProperty(IVCRulePropertyStorage propertyStorage, string propertyName)
|
{
|
if (propertyStorage == null)
|
return false;
|
propertyStorage.DeleteProperty(propertyName);
|
return true;
|
}
|
|
public bool DeleteProperty(object propertyStorage, string itemType, string propertyName)
|
{
|
if (propertyStorage == null)
|
return false;
|
if (propertyStorage is VCFileConfiguration) {
|
return DeleteProperty(
|
(propertyStorage as VCFileConfiguration).Tool
|
as IVCRulePropertyStorage,
|
propertyName);
|
} else if (propertyStorage is VCConfiguration) {
|
var config = propertyStorage as VCConfiguration;
|
var ruleName = QtProject.GetRuleName(config, itemType);
|
return DeleteProperty(
|
config.Rules.Item(ruleName)
|
as IVCRulePropertyStorage,
|
propertyName);
|
}
|
return false;
|
}
|
|
public string GetConfigName(object propertyStorage)
|
{
|
if (propertyStorage == null)
|
return "";
|
if (propertyStorage is VCFileConfiguration)
|
return (propertyStorage as VCFileConfiguration).Name;
|
else if (propertyStorage is VCConfiguration)
|
return (propertyStorage as VCConfiguration).Name;
|
return "";
|
}
|
|
string GetItemType(VCFileConfiguration propertyStorage)
|
{
|
if (propertyStorage == null)
|
return "";
|
VCFile file = propertyStorage.File as VCFile;
|
if (file == null)
|
return "";
|
return file.ItemType;
|
}
|
|
public string GetItemType(object propertyStorage)
|
{
|
if (propertyStorage == null)
|
return "";
|
if (propertyStorage is VCFileConfiguration)
|
return GetItemType(propertyStorage as VCFileConfiguration);
|
return "";
|
}
|
|
string GetItemName(VCFileConfiguration propertyStorage)
|
{
|
if (propertyStorage == null)
|
return "";
|
VCFile file = propertyStorage.File as VCFile;
|
if (file == null)
|
return "";
|
return file.Name;
|
}
|
|
public string GetItemName(object propertyStorage)
|
{
|
if (propertyStorage == null)
|
return "";
|
if (propertyStorage is VCFileConfiguration)
|
return GetItemName(propertyStorage as VCFileConfiguration);
|
return "";
|
}
|
|
object GetParentProject(VCConfiguration propertyStorage)
|
{
|
if (propertyStorage == null)
|
return null;
|
return propertyStorage.project as VCProject;
|
}
|
|
object GetParentProject(VCFileConfiguration propertyStorage)
|
{
|
if (propertyStorage == null)
|
return null;
|
return GetParentProject(propertyStorage.ProjectConfiguration as VCConfiguration);
|
}
|
|
public object GetParentProject(object propertyStorage)
|
{
|
if (propertyStorage == null)
|
return null;
|
if (propertyStorage is VCFileConfiguration)
|
return GetParentProject(propertyStorage as VCFileConfiguration);
|
else if (propertyStorage is VCConfiguration)
|
return GetParentProject(propertyStorage as VCConfiguration);
|
return null;
|
}
|
|
object GetProjectConfiguration(VCProject project, string configName)
|
{
|
if (project == null)
|
return null;
|
foreach (VCConfiguration projConfig in (IVCCollection)project.Configurations) {
|
if (projConfig.Name == configName)
|
return projConfig;
|
}
|
return null;
|
}
|
|
public object GetProjectConfiguration(object project, string configName)
|
{
|
if (project == null)
|
return null;
|
return GetProjectConfiguration(project as VCProject, configName);
|
}
|
|
IEnumerable<object> GetItems(VCProject project, string itemType, string configName = "")
|
{
|
if (project == null)
|
return new List<object>();
|
var allItems = project.GetFilesWithItemType(itemType) as IVCCollection;
|
var items = new List<VCFileConfiguration>();
|
foreach (VCFile vcFile in allItems) {
|
foreach (VCFileConfiguration vcFileConfig
|
in vcFile.FileConfigurations as IVCCollection) {
|
if (!string.IsNullOrEmpty(configName) && vcFileConfig.Name != configName)
|
continue;
|
items.Add(vcFileConfig);
|
}
|
}
|
return items;
|
}
|
|
public IEnumerable<object> GetItems(
|
object project,
|
string itemType,
|
string configName = "")
|
{
|
if (project == null)
|
return null;
|
return GetItems(project as VCProject, itemType, configName);
|
}
|
|
}
|
|
public class VCMacroExpander : IVSMacroExpander
|
{
|
object config;
|
|
public VCMacroExpander(object config)
|
{
|
this.config = config;
|
}
|
|
public string ExpandString(string stringToExpand)
|
{
|
HelperFunctions.ExpandString(ref stringToExpand, config);
|
return stringToExpand;
|
}
|
}
|
|
public class QtCustomBuildTool
|
{
|
QtMsBuildContainer qtMsBuild;
|
VCFileConfiguration vcConfig;
|
VCFile vcFile;
|
VCCustomBuildTool tool;
|
VCMacroExpander macros;
|
|
enum FileItemType { Other = 0, CustomBuild, QtMoc, QtRcc, QtRepc, QtUic };
|
FileItemType itemType = FileItemType.Other;
|
public QtCustomBuildTool(VCFileConfiguration vcConfig, QtMsBuildContainer container = null)
|
{
|
if (container != null)
|
qtMsBuild = container;
|
else
|
qtMsBuild = new QtMsBuildContainer(new VCPropertyStorageProvider());
|
this.vcConfig = vcConfig;
|
if (vcConfig != null)
|
vcFile = vcConfig.File as VCFile;
|
if (vcFile != null) {
|
if (vcFile.ItemType == "CustomBuild")
|
itemType = FileItemType.CustomBuild;
|
else if (vcFile.ItemType == QtMoc.ItemTypeName)
|
itemType = FileItemType.QtMoc;
|
else if (vcFile.ItemType == QtRcc.ItemTypeName)
|
itemType = FileItemType.QtRcc;
|
else if (vcFile.ItemType == QtRepc.ItemTypeName)
|
itemType = FileItemType.QtRepc;
|
else if (vcFile.ItemType == QtUic.ItemTypeName)
|
itemType = FileItemType.QtUic;
|
}
|
if (itemType == FileItemType.CustomBuild)
|
tool = HelperFunctions.GetCustomBuildTool(vcConfig);
|
macros = new VCMacroExpander(vcConfig);
|
}
|
|
public string CommandLine
|
{
|
get
|
{
|
switch (itemType) {
|
case FileItemType.CustomBuild:
|
return (tool != null) ? tool.CommandLine : "";
|
case FileItemType.QtMoc:
|
return qtMsBuild.GenerateQtMocCommandLine(vcConfig);
|
case FileItemType.QtRcc:
|
return qtMsBuild.GenerateQtRccCommandLine(vcConfig);
|
case FileItemType.QtRepc:
|
return qtMsBuild.GenerateQtRepcCommandLine(vcConfig);
|
case FileItemType.QtUic:
|
return qtMsBuild.GenerateQtUicCommandLine(vcConfig);
|
}
|
return "";
|
}
|
set
|
{
|
switch (itemType) {
|
case FileItemType.CustomBuild:
|
if (tool != null)
|
tool.CommandLine = value;
|
break;
|
case FileItemType.QtMoc:
|
qtMsBuild.SetQtMocCommandLine(vcConfig, value, macros);
|
break;
|
case FileItemType.QtRcc:
|
qtMsBuild.SetQtRccCommandLine(vcConfig, value, macros);
|
break;
|
case FileItemType.QtRepc:
|
qtMsBuild.SetQtRepcCommandLine(vcConfig, value, macros);
|
break;
|
case FileItemType.QtUic:
|
qtMsBuild.SetQtUicCommandLine(vcConfig, value, macros);
|
break;
|
}
|
}
|
}
|
|
public string Outputs
|
{
|
get
|
{
|
switch (itemType) {
|
case FileItemType.CustomBuild:
|
return (tool != null) ? tool.Outputs : "";
|
case FileItemType.QtMoc:
|
return qtMsBuild.GetPropertyValue(vcConfig, QtMoc.Property.OutputFile);
|
case FileItemType.QtRcc:
|
return qtMsBuild.GetPropertyValue(vcConfig, QtRcc.Property.OutputFile);
|
case FileItemType.QtRepc:
|
return qtMsBuild.GetPropertyValue(vcConfig, QtRepc.Property.OutputFile);
|
case FileItemType.QtUic:
|
return qtMsBuild.GetPropertyValue(vcConfig, QtUic.Property.OutputFile);
|
}
|
return "";
|
}
|
}
|
|
}
|
|
}
|