Inconsistent path case causes "Error - could not find any files to build in any projects"

18 views
Skip to first unread message

Julien Guertault

unread,
Dec 20, 2018, 10:39:12 PM12/20/18
to Runtime-Compiled C++
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:
  1. pFilename:"..\\..\\src\\meshes\\Viaduct.cpp"
  2. After GetCleanPath(): "..\\..\\src\\meshes\\Viaduct.cpp"
  3. 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:
  1. After concatenation: "d:\\ctrl-alt-test\\h2o\\src\\meshes\\Viaduct.cpp"
  2. After DelimitersToOSDefault(): "d:\\ctrl-alt-test\\h2o\\src\\meshes\\Viaduct.cpp"
  3. 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,

Doug Binks

unread,
Dec 21, 2018, 5:26:48 AM12/21/18
to Runtime-Compiled C++
I can think of a couple of things off the top of my head. One is that you might not have the Visual Studio option /FC set, which controls __FILE__ macro expansion (see the wiki page on project setup). The other is I recall seeing this and solving it so an updated version of RCC++ might help if /FC doesn't (the solution might have been to add /FC to the project, so an update might not help).

Ill also look into seeing if I can fix or imrpove this. If the problem is /FC I'll look into whether it's possible to detect that this isn't set and emit a warning, and since it seems RCC++ FindFile() works fairly well here it might be just that the logic needs improving to be more robust when /FC isn't set.

Julien Guertault

unread,
Dec 21, 2018, 8:10:02 AM12/21/18
to Runtime-Compiled C++
Friday, December 21, 2018 at 7:26:48 PM UTC+9, Doug Binks :
I can think of a couple of things off the top of my head. One is that you might not have the Visual Studio option /FC set, which controls __FILE__ macro expansion (see the wiki page on project setup). The other is I recall seeing this and solving it so an updated version of RCC++ might help if /FC doesn't (the solution might have been to add /FC to the project, so an update might not help).

Ill also look into seeing if I can fix or imrpove this. If the problem is /FC I'll look into whether it's possible to detect that this isn't set and emit a warning, and since it seems RCC++ FindFile() works fairly well here it might be just that the logic needs improving to be more robust when /FC isn't set.

Well spotted!
It was indeed the /FC option that I had lost. Putting it back fixed the problem. Thank you!

As a test, I also tried adding foundFile.ToOSCanonicalCase(); as a last instruction at the end of FindFile().
In my case this too seemed to fix the problem, but I only quickly tested one case.

Cheers,

Doug Binks

unread,
Dec 21, 2018, 8:23:08 AM12/21/18
to Runtime-Compiled C++
Glad that fixed it - and your fix in FindFile() sounds a good option so I'll try it and run some tests.

In general the /FC option is better for when the executable is not in a subdirectory of the source, as FindFile() has problems locating the root directory then.
Reply all
Reply to author
Forward
0 new messages