I have a C# project with two platforms: x86 and x64. This C# project depends on a native dll that must also be built as x86 or x64.
So far, I have successfully added cmake as a pre-build event to the .csproj of the C# project:
<Target Name="BeforeBuild">
<Message Text="Building native library" />
<Exec Command="cmake -DINSTALL_DIR=../bin/$(Platform)/$(Configuration) ../src/native" />
<Exec Command="cmake --build . --target install" />
</Target>
This builds and copies the native dll to the output directory of the project, matching the selected configuration (e.g. bin/x86/Debug or bin/x64/Release).
If I use the x86 configuration in Visual Studio, then everything is fine. However, if I use the x64 configuration I get a failure, because the native library is still built as x86. In other words, I need to find a way to inform cmake to build a x64 binary when $(Platform) is 'x64'.
Is there a commandline switch to instruct cmake to built a x64 binary? I tried the -G and -T options, but they don't appear to support this (or I wasn't able to find the correct way to use them).
Ideas welcome!
Edit: I've managed to get a little bit closer by passing the $(VisualStudioVersion) property to cmake.
<PropertyGroup>
<CMakeGenerator Condition="'$(OS)' == 'Windows_NT' and '$(Platform)' == 'x86'">-G"Visual Studio $(VisualStudioVersion)"</CMakeGenerator>
<CMakeGenerator Condition="'$(OS)' == 'Windows_NT' and '$(Platform)' == 'AnyCPU'">-G"Visual Studio $(VisualStudioVersion) Win64"</CMakeGenerator>
<CMakeGenerator Condition="'$(OS)' != 'Windows_NT'"></CMakeGenerator>
</PropertyGroup>
<Target Name="BeforeBuild">
<Message Text="Building native library" />
<Exec Command="cmake $(CMakeGenerator) -DINSTALL_DIR=../bin/$(Platform)/$(Configuration) ../src/native" />
<Exec Command="cmake --build . --target install" />
</Target>
Unfortunately, $(VisualStudioVersion) returns a decimal number (e.g. 12.0 for VS2013), whereas cmake expects an integer (e.g. 12 for VS2013). If I can convert $(VisualStudioVersion) to an integer, then this should work! Can this be done?
Edit 2: solved!
MSBuild 4.0/4.5 adds property functions that can be used to modify properties. In this case, the following works perfectly:
<PropertyGroup>
<CMakeVSVersion>$(VisualStudioVersion.Substring(0, $(VisualStudioVersion).IndexOf(".")))</CMakeVSVersion>
<CMakeGenerator Condition="'$(OS)' == 'Windows_NT' and '$(Platform)' == 'x86'">-G"Visual Studio $(CMakeVSVersion)"</CMakeGenerator>
<CMakeGenerator Condition="'$(OS)' == 'Windows_NT' and '$(Platform)' == 'AnyCPU'">-G"Visual Studio $(CMakeVSVersion) Win64"</CMakeGenerator>
<CMakeGenerator Condition="'$(OS)' != 'Windows_NT'"></CMakeGenerator>
</PropertyGroup>
<Target Name="BeforeBuild">
<Message Text="Building native library" />
<Exec Command="cmake $(CMakeGenerator) -DINSTALL_DIR=../bin/$(Platform)/$(Configuration) ../src/native" />
<Exec Command="cmake --build . --target install" />
</Target>
Hopefully someone might find this useful in the future!
Unfortunately, the Visual Studio generators require the Visual Studio version to be explicitly specified for x64 builds. However, you should be able to make this work with the NMake generator:
<Target Name="BeforeBuild">
<Message Text="Build native library" />
<Exec Command="cmake -G"NMake Makefiles" -DINSTALL_DIR=../bin/$(Platform)/$(Configuration) ../src/native" />
<Exec Command="cmake --build . --target install" />
</Target>
The NMake generator expects to find everything set up correctly on the command line (including path to the appropriate platform compiler), but that's taken care of by the target platform selected in the driving VS.
I don't have a way of testing it right now, so the actual syntax for the project file might differ, but the idea should work.
Related
I'm a newbie trying to modify on publish the ApplicationVersion value by AssemblyVersion one on a MS Office AddIn.
Here is my csproj :
<Target Name="SetAssemblyVersionToPublish" AfterTargets="AfterCompile">
<ReadLinesFromFile File="Properties\AssemblyInfo.cs">
<Output TaskParameter="Lines" ItemName="AssemblyVersion" />
</ReadLinesFromFile>
<PropertyGroup>
<In>#(AssemblyVersion)</In>
<Pattern>\[assembly: AssemblyVersion\(.(\d+)\.(\d+)\.(\d+).(\d+)</Pattern>
<Out>$([System.Text.RegularExpressions.Regex]::Match($(In), $(Pattern)))</Out>
<ApplicationVersion>$(Out.Remove(0, 28))</ApplicationVersion>
</PropertyGroup>
<Message Text="app Version : $(ApplicationVersion)" Importance="High" />
When I publish the app from Visual Studio 2015, logs show the good version :
app Version : 4.4.9.0
But in fact it is the ApplicationVersion defined in VS that is used :
<ApplicationVersion>1.0.0.0</ApplicationVersion>
I already tried :
reset all VS settings
disable any vs third party extensions
use safemode
if I publish a WPF app, it works well
Any one would know why I get this change ?
Update
After some test, I found that MSBUILD use a different target file for VSTO : MSBuild\Microsoft\VisualStudio\v14.0\OfficeTools\Microsoft.VisualStudio.Tools.Office.targets.
It seems to use PublishVersion which is a copy of ApplicationVersion. I don't know why but if I set ApplicationVersion in my target, it does not update the PublishVersion... If I set the publishVersion, I get the good version in my bin folder, but publishing failed (don't copy to publish folder because it still want to get the folder with 1_0_0_0 in bin).
It may be a problem with a bad step which launch my target, but I don't figure when it must be done.
Any help ?
UPDATE 2
It seems to be a bug with VS2015 publishing tool. If I try with msbuild.exe command line, it works well:
On VS I get an error asking for the below folder :
Whereas with the following msbuild command, it works :
MSBuild xxx\ExcelAddIn1\ExcelAddIn1\ExcelAddIn1.csproj /t:clean;publish
Anyone know what can be done as a workaround ?
First of all, I have a question, when I use your code in a winform project and execute publish, I got an error like:
After I test, I found that
ApplicationVersion which you got is illegal three digits instead of four digits, so there is a problem with your method of obtaining AssemblyVersion.
In general, the publish version is under Project Properties(right-click on your project)-->Publish
You can note that it is four digits.
Which proves that you have miss a node on Pattern property.
Suggestion
You should use
<Pattern>\[assembly: AssemblyVersion\(.(\d+)\.(\d+)\.(\d+).(\d+)</Pattern>
The whole code are:
<Target Name="AfterCompile">
<ReadLinesFromFile File="Properties\AssemblyInfo.cs">
<Output TaskParameter="Lines" ItemName="AssemblyVersion" />
</ReadLinesFromFile>
<PropertyGroup>
<In>#(AssemblyVersion)</In>
<Pattern>\[assembly: AssemblyVersion\(.(\d+)\.(\d+)\.(\d+).(\d+)</Pattern>
<Out>$([System.Text.RegularExpressions.Regex]::Match($(In), $(Pattern)))</Out>
<ApplicationVersion>$(Out.Remove(0, 28))</ApplicationVersion>
</PropertyGroup>
<Message Text="app Version : $(ApplicationVersion)" Importance="High" />
</Target>
It will reads the AssemblyVersion from the AssemblyInfo.cs file.
In my side, it is
Actually, your method already works and it overwrite the publish version for the app.
I think you have read the first part of the build output log like this:
It is only the default system initial value at the beginning of the build, and it is just displayed there. And then through your custom msbuild script actually has overwritten its value.
Before executing publish, you should delete the publish folder, bin and obj folder, then execute the publish, you can enter the folder to check:
Update 1
I think your csproj file has imported some targets or props file which has other targets overwrite the AfterCompile target. So your method failed.
That is, your method may be overwritten elsewhere.
So I think you should not use AfterCompile as the target name and should name it as another to distinguish between them.
Use this:
<Target Name="SetAssemblyVersionToPublish" AfterTargets="AfterCompile">
<ReadLinesFromFile File="Properties\AssemblyInfo.cs">
<Output TaskParameter="Lines" ItemName="AssemblyVersion" />
</ReadLinesFromFile>
<PropertyGroup>
<In>#(AssemblyVersion)</In>
<Pattern>\[assembly: AssemblyVersion\(.(\d+)\.(\d+)\.(\d+).(\d+)</Pattern>
<Out>$([System.Text.RegularExpressions.Regex]::Match($(In), $(Pattern)))</Out>
<ApplicationVersion>$(Out.Remove(0, 28))</ApplicationVersion>
</PropertyGroup>
<Message Text="app Version : $(ApplicationVersion)" Importance="High" />
</Target>
Or, You can add a file called Directory.Build.targets file on your project folder
and then add my code on it:
<Project>
<Target Name="SetAssemblyVersionToPublish" AfterTargets="AfterCompile">
<ReadLinesFromFile File="Properties\AssemblyInfo.cs">
<Output TaskParameter="Lines" ItemName="AssemblyVersion" />
</ReadLinesFromFile>
<PropertyGroup>
<In>#(AssemblyVersion)</In>
<Pattern>\[assembly: AssemblyVersion\(.(\d+)\.(\d+)\.(\d+).(\d+)</Pattern>
<Out>$([System.Text.RegularExpressions.Regex]::Match($(In), $(Pattern)))</Out>
<ApplicationVersion>$(Out.Remove(0, 28))</ApplicationVersion>
</PropertyGroup>
<Message Text="app Version : $(ApplicationVersion)" Importance="High" />
</Target>
</Project>
Then, delete bin, obj, publish folder and then republish again to check it.
If the issue still persists, you should try the following suggestions to troubleshoot the issue:
1) Try to reset vs settings by Tools-->Import and Export settings-->Reset all vs settings
2) disable any vs third party extensions under Tools-->Extensions and Updates -->Installed, after that, close VS ,restart your project.
3) you could try devenv /safemode on the Developer Command Prompt for VS2015 to start a pure, initial vs to test your solution.
===============================================
Update 2
The MS Office Excel AddIn project is quite different from the traditional projects. And it is impossible by using this way.
As a workaround, I think you should use msbuild script to publish the project.
1) create a file called PublishExcel.proj
2) add these content on that file:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="SetAssemblyVersionToPublish">
<!--you must specify the full path of the AssemblyInfo.cs from your project -->
<ReadLinesFromFile File="C:\Users\xxx\Documents\Visual Studio 2015\Projects\ExcelAddIn1\ExcelAddIn1\Properties\AssemblyInfo.cs">
<Output TaskParameter="Lines" ItemName="AssemblyVersion" />
</ReadLinesFromFile>
<PropertyGroup>
<In>#(AssemblyVersion)</In>
<Pattern>\[assembly: AssemblyVersion\(.(\d+)\.(\d+)\.(\d+).(\d+)</Pattern>
<Out>$([System.Text.RegularExpressions.Regex]::Match($(In), $(Pattern)))</Out>
<ApplicationVersion>$(Out.Remove(0, 28))</ApplicationVersion>
</PropertyGroup>
<Message Text="app Version : $(ApplicationVersion)" Importance="High" />
<MSBuild Projects="C:\Users\Administrator\Documents\Visual Studio 2015\Projects\ExcelAddIn1\ExcelAddIn1\ExcelAddIn1.csproj" Properties="ApplicationVersion=$(ApplicationVersion)" Targets="Publish">
</MSBuild>
</Target>
</Project>
3) then open Developer Command prompt for VS2015 and then type:
msbuild xxx\xxx\PublishExcel.proj -t:SetAssemblyVersionToPublish
And the publish folder will be under the bin\Debug or Release\app.publish folder.
This function will work for MS Office Excel AddIn project.
I want to use some tools during build that are acquired with nuget. Here is relevant part of csproj file:
<Target Name="AfterBuild" Condition=" '$(Configuration)' == 'Release'">
<GetAssemblyIdentity AssemblyFiles="$(TargetPath)">
<Output TaskParameter="Assemblies" ItemName="myAssemblyInfo"/>
</GetAssemblyIdentity>
<Exec Command="nuget pack MyApp.nuspec -Version %(myAssemblyInfo.Version) -Properties Configuration=Release -OutputDirectory bin\Release -BasePath bin\Release" />
<Exec Command="squirrel --no-msi --releasify bin\Release\MyApp.%(myAssemblyInfo.Version).nupkg" />
</Target>
Namely I want to use Squirrel and NuGet itself (contained in NuGet.CommandLine package) to build an installer. Executables are located in packages\<package name>\tools\*.exe. The lines used in Exec command work in Package Manager Console but Visual Studio can't find the executables during build (error 9009). It there a way to include package tools in current path during build to make them available?
I'm trying to upgrade our TFS server to 2013. We're currently using 2012, but we've also been clinging on to the upgrade template for dear life. With 2013, we'd like to go to the default template and modify it as little as possible.
The problem comes in when you consider that the default template asks you to add each individual .csproj or .sln file that you would like to build. The nice thing about the tfsbuild.proj files is that not only can you build on the server, but you can check out the entire branch and build everything locally, on the command line, by just passing the tfsbuild.proj file to msbuild.exe. Also, developers can own the tfsbuild.proj file without having write access to change the build definition.
What is the replacement for the TFSBuild.proj file in TFS 2013?
My requirements are:
Clean build configuration.
Can easily build everything locally.
What is the solution to this problem in TFS 2013?
Create a wrapper MSBuild .proj that your TFS build definition uses. We use this technique for NuGet package restore, but it can equally be used to chain together multiple solution files.
For local builds you can use msbuild with that .proj wrapper as the target (I just build the .sln file directly as there is only 1).
.proj file (not suggesting that you should use this exact .proj file, just an example)
<PropertyGroup>
<OutDir Condition=" '$(OutDir)'=='' ">$(MSBuildThisFileDirectory)bin\</OutDir>
<Configuration Condition=" '$(Configuration)'=='' ">Release</Configuration>
<SourceHome Condition=" '$(SourceHome)'=='' ">$(MSBuildThisFileDirectory)</SourceHome>
<ToolsHome Condition=" '$(ToolsHome)'=='' ">$(MSBuildThisFileDirectory)tools\</ToolsHome>
</PropertyGroup>
<ItemGroup>
<Solution Include="$(SourceHome)*.sln">
<AdditionalProperties>OutDir=$(OutDir);Configuration=$(Configuration)</AdditionalProperties>
</Solution>
</ItemGroup>
<Target Name="RestorePackages">
<Exec Command=""$(ToolsHome)NuGet\NuGet.exe" restore "%(Solution.Identity)"" />
</Target>
<Target Name="Clean">
<MSBuild Targets="Clean"
Projects="#(Solution)" />
</Target>
<Target Name="Build" DependsOnTargets="RestorePackages">
<MSBuild Targets="Build"
Projects="#(Solution)" />
</Target>
<Target Name="Rebuild" DependsOnTargets="RestorePackages">
<MSBuild Targets="Rebuild"
Projects="#(Solution)" />
</Target>
I have following target on csproj file using VS2012, i want to run "Publish" on the project once the build has finished.
This gives me following error "error MSB4006: There is a circular dependency in the target dependency graph involving target "AfterBuild""
<Target Name="AfterBuild">
<Message Text="Running Publish..." Importance="high"/>
<MSBuild Projects="$(ProjectPath)" Properties="DeployOnBuild=true;PublishProfile=WebDeploy;CreatePackageOnPublish=True;VisualStudioVersion=11.0"/>
</Target>
i have tried replacing the MSBuild step with
<Exec Command="$(MSBuildBinPath)\MSBuild C:\MyProj.csproj /p:DeployOnBuild=true /p:PublishProfile=WebDeploy /p:CreatePackageOnPublish=True /p:VisualStudioVersion=11.0" ContinueOnError="false" />
Doing above results in build/publish being run over and over.
i have tried naming target different, calling it via another target to no avail.
How can i run "Publish" on the project without getting into repeated cycles? can this be done in another way?
If you only build in Visual Studio, then putting something like this into your csproj file (at the end) will work:
<Target Name="Deploy" AfterTargets="Build">
<MSBuild
Projects="$(ProjectPath)"
Targets="WebPublish"
Properties="PublishProfile=LocalDeploy"
/>
</Target>
However, if you build with with MSBuild this will result in a circular dependency. I have not yet figured out a solution that will allow you to publish on build that works in both Visual Studio and MSBuild.
Previously I was building with Visual Studio and TFS Server, which worked fine, but when i moved to GO-CD the following code caused a circular dependency creating packages.
<Target Name="CopyLinkedContentFiles" AfterTargets="Build" DependsOnTargets="PipelinePreDeployCopyAllFilesToOneFolder">
<Copy SourceFiles="%(Content.Identity)"
DestinationFiles="%(Content.Link)"
SkipUnchangedFiles='true'
OverwriteReadOnlyFiles='true'
Condition="'%(Content.Link)' != ''" />
I have several XSLTs used in my ASP.NET web application.
I want these files to be compiled to dll whenever I build the project.
Currently, I'm compiling the xslts manually by invoking xsltc.exe from vs2010 tools command prompt.
How can I add msbuild task for xsltc.exe so that it will generate assembly whenevr i build my project?
I'm using .NET 4.0.
That works but doesn't really wrap the tool in a MSBuild friendly way.
I came up with this (which was good enough to get by).
<!-- The Transform File Names... -->
<ItemGroup>
<XsltcTransform Include="Transform1.xslt">
<!-- And the generated .Net Class name. -->
<Class>Transform1Class</Class>
</XsltcTransform>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- Sadly using $(OutDir) MUST come after the Import of CSharp.targets -->
<PropertyGroup>
<XSLTCOutputDll>$(OutDir)xslts.dll</XSLTCOutputDll>
</PropertyGroup>
<Target Name="FindXSLTC">
<PropertyGroup>
<XSLTC>"$(TargetFrameworkSDKToolsDirectory)xsltc.exe"</XSLTC>
</PropertyGroup>
</Target>
<Target Name="XSLTC" Inputs="#(XsltcTransform)" Outputs="$(XSLTCOutputDll)" DependsOnTargets="FindXSLTC">
<Exec Command="$(XSLTC) /out:"$(XSLTCOutputDll)" #(XsltcTransform -> ' /class:%(Class) %(FullPath) ')" />
</Target>
<Target Name="BeforeResolveReferences" DependsOnTargets="XSLTC">
</Target>
These targets will let you compile multiple transforms into one DLL.
Running XSLTC before "BeforeResolveRefereneces" is necessary so that you can have an assembly reference to the generated DLL.
<PropertyGroup>
<WinSDK>C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin</WinSDK>
</PropertyGroup>
<Target Name="Build">
<Exec Command="%22$(WinSDK)\xsltc.exe%22 /out:$(OutputPath)\_PublishedWebsites\xyzapp\bin\Xslts.dll /class:ABC %22$(MSBuildProjectDirectory)\xyzapp\a.xslt%22 /class:DEF %22$(MSBuildProjectDirectory)\xyzapp\b.xslt%22 /class:GHI %22$(MSBuildProjectDirectory)\xyzapp\c.xslt%22"/>
</Target>