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

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.

Related

Where exactly is macro $(VCTargetsPath) defined?

We had a discussion before.
https://social.msdn.microsoft.com/Forums/vstudio/en-US/e04e7791-c0c4-4598-b900-310878f5af45/how-can-i-locate-and-change-the-vctargetspath-variable?forum=msbuild
After hours searching .props files, all the $(VCTargetsPath) in .prop and .targets are deleted, but Visual Studio can still recognize this macro/variable correctly.
By modifing Microsoft.Cpp.ToolsetLocation.props, $(VCTargetsPath) can be modified and in consequence VS can no longer create new project.
So, where exactly this macro defined?
I believed that this macro is not and shouldn't be hardcoded.
Where exactly is macro $(VCTargetsPath) defined?
Actually, VCTargetsPath property is defined in the MSBuild system props or targets files under MSBuild folder(C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild). And the files are nested and related to each other. Therefore, the values of various properties are referred to each other in the level-by-level files, and the value of VCTargetsPath is no exception.
==========================================================================
MSBuild is actually equivalent to soft coding. Once MSBuild is installed, it exists as a bunch of dlls and various established props and targets files. You can modify its properties or extend its functions in various ways in the props or targets file. The MSBuild itself is an open source build tool. It is not as unchangeable as you think.
==========================================================================
The VCTargetsPath is actually defined in the msbuild props file called Microsoft.Cpp.ToolsetLocation.props as you said.
It's just that the various targets and props files in MSBuild are nested and interrelated. VCTargetsPath is set as the value of _VCTargetsPathForToolset property while _VCTargetsPathForToolset is defined in another associated targets or props file.
In general, use <import projects="xxxx\xxx.props or targets" /> to embed another file in the current targets or props file.
And there are so many files in MSBuild that if you want to search layer by layer until you find the final specific value, it might seem a little complicated.
Besides, VCTargetsPath is the path of some tools used by MSBuild to compile c++ projects.
The default value in VS2019 is C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VC\v160.
You can write a custom target in the xxx.vcxproj file to output its value.
1) write this in xxx.vcxproj file:
<Target Name="test123" AfterTargets="Build">
<Message Importance="high" Text="$(VCTargetsPath)"></Message>
</Target>
2) Then rebuild your project and you can see this:
It is the MSBuild system defined path. If you change it easily, it will cause the project to fail to compile, unless you have a set of self-defined system similar to MSBuild to build C++ projects, and then put it in new path, let the new path overwrite VCTargetsPath property.
In addition, I am curious why you want to find the lowest VCTargetPath value. If you want to know the principle of it, the above answer explains it.
And if you want to overwrite its value, you can just create an environment system variable called VCTargetsPath directly, and then set its value to a new one.
Restart VS to enable such new value. It is much easier than modifying the targets file.

ResolveAssemblyReference cannot find dll and I cannot force it to look where it is

I have solution with n csharp projects and cpp project on top, this cpp provides interfaces and headers so those csharp ones can be used in other cpp solutions.
The build machine is configured to build csharp project with anyCPU architecture so it provides single assembly per build in Solution\bin\Release. For cpp the anyCpu is not available so I build project twice and store assemblies in Solution\bin\Release\x86 and x64 folders.
This is all to get it packaged in nuget as a single package with .targets file to ease consumption in other cpp projects.
Issue is that cpp project is looking for csharp asseblies using ResolveAssemblyReference and cannot find it, giving missleading message:
ResolveAssemblyReferences:
Primary reference "Implementation".
Could not find dependent files. Expected file "C:\Jenkins\Workspace\Solution\bin\Release\x86\Implementation.dll" does not exist.
Could not find dependent files. Expected file "C:\Jenkins\Workspace\Solution\bin\Release\x86\Implementation.dll" does not exist.
Resolved file path is "C:\Jenkins\Workspace\Solution\bin\Release\x86\Implementation.dll".
Reference found at search path location "".
I tried to alternate ResolveAssemblyReferences behaviour using command line properties, custom targets/properties, but without any luck. The parameters described in https://learn.microsoft.com/en-us/visualstudio/msbuild/resolveassemblyreference-task?view=vs-2017 seem to be computed during the build process and I cannot inject any value, which should be in this case something like $(OutDir)..
The one feasable solution seems to be copy c# dlls into each cpp folder, but I dont think it is the way to solve it properly.
Closes I got is by using /p:ReferencePath like below:
"C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\MsBuild\15.0\bin\MsBuild.exe" /p:BuildProjectReferences=false /p:Configuration=Release /p:DebugType=full /p:DebugSymbols=true /p:PlatformToolset=v120 /p:WindowsTargetPlatformVersion=8.1 /p:ForceImportBeforeCppTargets="C:\Jenkins\Workspace\Solution\Cpp.props" /p:OutDir="C:\Jenkins\Workspace\Solution\bin\Release\x86\" /p:Platform=Win32 /t:Build Interface\Interface.vcxproj /p:ReferencePath="C:\jenkins\workspace\Solution\bin\Release"
My custom Cpp.props does:
<Target Name="Output" BeforeTargets="ResolveAssemblyReferences">
<Message Text="AssemblySearchPaths: $(AssemblySearchPaths)" />
</Target>
and by adding /p:ReferencePath it got added to AssemblySearchPaths as second record, after {CandidateAssemblyFiles}; but it is still not finding those dlls

C++ Windows Driver MSB3030 could not copy the file '' because it was not found

VS2017, SDK/WDK, C++ project
we have a c++ solution (driver) that is shared across developers via Team Foundation Services - visualstudio.com (now called azure devops?).
When I perform a get latest source code, and want to rebuild the solution I get two MSB3030 errors:
"Could not copy the file "C:\path of my colleague his file" because it was not found."
I found it strange that I saw on one of the two errors a path of my colleague his pc. He works on C:\ I'm working on E:\
Unloading the project, I saw he path being set here:
<ItemGroup>
<FilesToPackage Include="C:\path of my colleague\foo.xml" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<PackageRelativeDirectory>
</PackageRelativeDirectory>
</FilesToPackage>
We cannot get this solution to build because of the MSB3030. First we have to clean the specific projects individually, rebuild it, then build another project etc.. a few steps to perform manually in the correct order , trial and error, drinking coffee, throwing bananas to the pc and praying that a monkey outputs the code correctly.
Has anyone seen somehting similar regarding MSB3030 errors?
On my pc I see the path of my colleague, but he doesn't see my path (strange!).
C:\Program Files (x86)\Windows
Kits\10\build\WindowsDriver.common.targets(1699,5): error MSB3030:
Could not copy the file 'C:...' because it was not found.
I've set the Any CPU to x64 because it doesn't make any sense for c++.
C++ Windows Driver MSB3030 could not copy the file '' because it was not found
The reason for this issue is that the path of the ItemGroup is an absolute path in the project file:
<ItemGroup>
<FilesToPackage Include="C:\path of my colleague\foo.xml" ...>
...
</FilesToPackage>
</ItemGroup>
Regardless of whether your colleague has added this file to source control, when you pull the code from the TFS server to your local and put the code in a different local folder, the absolute path will bring you a lot of trouble, you need to manually check the code on the TFS server for this file and you need to modify the absolute path of this file in your project. But this problem will reappear after your colleague updates after you submit your code. Because an absolute path cannot be assigned to two different paths C:\ and E:\.
To resolve this issue, you need to change the absolute path to a relative path in the source code. Generally, we prefer to add this file to the Solution/Project folder, then use the MSBuild Macros $(SolutionDir)/$(ProjectDir) to specify it.
Check Common macros for build commands and properties for some more details.
Hope this helps.

How to efficienlty get all include paths in MSVC2013

I'm tyring to refactor my code using include-what-you-use, but I need to figure out exactly which directories VS is looking in.
How do I get a listing of all include paths visible to files in my project?
If I add an incorrect include, something like "#include " I get the listing I want, but I can't copy and paste the damn thing! (and OCR doesn't seem to work).
How do I get this list?
Copy/pasting from the dialog is ok if you want to do this once manually but doesn't scale well. Since you tagged this msbuild, here's a solution using it. Create a file names showincludes.targets and paste this msbuild code:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="ShowIncludes">
<Message Text="$(Include);%(ClCompile.AdditionalIncludeDirectories)"/>
</Target>
</Project>
Now to get the list of includes for any project file use
msbuild \path\to\vcxproj /p:ForceImportAfterCppTargets=\path\to\showincludes.targets /t:ShowIncludes
This will import said file into the project give, so it has access to all properties, and print out the value of the INCLUDE environment variable which is by default used by the compiler, and also the value of AdditionalIncludeDirectories which is passed to the compiler by msbuild.

MSBuild: Custom.After.Microsoft.Common.targets for native C++ projects in VS2010

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.