IS there a way to change what framework a project (that has multiple target frameworks) is compiled in without updating the csproj?
I'm writing a NuGet package that supports both .NET 4.8 and .NET 6. (I can't use .NET Standard 2.0.)
I have files that I want to be compiled only when targeting .NET 4.8 and others that should only be compiled when targeting .NET 6.0. I know there's a couple ways to achieve this, but I am trying to structure my files such that the directory /AspNetCore contains all of my .NET 6 files and /NetFramework contains all my .NET 4.8 files.
With that, in my csproj, I can do:
<ItemGroup Condition="'$(TargetFramework)' == 'net6.0'">
<Compile Remove="NetFramework\**" />
<EmbeddedResource Remove="NetFramework\**" />
<None Remove="NetFramework\**" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net48'">
<Compile Remove="AspNetCore\**" />
<EmbeddedResource Remove="AspNetCore\**" />
<None Remove="AspNetCore\**" />
</ItemGroup>
But then the /AspNetCore folder is hidden because the IDE is choosing NET48 as the target framework. This is fine when I'm working on the NET48 code, but not ideal when I'm working on the NET6.0 code.
If I were using #if NETFRAMEWORK #elif NET6_0 #endif syntax in each file, then I could select the target framework from the project dropdown, but I want to avoid having compile-time logic in my files. I could also keep going back to my csproj and updating the tag, but I don't want to do that either in case I accidentally forget to change it back.
Is there a good to change the target framework in the IDE when targeting multiple frameworks like this?
Create a Directory.Build.targets file in your solution folder and copy the contents below:
<Project>
<PropertyGroup>
<BuildDependsOn>
RemoveNet48Files;
RemoveNet60Files;
$(BuildDependsOn)
</BuildDependsOn>
</PropertyGroup>
<Target Name="RemoveNet48Files" Condition="'$(TargetFramework)' != 'net48'">
<ItemGroup>
<Compile Remove="NetFramework\**" />
<EmbeddedResource Remove="NetFramework\**" />
<None Remove="NetFramework\**" />
</ItemGroup>
</Target>
<Target Name="RemoveNet60Files" Condition="'$(TargetFramework)' != 'net6.0'">
<ItemGroup>
<Compile Remove="AspNetCore\**" />
<EmbeddedResource Remove="AspNetCore\**" />
<None Remove="AspNetCore\**" />
</ItemGroup>
</Target>
</Project>
This way the files will be removed from the item group only before build.
Related
I added realm package to my project and it works fine but for some reason it also added some not valid local dependencies which i cannot remove. I tried to remove them manually from csproj file but there is no trace of them. How can i get rid of them?
You have added RuntimeIdentifier xml node on csproj file on a non-sdk net framework project.
That is the cause. And you should note that RuntimeIdentifier works for new sdk net core cross-platform project rather than your non-sdk net framework windows project.
RuntimeIdentifier does not work for non-sdk net framework projects.
So you have to remove these on csproj file.
<PropertyGroup>
<RuntimeIdentifier>osx-x64</RuntimeIdentifier>
</PropertyGroup>
When I remove it, all work well.
Update
It is a well-known issue which I have reported before.
The problem is here:
C:\Users\xxx\.nuget\packages\realm\10.1.1\build\Realm.props and then open that file, you will see:
You have two points which needed to care:
1) NativeReference works for ios apps rather than android apps, actually, you could just delete the NativeReference node but for the inclusiveness and comprehensiveness of the nuget package, it is not advisable to delete it.
2) NativeReference cannot recognize the value of MSBuild property. You can't pass a property value in there. Just as my link hinted.
First of all, the itemgroup condition will indeed be processed by vs according to the conditions when it is built, but when it is not built, it will ignore the condition to check its content to determine whether it is valid, but because your Android project has not been able to recognize the nativereference , So the problem has always existed.
In order to skip this detection mechanism, you'd better use choose, when. And in this scenario, you are using an Android project, so there is no need to consider the problem that the nativereference cannot identify the property.
Suggestion One
modify the Realm.props to:
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<_RealmNugetNativePath Condition="'$(_RealmNugetNativePath)' == ''">$(MSBuildThisFileDirectory)..\native\</_RealmNugetNativePath>
</PropertyGroup>
<Choose>
<When Condition="'$(TargetFrameworkIdentifier)' == 'Xamarin.iOS'">
<ItemGroup>
<NativeReference Include="$(_RealmNugetNativePath)ios\universal\realm-wrappers.framework">
<Kind>Framework</Kind>
<SmartLink>False</SmartLink>
</NativeReference>
</ItemGroup>
</When>
<When Condition="'$(TargetFrameworkIdentifier)' == 'Xamarin.Mac'">
<ItemGroup>
<NativeReference Include="$(_RealmNugetNativePath)..\runtimes\osx-x64\native\librealm-wrappers.dylib">
<Kind>Dynamic</Kind>
</NativeReference>
</ItemGroup>
</When>
</Choose>
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == 'Xamarin.iOS'">
<Content Include="$(_RealmNugetNativePath)ios\Realm.dll.config">
<Link>Realm.dll.config</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == 'MonoAndroid'">
<AndroidNativeLibrary Include="$(_RealmNugetNativePath)android\armeabi-v7a\librealm-wrappers.so">
<Link>$(_RealmNugetNativePath)android\armeabi-v7a\librealm-wrappers.so</Link>
</AndroidNativeLibrary>
<AndroidNativeLibrary Include="$(_RealmNugetNativePath)android\x86\librealm-wrappers.so">
<Link>$(_RealmNugetNativePath)android\x86\librealm-wrappers.so</Link>
</AndroidNativeLibrary>
<!-- 64bit -->
<AndroidNativeLibrary Include="$(_RealmNugetNativePath)android\arm64-v8a\librealm-wrappers.so">
<Link>$(_RealmNugetNativePath)android\arm64-v8a\librealm-wrappers.so</Link>
</AndroidNativeLibrary>
<AndroidNativeLibrary Include="$(_RealmNugetNativePath)android\x86_64\librealm-wrappers.so">
<Link>$(_RealmNugetNativePath)android\x86_64\librealm-wrappers.so</Link>
</AndroidNativeLibrary>
</ItemGroup>
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'">
<None Include="$(_RealmNugetNativePath)..\runtimes\win-x86\native\realm-wrappers.dll">
<Link>lib\win32\x86\realm-wrappers.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(_RealmNugetNativePath)..\runtimes\win-x64\native\realm-wrappers.dll">
<Link>lib\win32\x64\realm-wrappers.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
Suggestion Two
2) If you use an IOS app further, you have to try these:
a) delete two NativeReference nodes directly under Realm.props file
b) then add these on ios.csoroj file:
<Choose>
<When Condition="'$(TargetFrameworkIdentifier)' == 'Xamarin.iOS'">
<ItemGroup>
<NativeReference Include="C:\Users\xxx\.nuget\packages\realm\10.1.1\native\ios\universal\realm-wrappers.framework" Kind="Framework" SmartLink="False">
</NativeReference>
</ItemGroup>
</When>
<When Condition="'$(TargetFrameworkIdentifier)' == 'Xamarin.Mac'">
<ItemGroup>
<NativeReference Include="C:\Users\xxx\.nuget\packages\realm\10.1.1\runtimes\osx-x64\native\librealm-wrappers.dylib" Kind="Dynamic">
</NativeReference>
</ItemGroup>
</When>
</Choose>
Right click on your project, select Unload Project.
Select the unloaded project, you'll see a xml file opened.
Look for <ItemGroup> which holds the list of references.
Delete the items that you don't need anymore.
Save the file. Right click on the project and Reload it.
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
EDIT
For info, I'm developping on macOS using VS Code
I'm trying to include files in my publish process ( Currently cshtmlthat represents my email templates ).
I follow this thread on github but seems that their solutions don't work for me.
Here my csproj to add an unique cshtml file :
<Target Name="PrepublishScript" BeforeTargets="PrepareForPublish">
<ItemGroup>
<EmailFile Include="$(ProjectDir)/EmailTemplates/OrderCompleteEmail.cshtml" />
</ItemGroup>
<Copy SourceFiles="#(EmailFile)" DestinationFolder="$(PublishDir)" SkipUnchangedFiles="false" />
</Target>
Your solution was almost correct, you have to use AfterTargets="Publish":
<Target Name="CopyCustomContentOnPublish" AfterTargets="Publish">
<ItemGroup>
<EmailFile Include="EmailTemplates/OrderCompleteEmail.cshtml" />
</ItemGroup>
<Copy SourceFiles="#(EmailFile)" DestinationFolder="$(PublishDir)" />
</Target>
You can also copy all your email templates in a single Target to the same folder like:
<Target Name="CopyCustomContentOnPublish" AfterTargets="Publish">
<ItemGroup>
<EmailTemplates Include="EmailTemplates\*.cshtml" />
</ItemGroup>
<Copy SourceFiles="#(EmailTemplates)" DestinationFolder="$(PublishDir)%(EmailTemplates.RelativeDir)" />
</Target>
I am trying to set up a simple project with Antlr in .net core 1.0 project using VS2017.
Following https://github.com/sharwell/antlr4cs, added .g4 file to the project. The project file looks like this,
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp1.0</TargetFramework> </PropertyGroup>
<ItemGroup>
<None Remove="Calculator.g4" /> </ItemGroup>
<ItemGroup>
<PackageReference Include="Antlr4" Version="4.5.4-beta001" /> </ItemGroup>
<ItemGroup>
<AdditionalFiles Include="Calculator.g4" />
</ItemGroup>
</Project>
But the document says,
Locate an existing XML element according to the MSBuild Property
column in the table above, or add one if it does not already exist.
For example, to generate both the parse tree listener and visitor
interfaces and base classes for your parser, update the project item
to resemble the following.
<Antlr4 Include="CustomLanguage.g4">
<Generator>MSBuild:Compile</Generator>
<CustomToolNamespace>MyProject.Folder</CustomToolNamespace>
<Listener>True</Listener> <Visitor>True</Visitor> </Antlr4>
There is no any Antlr4 tag in this proj file. Is Antlr not supported in VS2017?
is tehre a good example I can follow to use ANtlr with .net core?
This is simply all I need in my .NET Standard 1.3 class library project to hold the grammar file.
<ItemGroup>
<Antlr4 Include="Something.g4">
<Generator>MSBuild:Compile</Generator>
<Listener>False</Listener>
<Visitor>False</Visitor>
</Antlr4>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Antlr4" Version="4.6.1-beta001" />
</ItemGroup>
Note that you might use a newer Antlr4 package version as 4.6.1 was the only version available when this answer was created.
I was just looking for the same thing, for .NET Core 2.0.
The current ANTLR4 package version is 4.6.5 Beta 1. In this version the C# generator was ported to C# so the dependency to Java was removed. This is still experimental and has to be enabled manually with :
<Antlr4UseCSharpGenerator>True</Antlr4UseCSharpGenerator>
Files aren't generated when a .g4 file is modified. They will be generated when dotnet build is called.
File globbing works as expected BUT changing settings like <Visitor>false</Visitor> requires a call dotnet clean before dotnet build.
The default Antlr task options can be found in the source :
<Antlr4>
<Generator>MSBuild:Compile</Generator>
<CustomToolNamespace Condition="'$(Antlr4IsSdkProject)' != 'True'">$(RootNamespace)</CustomToolNamespace>
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
<Encoding>UTF-8</Encoding>
<TargetLanguage>CSharp</TargetLanguage>
<Listener>true</Listener>
<Visitor>true</Visitor>
<Abstract>false</Abstract>
<ForceAtn>false</ForceAtn>
</Antlr4>
Globbing works, so if I want to build all g4 files and disable visitors, all I have to write is :
<ItemGroup>
<Antlr4 Include="**/*.g4" >
<Visitor>false</Visitor>
</Antlr4>
</ItemGroup>
My entire csproj file looks like this :
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<Antlr4UseCSharpGenerator>True</Antlr4UseCSharpGenerator>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Antlr4">
<Version>4.6.5-beta001</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Antlr4 Include="**/*.g4" >
<Visitor>false</Visitor>
</Antlr4>
</ItemGroup>
</Project>
I currently have a build setup as follows, allowing me to embed all references DLLs as embedded resources in my assembly. This operates at the AfterResolveReferences target and works flawlessly. It also allows me to produce a single executable which doesn't need any additional DLLs to launch (since it loads these at runtime).
Now, I would like to include the PDB information as well. I already do this with all referenced assemblies, but not the assembly I am building, since that is (for obvious reasons) produced after that target.
To recap:
I am building AssemblyA.exe.
It has AssemblyB.dll and AssemblyC.dll as references, so these are included in AssemblyA.exe as embedded resources during build.
After building AssemblyA.exe, MSBuild also produces a AssemblyA.pdb file.
This is where I want to then also embed AssemblyA.pdb into AssemblyA.exe as embedded resource.
Is that possible somehow? I am aware that this may trigger a double-build.
I ended up writing the following to my project file - works flawlessly. It does a double-build, but it works.
<Target Name="Prebuild">
<CallTarget Targets="Clean" />
<MSBuild Projects="$(SolutionPath)" Targets="Build" Properties="Configuration=Debug;IgnoreRecursion=true" />
</Target>
<Target Name="BeforeBuild">
<ItemGroup>
<_IgnoreRecursion Include="$(IgnoreRecursion)"/>
</ItemGroup>
<CallTarget Targets="Prebuild" Condition="'%(_IgnoreRecursion.Identity)' != 'true'" />
<CreateItem Include="$(TargetDir)\**\*.*">
<Output TaskParameter="Include" ItemName="OutputFiles" />
</CreateItem>
<ItemGroup>
<EmbeddedResource Include="#(OutputFiles)" Condition="('%(OutputFiles.Extension)' == '.dll' Or '%(OutputFiles.Extension)' == '.pdb')">
<LogicalName>%(OutputFiles.DestinationSubDirectory)%(OutputFiles.Filename)%(OutputFiles.Extension)</LogicalName>
</EmbeddedResource>
</ItemGroup>
<Message Importance="high" Text="Embedding: #(OutputFiles->'%(Filename)%(Extension)', ', ')" />
</Target>
If a double compile is not a problem you can create your own target, compile to a temporay folder via msbuild task and then embed the files you need from this temporary folder.
You have to do a rebuild because otherwise it will cache the assemblies.
Your target to compile in the .proj file would look like this:
<Target Name="YourBuild">
<MSBuild Projects="YourProject.csproj" Targets="Build"
Properties="Configuration=Debug;OutputPath=tmp"/>
<MSBuild Projects="YourProject.csproj" Targets="Rebuild"
Properties="Configuration=Debug"/>
</Target>
Files that are included as EmbeddedResoucre in BeforeBuild target in the project:
<Target Name="BeforeBuild">
<ItemGroup>
<YourFiles Include="tmp\*.pdb" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="#(YourFiles ->'%(Relativedir)%(filename)%(extension)')"/>
</ItemGroup>
</Target>