Visual Studio deletes a shared .pch file, and questions about custom build steps - c++

I try to use a shared .pch file, which is compiled in one project and used in others.
However the .pch file is deleted if a .pdb filename of the PCH project differs from .pdb filenames of the other projects.
This page doesn't answer the question: https://devblogs.microsoft.com/cppblog/shared-pch-usage-sample-in-visual-studio/
I don't want to use a same name for all PDBs.
Questions:
1) Why the .pch file is deleted at the start of other projects compilation, which leads to a C1083 error (.pch not found), if PDB names are not equal, not like in that page?
2) I copy pch.pdb and pch.idb files using COPY command, is there a RENAME comand or something, if the copied pch.pdb should be named just like a dependent project's PDB? And where can I find a complete list of Custom Build Step command?
3) I don't understand the purpose of "Additional dependencies" and "Outputs" in Custom Build Step. Can I enter the .pch filename into the dependency list, so it won't be deleted? Does the output list need to contain the dependent project's PDB name, or the pch.pdb, or both?

For some reason (I did this or not) the generated by compiler .pdb file was not $(PlatformToolsetVersion).pdb, but $(ProjectName).pdb . So the copied into other project folders shared .pdb file was pch.pdb in my case, while other projects were expecting different names. And that was triggering a DELETE task in Microsoft.CppCommon.targets , ("Delete the pch file if the pdb file has been deleted."). Instead of changing the output .pdb name I just looked into XCOPY command and made it to change the copied filename to an expected by a specific project (actually then I just added a custom Target with a renaming Copy task right into the project file instead of using the CustomBuildStep calling a xcopy OS's command, as now I learned more about MSBuild).
Then I also changed the generated by Linker output .pdb, just added "Linked" suffix to the name, so there are no conflicts between Compiler's and Linker's PDBs. Not sure if that is a good idea to change the default settings without a big reason.
I guess it's better just to change the Compiler's output PDB to $(PlatformToolsetVersion).pdb , so all projects will use the same name.
That was the first time I had looked into MSBuild and advanced project settings, now it seems to be obvious, that a project using a shared .pdb wants some familiar .pdb name, not a random pch.pdb
Here is my custom Target imported into project files copying the shared .pdb only if it was rebuilt (.idb is not generated in my case):
<Target Name="CopyFreshPchPdb" BeforeTargets="ClCompile"
Inputs="$(PchDir)\pch.pdb"
Outputs="$(IntDir)\$(ProjectName).pdb">
<Message Importance="High" Text="Copying shared pch.pdb" />
<Copy
SourceFiles="$(PchDir)\pch.pdb"
DestinationFiles="$(IntDir)\$(ProjectName).pdb">
</Copy>
</Target>

Did you use the sample code under the github link.
If so, you should download and then use that sample and if you create your own project, you should check your projects carefully.
Borrowing from this tutorial to your project, I think you need to pay attention to whether you have any additional custom targets in your xxx.vcxproj file to delete the PCH file. Therefore, you need to check each xxx.vcxproj file carefully. In vs, there will be no deletion of certain files due to the different .pdb file names of the PCH project and other projects, so check whether there are additional operations of your own.
1) Why the .pch file is deleted at the start of other projects
compilation, which leads to a C1083 error (.pch not found), if PDB
names are not equal, not like in that page?
First of All, make sure that there are no other option to delete PCH file in your projects.
The PCH project is to create a PCH file and the other two projects are to use such file. And every time when you build the two projects(reference the PCH project), and always execute the build of PCH project and then build the two project. So the PCH is always created and later be used in two projects.
Based on it, you should ensure that all three projects create and use the same address for the file.
SharedPCH project
ConsoleApplication1
ConsoleApplication2
In the sample code,the PCH file exists under SharedPchSample\Outputs\Intermediate\Shared\Win32\Debug.
2) I copy pch.pdb and pch.idb files using COPY command, is there a
RENAME comand or something, if the copied pch.pdb should be named just
like a dependent project's PDB? And where can I find a complete list
of Custom Build Step command?
Custom Build Step is under every project-->Properties-->Custom Build Step-->Command Line, and then you can find it.That custom step is just CMD command. And you can execute CMD in that to do extra opertion.
Besides, I guess you want to make those xxx.pdb and xxx.idb be the same name of the project name in order to distinguish one from another. You can right-click on every project-->Properties-->C/C++-->Output Files-->Program Database File Name-->change it and to use $(IntDir)$(ProjectName).pdb. More about Custom Build Steps, you can refer to this link.
I don't understand the purpose of "Additional dependencies" and
"Outputs" in Custom Build Step. Can I enter the .pch filename into the
dependency list, so it won't be deleted? Does the output list need to
contain the dependent project's PDB name, or the pch.pdb, or both?
Additional dependencies is set to use the PCH file's content in the project 1 and 2 which is similar to configuring the address of a reference class library in a c++ project. And I think it might be redundant and since the author has add it which implies that it is well-founded.
And Outputs is the author customized output path, the author changed the output address of the project, and started a new custom output path and a temporary output path.
Actually, the xxx.pch and its pdb and idb file will not be copied into outputpath. So the custom build step is to copied the files into temporary output path. And if you want to copied them into the final outputpath, you can also use these in CustomBuildStep.targets file:
<CustomBuildStep>
<Command>
if EXIST "$(SharedPdb)" xcopy /Y /F "$(SharedPdb)" "$(IntDir)"
if EXIST "$(SharedIdb)" xcopy /Y /F "$(SharedIdb)" "$(IntDir)"
if EXIST "$(SharedPdb)" xcopy /Y /F "$(SharedPdb)" "$(OutDir)"
if EXIST "$(SharedIdb)" xcopy /Y /F "$(SharedIdb)" "$(OutDir)"
</Command>
<Outputs>$(IntDir)vc$(PlatformToolsetVersion).pdb;</Outputs>
<Inputs>$(SharedPdb)</Inputs>
</CustomBuildStep>
And in fact, one project references another project, and the output files of the referenced project are automatically copied to the main project. Perhaps this is because the author's SharePCH project does not generate the pdb and idb files, so those files of the dependent project will not be found in the main project.

I'd like to add that I had a similar situation where a shared .pch file was being deleted but for a different reason related to the .pdb file.
The reason was that the pdb formats were different across the exe and the PCH.lib. The PCH library project has its 'Project Properties -> C/C++ -> General -> Debug Information Format' set to 'C7 compatible (/Z7)'.
When I added a new project exe that depended on the PCH library I had forgotten that new projects default to using 'Program Database (/Zi)' for its 'Debug Information Format'.
So now when the main project is being built and linked with the PCH it would delete the PCH.pch file and complain that the .PCH is missing.
Having all projects with the same matching Debug Information Format was the fix to prevent the PCH from being deleted.

Related

Build specific projects with devenv

I have the following folder structure for a VS2019 solution/project:
Solution_folder\
my_solution.sln
cpp_project\
my_cpp_project.vcproj
ifort_project\
my_ifort_project.vfproj
...
...
and I want to build specific projects from this solution using the command prompt.
Following the answer here, as well as the MS docs guidance
I tried the following:
devenv %path_to_sln_folder%\my_solution.sln /build Release /project .\ifort_project\my_ifort_project.vfproj /projectconfig Release
Also tried other variations according to the documentation (eg reference the name of the project only or pass the absolute path of the project). However, I always get the following error:
The operation could not be completed
Use:
devenv [solutionfile | projectfile | folder | anyfile.ext] [switches]
The first argument for devenv is usually a solution file, project file or a folder.
You can also use any other file as the first argument if you want to have the
file open automatically in an editor. When you enter a project file, the IDE
looks for an .sln file with the same base name as the project file in the
parent directory for the project file. If no such .sln file exists, then the
IDE looks for a single .sln file that references the project. If no such single
.sln file exists, then the IDE creates an unsaved solution with a default .sln
file name that has the same base name as the project file.
Command line builds:
devenv solutionfile.sln /build [ solutionconfig ] [ /project projectnameorfile [
/projectconfig name ] ]
Available command line switches:
/Build Builds the solution or project with the specified solution
configuration. For example "Debug". If multiple platforms
are possible, the configuration name must be enclosed in quotes
and contain platform name. For example: "Debug|Win32".
/Clean Deletes build outputs.
/Command Starts the IDE and executes the command.
/Deploy Builds and then deploys the specified build configuration.
/DoNotLoadProjects Opens the specified solution without loading any projects.
/Edit Opens the specified files in a running instance of this
application. If there are no running instances, it will
start a new instance with a simplified window layout.
/LCID Sets the default language in the IDE for the UI.
/Log Logs IDE activity to the specified file for troubleshooting.
/NoVSIP Disables the VSIP developer's license key for VSIP testing.
/Out Appends the build log to a specified file.
/Project Specifies the project to build, clean, or deploy.
Must be used with /Build, /Rebuild, /Clean, or /Deploy.
/ProjectConfig Overrides the project configuration specified in the solution
configuration. For example "Debug". If multiple platforms are
possible, the configuration name must be enclosed in quotes
and contain platform name. For example: "Debug|Win32".
Must be used with /Project.
/Rebuild Cleans and then builds the solution or project with the
specified configuration.
/ResetSettings Restores the IDE's default settings, optionally resets to
the specified VSSettings file.
/ResetSkipPkgs Clears all SkipLoading tags added to VSPackages.
/Run Compiles and runs the specified solution.
/RunExit Compiles and runs the specified solution then closes the IDE.
/SafeMode Launches the IDE in safe mode loading minimal windows.
/Upgrade Upgrades the project or the solution and all projects in it.
A backup of these files will be created as appropriate. Please
see Help on 'Visual Studio Conversion Wizard' for more
information on the backup process.
Product-specific switches:
/debugexe Open the specified executable to be debugged. The remainder of
the command line is passed to this executable as its arguments.
/diff Compares two files. Takes four parameters:
SourceFile, TargetFile, SourceDisplayName(optional),
TargetDisplayName(optional)
/TfsLink Opens Team Explorer and launches a viewer for the
provided artifact URI if one is registered.
/useenv Use PATH, INCLUDE, LIBPATH, and LIB environment variables
instead of IDE paths for VC++ builds.
To attach the debugger from the command line, use:
VsJITDebugger.exe -p <pid>
I must say that just by removing the part from /project onwards, the build starts ok and finishes without errors, but it is not what I want.
It strikes me as odd, as I believe I'm following the documentation correctly, yet the error message suggests I don't? Also, it doesn't seem to be solution- or project-specific as it's happening with other solutions/projects.
Am I missing anything obvious here?
Thanks

Adding a CSV file to a project in Visual Studio

I am working on a project where I have to read in serveral pre-existing CSV (dog.csv, horse.csv, etc.). I want to know how would I add these file into my project so that I may test to see if my print functions work (the code is written in c++). Would I have to copy and paste the files into the debugging folder or would I place it under the test folder of the project?
You can include the files in your project in whatever (sub)folder you wish by using Right click -> Add -> Existing Item. Then, right-click on each file and choose Properties. Set up "Copy to output directory" to "Copy if newer".
Then after build, your files will be copied into the bin/debug folder.
To read the file, you can just use:
System.IO.File.ReadAllText("dog.csv");
Another possible way is to add a file within project, right click and select properties, and then in Copy to Output Directory, select Copy always. This way, csv file will be automatically copied in your debug and release packages too.
string executableLocation = Path.GetDirectoryName(
Assembly.GetExecutingAssembly().Location);
string csvLocation= Path.Combine(executableLocation, "file.csv");
Above code will read file location from bin directory where your csv file will be stored.
This link should help guide you how to add CSV files to a project.
If you wanted to do a down and dirty way you could just save the CSV's somewhere on your local machine, and then hard code the file path to that location.
Example:
c:\test\Dog.csv and then set that as a variable for whenever you need to read in the csv file.

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.

Compiling C++Builder project on command line

Is there a way to compile a C++Builder project (a specific build configuration) from the command line?
Something like:
CommandToBuild ProjectNameToBuild BuildConfiguration ...
There are different ways for automating your builds in C++Builder (as of my experience, I'm speaking about old C++Builder versions like 5 and 6).
You can manually call compilers - bcc32.exe (also dcc32.exe, brcc32.exe and tasm32.exe if you have to compile Delphi units, resource files or assembly language lines of code in your sources) and linker - ilink32.exe.
In this case, you will need to manually provide the necessary input files, paths, and keys as arguments for each stage of compilation and linking.
All data necessary for compilation and linking is stored in project files and, hopefully there are special utilities, included in the C++Builder installation, which can automate this dirty work, provide necessary parameters to compilers and linker and run them. Their names are bpr2mak.exe and make.exe.
First you have to run bpr2mak.exe, passing your project *.bpr or *.bpk file as a parameter and then you will get a special *.mak file as output, which you can use to feed on make.exe, which finally will build your project.
Look at this simple cmd script:
#bpr2mak.exe YourProject.bpr
#ren YourProject.mak makefile
#make.exe
You can provide the real name of "YourProject.mak" as a parameter to make.exe, but the most straightforward way is to rename the *.mak file to "makefile", and then make.exe will find it.
To have different build options, you can do the following:
The first way: you can open your project in the IDE, edit options and save it with a different project name in the same folder (usually there are two project files for debug and release compile options). Then you can provide your building script with different *.bpr files. This way, it looks simple, because it doesn't involves scripting, but the user will have to manually maintain coherency of all project files if something changes (forms or units added and so on).
The second way is to make a script which edits the project file or make file. You will have to parse files, find compiler and linker related lines and put in the necessary keys. You can do it even in a cmd script, but surely a specialised scripting language like Python is preferable.
Use:
msbuild project.cbproj /p:config=[build configuration]
More specifics can be found in Building a Project Using an MSBuild Command.
A little detail not mentioned.
Suppose you have external dependencies and that the .dll file does not initially exist in your folder
You will need to include the external dependencies in the ILINK32.CFG file.
This file is usually in the folder
C:\Program Files (x86)\Borland\CBuilder6\Bin\ilink32.cfg
(consider your installation location)
In this file, place the note for your dependencies.
Example: A dependency for TeeChart, would look like this (consider the last parameter):
-L"C:\Program Files (x86)\Borland\CBuilder6\lib";"C:\Program Files (x86)\Borland\CBuilder6\lib\obj";"C:\Program Files (x86)\Borland\CBuilder6\lib\release";"C:\Program Files (x86)\Steema Software\TeeChart 805 for Builder 6\Builder6\Include\";"C:\Program Files (x86)\Steema Software\TeeChart 805 for Builder 6\Builder6\Lib\"
You will also need to include the -f command to compile.
In cmd, do:
//first generate the file.mak
1 - bpr2mak.exe MyProject.bpr
//then compile the .mak
2 - make.exe -f MyProject.mak
You can also generate a temporary mak file with another name, as the answer above says, directly with bpr2mak
bpr2mak.exe MyProject.bpr -oMyTempMak.mak

Why does visual studio ignore the tlb filename specified in the project file

I'm in the process of upgrading a Visual C++ 6 project to Visual Studio 2010, and I've been replacing the post-compile steps of copying files to a common location with having the output file put directly in the final location. However, for the *.tlb files that are being generated, there is an option (in project properties -> MIDL -> Output) to specify the filename. When I put the full path there, it looks reasonable in the command line (says /tlb "full\path\to\filename.tlb"). However, when it actually compiles, the file doesn't get put in the right place, and the command that was executed according to the log was /tlb ".\filename.tlb"). I'm hesitant to specify the path as the output directory, because then it will output the XXX_i.c and XXX.h files into that location as well, which isn't what I want.
Is there any way to get Visual Studio to respect the setting I actually put in the option, instead of doing what it wants?
I just had this problem as well and I finally found out why. Even though this question is a bit old, since it's still open I'll post my solution...
In addition to the MIDL settings under the project properties, there's the same settings under the IDL file itself. Just right-click the IDL file -> Properties -> MIDL -> Output.
This did it for me. Seems illogical, though.
I also ran into same situation so I specified the output file as a relative path and it generated the tlb file in the correct location instead of the default location