VS: Relative Paths in Generated Visual Studio Files, Again
The generated "*.vcxproj.filters" files have absolute paths in them for the "Include
" attribute of "ClInclude
" (the tag for each referenced file). This fact has been raised in various places a few times as an issue (e.g. (1), (2), (3)). Each time, the motivation has been because the user wanted to redistribute project files. The concern has therefore been dismissed because CMake's model is for project files to be regenerated instead of redistributed.
What seems to have escaped notice, however, is that there are better reasons to use relative paths.
As it happens, I have a motivating example I'd like to raise. In the large projects CMake is good at managing, it happens that there are files with the same filename in different directories. In projects with thousands of source files, it is not reasonable to ensure all names are distinct, even if you wanted to do that. Moreover, note that there are good reasons to do this—for example, separate but analogous implementations for different platforms.
Nevertheless, Visual Studio, in its infinite wisdom, dumps all built objects into the same directory by default, leading to (silent!) breakage. The only way to solve this (e.g. (4) (5)) is to set "Configuration Properties -> C/C++ -> Output Files -> Output File Name" to something like "$(IntDir)\%(RelativeDir)\%(Filename).obj
".
The problem is that the file-varying macro "%(RelativeDir)
" is essentially a synonym for the directory of the "Include
" attribute of each file referenced in the "*.vcxproj.filters" file. If you use the Visual Studio GUI to add files instead of CMake, the paths will indeed be written into that file as relative paths. However, CMake writes an absolute path, breaking everything. From this behavior, we can see that Microsoft's definition of that field is that it is relative. This can be proved by looking at Microsoft's specification (6):
%(RelativeDir) Contains the path specified in the
Include
attribute, up to the final backslash (\).
However, CMake is violating that assumption, and it is only an accident that absolute paths, shoved into the location meant for relative paths, happen to work most of the time. As we see, it doesn't work in this use-case.
While I appreciate the bravery of using absolute paths everywhere, in this case it goes against the literal definition of the file CMake is trying to generate, and it causes real-world problems that are impossible to work around in any reasonable way. Please fix this. Thank you.