majkel.mk
majkel.mk

Reputation: 428

Library headers not visible in headers but perfectly visible inside .cpp file under cmake build. Why?

I have a C++ project containing several modules, some built as libraries, with such structure:

/MyProject
 +---/build 
     /ModuleA 
      +---CMakeLists.txt        <- module level CMakeLists
      +---/src
      |     +--CMakeLists.txt   <- src level CMakeLists
      |     +--FileA1.cpp
      |     +--FileA2.cpp
      +---/include
      |     +--FileA1.h
      |     +--FileA2.h
      |     +--FileA3.h
      /ModuleB
      +---CMakeLists.txt
      +---/src
      |     +--CMakeLists.txt
      |     +--FileB1.cpp
      |     +--FileB2.cpp
      +---/include
      |     +--FileB1.h
      |     +--FileB2.h
      |     +--FileB3.h
      main.cpp
      CMakeLists.txt            <- project level CMakeLists

CMakeLists.txt files look as follow:

project level:

cmake_minimum_required(VERSION 3.05)
project(MyProject)
subdirs(ModuleA ModuleB)   
set(CMAKE_CXX_STANDARD 11) 
add_executable(MyProject main.cpp)
target_link_libraries(MyProject ModuleA ModuleB)

module level:

subdirs(src)

src level:

FIND_PACKAGE(SomePackage REQUIRED) 
INCLUDE_DIRECTORIES(
        ${SomePackage_INCLUDE_DIR}
        ${MyProject_SOURCE_DIR}/ModuleA/include
)       
SET(SOURCE_FILES <all files from ModuleA/src goes here>)
ADD_LIBRARY(ModuleA STATIC ${SOURCE_FILES})
TARGET_LINK_LIBRARIES(ModuleA
        ${SomePackage_LIBRARIES}
)

The problem is: when I include header files from 'SomePackage' in my ModuleA header files (i.e. SomePackageFile.hpp in FileA1.h) I get an error while running a build with make:

fatal error: SomePackageFile.hpp: No such file or directory

When I include them in cpp files they are visible and project compiles correctly. I assume that is sth wrong with CMakeLists on src level or entire hierarchy of files is missing something.

Upvotes: 0

Views: 1077

Answers (2)

majkel.mk
majkel.mk

Reputation: 428

Switching from INCLUDE_DIRECTORIES() to TARGET_INCLUDE_DIRECTORIES() was the case, no change to the structure of the project was needed.

Upvotes: 0

Gergely Nyiri
Gergely Nyiri

Reputation: 345

I have a github project to be used as a skeleton for other projects:

https://github.com/gnyiri/cmake-sandbox

If you follow this layout, you will not need to add ${SomePackage_INCLUDE_DIR} to INCLUDE_DIRECTORIES which is not the best way to add directories to the include path otherwise.

In a nutshell, you should define a new library like this:

project(module_a)

set(sources
  src/source_a_1.cc
)

add_library(library_a
  ${sources}
)

target_include_directories(library_a
  PUBLIC
    $<INSTALL_INTERFACE:include>
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
)

Then, if you define another library (library_b), you only need to add library_a in target_link_libraries:

project(module_b)

# set list of sources, needs to be extended when new source arrives
set(sources
  src/source_b_1.cc
)

# define a library (static by default -> liblibrary_b.a or library_a.lib will be generated)
add_library(library_b
  ${sources}
)

# include directories
target_include_directories(library_b
  PUBLIC
    $<INSTALL_INTERFACE:include>
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
)

# link library_b
target_link_libraries(library_b
  library_a
)

Note that in this source tree, all the header files are located in

<module>/include/<module>

This way you will include a header file from like this:

#include "<module>/<module_header.h>"

This is simply because /include will be on include path.

Upvotes: 2

Related Questions