Creating a cmake project with visual studio

2019-01-18 14:37发布

问题:

Visual Studio 2017 provides built-in support for handling CMake projects. The documentation mostly covers scenarios based on pre-existing cmake projects. But is there any support for creating a cmake project without having to fiddle with the CMakeLists.txt file?

回答1:

EDIT: VS2017 15.6 added an official New Project CMake Wizard

With version 15.6 came the feature of "Create CMake projects from the Add New Project dialog."

This creates a simple ninja based C++ "Hello CMake" project.

A Custom CMake Wizard

Your question and the lack of an existing Wizard inspired me to write one. It's a very basic setup and would most definitely benefit if people with more experience in writing Visual Studio extensions would contribute, but here it is:

https://github.com/FloriansGit/VSCMakeWizards

Edit: Latest VSIX installer is now also available for free on VS Marketplace

https://marketplace.visualstudio.com/items?itemName=oOFlorianOo.CMakeProjectWizards

The new "CMake Executable Template" will show up after a restart of your Visual Studio 2017 under "File/New/Project/Visual C++":

It generates the following files in the given folder and then uses "Open Folder" on it:

CMakeLists.txt
CMakeSettings.json
MyProject1.cpp 

Next Steps

Possible next steps would be to:

  • Add an interactive Wizard Dialog for some basic project/compiler settings
  • Add also an Item Wizard to be able to add source files to the CMakeLists.txt

I'm looking forward getting feedback on the basic idea. Please add any requests directly to:

https://github.com/FloriansGit/VSCMakeWizards/issues

The Code

And here is the Wizards basic/initial code as a reference:

WizardImplementationClass.cs

// Based on https://docs.microsoft.com/en-us/visualstudio/extensibility/how-to-use-wizards-with-project-templates
//      and https://stackoverflow.com/questions/3882764/issue-with-visual-studio-template-directory-creation

using System;
using System.IO;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using EnvDTE;
using Microsoft.VisualStudio.TemplateWizard;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using EnvDTE80;

namespace VSCMakeWizards
{
    public class WizardImplementation : IWizard
    {
        public void RunStarted(object automationObject,
            Dictionary<string, string> replacementsDictionary,
            WizardRunKind runKind, object[] customParams)
        {
            var destinationDir = replacementsDictionary["$destinationdirectory$"];
            var desiredNamespace = replacementsDictionary["$safeprojectname$"];
            var templatePath = Path.GetDirectoryName((string)customParams[0]);

            var dte = automationObject as DTE2;
            var solution = dte.Solution as EnvDTE100.Solution4;

            if (solution.IsOpen)
            {
                solution.Close();
            }

            File.Copy(Path.Combine(templatePath, "CMakeSettings.json"), Path.Combine(destinationDir, "CMakeSettings.json"));
            File.Copy(Path.Combine(templatePath, "main.cpp"), Path.Combine(destinationDir, desiredNamespace + ".cpp"));

            // see https://stackoverflow.com/questions/1231768/c-sharp-string-replace-with-dictionary
            Regex re = new Regex(@"(\$\w+\$)", RegexOptions.Compiled);
            string input = File.ReadAllText(Path.Combine(templatePath, "CMakeLists.txt"));
            string output = re.Replace(input, match => replacementsDictionary[match.Groups[1].Value]);

            File.WriteAllText(Path.Combine(destinationDir, "CMakeLists.txt"), output);

            var vsSolution = Package.GetGlobalService(typeof(SVsSolution)) as IVsSolution7;

            if (vsSolution != null)
            {
                vsSolution.OpenFolder(destinationDir);
            }

            throw new WizardCancelledException();
        }

        // This method is called before opening any item that   
        // has the OpenInEditor attribute.  
        public void BeforeOpeningFile(ProjectItem projectItem)
        {
        }

        public void ProjectFinishedGenerating(Project project)
        {
        }

        // This method is only called for item templates,  
        // not for project templates.  
        public void ProjectItemFinishedGenerating(ProjectItem
            projectItem)
        {
        }

        // This method is called after the project is created.  
        public void RunFinished()
        {
        }

        // This method is only called for item templates,  
        // not for project templates.  
        public bool ShouldAddProjectItem(string filePath)
        {
            return false;
        }
    }
}

Note: The WizardCancelledException is necessary, because Visual Studio otherwise would try to generate/open an actual solution. An "Open Folder" kind of project wizard is not yet supported (no SDK API for this).

References

  • Issue with visual studio template & directory creation
  • C# String replace with dictionary


回答2:

As far as I know, there is no Wizard to create a new CMake project, but it can be done by configuring a CMakeSettings.json file. https://blogs.msdn.microsoft.com/vcblog/2017/08/14/cmake-support-in-visual-studio-customizing-your-environment/