+ }
+
+ // Use @search_paths to resolve the reference
+ ResolvedReference ResolveReference (ITaskItem item, IEnumerable<string> search_paths, bool set_copy_local)
+ {
+ ResolvedReference resolved = null;
+ bool specific_version;
+
+ assembly_resolver.ResetSearchLogger ();
+
+ if (!TryGetSpecificVersionValue (item, out specific_version))
+ return null;
+
+ foreach (string spath in search_paths) {
+ assembly_resolver.LogSearchMessage ("For searchpath {0}", spath);
+
+ if (String.Compare (spath, "{HintPathFromItem}") == 0) {
+ resolved = assembly_resolver.ResolveHintPathReference (item, specific_version);
+ } else if (String.Compare (spath, "{TargetFrameworkDirectory}") == 0) {
+ if (targetFrameworkDirectories == null)
+ continue;
+ foreach (string fpath in targetFrameworkDirectories) {
+ resolved = assembly_resolver.FindInTargetFramework (item,
+ fpath, specific_version);
+ if (resolved != null)
+ break;
+ }
+ } else if (String.Compare (spath, "{GAC}") == 0) {
+ resolved = assembly_resolver.ResolveGacReference (item, specific_version);
+ } else if (String.Compare (spath, "{RawFileName}") == 0) {
+ //FIXME: identify assembly names, as extract the name, and try with that?
+ AssemblyName aname;
+ if (assembly_resolver.TryGetAssemblyNameFromFile (item.ItemSpec, out aname))
+ resolved = assembly_resolver.GetResolvedReference (item, item.ItemSpec, aname, true,
+ SearchPath.RawFileName);
+ } else if (String.Compare (spath, "{CandidateAssemblyFiles}") == 0) {
+ assembly_resolver.LogSearchMessage (
+ "Warning: {{CandidateAssemblyFiles}} not supported currently");
+ } else if (String.Compare (spath, "{PkgConfig}") == 0) {
+ resolved = assembly_resolver.ResolvePkgConfigReference (item, specific_version);
+ } else {
+ resolved = assembly_resolver.FindInDirectory (
+ item, spath,
+ allowedAssemblyExtensions ?? default_assembly_extensions,
+ specific_version);
+ }
+
+ if (resolved != null)
+ break;
+ }
+
+ if (resolved != null && set_copy_local)
+ SetCopyLocal (resolved.TaskItem, resolved.CopyLocal.ToString ());
+
+ return resolved;
+ }
+
+ bool TryGetSpecificVersionValue (ITaskItem item, out bool specific_version)
+ {
+ specific_version = true;
+ string value = item.GetMetadata ("SpecificVersion");
+ if (String.IsNullOrEmpty (value)) {
+ //AssemblyName name = new AssemblyName (item.ItemSpec);
+ // If SpecificVersion is not specified, then
+ // it is true if the Include is a strong name else false
+ //specific_version = assembly_resolver.IsStrongNamed (name);
+
+ // msbuild seems to just look for a ',' in the name :/
+ specific_version = item.ItemSpec.IndexOf (',') >= 0;
+ return true;
+ }
+
+ if (Boolean.TryParse (value, out specific_version))
+ return true;
+
+ Log.LogError ("Item '{0}' has attribute SpecificVersion with invalid value '{1}' " +
+ "which could not be converted to a boolean.", item.ItemSpec, value);
+ return false;
+ }
+
+ //FIXME: Consider CandidateAssemblyFiles also here
+ void ResolveAssemblyFiles ()
+ {
+ if (assemblyFiles == null)
+ return;
+
+ foreach (ITaskItem item in assemblyFiles) {
+ assembly_resolver.ResetSearchLogger ();
+
+ if (!File.Exists (item.ItemSpec)) {
+ LogWithPrecedingNewLine (MessageImportance.Low,
+ "Primary Reference from AssemblyFiles {0}, file not found. Ignoring",
+ item.ItemSpec);
+ continue;
+ }
+
+ LogWithPrecedingNewLine (MessageImportance.Low, "Primary Reference from AssemblyFiles {0}", item.ItemSpec);
+ string copy_local;
+
+ AssemblyName aname;
+ if (!assembly_resolver.TryGetAssemblyNameFromFile (item.ItemSpec, out aname)) {
+ Log.LogWarning ("Reference '{0}' not resolved", item.ItemSpec);
+ assembly_resolver.LogSearchLoggerMessages (MessageImportance.Normal);
+ continue;
+ }
+
+ if (Environment.GetEnvironmentVariable ("XBUILD_LOG_REFERENCE_RESOLVER") != null)
+ assembly_resolver.LogSearchLoggerMessages (MessageImportance.Low);
+
+ ResolvedReference rr = assembly_resolver.GetResolvedReference (item, item.ItemSpec, aname, true,
+ SearchPath.RawFileName);
+ copy_local = rr.CopyLocal.ToString ();
+
+ if (!TryAddNewReference (tempResolvedFiles, rr))
+ // already resolved
+ continue;
+
+ SetCopyLocal (rr.TaskItem, copy_local);
+
+ FindAndAddRelatedFiles (item.ItemSpec, copy_local);
+ FindAndAddSatellites (item.ItemSpec, copy_local);
+
+ if (FindDependencies && !IsFromGacOrTargetFramework (rr) &&
+ rr.FoundInSearchPath != SearchPath.PkgConfig)
+ primaryReferences.Add (new PrimaryReference (item, copy_local));
+ }
+ }
+
+ // Tries to resolve assemblies referenced by @item
+ // Skips gac references
+ // @item : filename
+ void ResolveAssemblyFileDependencies (ITaskItem item, string parent_copy_local)
+ {
+ Queue<string> dependencies = new Queue<string> ();
+ dependencies.Enqueue (item.ItemSpec);
+
+ while (dependencies.Count > 0) {
+ string filename = Path.GetFullPath (dependencies.Dequeue ());
+ Assembly asm = Assembly.ReflectionOnlyLoadFrom (filename);
+ if (alreadyScannedAssemblyNames.ContainsKey (asm.FullName))
+ continue;
+
+ // set the 1st search path to this ref's base path
+ // Will be used for resolving the dependencies
+ dependency_search_paths [0] = Path.GetDirectoryName (filename);
+
+ foreach (AssemblyName aname in asm.GetReferencedAssemblies ()) {
+ if (alreadyScannedAssemblyNames.ContainsKey (aname.FullName))
+ continue;
+
+ ResolvedReference resolved_ref = ResolveDependencyByAssemblyName (
+ aname, asm.FullName, parent_copy_local);
+
+ if (resolved_ref != null && !IsFromGacOrTargetFramework (resolved_ref)
+ && resolved_ref.FoundInSearchPath != SearchPath.PkgConfig)
+ dependencies.Enqueue (resolved_ref.TaskItem.ItemSpec);
+ }
+ alreadyScannedAssemblyNames.Add (asm.FullName, String.Empty);
+ }
+ }
+
+ // Resolves by looking dependency_search_paths
+ // which is dir of parent reference file, and
+ // SearchPaths
+ ResolvedReference ResolveDependencyByAssemblyName (AssemblyName aname, string parent_asm_name,
+ string parent_copy_local)
+ {
+ // This will check for compatible assembly name/version
+ ResolvedReference resolved_ref;
+ if (TryGetResolvedReferenceByAssemblyName (aname, false, out resolved_ref))
+ return resolved_ref;
+
+ LogWithPrecedingNewLine (MessageImportance.Low, "Dependency {0}", aname);
+ Log.LogMessage (MessageImportance.Low, "\tRequired by {0}", parent_asm_name);
+
+ ITaskItem item = new TaskItem (aname.FullName);
+ item.SetMetadata ("SpecificVersion", "false");
+ resolved_ref = ResolveReference (item, dependency_search_paths, false);
+
+ if (resolved_ref != null) {
+ if (Environment.GetEnvironmentVariable ("XBUILD_LOG_REFERENCE_RESOLVER") != null)
+ assembly_resolver.LogSearchLoggerMessages (MessageImportance.Low);
+
+ Log.LogMessage (MessageImportance.Low, "\tReference {0} resolved to {1}.",
+ aname, resolved_ref.TaskItem.ItemSpec);
+
+ Log.LogMessage (MessageImportance.Low,
+ "\tReference found at search path {0}",
+ resolved_ref.FoundInSearchPathAsString);
+
+ if (resolved_ref.FoundInSearchPath == SearchPath.Directory) {
+ // override CopyLocal with parent's val
+ SetCopyLocal (resolved_ref.TaskItem, parent_copy_local);
+
+ Log.LogMessage (MessageImportance.Low,
+ "\tThis is CopyLocal {0} as parent item has this value",
+ parent_copy_local);
+
+ if (TryAddNewReference (tempResolvedFiles, resolved_ref)) {
+ FindAndAddRelatedFiles (resolved_ref.TaskItem.ItemSpec, parent_copy_local);
+ FindAndAddSatellites (resolved_ref.TaskItem.ItemSpec, parent_copy_local);
+ }
+ } else {
+ //gac or tgtfmwk
+ Log.LogMessage (MessageImportance.Low,
+ "\tThis is CopyLocal false as it is in the gac," +
+ "target framework directory or provided by a package.");
+
+ TryAddNewReference (tempResolvedFiles, resolved_ref);
+ }
+ } else {
+ Log.LogWarning ("Reference '{0}' not resolved", aname);
+ assembly_resolver.LogSearchLoggerMessages (MessageImportance.Normal);
+ }
+
+ return resolved_ref;
+ }
+
+ void FindAndAddRelatedFiles (string filename, string parent_copy_local)
+ {
+ if (!findRelatedFiles || allowedRelatedFileExtensions == null)
+ return;
+
+ foreach (string ext in allowedRelatedFileExtensions) {
+ string rfile = filename + ext;
+ if (File.Exists (rfile)) {
+ ITaskItem item = new TaskItem (rfile);
+ SetCopyLocal (item, parent_copy_local);
+
+ tempRelatedFiles.AddUniqueFile (item);
+ }
+ }
+ }
+
+ void FindAndAddSatellites (string filename, string parent_copy_local)
+ {
+ if (!FindSatellites)
+ return;
+
+ string basepath = Path.GetDirectoryName (filename);
+ string resource = String.Format ("{0}{1}{2}",
+ Path.GetFileNameWithoutExtension (filename),
+ ".resources",
+ Path.GetExtension (filename));
+
+ string dir_sep = Path.DirectorySeparatorChar.ToString ();
+ foreach (string dir in Directory.GetDirectories (basepath)) {
+ string culture = Path.GetFileName (dir);
+ if (!CultureNamesTable.ContainsKey (culture))
+ continue;
+
+ string res_path = Path.Combine (dir, resource);
+ if (File.Exists (res_path)) {
+ ITaskItem item = new TaskItem (res_path);
+ SetCopyLocal (item, parent_copy_local);
+ item.SetMetadata ("DestinationSubdirectory", culture + dir_sep);
+ tempSatelliteFiles.AddUniqueFile (item);
+ }
+ }
+ }
+
+ // returns true is it was new
+ bool TryAddNewReference (List<ITaskItem> file_list, ResolvedReference key_ref)
+ {
+ ResolvedReference found_ref;
+ if (!TryGetResolvedReferenceByAssemblyName (key_ref.AssemblyName, key_ref.IsPrimary, out found_ref)) {
+ assemblyNameToResolvedRef [key_ref.AssemblyName.Name] = key_ref;
+ file_list.Add (key_ref.TaskItem);
+
+ return true;
+ }
+ return false;
+ }
+
+ void SetCopyLocal (ITaskItem item, string copy_local)
+ {
+ item.SetMetadata ("CopyLocal", copy_local);
+
+ // Assumed to be valid value
+ if (Boolean.Parse (copy_local))
+ tempCopyLocalFiles.AddUniqueFile (item);
+ }
+
+ bool TryGetResolvedReferenceByAssemblyName (AssemblyName key_aname, bool is_primary, out ResolvedReference found_ref)
+ {
+ found_ref = null;
+ // Match by just name
+ if (!assemblyNameToResolvedRef.TryGetValue (key_aname.Name, out found_ref))
+ // not there
+ return false;
+
+ // match for full name
+ if (AssemblyResolver.AssemblyNamesCompatible (key_aname, found_ref.AssemblyName, true, false))
+ // exact match, so its already there, dont add anything
+ return true;
+
+ // we have a name match, but version mismatch!
+ assembly_resolver.LogSearchMessage ("A conflict was detected between '{0}' and '{1}'",
+ key_aname.FullName, found_ref.AssemblyName.FullName);
+
+ if (is_primary == found_ref.IsPrimary) {
+ assembly_resolver.LogSearchMessage ("Unable to choose between the two. " +
+ "Choosing '{0}' arbitrarily.", found_ref.AssemblyName.FullName);
+ return true;
+ }
+
+ // since all dependencies are processed after
+ // all primary refererences, the one in the cache
+ // has to be a primary
+ // Prefer a primary reference over a dependency
+
+ assembly_resolver.LogSearchMessage ("Choosing '{0}' as it is a primary reference.",
+ found_ref.AssemblyName.FullName);
+
+ LogConflictWarning (found_ref.AssemblyName.FullName, key_aname.FullName);
+