Search code examples
cmakelinkershared-librariesprojectstatic-libraries

How to properly use CMake to create a complex project with dependencies on custom libraries


I'm trying to create a complex project that becomes a single executable file that uses the following libraries: two libraries BHV and HAL that use one interface library. I have this project structure:

.
├── BHV
│   ├── CMakeCache.txt
│   ├── CMakeFiles
│   ├── cmake_install.cmake
│   ├── CMakeLists.txt
│   ├── include
│   ├── libBHV_Library.so
│   ├── Makefile
│   └── sources
├── HAL
│   ├── check_libraries.cmake
│   ├── CMakeCache.txt
│   ├── CMakeFiles
│   ├── cmake_install.cmake
│   ├── CMakeLists.txt
│   ├── include
│   ├── libHAL_Library.so
│   ├── Makefile
│   └── sources
├── Interface
│   ├── CMakeCache.txt
│   ├── CMakeFiles
│   ├── cmake_install.cmake
│   ├── CMakeLists.txt
│   ├── include
│   ├── libInterface_Library.a
│   ├── Makefile
│   └── sources
├── CMakeCache.txt
├── CMakeFiles
├── cmake_install.cmake
├── CMakeLists.txt
├── main.cpp
├── Makefile
├── README.md

Unfortunately, I can't connect the individual libraries to each other.

In Interface_lib CMakeList.txt I have this:

cmake_minimum_required(VERSION 3.10)
project(Interface_Library)

#requires at least C++17
set(CMAKE_CXX_STANDARD 17)


# Add all .cpp files from sources folder
file(GLOB SOURCES "sources/*.cpp")

# Add all .h files from include folder
file(GLOB HEADERS "include/*.h")

# Add main.cpp to the project
add_library(Interface_Library STATIC ${SOURCES} ${HEADERS})

In HAL_lib CMakeList.txt I have this:

cmake_minimum_required(VERSION 3.10)
project(HAL_Library)

# requires at least C++17
set(CMAKE_CXX_STANDARD 17)

################################### DIR_MANAGMENT #########################################

# Get the parent directory
get_filename_component(PARENT_DIR ${CMAKE_CURRENT_LIST_DIR} DIRECTORY)

#Set the directory of the parent file as the current directory
set(CMAKE_CURRENT_LIST_DIR ${PARENT_DIR})

message("MYPROJECT_DIR directory: ${CMAKE_CURRENT_LIST_DIR}")

################################### HAL_LIB #########################################

# Add all .cpp files from sources folder
file(GLOB SOURCES "sources/*.cpp")

# Add all .h files from include folder
file(GLOB HEADERS "include/*.h")

# Add main.cpp to the project
add_library(HAL_Library SHARED ${SOURCES} ${HEADERS})

################################### INTERFACE_LIB #########################################

target_link_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_LIST_DIR}/Interface)

# Link the Interface_Library into the HAL_Library
target_link_libraries(HAL_Library Interface_Library)

# check if libraries were included
set(TARGET_NAME HAL_Library)
include(check_libraries.cmake)

this is the code i use to check_libraries.cmake (from the internet)

# Get a list of referenced libraries
get_target_property(LINK_LIBS ${TARGET_NAME} LINK_LIBRARIES)

# Print the list of referenced libraries
message("Odkazované knihovny: ${LINK_LIBS}")

# Verify that libraries are available on the system
foreach(LIB ${LINK_LIBS})
    execute_process(COMMAND ldd $<TARGET_FILE:${TARGET_NAME}> | grep ${LIB}
                    RESULT_VARIABLE res
                    OUTPUT_QUIET ERROR_QUIET)
    if(res EQUAL "0")
        message("Library ${LIB} was successfully linked with ${TARGET_NAME}")
    else()
        message(FATAL_ERROR "Error: Library ${LIB} not found.")
    endif()
endforeach()

As an output I keep getting the library not found. What am I doing wrong? And is my approach to project structure correct?

Thank you.


Solution

  • Typically you do:

    # ./CMakeLists.txt
    cmake_minimum_required(VERSION 3.10)
    project(Interface_Library)
    add_subdirectory(HAL)
    add_subdirectory(Interface)
    
    # HAL/CMakeListst.txt
    file(srcs GLOB sources/*.c include/*.h)
    add_library(HAL ${srcs})
    target_include_directories(HAL PUBLIC include)
    target_link_libraries(HAL PUBLIC Interface)
    
    # Interface/CMakeLists.txt
    file(srcs GLOB source/*.c include/*.h)
    add_library(Interface ${srcs})
    target_include_directories(HAL PUBLIC include)
    

    That's all. Only one project() call, in the root. Note the target_include_directories missing in your code. Note the main root CMakeLists.txt that includes all. I find HEADERS and SOURCES separately confusing, I would also use lowercase everything. No target_link_directories, CMake will find everything. Also, everything is compiled as one big project, not separately.