简体   繁体   中英

Handling Shared Library Dependencies with CMake and C++

I have a c++ project that utilizes shared libraries, some of which have dependencies of their own. However, I am being forced to include the header files for the shared library dependencies within my main.cpp file. I'm assuming that this is an issue with how I have structured my project, but I'm not sure.

Project Structure:

- myproject
|-> foo1
  |-> include
    |-> foo1_stuff.hpp
  |-> src
    |-> main.cpp
  |-> build
  |-> CMakeLists.txt
|-> foo2
  |-> include
    |-> foo2_stuff.hpp
  |-> src
    |-> main.cpp
  |-> build
  |-> CMakeLists.txt
|-> lib
  |-> bar
    |-> include
      |-> bar.hpp
    |-> src
      |-> bar.cpp
  |-> bar_tool
    |-> include
      |-> bar_tool.hpp
    |-> src
      |-> bar_tool.cpp
  |-> CmakeLists.txt

foo1's main.cpp:

#include <bar_tool.hpp>

int main()
{
    bar_tool tool;
    tool.doStuff();

    return 0;
}

bar_tool.hpp:

#include <bar.hpp>

class bar_tool
{
public:
    bar_tool();
    ~bar_tool();
    int var;
    void doStuff();
};

bar_tool.cpp:

#include <iostream>
#include <bar_tool.hpp>

bar_tool::bar_tool() : var(0) {}
bar_tool::~bar_tool() {}

void bar_tool::doStuff()
{
    std::cout << barFunction(var) << std::endl;
}

bar.cpp:

int barFunction(int value)
{
    return value + 2;
}

Foo1 CMakeLists:

cmake_minimum_required(VERSION 3.10.2)
project(foo)

set(PROJECT_ROOT ~/myproject/)
set(
    CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_ROOT}/bin/
)

link_directories(
    /usr/local/lib
    /usr/lib
    ${PROJECT_ROOT}/lib
)

include_directories(
    include
    ${PROJECT_ROOT}/lib/bar_tool/include
)

file(GLOB SOURCES "src/*.cpp")

add_executable(${PROJECT_NAME} ${SOURCES})
target_link_libraries(
    ${PROJECT_NAME}
    bar_tool
)

Shared Libraries CMakeLists:

cmake_minimum_required(VERSION 3.10.2)
project(myproject)

set(PROJECT_ROOT ~/myproject/)
set(
    CMAKE_LIBRARY_OUTPUT_DIRECTORY
    ${PROJECT_ROOT}/lib/
)

link_directories(
    /usr/local/lib
    /usr/lib
    ${PROJECT_ROOT}/lib
)

include_directories(
    include
    ${PROJECT_ROOT}/lib/bar/include
    ${PROJECT_ROOT}/lib/bar_tool/include
)

# bar library
set(LIB_NAME "bar")
file(GLOB LIB_SRC "${LIB_NAME}/src/*.cpp")
add_library(${LIB_NAME} SHARED ${LIB_SRC})

# bar_tool library
set(LIB_NAME "bar_tool")
file(GLOB LIB_SRC "${LIB_NAME}/src/*.cpp")
add_library(${LIB_NAME} SHARED ${LIB_SRC})
target_link_libraries(
    ${LIB_NAME}
        bar
)

I would expect that using the compiled bar_tool shared library ( libbar_tool.so ) would not require having to include bar.hpp in the include_directories section of foo1's CMakeLists. However, I get following error if I don't:

In file included from /home/mrd/Development/compile_test/foo/src/main.cpp:1:0:
/home/mrd/Development/compile_test/lib/bar_tool/include/bar_tool.hpp:1:10: fatal error: bar.hpp: No such file or directory
 #include <bar.hpp>
          ^~~~~~~~~
compilation terminated.

Am I not using shared libraries or CMake (or both) correctly?

FIX:

UPDATED Shared Libraries CMakeLists:

cmake_minimum_required(VERSION 3.10.2)
project(myproject)

set(PROJECT_ROOT ~/myproject/)
set(
    CMAKE_LIBRARY_OUTPUT_DIRECTORY
    ${PROJECT_ROOT}/lib/
)

# bar library
set(LIB_NAME "bar")
file(GLOB LIB_SRC "${LIB_NAME}/src/*.cpp")
add_library(${LIB_NAME} SHARED ${LIB_SRC})
target_include_directories(
    ${LIB_NAME} PUBLIC
    ${PROJECT_ROOT}/lib/bar/include
)

# bar_tool library
set(LIB_NAME "bar_tool")
file(GLOB LIB_SRC "${LIB_NAME}/src/*.cpp")
add_library(${LIB_NAME} SHARED ${LIB_SRC})
target_include_directories(
    ${LIB_NAME} PUBLIC
    ${PROJECT_ROOT}/lib/bar_tool/include
)
target_link_libraries(
    ${LIB_NAME} PUBLIC
    bar
)

Not sure if this had any effect, but I changed this also:

UPDATED Foo1 CMakeLists:

cmake_minimum_required(VERSION 3.10.2)
project(foo)

set(PROJECT_ROOT /home/mrd/Development/compile_test)
set(
    CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_ROOT}/bin/
)

add_subdirectory(${PROJECT_ROOT}/lib/ bin)

file(GLOB SOURCES "src/*.cpp")

add_executable(${PROJECT_NAME} ${SOURCES})
target_link_libraries(
    ${PROJECT_NAME}
    bar_tool
)

Any other suggestions are more than welcome!

Since you have the compiled library you do not need to add the paths of the source files. All the function calls, external variable access etc will be linked to this precompiled library.

Whereas when you include header file this is not the case. Make creates a list of dependencies before compilation where it tries to locate all the headers. Hence paths of all the headers which are included directly or indirectly must be provided.

In your Shared Libraries CMakeLists.txt file, consider adding the PUBLIC keyword to ensure that the transitive dependencies (ie the bar library) can be propagated to the final target. Also, modern CMake encourages the use of target_include_directories() instead of include_directories() . Similarly, you should add the PUBLIC keyword here also:

target_include_directories(bar PUBLIC
    ${PROJECT_ROOT}/lib/bar/include
)
target_include_directories(bar_tool PUBLIC
    ${PROJECT_ROOT}/lib/bar_tool/include
)

target_link_libraries(
    ${LIB_NAME} PUBLIC
        bar
)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM