debug_all_the_time
debug_all_the_time

Reputation: 574

Cmake Linking Shared Library: "No such file or directory" when include a header file from library

I am learning to build a library using CMake. The code structure for building library is like below:

include:  
   Test.hpp       
   ITest.hpp     // interface
src:
   Test.cpp
   ITest.cpp

In CMakeLists.txt, the sentences I used to build library is :

file(GLOB SRC_LIST "src/iTest.cpp" "src/Test.cpp" "include/Test.hpp"
        "include/iTest.hpp"  "include/deadreckoning.hpp")
add_library(test SHARED ${SRC_LIST})
target_link_libraries( test ${OpenCV_LIBS})  // link opencv libs to libtest.so

Then I wrote another test file (main.cpp), copy and paste the library under the same directory, link library and call functions inside the library. This CMakeLists.txt is

cmake_minimum_required(VERSION 2.8)
project(myapp)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -pthread -O3 -Wall -ftree-vectorize -ffast-math -funroll-loops")

add_executable(myapp main.cpp)
target_link_libraries(myapp "/home/labUser/test_lib/libtest.so")

The main.cpp compiles and runs succussfully if I don't include the header files inside the library:

#include <iostream>
using namespace std;

int main(){
    cout << "hello world" << endl;
    return -1;
}

But when I include the header file #include "ITest.hpp", it has error:

fatal error: iTest.hpp: No such file or directory
  #include "iTest.hpp"   
compilation terminated.

I don't understand why it happens. I think I have already linked the library successfully because when I run main.cpp without including header file, it doesn't give any "linking" error. And I think apparently the header files are inside the library. Why I can't include it? Can anyone help me figure this out?

Upvotes: 5

Views: 22036

Answers (1)

Steve Lorimer
Steve Lorimer

Reputation: 28659

You have a couple of issues here.

Propagating headers to users of your target:

Whilst you've added the include file to your library target, you need to let consumers of your library target know how to find the header.

As such, when your app myapp links against your library target test, you need to tell cmake to add ./include to myapp's include search path.

There is a special cmake variable, ${CMAKE_CURRENT_LIST_DIR} which resolves to the path to the directory in which the current CMakeLists.txt being processed is.

In your instance, that is the parent folder of both src and include.

./                    <-- ${CMAKE_CURRENT_LIST_DIR} is this directory
+--- CMakeLists.txt
+--- src/
|    +---Test.cpp
|    +---ITest.cpp
+--- include/
     +---Test.hpp
     +---ITest.hpp

In order to tell cmake to add a path to its include search path you use target_include_directories

For this the path will then be ${CMAKE_CURRENT_LIST_DIR}/include

So the syntax you'd be looking for is:

target_include_directories(test PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)

Note that this means you don't have to add "include/iTest.hpp" and "include/Test.hpp" to your SRC_LIST glob, as the compiler will be able to find them from the above target_include_directories

Linking to your test library:

Now that you've created your library and added the include directories, to actually use it in your app, you should again use target_link_libraries, but don't specify the path to the generated .so file, instead refer to the name of the library target you created, test

target_link_libraries(myapp test)

Now myapp will know how to find Test.hpp because it will get that information from the "dependency link" you've created between myapp and test

As such, assuming the following directory structure, the following CMakeLists.txt files may work

src/
+--- library/
|    +--- < sources for your shared library >
+--- app/
     +--- < sources for your application >

src/CMakeLists.txt

cmake_minimum_required(VERSION 3.0)
project(myapp)

add_subdirectory(library)
add_subdirectory(app)

src/library/CMakeLists.txt

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} 
    -std=c++11 
    -pthread 
    -O3 
    -Wall 
    -ftree-vectorize 
    -ffast-math 
    -funroll-loops")

find_package(OpenCV REQUIRED)

add_library(test SHARED "src/iTest.cpp src/Test.cpp")
target_link_libraries(test ${OpenCV_LIBS})  // link opencv libs to libtest.so
target_include_directories(test PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)

src/app/CMakeLists.txt

add_executable(myapp main.cpp)
target_link_libraries(myapp test)

Upvotes: 10

Related Questions