c++qtcmakeqtestlib

CMake subdirectory - No such file or directory for included header file when compiling test subproject


I have relatively complex cmake project with multiple sub-projects - one for third party software (which also includes further sub-projects), one for the application I'm working on and one for the tests.

project: CMakeLists.txt
      |
      +---3rdparty: CMakeLists.txt
      |           |
      |           +---... (various 3rd party projects as libs)
      |
      +---application: CMakeLists.txt
      |
      +---tests: CMakeLists.txt

The application's CMakeLists.txt looks like this:

set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wno-reorder")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wno-reorder")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Wno-reorder")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Wno-reorder")

# -----------------------------------------------------------------------------
# SOURCE FILES
# -----------------------------------------------------------------------------

set(FILTERS_SRC
    filters/... # CPP files
)

set(DATAGRAM_PARSERS_SRC
    parsers/datagram/datagram1parser.cpp
    parsers/dataegram/datagram2parser.cpp
    parsers/datagram/datagram3parser.cpp
   ... # other CPP files
)

set(SOURCE_FILES
    main.cpp
    mainapplication.cpp

    ... # other CPP files)

    ${FILTERS_SRC}
    ${DATAGRAM_PARSERS_SRC}
)

add_library(filters SHARED
    ${FILTERS_SRC}
)

add_library(datagramparsers SHARED
    ${DATAGRAM_PARSERS_SRC}
)

# -----------------------------------------------------------------------------
# SETUP
# -----------------------------------------------------------------------------

find_package(Qt5Core REQUIRED)
find_package(Qt5Network REQUIRED)
find_package(Qt5Xml REQUIRED) 
find_package(Qt5XmlPatterns REQUIRED)

# Automatically generate Qt moc files for QObject subclasses.
set(CMAKE_AUTOMOC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)

include_directories(${CMAKE_SOURCE_DIR}/3rdparty/LL/include/
                    ${CMAKE_SOURCE_DIR}/3rdparty/easyloggingpp/src/)

set(AUTORCC ON)
set(QRC_DIR ${CMAKE_SOURCE_DIR}/resources)
#set(QRC_FILES ${QRC_DIR}/xml.qrc)

target_link_libraries(filters Qt5::Core)
target_link_libraries(datagramparsers Qt5::Core)

# Build executable from the *.cpp source files defined above.
add_executable(${PROJECT_NAME} ${SOURCE_FILES} ${QRC_FILES})
target_link_libraries(${PROJECT_NAME} LL Qt5::Core Qt5::Network Qt5::Xml Qt5::XmlPatterns)


# -----------------------------------------------------------------------------
# These macros are defined in common.cmake
# -----------------------------------------------------------------------------
add_common_targets()
add_common_commands()
add_common_easyloggingpp_defines()

# -----------------------------------------------------------------------------
# Misc. commands
# -----------------------------------------------------------------------------
# Copy CSV file
add_custom_command(
        TARGET ${PROJECT_BINARY}
        POST_BUILD
        COMMAND cp -rp
                ${CMAKE_SOURCE_DIR}/resources/csv1/*
                ${CMAKE_BINARY_DIR}/${PROJECT_CONFIG_DIR}
        COMMAND cp -rp
                ${CMAKE_SOURCE_DIR}/resources/csv2/*
                ${CMAKE_BINARY_DIR}/${PROJECT_CONFIG_DIR}
)

Inside the ${CMAKE_SOURCE_DIR}/3rdparty/LL/include/ I have a header file. Let's call it iparsers.h, which I am using in each and every one of the header files corresponding to the respective CPP file from DATAGRAM_PARSERS_SRC. For example:

datagram1parser.h

#include <LL/network/iparser.h>
#include <QObject>

class Datagram1Parser : public QObject, public LL::Network::IParser
{
  Q_OBJECT
  ...
}

datagram1parser.cpp

#include "datagram1parser.h"

#include <QByteArray>
#include <QStringList>
#include <QRegExp>

#include <easylogging++.h>

Datagram1Parser::Datagram1Parser(QObject* parent) : QObject(parent)
{
  ...
}

...

Now the CMakeLists.txt of my tests subproject looks like this:

# -----------------------------------------------------------------------------
# SETUP
# -----------------------------------------------------------------------------

enable_testing()

find_package(Qt5Core REQUIRED)
find_package(Qt5Test REQUIRED)
find_package(Qt5Network REQUIRED)       # For handling network access (HTTP requests to HAFAS server etc.)
find_package(Qt5Xml REQUIRED)           # For processing XML data (from HAFAS server)
find_package(Qt5XmlPatterns REQUIRED)   # For validating XML data (from HAFAS server)

# Explicitly set automoc to OFF because macro add_qttest needs moc files to
# be manually created.
set(CMAKE_AUTOMOC OFF)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/test-bin)


include_directories(
    ${CMAKE_SOURCE_DIR}/src
    ${CMAKE_SOURCE_DIR}/3rdparty/easyloggingpp/src/
)
add_common_easyloggingpp_defines()

# -----------------------------------------------------------------------------
# TARGETS
# -----------------------------------------------------------------------------

set(TEST_DATAGRAM_PARSERS_LIBS LL datagramparsers)
file(GLOB DATAGRAM_PARSERS_HEADERS
    "${CMAKE_SOURCE_DIR}/src/parsers/datagram/*.h"
)
message(${CMAKE_SOURCE_DIR}/3rdparty/LL/include/LL/network/iparser.h)
set(TEST_DATAGRAM_PARSERS_SRC
    ${CMAKE_SOURCE_DIR}/3rdparty/LL/include/LL/network/iparser.h
    ${DATAGRAM_PARSERS_HEADERS}
)
add_qttest2(testdatagramparsers
    testdatagramparsers.h
    testdatagramparsers.cpp
    TEST_DATAGRAM_PARSERS_SRC
    TEST_DATAGRAM_PARSERS_LIBS
)

with the micro add_qttest2 looking as follows:

macro(add_qttest2 TESTNAME MAIN_H MAIN_CPP OTHER_SRC_FILES LINK_LIBS)
    set(COVERAGE_COMMAND ${CTEST_COVERAGE_COMMAND})
    set(MOC_FILE)
    qt5_wrap_cpp(MOC_FILE ${MAIN_H})
    add_executable(${TESTNAME} ${MAIN_CPP} ${${OTHER_SRC_FILES}} ${MOC_FILE})
    target_link_libraries(${TESTNAME} Qt5::Test ${${LINK_LIBS}})
    add_test(NAME ${TESTNAME}
             COMMAND ${TESTNAME}
             WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
    set(MOC_FILE)
endmacro()

The testdatagramparsers header and source files look like this:

testdatagramparsers.h

#include <QObject>
#include <QtTest/QTest>

class TestDatagramParsers : public QObject
{
  Q_OBJECT
private:
  ...
private slots:
  void initTestCase();
  void cleanup();

  void testCaseDatagram1();
  void testCaseDatagram2();
  ...
}

testdatagramparsers.cpp

#include "testdatagramparsers.h"
#include "parsers/datagram/datagram1parser.h"
#include "parsers/datagram/datagram2parser.h"
...

My application project compiles and runs fine however when I try to compile my test target I get that

fatal error: LL/network/iparser.h: No such file or directory

when the dependency scanning phase takes place.

I'm not sure what else I can do. I even printed the output of ${CMAKE_SOURCE_DIR}/3rdparty/LL/include/LL/network/iparser.h and I checked it - it is the correct path.

I have also other tests (removed from the CMakeLists.txt above) that work just fine. The only difference is that they do not use any of the 3rd party headers.


Solution

  • I asume your file is in ${CMAKE_SOURCE_DIR}/3rdparty/LL/include/LL/network.

    You didn't add ${CMAKE_SOURCE_DIR}/3rdparty/LL/include/ to the include directories of your test project so it can't be found.

    Adding

    include_directories(
        ${CMAKE_SOURCE_DIR}/3rdparty/LL/include/
    )
    

    to the CMakeLists.txt of your test project might fix this.