Hello Doug,
I have been happily using your library for three years now, and it has been extremely helpful. Thank you for that.
Recently I started to reorganize the build configurations of my projects in
Visual Studio. In doing so I apparently broke something and RCC++ stopped working: when a file is modified, a recompilation is triggered as usual, but it immediately fails with
"Error - could not find any files to build in any projects". The apparent cause is the case of path of the file to recompile doesn't match between initialization and the recompilation event.
Disclaimer: I am using a three years old version of RCC++. However I didn't notice significant changes in the code where the problem manifests itself. I only started investigating what was going on, but because of how peculiar the error is, I thought I'd share my findings so far.
The behavior I see is the following:
I looked at what happens to one specific file. The actual path to that file, as obtained in
Windows Explorer with
"Copy as path" (in the extended context menu, with shift+right click on the file), is:
"D:\Ctrl-Alt-Test\H2O\src\meshes\Viaduct.cpp"Let's call it "ground truth". :)
1. Upon application launch, RCC++ is initialized.
The values in
RuntimeObjectSystem::SetupRuntimeFileTracking() are:
- pFilename:"..\\..\\src\\meshes\\Viaduct.cpp"
- After GetCleanPath(): "..\\..\\src\\meshes\\Viaduct.cpp"
- After FindFile(): "D:\\Ctrl-Alt-Test\\H2O\\src\\meshes\\viaduct.cpp"
This path is correct, although note how the directory path has the same case as the ground truth, but the file name is lowercase.
It is added to project.m_RuntimeFileList by AddToRuntimeFileList().
Before "// step 1" of RuntimeObjectSystem::FindFile(), all paths (requestedDirectory, filename, foundFile) are transformed to canonical case.
However in "// step 2", m_FoundSourceDirectoryMappings contains paths with decorated case.
After breaking out, the resulting foundDir it is concatenated with the canonical case filename: foundFile = foundDir / filename;
Therefore, the function FindFile() returns a path that is a mix of raw case and converted case.
2.
FileChangeNotifier::Watch() converts the case of the path and inserts the listener at the key
"d:\\ctrl-alt-test\\h2o\\src\\meshes\\viaduct.cpp" of the map.
3. Upon modification of the file,
WatchCallback() is called.
The value of the local variables are:
- pWatch.mDirName: "d:\\ctrl-alt-test\\h2o\\src\\meshes"
- pNotify->FileName: "Viaduct.cpp"
Note how the directory path is now lowercase, but the file name has the same case as the ground truth.
4. Inside
FileChangeNotifier::handleFileAction() the complete path is constructed:
- After concatenation: "d:\\ctrl-alt-test\\h2o\\src\\meshes\\Viaduct.cpp"
- After DelimitersToOSDefault(): "d:\\ctrl-alt-test\\h2o\\src\\meshes\\Viaduct.cpp"
- After ToOSCanonicalCase(): "d:\\ctrl-alt-test\\h2o\\src\\meshes\\viaduct.cpp"
Note how it's entirely lowercase.
This path is added to m_changedFileList.
5. Finally
RuntimeObjectSystem::OnFileChange() tries to find what this path corresponds to.
- On one side it has a filelist which contains: "d:\\ctrl-alt-test\\h2o\\src\\meshes\\viaduct.cpp"
- On the other side is has a m_RuntimeFileList which contains: "D:\\Ctrl-Alt-Test\\H2O\\src\\meshes\\viaduct.cpp"
The std::find() doesn't find a match. :-(
So this is where I am so far. Since I never had this problem before, I suspect I might have introduced inconsistent compilation parameters, or some problem of a similar kind. I will try to confirm that by looking deeper into how the path is obtained, and see if there is a macro or some conditional code that goes into the wrong branch. However it is starting to look to me like there is a bug in
FindFile().Until then, I wish you good end of year holidays.
Regards,