I have a C++ library organized like:
Library/
CMakeLists.txt
main.cpp
src/
file1.cpp
include/
file1.h
Domains/
CMakeLists.txt
BlackJack/
CMakeLists.txt
src/
foo1.cpp
include/
foo1.h
...
libs/
tapkee/
CMakeLists.txt
include/
foo.hpp
....
Each library(i.e. Domains) contains linking and simple code for organizational purposes:
project(Domains)
cmake_minimum_required(VERSION 2.8)
add_subdirectory(IDomain)
add_subdirectory(Blackjack)
add_library(Domains STATIC)
target_link_libraries(Domains IDomain BLACKJACK)
Each sub-library (i.e. Blackjack) has a really simple CMakeLists.txt that just compiles the library (add_library).
This has been working just fine, until now.
I'm adding a third-party library (http://tapkee.lisitsyn.me/). This is a header-only library. It looks like CMake doesn't support this, but I found some work-arounds. I create a empty dummy.cpp file. Here is the CMakeLists for the third-party library:
project (TAPKEE)
file(GLOB TAPKEE_INCLUDE
"include/tapkee/*.hpp"
"include/tapkee/callbacks/*.hpp"
"include/tapkee/defines/*.hpp"
"include/tapkee/external/*.hpp"
"include/tapkee/neighbors/*.hpp"
"include/tapkee/parameters/*.hpp"
"include/tapkee/routines/*.hpp"
"include/tapkee/traits/*.hpp"
"include/tapkee/utils/*.hpp"
)
add_library(${PROJECT_NAME} header_only_BS.cpp ${TAPKEE_INCLUDE})
Here is the weird thing: My main.cpp and anything in the root src directory can include this tapkee library just fine, but none of the sub-libraries can (i.e. BlackJack). I get thousands of redefinition linker errors for the functions within tapkee.
Here is an example of the top-level CMakeLists:
project(ManifoldLearning)
#Root
set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
set(INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include)
#Domains
set(BLACKJACK_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Domains/Blackjack/include)
set(TAPKEE_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libs/tapkee/include/)
include_directories(${INCLUDE_DIR} ${SRC_DIR})
include_directories(${TAPKEE_INCLUDE_DIR})
include_directories(${BLACKJACK_INCLUDE_DIR})
add_subdirectory(Domains)
#add_subdirectory(libs/tapkee)
add_executable(${PROJECT_NAME} ${SRC_LIST} ${HEADER_LIST})
target_link_libraries(${PROJECT_NAME} Domains)
I've been stuck on this for days, and any help/advice would be appreciated.
Update: I've removed the inclusion of the tapkee CMakeLists.txt (add_subdirectory) as per Antonio's direction. I still get redefinition errors, which I find strange. It's now not compiled anywhere and only included in BlackJack/src/foo1.cpp
Related
I'm having the following project structure in a C++ project. I am depending on an external library (libA as for the following) and I'm cloning the external library into the include folder using a shell script.
include/
libA
src/
source.c
lib/
include/
libA.a
src/
fileA.cpp
main.cpp
CMakeLists.txt
The command given to compile the program is
clang -I include/libA/lib/include main.cpp fileA.cpp include/libA/src/source.c include/libA/src/libA.a
I have seen on stackoverflow that in order to add this external library I have to create a separate CMakeLists.txt in the external library folder and use add_library(). And in the main CMakeLists.txt file use add_subdirectory().
Is there a way to do this without a seperate CMakeLists.txt.
My current main CMakeLists.txt file. (This works but I think I'm missing something)
cmake_minimum_required(VERSION 3.16.3)
project(test)
add_executable(${PROJECT_NAME} src/main.cpp src/fileA.cpp include/libA/src/source.c )
include_directories(include/libA/lib/include)
target_link_libraries(${PROJECT_NAME} /include/libA/libA.a )
target_include_directories(${PROJECT_NAME} PUBLIC include/libA/lib/include)
I am trying to work with CMake for the first time and am struggling to link header files into my main. My cmake directory looks like this:
Project
| CmakeLists.txt
| src
|| CMakeLists.txt
|| Main.cpp
| Libs
|| CMakeLists.txt
|| headers
|||obstacle_detection.hpp
||source
|||obstacle_detection.cpp
|build
||"build files"
I would like to link the files in the headers folder to main, but what I currently have does not appear to work. The following runs the CMake command correctly but fails to compile with the make command, being unable to find the given header file. My CMakeLists files are as follows:
Project:
cmake_minimum_required(VERSION 3.17)
project(Sensivision)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
find_package(OpenCV REQUIRED)
find_package(realsense2 REQUIRED)
find_library(darknet REQUIRED)
add_subdirectory(libs)
add_subdirectory(src)
target_link_libraries(${PROJECT_NAME} obstacle_detection)
Libs:
add_library(
obstacle_detection
headers/obstacle_detection.hpp
sources/obstacle_detection.cpp
)
target_link_directories(obstacle_detection PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
src:
add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBS})
target_link_libraries(${PROJECT_NAME} ${realsense2_LIBRARY})
My include in main.cpp is
include <obstacle_detection.hpp>
I have also tried
include <headers/obstacle_detection.hpp>
and
include <obstacle_detection>
Each gives the error:
obstacle_detection.hpp: no such file or directory
What am I doing incorrectly to link the header to the main?
You haven't added any include directories to the obstacle_detection library. By listing the header file in the add_library call, this may allow the header to be displayed in an IDE, but it doesn't do anything for compilation. You should use target_include_directories to add the headers directory as an include directory for the obstacle_detection library. Otherwise, it, and other consuming targets, will have no knowledge of the headers in that directory.
add_library(
obstacle_detection
headers/obstacle_detection.hpp
sources/obstacle_detection.cpp
)
# Add this line.
target_include_directories(obstacle_detection PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/headers)
# Not sure this line is necessary, as it doesn't appear you actually link anything...
target_link_directories(obstacle_detection PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
You haven't shown the CMake code in the src directory, but be sure to link the obstacle_detection library target to the main target, e.g.:
target_link_libraries(MyExeTarget PRIVATE obstacle_detection)
In addition, because this header file is local, it is best if you use quotes to include the header:
#include "obstacle_detection.hpp"
You can use target_include_directories to add folder where your headers are located and #include <header.hpp> where needed.
Ex:
libs cmake:
add_library(
obstacle_detection
headers/obstacle_detection.hpp
sources/obstacle_detection.cpp
)
target_include_directories(obstacle_detection PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
cpp:
#include <headers/obstacle_detection.hpp>
File Structure:
CMakeLists.txt
src/
evolution.cpp
evolution.h
main.cpp
helpers/
disposable.h
engine/
game.h
game.cpp
CMakeLists.txt:
cmake_minimum_required(VERSION 3.17)
project(evolution)
add_library(helpers
src/helpers/disposable.h)
set_target_properties(helpers PROPERTIES LINKER_LANGUAGE CXX)
add_library(engine
src/engine/game.h
src/engine/game.cpp)
add_executable(evolution src/main.cpp)
target_link_libraries(evolution engine helpers)
The Game class (game.h) inherits from Diposable (disposable.h), but I am unable to build the project with a simple #include "disposable.h" in the game.h file.
How do I configure CMake so that the engine library can see the helpers library?
CMake error:
[ 20%] Building CXX object CMakeFiles/engine.dir/src/engine/game.cpp.o
In file included from /home/shane/projects/evolution/src/engine/game.cpp:1:
/home/shane/projects/evolution/src/engine/game.h:4:10: fatal error: disposable.h: No such file or directory
4 | #include "disposable.h"
| ^~~~~~~~~~~~~~
compilation terminated.
Adding headers to a project really only helps IDEs find the headers. It doesn't change the build instructions. Instead you need to use target_include_directories() with a INTERFACE or PUBLIC section to get any libraries that link to this to add the include directories to itself.
Your helpers library is more of an interface for now. To get this minimum example working do this:
cmake_minimum_required(VERSION 3.17)
project(evolution)
add_library(helpers INTERFACE) # INTERFACE is good for header-only libraries
target_include_directories(helpers INTERFACE src/helpers)
add_library(engine
src/engine/game.h
src/engine/game.cpp)
add_executable(evolution src/main.cpp)
target_link_libraries(evolution engine helpers)
Now include with angular brackets: #include <disposable.h>
If your library becomes more complicated (more than just header files), then replace INTERFACE in add_library with your sources. To make include directories available to the helpers library and any library that links to it, change INTERFACE to PUBLIC in target_include_directories.
cmake_minimum_required(VERSION 3.17)
project(evolution)
add_library(helpers src/helpers/helper.cpp)
target_include_directories(helpers PUBLIC src/helpers)
add_library(engine
src/engine/game.h
src/engine/game.cpp)
add_executable(evolution src/main.cpp)
target_link_libraries(evolution engine helpers)
I am trying to write a CMakeLists.txt for my project in C++, that depends on a few third party libraries. One of the libraries follows an unusual pattern (to me) when including header files as described below.
My code is structured as:
project/
- CMakeLists.txt
- src/
- main.cpp
- lib/
- CMakeLists.txt
- moduleA/
-CMakeLists.txt
- fooA.cpp
- fooA.h
- barA.cpp
- barA.h
- moduleB/
- CMakeLists.txt
- fooB.cpp
- fooB.h
moduleA depends on moduleB, and in addition fooA also depends on barA. The issue is with the include statements of fooA.cpp and barA.cpp:
// fooA.cpp
#include "moduleA/fooA.h"
#include "moduleA/barA.h"
...
Likewise for barA.cpp. When I run make after cmake it complains that it cannot find moduleA/fooA.h while compiling fooA.cpp. I am not sure how to include the files in moduleA, or in which CMakeLists.txt should I include those. moduleB compiles properly. I cannot change the code of the libraries, but I can add cmake files.
My CMakeLists.txt in lib and CMakeLists.txt in moduleA are as follows.
# lib/CMakeLists.txt
cmake_minimum_required(VERSION 3.1...3.14)
project(mylibs VERSION 1.0.0 LANGUAGES CXX)
add_subdirectory(moduleA)
add_subdirectory(moduleB)
#moduleA/CMakeLists.txt
cmake_minimum_required(VERSION 3.1...3.14)
project(moduleA VERSION 1.0.0 LANGUAGES CXX)
set (SOURCES fooA.cpp barA.cpp)
set (HEADERS fooA.h barA.h)
add_library(moduleA STATIC ${SOURCES} ${HEADERS})
target_link_libraries(moduleA PUBLIC moduleB)
The error is essentially the compiler not finding moduleA headers, when compiling moduleA source code, because the moduleA source files include headers in the same directory in an unusual (to me) way, #include "moduleA/header".
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?
Big thanks!
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)