5

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?

0

1 Answer 1

10

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) 
Sign up to request clarification or add additional context in comments.

12 Comments

Thanks for the answer! I tried to modify the library CMakeLists but I got the error when I compile: target_include_directories called with invalid arguments Do you know why? Do I need to specify where ${CMAKE_CURRENT_LIST_DIR} is?
@KathyLee looks like you're using an old version of cmake. Are you able to upgrade to a newer version? (cmake 2.8 is very old)
@KathyLee if you can't upgrade, try use ${CMAKE_CURRENT_SOURCE_DIR} instead, I believe this variable exists in 2.8
@KathyLee for something this small you could just add include_directories(include)
@afakih that's not recommended, and for someone trying to learn cmake, teaching best practice is probably a good idea
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.