Add support for resolving pkg-config provided assemblies.
[mono.git] / mcs / class / Microsoft.Build.Tasks / Microsoft.Build.Tasks / ResolveAssemblyReference.cs
1 //
2 // ResolveAssemblyReference.cs: Searches for assembly files.
3 //
4 // Author:
5 //   Marek Sieradzki (marek.sieradzki@gmail.com)
6 //   Ankit Jain (jankit@novell.com)
7 // 
8 // (C) 2006 Marek Sieradzki
9 // Copyright 2009 Novell, Inc (http://www.novell.com)
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 //
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 //
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
30 #if NET_2_0
31
32 using System;
33 using System.Collections.Generic;
34 using System.Globalization;
35 using System.IO;
36 using System.Linq;
37 using System.Reflection;
38 using System.Security;
39 using Microsoft.Build.Framework;
40 using Microsoft.Build.Utilities;
41
42 namespace Microsoft.Build.Tasks {
43         public class ResolveAssemblyReference : TaskExtension {
44         
45                 bool            autoUnify;
46                 ITaskItem[]     assemblyFiles;
47                 ITaskItem[]     assemblies;
48                 string          appConfigFile;
49                 string[]        allowedAssemblyExtensions;
50                 string[]        allowedRelatedFileExtensions;
51                 string[]        candidateAssemblyFiles;
52                 ITaskItem[]     copyLocalFiles;
53                 ITaskItem[]     filesWritten;
54                 bool            findDependencies;
55                 bool            findRelatedFiles;
56                 bool            findSatellites;
57                 bool            findSerializationAssemblies;
58                 string[]        installedAssemblyTables;
59                 ITaskItem[]     relatedFiles;
60                 ITaskItem[]     resolvedDependencyFiles;
61                 ITaskItem[]     resolvedFiles;
62                 ITaskItem[]     satelliteFiles;
63                 ITaskItem[]     scatterFiles;
64                 string[]        searchPaths;
65                 ITaskItem[]     serializationAssemblyFiles;
66                 bool            silent;
67                 string          stateFile;
68                 ITaskItem[]     suggestedRedirects;
69                 string[]        targetFrameworkDirectories;
70                 string          targetProcessorArchitecture;
71                 static string []        default_assembly_extensions;
72
73                 AssemblyResolver        assembly_resolver;
74                 List<string> dependency_search_paths;
75                 Dictionary<string, ResolvedReference> assemblyNameToResolvedRef;
76                 Dictionary<string, ITaskItem>   tempSatelliteFiles, tempRelatedFiles,
77                         tempResolvedDepFiles, tempCopyLocalFiles;
78                 List<ITaskItem> tempResolvedFiles;
79                 List<PrimaryReference> primaryReferences;
80                 Dictionary<string, string> alreadyScannedAssemblyNames;
81
82                 //FIXME: construct and use a graph of the dependencies, useful across projects
83
84                 static ResolveAssemblyReference ()
85                 {
86                         default_assembly_extensions = new string [] { ".dll", ".exe" };
87                 }
88
89                 public ResolveAssemblyReference ()
90                 {
91                         assembly_resolver = new AssemblyResolver ();
92                 }
93
94                 //FIXME: make this reusable
95                 public override bool Execute ()
96                 {
97                         assembly_resolver.Log = Log;
98                         tempResolvedFiles = new List<ITaskItem> ();
99                         tempCopyLocalFiles = new Dictionary<string, ITaskItem> ();
100                         tempSatelliteFiles = new Dictionary<string, ITaskItem> ();
101                         tempRelatedFiles = new Dictionary<string, ITaskItem> ();
102                         tempResolvedDepFiles = new Dictionary<string, ITaskItem> ();
103
104                         primaryReferences = new List<PrimaryReference> ();
105                         assemblyNameToResolvedRef = new Dictionary<string, ResolvedReference> ();
106
107                         foreach (ITaskItem item in assemblies) {
108                                 if (!String.IsNullOrEmpty (item.GetMetadata ("SubType"))) {
109                                         Log.LogWarning ("Reference '{0}' has non-empty SubType. Ignoring.", item.ItemSpec);
110                                         continue;
111                                 }
112
113                                 Log.LogMessage (MessageImportance.Low, "Primary Reference {0}", item.ItemSpec);
114                                 ResolvedReference resolved_ref = ResolveReference (item, searchPaths);
115                                 if (resolved_ref == null) {
116                                         Log.LogWarning ("\tReference '{0}' not resolved", item.ItemSpec);
117                                         Log.LogMessage ("{0}", assembly_resolver.SearchLogger.ToString ());
118                                 } else {
119                                         Log.LogMessage (MessageImportance.Low,
120                                                         "\tReference {0} resolved to {1}. CopyLocal = {2}",
121                                                         item.ItemSpec, resolved_ref.TaskItem,
122                                                         resolved_ref.TaskItem.GetMetadata ("CopyLocal"));
123
124                                         Log.LogMessage (MessageImportance.Low,
125                                                         "\tReference found at search path {0}",
126                                                         resolved_ref.FoundInSearchPathAsString);
127
128                                         if (TryAddNewReference (tempResolvedFiles, resolved_ref) &&
129                                                 !IsFromGacOrTargetFramework (resolved_ref)) {
130                                                 primaryReferences.Add (new PrimaryReference (
131                                                                 resolved_ref.TaskItem,
132                                                                 resolved_ref.TaskItem.GetMetadata ("CopyLocal")));
133                                         }
134                                 }
135                         }
136
137                         ResolveAssemblyFiles ();
138
139                         alreadyScannedAssemblyNames = new Dictionary<string, string> ();
140
141                         // the first element is place holder for parent assembly's dir
142                         dependency_search_paths = new List<string> () { String.Empty };
143                         dependency_search_paths.AddRange (searchPaths);
144
145                         // resolve dependencies
146                         foreach (PrimaryReference pref in primaryReferences)
147                                 ResolveAssemblyFileDependencies (pref.TaskItem, pref.ParentCopyLocal);
148
149                         resolvedFiles = tempResolvedFiles.ToArray ();
150                         copyLocalFiles = tempCopyLocalFiles.Values.ToArray ();
151                         satelliteFiles = tempSatelliteFiles.Values.ToArray ();
152                         relatedFiles = tempRelatedFiles.Values.ToArray ();
153                         resolvedDependencyFiles = tempResolvedDepFiles.Values.ToArray ();
154
155                         tempResolvedFiles.Clear ();
156                         tempCopyLocalFiles.Clear ();
157                         tempSatelliteFiles.Clear ();
158                         tempRelatedFiles.Clear ();
159                         tempResolvedDepFiles.Clear ();
160                         alreadyScannedAssemblyNames.Clear ();
161                         primaryReferences.Clear ();
162                         assemblyNameToResolvedRef.Clear ();
163                         dependency_search_paths = null;
164
165                         return true;
166                 }
167
168                 // Use @search_paths to resolve the reference
169                 ResolvedReference ResolveReference (ITaskItem item, IEnumerable<string> search_paths)
170                 {
171                         ResolvedReference resolved = null;
172                         bool specific_version;
173
174                         assembly_resolver.ResetSearchLogger ();
175
176                         if (!TryGetSpecificVersionValue (item, out specific_version))
177                                 return null;
178
179                         foreach (string spath in search_paths) {
180                                 assembly_resolver.SearchLogger.WriteLine ("For searchpath {0}", spath);
181
182                                 if (String.Compare (spath, "{HintPathFromItem}") == 0) {
183                                         resolved = assembly_resolver.ResolveHintPathReference (item, specific_version);
184                                 } else if (String.Compare (spath, "{TargetFrameworkDirectory}") == 0) {
185                                         foreach (string fpath in targetFrameworkDirectories) {
186                                                 resolved = assembly_resolver.FindInTargetFramework (item,
187                                                                 fpath, specific_version);
188                                                 if (resolved != null)
189                                                         break;
190                                         }
191                                 } else if (String.Compare (spath, "{GAC}") == 0) {
192                                         resolved = assembly_resolver.ResolveGacReference (item, specific_version);
193                                 } else if (String.Compare (spath, "{RawFileName}") == 0) {
194                                         //FIXME: identify assembly names, as extract the name, and try with that?
195                                         AssemblyName aname = assembly_resolver.GetAssemblyNameFromFile (item.ItemSpec);
196                                         if (aname != null)
197                                                 resolved = assembly_resolver.GetResolvedReference (item, item.ItemSpec, aname, true,
198                                                                 SearchPath.RawFileName);
199                                 } else if (String.Compare (spath, "{CandidateAssemblyFiles}") == 0) {
200                                         assembly_resolver.SearchLogger.WriteLine (
201                                                         "Warning: {CandidateAssemblyFiles} not supported currently");
202                                 } else if (String.Compare (spath, "{PkgConfig}") == 0) {
203                                         resolved = assembly_resolver.ResolvePkgConfigReference (item, specific_version);
204                                 } else {
205                                         resolved = assembly_resolver.FindInDirectory (
206                                                         item, spath,
207                                                         allowedAssemblyExtensions ?? default_assembly_extensions);
208                                 }
209
210                                 if (resolved != null)
211                                         break;
212                         }
213
214                         if (resolved != null)
215                                 SetCopyLocal (resolved.TaskItem, resolved.CopyLocal.ToString ());
216
217                         return resolved;
218                 }
219
220                 bool TryGetSpecificVersionValue (ITaskItem item, out bool specific_version)
221                 {
222                         specific_version = true;
223                         string value = item.GetMetadata ("SpecificVersion");
224                         if (String.IsNullOrEmpty (value)) {
225                                 AssemblyName name = new AssemblyName (item.ItemSpec);
226                                 // If SpecificVersion is not specified, then
227                                 // it is true if the Include is a strong name else false
228                                 specific_version = assembly_resolver.IsStrongNamed (name);
229                                 return true;
230                         }
231
232                         if (Boolean.TryParse (value, out specific_version))
233                                 return true;
234
235                         Log.LogError ("Item '{0}' has attribute SpecificVersion with invalid value '{1}' " +
236                                         "which could not be converted to a boolean.", item.ItemSpec, value);
237                         return false;
238                 }
239
240                 //FIXME: Consider CandidateAssemblyFiles also here
241                 void ResolveAssemblyFiles ()
242                 {
243                         foreach (ITaskItem item in assemblyFiles) {
244                                 assembly_resolver.ResetSearchLogger ();
245
246                                 if (!File.Exists (item.ItemSpec)) {
247                                         Log.LogMessage (MessageImportance.Low,
248                                                         "Primary Reference from AssemblyFiles {0}, file not found. Ignoring",
249                                                         item.ItemSpec);
250                                         continue;
251                                 }
252
253                                 Log.LogMessage (MessageImportance.Low, "Primary Reference from AssemblyFiles {0}", item.ItemSpec);
254                                 string copy_local;
255
256                                 AssemblyName aname = assembly_resolver.GetAssemblyNameFromFile (item.ItemSpec);
257                                 if (aname == null) {
258                                         Log.LogWarning ("\tReference '{0}' not resolved", item.ItemSpec);
259                                         Log.LogMessage ("{0}", assembly_resolver.SearchLogger.ToString ());
260                                         continue;
261                                 }
262
263                                 ResolvedReference rr = assembly_resolver.GetResolvedReference (item, item.ItemSpec, aname, true,
264                                                 SearchPath.RawFileName);
265                                 copy_local = rr.CopyLocal.ToString ();
266
267                                 if (!TryAddNewReference (tempResolvedFiles, rr))
268                                         // already resolved
269                                         continue;
270
271                                 SetCopyLocal (rr.TaskItem, copy_local);
272
273                                 FindAndAddRelatedFiles (item.ItemSpec, copy_local);
274                                 FindAndAddSatellites (item.ItemSpec, copy_local);
275
276                                 if (FindDependencies && !IsFromGacOrTargetFramework (rr))
277                                         primaryReferences.Add (new PrimaryReference (item, copy_local));
278                         }
279                 }
280
281                 // Tries to resolve assemblies referenced by @item
282                 // Skips gac references
283                 // @item : filename
284                 void ResolveAssemblyFileDependencies (ITaskItem item, string parent_copy_local)
285                 {
286                         Queue<string> dependencies = new Queue<string> ();
287                         dependencies.Enqueue (item.ItemSpec);
288
289                         while (dependencies.Count > 0) {
290                                 string filename = Path.GetFullPath (dependencies.Dequeue ());
291                                 Assembly asm = Assembly.ReflectionOnlyLoadFrom (filename);
292                                 if (alreadyScannedAssemblyNames.ContainsKey (asm.FullName))
293                                         continue;
294
295                                 // set the 1st search path to this ref's base path
296                                 // Will be used for resolving the dependencies
297                                 dependency_search_paths [0] = Path.GetDirectoryName (filename);
298
299                                 foreach (AssemblyName aname in asm.GetReferencedAssemblies ()) {
300                                         if (alreadyScannedAssemblyNames.ContainsKey (aname.FullName))
301                                                 continue;
302
303                                         ResolvedReference resolved_ref = ResolveDependencyByAssemblyName (
304                                                         aname, asm.FullName, parent_copy_local);
305
306                                         if (resolved_ref != null && !IsFromGacOrTargetFramework (resolved_ref))
307                                                 dependencies.Enqueue (resolved_ref.TaskItem.ItemSpec);
308                                 }
309                                 alreadyScannedAssemblyNames.Add (asm.FullName, String.Empty);
310                         }
311                 }
312
313                 // Resolves by looking dependency_search_paths
314                 // which is dir of parent reference file, and
315                 // SearchPaths
316                 ResolvedReference ResolveDependencyByAssemblyName (AssemblyName aname, string parent_asm_name,
317                                 string parent_copy_local)
318                 {
319                         // This will check for compatible assembly name/version
320                         ResolvedReference resolved_ref;
321                         if (TryGetResolvedReferenceByAssemblyName (aname, false, out resolved_ref))
322                                 return resolved_ref;
323
324                         Log.LogMessage (MessageImportance.Low, "Dependency {0}", aname);
325                         Log.LogMessage (MessageImportance.Low, "\tRequired by {0}", parent_asm_name);
326
327                         ITaskItem item = new TaskItem (aname.FullName);
328                         item.SetMetadata ("SpecificVersion", "false");
329                         resolved_ref = ResolveReference (item, dependency_search_paths);
330
331                         string copy_local = "false";
332                         if (resolved_ref != null) {
333                                 Log.LogMessage (MessageImportance.Low, "\tReference {0} resolved to {1}.",
334                                         aname, resolved_ref.TaskItem.ItemSpec);
335
336                                 Log.LogMessage (MessageImportance.Low,
337                                                 "\tReference found at search path {0}",
338                                                 resolved_ref.FoundInSearchPathAsString);
339
340                                 if (resolved_ref.FoundInSearchPath == SearchPath.Directory) {
341                                         // override CopyLocal with parent's val
342                                         resolved_ref.TaskItem.SetMetadata ("CopyLocal", parent_copy_local);
343
344                                         Log.LogMessage (MessageImportance.Low,
345                                                         "\tThis is CopyLocal {0} as parent item has this value",
346                                                         copy_local);
347
348                                         if (TryAddNewReference (tempResolvedFiles, resolved_ref)) {
349                                                 FindAndAddRelatedFiles (resolved_ref.TaskItem.ItemSpec, parent_copy_local);
350                                                 FindAndAddSatellites (resolved_ref.TaskItem.ItemSpec, parent_copy_local);
351                                         }
352                                 } else {
353                                         //gac or tgtfmwk
354                                         Log.LogMessage (MessageImportance.Low,
355                                                         "\tThis is CopyLocal {0} as it is in the gac," +
356                                                         "target framework directory or provided by a package.",
357                                                         copy_local);
358
359                                         TryAddNewReference (tempResolvedFiles, resolved_ref);
360                                 }
361                         } else {
362                                 Log.LogWarning ("\tReference '{0}' not resolved", aname);
363                                 Log.LogMessage ("{0}", assembly_resolver.SearchLogger.ToString ());
364                         }
365
366                         return resolved_ref;
367                 }
368
369                 void FindAndAddRelatedFiles (string filename, string parent_copy_local)
370                 {
371                         if (!findRelatedFiles || allowedRelatedFileExtensions == null)
372                                 return;
373
374                         foreach (string ext in allowedRelatedFileExtensions) {
375                                 string rfile = filename + ext;
376                                 if (File.Exists (rfile)) {
377                                         ITaskItem item = new TaskItem (rfile);
378                                         SetCopyLocal (item, parent_copy_local);
379
380                                         tempRelatedFiles.AddUniqueFile (item);
381                                 }
382                         }
383                 }
384
385                 void FindAndAddSatellites (string filename, string parent_copy_local)
386                 {
387                         if (!FindSatellites)
388                                 return;
389
390                         string basepath = Path.GetDirectoryName (filename);
391                         string resource = String.Format ("{0}{1}{2}",
392                                         Path.GetFileNameWithoutExtension (filename),
393                                         ".resources",
394                                         Path.GetExtension (filename));
395
396                         string dir_sep = Path.DirectorySeparatorChar.ToString ();
397                         foreach (string dir in Directory.GetDirectories (basepath)) {
398                                 string culture = Path.GetFileName (dir);
399                                 if (!CultureNamesTable.ContainsKey (culture))
400                                         continue;
401
402                                 string res_path = Path.Combine (dir, resource);
403                                 if (File.Exists (res_path)) {
404                                         ITaskItem item = new TaskItem (res_path);
405                                         SetCopyLocal (item, parent_copy_local);
406                                         item.SetMetadata ("DestinationSubdirectory", culture + dir_sep);
407                                         tempSatelliteFiles.AddUniqueFile (item);
408                                 }
409                         }
410                 }
411
412                 // returns true is it was new
413                 bool TryAddNewReference (List<ITaskItem> file_list, ResolvedReference key_ref)
414                 {
415                         ResolvedReference found_ref;
416                         if (!TryGetResolvedReferenceByAssemblyName (key_ref.AssemblyName, key_ref.IsPrimary, out found_ref)) {
417                                 assemblyNameToResolvedRef [key_ref.AssemblyName.Name] = key_ref;
418                                 file_list.Add (key_ref.TaskItem);
419
420                                 return true;
421                         }
422                         return false;
423                 }
424
425                 void SetCopyLocal (ITaskItem item, string copy_local)
426                 {
427                         item.SetMetadata ("CopyLocal", copy_local);
428
429                         // Assumed to be valid value
430                         if (Boolean.Parse (copy_local))
431                                 tempCopyLocalFiles.AddUniqueFile (item);
432                 }
433
434                 bool TryGetResolvedReferenceByAssemblyName (AssemblyName key_aname, bool is_primary, out ResolvedReference found_ref)
435                 {
436                         found_ref = null;
437                         // Match by just name
438                         if (!assemblyNameToResolvedRef.TryGetValue (key_aname.Name, out found_ref))
439                                 // not there
440                                 return false;
441
442                         // match for full name
443                         if (AssemblyResolver.AssemblyNamesCompatible (key_aname, found_ref.AssemblyName, true))
444                                 // exact match, so its already there, dont add anything
445                                 return true;
446
447                         // we have a name match, but version mismatch!
448                         assembly_resolver.SearchLogger.WriteLine ("A conflict was detected between '{0}' and '{1}'",
449                                         key_aname.FullName, found_ref.AssemblyName.FullName);
450
451                         if (is_primary == found_ref.IsPrimary) {
452                                 assembly_resolver.SearchLogger.WriteLine ("Unable to choose between the two. " +
453                                                 "Choosing '{0}' arbitrarily.", found_ref.AssemblyName.FullName);
454                                 return true;
455                         }
456
457                         // since all dependencies are processed after
458                         // all primary refererences, the one in the cache
459                         // has to be a primary
460                         // Prefer a primary reference over a dependency
461
462                         assembly_resolver.SearchLogger.WriteLine ("Choosing '{0}' as it is a primary reference.",
463                                         found_ref.AssemblyName.FullName);
464
465                         Log.LogWarning ("Found a conflict between : '{0}' and '{1}'. Using '{0}' reference.",
466                                         found_ref.AssemblyName.FullName,
467                                         key_aname.FullName);
468
469                         return true;
470                 }
471
472                 bool IsCopyLocal (ITaskItem item)
473                 {
474                         return Boolean.Parse (item.GetMetadata ("CopyLocal"));
475                 }
476
477                 bool IsFromTargetFramework (string filename)
478                 {
479                         foreach (string fpath in targetFrameworkDirectories)
480                                 if (filename.StartsWith (fpath))
481                                         return true;
482
483                         return false;
484                 }
485
486                 bool IsFromGacOrTargetFramework (ResolvedReference rr)
487                 {
488                         return rr.FoundInSearchPath == SearchPath.Gac ||
489                                 rr.FoundInSearchPath == SearchPath.TargetFrameworkDirectory;
490                 }
491
492                 public bool AutoUnify {
493                         get { return autoUnify; }
494                         set { autoUnify = value; }
495                 }
496                 
497                 public ITaskItem[] AssemblyFiles {
498                         get { return assemblyFiles; }
499                         set { assemblyFiles = value; }
500                 }
501                 
502                 public ITaskItem[] Assemblies {
503                         get { return assemblies; }
504                         set { assemblies = value; }
505                 }
506                 
507                 public string AppConfigFile {
508                         get { return appConfigFile; }
509                         set { appConfigFile = value; }
510                 }
511                 
512                 public string[] AllowedAssemblyExtensions {
513                         get { return allowedAssemblyExtensions; }
514                         set { allowedAssemblyExtensions = value; }
515                 }
516
517                 public string[] AllowedRelatedFileExtensions {
518                         get { return allowedRelatedFileExtensions; }
519                         set { allowedRelatedFileExtensions = value; }
520                 }
521                 
522                 public string[] CandidateAssemblyFiles {
523                         get { return candidateAssemblyFiles; }
524                         set { candidateAssemblyFiles = value; }
525                 }
526                 
527                 [Output]
528                 public ITaskItem[] CopyLocalFiles {
529                         get { return copyLocalFiles; }
530                 }
531                 
532                 [Output]
533                 public ITaskItem[] FilesWritten {
534                         get { return filesWritten; }
535                         set { filesWritten = value; }
536                 }
537                 
538                 public bool FindDependencies {
539                         get { return findDependencies; }
540                         set { findDependencies = value; }
541                 }
542                 
543                 public bool FindRelatedFiles {
544                         get { return findRelatedFiles; }
545                         set { findRelatedFiles = value; }
546                 }
547                 
548                 public bool FindSatellites {
549                         get { return findSatellites; }
550                         set { findSatellites = value; }
551                 }
552                 
553                 public bool FindSerializationAssemblies {
554                         get { return findSerializationAssemblies; }
555                         set { findSerializationAssemblies = value; }
556                 }
557                 
558                 public string[] InstalledAssemblyTables {
559                         get { return installedAssemblyTables; }
560                         set { installedAssemblyTables = value; }
561                 }
562                 
563                 [Output]
564                 public ITaskItem[] RelatedFiles {
565                         get { return relatedFiles; }
566                 }
567                 
568                 [Output]
569                 public ITaskItem[] ResolvedDependencyFiles {
570                         get { return resolvedDependencyFiles; }
571                 }
572                 
573                 [Output]
574                 public ITaskItem[] ResolvedFiles {
575                         get { return resolvedFiles; }
576                 }
577                 
578                 [Output]
579                 public ITaskItem[] SatelliteFiles {
580                         get { return satelliteFiles; }
581                 }
582                 
583                 [Output]
584                 public ITaskItem[] ScatterFiles {
585                         get { return scatterFiles; }
586                 }
587                 
588                 [Required]
589                 public string[] SearchPaths {
590                         get { return searchPaths; }
591                         set { searchPaths = value; }
592                 }
593                 
594                 [Output]
595                 public ITaskItem[] SerializationAssemblyFiles {
596                         get { return serializationAssemblyFiles; }
597                 }
598                 
599                 public bool Silent {
600                         get { return silent; }
601                         set { silent = value; }
602                 }
603                 
604                 public string StateFile {
605                         get { return stateFile; }
606                         set { stateFile = value; }
607                 }
608                 
609                 [Output]
610                 public ITaskItem[] SuggestedRedirects {
611                         get { return suggestedRedirects; }
612                 }
613                 
614                 public string[] TargetFrameworkDirectories {
615                         get { return targetFrameworkDirectories; }
616                         set { targetFrameworkDirectories = value; }
617                 }
618                 
619                 public string TargetProcessorArchitecture {
620                         get { return targetProcessorArchitecture; }
621                         set { targetProcessorArchitecture = value; }
622                 }
623
624                 static Dictionary<string, string> cultureNamesTable;
625                 static Dictionary<string, string> CultureNamesTable {
626                         get {
627                                 if (cultureNamesTable == null) {
628                                         cultureNamesTable = new Dictionary<string, string> ();
629                                         foreach (CultureInfo ci in CultureInfo.GetCultures (CultureTypes.AllCultures))
630                                                 cultureNamesTable [ci.Name] = ci.Name;
631                                 }
632
633                                 return cultureNamesTable;
634                         }
635                 }
636         }
637
638         static class ResolveAssemblyReferenceHelper {
639                 public static void AddUniqueFile (this Dictionary<string, ITaskItem> dic, ITaskItem item)
640                 {
641                         if (dic == null)
642                                 throw new ArgumentNullException ("dic");
643                         if (item == null)
644                                 throw new ArgumentNullException ("item");
645
646                         string fullpath = Path.GetFullPath (item.ItemSpec);
647                         if (!dic.ContainsKey (fullpath))
648                                 dic [fullpath] = item;
649                 }
650         }
651
652         struct PrimaryReference {
653                 public ITaskItem TaskItem;
654                 public string ParentCopyLocal;
655
656                 public PrimaryReference (ITaskItem item, string parent_copy_local)
657                 {
658                         TaskItem = item;
659                         ParentCopyLocal = parent_copy_local;
660                 }
661         }
662
663 }
664
665 #endif