Is it possible to remove a project reference from the command line? And if so, how? Imagine I have two projects in a solution: WPF project A, and Class Library B. A has a project reference to B so that it will depend on the output of project B. Now I wan't to remove the project reference from the command line as to be able to automate in our build. Looking as the .csproj file the project reference looks something like this.
<ProjectReference Include="..\B\B.csproj">
<Project>{7B68745C-382E-4272-897D-123A0AD80391}</Project>
<Name>B</Name>
</ProjectReference>
ProjectReference is an item, you can add the Item to be conditionally excluded inside a conditioned ItemGroup:
<PropertyGroup>
<ExcludeReference Condition="'$(ExcludeReference)'==''">false</ExcludeReference>
</PropertyGroup>
<ItemGroup Condition="'$(ExcludeReference)'=='true'">
<ProjectReference Include="..\B\B.csproj">
<Project>{7B68745C-382E-4272-897D-123A0AD80391}</Project>
<Name>B</Name>
</ProjectReference>
</ItemGroup>
From the command line you can pass:
MsBuild SomeProject.proj /p:ExcludeReference=true
UPDATE:
You can have your optional reference in a separate project and import it:
ConditionalReferences.proj
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ProjectReference Include="..\B\B.csproj">
<Project>{7B68745C-382E-4272-897D-123A0AD80391}</Project>
<Name>B</Name>
</ProjectReference>
</ItemGroup>
</Project>
And in your .csproj
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ExcludeReference Condition="'$(ExcludeReference)'==''">false</ExcludeReference>
</PropertyGroup>
<Import Project="ConditionalReferences.proj" Condition="'$(ExcludeReference)'=='false'"/>
</Project>
Related
I'm attempting to create a nupkg with Visual Studio using the built in nuget package building and include the build directory from my project in the nupkg. It seems like it should be a fairly simple task but I can't get it to work. From my googling adding either of these to my csproj file should work, but both create an empty 'build' directory in the nupkg:
<ItemGroup>
<None Include="build\**">
<Pack>true</Pack>
<PackagePath>build\</PackagePath>
<IncludeInPackage>true</IncludeInPackage>
</None>
</ItemGroup>
Using nuget pack to create the package with the following in my nuspec does work:
<files>
<!-- Include everything in \build -->
<file src="build\**" target="build" />
</files>
Include build directory in nuget package using visual studio pack
According to the document Including content in a package, you should use the properties <Pack>true</Pack> and <PackagePath>build\</PackagePath>:
If you want to copy all your content to only a specific root folder(s) (instead of content and contentFiles both), you can use the MSBuild property ContentTargetFolders, which defaults to "content;contentFiles" but can be set to any other folder names.
PackagePath can be a semicolon-delimited set of target paths.
Specifying an empty package path would add the file to the root of the
package.
So, you can change your ItemGroup like following:
<ItemGroup>
<None Include="build\**" Pack="True" PackagePath="build\" />
</ItemGroup>
Update:
I believe this is the same as what I added but in a different XML
structure and without the Pack attribute
The Pack attribute is the key point. It works fine with your XML structure and the Pack attribute. You should make sure you have the files in the build folder in your project folder:
Check my test demo below:
Update2:
Ah! You are using the .net framework project!! That the reason for this issue. This method is used for .net standard and .net core project by default and it not work for .net framework. To resolve this issue you have to use the .nupsec file, like you post in the question.
If you still want to include build directory in nuget package using visual studio pack, you need change your project type to SDK type:
Check this document for some more details.
Then you can use the method, which we talked about before.
Hope this helps.
The solution to this issue was to upgrade the project to SDK type (Xamarin binding projects by default use the old format but seem to work with the new type) and then use:
<ItemGroup>
<None Update="build\**">
<IncludeInPackage>true</IncludeInPackage>
</None>
</ItemGroup>
To include the build directory. The alternative is using nuget pack.
When converting the project make sure to leave in the Xamarin import:
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.ObjCBinding.CSharp.targets" />
Here's how my project file looks afterwards:
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
<PropertyGroup>
<PackageId></PackageId>
<PackageVersion>3.3.2</PackageVersion>
<ReleaseVersion>$(PackageVersion)</ReleaseVersion>
<AssemblyVersion>$(PackageVersion)</AssemblyVersion>
<Authors>Nick Brook</Authors>
<Description></Description>
<Copyright></Copyright>
<PackageProjectUrl></PackageProjectUrl>
<Summary></Summary>
<PackageTags></PackageTags>
<Title></Title>
<PackageReleaseNotes>Initial Release</PackageReleaseNotes>
<OutputType>Library</OutputType>
<IPhoneResourcePrefix>Resources</IPhoneResourcePrefix>
<OutputPath>bin\$(Configuration)</OutputPath>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<Optimize>true</Optimize>
<PackageOutputPath>packed</PackageOutputPath>
<PackOnBuild>true</PackOnBuild>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="Xamarin.iOS" />
</ItemGroup>
<ItemGroup>
<ObjcBindingApiDefinition Include="ApiDefinition.cs" />
</ItemGroup>
<ItemGroup>
<ObjcBindingCoreSource Include="Structs.cs" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Structs.cs" Condition=" '$(EnableDefaultCompileItems)' == 'true' " />
<Compile Remove="ApiDefinition.cs" Condition=" '$(EnableDefaultCompileItems)' == 'true' " />
</ItemGroup>
<ItemGroup>
<None Remove="packed\**" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Xamarin.Build.Download" Version="0.4.11" />
<PackageReference Include="NuGet.Build.Packaging" Version="0.2.2" />
</ItemGroup>
<ItemGroup>
<None Update="build\**">
<IncludeInPackage>true</IncludeInPackage>
</None>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.ObjCBinding.CSharp.targets" />
</Project>
I have a solution that has multiple projects, and I'd like them all to be able to access a set of shared properties that have been defined once in a common file at the solution level.
This mostly works fine using the code below and I can use the imported properties in the BeforeBuild target, however the problem I'm having is that I can't use the imported properties in conditions.
So I have the following in a CommonSettings.targets file in the solution folder:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="CommonSettingsTarget">
<PropertyGroup>
<MyCustomProperty>Sample</MyCustomProperty>
</PropertyGroup>
</Target>
</Project>
In my project file I have:
<Project ToolsVersion="14.0" DefaultTargets="Build" InitialTargets="CommonSettingsTarget" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(SolutionDir)CommonSettings.targets" />
<ItemGroup>
<EmbeddedResource Include="EmbeddedDocument.txt" Condition=" '$(MyCustomProperty)' == 'Sample' " />
</ItemGroup>
<Target Name="BeforeBuild">
<Message Text="MyCustomProperty='$(MyCustomProperty)'" Importance="high" />
</Target>
</Project>
In the above, I can see my imported property displayed in the output window as "MyCustomProperty='Sample'" which is great, however when it's used as part of a condition (to optionally include an embedded resource), the condition is never satisfied.
Is there any way to make the imported properties work with conditions?
As your ItemGroup is not within a target, but the PropertyGroup is, the CommonSettingsTarget has not yet been executed when your condition is evaluated and thus MyCustomProperty has not yet been defined.
The Message task is called from within the BeforeBuild target which depends on CommonSettingsTarget and thus MyCustomProperty has been defined when you create the message.
Think of the Import as copying the imported project into your project file. The result would be something like this:
<Project ToolsVersion="14.0" DefaultTargets="Build" InitialTargets="CommonSettingsTarget" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="CommonSettingsTarget">
<PropertyGroup>
<MyCustomProperty>Sample</MyCustomProperty>
</PropertyGroup>
</Target>
<ItemGroup>
<EmbeddedResource Include="EmbeddedDocument.txt" Condition=" '$(MyCustomProperty)' == 'Sample' " />
</ItemGroup>
<Target Name="BeforeBuild">
<Message Text="MyCustomProperty='$(MyCustomProperty)'" Importance="high" />
</Target>
</Project>
This is what happens:
You define a target CommonSettingsTarget which will define MyCustomProperty when it is executed. Not now.
You define the ItemGroup and therefore evaluate the condition. It returns false, because MyCustomProperty has not yet been defined.
You define a target BeforeBuild.
You run the initial target, i.e. CommonSettingsTarget. Now MyCustomProperty is defined.
You run the default target which depends on BeforeBuild and thus runs BeforeBuild. There you evaluate MyCustomProperty which has been defined in step 4.
As a solution, remove the CommonSettingsTarget target and define the PropertyGroup as a child of the Project in CommonSettings.targets instead:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MyCustomProperty>Sample</MyCustomProperty>
</PropertyGroup>
</Project>
In your project file, you should remove the InitialTargets="CommonSettingsTarget" then.
I'm using Jenkins and MSBuild to build our solution and would like to use the command line tool that is bundled with one of our Visual Studio plugins to generate CSS and JavaScript for us. For reasons that I hope are obvious, I'd like to do this using MSBuild and the Visual Studio project file as opposed to having to maintain a separate batch file.
I've got as far as creating a separate .targets file and have got that to run, but I'm struggling when it comes to grabbing the files themselves. I can use a wildcard to grab files from the filesystem, but what I'd really like to do is get a list of files from the project file itself.
Here's a brief version of our project file – I've removed a lot of the 'default' stuff:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- I'll omit all the standard project bits and bobs for brevity -->
<ItemGroup>
<Content Include="css\scss\styles.scss">
<Compile>True</Compile>
<Minify>False</Compile>
<CompileStyle>Nested</CompileStyle>
<DebugInfo>False</DebugInfo>
</Content>
<Content Include="css\scss\_imported-1.scss">
<Compile>False</Compile>
<Minify>False</Compile>
<CompileStyle>Nested</CompileStyle>
<DebugInfo>False</DebugInfo>
</Content>
<Content Include="css\scss\_imported-2.scss">
<Compile>False</Compile>
<Minify>False</Compile>
<CompileStyle>Nested</CompileStyle>
<DebugInfo>False</DebugInfo>
</Content>
</ItemGroup>
<Import Project="$(SolutionDir)\.webcompile\WebCompile.targets" />
</Project>
WebCompile.targets looks like this:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<BuildDependsOn>
$(BuildDependsOn);
WebCompile
</BuildDependsOn>
</PropertyGroup>
<ItemGroup>
<SassFiles Include="**/*.scss" />
</ItemGroup>
<Target Name="WebCompile">
<Message Text="SassFiles: #(SassFiles)" />
</Target>
</Project>
This returns all of the matching *.scss files from the Solution directory, but I'm really interested in just returning files that are already listed in the project file that have the <Compile> child node set to True.
Is this possible?
This returns all of the matching *.scss files from the Solution
directory, but I'm really interested in just returning files that are
already listed in the project file that have the child node
set to True.
You could add a filter to the SassFiles itemgroup where only the members with the appropriate criteria would appear.
<ItemGroup>
<SassFiles Include= "#(Content)" Condition = "'%(Extension)' == '.scss' AND '%(Compile)' == 'true'"/>
</ItemGroup>
#Abit, here is my MsBuild script (saved as "abit.msbuild"):
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="WebCompile" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- I'll omit all the standard project bits and bobs for brevity -->
<ItemGroup>
<Content Include="css\scss\styles.scss">
<Compile>True</Compile>
<Minify>False</Minify>
<CompileStyle>Nested</CompileStyle>
<DebugInfo>False</DebugInfo>
</Content>
<Content Include="css\scss\_imported-1.scss">
<Compile>False</Compile>
<Minify>False</Minify>
<CompileStyle>Nested</CompileStyle>
<DebugInfo>False</DebugInfo>
</Content>
<Content Include="css\scss\_imported-2.scss">
<Compile>False</Compile>
<Minify>False</Minify>
<CompileStyle>Nested</CompileStyle>
<DebugInfo>False</DebugInfo>
</Content>
</ItemGroup>
<Target Name="WebCompile">
<ItemGroup>
<SassFiles Include="#(Content)" Condition="'%(Extension)' == '.scss' AND '%(Compile)' == 'true'" />
</ItemGroup>
<Message Text="SassFiles: #(SassFiles)" />
</Target>
</Project>
This is the command I am running:
%WinDir%\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe abit.msbuild
Here is the output:
Project "d:\msbuild\abit.msbuild" on node 1 (default targets).
WebCompile:
SassFiles: css\scss\styles.scss
Done Building Project "d:\msbuild\abit.msbuild" (default targets).
I'm not seeing any errors due to the condition on the #(SassFiles) ItemGroup, and I believe I'm seeing the correct output.
This is probably a FAQ, but we weren't able to find a solution even after a lot of searching.
We have a number of msbuild files that all operate on the same set of source files. (It's not particularly relevant but they compile to completely different platforms.) To make managing these a little simpler, we'd like to move the <Compile> source file names to a separate file and reference that from all the msbuild files.
We tried cutting the <ItemGroup> containing the <Compile> items and pasting it into a new file, and surrounding it with
<Project DefaultTargets="Build" ToolsVersion="3.5" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
and then referencing that file from the original with
<Import Project="Common.files.csproj" />
but that does not work - the solution opens (with a warning since we hacked the default config), but no items appear in the Solution Explorer.
What are we doing wrong?
Tried with Visual Studio 2010:
1) Create your external .proj (or .target) file and add your files (I used a different item name but that shouldn't matter)
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ExternalCompile Include="Program.cs" />
<ExternalCompile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
</Project>
2) Import your external .proj file at the top of your Visual Studio project file:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="MyExternalSources.proj" />
<PropertyGroup>
...
and modify the Compile ItemGroup like this:
...
<ItemGroup>
<Compile Include="#(ExternalCompile)" />
</ItemGroup>
...
Warning: You'll have to add new items/files to your external .proj file - all items/files added from within Visual Studio will end up like this:
...
<ItemGroup>
<Compile Include="#(ExternalCompile)" />
<Compile Include="MyNewClass.cs" />
</ItemGroup>
...
I've never seen "include" files work with MSBuild. Obviously Targets files work this way, but I haven't seen a partial msbuild file included in another. COuld you use a method such as illustrated in this?
http://msdn.microsoft.com/en-us/library/ms171454(VS.80).aspx
Using wildcards is how I've addressed this in the past.
I am working with Visual Studio 2010. I have directed project output to a specific folder which will contain all the DLLs and EXEs when built. However when I clean the solution, the folder is not getting cleaned, and the DLLs are still present in it.
Can anyone tell me how to handle the clean solution command to clear out the folders I want to clean? I tried working with MSBuild and handling the BeforeClean and AfterClean targets, but it did not provide the desired result.
The answer from Sergio should work but I think it could be cleaner to override the BeforeClean/AfterClean targets. These are hooks into the build/clean process provided by microsoft. When you do a clean, VS do call the targets : BeforeClean;Clean;AfterClean and by default the first and the last do nothing.
In one of your existing .csproj file you can add the following :
<Target Name="BeforeClean">
<!-- DO YOUR STUFF HERE -->
</Target>
You can add to your VS .sln file special target named let's say BuildCustomAction.csproj:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
</PropertyGroup>
<ItemGroup>
<CleanOutCatalogFiles Include="..\..\bin\$(Configuration)\**\*.dll">
<Visible>false</Visible>
</CleanOutCatalogFiles>
<CleanOutCatalogFiles Include="..\..\bin\$(Configuration)\**\*.exe">
<Visible>false</Visible>
</CleanOutCatalogFiles>
</ItemGroup>
<Target Name="Build">
</Target>
<Target Name="Rebuild"
DependsOnTargets="Clean;Build">
</Target>
<Target Name="Clean"
Condition="'#(CleanOutCatalogFiles)'!=''">
<Message Text="Cleaning Output Dlls and EXEs" Importance="high" />
<Delete Files="#(CleanOutCatalogFiles)" />
</Target>
</Project>
Place it everywhere you want and specify relative path to the output catalog for your binaries. Add in VS this project as existing. That's all. With this you can do own custom actions for three common actions in VS: Build, Rebuild, Clean.
There exists more complex way to customize build process using CustomBeforeMicrosoftCommonTargets and CustomAfterMicrosoftCommonTargets but it requires to be very good in MSBuild.
Hope this helps.