Struggling to get a compiled c++ dll (both x86 and x64) packaged up so that a C# library can consume it.
Managed to pack and push the dll using nuspec file however when using VS2019 package manager it successfully installs the package however the reference does not appear. (Any Cpu)
.nuspec
<?xml version="1.0"?>
<package >
<metadata>
<id>component1</id>
<version>1.0.0</version>
<description>mycomponent</description>
<authors>Me</authors>
</metadata>
<files>
<file src="32\component1.dll" target="build\x86" />
<file src="64\component1.dll" target="build\x64" />
<file src="component1.targets" target="lib\net40" />
</files>
</package>
As the consuming project is targeting .NET 4.0 I created a component1.targets file pointing to the same framework
.targets
<ItemGroup Condition=" '$(Platform)' == 'x64' ">
<Reference Include="component1">
<HintPath>"$(MSBuildThisFileDirectory)..\..\build\x64\component1.dll"</HintPath>
</Reference>
</ItemGroup>
<ItemGroup Condition=" '$(Platform)' == 'x86' OR '$(Platform)' == 'AnyCPU' OR '$(Platform)' == 'Any CPU' ">
<Reference Include="component1">
<HintPath>$(MSBuildThisFileDirectory)..\..\build\x32\component1.dll</HintPath>
</Reference>
</ItemGroup>
Your steps are in a mess.
You should note that the targets file should be named as <package_id>.targets`, the same name as the nuget package id or it could not work. See this link.
Also, the targets file should be put into build folder of nupkg.
That are the two importance tips.
1) Please change your nuspec file to this:
<?xml version="1.0"?>
<package >
<metadata>
<id>component1</id>
<version>1.0.0</version>
<description>mycomponent</description>
<authors>Me</authors>
</metadata>
<files>
<file src="32\component1.dll" target="build\x86" />
<file src="64\component1.dll" target="build\x64" />
<file src="component1.targets" target="build" />
</files>
</package>
2) Then, change your component1.targets to these:
You should remove the "" under "$(MSBuildThisFileDirectory)..\..\build\x64\component1.dll".
<Project>
<ItemGroup Condition=" '$(Platform)' == 'x64' ">
<Reference Include="component1">
<HintPath>$(MSBuildThisFileDirectory)..\build\x64\component1.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup Condition=" '$(Platform)' == 'x86' OR '$(Platform)' == 'AnyCPU' OR '$(Platform)' == 'Any CPU' ">
<Reference Include="component1">
<HintPath>$(MSBuildThisFileDirectory)..\build\x32\component1.dll</HintPath>
</Reference>
</ItemGroup>
</Project>
3) use nuget pack to repack the nuget package. And before you install this new version of the nuget package, please clean nuget caches first or just delete all files under C:\Users\xxx(current user name)\.nuget\packages.
And it works well in my side.
My nuget package is called testt, and I referenced ClassLibrary21.dll under x64.
Related
I have a PCL-project with different functions and classes for each platform. I want to implement .net core support now. But I cant use controls like UserControl because the Microsoft.NET.Sdk.WindowsDesktop SDK isn't referenced. The .net framework is easy to implement because I only have to reference each assembly... But in .net core, I can't reference the assembly...
<Project Sdk="MSBuild.Sdk.Extras">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;xamarin.ios10;xamarin.mac20;xamarin.tvos10;monoandroid10.0;tizen40</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">uap10.0.17763;net472;netcoreapp3.1;$(TargetFrameworks)</TargetFrameworks>
</PropertyGroup>
<ItemGroup Condition=" $(TargetFramework.StartsWith('net4')) And '$(OS)' == 'Windows_NT' ">
...
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="System.Xaml" />
</ItemGroup>
<ItemGroup Condition=" $(TargetFramework.StartsWith('netcoreapp3')) And '$(OS)' == 'Windows_NT' ">
...
<SDKReference Include="Microsoft.NET.Sdk.WindowsDesktop" />
</ItemGroup>
That's my executable app, referencing the PCL-project above;
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<ProjectReference ...... />
</ItemGroup>
</Project>
I already tried this to reference the SDK but its not working.
<SDKReference Include="Microsoft.NET.Sdk.WindowsDesktop" />
I want to implement .net core support now. But I cant use controls
like UserControl because the Microsoft.NET.Sdk.WindowsDesktop SDK
isn't referenced. The .net framework is easy to implement because I
only have to reference each assembly... But in .net core, I can't
reference the assembly..
After doing a deep research, I found that Microsoft.NET.Sdk.WindowsDesktop cannot be used by SDKReference.
As a suggestion, you could create a custom targets file and then import it into your PCL-project to use the Net Core SDK.
1) create a file called custom.targets in your PCL project folder.
2) Then add these in custom.targets:
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<UseWPF>true</UseWPF>
</PropertyGroup>
</Project>
3) import this in xxx.csproj file of PCL-Project.
<Import Project="$(ProjectDir)custom.targets" Condition=" $(TargetFramework.StartsWith('netcoreapp3')) And '$(OS)' == 'Windows_NT' "/>
4) Then restart your project. Although there are some warnings that reminds you that some sdks are repeatedly quoted, you can ignore them and it will not have any impact on your project.
You can check this, which works well in my side.
I'm trying to build a single NuGet package that can be installed in Xamarin.Android, Xamarin.iOS, Xamarin.UWP and Xamarin.Forms (.NET Standard) projects. I can't use .NET Standard since I need to have a custom Activity for my Android project, custom AppDelegate for my iOS project, and a custom MainPage for my UWP project. In the initiators I want to use the ServiceCollection as DI provider.
In the docs they still mention the Portable Class Library (explicitly mentioned legacy, doesn't exist anymore in VS), or Manually Creating Packages (can't figure out what to do here), and then you also have websites mentioning the Xamarin.Forms Plugin, which also doesn't exist anymore.
I already made a solution with all 4 projects, but I can't figure out how I can create a single NuGet package for all 4 projects (all 3 target platforms).
Does anyone have an idea how we can build a multi-target NuGet package containing code for Android, iOS, and UWP, just like the Xamarin.Forms NuGet package?
I've also seen discussions like this: How does one create a project to create a Nuget package for Xamarin Forms supporting iOS, Android, and UWP?, but I'm not sure if this is still relevant, since the build.props and build.targets no longer exist in the MvvmCross repo.
On starting point is https://github.com/onovotny/MSBuildSdkExtras
A year ago, I made a sample (and collected some documentation and references), which might be inspiring for this subject: https://github.com/ZeProgFactory/MSBuildSdkExtrasTest
and https://github.com/ZeProgFactory/MediaPlayer is using it
And definitively, you should look at the repositories of James Montemagno's components at https://github.com/jamesmontemagno
With these references you should be able to start. But all of these had a mayor difference with your approach:
they are using one project (via MSBuildSdkExtras),
which is builded for all the platforms
and, finally, the binaries are assembled in one NuGet.
Perhaps you may take only this last step. Anyway, this approach is at least an option.
Hope this helps …
I've pushed a working version to https://github.com/MintPlayer/MintPlayer.MVVM
csproj-file
<Project Sdk="MSBuild.Sdk.Extras/2.0.41">
<!-- You must have the Android 8.0 SDK installed through the Android SDK manager -->
<PropertyGroup>
<AssemblyName>MintPlayer.MVVM</AssemblyName>
<RootNamespace>MintPlayer.MVVM</RootNamespace>
<TargetFrameworks>netstandard2.0;Xamarin.iOS10;MonoAndroid80;uap10.0.16299</TargetFrameworks>
<_WriteTelemetryProperties>false</_WriteTelemetryProperties>
<Authors>Pieterjan De Clippel</Authors>
<Company>MintPlayer</Company>
<Product>MintPlayer.MVVM</Product>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<Description>This package allows you to implement ViewModel Navigation and Dependency Injection in a Xamarin.Forms project</Description>
<Version>1.0.0</Version>
<Copyright />
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/MintPlayer/MintPlayer.MVVM</PackageProjectUrl>
<RepositoryUrl>https://github.com/MintPlayer/MintPlayer.MVVM</RepositoryUrl>
<PackageTags>Xamarin.Forms, Viewmodel navigation, Dependency Injection</PackageTags>
<PackageReleaseNotes>This package is still under construction</PackageReleaseNotes>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Platforms\**\*.cs" />
<None Include="Platforms\**\*.cs" />
<None Include="Resources\*.cs" />
<Compile Remove="Resources\*.cs" />
</ItemGroup>
<ItemGroup Condition=" $(TargetFramework.StartsWith('uap')) ">
<Compile Include="Platforms\UAP\**\*.cs" />
<Compile Include="Platforms\Common\**\*.cs" />
</ItemGroup>
<ItemGroup Condition=" $(TargetFramework.StartsWith('netstandard')) ">
<Compile Include="Platforms\Common\**\*.cs" />
</ItemGroup>
<ItemGroup Condition=" $(TargetFramework.StartsWith('Xamarin.iOS')) ">
<Compile Include="Platforms\iOS\**\*.cs" />
<Compile Include="Platforms\Common\**\*.cs" />
</ItemGroup>
<ItemGroup Condition=" $(TargetFramework.StartsWith('MonoAndroid')) ">
<Compile Include="Platforms\Android\**\*.cs" />
<Compile Include="Platforms\Common\**\*.cs" />
<AndroidResource Include="Resources\**\*.xml" SubType="Designer" Generator="MSBuild:UpdateAndroidResources" />
<AndroidResource Include="Resources\**\*.axml" SubType="Designer" Generator="MSBuild:UpdateAndroidResources" />
</ItemGroup>
<ItemGroup>
<None Remove="Platforms\Common\MintPlayerMvvmExtensions.cs" />
<None Remove="Platforms\Common\NavigationService.cs" />
<None Remove="Platforms\Common\Platform.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="3.1.6" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.6" />
<!--<PackageReference Include="Xamarin.Forms" Version="4.5.0.495" />-->
<PackageReference Include="Xamarin.Forms" Version="3.1.0.697729" />
</ItemGroup>
</Project>
Directory.build.props
<Project>
<PropertyGroup>
<Company>MintPlayer</Company>
<Copyright>Copyright © MintPlayer</Copyright>
<RepositoryUrl>https://github.com/MintPlayer/MintPlayer.MVVM</RepositoryUrl>
<Authors>Pieterjan De Clippel</Authors>
<Owners>MintPlayer</Owners>
<PackageReleaseNotes />
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<RepositoryType>git</RepositoryType>
<Product>$(AssemblyName) ($(TargetFramework))</Product>
<NeutralLanguage>en</NeutralLanguage>
<LangVersion>latest</LangVersion>
<NoWarn>$(NoWarn);1591;1701;1702;1705;VSX1000;NU1603</NoWarn>
<GenerateDocumentationFile Condition=" '$(Configuration)' == 'Release' ">true</GenerateDocumentationFile>
<GeneratePackageOnBuild Condition=" '$(Configuration)' == 'Release' and '$(IsTestProject)' != 'true'">true</GeneratePackageOnBuild>
<Platform>AnyCPU</Platform>
<DebugType>portable</DebugType>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<IsTestProject>$(MSBuildProjectName.Contains('UnitTests'))</IsTestProject>
</PropertyGroup>
</Project>
Directory.build.targets
<Project>
<PropertyGroup Condition="$(TargetFramework.StartsWith('netstandard'))">
<DefineConstants>$(DefineConstants);NETSTANDARD;PORTABLE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="$(TargetFramework.StartsWith('Xamarin.iOS'))">
<DefineConstants>$(DefineConstants);MONO;UIKIT;COCOA;IOS</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="$(TargetFramework.StartsWith('MonoAndroid'))">
<DefineConstants>$(DefineConstants);MONO;ANDROID</DefineConstants>
<MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>
<AndroidResgenClass>Resource</AndroidResgenClass>
<AndroidResgenFile>Resources\Resource.designer.cs</AndroidResgenFile>
</PropertyGroup>
</Project>
You must add the following to your .sln file
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7004E39A-BAF2-4F2F-B505-CC3DEC393CB6}"
ProjectSection(SolutionItems) = preProject
Directory.build.props = Directory.build.props
Directory.build.targets = Directory.build.targets
EndProjectSection
EndProject
I'm having issues referring to System.Net.Http.dll version 4.2.0.0
Here is my setup -
Visual Studio 2017, 15.8.7
A simple console application targeting .net 4.7.2
When I create a new project, by default it has a reference to System.Net.Http.dll and the location is C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Net.Http.dll.
But when I execute my code,
class Program
{
static void Main(string[] args)
{
var assembly = GetAssemblyNameContainingType(typeof(HttpClient).FullName);
Console.WriteLine("Path: " + assembly.Location);
Console.WriteLine("Version: " + assembly.GetName().Version);
Console.ReadKey();
}
public static Assembly GetAssemblyNameContainingType(String typeName)
{
foreach (Assembly currentassembly in AppDomain.CurrentDomain.GetAssemblies())
{
Type t = currentassembly.GetType(typeName, false, true);
if (t != null)
{ return currentassembly; }
}
return null;
}
}
I get the below output
Path: C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Net.Http\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Net.Http.dll
Version: 4.0.0.0
It seems to pick up reference to System.Net.Http.dll from GAC instead of the Programs Files (x86) folder.
I specifically need reference to 4.2.0.0 - since it addresses serialization of HttpRequestException in a way Newtonsoft json can serialize and deserialize it without erroring out.
I read quite a few posts about others facing an issue with System.Net.Http.dll, many of those said that this was addressed in Visual Studio 2017, 15.8 and that one won't have to add reference to the System.Net.Http nugets and should let visual studio to refer it appropriately from framework.
Am i missing something?
I have tried numerous things -
Adding reference path (C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.7.2) in project properties - did not help
Adding reference using path to C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.7.2\System.Net.Http.dll - did not help
Copy local - True - did not help
Specific version - True - did not help
Added binding redirect - did not help. Gave below exception
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
System.BadImageFormatException: 'Could not load file or assembly 'System.Net.Http, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. Reference assemblies should not be loaded for execution. They can only be loaded in the Reflection-only loader context. (Exception from HRESULT: 0x80131058)'
Unchecked Auto-generate binding redirects in project properties - did not help
Unchecked Auto-generate binding redirects with manual binding redirect - did not help
Unchecked Auto-generate binding redirects with manual binding redirect + copy local - did not help
Adding a hint path - did not help
C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.7.2\System.Net.Http.dll
Here is my .csproj (original, reverted after doing all above changes)
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{EEE1B52B-0316-4EB5-9F3B-383E377964BE}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>SysNetHttpTests</RootNamespace>
<AssemblyName>SysNetHttpTests</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
Official MS answer (by Jose Perez Rodriguez):
This is by design. Due to a Windows requirement, all of the framework
assemblies installed in the GAC need to be versioned 4.0.0.0. The
actual implementation contained in that assembly is not the 4.0.0.0
implementation but the 4.2.0.0 instead. There are a bunch of
complicated reasons of why Windows has this requirement on our
assemblies installed on the GAC, like servicing, bugfixing, and just
having one GAC for all .NET 4+ frameworks, but essentially this is
expected.
While you think it is 4.0 it's in fact 4.2. Dll hell, welcome back!
I've written a small Media Foundation Transform and added the C++ DLL to my C# Windows Store App project.
The 32bit version of the DLL running the x86 configuration works just fine but x64 doesn't work (it throws an Exception with the following message:
"MF_MEDIA_ENGINE_ERR_SRC_NOT_SUPPORTED : HRESULT - 0x800700C1")
If I add the 64bit version it's the same just the other way around x64 works and x86 doesn't.
Is there any way I can set it up so that it uses the x86 version of the DLL for the x86 configuration and the x64 version for the x64 configuration?
Took me some time but I figured out how to do it using NuGet.
First I added a location on my PC as package source as explained here.
In VS2013 CE you do this by opening the NuGet Package Manager Settings (Tools > NuGet Package Manager > Package Manager Settings) and under Package Sources you add a location on your computer.
To create the NuGet I combined several HowTo's since one alone didn't work.
The main one was this.
I built the dlls for my required platforms and created the following folder structure
Since it might be a little hard to see ProjectName.props and ProjectName.targets are located in the netcore451 folder.
The .dll, .pri and .winmd in lib are the x86 version. According to the HowTo it's redundant and you can just ignore these files but without them VS might not work correctly in design mode.
In the folder that contains build and lib I created a file ProjectName.nuspec
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2013/01/nuspec.xsd">
<metadata minClientVersion="2.5">
<id>ProjectName</id>
<version>1.0.0</version>
<authors>Stefan Fabian</authors>
<owners>Stefan Fabian</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Description</description>
<releaseNotes>First release.</releaseNotes>
<copyright>Copyright 2015</copyright>
<references>
<group targetFramework=".NETCore4.5.1">
<reference file="ProjectName.winmd" />
</group>
</references>
</metadata>
</package>
ProjectName.props
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
</Project>
ProjectName.targets
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="PlatformCheck" BeforeTargets="InjectReference"
Condition=" ( ('$(Platform)' != 'x86') AND ('$(Platform)' != 'AMD64') AND ('$(Platform)' != 'Win32') AND ('$(Platform)' != 'ARM') AND ('$(Platform)' != 'x64') )">
<Error Text="$(MSBuildThisFileName) does not work correctly on '$(Platform)'
platform. You need to specify platform (x86 / x64 or ARM)." />
</Target>
<Target Name="InjectReference" BeforeTargets="ResolveAssemblyReferences">
<ItemGroup Condition="'$(Platform)' == 'x86' or '$(Platform)' == 'Win32'">
<Reference Include="ProjectName">
<HintPath>$(MSBuildThisFileDirectory)x86\ProjectName.winmd</HintPath>
</Reference>
</ItemGroup>
<ItemGroup Condition="'$(Platform)' == 'x64' or '$(Platform)' == 'AMD64'">
<Reference Include="ProjectName">
<HintPath>$(MSBuildThisFileDirectory)x64\ProjectName.winmd</HintPath>
</Reference>
</ItemGroup>
<ItemGroup Condition="'$(Platform)' == 'ARM'">
<Reference Include="ProjectName">
<HintPath>$(MSBuildThisFileDirectory)ARM\ProjectName.winmd</HintPath>
</Reference>
</ItemGroup>
</Target>
</Project>
I'm not sure if it's necessary to check for x86 and Win32 but it works for me.
Disclaimer
This was the first time ever I created a NuGet package and the code above might suck.
I have customised an MSBuild project so that the default target is a new target named similarly to 'BuildWithExternalReference'. This new target calls two other targets; the first is a custom target called something like 'BuildExternalReference' which builds a DLL using an external tool. The DLL that is built is a reference for the main project, which is built using the normal 'Build' target. I have setup the Inputs and Outputs attributes for the 'BuildExternalReference' target so the Inputs reference the source files and the outputs reference the resulting DLL.
In both Visual Studio 2012 and Visual Studio 2010 the build works correctly the first time it is invoked. However, on subsequent builds if I change the external source files (referenced by the 'BuildExternalReference' target Inputs attribute) then Visual Studio 2012 simply reports 'Build: 0 succeeded, 0 failed, 1 up-to-date, 0 skipped'. Visual Studio 2010 continues to work perfectly. In addition, building from the command line with MSBuild.exe works perfectly.
I'm aware that the build system in Visual Studio 2012 has changed, but I can't find information about changes to the way incremental builds are performed.
Has anything changed in Visual Studio 2012 to cause incremental builds to change?
Here's a cut down version of the csproj file I'm using:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="BuildWithExternalTool" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ExternalSourceFiles Include="..\ExternalSourceFiles\\*\*.cs" />
<ExternalDll Include="..\ExternalSource\External.dll" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Target Name="BuildExternalTool" Inputs="#(ExternalSourceFiles);" Outputs="#(ExternalDll)">
<Exec Command="C:\External\Path\To\Tool.exe" />
</Target>
<Target Name="BuildWithExternalTool">
<CallTarget Targets="BuildExternalTool" />
<CallTarget Targets="Build" />
</Target>
</Project>
Update 1st of November 2012
Here's a complete self contained example which reproduces the issue:
https://skydrive.live.com/redir?resid=EA1DD6ACA92F9EFF!155&authkey=!ANhuqF_rrCgxpLE
This is a solution with one project. The MSBuildIssueExample\MSBuildIssueExample.csproj file has been customised so there is a custom default target. This default target calls a custom target (called 'ExternalTool') and then the default Build target.
The custom ExternalTool target writes out some messages to make sure it's working, and also copies the contents of the MSBuildIssueExample\ExternalTool\Input.txt file over the MSBuildIssueExample\ExternalTool\Output.txt file.
The Input.txt file is a input of the ExternalTool target, and Output.txt is an output.
To recreate the issue follow these steps:
1) Open the solution in the designated version of Visual Studio
2) Build the solution once to make sure the outputs are up to date with respect to the inputs
3) Modify MSBuildIssueExample\ExternalTool\Input.txt so its content does not match Output.txt
4) Build again
When you go through this process in Visual Studio 2010 the ExternalTool target will be invoked again, and the Input.txt file will be copied over Output.txt.
When you go through this process in Visual Studio 2012 the ExternalTool target will not be invoked, even though the inputs are newer than the outputs, and as a result the contents of Input.txt will not be written to Output.txt.
However, if you do Rebuild (rather than just Build) then both versions of Visual Studio work as expected.
This feedback from Microsoft answers the question:
This is due to a change in VS 2012 where C#/VB projects now do a "fast up-to-date check" that allows them to skip the build, rather than forcing the build all the time. One downside, however, is that fast up-to-date check does not take into account custom targets, which is why your incremental change was not detected. If you wish to disable the "fast up-to-date check" please set "DISABLEFASTUPTODATECHECK" to true either as an MSBuild property in the project file or as an environment variable in the environment you launch VS from.
So basically this is a breaking change in Visual Studio 2012 that unfortunately does not seem to be documented very well.
This is an old issue, but still relevant. Thank you very much for raising it here.
I would like to provide the results of my research.
The example you share shows the abnormal behavior both when built inside the Visual Studio GUI and by the devenv command line (devenv .\MSBuildIssueExample.sln /build)
However, if you replace your csproj file with the following:
MSBuildIssueExample.csproj
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{4EA8847D-262C-4937-8536-E526E9BAB1C7}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MSBuildIssueExample</RootNamespace>
<AssemblyName>MSBuildIssueExample</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Class1.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="Custom.Targets" />
</Project>
Custom.Targets
<?xml version="1.0" encoding="utf-8" ?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<CompileDependsOn>ExternalTool;$(CompileDependsOn)</CompileDependsOn>
<CleanDependsOn>CleanOutput;$(CleanDependsOn)</CleanDependsOn>
</PropertyGroup>
<ItemGroup>
<ExternalToolInputs Include="ExternalTool\Input.txt">
<InProject>false</InProject>
</ExternalToolInputs>
<ExternalToolOutputs Include="ExternalTool\Output.txt">
<InProject>false</InProject>
</ExternalToolOutputs>
</ItemGroup>
<Target Name="ExternalTool" Inputs="#(ExternalToolInputs)" Outputs="#(ExternalToolOutputs)">
<Message Text="ExternalTool target start, copying input file over output..." />
<Copy SourceFiles="#(ExternalToolInputs)" DestinationFiles="#(ExternalToolOutputs)" />
<Message Text="ExternalTool target end, copy successful" />
</Target>
<Target Name="CleanOutput">
<Delete Files="#(ExternalToolOutputs)" ContinueOnError="true" />
</Target>
</Project>
Then the behavior is different !
Visual Studio GUI continues to misbehave, however, the command line build with devenv does recognize the change in the input!
Also note, that running msbuild on the command line instead of devenv works correctly in both versions. Although msbuild has other problems ...
EDIT
There is a solution for the GUI build, which is only applicable when the amount of external files is small. You add them to the project as links and make sure the Build Action is None. Then it works fine in the GUI.
Although, I have only checked with the Custom.Targets, but I am pretty sure it is going to work with the original version as well.
To expand on mark's Edit, and since None-items didn't work for me, here's an example of a custom targets file that I can import in other projects, that reads a text file into a property (which I can then use in the DefineConstants property), and that will mark the text file as input for the CoreCompile target:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<CommonDefines>$([System.IO.File]::ReadAllText('$(SolutionDir)\_meta\definesFlags.txt'));$(CommonDefines)</CommonDefines>
</PropertyGroup>
<ItemGroup>
<CustomAdditionalCompileInputs Include="$(SolutionDir)\_meta\definesFlags.txt" />
</ItemGroup>
</Project>
CustomAdditionalCompileInputs-items is taken as an input by Microsoft.Csharp.Core.targets.