/// <summary> /// Get output assembly for a specific configuration name /// </summary> /// <param name="configCanonicalName">Name of configuration</param> /// <returns>Name of output assembly</returns> public string GetOutputAssembly(ConfigCanonicalName configCanonicalName) { ProjectOptions options = this.GetProjectOptions(configCanonicalName); return options.OutputAssembly; }
public ProjectConfig(ProjectNode project, ConfigCanonicalName configName) { this.project = project; this.configCanonicalName = configName; this.lastCache = DateTime.MinValue; // Because the project can be aggregated by a flavor, we need to make sure // we get the outer most implementation of that interface (hence: project --> IUnknown --> Interface) IntPtr projectUnknown = Marshal.GetIUnknownForObject(this.ProjectMgr); try { IVsProjectFlavorCfgProvider flavorCfgProvider = (IVsProjectFlavorCfgProvider)Marshal.GetTypedObjectForIUnknown(projectUnknown, typeof(IVsProjectFlavorCfgProvider)); ErrorHandler.ThrowOnFailure(flavorCfgProvider.CreateProjectFlavorCfg(this, out flavoredCfg)); if (flavoredCfg == null) throw new COMException(); } finally { if (projectUnknown != IntPtr.Zero) Marshal.Release(projectUnknown); } // if the flavored object support XML fragment, initialize it IPersistXMLFragment persistXML = flavoredCfg as IPersistXMLFragment; if (null != persistXML) { this.project.LoadXmlFragment(persistXML, this.DisplayName); } }
/// <summary> /// This is called from the main thread before the background build starts. /// cleanBuild is not part of the vsopts, but passed down as the callpath is differently /// PrepareBuild mainly creates directories and cleans house if cleanBuild is true /// </summary> /// <param name="config"></param> /// <param name="cleanBuild"></param> public virtual void PrepareBuild(ConfigCanonicalName config, bool cleanBuild) { if (this.buildIsPrepared && !cleanBuild) return; ProjectOptions options = this.GetProjectOptions(config); string outputPath = Path.GetDirectoryName(options.OutputAssembly); if (cleanBuild && this.ProjectInstance.Targets.ContainsKey(MsBuildTarget.Clean)) { this.InvokeMsBuild(MsBuildTarget.Clean); } PackageUtilities.EnsureOutputPath(outputPath); if (!String.IsNullOrEmpty(options.XMLDocFileName)) { PackageUtilities.EnsureOutputPath(Path.GetDirectoryName(options.XMLDocFileName)); } this.buildIsPrepared = true; }
/// <summary> /// Proved access to an IDispatchable object being a list of configuration properties /// </summary> /// <param name="configurationName">Combined Name and Platform for the configuration requested</param> /// <param name="configurationProperties">The IDispatchcable object</param> /// <returns>S_OK if successful</returns> public virtual int GetAutomationObject(string configurationName, out object configurationProperties) { //Init out param configurationProperties = null; var canonicalCfgName = new ConfigCanonicalName(configurationName); // Get the configuration IVsCfg cfg; ErrorHandler.ThrowOnFailure(this.GetCfgOfName(canonicalCfgName.ConfigName, canonicalCfgName.Platform, out cfg)); // Get the properties of the configuration configurationProperties = ((ProjectConfig)cfg).ConfigurationProperties; return VSConstants.S_OK; }
/// <summary> /// Creates new Project Configuartion objects based on the configuration name. /// </summary> /// <param name="configName">The name of the configuration</param> /// <returns>An instance of a ProjectConfig object.</returns> protected ProjectConfig GetProjectConfiguration(ConfigCanonicalName canonicalName) { // if we already created it, return the cached one if (configurationsList.ContainsKey(canonicalName)) { return configurationsList[canonicalName]; } ProjectConfig requestedConfiguration = CreateProjectConfiguration(canonicalName); configurationsList.Add(canonicalName, requestedConfiguration); return requestedConfiguration; }
protected virtual ProjectConfig CreateProjectConfiguration(ConfigCanonicalName canonicalName) { return new ProjectConfig(this.project, canonicalName); }
/// <summary> /// Copies an existing platform name or creates a new one. /// </summary> /// <param name="platformName">The name of the new platform.</param> /// <param name="clonePlatformName">The name of the platform to copy, or a null reference, indicating that AddCfgsOfPlatformName should create a new platform.</param> /// <returns>If the method succeeds, it returns S_OK. If it fails, it returns an error code.</returns> public virtual int AddCfgsOfPlatformName(string platformName, string clonePlatformName) { // We need to QE/QS the project file if (!this.ProjectMgr.QueryEditProjectFile(false)) { throw Marshal.GetExceptionForHR(VSConstants.OLE_E_PROMPTSAVECANCELLED); } // Get all configs List<ProjectPropertyGroupElement> configGroup = new List<ProjectPropertyGroupElement>(this.project.BuildProject.Xml.PropertyGroups); // configName -> property group var configToClone = new Dictionary<string, ProjectPropertyGroupElement>(StringComparer.Ordinal); if (clonePlatformName != null) { // Find the configuration to clone foreach (var currentConfig in configGroup) { // Only care about conditional property groups if (currentConfig.Condition == null || currentConfig.Condition.Length == 0) continue; var configCanonicalName = ConfigCanonicalName.OfCondition(currentConfig.Condition); // Skip if it isn't the group we want if (!configCanonicalName.MatchesPlatform(clonePlatformName)) continue; if (!configToClone.ContainsKey(configCanonicalName.ConfigName)) configToClone.Add(configCanonicalName.ConfigName, currentConfig); } } var configNames = GetPropertiesConditionedOn(ProjectFileConstants.Configuration); if (configNames.Length == 0) return VSConstants.E_FAIL; foreach (var configName in configNames) { // If we have any property groups to clone, and we do not have sourec for this config, skip if (configToClone.Count > 0 && !configToClone.ContainsKey(configName)) continue; var newCanonicalName = new ConfigCanonicalName(configName, platformName); ProjectPropertyGroupElement newConfig = null; if (configToClone.ContainsKey(configName)) { // Clone the configuration settings newConfig = this.project.ClonePropertyGroup(configToClone[configName]); foreach (ProjectPropertyElement property in newConfig.Properties) { if (property.Name.Equals(ProjectFileConstants.PlatformTarget, StringComparison.OrdinalIgnoreCase)) { property.Parent.RemoveChild(property); } } } else { // no source to clone from, lets just create a new empty config PopulateEmptyConfig(ref newConfig); this.AddOutputPath(newConfig, configName); } newConfig.AddProperty(ProjectFileConstants.PlatformTarget, newCanonicalName.PlatformTarget); // Set the condition that will define the new configuration string newCondition = newCanonicalName.ToMSBuildCondition(); newConfig.Condition = newCondition; } NotifyOnPlatformNameAdded(platformName); return VSConstants.S_OK; }
/// <summary> /// Set the configuration property in MSBuild. /// This does not get persisted and is used to evaluate msbuild conditions /// which are based on the $(Configuration) property. /// </summary> /// <param name="config">Configuration name</param> protected internal virtual void SetConfiguration(ConfigCanonicalName configCanonicalName) { // Can't ask for the active config until the project is opened, so do nothing in that scenario if (!projectOpened) return; // We cannot change properties during the build so if the config // we want to se is the current, we do nothing otherwise we fail. if (this.BuildInProgress) { EnvDTE.Project automationObject = this.GetAutomationObject() as EnvDTE.Project; ConfigCanonicalName currentConfigName; if (Utilities.TryGetActiveConfigurationAndPlatform(this.Site, this, out currentConfigName)) { if (currentConfigName == configCanonicalName) return; } throw new InvalidOperationException(); } MSBuildProject.SetGlobalProperty(this.buildProject, ProjectFileConstants.Configuration, configCanonicalName.ConfigName); MSBuildProject.SetGlobalProperty(this.buildProject, ProjectFileConstants.Platform, configCanonicalName.MSBuildPlatform); this.UpdateMSBuildState(); }
private void TellMSBuildCurrentSolutionConfiguration() { IVsSolutionBuildManager buildMgr = this.Site.GetService(typeof(SVsSolutionBuildManager)) as IVsSolutionBuildManager; IVsProjectCfg[] cfgs = new IVsProjectCfg[] { null }; buildMgr.FindActiveProjectCfg(System.IntPtr.Zero, System.IntPtr.Zero, this, cfgs); if (cfgs[0] != null) { string cfgName = ""; cfgs[0].get_CanonicalName(out cfgName); // cfgName conventionally has form "Configuration|Platform" var canonicalCfgName = new ConfigCanonicalName(cfgName); if (String.IsNullOrEmpty(canonicalCfgName.Platform)) { // cfgName is not conventional, just do something reasonable MSBuildProject.SetGlobalProperty(this.buildProject, ProjectFileConstants.Configuration, canonicalCfgName.ConfigName); } else { MSBuildProject.SetGlobalProperty(this.buildProject, ProjectFileConstants.Configuration, canonicalCfgName.ConfigName); MSBuildProject.SetGlobalProperty(this.buildProject, ProjectFileConstants.Platform, canonicalCfgName.MSBuildPlatform); } this.UpdateMSBuildState(); } }
/// <summary> /// Get the assembly name for a give configuration /// </summary> /// <param name="config">the matching configuration in the msbuild file</param> /// <returns>assembly name</returns> public virtual string GetAssemblyName(ConfigCanonicalName config) { this.SetConfiguration(config); return GetAssemblyName(); }
/// <summary> /// Set configuration properties for a specific configuration /// </summary> /// <param name="config">configuration name</param> /// <param name="platformName">platform name</param> protected virtual void SetBuildConfigurationProperties(ConfigCanonicalName config) { ProjectOptions options = null; options = this.GetProjectOptions(config); if (options != null && this.buildProject != null) { // Make sure the project configuration is set properly this.SetConfiguration(config); } }
public virtual ProjectOptions GetProjectOptions(ConfigCanonicalName configCanonicalName) { if (this.options != null) return this.options; ProjectOptions options = this.options = CreateProjectOptions(); options.GenerateExecutable = true; this.SetConfiguration(configCanonicalName); string outputPath = this.GetOutputPath(); if (!String.IsNullOrEmpty(outputPath)) { // absolutize relative to project folder location outputPath = Path.Combine(this.ProjectFolder, outputPath); } // Set some default values options.OutputAssembly = outputPath + this.Caption + ".exe"; options.ModuleKind = ModuleKindFlags.ConsoleApplication; options.RootNamespace = GetProjectProperty(ProjectFileConstants.RootNamespace, false); options.OutputAssembly = outputPath + this.GetAssemblyName(configCanonicalName); string outputtype = GetProjectProperty(ProjectFileConstants.OutputType, false); if (!String.IsNullOrEmpty(outputtype)) { outputtype = outputtype.ToLower(CultureInfo.InvariantCulture); } if (outputtype == "library") { options.ModuleKind = ModuleKindFlags.DynamicallyLinkedLibrary; options.GenerateExecutable = false; // DLL's have no entry point. } else if (outputtype == "winexe") options.ModuleKind = ModuleKindFlags.WindowsApplication; else options.ModuleKind = ModuleKindFlags.ConsoleApplication; options.Win32Icon = GetProjectProperty("ApplicationIcon", false); options.MainClass = GetProjectProperty("StartupObject", false); string targetPlatform = GetProjectProperty("TargetPlatform", false); if (targetPlatform != null && targetPlatform.Length > 0) { try { options.TargetPlatform = (PlatformType)Enum.Parse(typeof(PlatformType), targetPlatform); } catch (ArgumentException e) { Trace.WriteLine("Exception : " + e.Message); } options.TargetPlatformLocation = GetProjectProperty("TargetPlatformLocation", false); this.SetTargetPlatform(options); } // other settings from CSharp we may want to adopt at some point... // AssemblyKeyContainerName = "" //This is the key file used to sign the interop assembly generated when importing a com object via add reference // AssemblyOriginatorKeyFile = "" // DelaySign = "false" // DefaultClientScript = "JScript" // DefaultHTMLPageLayout = "Grid" // DefaultTargetSchema = "IE50" // PreBuildEvent = "" // PostBuildEvent = "" // RunPostBuildEvent = "OnBuildSuccess" // transfer all config build options... if (GetBoolAttr("AllowUnsafeBlocks")) { options.AllowUnsafeCode = true; } if (GetProjectProperty("BaseAddress", false) != null) { try { options.BaseAddress = Int64.Parse(GetProjectProperty("BaseAddress", false), CultureInfo.InvariantCulture); } catch (ArgumentNullException e) { Trace.WriteLine("Exception : " + e.Message); } catch (ArgumentException e) { Trace.WriteLine("Exception : " + e.Message); } catch (FormatException e) { Trace.WriteLine("Exception : " + e.Message); } catch (OverflowException e) { Trace.WriteLine("Exception : " + e.Message); } } if (GetBoolAttr("CheckForOverflowUnderflow")) { options.CheckedArithmetic = true; } if (GetProjectProperty("DefineConstants", false) != null) { options.DefinedPreProcessorSymbols = new StringCollection(); foreach (string s in GetProjectProperty("DefineConstants", false).Replace(" \t\r\n", "").Split(';')) { options.DefinedPreProcessorSymbols.Add(s); } } string docFile = GetProjectProperty("DocumentationFile", false); if (!String.IsNullOrEmpty(docFile)) { options.XMLDocFileName = Path.Combine(this.ProjectFolder, docFile); } if (GetBoolAttr("DebugSymbols")) { options.IncludeDebugInformation = true; } if (GetProjectProperty("FileAlignment", false) != null) { try { options.FileAlignment = Int32.Parse(GetProjectProperty("FileAlignment", false), CultureInfo.InvariantCulture); } catch (ArgumentNullException e) { Trace.WriteLine("Exception : " + e.Message); } catch (ArgumentException e) { Trace.WriteLine("Exception : " + e.Message); } catch (FormatException e) { Trace.WriteLine("Exception : " + e.Message); } catch (OverflowException e) { Trace.WriteLine("Exception : " + e.Message); } } if (GetBoolAttr("IncrementalBuild")) { options.IncrementalCompile = true; } if (GetBoolAttr("Optimize")) { options.Optimize = true; } if (GetBoolAttr("RegisterForComInterop")) { } if (GetBoolAttr("RemoveIntegerChecks")) { } if (GetBoolAttr("TreatWarningsAsErrors")) { options.TreatWarningsAsErrors = true; } if (GetProjectProperty("WarningLevel", false) != null) { try { options.WarningLevel = Int32.Parse(GetProjectProperty("WarningLevel", false), CultureInfo.InvariantCulture); } catch (ArgumentNullException e) { Trace.WriteLine("Exception : " + e.Message); } catch (ArgumentException e) { Trace.WriteLine("Exception : " + e.Message); } catch (FormatException e) { Trace.WriteLine("Exception : " + e.Message); } catch (OverflowException e) { Trace.WriteLine("Exception : " + e.Message); } } return options; }
public virtual BuildResult Build(uint vsopts, ConfigCanonicalName configCanonicalName, IVsOutputWindowPane output, string target) { lock (ProjectNode.BuildLock) { bool engineLogOnlyCritical = BuildPrelude(output); BuildResult result = BuildResult.FAILED; this.SetBuildConfigurationProperties(configCanonicalName); result = this.InvokeMsBuild(target); return result; } }
/// <summary> /// Do the build asynchronously. /// </summary> /// <param name="vsopts"></param> /// <param name="configCanonicalName"></param> /// <param name="output"></param> /// <param name="target"></param> /// <param name="coda"></param> internal virtual void BuildAsync(uint vsopts, ConfigCanonicalName configCanonicalName, IVsOutputWindowPane output, string target, MSBuildCoda coda) { bool engineLogOnlyCritical = BuildPrelude(output); MSBuildCoda fullCoda = (res, instance) => { coda(res, instance); }; try { this.SetBuildConfigurationProperties(configCanonicalName); ProjectInstance ignoreMeToo = null; this.DoMSBuildSubmission(BuildKind.ASYNC, target, ref ignoreMeToo, fullCoda); } catch (Exception) { fullCoda(MSBuildResult.Failed, null); throw; } }
/// <summary> /// Provides access to the IVsProjectCfg interface implemented on a project's configuration object. /// </summary> /// <param name="projectCfgCanonicalName">The canonical name of the configuration to access.</param> /// <param name="projectCfg">The IVsProjectCfg interface of the configuration identified by szProjectCfgCanonicalName.</param> /// <returns>If the method succeeds, it returns S_OK. If it fails, it returns an error code. </returns> public override int OpenProjectCfg(string projectCfgCanonicalName, out IVsProjectCfg projectCfg) { if (String.IsNullOrEmpty(projectCfgCanonicalName)) { throw new ArgumentNullException("projectCfgCanonicalName"); } ConfigCanonicalName config = new ConfigCanonicalName(projectCfgCanonicalName); projectCfg = this.GetProjectConfiguration(config); return VSConstants.S_OK; }
/// <summary> /// Resumes MSBuild. /// </summary> public void ResumeMSBuild(ConfigCanonicalName config, IVsOutputWindowPane output, string target) { this.suspendMSBuildCounter--; if (this.suspendMSBuildCounter == 0 && this.invokeMSBuildWhenResumed) { try { this.Build(config, output, target); } finally { this.invokeMSBuildWhenResumed = false; } } }
private ProjectConfig GetProjectConfiguration(string config, string platform) { ConfigCanonicalName configCanonicalName = new ConfigCanonicalName(config, platform); if (this.configurationsList.ContainsKey(configCanonicalName)) { return this.configurationsList[configCanonicalName]; } ProjectConfig requestedConfiguration = new WixProjectConfig((WixProjectNode) this.ProjectMgr, config, platform); this.configurationsList.Add(configCanonicalName, requestedConfiguration); return requestedConfiguration; }
/// <summary> /// Resumes MSBuild. /// </summary> public void ResumeMSBuild(ConfigCanonicalName config, string target) { this.ResumeMSBuild(config, null, target); }
/// <summary> /// Provides access to the IVsProjectCfg interface implemented on a project's configuration object. /// </summary> /// <param name="projectCfgCanonicalName">The canonical name of the configuration to access.</param> /// <param name="projectCfg">The IVsProjectCfg interface of the configuration identified by szProjectCfgCanonicalName.</param> /// <returns>If the method succeeds, it returns S_OK. If it fails, it returns an error code. </returns> public virtual int OpenProjectCfg(string projectCfgCanonicalName, out IVsProjectCfg projectCfg) { if (projectCfgCanonicalName == null) { throw new ArgumentNullException("projectCfgCanonicalName"); } projectCfg = null; // Be robust in release if (projectCfgCanonicalName == null) { return VSConstants.E_INVALIDARG; } Debug.Assert(this.project != null && this.project.BuildProject != null); string[] configs = GetPropertiesConditionedOn(ProjectFileConstants.Configuration); string[] platforms = GetPropertiesConditionedOn(ProjectFileConstants.Platform); var configCanonicalName = new ConfigCanonicalName(projectCfgCanonicalName); foreach (string config in configs) { foreach (string platform in platforms) { if (configCanonicalName == new ConfigCanonicalName(config, platform)) { projectCfg = this.GetProjectConfiguration(configCanonicalName); if (projectCfg != null) { return VSConstants.S_OK; } else { return VSConstants.E_FAIL; } } } } return VSConstants.E_INVALIDARG; }
/// <summary> /// Calls MSBuild if it is not suspended. If it is suspended then it will remeber to call when msbuild is resumed. /// </summary> public BuildResult CallMSBuild(ConfigCanonicalName config, IVsOutputWindowPane output, string target) { if (this.suspendMSBuildCounter > 0) { // remember to invoke MSBuild this.invokeMSBuildWhenResumed = true; return new BuildResult(MSBuildResult.Suspended, null); } else { return this.Build(config, output, target); } }
/// <summary> /// Assigns a new name to a configuration. /// </summary> /// <param name="old">The old name of the target configuration.</param> /// <param name="newname">The new name of the target configuration.</param> /// <returns>If the method succeeds, it returns S_OK. If it fails, it returns an error code.</returns> public virtual int RenameCfgsOfCfgName(string old, string newname) { // First create the condition that represent the configuration we want to rename string condition = String.Format(CultureInfo.InvariantCulture, configString, old).Trim(); foreach (var config in this.project.BuildProject.Xml.PropertyGroups) { // Only care about conditional property groups if (config.Condition == null || config.Condition.Length == 0) continue; var configCanonicalName = ConfigCanonicalName.OfCondition(config.Condition); // Skip if it isn't the group we want if (!configCanonicalName.MatchesConfigName(old)) continue; var newCanonicalName = new ConfigCanonicalName(newname, configCanonicalName.Platform); // Change the name config.Condition = newCanonicalName.ToMSBuildCondition(); var propertyCollection = config.Properties; var outputPathProperty = propertyCollection.Where(p => p.Name == ProjectFileConstants.OutputPath).FirstOrDefault(); if (outputPathProperty != null) { string outputBasePath = this.ProjectMgr.OutputBaseRelativePath; if (outputBasePath.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)) outputBasePath = Path.GetDirectoryName(outputBasePath); var expectedOutputPathValue = Path.Combine(outputBasePath, old); if (String.Equals(expectedOutputPathValue, outputPathProperty.Value, StringComparison.OrdinalIgnoreCase)) { var newOutputPathValue = Path.Combine(outputBasePath, newname); config.SetProperty(ProjectFileConstants.OutputPath, newOutputPathValue); } } // Update the name in our config list if (configurationsList.ContainsKey(configCanonicalName)) { ProjectConfig configuration = configurationsList[configCanonicalName]; configurationsList.Remove(configCanonicalName); configurationsList.Add(newCanonicalName, configuration); // notify the configuration of its new name configuration.ConfigName = newname; } } NotifyOnCfgNameRenamed(old, newname); return VSConstants.S_OK; }
/// <summary> /// Overloaded method. Calls MSBuild if it is not suspended. Does not log on the outputwindow. If it is suspended then it will remeber to call when msbuild is resumed. /// </summary> public BuildResult CallMSBuild(ConfigCanonicalName config, string target) { return this.CallMSBuild(config, null, target); }
/// <summary> /// Gets all the platforms defined in the project /// </summary> /// <returns>An array of platform names.</returns> private string[] GetPlatformsFromProject() { string[] platforms = GetPropertiesConditionedOn(ProjectFileConstants.Platform); if (platforms == null || platforms.Length == 0) { return new string[] { AnyCPUPlatform }; } for (int i = 0; i < platforms.Length; i++) { platforms[i] = new ConfigCanonicalName("", platforms[i]).Platform; } return platforms; }
/// <summary> /// Overloaded method to invoke MSBuild /// </summary> public BuildResult Build(ConfigCanonicalName config, IVsOutputWindowPane output, string target) { return this.Build(0, config, output, target); }
public bool Equals(ConfigCanonicalName other) { return CMP.Equals(myConfigName, other.myConfigName) && CMP.Equals(myPlatform, other.myPlatform); }
/// <summary> /// Overloaded method to invoke MSBuild. Does not log build results to the output window pane. /// </summary> public BuildResult Build(ConfigCanonicalName config, string target) { return this.Build(0, config, null, target); }
public DebuggableProjectConfig(ProjectNode project, ConfigCanonicalName conigName) : base(project, conigName) { }
/// <summary> /// Sets the configuration for the .user build file /// </summary> /// <param name="configCanonicalName">Configuration</param> protected internal override void SetConfiguration(ConfigCanonicalName configCanonicalName) { base.SetConfiguration(configCanonicalName); if (this.userBuildProject != null) { this.userBuildProject.SetGlobalProperty(ProjectFileConstants.Configuration, configCanonicalName.ConfigName); this.userBuildProject.SetGlobalProperty(ProjectFileConstants.Platform, configCanonicalName.MSBuildPlatform); } }