Where exactly is macro $(VCTargetsPath) defined? - c++

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.

Related

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.

CMake: How to add a .obj 3d models to C++ Visual Studio UWP project

I'm trying to add a 3d model to the resources of an Appx in a cmake build. I have it successfully working with most formats, but files ending in .obj are being treated as compiled object files.
The cmake Visual Studio generator seems to always treat any file with an extension .obj as an object file and adds it to the vcxproj with the tag.
Is there a way to change the internal type of a file that cmake is using? Can I specify that this file is NOT an "EXTERNAL_OBJECT"?
Setting the VS_DEPLOYMENT_CONTENT to 1 doesn't help.
Adding it to the RESOURCES property doesn't help.
It looks like it might be an issue in the cmake source code itself where it checks if a file type if EXTERNAL_OBJECT before checking any other flags or types, and I can't figure out how to unset that type.
As per this issue on the cmake gitlab repo https://gitlab.kitware.com/cmake/cmake/issues/18820, there is a hacky fix solution but no "correct" fix yet.
Brad King:
As a very hacky not very futureproof workaround that abuses current implementation details, try:
get_property(loc SOURCE myfile.obj PROPERTY LOCATION)
set_property(SOURCE myfile.obj PROPERTY EXTERNAL_OBJECT 0)
The first line forces this code and therefore this code to run, causing CMake to initialize the EXTERNAL_OBJECT property earlier than it normally would. Once that is done then we can set the property back to 0.
A possible fix would be to teach the latter code (in CheckExtension) to not set the EXTERNAL_OBJECT property if it is already set. We can't change the default behavior of treating .obj files as objects to link, but we can at least make an explicit property setting work without the above hack.
I have confirmed that this works for the .obj files in our solution.

How can I make a custom MSBuild Target's execution dependent on a file's time stamp?

The C++ project I'm working on (which I converted from VS2008 to VS2010) used to use several vcbuild .rules files to specify custom build rules. These .rules files had a specific "AdditionalDependencies" property for the CustomBuildRule node which specified a list of files that the should be taken into account when working out if the target needs rebuilding or not. These "AdditionalDependencies" were faithfully carried over into the corresponding .props file during the VS2010 conversion.
The .targets file associated with the custom build rule does add these AdditionalDependencies to the Inputs property of the Target node. This ensures that the target gets executed in case any of the files listed in the dependencies doesn't exist, but it does not execute the target if one of the dependencies is newer than the target's output. It's also not quite logically correct as not all of the files are actually inputs, several of them refer to executables that might be used during the target's build. As such, they might be checked into version control and will be present, but a newer version of the file needs to trigger a rebuild of the affected target.
The MSDN documentation for the Target node shows a Condition property which should work fine for my requirements, but the conditions supported by this property don't appear go past the 'Exists' test that is already being performed.
Is there a condition that I can use which will compare two files' time stamps (or ideally, the time stamp of the files currently listed in AdditionalDependencies against the Target's output files) and thus allow me to trigger a make-like "rebuild this target if it is out of date these dependencies"?
Please take a closer look to the target Output property:
"MSBuild can compare the timestamps of the input files with the timestamps of the output files and determine whether to skip, build, or partially rebuild a target. In the following example, if any file in the #(CSFile) item list is newer than the hello.exe file, MSBuild will run the target; otherwise it will be skipped:"
<Target Name="Build"
Inputs="#(CSFile)"
Outputs="hello.exe">
<Csc
Sources="#(CSFile)"
OutputAssembly="hello.exe"/>
</Target>
The original article and more information about incremental builds with MSBuild can be found here.

How to delete dlldata.c during clean build in Visual Studio?

I will be creating a series of projects set up to build COM objects. I attempting to create a property sheet (.vsprops file) which will set up the builds for each project. One of the things I am doing with the properties file is customizing the location and names of the files created by the MIDL compiler. Here's the code I use for this:
<Tool
Name="VCMIDLTool"
TypeLibraryName="$(InputName).tlb"
OutputDirectory="$(RPCDIR)"
HeaderFileName="$(InputName).h"
DLLDataFileName="$(InputName)_dlldata.c"
InterfaceIdentifierFileName="$(InputName)_i.c"
ProxyFileName="$(InputName)_p.c"
/>
RPCDIR is a macro defined before this section of the property file. This works great for compiling the code. When I build my project, these five files are created with the correct names in the location I specified in the RPCDIR macro. My problem is when I try to clean the build. The clean successfully deletes four of the files, but the DLL Data File does not get deleted. I'm especially confused that some are deleted and one is not - I would have thought that either they would all be deleted or none be deleted rather than a split like this.
Does anyone know how I can customize the clean build to correctly delete these files? Optimally any changes I need to make would be in the property sheet so that I can share it with other projects, but if that's not possible then I'd like to at least be able to do it in the project file. Thanks in advance for any help you can offer!
Not your problem, it is a bug in the build system. The dlldata.c file doesn't get deleted using a regular build either. There aren't enough diagnostics available in the msbuild .log files to see what target fumbles this. I'm guessing it has something to do with the <FilePatternsToDelete> item in the Microsoft.CppClean.targets file.
I recommend you report this problem at connect.microsoft.com