Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / BuildTasks / Microsoft / Build / Tasks / Windows / MarkupCompilePass1.cs / 1 / MarkupCompilePass1.cs
//---------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: An MSBuild Task that can generate .xaml markup file to specific // Mangaged language code such as .cs, .js, .vb,etc, and /or binary // token file .baml // // Spec: http://avalon/app/Compilation/Avalon-MSBUILD%20Targets.doc // // History: // 06/20/03: weibz rewrite and moved over to WCP tree // //--------------------------------------------------------------------------- using System; using System.IO; using System.Collections; using System.Security; using System.Security.Permissions; using System.Globalization; using System.Diagnostics; using System.Reflection; using System.Resources; using System.Runtime.InteropServices; using System.CodeDom; using System.CodeDom.Compiler; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; using MS.Utility; using MS.Internal; using MS.Internal.Tasks; using MS.Internal.Markup; // Since we disable PreSharp warnings in this file, PreSharp warning is unknown to C# compiler. // We first need to disable warnings about unknown message numbers and unknown pragmas. #pragma warning disable 1634, 1691 namespace Microsoft.Build.Tasks.Windows { #region MarkupCompilePass1 Task class ////// Class of MarkupCompilePass1 Task /// public sealed class MarkupCompilePass1 : Task { // Security Concerns: hamidm 04/13/05 // // 1) OutputPath property exposes the current dir and is publicly available. // 2) This class generates code files and copies them on the disk. // // The above two are already mitigated by the following facts: // // 1) PresentationBuildTasks is not APTCA and thus partial trust assemblies // cannot call into it. // 2) There is a possibility that some APTCA assembly (eg. PF.dll) can create // this object and pass it on to partial trust code. This is mitigated by // FxCop rule against it. // //----------------------------------------------------- // // Constructors // //----------------------------------------------------- #region Constructors ////// Constructor /// public MarkupCompilePass1( ) : base(SR.ResourceManager) { // set the source directory _sourceDir = Directory.GetCurrentDirectory() + "\\"; _outputType = SharedStrings.WinExe; // By default, no localization information is stripped out. _localizationDirectives = MS.Internal.LocalizationDirectivesToLocFile.None; _nErrors = 0; } #endregion Constructors //------------------------------------------------------ // // Public Methods // //----------------------------------------------------- #region Public Methods ////// Execute method in Task /// ///public override bool Execute() { //CASRemoval:(new PermissionSet(PermissionState.Unrestricted)).Assert(); TaskHelper.DisplayLogo(Log, SR.Get(SRID.MarkupCompilePass1Task)); bool bSuccess = true; try { // // Create the TaskFileService instance here // _taskFileService = new TaskFileService(this) as ITaskFileService; _compilerState = new CompilerState( OutputPath + AssemblyName + (TaskFileService.IsRealBuild? SharedStrings.StateFile : SharedStrings.IntellisenseStateFile), TaskFileService); _compilerLocalRefCache = new CompilerLocalReference( OutputPath + AssemblyName + (TaskFileService.IsRealBuild? SharedStrings.LocalTypeCacheFile : SharedStrings.IntellisenseLocalTypeCacheFile), TaskFileService); if ((PageMarkup == null || PageMarkup.Length == 0) && (ApplicationMarkup == null || ApplicationMarkup.Length == 0)) { // Don't need to do further work. // stop here. CleanupCacheFiles(); return true; } VerifyInputs(); Log.LogMessageFromResources(MessageImportance.Low, SRID.CurrentDirectory, SourceDir); // If wrong files are set to some properties, the task // should stop here immediatelly. if (_nErrors > 0) { Log.LogErrorWithCodeFromResources(SRID.WrongPropertySetting); } else { // create output directory if (!Directory.Exists(OutputPath)) { Directory.CreateDirectory(OutputPath); } // Analyze project inputs to detect which xaml files require to recompile. AnalyzeInputsAndSetting(); Log.LogMessageFromResources(MessageImportance.Low, SRID.AnalysisResult, CompilerAnalyzer.AnalyzeResult); if (!SkipMarkupCompilation) { if (CompilerAnalyzer.RecompileMarkupPages != null) { for (int i = 0; i < CompilerAnalyzer.RecompileMarkupPages.Length; i++) { Log.LogMessageFromResources(MessageImportance.Low, SRID.RecompiledXaml, CompilerAnalyzer.RecompileMarkupPages[i]); } } // If recompile is required, CompilerAnalyzer contains all the files which need to recompile. // Cleanup baml files and code files generated in previous build. if (TaskFileService.IsRealBuild) { CleanupGeneratedFiles(); } // Call the Markup Compiler to do the real compiling work DoMarkupCompilation(); } // Generate the required output items. GenerateOutputItems(); Log.LogMessageFromResources(MessageImportance.Low, SRID.CompilationDone); } } #pragma warning disable 6500 catch (Exception e) { string message; string errorId; errorId = Log.ExtractMessageCode(e.Message, out message); if (String.IsNullOrEmpty(errorId)) { errorId = UnknownErrorID; message = SR.Get(SRID.UnknownBuildError, message); } Log.LogError(null, errorId, null, null, 0, 0, 0, 0, message, null); _nErrors++; } catch // Non-CLS compliant errors { Log.LogErrorWithCodeFromResources(SRID.NonClsError); _nErrors++; } #pragma warning restore 6500 if (_nErrors > 0) { // When error counter is changed, the appropriate error message should have // been reported, simply return false here. bSuccess = false; CleanupCacheFiles(); } else { Log.LogMessageFromResources(MessageImportance.Low, SRID.CompileSucceed_Pass1); } return bSuccess; } #endregion Public Methods //------------------------------------------------------ // // Public Properties // //------------------------------------------------------ #region Public Properties /// /// The Language the managed compiler supports. /// the valid languages are C#, VB, Jscript, J#, C++ /// [Required] public string Language { get { return _language; } set { _language = value;} } ////// The valid source file extension for the passed language. /// Normally a language supports more valid source file extensions. /// User could choose one of them in project file. /// If this property is not set, we will take use of the default one for the language. /// public string LanguageSourceExtension { get { return _languageSourceExtension; } set { _languageSourceExtension = value; } } ////// OutputPath : Generated code files, Baml fles will be put in this directory. /// [Required] public string OutputPath { get { return _outputDir; } set { string filePath = value; // Get the relative path based on sourceDir _outputDir= TaskHelper.CreateFullFilePath(filePath, SourceDir); // Make sure OutputDir always ends with '\\'. if (!_outputDir.EndsWith("\\", StringComparison.Ordinal)) { _outputDir += "\\"; } } } ////// OutputType /// Valid types: winexe, exe, library, netmodule. /// [Required] public string OutputType { get { return _outputType; } set { _outputType = TaskHelper.GetLowerString(value); } } ////// AssemblyName /// The short name of assembly which will be generated for this project. /// [Required] public string AssemblyName { get { return _assemblyName; } set { _assemblyName = value; } } ////// The version of the assembly /// public string AssemblyVersion { get { return _assemblyVersion; } set { _assemblyVersion = value; } } ////// The public key token of the assembly /// public string AssemblyPublicKeyToken { get { return _assemblyPublicKeyToken; } set { _assemblyPublicKeyToken = value; } } ////// Root namespace for the classes inside the project. /// It is also used as default CLR namespace of a generated code file /// when the corresponding markup page is not set x:Class attribute. /// public string RootNamespace { get { return _rootNamespace; } set { _rootNamespace = value; } } ////// The UI Culture controls which culture satellite assembly will hold /// the generated baml files. /// If UICulture is not set, the generated baml files will be embedded /// into main assembly. /// public string UICulture { get { return _uiCulture; } set { _uiCulture = value; } } ////// Source code file list for the current project. /// It doesnt include any generated code files. /// public ITaskItem[] SourceCodeFiles { get { return _sourceCodeFiles; } set { _sourceCodeFiles = value; } } ////// DefineConstants /// /// Keep the current value of DefineConstants. /// /// DefineConstants can affect the final assembly generation, if DefineConstants /// value is changed, the public API might be changed in the target assembly, which /// then has potential impacts on compilation for xaml files which contains local types. /// /// public string DefineConstants { get { return _defineConstants; } set { _defineConstants = value; } } ////// ApplicationMarkup /// public ITaskItem [] ApplicationMarkup { get { return _applicationMarkup; } set { _applicationMarkup = value;} } ////// Description /// public ITaskItem [] PageMarkup { get { return _pagemarkupFiles; } set { _pagemarkupFiles = value; } } ////// Splash screen image to be displayed before application init /// public ITaskItem[] SplashScreen { get { return _splashScreen; } set { _splashScreen = value; } } internal string SplashImageName { get { if (SplashScreen != null && SplashScreen.Length > 0) { return SplashScreen[0].ItemSpec.ToLowerInvariant(); } return null; } } ////// Loose file content list /// public ITaskItem[] ContentFiles { get { return _contentFiles; } set { _contentFiles = value; } } ////// Assembly References. /// ///public ITaskItem[] References { get { return _references; } set { _references = value; } } /// /// public bool XamlDebuggingInformation { get { return _xamlDebuggingInformation; } set { _xamlDebuggingInformation = value; } } ////// Keep a list of Build control files. /// If one of them is changed since last build, it would trigger recompilation of all the xaml files. /// Such as WinFX target file change could require a rebuild etc. /// public ITaskItem [] ExtraBuildControlFiles { get { return _extraBuildControlFiles; } set { _extraBuildControlFiles = value; } } //////If true code for supporting hosting in Browser is generated /// public string HostInBrowser { get { return _hostInBrowser; } set { _hostInBrowser = TaskHelper.GetLowerString(value); } } ////// Controls how to generate localization information for each xaml file. /// Valid values: None, CommentsOnly, All. /// public string LocalizationDirectivesToLocFile { get { string localizationDirectives = SharedStrings.Loc_None; switch (_localizationDirectives) { case MS.Internal.LocalizationDirectivesToLocFile.None : localizationDirectives = SharedStrings.Loc_None; break; case MS.Internal.LocalizationDirectivesToLocFile.CommentsOnly: localizationDirectives = SharedStrings.Loc_CommentsOnly; break; case MS.Internal.LocalizationDirectivesToLocFile.All: localizationDirectives = SharedStrings.Loc_All; break; } return localizationDirectives; } set { string localizationDirectives = value; if (localizationDirectives != null) { localizationDirectives = localizationDirectives.ToLower(CultureInfo.InvariantCulture); } switch (localizationDirectives) { case SharedStrings.Loc_None : _localizationDirectives = MS.Internal.LocalizationDirectivesToLocFile.None; break; case SharedStrings.Loc_CommentsOnly : _localizationDirectives = MS.Internal.LocalizationDirectivesToLocFile.CommentsOnly; break; case SharedStrings.Loc_All : _localizationDirectives = MS.Internal.LocalizationDirectivesToLocFile.All; break; default: _localizationDirectives = MS.Internal.LocalizationDirectivesToLocFile.Unknown; break; } } } ////// Known reference paths hold referenced assemblies which are never changed during the build procedure. /// such as references in GAC, in framework directory or framework SDK directory etc. /// Users could add their own known reference paths in project files. /// public string[] KnownReferencePaths { get { return _knownReferencePaths; } set { _knownReferencePaths = value; } } ////// A list of reference assemblies that are to change for sure during the build cycle. /// /// Such as in VS.NET, if one project wants to reference another project's output, the /// second project's output could be put in AssembliesGeneratedDuringBuild list. /// Note: Once this property is set, it must contain the complete list of generated /// assemblies in this build solution. /// public string[] AssembliesGeneratedDuringBuild { get { return _assembliesGeneratedDuringBuild; } set { _assembliesGeneratedDuringBuild = value; } } ////// Control whether to run the compilation in second appdomain. /// By default, it is set to true, but project can set this property /// to false to make markup file compilation faster. /// public bool AlwaysCompileMarkupFilesInSeparateDomain { get { return _alwaysCompileMarkupFilesInSeparateDomain; } set { _alwaysCompileMarkupFilesInSeparateDomain = value; } } ////// Generated source code files for the given programing language. /// [Output] public ITaskItem [] GeneratedCodeFiles { get { if (_generatedCodeFiles == null) _generatedCodeFiles = new TaskItem[0]; return _generatedCodeFiles; } set { _generatedCodeFiles = value; } } ////// Generated Baml files for the passed Markup files. /// [Output] public ITaskItem [] GeneratedBamlFiles { get { if (_generatedBamlFiles == null) _generatedBamlFiles = new TaskItem[0]; return _generatedBamlFiles; } set { _generatedBamlFiles = value; } } ////// The generated localization file for each localizable xaml file. /// [Output] public ITaskItem[] GeneratedLocalizationFiles { get { if (_generatedLocalizationFiles == null) _generatedLocalizationFiles = new TaskItem[0]; return _generatedLocalizationFiles; } set { _generatedLocalizationFiles = value; } } #region Local Reference Xaml markup files ////// Indicate whether the project contains xaml files which reference local types and /// the corresponding baml file will be embedded into main assembly. /// [Output] public bool RequirePass2ForMainAssembly { get { return _requirePass2ForMainAssembly; } set { _requirePass2ForMainAssembly = value; } } ////// Indicate whether the project contains xaml files which reference local types and /// the corresponding baml file will be embedded into satellite assembly for current UICulture. /// [Output] public bool RequirePass2ForSatelliteAssembly { get { return _requirePass2ForSatelliteAssembly; } set { _requirePass2ForSatelliteAssembly = value; } } #endregion Local Reference Xaml markup files ////// A complete list of files which are generated by MarkupCompiler. /// [Output] public ITaskItem[] AllGeneratedFiles { get { return _allGeneratedFiles; } set { _allGeneratedFiles = value; } } #endregion Public Properties #region internal methods // // Get the generated code file and baml file for a given xaml file // If the generated file doesn't exist, the output paramter is set to empty string. // internal void GetGeneratedFiles(string xamlFile, out string codeFile, out string bamlFile) { string newSourceDir = SourceDir; codeFile = String.Empty; bamlFile = String.Empty; if (String.IsNullOrEmpty(xamlFile)) { // if xaml file is empty, return it now. return; } string relativeFilePath = GetResolvedFilePath(xamlFile, ref newSourceDir); string langExt = (TaskFileService.IsRealBuild? SharedStrings.GeneratedExtension : SharedStrings.IntellisenseGeneratedExtension) + LanguageSourceExtension; // Replace the .xaml with corresponding generated file extensions. codeFile = OutputPath + Path.ChangeExtension(relativeFilePath, langExt); bamlFile = OutputPath + Path.ChangeExtension(relativeFilePath, SharedStrings.BamlExtension); // If the file doesn't exist, return empty string for the corresponding output parameter. if (!TaskFileService.Exists(codeFile)) { codeFile = String.Empty; } // // Baml file is not generated for intellisense build. // if ((TaskFileService.IsRealBuild == false) || (!TaskFileService.Exists(bamlFile))) { bamlFile = String.Empty; } } #endregion internal methods #region internal Properties internal bool IsApplicationTarget { get { return _isApplicationTarget; } } // // ApplicationFile // internal string ApplicationFile { get { return _applicationFile; } } // // PageMarkupCache // It is caculated from current PageMarkup list, will be saved in the // cache file to support incremental compilation. // internal string PageMarkupCache { get { return _pageMarkupCache; } } // // ContentFilesCache // It is caculated from current ContentFiles list, will be saved in the // cache file to support incremental compilation. // internal string ContentFilesCache { get { return _contentFilesCache; } } // // SourceCodeFilesCache // It is caculated from current SourceCodeFiles list, will be saved in the // cache file to support incremental compilation. // internal string SourceCodeFilesCache { get { return _sourceCodeFilesCache; } } // // ReferencesCache // It is caculated from current ReferencesCache list, will be saved in the // cache file to support incremental compilation. // internal string ReferencesCache { get { return _referencesCache; } } // // Application File with Local Type // internal LocalReferenceFile LocalApplicationFile { get { return _localApplicationFile; } } // // Markup Page files with local types // internal LocalReferenceFile[] LocalMarkupPages { get { return _localMarkupPages; } } // // TaskFileService // internal ITaskFileService TaskFileService { get { return _taskFileService; } } // // CompilerState // internal CompilerState CompilerState { get { return _compilerState; } } // // CompilerLocalReference // internal CompilerLocalReference CompilerLocalReference { get { return _compilerLocalRefCache; } } // // Tell MarkupCompilePass2 whether it further handles InternalTypeHelper class. // internal bool FurtherCheckInternalTypeHelper { get { return _furtherCheckInternalTypeHelper; } set { _furtherCheckInternalTypeHelper = value; } } // // Get the file path for the generated InternalTypeHelper class. // internal string InternalTypeHelperFile { get { string fileName = SharedStrings.GeneratedInternalTypeHelperFileName + (TaskFileService.IsRealBuild? SharedStrings.GeneratedExtension : SharedStrings.IntellisenseGeneratedExtension) + LanguageSourceExtension; return Path.Combine(OutputPath, fileName); } } #endregion internal Properties //----------------------------------------------------- // // Private Methods // //------------------------------------------------------ #region Private Methods // // Check if all the input properties are set valid values // If any property contains an invalid value, Error counter _nErrors will // be changed. // private void VerifyInputs() { // Check if the OutputType is valid type. IsSupportedOutputType(OutputType); // Check if the Localization property is set correctly. IsValidLocalizationDirectives(); VerifyApplicationFile(); if (PageMarkup != null && PageMarkup.Length > 0) { VerifyInputTaskItems(PageMarkup); } if (SplashScreen != null && SplashScreen.Length > 1) { Log.LogErrorWithCodeFromResources(SRID.MultipleSplashScreenImages); _nErrors++; } } // // Verify if the Application file is set correctly // in project file. // private void VerifyApplicationFile() { if (!IsApplicationTarget) { // // For non Application target type. // if (ApplicationMarkup != null && ApplicationMarkup.Length > 0) { // // For non-Application target type, Application definition should not be set. // Log.LogErrorWithCodeFromResources(SRID.AppDefIsNotRequired); _nErrors++; } } else { // // For Application Target type. // if (ApplicationMarkup != null && ApplicationMarkup.Length > 0) { if (ApplicationMarkup.Length > 1) { Log.LogErrorWithCodeFromResources(SRID.MutlipleApplicationFiles); _nErrors++; } _applicationFile = TaskHelper.CreateFullFilePath(ApplicationMarkup[0].ItemSpec, SourceDir); Log.LogMessageFromResources(MessageImportance.Low, SRID.ApplicationDefinitionFile, ApplicationFile); if (!TaskFileService.Exists(ApplicationFile)) { Log.LogErrorWithCodeFromResources(SRID.FileNotFound, ApplicationFile); _nErrors++; } } } } // // Don't support local reference xaml compilation for Container and netmodule type. // private bool IsSupportedOutputType(string outputType) { bool isSupported = false; switch (outputType) { case SharedStrings.Exe: case SharedStrings.WinExe: isSupported = true; _isApplicationTarget = true; break; case SharedStrings.Library: case SharedStrings.Module: isSupported = true; break; default: isSupported = false; break; } if (isSupported == false) { Log.LogErrorWithCodeFromResources(SRID.TargetIsNotSupported, outputType); // Keep the error numbers so that the task can stop immediatelly // later when Execute( ) is called. _nErrors++; } return isSupported; } private bool IsValidLocalizationDirectives() { bool bValid = true; if (_localizationDirectives == MS.Internal.LocalizationDirectivesToLocFile.Unknown) { bValid = false; Log.LogErrorWithCodeFromResources(SRID.WrongLocalizationPropertySetting_Pass1); // Keep the error numbers so that the task can stop immediatelly // later when Execute( ) is called. _nErrors++; } return bValid; } //// Check if the passed TaskItems have valid ItemSpec // // //private bool VerifyInputTaskItems(ITaskItem[] inputItems) { bool bValid = true; foreach (ITaskItem inputItem in inputItems) { bool bValidItem; bValidItem = IsValidInputFile(inputItem.ItemSpec); if (bValidItem == false) { bValid = false; } } return bValid; } private bool IsValidInputFile(string filePath) { bool bValid = true; if (!TaskFileService.Exists(TaskHelper.CreateFullFilePath(filePath, SourceDir))) { bValid = false; Log.LogErrorWithCodeFromResources(SRID.FileNotFound, filePath); // Keep the error numbers so that the task can stop immediatelly // later when Execute( ) is called. _nErrors ++; } return bValid; } // // Return a new sourceDir and relative filepath for a given filePath. // This is for supporting of fullpath or ..\ in the original FilePath. // private string GetResolvedFilePath(string filePath, ref string newSourceDir) { // Create a full path for the originalFilePath. string fullFilePath = TaskHelper.CreateFullFilePath(filePath, SourceDir); // Get the relative path based on sourceDir string relPath = TaskHelper.GetRootRelativePath(SourceDir, fullFilePath); string newRelativeFilePath; if (relPath.Length > 0) { // the original file is relative to the SourceDir. newSourceDir = SourceDir; newRelativeFilePath = relPath; } else { // the original file is not relative to the SourceDir. // it could have its own fullpath or contains "..\" etc. // // In this case, we want to put the filename as relative filepath // and put the deepest directory that file is in as the new // SourceDir. // int pathEndIndex = fullFilePath.LastIndexOf("\\", StringComparison.Ordinal); newSourceDir = fullFilePath.Substring(0, pathEndIndex + 1); newRelativeFilePath = TaskHelper.GetRootRelativePath(newSourceDir, fullFilePath); } return newRelativeFilePath; } // // Analyze the project setting and input files for incremental build support. private void AnalyzeInputsAndSetting() { // Initialize the cache file paths and related information. _pageMarkupCache = CompilerState.GenerateCacheForFileList(PageMarkup); _contentFilesCache = CompilerState.GenerateCacheForFileList(ContentFiles); _sourceCodeFilesCache = CompilerState.GenerateCacheForFileList(SourceCodeFiles); _referencesCache = CompilerState.GenerateCacheForFileList(References); _compilerAnalyzer = new IncrementalCompileAnalyzer(this); _compilerAnalyzer.AnalyzeInputFiles(); _isCleanBuild = (CompilerAnalyzer.AnalyzeResult == RecompileCategory.All) ? true : false; } // // Specially handle Reference list to prepare for xaml file compilation. // private ArrayList ProcessReferenceList( ) { ArrayList referenceList = new ArrayList(); // Generate the asmmebly reference list. if (References != null && References.Length > 0) { ReferenceAssembly asmReference; string refpath, asmname; for (int i = 0; i < References.Length; i++) { // The reference path must be full file path. refpath = References[i].ItemSpec; refpath = TaskHelper.CreateFullFilePath(refpath, SourceDir); asmname = Path.GetFileNameWithoutExtension(refpath); asmReference = new ReferenceAssembly(refpath, asmname); referenceList.Add(asmReference); // // If always run the compilation in second appdomain, there is no need to specially // handle the referenced assemblies. // Unload the appdomain can unload all the referenced assemblies. // if (AlwaysCompileMarkupFilesInSeparateDomain == false) { bool bCouldbeChanged = TaskHelper.CouldReferenceAssemblyBeChanged(refpath, KnownReferencePaths, AssembliesGeneratedDuringBuild); if (bCouldbeChanged) { MarkupCompiler.InitializeAssemblyState(asmname); } } Log.LogMessageFromResources(MessageImportance.Low, SRID.ReferenceFile, refpath); } } return referenceList; } // Cleanup baml files and code files generated in previous build. private void CleanupGeneratedFiles( ) { string codeFile, bamlFile; if (IsApplicationTarget && !String.IsNullOrEmpty(CompilerAnalyzer.RecompileApplicationFile)) { GetGeneratedFiles(CompilerAnalyzer.RecompileApplicationFile, out codeFile, out bamlFile); if (!String.IsNullOrEmpty(codeFile)) { TaskFileService.Delete(codeFile); } if (!String.IsNullOrEmpty(bamlFile)) { TaskFileService.Delete(bamlFile); } } if (CompilerAnalyzer.RecompileMarkupPages != null) { for (int i = 0; i < CompilerAnalyzer.RecompileMarkupPages.Length; i++) { GetGeneratedFiles(CompilerAnalyzer.RecompileMarkupPages[i], out codeFile, out bamlFile); if (!String.IsNullOrEmpty(codeFile)) { TaskFileService.Delete(codeFile); } if (!String.IsNullOrEmpty(bamlFile)) { TaskFileService.Delete(bamlFile); } } } // If the content file setting is changed, the generated content.g.cs code file should be updated later, // so delete the file here first. // // This includes the scenario that all the previous content files are removed from the content item list in // this build run. if ((CompilerAnalyzer.AnalyzeResult & RecompileCategory.ContentFiles) == RecompileCategory.ContentFiles) { if (TaskFileService.Exists(ContentCodeFile)) { TaskFileService.Delete(ContentCodeFile); } } // If this is for CleanBuild, and the InternalTypeHelper file exists, delete it first. if (IsCleanBuild && TaskFileService.Exists(InternalTypeHelperFile)) { TaskFileService.Delete(InternalTypeHelperFile); } } // // Call MarkupCompiler to do the real compilation work. // private void DoMarkupCompilation() { Log.LogMessageFromResources(MessageImportance.Low, SRID.DoCompilation); Log.LogMessageFromResources(MessageImportance.Low, SRID.OutputType, OutputType); // When code goes here, the MarkupCompilation is really required, so don't need // to do more further validation inside this private method. AppDomain appDomain = null; CompilerWrapper compilerWrapper = null; try { compilerWrapper = TaskHelper.CreateCompilerWrapper(AlwaysCompileMarkupFilesInSeparateDomain, ref appDomain); if (compilerWrapper != null) { compilerWrapper.OutputPath = OutputPath; compilerWrapper.AssemblyVersion = AssemblyVersion; compilerWrapper.AssemblyPublicKeyToken = AssemblyPublicKeyToken; compilerWrapper.LanguageSourceExtension = LanguageSourceExtension; compilerWrapper.HostInBrowser = TaskHelper.BooleanStringValue(HostInBrowser); compilerWrapper.SplashImage = SplashImageName; compilerWrapper.TaskLogger = Log; compilerWrapper.UnknownErrorID = UnknownErrorID; compilerWrapper.XamlDebuggingInformation = XamlDebuggingInformation; compilerWrapper.TaskFileService = TaskFileService; if (IsApplicationTarget) { compilerWrapper.ApplicationMarkup = CompilerAnalyzer.RecompileApplicationFile; } compilerWrapper.ContentFiles = CompilerAnalyzer.ContentFiles; // Process Reference list here. ArrayList referenceList = ProcessReferenceList(); compilerWrapper.References = referenceList; compilerWrapper.LocalizationDirectivesToLocFile = (int)_localizationDirectives; compilerWrapper.DoCompilation(AssemblyName, Language, RootNamespace, CompilerAnalyzer.RecompileMarkupPages, false); // Keep the Local-Type-Ref file lists _localXamlPages = compilerWrapper.LocalXamlPages; _localXamlApplication = compilerWrapper.LocalXamlApplication; _hasInternals = compilerWrapper.HasInternals; } } finally { if (compilerWrapper != null && compilerWrapper.ErrorTimes > 0) { _nErrors += compilerWrapper.ErrorTimes; } if (appDomain != null) { AppDomain.Unload(appDomain); compilerWrapper = null; } } } // // Generate the required Output Items. // private void GenerateOutputItems( ) { // For the rest target types, // Create the output lists for CS and Baml files. ArrayList bamlFileList = new ArrayList(); ArrayList csFileList = new ArrayList(); ArrayList localRefPageList = new ArrayList(); ArrayList localRefAppdefList = new ArrayList(); // Generate Output Items for PageMarkup if (PageMarkup != null && PageMarkup.Length > 0) { GenerateOutputItemsForCompiledXamlFiles(PageMarkup, _localXamlPages, ref bamlFileList, ref csFileList, ref localRefPageList); } // // Generate output items for ApplicationDefinition if it is set in the project file. // if (ApplicationFile != null && ApplicationFile.Length > 0) { string[] appdefLocalList = null; if (!String.IsNullOrEmpty(_localXamlApplication)) { appdefLocalList = new string[1] { _localXamlApplication }; } GenerateOutputItemsForCompiledXamlFiles(ApplicationMarkup, appdefLocalList, ref bamlFileList, ref csFileList, ref localRefAppdefList); } if (TaskFileService.Exists(ContentCodeFile)) { csFileList.Add(new TaskItem(ContentCodeFile)); } // Generate the Baml, code and /or locally-defined type related output items. GeneratedBamlFiles = (ITaskItem[])bamlFileList.ToArray(typeof(ITaskItem)); if (!SkipMarkupCompilation) { if (localRefAppdefList.Count > 0) { _localApplicationFile = (LocalReferenceFile)localRefAppdefList[0]; } if (localRefPageList.Count > 0) { _localMarkupPages = (LocalReferenceFile[])localRefPageList.ToArray(typeof(LocalReferenceFile)); } // // If MarkupCompilePass2 is required for Main assembly, there is no need to invoke MarkupCompilePass2 // for satellite assembly again. // if (_requirePass2ForMainAssembly) { _requirePass2ForSatelliteAssembly = false; } } // // Detect whether or not to ask Pass2 to do further handding for the InternalTypeHelper class. // // Only when all of below conditions are true, it requires Pass2 to further handling this wrapper class: // // 1. InternalTypeHelper file exists. // 2. It is a CleanBuild. // 3. No any xaml files which don't contain local types contains internal types from friend assembly. // 4. _requirePass2ForMainAssembly is true. // // If InternalTypeHelper File exists, Pass1 would always add it to the code file list, so that consequent task // can take it. If Pass2 determines that this wrapper class is not required, it can simply make an empty file. // But we still keep the list of generated code files. bool existsInternalTypeHelper = TaskFileService.Exists(InternalTypeHelperFile); if (IsCleanBuild && existsInternalTypeHelper && _requirePass2ForMainAssembly && !_hasInternals) { FurtherCheckInternalTypeHelper = true; } else { FurtherCheckInternalTypeHelper = false; } if (existsInternalTypeHelper) { csFileList.Add(new TaskItem(InternalTypeHelperFile)); } GeneratedCodeFiles = (ITaskItem[])csFileList.ToArray(typeof(ITaskItem)); // Generate the Localization Output files if (_localizationDirectives != MS.Internal.LocalizationDirectivesToLocFile.None) { GenerateOutputItemsForLocFiles(); } HandleCacheFiles(); // // Put all the generated files into one output Item so that it can be set to // FileWrites item in target file, this list of files will be cleaned up for // next clean build by msbuild. // The generated files should include Baml files, code files, localization files // and the cache files. // ArrayList allGeneratedFiles = new ArrayList( ); for (int i = 0; i < GeneratedBamlFiles.Length; i++) { allGeneratedFiles.Add(GeneratedBamlFiles[i]); } for (int i = 0; i < GeneratedCodeFiles.Length; i++) { allGeneratedFiles.Add(GeneratedCodeFiles[i]); } for (int i = 0; i < GeneratedLocalizationFiles.Length; i++) { allGeneratedFiles.Add(GeneratedLocalizationFiles[i]); } // Add the CompilerState cache file into the list allGeneratedFiles.Add(new TaskItem(CompilerState.CacheFilePath)); if (CompilerLocalReference.CacheFileExists()) { allGeneratedFiles.Add(new TaskItem(CompilerLocalReference.CacheFilePath)); } AllGeneratedFiles = (ITaskItem[])allGeneratedFiles.ToArray(typeof(ITaskItem)); } // // Both MarkupPage and MarkupResource have the similar code to generate // output baml, code file and /or locallyDefined xaml files. // so put all the common code in this private method. // // Inputs : // Xaml file items: PageMarkup or MarkupResource // LocallyDefined Xaml List (Generated by MarkupCompiler) // // Outputs: BamlFile List, // CodeFile List, // LocallyDefined Xaml List // private void GenerateOutputItemsForCompiledXamlFiles(ITaskItem[] inputXamlItemList, string[] inputLocalRefXamlFileList, ref ArrayList outputBamlFileList, ref ArrayList outputCodeFileList, ref ArrayList outputLocalRefXamlList) { // // For each input xaml file, check if the code and baml file are generated or not. // If baml or code files are generated, put them into the appropriate output file item list. // for (int i = 0; i < inputXamlItemList.Length; i++) { string genLangFilePath, bamlFile; GetGeneratedFiles(inputXamlItemList[i].ItemSpec, out genLangFilePath, out bamlFile); if (!String.IsNullOrEmpty(genLangFilePath) && outputCodeFileList != null) { TaskItem codeItem; codeItem = new TaskItem(); codeItem.ItemSpec = genLangFilePath; outputCodeFileList.Add(codeItem); Log.LogMessageFromResources(MessageImportance.Low, SRID.GeneratedCodeFile, codeItem.ItemSpec); } if (!String.IsNullOrEmpty(bamlFile)) { TaskItem bamlItem = GenerateBamlItem(bamlFile, inputXamlItemList[i]); // Add bamlItem to the output Baml List outputBamlFileList.Add(bamlItem); Log.LogMessageFromResources(MessageImportance.Low, SRID.GeneratedBamlFile, bamlItem.ItemSpec); } } // End of for { } loop. // // If the project contains local-type xaml files, put them into the right output item list here. // // // If MarkupCompilation is skipped, there is no need to check local-type xaml files. // if (!SkipMarkupCompilation && inputLocalRefXamlFileList != null && inputLocalRefXamlFileList.Length > 0) { for (int i = 0; i < inputLocalRefXamlFileList.Length; i++) { string fullLocalXamlFile = TaskHelper.CreateFullFilePath(inputLocalRefXamlFileList[i], SourceDir); LocalReferenceFile localFile = GenerateLocalTypeItem(fullLocalXamlFile, inputXamlItemList); if (localFile != null && outputLocalRefXamlList != null) { outputLocalRefXamlList.Add(localFile); } } } } // // Generate appropriate output file list for local-type xaml file. This information will be saved // into the .lref cache file so that the MarkupCompilePass2 can take it. // private LocalReferenceFile GenerateLocalTypeItem(string localTypeXamlFile, ITaskItem[] inputXamlItemList) { LocalReferenceFile localFile = null; bool isLocalizable = false; // // Check if the local-type xaml file is localizable or not. // for (int i = 0; i < inputXamlItemList.Length; i++) { ITaskItem inputXamlItem = inputXamlItemList[i]; string xamlInputFullPath = TaskHelper.CreateFullFilePath(inputXamlItem.ItemSpec, SourceDir); if (String.Compare(localTypeXamlFile, xamlInputFullPath, StringComparison.OrdinalIgnoreCase) == 0) { // // Got this file from the original XamlFile TaskItem list. // Check if this item is localizable or not and stop the search here. // isLocalizable = IsItemLocalizable(inputXamlItem); break; } } // // Generate the instance of LocalReferenceFile for this local-type xaml file. // localFile = new LocalReferenceFile(localTypeXamlFile, isLocalizable); if (isLocalizable) { _requirePass2ForSatelliteAssembly = true; } else { _requirePass2ForMainAssembly = true; } return localFile; } // // Generate a baml TaskItem for the given xmal file, and transfer the appropriate // source task item's custom attributes to the generated baml item if necessary. // The xaml file could be an application definition file, a Markup Page. // The bamlFile must exist before this method is called. private TaskItem GenerateBamlItem(string bamlFile, ITaskItem SourceItem) { TaskItem bamlItem; bamlItem = new TaskItem(); bamlItem.ItemSpec = bamlFile; // // Transfer some special custom attributes from source task item // to output item. // Such as transfer the Localizable attribute from a given .xaml file item // to the generated .baml file item. // // Normally MarkupPage and MarkupResource need to transfer their attributes. // But Application definition doesn't require this. if (SourceItem != null) { string[] listCarryOverAttribute = new string[] { "Localizable" }; for (int j = 0; j < listCarryOverAttribute.Length; j++) { string attributeValue; attributeValue = SourceItem.GetMetadata(listCarryOverAttribute[j]); if (attributeValue != null) { bamlItem.SetMetadata(listCarryOverAttribute[j], attributeValue); } } } return bamlItem; } // // Generate output item list for localization files. // private void GenerateOutputItemsForLocFiles() { ArrayList locFileItemList = new ArrayList(); TaskItem tiLoc; ITaskItem xamlItem; if (ApplicationMarkup != null && ApplicationMarkup.Length > 0 && ApplicationMarkup[0] != null) { tiLoc = ProcessLocFileForXamlItem(ApplicationMarkup[0]); if (tiLoc != null) { // Add this LocItem to the locFileItemList locFileItemList.Add(tiLoc); } } if (PageMarkup != null) { for (int i = 0; i < PageMarkup.Length; i++) { xamlItem = PageMarkup[i]; tiLoc = ProcessLocFileForXamlItem(xamlItem); if (tiLoc != null) { // Add this LocItem to the locFileItemList locFileItemList.Add(tiLoc); } } } // Generate the Output TaskItem List GeneratedLocalizationFiles = (ITaskItem[])locFileItemList.ToArray(typeof(ITaskItem)); } // // General method to handle an input xaml file item for Localization. // // If the XamlFile is localizable, generate a TaskItem for LocFile. // If the XamlFile is not localizable, and if the .loc file is generated, delelet it // so that it won't affec the incremental build next time. // private TaskItem ProcessLocFileForXamlItem(ITaskItem xamlItem) { TaskItem tiLoc = null; string tempDir = SourceDir; // Just for calling GetResolvedFilePath, the value is not used here. // Get a relative file path for the passed .xaml file string xamlRelativeFilePath = GetResolvedFilePath(xamlItem.ItemSpec, ref tempDir); string locFile; // Change the extension from .xaml to .loc locFile = Path.ChangeExtension(xamlRelativeFilePath, SharedStrings.LocExtension); // the .loc file is at OutputPath + relative Path. locFile = OutputPath + locFile; if (TaskFileService.Exists(locFile)) { // // Per discussion with Globalization team: // // Globalization requests to collect .loc file for a baml file // no matter the baml is in main assembly or satelliate assembly. // // The localization tool can localize the baml from the main assembly as well. // // Generate a TaskItem to include .loc file // The item is going to add to the output LocFile list tiLoc = new TaskItem(locFile); } return tiLoc; } // // Check if the given TaskItem localizable. // private bool IsItemLocalizable(ITaskItem ti) { bool bIsLocalizable; if (String.IsNullOrEmpty(UICulture)) { // if UICulture is not set, all baml files are not localizable. // The Localizable metadate value is ignored for this case. bIsLocalizable = false; } else { string strLocalizable; // if UICulture is set, by default all the baml files are localizable unless // an explicit value "false" is set to Localizable metadata. bIsLocalizable = true; strLocalizable = ti.GetMetadata(SharedStrings.Localizable); if (strLocalizable != null && String.Compare(strLocalizable, "false", StringComparison.OrdinalIgnoreCase) == 0) { bIsLocalizable = false; } } return bIsLocalizable; } // // Cleanup the cache files. // It could happen if build error occurs. // private void CleanupCacheFiles() { CompilerState.CleanupCache(); CompilerLocalReference.CleanupCache(); } // // A central place to update cache files based on current build status MarkupCompiler result. // // This method should be called after the markupcompiler is done or skipped. // private void HandleCacheFiles() { // Update the CompilerState file based on new project setting, no matter MarkupCompiler is skipped or not. CompilerState.SaveStateInformation(this); if ( (CompilerAnalyzer.AnalyzeResult & ( RecompileCategory.PagesWithLocalType | RecompileCategory.ModifiedPages )) != RecompileCategory.NoRecompile) { // The modified xaml files and all the local-type xaml files should be recompiled, depends on the // MarkupCompiler return, it will keep or delete the cache file for local type xaml files. if (_requirePass2ForMainAssembly || _requirePass2ForSatelliteAssembly) { CompilerLocalReference.SaveCacheInformation(this); } else { CompilerLocalReference.CleanupCache(); } } // if build doesn't handle the local-ref xaml files, (it implies not handling the modified xaml files either), // such as the build handles only for Application (HIB change) and Content files changes, or the markup compilation // is skipped, ( NoRecompile). // // For this scenario, if .lref file exists, it should still be kept. // } #endregion Private Methods //----------------------------------------------------- // // Private Properties // //----------------------------------------------------- #region Private Properties //// The root directory for the applicaiton project. // private string SourceDir { get { return _sourceDir; } } private IncrementalCompileAnalyzer CompilerAnalyzer { get { return _compilerAnalyzer; } } // // If no input file is modified, Markup compilation will be skipped. // But the code still generates the correct output item lists. // private bool SkipMarkupCompilation { get { return CompilerAnalyzer.AnalyzeResult == RecompileCategory.NoRecompile; } } private string ContentCodeFile { get { return OutputPath + AssemblyName + SharedStrings.ContentFile + (TaskFileService.IsRealBuild? SharedStrings.GeneratedExtension : SharedStrings.IntellisenseGeneratedExtension) + LanguageSourceExtension; } } // // Whether this is a clean build or not // private bool IsCleanBuild { get { return _isCleanBuild; } } #endregion Private Properties //----------------------------------------------------- // // Private Fields // //------------------------------------------------------ #region Private Fields private string _language; private string _languageSourceExtension = string.Empty; private ITaskItem [] _pagemarkupFiles; private ITaskItem [] _contentFiles; private ITaskItem [] _references; private bool _xamlDebuggingInformation = false; private string _outputType; private string _assemblyName; private string _assemblyVersion; private string _assemblyPublicKeyToken; private string _rootNamespace = String.Empty; private ITaskItem [] _applicationMarkup; private ITaskItem[] _splashScreen; private bool _alwaysCompileMarkupFilesInSeparateDomain = true; private string[] _assembliesGeneratedDuringBuild; private string[] _knownReferencePaths; private string _sourceDir; private string _outputDir; private ITaskItem[] _extraBuildControlFiles; private string _uiCulture = String.Empty; private string _applicationFile = String.Empty; private bool _isApplicationTarget = false; private string _hostInBrowser = String.Empty; private LocalizationDirectivesToLocFile _localizationDirectives; private ITaskItem [] _generatedCodeFiles; private ITaskItem [] _generatedBamlFiles; private ITaskItem [] _generatedLocalizationFiles; private ITaskItem [] _allGeneratedFiles = null; private string _localXamlApplication; private string[] _localXamlPages; private bool _hasInternals = false; private int _nErrors; private string _defineConstants = String.Empty; private ITaskItem[] _sourceCodeFiles; private string _pageMarkupCache = String.Empty; private string _contentFilesCache = String.Empty; private string _sourceCodeFilesCache = String.Empty; private string _referencesCache = String.Empty; private LocalReferenceFile _localApplicationFile = null; private LocalReferenceFile[] _localMarkupPages = null; private bool _requirePass2ForMainAssembly = false; private bool _requirePass2ForSatelliteAssembly = false; private bool _furtherCheckInternalTypeHelper = false; private CompilerState _compilerState; private CompilerLocalReference _compilerLocalRefCache; private IncrementalCompileAnalyzer _compilerAnalyzer; private ITaskFileService _taskFileService; private bool _isCleanBuild = true; // Indicates whether this is a cleanbuild or incremental build. #region const string private const string UnknownErrorID = "MC1000"; #endregion const string #endregion Private Fields } #endregion MarkupCompilePass1 Task class } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //---------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: An MSBuild Task that can generate .xaml markup file to specific // Mangaged language code such as .cs, .js, .vb,etc, and /or binary // token file .baml // // Spec: http://avalon/app/Compilation/Avalon-MSBUILD%20Targets.doc // // History: // 06/20/03: weibz rewrite and moved over to WCP tree // //--------------------------------------------------------------------------- using System; using System.IO; using System.Collections; using System.Security; using System.Security.Permissions; using System.Globalization; using System.Diagnostics; using System.Reflection; using System.Resources; using System.Runtime.InteropServices; using System.CodeDom; using System.CodeDom.Compiler; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; using MS.Utility; using MS.Internal; using MS.Internal.Tasks; using MS.Internal.Markup; // Since we disable PreSharp warnings in this file, PreSharp warning is unknown to C# compiler. // We first need to disable warnings about unknown message numbers and unknown pragmas. #pragma warning disable 1634, 1691 namespace Microsoft.Build.Tasks.Windows { #region MarkupCompilePass1 Task class ////// Class of MarkupCompilePass1 Task /// public sealed class MarkupCompilePass1 : Task { // Security Concerns: hamidm 04/13/05 // // 1) OutputPath property exposes the current dir and is publicly available. // 2) This class generates code files and copies them on the disk. // // The above two are already mitigated by the following facts: // // 1) PresentationBuildTasks is not APTCA and thus partial trust assemblies // cannot call into it. // 2) There is a possibility that some APTCA assembly (eg. PF.dll) can create // this object and pass it on to partial trust code. This is mitigated by // FxCop rule against it. // //----------------------------------------------------- // // Constructors // //----------------------------------------------------- #region Constructors ////// Constructor /// public MarkupCompilePass1( ) : base(SR.ResourceManager) { // set the source directory _sourceDir = Directory.GetCurrentDirectory() + "\\"; _outputType = SharedStrings.WinExe; // By default, no localization information is stripped out. _localizationDirectives = MS.Internal.LocalizationDirectivesToLocFile.None; _nErrors = 0; } #endregion Constructors //------------------------------------------------------ // // Public Methods // //----------------------------------------------------- #region Public Methods ////// Execute method in Task /// ///public override bool Execute() { //CASRemoval:(new PermissionSet(PermissionState.Unrestricted)).Assert(); TaskHelper.DisplayLogo(Log, SR.Get(SRID.MarkupCompilePass1Task)); bool bSuccess = true; try { // // Create the TaskFileService instance here // _taskFileService = new TaskFileService(this) as ITaskFileService; _compilerState = new CompilerState( OutputPath + AssemblyName + (TaskFileService.IsRealBuild? SharedStrings.StateFile : SharedStrings.IntellisenseStateFile), TaskFileService); _compilerLocalRefCache = new CompilerLocalReference( OutputPath + AssemblyName + (TaskFileService.IsRealBuild? SharedStrings.LocalTypeCacheFile : SharedStrings.IntellisenseLocalTypeCacheFile), TaskFileService); if ((PageMarkup == null || PageMarkup.Length == 0) && (ApplicationMarkup == null || ApplicationMarkup.Length == 0)) { // Don't need to do further work. // stop here. CleanupCacheFiles(); return true; } VerifyInputs(); Log.LogMessageFromResources(MessageImportance.Low, SRID.CurrentDirectory, SourceDir); // If wrong files are set to some properties, the task // should stop here immediatelly. if (_nErrors > 0) { Log.LogErrorWithCodeFromResources(SRID.WrongPropertySetting); } else { // create output directory if (!Directory.Exists(OutputPath)) { Directory.CreateDirectory(OutputPath); } // Analyze project inputs to detect which xaml files require to recompile. AnalyzeInputsAndSetting(); Log.LogMessageFromResources(MessageImportance.Low, SRID.AnalysisResult, CompilerAnalyzer.AnalyzeResult); if (!SkipMarkupCompilation) { if (CompilerAnalyzer.RecompileMarkupPages != null) { for (int i = 0; i < CompilerAnalyzer.RecompileMarkupPages.Length; i++) { Log.LogMessageFromResources(MessageImportance.Low, SRID.RecompiledXaml, CompilerAnalyzer.RecompileMarkupPages[i]); } } // If recompile is required, CompilerAnalyzer contains all the files which need to recompile. // Cleanup baml files and code files generated in previous build. if (TaskFileService.IsRealBuild) { CleanupGeneratedFiles(); } // Call the Markup Compiler to do the real compiling work DoMarkupCompilation(); } // Generate the required output items. GenerateOutputItems(); Log.LogMessageFromResources(MessageImportance.Low, SRID.CompilationDone); } } #pragma warning disable 6500 catch (Exception e) { string message; string errorId; errorId = Log.ExtractMessageCode(e.Message, out message); if (String.IsNullOrEmpty(errorId)) { errorId = UnknownErrorID; message = SR.Get(SRID.UnknownBuildError, message); } Log.LogError(null, errorId, null, null, 0, 0, 0, 0, message, null); _nErrors++; } catch // Non-CLS compliant errors { Log.LogErrorWithCodeFromResources(SRID.NonClsError); _nErrors++; } #pragma warning restore 6500 if (_nErrors > 0) { // When error counter is changed, the appropriate error message should have // been reported, simply return false here. bSuccess = false; CleanupCacheFiles(); } else { Log.LogMessageFromResources(MessageImportance.Low, SRID.CompileSucceed_Pass1); } return bSuccess; } #endregion Public Methods //------------------------------------------------------ // // Public Properties // //------------------------------------------------------ #region Public Properties /// /// The Language the managed compiler supports. /// the valid languages are C#, VB, Jscript, J#, C++ /// [Required] public string Language { get { return _language; } set { _language = value;} } ////// The valid source file extension for the passed language. /// Normally a language supports more valid source file extensions. /// User could choose one of them in project file. /// If this property is not set, we will take use of the default one for the language. /// public string LanguageSourceExtension { get { return _languageSourceExtension; } set { _languageSourceExtension = value; } } ////// OutputPath : Generated code files, Baml fles will be put in this directory. /// [Required] public string OutputPath { get { return _outputDir; } set { string filePath = value; // Get the relative path based on sourceDir _outputDir= TaskHelper.CreateFullFilePath(filePath, SourceDir); // Make sure OutputDir always ends with '\\'. if (!_outputDir.EndsWith("\\", StringComparison.Ordinal)) { _outputDir += "\\"; } } } ////// OutputType /// Valid types: winexe, exe, library, netmodule. /// [Required] public string OutputType { get { return _outputType; } set { _outputType = TaskHelper.GetLowerString(value); } } ////// AssemblyName /// The short name of assembly which will be generated for this project. /// [Required] public string AssemblyName { get { return _assemblyName; } set { _assemblyName = value; } } ////// The version of the assembly /// public string AssemblyVersion { get { return _assemblyVersion; } set { _assemblyVersion = value; } } ////// The public key token of the assembly /// public string AssemblyPublicKeyToken { get { return _assemblyPublicKeyToken; } set { _assemblyPublicKeyToken = value; } } ////// Root namespace for the classes inside the project. /// It is also used as default CLR namespace of a generated code file /// when the corresponding markup page is not set x:Class attribute. /// public string RootNamespace { get { return _rootNamespace; } set { _rootNamespace = value; } } ////// The UI Culture controls which culture satellite assembly will hold /// the generated baml files. /// If UICulture is not set, the generated baml files will be embedded /// into main assembly. /// public string UICulture { get { return _uiCulture; } set { _uiCulture = value; } } ////// Source code file list for the current project. /// It doesnt include any generated code files. /// public ITaskItem[] SourceCodeFiles { get { return _sourceCodeFiles; } set { _sourceCodeFiles = value; } } ////// DefineConstants /// /// Keep the current value of DefineConstants. /// /// DefineConstants can affect the final assembly generation, if DefineConstants /// value is changed, the public API might be changed in the target assembly, which /// then has potential impacts on compilation for xaml files which contains local types. /// /// public string DefineConstants { get { return _defineConstants; } set { _defineConstants = value; } } ////// ApplicationMarkup /// public ITaskItem [] ApplicationMarkup { get { return _applicationMarkup; } set { _applicationMarkup = value;} } ////// Description /// public ITaskItem [] PageMarkup { get { return _pagemarkupFiles; } set { _pagemarkupFiles = value; } } ////// Splash screen image to be displayed before application init /// public ITaskItem[] SplashScreen { get { return _splashScreen; } set { _splashScreen = value; } } internal string SplashImageName { get { if (SplashScreen != null && SplashScreen.Length > 0) { return SplashScreen[0].ItemSpec.ToLowerInvariant(); } return null; } } ////// Loose file content list /// public ITaskItem[] ContentFiles { get { return _contentFiles; } set { _contentFiles = value; } } ////// Assembly References. /// ///public ITaskItem[] References { get { return _references; } set { _references = value; } } /// /// public bool XamlDebuggingInformation { get { return _xamlDebuggingInformation; } set { _xamlDebuggingInformation = value; } } ////// Keep a list of Build control files. /// If one of them is changed since last build, it would trigger recompilation of all the xaml files. /// Such as WinFX target file change could require a rebuild etc. /// public ITaskItem [] ExtraBuildControlFiles { get { return _extraBuildControlFiles; } set { _extraBuildControlFiles = value; } } //////If true code for supporting hosting in Browser is generated /// public string HostInBrowser { get { return _hostInBrowser; } set { _hostInBrowser = TaskHelper.GetLowerString(value); } } ////// Controls how to generate localization information for each xaml file. /// Valid values: None, CommentsOnly, All. /// public string LocalizationDirectivesToLocFile { get { string localizationDirectives = SharedStrings.Loc_None; switch (_localizationDirectives) { case MS.Internal.LocalizationDirectivesToLocFile.None : localizationDirectives = SharedStrings.Loc_None; break; case MS.Internal.LocalizationDirectivesToLocFile.CommentsOnly: localizationDirectives = SharedStrings.Loc_CommentsOnly; break; case MS.Internal.LocalizationDirectivesToLocFile.All: localizationDirectives = SharedStrings.Loc_All; break; } return localizationDirectives; } set { string localizationDirectives = value; if (localizationDirectives != null) { localizationDirectives = localizationDirectives.ToLower(CultureInfo.InvariantCulture); } switch (localizationDirectives) { case SharedStrings.Loc_None : _localizationDirectives = MS.Internal.LocalizationDirectivesToLocFile.None; break; case SharedStrings.Loc_CommentsOnly : _localizationDirectives = MS.Internal.LocalizationDirectivesToLocFile.CommentsOnly; break; case SharedStrings.Loc_All : _localizationDirectives = MS.Internal.LocalizationDirectivesToLocFile.All; break; default: _localizationDirectives = MS.Internal.LocalizationDirectivesToLocFile.Unknown; break; } } } ////// Known reference paths hold referenced assemblies which are never changed during the build procedure. /// such as references in GAC, in framework directory or framework SDK directory etc. /// Users could add their own known reference paths in project files. /// public string[] KnownReferencePaths { get { return _knownReferencePaths; } set { _knownReferencePaths = value; } } ////// A list of reference assemblies that are to change for sure during the build cycle. /// /// Such as in VS.NET, if one project wants to reference another project's output, the /// second project's output could be put in AssembliesGeneratedDuringBuild list. /// Note: Once this property is set, it must contain the complete list of generated /// assemblies in this build solution. /// public string[] AssembliesGeneratedDuringBuild { get { return _assembliesGeneratedDuringBuild; } set { _assembliesGeneratedDuringBuild = value; } } ////// Control whether to run the compilation in second appdomain. /// By default, it is set to true, but project can set this property /// to false to make markup file compilation faster. /// public bool AlwaysCompileMarkupFilesInSeparateDomain { get { return _alwaysCompileMarkupFilesInSeparateDomain; } set { _alwaysCompileMarkupFilesInSeparateDomain = value; } } ////// Generated source code files for the given programing language. /// [Output] public ITaskItem [] GeneratedCodeFiles { get { if (_generatedCodeFiles == null) _generatedCodeFiles = new TaskItem[0]; return _generatedCodeFiles; } set { _generatedCodeFiles = value; } } ////// Generated Baml files for the passed Markup files. /// [Output] public ITaskItem [] GeneratedBamlFiles { get { if (_generatedBamlFiles == null) _generatedBamlFiles = new TaskItem[0]; return _generatedBamlFiles; } set { _generatedBamlFiles = value; } } ////// The generated localization file for each localizable xaml file. /// [Output] public ITaskItem[] GeneratedLocalizationFiles { get { if (_generatedLocalizationFiles == null) _generatedLocalizationFiles = new TaskItem[0]; return _generatedLocalizationFiles; } set { _generatedLocalizationFiles = value; } } #region Local Reference Xaml markup files ////// Indicate whether the project contains xaml files which reference local types and /// the corresponding baml file will be embedded into main assembly. /// [Output] public bool RequirePass2ForMainAssembly { get { return _requirePass2ForMainAssembly; } set { _requirePass2ForMainAssembly = value; } } ////// Indicate whether the project contains xaml files which reference local types and /// the corresponding baml file will be embedded into satellite assembly for current UICulture. /// [Output] public bool RequirePass2ForSatelliteAssembly { get { return _requirePass2ForSatelliteAssembly; } set { _requirePass2ForSatelliteAssembly = value; } } #endregion Local Reference Xaml markup files ////// A complete list of files which are generated by MarkupCompiler. /// [Output] public ITaskItem[] AllGeneratedFiles { get { return _allGeneratedFiles; } set { _allGeneratedFiles = value; } } #endregion Public Properties #region internal methods // // Get the generated code file and baml file for a given xaml file // If the generated file doesn't exist, the output paramter is set to empty string. // internal void GetGeneratedFiles(string xamlFile, out string codeFile, out string bamlFile) { string newSourceDir = SourceDir; codeFile = String.Empty; bamlFile = String.Empty; if (String.IsNullOrEmpty(xamlFile)) { // if xaml file is empty, return it now. return; } string relativeFilePath = GetResolvedFilePath(xamlFile, ref newSourceDir); string langExt = (TaskFileService.IsRealBuild? SharedStrings.GeneratedExtension : SharedStrings.IntellisenseGeneratedExtension) + LanguageSourceExtension; // Replace the .xaml with corresponding generated file extensions. codeFile = OutputPath + Path.ChangeExtension(relativeFilePath, langExt); bamlFile = OutputPath + Path.ChangeExtension(relativeFilePath, SharedStrings.BamlExtension); // If the file doesn't exist, return empty string for the corresponding output parameter. if (!TaskFileService.Exists(codeFile)) { codeFile = String.Empty; } // // Baml file is not generated for intellisense build. // if ((TaskFileService.IsRealBuild == false) || (!TaskFileService.Exists(bamlFile))) { bamlFile = String.Empty; } } #endregion internal methods #region internal Properties internal bool IsApplicationTarget { get { return _isApplicationTarget; } } // // ApplicationFile // internal string ApplicationFile { get { return _applicationFile; } } // // PageMarkupCache // It is caculated from current PageMarkup list, will be saved in the // cache file to support incremental compilation. // internal string PageMarkupCache { get { return _pageMarkupCache; } } // // ContentFilesCache // It is caculated from current ContentFiles list, will be saved in the // cache file to support incremental compilation. // internal string ContentFilesCache { get { return _contentFilesCache; } } // // SourceCodeFilesCache // It is caculated from current SourceCodeFiles list, will be saved in the // cache file to support incremental compilation. // internal string SourceCodeFilesCache { get { return _sourceCodeFilesCache; } } // // ReferencesCache // It is caculated from current ReferencesCache list, will be saved in the // cache file to support incremental compilation. // internal string ReferencesCache { get { return _referencesCache; } } // // Application File with Local Type // internal LocalReferenceFile LocalApplicationFile { get { return _localApplicationFile; } } // // Markup Page files with local types // internal LocalReferenceFile[] LocalMarkupPages { get { return _localMarkupPages; } } // // TaskFileService // internal ITaskFileService TaskFileService { get { return _taskFileService; } } // // CompilerState // internal CompilerState CompilerState { get { return _compilerState; } } // // CompilerLocalReference // internal CompilerLocalReference CompilerLocalReference { get { return _compilerLocalRefCache; } } // // Tell MarkupCompilePass2 whether it further handles InternalTypeHelper class. // internal bool FurtherCheckInternalTypeHelper { get { return _furtherCheckInternalTypeHelper; } set { _furtherCheckInternalTypeHelper = value; } } // // Get the file path for the generated InternalTypeHelper class. // internal string InternalTypeHelperFile { get { string fileName = SharedStrings.GeneratedInternalTypeHelperFileName + (TaskFileService.IsRealBuild? SharedStrings.GeneratedExtension : SharedStrings.IntellisenseGeneratedExtension) + LanguageSourceExtension; return Path.Combine(OutputPath, fileName); } } #endregion internal Properties //----------------------------------------------------- // // Private Methods // //------------------------------------------------------ #region Private Methods // // Check if all the input properties are set valid values // If any property contains an invalid value, Error counter _nErrors will // be changed. // private void VerifyInputs() { // Check if the OutputType is valid type. IsSupportedOutputType(OutputType); // Check if the Localization property is set correctly. IsValidLocalizationDirectives(); VerifyApplicationFile(); if (PageMarkup != null && PageMarkup.Length > 0) { VerifyInputTaskItems(PageMarkup); } if (SplashScreen != null && SplashScreen.Length > 1) { Log.LogErrorWithCodeFromResources(SRID.MultipleSplashScreenImages); _nErrors++; } } // // Verify if the Application file is set correctly // in project file. // private void VerifyApplicationFile() { if (!IsApplicationTarget) { // // For non Application target type. // if (ApplicationMarkup != null && ApplicationMarkup.Length > 0) { // // For non-Application target type, Application definition should not be set. // Log.LogErrorWithCodeFromResources(SRID.AppDefIsNotRequired); _nErrors++; } } else { // // For Application Target type. // if (ApplicationMarkup != null && ApplicationMarkup.Length > 0) { if (ApplicationMarkup.Length > 1) { Log.LogErrorWithCodeFromResources(SRID.MutlipleApplicationFiles); _nErrors++; } _applicationFile = TaskHelper.CreateFullFilePath(ApplicationMarkup[0].ItemSpec, SourceDir); Log.LogMessageFromResources(MessageImportance.Low, SRID.ApplicationDefinitionFile, ApplicationFile); if (!TaskFileService.Exists(ApplicationFile)) { Log.LogErrorWithCodeFromResources(SRID.FileNotFound, ApplicationFile); _nErrors++; } } } } // // Don't support local reference xaml compilation for Container and netmodule type. // private bool IsSupportedOutputType(string outputType) { bool isSupported = false; switch (outputType) { case SharedStrings.Exe: case SharedStrings.WinExe: isSupported = true; _isApplicationTarget = true; break; case SharedStrings.Library: case SharedStrings.Module: isSupported = true; break; default: isSupported = false; break; } if (isSupported == false) { Log.LogErrorWithCodeFromResources(SRID.TargetIsNotSupported, outputType); // Keep the error numbers so that the task can stop immediatelly // later when Execute( ) is called. _nErrors++; } return isSupported; } private bool IsValidLocalizationDirectives() { bool bValid = true; if (_localizationDirectives == MS.Internal.LocalizationDirectivesToLocFile.Unknown) { bValid = false; Log.LogErrorWithCodeFromResources(SRID.WrongLocalizationPropertySetting_Pass1); // Keep the error numbers so that the task can stop immediatelly // later when Execute( ) is called. _nErrors++; } return bValid; } //// Check if the passed TaskItems have valid ItemSpec // // //private bool VerifyInputTaskItems(ITaskItem[] inputItems) { bool bValid = true; foreach (ITaskItem inputItem in inputItems) { bool bValidItem; bValidItem = IsValidInputFile(inputItem.ItemSpec); if (bValidItem == false) { bValid = false; } } return bValid; } private bool IsValidInputFile(string filePath) { bool bValid = true; if (!TaskFileService.Exists(TaskHelper.CreateFullFilePath(filePath, SourceDir))) { bValid = false; Log.LogErrorWithCodeFromResources(SRID.FileNotFound, filePath); // Keep the error numbers so that the task can stop immediatelly // later when Execute( ) is called. _nErrors ++; } return bValid; } // // Return a new sourceDir and relative filepath for a given filePath. // This is for supporting of fullpath or ..\ in the original FilePath. // private string GetResolvedFilePath(string filePath, ref string newSourceDir) { // Create a full path for the originalFilePath. string fullFilePath = TaskHelper.CreateFullFilePath(filePath, SourceDir); // Get the relative path based on sourceDir string relPath = TaskHelper.GetRootRelativePath(SourceDir, fullFilePath); string newRelativeFilePath; if (relPath.Length > 0) { // the original file is relative to the SourceDir. newSourceDir = SourceDir; newRelativeFilePath = relPath; } else { // the original file is not relative to the SourceDir. // it could have its own fullpath or contains "..\" etc. // // In this case, we want to put the filename as relative filepath // and put the deepest directory that file is in as the new // SourceDir. // int pathEndIndex = fullFilePath.LastIndexOf("\\", StringComparison.Ordinal); newSourceDir = fullFilePath.Substring(0, pathEndIndex + 1); newRelativeFilePath = TaskHelper.GetRootRelativePath(newSourceDir, fullFilePath); } return newRelativeFilePath; } // // Analyze the project setting and input files for incremental build support. private void AnalyzeInputsAndSetting() { // Initialize the cache file paths and related information. _pageMarkupCache = CompilerState.GenerateCacheForFileList(PageMarkup); _contentFilesCache = CompilerState.GenerateCacheForFileList(ContentFiles); _sourceCodeFilesCache = CompilerState.GenerateCacheForFileList(SourceCodeFiles); _referencesCache = CompilerState.GenerateCacheForFileList(References); _compilerAnalyzer = new IncrementalCompileAnalyzer(this); _compilerAnalyzer.AnalyzeInputFiles(); _isCleanBuild = (CompilerAnalyzer.AnalyzeResult == RecompileCategory.All) ? true : false; } // // Specially handle Reference list to prepare for xaml file compilation. // private ArrayList ProcessReferenceList( ) { ArrayList referenceList = new ArrayList(); // Generate the asmmebly reference list. if (References != null && References.Length > 0) { ReferenceAssembly asmReference; string refpath, asmname; for (int i = 0; i < References.Length; i++) { // The reference path must be full file path. refpath = References[i].ItemSpec; refpath = TaskHelper.CreateFullFilePath(refpath, SourceDir); asmname = Path.GetFileNameWithoutExtension(refpath); asmReference = new ReferenceAssembly(refpath, asmname); referenceList.Add(asmReference); // // If always run the compilation in second appdomain, there is no need to specially // handle the referenced assemblies. // Unload the appdomain can unload all the referenced assemblies. // if (AlwaysCompileMarkupFilesInSeparateDomain == false) { bool bCouldbeChanged = TaskHelper.CouldReferenceAssemblyBeChanged(refpath, KnownReferencePaths, AssembliesGeneratedDuringBuild); if (bCouldbeChanged) { MarkupCompiler.InitializeAssemblyState(asmname); } } Log.LogMessageFromResources(MessageImportance.Low, SRID.ReferenceFile, refpath); } } return referenceList; } // Cleanup baml files and code files generated in previous build. private void CleanupGeneratedFiles( ) { string codeFile, bamlFile; if (IsApplicationTarget && !String.IsNullOrEmpty(CompilerAnalyzer.RecompileApplicationFile)) { GetGeneratedFiles(CompilerAnalyzer.RecompileApplicationFile, out codeFile, out bamlFile); if (!String.IsNullOrEmpty(codeFile)) { TaskFileService.Delete(codeFile); } if (!String.IsNullOrEmpty(bamlFile)) { TaskFileService.Delete(bamlFile); } } if (CompilerAnalyzer.RecompileMarkupPages != null) { for (int i = 0; i < CompilerAnalyzer.RecompileMarkupPages.Length; i++) { GetGeneratedFiles(CompilerAnalyzer.RecompileMarkupPages[i], out codeFile, out bamlFile); if (!String.IsNullOrEmpty(codeFile)) { TaskFileService.Delete(codeFile); } if (!String.IsNullOrEmpty(bamlFile)) { TaskFileService.Delete(bamlFile); } } } // If the content file setting is changed, the generated content.g.cs code file should be updated later, // so delete the file here first. // // This includes the scenario that all the previous content files are removed from the content item list in // this build run. if ((CompilerAnalyzer.AnalyzeResult & RecompileCategory.ContentFiles) == RecompileCategory.ContentFiles) { if (TaskFileService.Exists(ContentCodeFile)) { TaskFileService.Delete(ContentCodeFile); } } // If this is for CleanBuild, and the InternalTypeHelper file exists, delete it first. if (IsCleanBuild && TaskFileService.Exists(InternalTypeHelperFile)) { TaskFileService.Delete(InternalTypeHelperFile); } } // // Call MarkupCompiler to do the real compilation work. // private void DoMarkupCompilation() { Log.LogMessageFromResources(MessageImportance.Low, SRID.DoCompilation); Log.LogMessageFromResources(MessageImportance.Low, SRID.OutputType, OutputType); // When code goes here, the MarkupCompilation is really required, so don't need // to do more further validation inside this private method. AppDomain appDomain = null; CompilerWrapper compilerWrapper = null; try { compilerWrapper = TaskHelper.CreateCompilerWrapper(AlwaysCompileMarkupFilesInSeparateDomain, ref appDomain); if (compilerWrapper != null) { compilerWrapper.OutputPath = OutputPath; compilerWrapper.AssemblyVersion = AssemblyVersion; compilerWrapper.AssemblyPublicKeyToken = AssemblyPublicKeyToken; compilerWrapper.LanguageSourceExtension = LanguageSourceExtension; compilerWrapper.HostInBrowser = TaskHelper.BooleanStringValue(HostInBrowser); compilerWrapper.SplashImage = SplashImageName; compilerWrapper.TaskLogger = Log; compilerWrapper.UnknownErrorID = UnknownErrorID; compilerWrapper.XamlDebuggingInformation = XamlDebuggingInformation; compilerWrapper.TaskFileService = TaskFileService; if (IsApplicationTarget) { compilerWrapper.ApplicationMarkup = CompilerAnalyzer.RecompileApplicationFile; } compilerWrapper.ContentFiles = CompilerAnalyzer.ContentFiles; // Process Reference list here. ArrayList referenceList = ProcessReferenceList(); compilerWrapper.References = referenceList; compilerWrapper.LocalizationDirectivesToLocFile = (int)_localizationDirectives; compilerWrapper.DoCompilation(AssemblyName, Language, RootNamespace, CompilerAnalyzer.RecompileMarkupPages, false); // Keep the Local-Type-Ref file lists _localXamlPages = compilerWrapper.LocalXamlPages; _localXamlApplication = compilerWrapper.LocalXamlApplication; _hasInternals = compilerWrapper.HasInternals; } } finally { if (compilerWrapper != null && compilerWrapper.ErrorTimes > 0) { _nErrors += compilerWrapper.ErrorTimes; } if (appDomain != null) { AppDomain.Unload(appDomain); compilerWrapper = null; } } } // // Generate the required Output Items. // private void GenerateOutputItems( ) { // For the rest target types, // Create the output lists for CS and Baml files. ArrayList bamlFileList = new ArrayList(); ArrayList csFileList = new ArrayList(); ArrayList localRefPageList = new ArrayList(); ArrayList localRefAppdefList = new ArrayList(); // Generate Output Items for PageMarkup if (PageMarkup != null && PageMarkup.Length > 0) { GenerateOutputItemsForCompiledXamlFiles(PageMarkup, _localXamlPages, ref bamlFileList, ref csFileList, ref localRefPageList); } // // Generate output items for ApplicationDefinition if it is set in the project file. // if (ApplicationFile != null && ApplicationFile.Length > 0) { string[] appdefLocalList = null; if (!String.IsNullOrEmpty(_localXamlApplication)) { appdefLocalList = new string[1] { _localXamlApplication }; } GenerateOutputItemsForCompiledXamlFiles(ApplicationMarkup, appdefLocalList, ref bamlFileList, ref csFileList, ref localRefAppdefList); } if (TaskFileService.Exists(ContentCodeFile)) { csFileList.Add(new TaskItem(ContentCodeFile)); } // Generate the Baml, code and /or locally-defined type related output items. GeneratedBamlFiles = (ITaskItem[])bamlFileList.ToArray(typeof(ITaskItem)); if (!SkipMarkupCompilation) { if (localRefAppdefList.Count > 0) { _localApplicationFile = (LocalReferenceFile)localRefAppdefList[0]; } if (localRefPageList.Count > 0) { _localMarkupPages = (LocalReferenceFile[])localRefPageList.ToArray(typeof(LocalReferenceFile)); } // // If MarkupCompilePass2 is required for Main assembly, there is no need to invoke MarkupCompilePass2 // for satellite assembly again. // if (_requirePass2ForMainAssembly) { _requirePass2ForSatelliteAssembly = false; } } // // Detect whether or not to ask Pass2 to do further handding for the InternalTypeHelper class. // // Only when all of below conditions are true, it requires Pass2 to further handling this wrapper class: // // 1. InternalTypeHelper file exists. // 2. It is a CleanBuild. // 3. No any xaml files which don't contain local types contains internal types from friend assembly. // 4. _requirePass2ForMainAssembly is true. // // If InternalTypeHelper File exists, Pass1 would always add it to the code file list, so that consequent task // can take it. If Pass2 determines that this wrapper class is not required, it can simply make an empty file. // But we still keep the list of generated code files. bool existsInternalTypeHelper = TaskFileService.Exists(InternalTypeHelperFile); if (IsCleanBuild && existsInternalTypeHelper && _requirePass2ForMainAssembly && !_hasInternals) { FurtherCheckInternalTypeHelper = true; } else { FurtherCheckInternalTypeHelper = false; } if (existsInternalTypeHelper) { csFileList.Add(new TaskItem(InternalTypeHelperFile)); } GeneratedCodeFiles = (ITaskItem[])csFileList.ToArray(typeof(ITaskItem)); // Generate the Localization Output files if (_localizationDirectives != MS.Internal.LocalizationDirectivesToLocFile.None) { GenerateOutputItemsForLocFiles(); } HandleCacheFiles(); // // Put all the generated files into one output Item so that it can be set to // FileWrites item in target file, this list of files will be cleaned up for // next clean build by msbuild. // The generated files should include Baml files, code files, localization files // and the cache files. // ArrayList allGeneratedFiles = new ArrayList( ); for (int i = 0; i < GeneratedBamlFiles.Length; i++) { allGeneratedFiles.Add(GeneratedBamlFiles[i]); } for (int i = 0; i < GeneratedCodeFiles.Length; i++) { allGeneratedFiles.Add(GeneratedCodeFiles[i]); } for (int i = 0; i < GeneratedLocalizationFiles.Length; i++) { allGeneratedFiles.Add(GeneratedLocalizationFiles[i]); } // Add the CompilerState cache file into the list allGeneratedFiles.Add(new TaskItem(CompilerState.CacheFilePath)); if (CompilerLocalReference.CacheFileExists()) { allGeneratedFiles.Add(new TaskItem(CompilerLocalReference.CacheFilePath)); } AllGeneratedFiles = (ITaskItem[])allGeneratedFiles.ToArray(typeof(ITaskItem)); } // // Both MarkupPage and MarkupResource have the similar code to generate // output baml, code file and /or locallyDefined xaml files. // so put all the common code in this private method. // // Inputs : // Xaml file items: PageMarkup or MarkupResource // LocallyDefined Xaml List (Generated by MarkupCompiler) // // Outputs: BamlFile List, // CodeFile List, // LocallyDefined Xaml List // private void GenerateOutputItemsForCompiledXamlFiles(ITaskItem[] inputXamlItemList, string[] inputLocalRefXamlFileList, ref ArrayList outputBamlFileList, ref ArrayList outputCodeFileList, ref ArrayList outputLocalRefXamlList) { // // For each input xaml file, check if the code and baml file are generated or not. // If baml or code files are generated, put them into the appropriate output file item list. // for (int i = 0; i < inputXamlItemList.Length; i++) { string genLangFilePath, bamlFile; GetGeneratedFiles(inputXamlItemList[i].ItemSpec, out genLangFilePath, out bamlFile); if (!String.IsNullOrEmpty(genLangFilePath) && outputCodeFileList != null) { TaskItem codeItem; codeItem = new TaskItem(); codeItem.ItemSpec = genLangFilePath; outputCodeFileList.Add(codeItem); Log.LogMessageFromResources(MessageImportance.Low, SRID.GeneratedCodeFile, codeItem.ItemSpec); } if (!String.IsNullOrEmpty(bamlFile)) { TaskItem bamlItem = GenerateBamlItem(bamlFile, inputXamlItemList[i]); // Add bamlItem to the output Baml List outputBamlFileList.Add(bamlItem); Log.LogMessageFromResources(MessageImportance.Low, SRID.GeneratedBamlFile, bamlItem.ItemSpec); } } // End of for { } loop. // // If the project contains local-type xaml files, put them into the right output item list here. // // // If MarkupCompilation is skipped, there is no need to check local-type xaml files. // if (!SkipMarkupCompilation && inputLocalRefXamlFileList != null && inputLocalRefXamlFileList.Length > 0) { for (int i = 0; i < inputLocalRefXamlFileList.Length; i++) { string fullLocalXamlFile = TaskHelper.CreateFullFilePath(inputLocalRefXamlFileList[i], SourceDir); LocalReferenceFile localFile = GenerateLocalTypeItem(fullLocalXamlFile, inputXamlItemList); if (localFile != null && outputLocalRefXamlList != null) { outputLocalRefXamlList.Add(localFile); } } } } // // Generate appropriate output file list for local-type xaml file. This information will be saved // into the .lref cache file so that the MarkupCompilePass2 can take it. // private LocalReferenceFile GenerateLocalTypeItem(string localTypeXamlFile, ITaskItem[] inputXamlItemList) { LocalReferenceFile localFile = null; bool isLocalizable = false; // // Check if the local-type xaml file is localizable or not. // for (int i = 0; i < inputXamlItemList.Length; i++) { ITaskItem inputXamlItem = inputXamlItemList[i]; string xamlInputFullPath = TaskHelper.CreateFullFilePath(inputXamlItem.ItemSpec, SourceDir); if (String.Compare(localTypeXamlFile, xamlInputFullPath, StringComparison.OrdinalIgnoreCase) == 0) { // // Got this file from the original XamlFile TaskItem list. // Check if this item is localizable or not and stop the search here. // isLocalizable = IsItemLocalizable(inputXamlItem); break; } } // // Generate the instance of LocalReferenceFile for this local-type xaml file. // localFile = new LocalReferenceFile(localTypeXamlFile, isLocalizable); if (isLocalizable) { _requirePass2ForSatelliteAssembly = true; } else { _requirePass2ForMainAssembly = true; } return localFile; } // // Generate a baml TaskItem for the given xmal file, and transfer the appropriate // source task item's custom attributes to the generated baml item if necessary. // The xaml file could be an application definition file, a Markup Page. // The bamlFile must exist before this method is called. private TaskItem GenerateBamlItem(string bamlFile, ITaskItem SourceItem) { TaskItem bamlItem; bamlItem = new TaskItem(); bamlItem.ItemSpec = bamlFile; // // Transfer some special custom attributes from source task item // to output item. // Such as transfer the Localizable attribute from a given .xaml file item // to the generated .baml file item. // // Normally MarkupPage and MarkupResource need to transfer their attributes. // But Application definition doesn't require this. if (SourceItem != null) { string[] listCarryOverAttribute = new string[] { "Localizable" }; for (int j = 0; j < listCarryOverAttribute.Length; j++) { string attributeValue; attributeValue = SourceItem.GetMetadata(listCarryOverAttribute[j]); if (attributeValue != null) { bamlItem.SetMetadata(listCarryOverAttribute[j], attributeValue); } } } return bamlItem; } // // Generate output item list for localization files. // private void GenerateOutputItemsForLocFiles() { ArrayList locFileItemList = new ArrayList(); TaskItem tiLoc; ITaskItem xamlItem; if (ApplicationMarkup != null && ApplicationMarkup.Length > 0 && ApplicationMarkup[0] != null) { tiLoc = ProcessLocFileForXamlItem(ApplicationMarkup[0]); if (tiLoc != null) { // Add this LocItem to the locFileItemList locFileItemList.Add(tiLoc); } } if (PageMarkup != null) { for (int i = 0; i < PageMarkup.Length; i++) { xamlItem = PageMarkup[i]; tiLoc = ProcessLocFileForXamlItem(xamlItem); if (tiLoc != null) { // Add this LocItem to the locFileItemList locFileItemList.Add(tiLoc); } } } // Generate the Output TaskItem List GeneratedLocalizationFiles = (ITaskItem[])locFileItemList.ToArray(typeof(ITaskItem)); } // // General method to handle an input xaml file item for Localization. // // If the XamlFile is localizable, generate a TaskItem for LocFile. // If the XamlFile is not localizable, and if the .loc file is generated, delelet it // so that it won't affec the incremental build next time. // private TaskItem ProcessLocFileForXamlItem(ITaskItem xamlItem) { TaskItem tiLoc = null; string tempDir = SourceDir; // Just for calling GetResolvedFilePath, the value is not used here. // Get a relative file path for the passed .xaml file string xamlRelativeFilePath = GetResolvedFilePath(xamlItem.ItemSpec, ref tempDir); string locFile; // Change the extension from .xaml to .loc locFile = Path.ChangeExtension(xamlRelativeFilePath, SharedStrings.LocExtension); // the .loc file is at OutputPath + relative Path. locFile = OutputPath + locFile; if (TaskFileService.Exists(locFile)) { // // Per discussion with Globalization team: // // Globalization requests to collect .loc file for a baml file // no matter the baml is in main assembly or satelliate assembly. // // The localization tool can localize the baml from the main assembly as well. // // Generate a TaskItem to include .loc file // The item is going to add to the output LocFile list tiLoc = new TaskItem(locFile); } return tiLoc; } // // Check if the given TaskItem localizable. // private bool IsItemLocalizable(ITaskItem ti) { bool bIsLocalizable; if (String.IsNullOrEmpty(UICulture)) { // if UICulture is not set, all baml files are not localizable. // The Localizable metadate value is ignored for this case. bIsLocalizable = false; } else { string strLocalizable; // if UICulture is set, by default all the baml files are localizable unless // an explicit value "false" is set to Localizable metadata. bIsLocalizable = true; strLocalizable = ti.GetMetadata(SharedStrings.Localizable); if (strLocalizable != null && String.Compare(strLocalizable, "false", StringComparison.OrdinalIgnoreCase) == 0) { bIsLocalizable = false; } } return bIsLocalizable; } // // Cleanup the cache files. // It could happen if build error occurs. // private void CleanupCacheFiles() { CompilerState.CleanupCache(); CompilerLocalReference.CleanupCache(); } // // A central place to update cache files based on current build status MarkupCompiler result. // // This method should be called after the markupcompiler is done or skipped. // private void HandleCacheFiles() { // Update the CompilerState file based on new project setting, no matter MarkupCompiler is skipped or not. CompilerState.SaveStateInformation(this); if ( (CompilerAnalyzer.AnalyzeResult & ( RecompileCategory.PagesWithLocalType | RecompileCategory.ModifiedPages )) != RecompileCategory.NoRecompile) { // The modified xaml files and all the local-type xaml files should be recompiled, depends on the // MarkupCompiler return, it will keep or delete the cache file for local type xaml files. if (_requirePass2ForMainAssembly || _requirePass2ForSatelliteAssembly) { CompilerLocalReference.SaveCacheInformation(this); } else { CompilerLocalReference.CleanupCache(); } } // if build doesn't handle the local-ref xaml files, (it implies not handling the modified xaml files either), // such as the build handles only for Application (HIB change) and Content files changes, or the markup compilation // is skipped, ( NoRecompile). // // For this scenario, if .lref file exists, it should still be kept. // } #endregion Private Methods //----------------------------------------------------- // // Private Properties // //----------------------------------------------------- #region Private Properties //// The root directory for the applicaiton project. // private string SourceDir { get { return _sourceDir; } } private IncrementalCompileAnalyzer CompilerAnalyzer { get { return _compilerAnalyzer; } } // // If no input file is modified, Markup compilation will be skipped. // But the code still generates the correct output item lists. // private bool SkipMarkupCompilation { get { return CompilerAnalyzer.AnalyzeResult == RecompileCategory.NoRecompile; } } private string ContentCodeFile { get { return OutputPath + AssemblyName + SharedStrings.ContentFile + (TaskFileService.IsRealBuild? SharedStrings.GeneratedExtension : SharedStrings.IntellisenseGeneratedExtension) + LanguageSourceExtension; } } // // Whether this is a clean build or not // private bool IsCleanBuild { get { return _isCleanBuild; } } #endregion Private Properties //----------------------------------------------------- // // Private Fields // //------------------------------------------------------ #region Private Fields private string _language; private string _languageSourceExtension = string.Empty; private ITaskItem [] _pagemarkupFiles; private ITaskItem [] _contentFiles; private ITaskItem [] _references; private bool _xamlDebuggingInformation = false; private string _outputType; private string _assemblyName; private string _assemblyVersion; private string _assemblyPublicKeyToken; private string _rootNamespace = String.Empty; private ITaskItem [] _applicationMarkup; private ITaskItem[] _splashScreen; private bool _alwaysCompileMarkupFilesInSeparateDomain = true; private string[] _assembliesGeneratedDuringBuild; private string[] _knownReferencePaths; private string _sourceDir; private string _outputDir; private ITaskItem[] _extraBuildControlFiles; private string _uiCulture = String.Empty; private string _applicationFile = String.Empty; private bool _isApplicationTarget = false; private string _hostInBrowser = String.Empty; private LocalizationDirectivesToLocFile _localizationDirectives; private ITaskItem [] _generatedCodeFiles; private ITaskItem [] _generatedBamlFiles; private ITaskItem [] _generatedLocalizationFiles; private ITaskItem [] _allGeneratedFiles = null; private string _localXamlApplication; private string[] _localXamlPages; private bool _hasInternals = false; private int _nErrors; private string _defineConstants = String.Empty; private ITaskItem[] _sourceCodeFiles; private string _pageMarkupCache = String.Empty; private string _contentFilesCache = String.Empty; private string _sourceCodeFilesCache = String.Empty; private string _referencesCache = String.Empty; private LocalReferenceFile _localApplicationFile = null; private LocalReferenceFile[] _localMarkupPages = null; private bool _requirePass2ForMainAssembly = false; private bool _requirePass2ForSatelliteAssembly = false; private bool _furtherCheckInternalTypeHelper = false; private CompilerState _compilerState; private CompilerLocalReference _compilerLocalRefCache; private IncrementalCompileAnalyzer _compilerAnalyzer; private ITaskFileService _taskFileService; private bool _isCleanBuild = true; // Indicates whether this is a cleanbuild or incremental build. #region const string private const string UnknownErrorID = "MC1000"; #endregion const string #endregion Private Fields } #endregion MarkupCompilePass1 Task class } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- Classification.cs
- RadialGradientBrush.cs
- Type.cs
- Evaluator.cs
- COM2ICategorizePropertiesHandler.cs
- TemplateParser.cs
- ToolStripDropDownItem.cs
- QilStrConcat.cs
- DataBoundLiteralControl.cs
- LinearQuaternionKeyFrame.cs
- PhysicalFontFamily.cs
- GPRECT.cs
- GenerateScriptTypeAttribute.cs
- ListViewSortEventArgs.cs
- SafeMemoryMappedViewHandle.cs
- Parameter.cs
- SoapDocumentMethodAttribute.cs
- KnownBoxes.cs
- TreeView.cs
- ValidatorCompatibilityHelper.cs
- FrameworkReadOnlyPropertyMetadata.cs
- ChildrenQuery.cs
- SectionXmlInfo.cs
- Timer.cs
- DisplayNameAttribute.cs
- DataControlButton.cs
- TypeBrowser.xaml.cs
- SettingsPropertyWrongTypeException.cs
- ByteStack.cs
- GeneralTransform.cs
- EventMetadata.cs
- Configuration.cs
- InvalidEnumArgumentException.cs
- cookiecollection.cs
- OrderedDictionary.cs
- StoreItemCollection.cs
- ZoneMembershipCondition.cs
- CompModSwitches.cs
- ApplicationId.cs
- ButtonBaseDesigner.cs
- RuntimeResourceSet.cs
- GeneralEndpointIdentity.cs
- Stack.cs
- RTLAwareMessageBox.cs
- CompilationLock.cs
- processwaithandle.cs
- ValidationHelper.cs
- TextContainerHelper.cs
- MessagingActivityHelper.cs
- IUnknownConstantAttribute.cs
- CodeExporter.cs
- ToolTipService.cs
- SimpleType.cs
- PropertyConverter.cs
- SmiRequestExecutor.cs
- MulticastNotSupportedException.cs
- OdbcConnectionFactory.cs
- RoleGroup.cs
- MSG.cs
- Decoder.cs
- SortKey.cs
- XmlIlVisitor.cs
- IndexObject.cs
- TdsValueSetter.cs
- WebPartEditVerb.cs
- HandledMouseEvent.cs
- BinaryFormatterWriter.cs
- unsafenativemethodstextservices.cs
- HttpServerVarsCollection.cs
- PrintDialog.cs
- TypeForwardedFromAttribute.cs
- ValidationHelpers.cs
- CheckedListBox.cs
- ItemCollection.cs
- CqlIdentifiers.cs
- FontWeights.cs
- OracleFactory.cs
- XmlSerializationGeneratedCode.cs
- TypeElement.cs
- WebEventTraceProvider.cs
- SoapMessage.cs
- PageContentCollection.cs
- BitmapMetadataBlob.cs
- Paragraph.cs
- Geometry.cs
- WebPartDeleteVerb.cs
- Configuration.cs
- CodeDOMProvider.cs
- IisTraceWebEventProvider.cs
- ChannelManagerBase.cs
- x509utils.cs
- HostExecutionContextManager.cs
- FixedSOMContainer.cs
- DoubleAnimationClockResource.cs
- EncodingInfo.cs
- JoinTreeNode.cs
- NamedServiceModelExtensionCollectionElement.cs
- CredentialCache.cs
- HttpRawResponse.cs
- RNGCryptoServiceProvider.cs