VisualStudio project with multiple sourcefiles of

2020-02-04 20:43发布

问题:

i have a largish C++ project, with source-files organised in multiple folders (on the filesystem).

in two of these folders, i have files with the same name. e.g.

\MyProject\foo\Blurp.cpp
\MyProject\foo\File.cpp
\MyProject\bar\File.cpp
\MyProject\bar\Knoll.cpp

the project is cross platform, and i use autoconf on linux and OSX, but have to use MSVC on W32 (due to some 3rd party C++ libraries i use on W32 and the C++ binary interface incompatibilities across compilers)

on the MSVC side, the project is organized into multiple "Filters" (those virtual Folders) as well (with names roughly corresponding to the Directories the files live in), so i can distinguish them.

now the problem is, when i build the project, MSVC puts the object files in a single flat diretory, and i end up with:

\MyProject\Release\Blurp.obj
\MyProject\Release\File.obj
\MyProject\Release\Knoll.obj

as can be seen, there's only one File.obj, so one binary object is missing. obviously, the linker complains, since it cannot find classes/functions/... defined in that missing object file.

is there a way to tell MSVC to create object files with a unique name depending on the directories (or filters) those files live in?

i imagine something like:

\MyProject\Release\foo\Blurp.obj
\MyProject\Release\foo\File.obj
\MyProject\Release\bar\File.obj
\MyProject\Release\bar\Knoll.obj

or

\MyProject\Release\foo-Blurp.obj
...

or whatever. all other build-systems i know (CMake, autotools) are able to deal with multiple files of the same name.

this question is similar to 3729515, but i'm currently stuck to VS2008. (the solution suggested there for VS2008 - to set the Object-Directory for each file in question - is something which indeed works theoretically, but which i would like to avoid for practical reasons)

回答1:

You can set a file-specific project setting for one (or both) of the files that conflict and set the "Object File Name" property to:

$(InputDir)\$(IntDir)\

Just right-click the filename instead of the project name to set the property for that file only.

For example, if you do that for \MyProject\foo\File.cpp then the object file for that source file will go to \MyProject\foo\Release\File.obj so it won't conflict with the object file for \MyProject\bar\File.cpp.

The drawbacks to this are that it can clutter your source tree with compiler outputs (but hopefully there aren't too many), and - even worse - file-specific project settings tend to get forgotten/hidden since they're not called out in the IDE at all. If sometime down the road you (or someone else) needs to change things, it can be quite a mystery about why the build acts so strangely for particular files until someone screws around with it for a half a day until it dawns on them what's going on.

I would personally prefer that a project-wide setting of $(InputDir)\$(IntDir)\ would cause object files to go to directories relative to the source file, but it actually doesn't work well at all as a project level setting. In that case VS still only sets the output directory once and it ends up being relative to the first source file in the list. Then the linker gets confused about where it should look for object files.



回答2:

Maybe you can set the project wide 'object file name' (Configurtion Properties->C/C++->Output Files) to

$(IntDir)%(RelativeDir)

which uses the relative source folder of the source files. Note the %, but this gets ugly if your source files are located out of your project directory, containing ..\



回答3:

Use

$(IntDir)%(Directory)

as "Object File Path".

%(Directory) contains the absolute path of the file without the volume and without the filename itself. This solution should work at least in VS 2019 and can be applied to a project directly.