0

I've tried looking for an answer to this question. There are similar questions but none that answer mine.

I am trying to create a library that depends on a couple other external libraries. I have the external libraries as git submodules and compile them myself in CMake using add_subdirectory followed by target_link_library.

After doing that, I am able to use the external libraries and include their header files in any source file in my library that I have added using target_sources and also in any header file that at least one of these source files include.

For example, I have an external library glm and call target_sources(myLib PRIVATE Application.cpp) in my library. The header files in my library are added to the project using target_include_directories.

Now, I can do #include <glm/glm.hpp> in the Application.cpp file with no problems.

I also have an Application.hpp file that is included in the Application.cpp file. Because it is included, that allows me to do #include <glm/glm.hpp> in the Application.hpp file as well.

However, now I also have a Core.hpp file without a corresponding Core.cpp file. Because the Core.hpp file is not included in any source files, doing #include <glm/glm.hpp> throws an error that the file cannot be found.

This is my root CMakeLists.txt:

cmake_minimum_required(VERSION 3.16)
project(Ivory)
set(CMAKE_CXX_STANDARD 20)

add_library(${PROJECT_NAME} SHARED)

# Determine compiler platform (x32 or x64)
math(EXPR PLATFORM_BITS "8*${CMAKE_SIZEOF_VOID_P}")
set(PLATFORM "x${PLATFORM_BITS}")

# Determine target build platform
target_compile_definitions(${PROJECT_NAME}
        PUBLIC
            IVORY_WINDOWS
        PRIVATE
            IVORY_BUILD_DLL
)

# Set output directory
set(OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin/${CMAKE_SYSTEM_NAME}-${CMAKE_BUILD_TYPE}-${PLATFORM})

# Subdirectories
add_subdirectory(src)
add_subdirectory(tests)
add_subdirectory(executables)

target_include_directories(${PROJECT_NAME} PUBLIC include)

# External Libraries #
set(BUILD_SHARED_LIBS OFF)

# GLM
add_subdirectory(lib/glm)
target_link_libraries(${PROJECT_NAME} PRIVATE glm)

# GLEW
add_subdirectory(lib/glew)
target_link_libraries(${PROJECT_NAME} PRIVATE libglew_static)

# SFML
add_subdirectory(lib/SFML)
target_link_libraries(${PROJECT_NAME} PRIVATE sfml-window sfml-audio)

# SPDLOG
add_subdirectory(lib/spdlog)
target_link_libraries(${PROJECT_NAME} PRIVATE spdlog)

# MinGW
target_link_libraries(${PROJECT_NAME} PRIVATE -static)

# Output Location
set_target_properties(${PROJECT_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${OUTPUT_DIRECTORY})

This is the src CMakeLists.txt:

target_sources(${PROJECT_NAME}
    PRIVATE
        Application.cpp
)

I am using CLion on Windows 10 with MinGW 7.3 compiler (64 bit). What am I doing wrong?

  • It seems that you've fell into "adding everything as subdirectories" trap. It would be better to move out all the external projects and let them properly expose their includes and build artifacts. Parts of this project that are also grabbed with add_subdirectory should probably be converted into external projects or into configuation-specific parts. Repetition of `add_subdirectory` `target_link_libraries` directives is a clear indicator that something is wrong. – user7860670 Apr 24 '20 at 10:24
  • What's the usage of a header not included by any src files? – LIU Qingyuan Apr 24 '20 at 10:33
  • @LIUQingyuan Those header files are to be included by the clients of the library. – Alex Khazov Apr 24 '20 at 10:36
  • @user7860670 Everything I have that does add_subdirectory followed by target_link_libraries are external library source code projects with their own CMakeLists.txt. I was under the impression that that is how those should be included in a project? – Alex Khazov Apr 24 '20 at 10:38
  • @AlexKhazov Then I believe source files that implemented interfaces in the header should include it, as this offers compiler a chance to check the declaration/definition consistency for you. – LIU Qingyuan Apr 24 '20 at 10:41
  • If the `Core.hpp` header is meant to be included by clients and glm headers are called from this header the glm dependency in the `target_link_libraries` command must be `PUBLIC` not `PRIVATE`. – vre Apr 24 '20 at 10:53
  • @vre Yes, that was the problem! Now that I think about it, it makes perfect sense. Thank you very much. Could you post your comment as an answer? – Alex Khazov Apr 24 '20 at 11:20
  • I think `add_subdirectory` should be used when some part of *this* project is supposed to be compiled differently compared to the rest of the project and therefore requires its own cmake file. It seems that dumping dependencies into project is not that uncommon practice but it certainly complicates things when project grows or amount of projects you are working on increases. With proper setup dependencies are declared like `deps(glm, glew(static), sfml-window, sfml-audio, spdlog, crt(static))` – user7860670 Apr 24 '20 at 11:38

1 Answers1

0

If the Core.hpp header is meant to be included by clients and glm headers are called from this header the glm dependency in the target_link_libraries command must be PUBLIC not PRIVATE.

For the CMake documentation see here. For a more detailed explanation of the PUBLIC, PRIVATE, and INTERFACE keywords with examples see here.

vre
  • 6,041
  • 1
  • 25
  • 39