Can I somehow define environment variables in VisualStudio?
Background:
I have two machines I am developing on, A and B.
On A, Boost is installed in "C:\boost"; on B, Boost is installed in "D:\boost".
I would like to somehow specify the include directory in the project configuration like
%(BoostDir)\include
and define BoostDir separately on each of the two machines.
You can read environment variables and use them. Microsoft has this documented:
<Project DefaultTargets="FakeBuild">
<PropertyGroup>
<FinalOutput>$(BIN_PATH)\myassembly.dll</FinalOutput>
<ToolsPath Condition=" '$(ToolsPath)' == '' ">
C:\Tools
</ToolsPath>
</PropertyGroup>
<Target Name="FakeBuild">
<Message Text="Building $(FinalOutput) using the tools at $(ToolsPath)..."/>
</Target>
</Project>
You can specify BIN_PATH either using a fixed environment variable that even survives reboots or set the value "on the fly" before calling Visual Studio:
#echo off
SET BIN_PATH=C:\Whatever
C:\Programs\VisualStudio\VS.exe
Take this as an example and adopt it to your needs.
Related
After some research, to get VisualStudio to build a project's object files in parallel, one must ensure that project properties MinimalRebuild is off and MultiProcessorCompilation is on. I can configure this in the project file, but is there a way to override these project settings on the command line using msbuild?
In other words, using msbuild from the command line, how would I override MinimalRebuild (/Gm-) to be false and MultiProcessorCompilation (/MP) to be true? The following doesn't seem to work
msbuild /m:7 /p:CL_MPCount=7 /p:MinimalRebuild=false /p:MultiProcessorCompilation=true
As an aside, is /p:CL_MPCOUNT redundant with the MultiProcessorCompilation property? Overall, I'm having trouble finding documentation on what fits the /p option.
In other words, using msbuild from the command line, how would I
override MinimalRebuild (/Gm-) to be false and
MultiProcessorCompilation (/MP) to be true?
CL_MPCount can be overrided by /p:xxx=xxx but MultiProcessorCompilation and MinimalRebuild are not. Just to be clear, It can only be overridden by /p:xxx=xxx(p means property) if it is a property of MSBuild. And the Property usually can be called by $. So I do some tests:
Edit
Test
1)CL_MPCount
This value means Maximum Number of concurrent C++ compilations in VS IDE.You can refer to this.
So I have assigned a value by VS IDE by(Debug->Options->Projects and Solutions->VC++ Project Solutions and set the Maximum Number of concurrent C++ compilations to 2.)
write a custom target like
<Target Name ="Test" AfterTargets="Build">
<Message Importance="high" Text="CL_MPCount is= $(CL_MPCount)">
</Message>
</Target>
Then Build and it shows;
From this we can see that this is a property that belongs to MSBuild.
2)MinimalRebuild
Usually, it means /GM and it usually set in the Properties in a c++ project. l have set it to True by (Right-click on the project-->Properties-->C/C++-->Code Generation-->set Enable Minimal Rebuild to True).
Custom target like
<Target Name ="Test" AfterTargets="Build">
<Message Importance="high" Text="MinimalRebuild is= $(MinimalRebuild)">
</Message>
</Target>
The result is like
From it, the value which set in the VS IDE cannot be available by $(MinimalRebuild) which means it is not a property of MSBuild.
3) MultiProcessorCompilation
It also means /MP and from the document we will find that it is an option of the the compiler not a property of MSBuild. Besides, l did the same as the MinimalRebuild and it is not being output. So it is also not a property of MSBuild.
In addition, l thought MinimalRebuild and MultiProcessorCompilation are the options of MSBuild before. So I type MSBuild -help in Command Line and found that it did not list these parameters at all. So I think these two parameters have nothing to do with MSBuild at all, but are just some of the compiler's options.
Hope it could help you.
I found a way to override both properties at User level. Anyway you may find them helpful (for example for Build host where incremental build is not meaningful at all).
Create these two properties files:
%USERPROFILE%\AppData\Local\Microsoft\MSBuild\v4.0\Microsoft.Cpp.Win32.user.props
%USERPROFILE%\AppData\Local\Microsoft\MSBuild\v4.0\Microsoft.Cpp.x64.user.props
with following content:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup>
<ClCompile>
<MinimalRebuild>false</MinimalRebuild>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<ProcessorNumber>2</ProcessorNumber>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup />
</Project>
Feel free to customize ProcessorNumber to suit your hardware.
Now MSBUild will use above values for all projects.
Is it somehow possible to do following:
branch.prop:
// excerpt
<PropertyGroup Label="UserMacros">
<Branch>Trunk</Branch>
</PropertyGroup>
And another property sheet, common.prop:
// excerpt
<PropertyGroup>
<OutDir>D:\output\$(Branch)\VW$(VW_VERSION)\$(KN_BUILD)\</OutDir>
<IntDir>D:\output\$(Branch)\VS_Output\$(VW_VERSION)\$(KN_BUILD)\$(ProjectName)\</IntDir>
</PropertyGroup>
Problem
The problem is, that I use both property sheets in my project and if I show my projects properties I see that it shows the correct output directory and intermediate directory (like e.g. ' D:\output\Trunk\VW2016\Debug\' ) but when I compile my project it does not work, meaning that the user macro is missing so that logs show lines like following:
Library "D:\output\\VS_Output\2016\Debug\SomeProject\SomeProject.lib" ...
Pay attention to \\ instead of \Trunk\ in the log line!
Is there some way that property sheets work with user macros defined in different property sheets? Something like nesting them e.g. or any other trick?
I want to avoid to define my output directory and intermediate directory in each project manually (which would work)...
NOT WORKING ALTERNATIVE IDEAS
use a prebuild script that reads out the current svn path and setting an environment variable => because the environment variable is only read by VS on VS start, so if the prebuild script changes it VS does not recognise this until it is restarted
Why do I need this
I need this because I'm forced quite often to switch between trunk and a branch to create a hotfix and so want to avoid long build times because of overwriting intermediate / output files...
You can import your branch.prop in common.prop, like this:
<ImportGroup Label="PropertySheets" >
<Import Project="branch.prop"/>
</ImportGroup>
I have a large solution with over 10 projects in it, in C++.
The entire solution is x64 only, except for project P which needs both both x64 and win32 versions ( the proper one is loaded at runtime).
Project P depends on several other projects for lib files: C and H which are compiled into libs.
P has a reference to C and H like so:
<ProjectReference Include="..\C\C.vcxproj">
<Project>{....}</Project>
</ProjectReference>
<ProjectReference Include="..\H\H.vcxproj">
<Project>{....}</Project>
</ProjectReference>
I want to build project P for both platforms.
I chose to do this from a meta-P project, which calls on P like so:
<MSBuild Projects="..\P\P.vcxproj" Properties="Platform=Win32"/>
<MSBuild Projects="..\P\P.vcxproj" Properties="Platform=x64"/>
This allows P to be changed freely by the developers, and then both versions are built at once by building meta-P.
The problem is that when meta-P calls MSBuild on project P the references to C and H are affected by the Solution environment (in which the active platform is always x64).
When it comes to linking the Win32 P to its proper C.lib and H.lib, the open solution configuration kicks in, and studio attempts to link it with the x64 version, and fails.
I temporarily solved it using an exec task in meta-P to run MsBuild.exe directly on P. This ignored the Visual Studio environment properties.
What is the correct solution to have the platform correctly read?
The correct solution is to add an undocumented property called ShouldUnsetParentConfigurationAndPlatform and set it to false.
The only correct place to put it, is within each Project Reference item in the P project, otherwise it gets ignored.
So it ends up looking like this:
<ProjectReference Include="..\C\C.vcxproj">
<Project>{....}</Project>
<Properties>ShouldUnsetParentConfigurationAndPlatform=false</Properties>
</ProjectReference>
<ProjectReference Include="..\H\H.vcxproj">
<Project>{....}</Project>
<Properties>ShouldUnsetParentConfigurationAndPlatform=false</Properties>
</ProjectReference>
This causes Visual Studio to follow through with C's and H's inherited properties, instead of reading them from the Solution environment.
Edit: see useful reference from comment:
https://github.com/Microsoft/msbuild/blob/98d38cb/src/XMakeTasks/AssignProjectConfiguration.cs#L198-L218
I'm not sure you need Meta-P. At work we had a similar issue.
In P, we added an ItemGroup with the two vcxproj :
<CppProjects Include="...\P64.vcxproj">
<Properties>Platform=x64</Properties>
</CppProjects>
<CppProjects Include="...\P32.vcxproj">
<Properties>Platform=Win32</Properties>
</CppProjects>
The Platform meta-data will force the expected platform.
Then add a build dependency in P.csproj with :
<Target Name="BuildCpp" BeforeTargets="Build">
<MSBuild Projects="#(CppProjects)" Properties="Configuration=$(Configuration)" RemoveProperties="Platform" />
</Target>
Has anyone done this? If so, what tools/techniques/approaches did you use?
Is it possible to do with installing the SQL Business Studio Version of Visual Studio?
Thanks in advance!
Got it folks...
1) Install MSBuild Extensions
2) Created a Build.Xml file as so...
<Project ToolsVersion="3.5" DefaultTargets="Default" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\ExtensionPack\MSBuild.ExtensionPack.tasks"/>
<Target Name="Default">
<PropertyGroup>
<OutputRoot>../../../build-artifacts</OutputRoot>
</PropertyGroup>
<ItemGroup>
<SSISProjectFile Include="SSISProject.dtproj"/>
<SSISProject Include="#(SSISProjectFile)">
<OutputDirectory>$(OutputRoot)</OutputDirectory>
</SSISProject>
</ItemGroup>
<ItemGroup>
<Namespaces Include="Mynamespace">
<Prefix>DTS</Prefix>
<Uri>www.microsoft.com/SqlServer/Dts</Uri>
</Namespaces>
</ItemGroup>
<MSBuild.ExtensionPack.Xml.XmlFile
TaskAction="UpdateElement"
File="EnclarityDataImport.dtsx"
XPath="//DTS:Property[#DTS:Name='ConfigurationString']"
InnerText="$(MSBuildProjectDirectory)\EnclarityDataImport.dtsConfig"
Namespaces="#(Namespaces)"/>
<MSBuild.ExtensionPack.SqlServer.BuildDeploymentManifest InputProject="#(SSISProject)"/>
</Target>
The only trick was the last part of the build here. By default visual studio adds the absolute path to your config and connection string files for your dtsx package. Team City will use these in conjunction with MSBuild extensions to build the package so a local path will break the build because the paths to the build directories in Team City are automatically generated. So using the code above and the $(MSBuildProjectDirectory) you can twiddle the value of the path on your dtsx file so that it points to the path where your compilation is exectuing.
Like booyaa says SSIS projects don't need to be compiled, but what i have done is make the .dtconfigs configurable by the build/deployment process.
I do this so that i can run the packages on deployment in different environments. So the build will copy a template of the dtconfig file.
this contains tokens- $(Servername) $(ConnectionString)
And then i do the replacement on deployment and then execute by wrapping the dtexec in an command.
Not sure about 2012.
I've read about the use of "Custom.Before.Microsoft.Common.targets" and "Custom.After.Microsoft.Common.targets" in order to execute a custom target before/after every project build and I would like to use this technique in order to change version info while building on our TeamCity build server.
The problem is that although it works for C# projects, it doesn't seem to work for native C++ projects.
After some digging around in the Microsoft.Cpp.targets file I found out that for native C++ projects this seems to be implemented through setting $(ForceImportBeforeCppTargets) and $(ForceImportAfterCppTargets).
I can't seem to find a single piece of information on the web about this technique for native C++ apps though, so I'm asking if I'm looking in the right direction or not.
Any help is appreciated.
For VC++ projects it is a bit different. You define a file to be imported either at the beginning or at the end of the project. To use this approach you need to define values for the properties ForceImportBeforeCppTargets or ForceImportAfterCppTargets. For example if you want a file to be included at the beginning of the project you can pass in the value at the command line. For example I just created a dummy VC++ project named CppTets01. Then I created the two sample files below.
Before.proj
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="CustomTargetInBefore" AfterTargets="Build">
<Message Text="From CustomTargetInBefore" Importance="high"/>
</Target>
</Project>
After.proj
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="CustomTargetInAfter" AfterTargets="Build">
<Message Text="From CustomTargetInAfter" Importance="high"/>
</Target>
</Project>
Then I executed the following command:
msbuild CppTest01.vcxproj
/p:ForceImportBeforeCppTargets="C:\Temp\_NET\ThrowAway\CppTest01\CppTest01\Before.proj";
ForceImportAfterCppTargets="C:\Temp\_NET\ThrowAway\CppTest01\CppTest01\After.proj"
The result was
C:\Temp_NET\ThrowAway\CppTest01\CppTest01>msbuild CppTest01.vcxproj /p:ForceImportBeforeCppTargets="C:\Temp_NET\ThrowAway\CppTest01\C
ppTest01\Before.proj";ForceImportAfterCppTargets="C:\Temp_NET\ThrowAway\CppTest01\CppTest01\After.proj"
Microsoft (R) Build Engine Version 4.0.30319.1
[Microsoft .NET Framework, Version 4.0.30319.1]
Copyright (C) Microsoft Corporation 2007. All rights reserved.
Build started 10/18/2010 8:32:55 AM.
Project "C:\Temp\_NET\ThrowAway\CppTest01\CppTest01\CppTest01.vcxproj" on node 1 (default targets).
InitializeBuildStatus:
Creating "Debug\CppTest01.unsuccessfulbuild" because "AlwaysCreate" was specified.
ClCompile:
All outputs are up-to-date.
All outputs are up-to-date.
ManifestResourceCompile:
All outputs are up-to-date.
Link:
All outputs are up-to-date.
Manifest:
All outputs are up-to-date.
FinalizeBuildStatus:
Deleting file "Debug\CppTest01.unsuccessfulbuild".
Touching "Debug\CppTest01.lastbuildstate".
CustomTargetInBefore:
From CustomTargetInBefore
CustomTargetInAfter:
From CustomTargetInAfter
Done Building Project "C:\Temp\_NET\ThrowAway\CppTest01\CppTest01\CppTest01.vcxproj" (default targets).
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:00.21
As you can see from the output the targets were successfully injected into the build process. If you want to relate this back to Custom.Before.Microsoft.Common.targets and Custom.Before.Microsoft.Common.targets then you should know that the technique used there is a bit different. Specifically if you create those files they are automatically imported into every C#/VB.NET project. In this case you have to set this property. You really have two options here:
You can set this property as an environment variable
You can use another technique, ImportBefore & ImportAfter which is specific to VC++
For #1 let me explain a bit. In MSBuild when you access a property with the syntax $(PropName) then if a property with the name PropName doesn't exist MSBuild will look up in the environment variables to see if such a value exists, if it does then that value is returned. So if you have a build server in which you want to include a file for each VC++ build, then just create those properties as environment variables. Now for the other technique.
ImportBefore/ImportAfter
In VC++ a new concept is introduced. In Microsoft.Cpp.Win32.targets you can see the declaration at the top of the .targets file.
<Import Project="$(VCTargetsPath)\Platforms\Win32\ImportBefore\*.targets"
Condition="Exists('$(VCTargetsPath)\Platforms\Win32\ImportBefore')" />
Then there is one towards the bottom
<Import Project="$(VCTargetsPath)\Platforms\Win32\ImportAfter\*.targets"
Condition="Exists('$(VCTargetsPath)\Platforms\Win32\ImportAfter')" />
A similar import declaration exists for the other target platforms as well. Take a look at the files at %ProgramFiles32%\MSBuild\Microsoft.Cpp\v4.0\Platforms\ for the specific names.
With this technique if you want a file to be imported then simply create a file that ends with .targets and place it into the appropriate folder. The advantage of this is that it will be imported into every VC++ build for that platform, and that you can create many different files. The drawback is that you have to place them in those specific folders. That's the main difference between both techniques. With this first technique you can specify the file location via property and its not automatically included for every build, but for the second approach it is but you cannot change the location
You can also add project content into one of *.props files from directory %LOCALAPPDATA%\Microsoft\MSBuild\v4.0\
It make same effect.