2 // GetReferenceAssemblyPaths.cs: Gets the target framework directories corresponding
3 // to target framework moniker
6 // Ankit Jain (jankit@novell.com)
8 // Copyright 2011 Novell, Inc (http://www.novell.com)
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using Microsoft.Build.Framework;
32 using System.Reflection;
34 using System.Collections.Generic;
36 using Mono.XBuild.Utilities;
39 namespace Microsoft.Build.Tasks
41 public class GetReferenceAssemblyPaths : TaskExtension
43 static string framework_base_path;
44 static string PathSeparatorAsString = Path.PathSeparator.ToString ();
45 const string MacOSXExternalXBuildDir = "/Library/Frameworks/Mono.framework/External/xbuild-frameworks";
47 public GetReferenceAssemblyPaths ()
51 public override bool Execute ()
53 FrameworkMoniker moniker = null;
54 if (!TryParseTargetFrameworkMoniker (TargetFrameworkMoniker, out moniker))
57 var framework = GetFrameworkDirectoriesForMoniker (moniker);
58 if (framework == null) {
59 Log.LogWarning ("Unable to find framework corresponding to the target framework moniker '{0}'. " +
60 "Framework assembly references will be resolved from the GAC, which might not be " +
61 "the intended behavior.", TargetFrameworkMoniker);
62 if (moniker.Identifier.Equals (".NETPortable"))
63 return CheckPclReferenceAssemblies (moniker);
67 ReferenceAssemblyPaths = FullFrameworkReferenceAssemblyPaths = framework.Directories;
68 TargetFrameworkMonikerDisplayName = framework.DisplayName;
73 bool CheckPclReferenceAssemblies (FrameworkMoniker moniker)
75 // Check for a supported profile
76 var check = new FrameworkMoniker (".NETPortable", "v4.0", "Profile24");
77 if (GetFrameworkDirectoriesForMoniker (check) != null)
78 Log.LogError ("Unsupported PCL Profile '{0}'.", moniker);
80 Log.LogError ("PCL Reference Assemblies not installed.");
84 Framework GetFrameworkDirectoriesForMoniker (FrameworkMoniker moniker)
86 string dirs = String.Join (PathSeparatorAsString, new string [] {
87 Environment.GetEnvironmentVariable ("XBUILD_FRAMEWORK_FOLDERS_PATH") ?? String.Empty,
88 MSBuildUtils.RunningOnMac ? MacOSXExternalXBuildDir : String.Empty,
90 DefaultFrameworksBasePath });
92 string [] paths = dirs.Split (new char [] {Path.PathSeparator}, StringSplitOptions.RemoveEmptyEntries);
93 foreach (string path in paths) {
94 var framework = GetFrameworkDirectoriesForMoniker (moniker, path);
95 if (framework != null)
102 //@base_path must be absolute
103 Framework GetFrameworkDirectoriesForMoniker (FrameworkMoniker moniker, string base_path)
105 if (String.IsNullOrEmpty (base_path)) {
106 Log.LogMessage (MessageImportance.Low, "Invalid *empty* base path, ignoring. " + Environment.StackTrace);
110 Log.LogMessage (MessageImportance.Low, "Looking for framework '{0}' in root path '{1}'",
112 string framework_path = Path.Combine (base_path, Path.Combine (moniker.Identifier, moniker.Version));
113 if (!String.IsNullOrEmpty (moniker.Profile))
114 framework_path = Path.Combine (framework_path, "Profile", moniker.Profile);
116 string redistlist_dir = Path.Combine (framework_path, "RedistList");
117 string framework_list = Path.Combine (redistlist_dir, "FrameworkList.xml");
118 if (!File.Exists (framework_list)) {
119 Log.LogMessage (MessageImportance.Low,
120 "Unable to find framework definition file '{0}' for Target Framework Moniker '{1}'",
121 framework_list, moniker);
125 Log.LogMessage (MessageImportance.Low, "Found framework definition list '{0}' for framework '{1}'",
126 framework_list, moniker);
127 XmlReader xr = XmlReader.Create (framework_list);
130 if (xr.LocalName != "FileList") {
131 Log.LogMessage (MessageImportance.Low, "Invalid frameworklist '{0}', expected a 'FileList' root element.",
136 var framework = new Framework ();
137 framework.DisplayName = xr.GetAttribute ("Name");
138 string framework_dir = xr.GetAttribute ("TargetFrameworkDirectory");
139 if (String.IsNullOrEmpty (framework_dir))
140 framework_dir = Path.Combine (redistlist_dir, "..");
142 framework_dir = Path.Combine (redistlist_dir, framework_dir);
144 var directories = new List<string> ();
146 //MSBuild has a trailing slash on this value
147 directories.Add (MSBuildUtils.FromMSBuildPath (framework_dir) + Path.DirectorySeparatorChar);
149 string include = xr.GetAttribute ("IncludeFramework");
150 if (!String.IsNullOrEmpty (include)) {
151 var included_framework = GetFrameworkDirectoriesForMoniker (new FrameworkMoniker (moniker.Identifier, include, null));
153 if (included_framework != null && included_framework.Directories != null)
154 directories.AddRange (included_framework.Directories);
157 framework.Directories = directories.ToArray ();
160 } catch (XmlException xe) {
161 Log.LogWarning ("Error reading framework definition file '{0}': {1}", framework_list, xe.Message);
162 Log.LogMessage (MessageImportance.Low, "Error reading framework definition file '{0}': {1}", framework_list,
167 ((IDisposable)xr).Dispose ();
171 bool TryParseTargetFrameworkMoniker (string moniker_literal, out FrameworkMoniker moniker)
174 if (String.IsNullOrEmpty (moniker_literal))
175 throw new ArgumentException ("Empty moniker string");
177 string [] parts = moniker_literal.Split (new char [] {','}, StringSplitOptions.RemoveEmptyEntries);
179 if (parts.Length < 2 || parts.Length > 3) {
180 LogInvalidMonikerError (null, moniker_literal);
184 string identifier = parts [0];
185 string version = null;
186 string profile = null;
188 if (!parts [1].StartsWith ("Version=")) {
189 LogInvalidMonikerError ("Invalid framework name", moniker_literal);
193 version = parts [1].Substring (8);
194 if (String.IsNullOrEmpty (version)) {
195 LogInvalidMonikerError ("Invalid framework version", moniker_literal);
199 if (parts.Length > 2) {
200 if (!parts [2].StartsWith ("Profile=")) {
201 LogInvalidMonikerError ("Invalid framework version", moniker_literal);
205 profile = parts [2].Substring (8);
206 if (String.IsNullOrEmpty (profile)) {
207 LogInvalidMonikerError ("Invalid framework profile", moniker_literal);
212 moniker = new FrameworkMoniker (identifier, version, profile);
216 void LogInvalidMonikerError (string msg, string moniker_literal)
219 Log.LogError ("{0} in the Target Framework Moniker '{1}'. Expected format: 'Identifier,Version=<version>[,Profile=<profile>]'. " +
220 "It should have either 2 or 3 comma separated components.", msg, moniker_literal);
222 Log.LogError ("Invalid Target Framework Moniker '{0}'. Expected format: 'Identifier,Version=<version>[,Profile=<profile>]'. " +
223 "It should have either 2 or 3 comma separated components.", moniker_literal);
226 public string TargetFrameworkMoniker { get; set; }
228 public string RootPath { get; set; }
230 public bool BypassFrameworkInstallChecks { get; set; }
233 public string TargetFrameworkMonikerDisplayName { get; set; }
236 public string[] ReferenceAssemblyPaths { get; private set; }
239 public string[] FullFrameworkReferenceAssemblyPaths { get; private set; }
241 static string DefaultFrameworksBasePath {
243 if (framework_base_path == null)
244 framework_base_path = Path.Combine (Path.GetDirectoryName (typeof (object).Assembly.Location),
245 Path.Combine ("..", "xbuild-frameworks"));
246 return framework_base_path;
251 class FrameworkMoniker {
252 public readonly string Identifier;
253 public readonly string Version;
254 public readonly string Profile;
256 public FrameworkMoniker (string identifier, string version, string profile)
258 this.Identifier = identifier;
259 this.Version = version;
260 this.Profile = profile;
263 public override string ToString ()
265 if (String.IsNullOrEmpty (Profile))
266 return String.Format ("{0},Version={1}", Identifier, Version);
267 return String.Format ("{0},Version={1},Profile={2}", Identifier, Version, Profile);
272 public string[] Directories;
273 public string DisplayName;