예제 #1
0
        /// <summary>
        /// Gathers toolset data from the registry and configuration file, if any.
        /// </summary>
        private static string ReadAllToolsetsNative
        (
            Dictionary <string, Toolset> toolsets,
#if FEATURE_WIN32_REGISTRY
            ToolsetRegistryReader registryReader,
#endif
#if FEATURE_SYSTEM_CONFIGURATION
            ToolsetConfigurationReader configurationReader,
#endif
            PropertyDictionary <ProjectPropertyInstance> environmentProperties,
            PropertyDictionary <ProjectPropertyInstance> globalProperties,
            ToolsetDefinitionLocations locations
        )
        {
            var initialProperties =
                new PropertyDictionary <ProjectPropertyInstance>(environmentProperties);

            initialProperties.ImportProperties(globalProperties);

            // The ordering here is important because the configuration file should have greater precedence
            // than the registry, and we do a check and don't read in the new toolset if there's already one.
            string defaultToolsVersionFromConfiguration         = null;
            string overrideTasksPathFromConfiguration           = null;
            string defaultOverrideToolsVersionFromConfiguration = null;

#if FEATURE_SYSTEM_CONFIGURATION
            if ((locations & ToolsetDefinitionLocations.ConfigurationFile) == ToolsetDefinitionLocations.ConfigurationFile)
            {
                if (configurationReader == null)
                {
                    configurationReader = new ToolsetConfigurationReader(environmentProperties, globalProperties);
                }

                // Accumulation of properties is okay in the config file because it's deterministically ordered
                defaultToolsVersionFromConfiguration = configurationReader.ReadToolsets(toolsets, globalProperties,
                                                                                        initialProperties, true /* accumulate properties */, out overrideTasksPathFromConfiguration,
                                                                                        out defaultOverrideToolsVersionFromConfiguration);
            }
#endif

            string defaultToolsVersionFromRegistry         = null;
            string overrideTasksPathFromRegistry           = null;
            string defaultOverrideToolsVersionFromRegistry = null;

            if ((locations & ToolsetDefinitionLocations.Registry) == ToolsetDefinitionLocations.Registry)
            {
#if FEATURE_WIN32_REGISTRY
                if (NativeMethodsShared.IsWindows || registryReader != null)
                {
                    // If we haven't been provided a registry reader (i.e. unit tests), create one
                    registryReader = registryReader ?? new ToolsetRegistryReader(environmentProperties, globalProperties);

                    // We do not accumulate properties when reading them from the registry, because the order
                    // in which values are returned to us is essentially random: so we disallow one property
                    // in the registry to refer to another also in the registry
                    defaultToolsVersionFromRegistry = registryReader.ReadToolsets(toolsets, globalProperties,
                                                                                  initialProperties, false /* do not accumulate properties */, out overrideTasksPathFromRegistry,
                                                                                  out defaultOverrideToolsVersionFromRegistry);
                }
                else
#endif
                {
                    var currentDir = BuildEnvironmentHelper.Instance.CurrentMSBuildToolsDirectory.TrimEnd(Path.DirectorySeparatorChar);
                    var props      = new PropertyDictionary <ProjectPropertyInstance>();

                    var libraryPath = NativeMethodsShared.FrameworkBasePath;

                    if (!string.IsNullOrEmpty(libraryPath))
                    {
                        // The 4.0 toolset is installed in the framework directory
                        var v4Dir =
                            FrameworkLocationHelper.GetPathToDotNetFrameworkV40(DotNetFrameworkArchitecture.Current);
                        if (v4Dir != null && !toolsets.ContainsKey("4.0"))
                        {
                            // Create standard properties. On Mono they are well known
                            var buildProperties =
                                CreateStandardProperties(globalProperties, "4.0", libraryPath, v4Dir);

                            toolsets.Add(
                                "4.0",
                                new Toolset(
                                    "4.0",
                                    v4Dir,
                                    buildProperties,
                                    environmentProperties,
                                    globalProperties,
                                    null,
                                    currentDir,
                                    string.Empty));
                        }

                        // Other toolsets are installed in the xbuild directory
                        var xbuildToolsetsDir = Path.Combine(libraryPath, $"xbuild{Path.DirectorySeparatorChar}");
                        if (FileSystems.Default.DirectoryExists(xbuildToolsetsDir))
                        {
                            var r = new Regex(Regex.Escape(xbuildToolsetsDir) + @"\d+\.\d+");
                            foreach (var d in Directory.GetDirectories(xbuildToolsetsDir).Where(d => r.IsMatch(d)))
                            {
                                var version = Path.GetFileName(d);
                                var binPath = Path.Combine(d, "bin");
                                if (toolsets.ContainsKey(version))
                                {
                                    continue;
                                }

                                if (NativeMethodsShared.IsMono && Version.TryParse(version, out Version parsedVersion) && parsedVersion.Major > 14)
                                {
                                    continue;
                                }

                                // Create standard properties. On Mono they are well known
                                var buildProperties =
                                    CreateStandardProperties(globalProperties, version, xbuildToolsetsDir, binPath);

                                toolsets.Add(
                                    version,
                                    new Toolset(
                                        version,
                                        binPath,
                                        buildProperties,
                                        environmentProperties,
                                        globalProperties,
                                        null,
                                        currentDir,
                                        string.Empty));
                            }
                        }
                    }
                    if (!toolsets.ContainsKey(MSBuildConstants.CurrentToolsVersion))
                    {
                        toolsets.Add(
                            MSBuildConstants.CurrentToolsVersion,
                            new Toolset(
                                MSBuildConstants.CurrentToolsVersion,
                                currentDir,
                                props,
                                new PropertyDictionary <ProjectPropertyInstance>(),
                                currentDir,
                                string.Empty));
                    }
                }
            }

            // The 2.0 .NET Framework installer did not write a ToolsVersion key for itself in the registry.
            // The 3.5 installer writes one for 2.0, but 3.5 might not be installed.
            // The 4.0 and subsequent installers can't keep writing the 2.0 one, because (a) it causes SxS issues and (b) we
            // don't want it unless 2.0 is installed.
            // So if the 2.0 framework is actually installed, we're reading the registry, and either the registry or the config
            // file have not already created the 2.0 toolset, mock up a fake one.
            if (((locations & ToolsetDefinitionLocations.Registry) != 0) && !toolsets.ContainsKey("2.0") &&
                FrameworkLocationHelper.PathToDotNetFrameworkV20 != null)
            {
                var synthetic20Toolset = new Toolset(
                    "2.0",
                    FrameworkLocationHelper.PathToDotNetFrameworkV20,
                    environmentProperties,
                    globalProperties,
                    null /* 2.0 did not have override tasks */,
                    null /* 2.0 did not have a default override toolsversion */);
                toolsets.Add("2.0", synthetic20Toolset);
            }

            string defaultToolsVersionFromLocal         = null;
            string overrideTasksPathFromLocal           = null;
            string defaultOverrideToolsVersionFromLocal = null;

            if ((locations & ToolsetDefinitionLocations.Local) == ToolsetDefinitionLocations.Local)
            {
                var localReader = new ToolsetLocalReader(environmentProperties, globalProperties);

                defaultToolsVersionFromLocal = localReader.ReadToolsets(
                    toolsets,
                    globalProperties,
                    initialProperties,
                    false /* accumulate properties */,
                    out overrideTasksPathFromLocal,
                    out defaultOverrideToolsVersionFromLocal);
            }

            // We'll use the path from the configuration file if it was specified, otherwise we'll try
            // the one from the registry.  It's possible (and valid) that neither the configuration file
            // nor the registry specify a override in which case we'll just return null.
            var overrideTasksPath = overrideTasksPathFromConfiguration ?? overrideTasksPathFromRegistry ?? overrideTasksPathFromLocal;

            // We'll use the path from the configuration file if it was specified, otherwise we'll try
            // the one from the registry.  It's possible (and valid) that neither the configuration file
            // nor the registry specify a override in which case we'll just return null.
            var defaultOverrideToolsVersion = defaultOverrideToolsVersionFromConfiguration
                                              ?? defaultOverrideToolsVersionFromRegistry
                                              ?? defaultOverrideToolsVersionFromLocal;

            // We'll use the default from the configuration file if it was specified, otherwise we'll try
            // the one from the registry.  It's possible (and valid) that neither the configuration file
            // nor the registry specify a default, in which case we'll just return null.
            var defaultToolsVersion = defaultToolsVersionFromConfiguration ?? defaultToolsVersionFromRegistry ?? defaultToolsVersionFromLocal;

            // If we got a default version from the registry or config file, and it
            // actually exists, fine.
            // Otherwise we have to come up with one.
            if (defaultToolsVersion != null && toolsets.ContainsKey(defaultToolsVersion))
            {
                return(defaultToolsVersion);
            }
            // We're going to choose a hard coded default tools version of 2.0.
            defaultToolsVersion = Constants.defaultToolsVersion;

            // But don't overwrite any existing tools path for this default we're choosing.
            if (toolsets.ContainsKey(Constants.defaultToolsVersion))
            {
                return(defaultToolsVersion);
            }
            // There's no tools path already for 2.0, so use the path to the v2.0 .NET Framework.
            // If an old-fashioned caller sets BinPath property, or passed a BinPath to the constructor,
            // that will overwrite what we're setting here.
            ErrorUtilities.VerifyThrow(
                Constants.defaultToolsVersion == "2.0",
                "Getting 2.0 FX path so default should be 2.0");
            var pathToFramework = FrameworkLocationHelper.PathToDotNetFrameworkV20;

            // We could not find the default toolsversion because it was not installed on the machine. Fallback to the
            // one we expect to always be there when running msbuild 4.0.
            if (pathToFramework == null)
            {
                pathToFramework     = FrameworkLocationHelper.PathToDotNetFrameworkV40;
                defaultToolsVersion = Constants.defaultFallbackToolsVersion;
            }

            // Again don't overwrite any existing tools path for this default we're choosing.
            if (toolsets.ContainsKey(defaultToolsVersion))
            {
                return(defaultToolsVersion);
            }
            var defaultToolset = new Toolset(
                defaultToolsVersion,
                pathToFramework,
                environmentProperties,
                globalProperties,
                overrideTasksPath,
                defaultOverrideToolsVersion);
            toolsets.Add(defaultToolsVersion, defaultToolset);

            return(defaultToolsVersion);
        }
예제 #2
0
        /// <summary>
        /// Gathers toolset data from the registry + configuration file + VS setup API, if any.
        /// NOTE:  this method is internal for unit testing purposes only.
        /// </summary>
        internal static string ReadAllToolsets
        (
            Dictionary <string, Toolset> toolsets,
#if FEATURE_WIN32_REGISTRY
            ToolsetRegistryReader registryReader,
#endif
#if FEATURE_SYSTEM_CONFIGURATION
            ToolsetConfigurationReader configurationReader,
#endif
            PropertyDictionary <ProjectPropertyInstance> environmentProperties,
            PropertyDictionary <ProjectPropertyInstance> globalProperties,
            ToolsetDefinitionLocations locations
        )
        {
            var defaultVer = ReadAllToolsetsNative
                             (
                toolsets,

#if FEATURE_WIN32_REGISTRY
                registryReader,
#endif
#if FEATURE_SYSTEM_CONFIGURATION
                configurationReader,
#endif
                environmentProperties,
                globalProperties,
                locations
                             );

            const string _CUR       = MSBuildConstants.CurrentToolsVersion;
            string       currentDir = BuildEnvironmentHelper.Instance.CurrentMSBuildToolsDirectory.TrimEnd(Path.DirectorySeparatorChar);

            foreach (var vs in VisualStudioLocationHelper.GetInstances())
            {
                string vstr    = $"{vs.Version.Major}.0";
                string toolbin = FileUtilities.CombinePaths
                                 (
                    vs.Path,
                    "MSBuild",
                    vs.Version.Major >= 16 ? _CUR : vstr,
                    "Bin"
                                 );

                if (IntPtr.Size == 8)
                {
                    string toolbin64 = FileUtilities.CombinePaths(toolbin, "amd64");
                    if (Directory.Exists(toolbin64))
                    {
                        toolbin = toolbin64;
                    }
                }

                if (!toolsets.ContainsKey(vstr))
                {
                    // For Mono
                    var buildProperties = CreateStandardProperties(globalProperties, vstr, NativeMethodsShared.FrameworkBasePath, toolbin);

                    toolsets.Add
                    (
                        vstr,
                        new Toolset
                        (
                            vstr,
                            toolbin,
                            buildProperties,
                            environmentProperties,
                            globalProperties,
                            null,
                            currentDir,
                            string.Empty
                        )
                    );
                }
            }

            if (!toolsets.ContainsKey(_CUR))
            {
                var actual = toolsets.GetMostActual();
                if (actual != null)
                {
                    toolsets.Add(_CUR, actual);
                }
                else
                {
                    toolsets.Add
                    (
                        _CUR,
                        new Toolset
                        (
                            _CUR,
                            currentDir,
                            new PropertyDictionary <ProjectPropertyInstance>(),
                            new PropertyDictionary <ProjectPropertyInstance>(),
                            currentDir,
                            string.Empty
                        )
                    );
                }
            }

            return(defaultVer);
        }