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?
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://learn.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
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/
Related
ImageLoader.cpp // ERROR:E3344 module file mapping for 'SafeReleaseM' is invalid
import SafeReleaseM;
import <wincodec.h>;
import <d2d1.h>;
class ImageLoader{};
SafeReleaseM.ixx
export module SafeReleaseM;
export template <class T> void SafeRelease(T** type)
{
if (*type)
{
(*type)->Release();
*type = NULL;
}
}
I've set the standard to the latest C++ standard and C standard, added my source folder to module dependency directory, enabled scanning for modules.
In my head, this is a very basic test of modules, am I doing something wrong? I'm new to S.O, so if i should add additional settings information, please do tell.
EDIT: I am using Visual Studio 2022 Community (msvc)
EDIT #2: In a separate project, a similar approach worked exporting a template function. Perhaps there is an issue with my project configuration.
Creating a new project and pasting the same code in worked.
Not sure what gave Visual Studio file mapping issues, but what i did differently was in a new project, I created the files through the solution explorer window. - Error might've been dependency/configuration related. Or caused by an update.
I have quite a complex project with many build variants and custom source sets. I have recently integrated the NDK and noticed something strange. Nothing is broken, everything seems to be working as it should. I'm thinking its a bug with Android Studio, unless something is wrong in the gradle config.
I added the following to my app/build.gradle
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
ndkVersion "22.0.6917172"
I then noticed that the directories within the "Project" pane of Android Studio were then displaying as if they were packages. It also looked as if every variant was being processed as well even though I am setting to be ignored.
This is what the directories looked like before
And this is what they look like now
The bigger issue is that custom source sets for build variants were being included at the app/src/ level with just the kotlin directory?
These are configured in the app/build.gradle like this example.
android {
...
sourceSets {
padoq.java.srcDirs += "src/standardTileHandler/kotlin"
}
...
}
padoq.java.srcDirs += nonHsdSource
Before, in project view, these appeared as the directory name with the packages inside, not with the kotlin directory at the root. Here is what it looked like before:
For completeness, I am ignoring certain build variants by setting the variant to be ignored in the root build.gradle's subprojects block:
subprojects {
afterEvaluate { project ->
if (project.hasProperty("android")) {
def androidProperty = project["android"]
if (androidProperty.hasProperty("flavorDimensionList")) {
def flavorDimensions = androidProperty["flavorDimensionList"]
if (flavorDimensions != null && flavorDimensions.contains("bopad")) {
androidProperty.invokeMethod("variantFilter", { variant ->
def names = variant.flavors*.name
// if names does not contain a variant that I want to build right now
setIgnore(true)
})
}
}
}
}
}
I'm trying to create a small application that will be able to communicate with the AWS IoT service. Since I want it to be fairly small and I wanted to try something new, I decided to go for Kotlin Native. I quickly noticed that AWS has released their C++ library that allows you to easily connect to the AWS IoT service (https://github.com/aws/aws-iot-device-sdk-cpp/tree/release) I downloaded it and even managed to compile with MinGW (yes, I'm on Windows). I noticed that it generated a bunch of *.o files. I reckon this is now the right time to import it to my Kotlin Native project. My build.gradle file for now looks completely standard
plugins {
id 'kotlin-multiplatform' version '1.3.11'
}
repositories {
mavenCentral()
}
kotlin {
targets {
// For ARM, preset should be changed to presets.iosArm32 or presets.iosArm64
// For Linux, preset should be changed to e.g. presets.linuxX64
// For MacOS, preset should be changed to e.g. presets.macosX64
fromPreset(presets.mingwX64, 'mingw')
configure([mingw]) {
// Comment to generate Kotlin/Native library (KLIB) instead of executable file:
compilations.main.outputKinds('EXECUTABLE')
// Change to specify fully qualified name of your application's entry point:
compilations.main.entryPoint = 'sample.main'
}
}
sourceSets {
// Note: To enable common source sets please comment out 'kotlin.import.noCommonSourceSets' property
// in gradle.properties file and re-import your project in IDE.
mingwMain {
}
mingwTest {
}
}
}
task runProgram {
def buildType = 'release' // Change to 'debug' to run application with debug symbols.
dependsOn "link${buildType.capitalize()}ExecutableMingw"
doLast {
def programFile = kotlin.targets.mingw.compilations.main.getBinary('EXECUTABLE', buildType)
exec {
executable programFile
args ''
}
}
}
for some reason I cannot find any examples as to how to add my freshly complied dependency. Normally when you code C++ you have to specify the path to Include directory and the Lib directory separately. AFAIK this is not something that gradle provides out of the box. How can I import this dependency then? Or perhaps there's some centralised repository I could simply pull such dependency from, like in pretty much every other programming language that is still used nowadays? At least this specific library doesn't seem to be available on NuGet :/
Kotlin/Native is not[1] interoperable with C++ at this moment. You can however create C wrapper for any C++ library and it's functions from Kotlin/Native[2].
When using multiplatform gradle plugin you can define native interop with this syntax:
kotlin {
linuxX64 { // Replace with a target you need.
compilations.main {
cinterops {
myInterop {
// Def-file describing the native API.
// The default path is src/nativeInterop/cinterop/<interop-name>.def
defFile project.file("def-file.def")
// Package to place the Kotlin API generated.
packageName 'org.sample'
// Options to be passed to compiler by cinterop tool.
compilerOpts '-Ipath/to/headers'
// Directories for header search (an analogue of the -I<path> compiler option).
includeDirs.allHeaders("path1", "path2")
// Additional directories to search headers listed in the 'headerFilter' def-file option.
// -headerFilterAdditionalSearchPrefix command line option analogue.
includeDirs.headerFilterOnly("path1", "path2")
// A shortcut for includeDirs.allHeaders.
includeDirs("include/directory", "another/directory")
}
anotherInterop { /* ... */ }
}
}
}
}
If you only define the interop name the plugin will look for .def file[3] in src/nativeInterop/cinterop/ directory and use it (in this case src/nativeInterop/cinterop/myInterop.def).
kotlin {
linuxX64 {
compilations.main {
cinterops {
myInterop {
}
}
}
}
}
The .def files[3] contains information about the library you are trying to use and typically look like this.
headers = png.h
headerFilter = png.h
package = png
More information about cinterop: https://kotlinlang.org/docs/reference/native/c_interop.html
More information about multiplatform projects: https://kotlinlang.org/docs/reference/building-mpp-with-gradle.html
I know there is this question:
How can XUnit be configured to show just the method name in the Visual Studio 2015 Test Explorer?
I tried both the solution using XML and the JSON file but the name in Text Explorer Window is still the full name with the class. I want to display the method name only as its hard to read the fully qualified names.
Its stated on this site that you can configure using XML
Configuring xUnit.net with XML
but I can't make the effect I'm expecting happen. I've restarted VS 2017 after adding an app.config file in the test project, but still nothing. Is it different for VS 2017?
I had the same issue. I'm doing a project in VS2017 using .NET Standard and solved it by following these steps:
In your tests project, create a file named xunit.runner.json
Add the following to the file: { "methodDisplay" : "method" }
In the Solution Explorer, right-click on xunit.runner.json and select "Properties". Set Copy to Output Directory to "Copy Always".
Taken from this comment.
W. Hampson answer is perfect, but just to inform about other possibility - use DisplayName attribute.
[Fact(DisplayName = "Just simple check")]
public void Check()
{
Assert.NotNull(_operation);
}
I've been trying to figure out a proper way of leveraging the information already present in a solution file of a rather big c++ code base.
The problem I'm trying to solve is calling an external script on some of the project files within the solution, but observing the already present dependencies specified in the solution and single project files.
I've successfully called said (python) script by adding a custom target to one of my project files and using msbuild with the /t:{TargetName} command on the vcxproj file.
I could now add this target to every project file that needs to call this script and afterwards call msbuild for each of them in the correct order, however this defeats the purpose of leveraging the dependencies known by the solution.
Calling the solution with the custom target does however not work (as seen by other stackoverflow questions like this: Invoke Custom MSBuild Target on Solution File).
On the other hand, since I want to be able to ONLY call the script target and not being dependent on also calling some Build command, I cannot use the proposed workarounds in some of those answers of adding a Post or PreBuild target.
Is there any other way of using the dependencies without having to go the route of msbuild and custom targets, or is there an other workaround that could serve my purpose?
Is there any other way of using the dependencies without having to go the route of msbuild and custom targets, or is there an other workaround that could serve my purpose?
You can build the sln programmatically, Here is a console APP with c# for your reference.
using Microsoft.Build.Construction;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Framework;
using Microsoft.Build.Logging;
using System;
namespace LoadAllProject
{
class Program
{
static void Main(string[] args)
{
ILogger logger = new ConsoleLogger();
string solutionPath = #"D:\Project\Msbuild\CppApp5\CppApp5.sln";
var solutionFile = SolutionFile.Parse(solutionPath);
foreach (var item in solutionFile.ProjectsInOrder)
{
Project project = ProjectCollection.GlobalProjectCollection.LoadProject(item.AbsolutePath);
project.SetGlobalProperty("Configuration", "Debug");
if (project.GetPropertyValue("RootNamespace") == "CppApp5")
{
project.Build(new[] { "Build", "Yourcustomtarget" }, new[] { logger });
}
else
{
project.Build(new[] { "Build" }, new[] { logger });
}
}
Console.ReadKey();
}
}
}