target_sources() and header visibility

Hi,
I’m trying modern cmake approach, but seems like my understanding of how target_sources() command works is wrong.
Consider following hierarchy:

foo_project/
├── CMakeLists.txt
├── headers
│   └── foo.h
├── interfaces
│   └── foo_interface.h
└── sources
    ├── foo.cpp

headers directory contains target’s private headers
interfaces directory contains target’s public headers (api)
sources contains .cpp files.

// CMakeLists.txt:

cmake_minimum_required(VERSION 3.15.0)

project(FooProject)

add_library(foo_lib STATIC)

    target_sources(foo_lib
        PRIVATE
            sources/foo.cpp
            headers/foo.h
        PUBLIC
            interfaces/foo_interface.h
    )

The problem is that in foo.h the only way to include foo_interface.h is by qualifying its directory name:

// foo.cpp
#include "../headers/foo.h"

// foo.h
#include "../interfaces/foo_interface.h"

The way i think it should look:

// foo.cpp
#include "foo.h"

// foo.h
#include "foo_interface.h"

How can i achieve this?

I think you probably want something like this:
cmake_minimum_required(VERSION 3.15.0)

project(FooProject)

add_library(foo_lib STATIC)

target_sources(foo_lib
    PRIVATE
    sources/foo.cpp
    headers/foo.h
    interfaces/foo_interface.h
)

target_include_directories(foo_lib PUBLIC interfaces PRIVATE headers)

It works now, thank you.

Can you clarify, what’s the deal with target_sources (… PUBLIC). My initial thought was that it allows to emulate target_include_directories(…PUBLIC) behavior.

so, i thought that

target_sources(foo_lib PUBLIC interface/foo_interface.h) 

and

target_include_directories(foo_lib PUBLIC interface) 

are equal.

I’m not deep enough to be sure but my understanding is that target_sources (… PUBLIC...) will cause inclusion of those source files in the source list of all targets that link to this target. In any case probably NOT what one wants. Someone smarter would have to answer that if you want details.

Yes, target_sources just adds source file paths to the list of files for consuming targets. Just like adding arbitrary/path/foo.h does not imply -Iarbitrary/path, if you want -I flags passed, you need to use target_include_directories.

There’s no documentation that indicates that your two examples are implied at all (if there is, please point us to it so it can be updated).

No, it’s just me not being familiar enough with CMake.

Thanks all.