MSBuild CL Task output directory - c++

i am writing a MSBuild script which compiles a C++ file using MSBuild CL Task, something like:
<CL Sources="c:\temp\myfile.cpp" />
How do i control where the output (myfile.obj) goes? By default, it goes to the path from where the script is present (and also happens to be the path from where i run the script): i.e. if i run the script (c:\someFolder\build.proj) from "c:\someFolder\" then myfile.obj is placed at "c:\someFolder\myfile.obj".
Going by a wild (illogical) guess, i also tried fidgeting with OutDir property(?!), something like:
<PropertyGroup>
<OutDir>d:\somePlace\<OutDir>
</PropertyGroup>
...
<CL Sources="c:\temp\myfile.cpp" />
Didn't work.

The answer to the original question about how to control the output of the CL task is by using the ObjectFileName argument (as provided by Hans Passant).
However, it now seems that using a minimum standard vcxproj is a better idea (as suggested by both stijn and Hans Passant).

Related

MSBuild - how to tell at compile time if a file exists and use it?

I am using MSBuild (recent), windows 10, to compile a C++ vcxproj file. During the compile, I need to use a giant dependencies folder. If the file exists locally to the build, I want to reference that one. If it doesn't exist locally, I want to use the folder pointed to in a system variable. I would like to set this up somehow in a .props file and include it, but I have no idea where to start.
Ideas? I don't want to use a .BAT file to shell out and set variables.
Have you tried using the Exists condition function? You would have two instances of the variable, one where the condition is true, the other where it is not.
<PropertyGroup>
<MyDependency Condition="Exists('LocalDir')">LocalDir</MyDependency>
<MyDependency Condition="!Exists('LocalDir')">$(REMOTE_DIR)</MyDependency>
</PropertyGroup>
To achieve this you can just use the Exists macro. Furthermore, i suggest that you also do a check for empty string. This allows you to override the default setting on build time:
<PropertyGroup>
<MyDependency Condition="'$(MyDependency)'==''">$(SystemVariable)</MyDependency>
<!-- You can even use regsitry Values as default -->
<MyDependency Condition="'$(MyDependency)'==''">$([MSBuild]::GetRegistryValue('HKEY_Local_Machine\...','KEYNAME')</MyDependency>
<MyDependency Condition="Exists('LocalDir')">LocalDir</MyDependency>
</PropertyGroup>

How do I put a condition on msbuild built-in targets like Build/Rebuild?

I am working differentially building a huge monolithic solution that includes about 80 projects. In my build pipeline right now I include a step to build the entire solution. But what I'd like to do is to build the solution but provide conditions as msbuild arguments so that I can exclude some of the projects that might not have any changes associated with them. I already have scripts to go through my commits and realize what changed and which projects need to be built.
I just need a way to send that info to MSBuild so that it does not build all projects everytime. I tried building projects separately but that takes a whole lot more time than just building the solution together.
So, I'm looking for any solutions out there through which I can specify to MSBuild that skip a specific project would help a lot. Thanks much!
I already have scripts to go through my commits and realize what
changed and which projects need to be built.
Since I could get clearly know that which script are you using to realize what changed and which projects need to be built. I am assuming that you are using MSbuildTarget script which in the xx.csproj to do these judgement.
=If I did not have misunderstanding, you can get help from this similar issue (See ilya's answer).
See this document and you'll find the build action is performed by these three targets, BeforeBuild,CoreBuild and AfterBuild. So assuming you have a target to go through my commits and realize what changed and if a project need to be built, you can add script like below to xx.csproj:
<PropertyGroup>
<BuildWrapperDependsOn>$(BuildDependsOn)</BuildWrapperDependsOn>
<BuildDependsOn>CheckIfBuildIsNeeded;BuildWrapper</BuildDependsOn>
</PropertyGroup>
<Target Name="CheckIfBuildIsNeeded">
<!-- Execute command here that checks if proceed with the build and sets the exit code -->
<Exec Command="exit /b 1" WorkingDirectory="$(SourcesPath)" IgnoreExitCode="true">
<Output TaskParameter="ExitCode" PropertyName="ExecExitCode"/>
</Exec>
<Message Text="Exit Code: $(ExecExitCode)" Importance="high" />
<PropertyGroup Condition="'$(ExecExitCode)' == '1'">
<DoBuild>false</DoBuild>
</PropertyGroup>
</Target>
<Target Name="BuildWrapper" Condition=" '$(DoBuild)' != 'false' " DependsOnTargets="$(BuildWrapperDependsOn)" Returns="$(TargetPath)" />
Above is the script from ilys, and hope my description can help you understand it. With this script, when we start a build target, it will firstly run the targets it depends on, so it will run the CheckIfBuildIsNeeded target and BuildWrapper target. And only when the DoBuild property is true, the BuildWrapper will actually execute. And since buildwrapper depends on original $(BuildDependsOn), it will continue the real build process.
The total logic is: Run CheckIfBuildIsNeeded script and output value to indicates whether need to build=>Try to Run BuildWrapper=>IF need to build, then run the real build success(BeforeBuild, Corebuild,Afterbuild), if the value is false, finish the build process. So I think you can do some little changes to this script then it can work for your situation. (Not sure what your script looks like, I can't complete it for you)
And since you have many projects, you don't need to add this script to every project manually. You can create a Directory.Build.props file, copy the script into it, and place the file in solution folder, then it will work for all projects in the solution.

Set debug/run environment variable in Visual Studio 2017 C++ project?

I'm trying to set automatically run/debug environmental variables for my project in Visual Studio.
I mean, is there any CMake or C++ code line to do this not needing to do it manually?
Here are the instructions how to do it manually (what I want to avoid).
Here there is an still unsolved question about how to do it with Cmake (seems not to be possible).
I also tried with setenv() and putenv() in different ways but it didn't work, because the main function doesn't even run until that line of code, before an error message shows up: "Some.dll was not found" and the program stops.
If your dll is one you are intending to use, this answer details how to quickly ensure it is found at runtime (putting the DLL alongside the executable)
If by 'automatic' you mean in code, you can set environment variables in code using _putenv as described in this answer similar to what you seem to be describing.
ostringstream classSize;
classSize << "classSize=" << howManyInClass;
_putenv(classSize.str().c_str());
The solution I found is base on this answer.
Steps for the solution:
Create a UserTemplate.vcxproj.user file next to the CMakeLists.txt file, with the next content:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LocalDebuggerEnvironment>PATH=..\Your\Path\to\Binaries;%PATH%".</LocalDebuggerEnvironment>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>
Where ..\Your\Path\to\Binaries is the relative path to your binary
files (the two points at the beginning .. are optional, if you
want to go up in the relative directory path, you may want to use
them).
Add the next lines of code in the CMakeLists.txt file.
# Configure the template file
SET(USER_FILE main.vcxproj.user)
SET(OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/${USER_FILE})
CONFIGURE_FILE(UserTemplate.vcxproj.user ${USER_FILE} #ONLY)
Where ProjectName is the name of the VS project where you want to define your PATH variable.

Define user macros in different property sheet

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>

Optional PreBuildEvent in MSBuild?

Is it possible to have an optional <PreBuildEvent> in a *.csproj file? I have the following:
<PropertyGroup>
<PreBuildEvent>git rev-parse HEAD >../../git-hash.txt</PreBuildEvent>
</PropertyGroup>
This outputs the latest git hash to a file, which is embedded in the executable elsewhere.
Since I'm a University student, I'm often writing code on the University machines (and not my linux machine at home) which have SVN and not git, causing the build process to fail. Is it possible to make the above <PreBuildEvent /> optional so that if git isn't installed the build process doesn't fail?
Just skipping the build event would leave you with an empty git-hash.txt so that doesn't seem the best idea. Instead you could just try to run the git command, and if it fails write a dummy hash to the file. I don't know the command line syntax to do that (a PreBuildEvent runs under cmd.exe) so here's an msbuild solution. Because of the BeforeTargets="Build" it will run before the build as well.
<Target Name="WriteGitHash" BeforeTargets="Build">
<Exec Command="git --work-tree=$(Repo) --git-dir=$(Repo)\.git rev-parse HEAD 2> NUL" ConsoleToMSBuild="true" IgnoreExitCode="True">
<Output TaskParameter="ConsoleOutput" PropertyName="GitTag" />
</Exec>
<PropertyGroup>
<GitTag Condition="'$(GitTag)' == ''">unknown</GitTag>
</PropertyGroup>
<WriteLinesToFile File="$(Repo)\git-hash.txt" Lines="$(GitTag)" Overwrite="True"/>
</Target>
Some notes:
The 2> NUL redirects standard error to the output so GitTag will be empty in case of an error, in which case it's set to 'unknown'
Relying on the current directory is nearly always a bad idea so specify the directory to run git in explicitly in a property
Same for the output file