2

I autogenerate a Visual Studio solution with CMake, the structure looks like this:

/src
  CMakeLists.txt
  SomeSource.cs
  /build       << contents of this folder generated by CMake
    GeneratedCode.cs
    MyProject.sln
    MyProjectNET.csharp
    <other files by CMake>

The problem is, when I open the solution in Visual Studio, the C# project contains everything in the /build folder, including output directories and so on. I have checked the .csproj file to see if CMake generated the project so that all those files are explicitly included, but that is not the case.

Now this would only be inconvenience. However, as you can see, I have GeneratedCode.cs in the /build directory. This code is generated by CMake. Since CMake knows it is part of the project, it explicitly adds a reference when generating MyProjectNET.csharp. The behavior I observe now is that when opening GeneratedCode.cs in Visual Studio, the editor underlines almost everything with red, saying it is an „Ambiguous reference“ and listing the same class located in GeneratedCode.cs twice as possible source. This makes it basically impossible to discover actual errors in the code.

Interestingly, compiling the code works. I only get a warning that the compiler got the same file twice as input. I nevertheless want to get rid of this behavior to work with the code more productively.

So, the reason for my problem is that my project contains all files in the /build folder automatically, and then the GeneratedCode.cs file explicitly, which confuses Visual Studio. Why are all the files in my project? I assume that is not normal behavior because I don't see it happening for C++ projects and for another C# project that is not generated by CMake. I assume CMake generated some strange setting in the .csproj file but I can't find anything that seems to have any relation to my problem in the project file. What setting would cause this behavior?

Edit: VS version is 2017, version 15.9.9. In the hope it fits, here's the actual project file:

<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk" DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup Label="Globals">
    <ProjectGuid>{0AE1D52A-C2A2-35E1-914D-92101FC2A02F}</ProjectGuid>
    <WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
    <Keyword>Win32Proj</Keyword>
    <Platform>x64</Platform>
    <ProjectName>libheroes.NET</ProjectName>
    <VCProjectUpgraderObjectName>NoUpgrade</VCProjectUpgraderObjectName>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
    <Authors>Felix Krause</Authors>
    <LangVersion>7.2</LangVersion>
    <PackageId>Libheroes.NET</PackageId>
    <RootNamespace>Heroes</RootNamespace>
    <Version>0.1.0</Version>
    <OutputType>Library</OutputType>
    <AppDesignerFolder>Properties</AppDesignerFolder>
  <TargetFramework>netstandard2.0</TargetFramework></PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
    <DebugSymbols>true</DebugSymbols>
    <DefineDebug>true</DefineDebug>
    <OutputPath>D:\Projects\libheroes\bindings\csharp\cmake-vs\Debug\</OutputPath>
    <PlatformToolset>v141</PlatformToolset>
    <AssemblyName>libheroes.NET</AssemblyName>
    <AdditionalOptions>/langversion:7.2</AdditionalOptions>
    <DebugType>full</DebugType>
    <DefineConstants>DEBUG</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <Optimize>false</Optimize>
    <WarningLevel>3</WarningLevel>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
    <OutputPath>D:\Projects\libheroes\bindings\csharp\cmake-vs\Release\</OutputPath>
    <PlatformToolset>v141</PlatformToolset>
    <AssemblyName>libheroes.NET</AssemblyName>
    <AdditionalOptions>/langversion:7.2</AdditionalOptions>
    <DebugType>none</DebugType>
    <DefineConstants />
    <ErrorReport>queue</ErrorReport>
    <Optimize>true</Optimize>
    <WarningLevel>1</WarningLevel>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='MinSizeRel|x64'" Label="Configuration">
    <OutputPath>D:\Projects\libheroes\bindings\csharp\cmake-vs\MinSizeRel\</OutputPath>
    <PlatformToolset>v141</PlatformToolset>
    <AssemblyName>libheroes.NET</AssemblyName>
    <AdditionalOptions>/langversion:7.2</AdditionalOptions>
    <DebugType>none</DebugType>
    <DefineConstants />
    <Optimize>true</Optimize>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|x64'" Label="Configuration">
    <DebugSymbols>true</DebugSymbols>
    <DefineDebug>true</DefineDebug>
    <OutputPath>D:\Projects\libheroes\bindings\csharp\cmake-vs\RelWithDebInfo\</OutputPath>
    <PlatformToolset>v141</PlatformToolset>
    <AssemblyName>libheroes.NET</AssemblyName>
    <AdditionalOptions>/langversion:7.2</AdditionalOptions>
    <DebugType>full</DebugType>
    <DefineConstants />
    <Optimize>false</Optimize>
  </PropertyGroup>
  <ImportGroup Label="ExtensionSettings">
  </ImportGroup>
  <ImportGroup Label="PropertySheets">
    <Import Project="$(UserRootDir)\Microsoft.CSharp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.CSharp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <PropertyGroup Label="UserMacros" />
  <ItemGroup>
    <None Include="D:\Projects\libheroes\bindings\csharp\CMakeLists.txt">
      <Link>CMakeLists.txt</Link>
    </None>
  </ItemGroup>
  <Target Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Name="CustomCommand_Debug_a636c07f1d51cd46229efc4bacc41a89" Inputs="D:/Projects/libheroes/bindings/csharp/CMakeLists.txt;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeCSharpCompiler.cmake.in;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeCSharpInformation.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeCompilerIdDetection.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeDetermineCSharpCompiler.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeDetermineCompiler.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeDetermineCompilerId.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeGenericSystem.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeInitializeConfigs.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeSystemSpecificInformation.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeSystemSpecificInitialize.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeTestCSharpCompiler.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeTestCompilerCommon.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CompilerId\VS-10.csproj.in;C:\Program Files\CMake\share\cmake-3.14\Modules\Platform\Windows.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\Platform\WindowsPaths.cmake;D:\Projects\libheroes\bindings\csharp\CMakeLists.txt;D:\Projects\libheroes\bindings\csharp\LibHeroes.NET.targets;D:\Projects\libheroes\bindings\csharp\cmake-vs\CMakeFiles\3.14.0\CMakeCSharpCompiler.cmake;D:\Projects\libheroes\bindings\csharp\cmake-vs\CMakeFiles\3.14.0\CMakeSystem.cmake;D:\Projects\libheroes\bindings\csharp\CMakeLists.txt" Outputs="D:\Projects\libheroes\bindings\csharp\cmake-vs\CMakeFiles\generate.stamp">
    <Exec Command="echo Building Custom Rule D:/Projects/libheroes/bindings/csharp/CMakeLists.txt" />
    <Exec Command="setlocal&#xA;&quot;C:\Program Files\CMake\bin\cmake.exe&quot; -SD:/Projects/libheroes/bindings/csharp -BD:/Projects/libheroes/bindings/csharp/cmake-vs --check-stamp-file D:/Projects/libheroes/bindings/csharp/cmake-vs/CMakeFiles/generate.stamp&#xA;if %errorlevel% neq 0 goto :cmEnd&#xA;:cmEnd&#xA;endlocal &amp; call :cmErrorLevel %errorlevel% &amp; goto :cmDone&#xA;:cmErrorLevel&#xA;exit /b %1&#xA;:cmDone&#xA;if %errorlevel% neq 0 goto :VCEnd" />
  </Target>
  <Target Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Name="CustomCommand_Release_a636c07f1d51cd46229efc4bacc41a89" Inputs="D:/Projects/libheroes/bindings/csharp/CMakeLists.txt;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeCSharpCompiler.cmake.in;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeCSharpInformation.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeCompilerIdDetection.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeDetermineCSharpCompiler.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeDetermineCompiler.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeDetermineCompilerId.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeGenericSystem.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeInitializeConfigs.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeSystemSpecificInformation.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeSystemSpecificInitialize.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeTestCSharpCompiler.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeTestCompilerCommon.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CompilerId\VS-10.csproj.in;C:\Program Files\CMake\share\cmake-3.14\Modules\Platform\Windows.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\Platform\WindowsPaths.cmake;D:\Projects\libheroes\bindings\csharp\CMakeLists.txt;D:\Projects\libheroes\bindings\csharp\LibHeroes.NET.targets;D:\Projects\libheroes\bindings\csharp\cmake-vs\CMakeFiles\3.14.0\CMakeCSharpCompiler.cmake;D:\Projects\libheroes\bindings\csharp\cmake-vs\CMakeFiles\3.14.0\CMakeSystem.cmake;D:\Projects\libheroes\bindings\csharp\CMakeLists.txt" Outputs="D:\Projects\libheroes\bindings\csharp\cmake-vs\CMakeFiles\generate.stamp">
    <Exec Command="echo Building Custom Rule D:/Projects/libheroes/bindings/csharp/CMakeLists.txt" />
    <Exec Command="setlocal&#xA;&quot;C:\Program Files\CMake\bin\cmake.exe&quot; -SD:/Projects/libheroes/bindings/csharp -BD:/Projects/libheroes/bindings/csharp/cmake-vs --check-stamp-file D:/Projects/libheroes/bindings/csharp/cmake-vs/CMakeFiles/generate.stamp&#xA;if %errorlevel% neq 0 goto :cmEnd&#xA;:cmEnd&#xA;endlocal &amp; call :cmErrorLevel %errorlevel% &amp; goto :cmDone&#xA;:cmErrorLevel&#xA;exit /b %1&#xA;:cmDone&#xA;if %errorlevel% neq 0 goto :VCEnd" />
  </Target>
  <Target Condition="'$(Configuration)|$(Platform)'=='MinSizeRel|x64'" Name="CustomCommand_MinSizeRel_a636c07f1d51cd46229efc4bacc41a89" Inputs="D:/Projects/libheroes/bindings/csharp/CMakeLists.txt;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeCSharpCompiler.cmake.in;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeCSharpInformation.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeCompilerIdDetection.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeDetermineCSharpCompiler.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeDetermineCompiler.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeDetermineCompilerId.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeGenericSystem.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeInitializeConfigs.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeSystemSpecificInformation.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeSystemSpecificInitialize.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeTestCSharpCompiler.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeTestCompilerCommon.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CompilerId\VS-10.csproj.in;C:\Program Files\CMake\share\cmake-3.14\Modules\Platform\Windows.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\Platform\WindowsPaths.cmake;D:\Projects\libheroes\bindings\csharp\CMakeLists.txt;D:\Projects\libheroes\bindings\csharp\LibHeroes.NET.targets;D:\Projects\libheroes\bindings\csharp\cmake-vs\CMakeFiles\3.14.0\CMakeCSharpCompiler.cmake;D:\Projects\libheroes\bindings\csharp\cmake-vs\CMakeFiles\3.14.0\CMakeSystem.cmake;D:\Projects\libheroes\bindings\csharp\CMakeLists.txt" Outputs="D:\Projects\libheroes\bindings\csharp\cmake-vs\CMakeFiles\generate.stamp">
    <Exec Command="echo Building Custom Rule D:/Projects/libheroes/bindings/csharp/CMakeLists.txt" />
    <Exec Command="setlocal&#xA;&quot;C:\Program Files\CMake\bin\cmake.exe&quot; -SD:/Projects/libheroes/bindings/csharp -BD:/Projects/libheroes/bindings/csharp/cmake-vs --check-stamp-file D:/Projects/libheroes/bindings/csharp/cmake-vs/CMakeFiles/generate.stamp&#xA;if %errorlevel% neq 0 goto :cmEnd&#xA;:cmEnd&#xA;endlocal &amp; call :cmErrorLevel %errorlevel% &amp; goto :cmDone&#xA;:cmErrorLevel&#xA;exit /b %1&#xA;:cmDone&#xA;if %errorlevel% neq 0 goto :VCEnd" />
  </Target>
  <Target Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|x64'" Name="CustomCommand_RelWithDebInfo_a636c07f1d51cd46229efc4bacc41a89" Inputs="D:/Projects/libheroes/bindings/csharp/CMakeLists.txt;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeCSharpCompiler.cmake.in;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeCSharpInformation.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeCompilerIdDetection.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeDetermineCSharpCompiler.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeDetermineCompiler.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeDetermineCompilerId.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeGenericSystem.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeInitializeConfigs.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeSystemSpecificInformation.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeSystemSpecificInitialize.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeTestCSharpCompiler.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CMakeTestCompilerCommon.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\CompilerId\VS-10.csproj.in;C:\Program Files\CMake\share\cmake-3.14\Modules\Platform\Windows.cmake;C:\Program Files\CMake\share\cmake-3.14\Modules\Platform\WindowsPaths.cmake;D:\Projects\libheroes\bindings\csharp\CMakeLists.txt;D:\Projects\libheroes\bindings\csharp\LibHeroes.NET.targets;D:\Projects\libheroes\bindings\csharp\cmake-vs\CMakeFiles\3.14.0\CMakeCSharpCompiler.cmake;D:\Projects\libheroes\bindings\csharp\cmake-vs\CMakeFiles\3.14.0\CMakeSystem.cmake;D:\Projects\libheroes\bindings\csharp\CMakeLists.txt" Outputs="D:\Projects\libheroes\bindings\csharp\cmake-vs\CMakeFiles\generate.stamp">
    <Exec Command="echo Building Custom Rule D:/Projects/libheroes/bindings/csharp/CMakeLists.txt" />
    <Exec Command="setlocal&#xA;&quot;C:\Program Files\CMake\bin\cmake.exe&quot; -SD:/Projects/libheroes/bindings/csharp -BD:/Projects/libheroes/bindings/csharp/cmake-vs --check-stamp-file D:/Projects/libheroes/bindings/csharp/cmake-vs/CMakeFiles/generate.stamp&#xA;if %errorlevel% neq 0 goto :cmEnd&#xA;:cmEnd&#xA;endlocal &amp; call :cmErrorLevel %errorlevel% &amp; goto :cmDone&#xA;:cmErrorLevel&#xA;exit /b %1&#xA;:cmDone&#xA;if %errorlevel% neq 0 goto :VCEnd" />
  </Target>
  <ItemGroup>
    <Compile Include="D:\Projects\libheroes\bindings\csharp\cmake-vs\LibHeroes.cs" />
    <Compile Include="D:\Projects\libheroes\bindings\csharp\Marshaling.cs">
      <Link>Marshaling.cs</Link>
    </Compile>
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="D:\Projects\libheroes\bindings\csharp\cmake-vs\ZERO_CHECK.vcxproj">
      <Project>{C0C9F6B6-CF04-32B9-BDB5-A1812B10331E}</Project>
      <Name>ZERO_CHECK</Name>
      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
      <CopyToOutputDirectory>Never</CopyToOutputDirectory>
    </ProjectReference>


    <ProjectReference Include="D:\Projects\libheroes\bindings\csharp\cmake-vs\build\libheroes.vcxproj">
      <Project>{E8B13004-193F-393B-90DB-A41070EDBD99}</Project>
      <Name>libheroes</Name>
      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
      <CopyToOutputDirectory>Never</CopyToOutputDirectory>
    </ProjectReference>
  </ItemGroup>

  <ImportGroup Label="ExtensionTargets">
  </ImportGroup>
  <PropertyGroup Condition="'$(Configuration)' == 'Debug'">
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)' == 'Release'">
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)' == 'MinSizeRel'">
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)' == 'RelWithDebInfo'">
  </PropertyGroup>
  <PropertyGroup>
    <BuildDependsOn>
      CustomCommand_Debug_a636c07f1d51cd46229efc4bacc41a89;
      CustomCommand_MinSizeRel_a636c07f1d51cd46229efc4bacc41a89;
      CustomCommand_RelWithDebInfo_a636c07f1d51cd46229efc4bacc41a89;
      CustomCommand_Release_a636c07f1d51cd46229efc4bacc41a89;
      $(BuildDependsOn)
</BuildDependsOn>
  </PropertyGroup>
<ItemGroup><Content Include="build\Libheroes.NET.targets"><Pack>true</Pack><PackagePath>\build\</PackagePath></Content><Content Include="build\$(Configuration)\yaml.dll"><Pack>true</Pack><PackagePath>\build\</PackagePath></Content><Content Include="build\$(Configuration)\libheroes.dll"><Pack>true</Pack><PackagePath>\build\</PackagePath></Content></ItemGroup></Project>
jessehouwing
  • 87,636
  • 19
  • 214
  • 286
flyx
  • 24,205
  • 5
  • 64
  • 96

1 Answers1

7

The new .NET Standard (<Project sdk="Microsoft.NET.Sdk">) style project files auto-include files with certain extensions automatically from the project folder. This change has been introduced with Visual Studio 2017/NetStandard/.NET Core and makes it much easier to maintain project files. Basically the new project system assumes that you want to include the following:

<Compile Include="**\*.cs" />
<EmbeddedResource Include="**\*.resx" />
<None Include"**\*" />

As a by-product, it can accidentally include files you didn't want to. This upgrade blog-post walks through the differences. It helped me understand many of the specifics.

By default /bin and /obj are excluded. The best way for you to proceed is to generate your build folder under the obj folder by directing the output to $(BaseIntermediateOutputPath)\build.

There are ways to disable the 'new behavior' and to exclude certain files and folders.

To switch to the old behavior, add the following to the top of your project file:

<PropertyGroup>
    <EnableDefaultCompileItems>false</EnableDefaultCompileItems>
    <EnableDefaultNoneItems>false</EnableDefaultNoneItems>
    <EnableDefaultContentItems>false</EnableDefaultContentItems>

    <!-- Or all default includes -->
    <EnableDefaultItems>false</EnableDefaultItems>
</PropertyGroup>

To exclude specific files from the solution I think this should do the trick:

<ItemGroup>
    <Compile Remove="build\**\*.cs">
    <EmbeddedResource Remove="build\**\*.resx" />
    <None Remove="build\**\*" />
</ItemGroup>

Or add the build folder to the $(DefaultItemExcludes):

<PropertyGroup>
     <DefaultItemExcludes>$(DefaultItemExcludes);build\**\*</DefaultItemExcludes>
</PropertyGroup>

Or you can exclude items from the Visual Studio Solution Explorer by right-clicking them and choosing Exclude from project.

See also:

jessehouwing
  • 87,636
  • 19
  • 214
  • 286
  • 1
    The `` tag was exactly what I was looking for. Generating the project with this tag fixed the error. Thanks for all the links, they are a great help. – flyx Jun 06 '19 at 15:46