Search code examples
c++cmakelinkerinclude-path

Link up src/ with CMake as library #include'd with some `libname/` prefix


For my research project I am setting up a project (coom) to benchmark a set of algorithms on a data structure. For unit testing I settled on Bandit, which leaves me with a project structure that looks as follows:

+ root
|-- CMakeLists.txt
|-+ external/
| \-- bandit/
|-+ src/
| |-- CMakeLists.txt
| |-- node.cpp
| \-- node.h 
\-+ test/
  |-- CMakeLists.txt
  |-- test.cpp
  \-- test_node.cpp

From my experience with other languages, this seems to me a standard project structure? The test/ folder contains unit tests for the logic in src/ and no dependencies are intermixed with the source and test code, but are instead in external/.

The testing files I want to look as follows (with irrelevant parts removed)

// test/test.cpp
#include <bandit/bandit.h>
(...)

#include "test_node.cpp"

int main(int argc, char* argv[]) {
  (...)
}
// test/test_node.cpp
#include <coom/node.h>
(...)

But my problem is, that when I try to compile with cmake .. and the subsequent Makefile, they are unable to find the source code in src/ where I get the compiler error:

fatal error: coom/node.h: No such file or directory. 

I would expect the test/CMakeLists.txt should look somewhat like the following:

# test/CMakeLists.txt
add_executable (test_unit test.cpp)
target_link_libraries(test_unit coom)

I cannot figure out how to setup the CMakeLists.txt and src/CMakeLists.txt to ensure I get the desired outcome above. Currently they look as follows:

# CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project (coom VERSION 0.1)

# ============================================================================ #
# Dependencies
(...)

# ============================================================================ #
# COOM project
add_subdirectory (src)
add_subdirectory (test)
# src/CMakeLists.txt
# ============================================================================ #
# Link up files for the library
set(HEADERS
  node.h
)

set(SOURCES
  node.cpp
)

add_library(coom ${HEADERS} ${SOURCES})

I can see from other projects, that it is possible to link the src/ directory with some libname/ prefix, but I cannot discern from their CMakeLists.txt files what I am doing wrong. I have looked at writing a coom.pc.in file and providing an install-target, and tried to set_target_properties with either FOLDER coom or PREFIX coom, but neither worked. I can hack an include_directory(../src) into the test/CMakeLists.txt to be able to include the file via an #include <node.cpp>, but that screams I'm doing something inherently wrong.

I'm at this point very much pulling my hairs out, and the CMake documentation is of very little help to me.


Solution

  • Your coom target has no include directories defined. You can define the include directories to use for this target (with target_include_directories()), and propagate these include directories so they are visible to the consuming test_unit target (by using PUBLIC):

    # src/CMakeLists.txt
    # ============================================================================ #
    # Link up files for the library
    set(HEADERS
      node.h
    )
    
    set(SOURCES
      node.cpp
    )
    
    add_library(coom ${HEADERS} ${SOURCES})
    
    target_include_directories(coom PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
    

    Furthermore, the file path to the node.h header is coom/src/node.h, not coom/node.h. But, because you now have coom/src as an public include directory, you can use the following to include the node.h header in your test file:

    #include <node.h>