Visual Studio 2019: Pass include paths between chain-referenced projects

Viewed 518

Let's suppose we have an existing Visual Studio 2019 solution that can't be generated from scratch with another tool, e.g. CMake.

The solution contains three projects: A, B and C, each containing only one file, this is a minimal example:

/// Project A, A.hpp
// content irrelevant

/// Project B, B.hpp
#include <A.hpp>  // B's public interface includes A's header

/// Project C.cpp
#include <B.hpp>  // C requires B's header, which includes A's header, to compile

Being used to CMake's "target-based" approach, I naively thought that I could handle things if:

  • B references A,
  • C references B

In this case however, C only consumes B's include paths, but it does not consume A's include paths. The C therefore does not compile.

The "workaround" which just "makes it work" is obvious: add A's include paths to C and it will compile. But we know that this scales horribly when number of project grows:

> /// Project C2, C2.cpp 
> #include <B.hpp>  // requires B interface to compile

> /// Project C3, C3.cpp 
> #include <B.hpp>  // requires B interface to compile

> /// Project C4, C5, ... and on and on 

Instead of having to having to specify the needs of B's interface across many projects, I am seeking what CMake offers: define the requirements (in my case: include paths) of B in B project itself and that's it.

My question is: how to achieve this entirely from within the Visual Studio 2019 IDE?

[1]: https://i.stack.imgur.com/CAMws.png

3 Answers

You can configure the include path manully with right project click, properties, "C++ directories" enter image description here

This works but performs not really well / is not that nice. You could configure it via MSBuild e.g. with a shared props file, too. But I do not like that approach either.

In my eyes the best option to do this, not just for multiple parts (exe, dlls... ) - but for cross-compiliation, too - is the usage a shared library / project with shared elements.

This allows you to put all interface files right there. I go even a step further - my projects contain no code - it is stored completely in shared projects. With this setup you can create for example a Windows Project which uses MSVC and a Linux version compiled with GCC using the same code base. Or create a static or dynamic library - nothing is fixed.

To use code from a shared project you can add it simply as reference (as you did with your other projects) - quite easy. If you need further help - please ask.

Here you can find a sample on github: https://github.com/bernd5/Stackoverflow-VS-Sample

For help some picture (my VS is in German - but I hope you can work with it):

Create Shared Project Project-Explorer


If you dislike the shared library approach you can find an alternative approach without ".." here: First you need to adjust the include-directories property for each project to: with SolutionDir (Added MSBuild-Variable SolutionDir)

Then you can simply write:

#include "A/A.h"

As some commented, the easiest way to fix that may be to add an upper level folder as include path and then include files relatively from here.

If your code is structured like that:

your_code/
    A/
        a.hpp
        a.cpp
    B/
        b.hpp
        b.cpp
    C/
        c.hpp
        c.cpp

Then, instead of adding your_code/A in B's include path and your_code/B in C's, add your_code to eveyone's and then include A/a.hpp from B and B/b.hpp from C. I think this approach is cleaner than using .. in your includes as proposed by Kamen.

The code can be organized differently (have inc/src folders to isolate headers/implementations, repeat library name under inc folder so that people having any_lib's inc in their library path would include any_lib/...hpp to avoid conflicts in header files lookup...), but in the end, the approach remains the same, try to have B lookup for A's include relatively from a place also known by C so that it finds it too.

Anyway, the good solution (long term) may be to use CMake in the end (or any build system) handling that correctly for you, but that is apparently not an option right now.


Edit: This post shows how to add a bunch of includes to a projet. You may also use that, have a IncludeDirsForB.txt with everything needed by B path and add @IncludeDirsForB.txt to the command line of every project using B...?

Related