CMake: target_include_directories() can't find header files - c++

At the top of my main.cpp file, No such file or directory is thrown at #include <sqlite3.h>.
Building the code manually by g++ -I"C:\Libraries\64_bit\SQLite3\include\" -L"C:\Libraries\64_bit\SQLite3\bin\" -lsqlite3 main.cpp Class1.cpp Class1.h Class2.cpp Class2.h -o main throws no errors.
CMake cannot seem to find the header, even though I've explicitly described where it is located in my file-system. According to the documentation for target_include_directories(), that should be enough:
Specified include directories may be absolute paths or relative paths. Repeated calls for the same append items in the order called.
Why is the target_include_directories() function not finding the headers, even though I've provided the exact absolute path?
I'm developing on a 64-bit Windows 10 machine, and CLion is set-up to compile with the MinGW-w64 g++ compiler.
I've downloaded the 64-bit Windows pre-compiled binary, sqlite3.dll and stored it locally in C:\Libraries\64_bit\SQLite3\bin\.
In order to access SQLite C++ functions I've also downloaded SQLite3's amalgamated source code and stored all source files in C:\Libraries\64_bit\SQLite3\include\.
I built my project in CLion, which is essentially a fancy GUI-wrapper for CMake. In my CMakeLists.txt, I've included SQLite3's headers and linked sqlite3 as follows:
cmake_minimum_required(VERSION 3.7)
project(My_Project)
set(CMAKE_CXX_STANDARD 11)
set(INCLUDE_DIRS C:\\Libraries\\64_bit\\SQLite3\\include\\)
set(LIBRARIES sqlite3.dll)
# My project's source code
set(SOURCE_FILES main.cpp Class1.cpp Class1.h Class2.cpp Class2.h)
add_executable(My_Project ${SOURCE_FILES})
# For compiler warnings
target_compile_options(My_Project PRIVATE -Wall)
# Including SQLite3's headers
target_include_directories(My_Project PRIVATE ${INCLUDE_DIRS})
# Linking against sqlite3.dll
target_link_libraries(My_Project ${LIBRARIES})

You can run into problems if you don't put paths between quotes.
Thus it is a good idea to write:
set(INCLUDE_DIRS "C:\\Libraries\\64_bit\\SQLite3\\include\\")
or, rather:
set(INCLUDE_DIRS "C:/Libraries/64_bit/SQLite3/include/")
Additionally, the CMakeLists.txt as it currently stands won't be able to find -lsqlite3. Thankfully, CMake makes finding libraries easy:
# Optionally, add 'PATHS "C:/Libraries/64_bit/SQLite3/bin/"'
find_library(SQLITE3_LIBRARY NAMES sqlite3)
If the library is discover-able on your system, the above command will return the path to the library and store that path in SQLITE3_LIBRARY. All that remains to do is link the project against the SQLite3 library:
# Link project to the SQLite3 library
target_link_libraries(MSP_Tool ${SQLITE3_LIBRARY})

Related

Should I use only add_executable() with raw cpp files or make a library via add_library()?

I'm learning CMake and I'm struggling with it a little. My "project" is using JsonCpp "library" that was provided as one .cpp file and two .h files. The structure looks like this:
myProject
build/
json/
CMakeLists.txt
jsoncpp.cpp
include/
json.h
json-forward.h
CMakeLists.txt
main.cpp
build/CMakeLists.txt:
cmake_minimum_required(VERSION 3.6.0)
project(myProject)
add_subdirectory(json)
add_executable(app main.cpp)
target_link_libraries(app PRIVATE json)
# add_executable(app main.cpp json/jsoncpp.cpp json/include/json.h json/include/json-forwards.h)
json/CMakeLists.txt:
cmake_minimum_required(VERSION 3.6.0)
add_library(
json
jsoncpp.cpp
include/json.h
include/json-forwards.h
)
target_include_directories(json PUBLIC '${CMAKE_CURRENT_SOURCE_DIR}/include')
What's a difference between using only add_executable() with all .cpp files and using target_link_libraries that transforms jsoncpp into static library and then link it? What approach should I choose?
A next thing confusing me is a target_include_directories(). What are the benefits using this function? If I comment it, and run cmake (then makefile and launch the app) everything still works fine. If I delete "include/json.h" "include/json-forward.h" from add_library(), everything still works.
What's a difference between using only add_executable() with all .cpp files and using target_link_libraries that transforms jsoncpp into static library and then link it? What approach should I choose?
Using add_library is required when you have 2 executables using the same jsoncpp code. In this case, if you list jsoncpp sources in both add_executable() calls, you'd have to compile it twice. Grouping them into add_library() will make it compile only once and then linked to both executables.
Another reason to use add_library is purely logical composition of modules.

Statically linking GLEW from source with cmake

I am somewhat new to cmake and completely new to glew, glfw, and the like. I'm following a youtube channel to learn more about game engines and programming.
My problem is linking the static glew library in my project using cmake.
First, I start with the glew source code from http://mcs.une.edu.au/doc/glew-devel/index.html.
I compile it by:
cd build; cmake ./cmake; make glew_s
This adds a lib directory into the build directory with libGLEW.a
A shortened version of my CMakeLists.txt looks like:
cmake_minimum_required (VERSION 3.5 FATAL_ERROR)
project (TestProject CXX)
set(CMAKE_CXX_FLAGS "-std=c++11")
###########################
# GLEW
###########################
add_subdirectory(${CMAKE_SOURCE_DIR}/Dependencies/GLEW)
target_link_libraries(${PROJECT_NAME} glew)
and in Dependencies/GLEW I have another CMakeLists.txt:
# Add glew source and header files
file(GLOB_RECURSE glew-lib ${CMAKE_CURRENT_SOURCE_DIR}/lib/*)
file(GLOB_RECURSE glew-headers ${CMAKE_CURRENT_SOURCE_DIR}/include/GL/*)
add_library(glew ${glew-lib} ${glew-headers})
target_include_directories(glew PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include/GL")
I put a copy of the libGLEW.a file into the lib directory and the include directory is copied from the glew source code include directory. It holds the GL directory, which contains the header files glew.h, wglew.h, eglew.h, and glxew.h.
When I run cmake I get the error:
CMake Error: Cannot determine link language for target "glew".
CMake Error: CMake can not determine linker language for target: glew
The glew source code also has a src directory with glew.c in it, but if I put it in the libs directory and include it in the Dependencies/GLEW/CMakeLists.txt like:
# Add glew source and header files
file(GLOB_RECURSE glew-lib ${CMAKE_CURRENT_SOURCE_DIR}/lib/*.c)
file(GLOB_RECURSE glew-headers ${CMAKE_CURRENT_SOURCE_DIR}/include/GL/*)
add_library(glew ${glew-lib} ${glew-headers})
target_include_directories(glew PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
I get the error:
CMake Error: Error required internal CMake variable not set, cmake may
be not be built correctly.
Missing variable is: CMAKE_C_COMPILE_OBJECT
CMake Error: Error required internal CMake variable not set, cmake may
be not be built correctly.
Missing variable is: CMAKE_C_CREATE_STATIC_LIBRARY
Lastly, I have tried just including the glew.c and headers in the root CMakeLists.txt like:
#########################
# GLEW
#########################
include_directories("${CMAKE_SOURCE_DIR}/Dependencies/GLEW/lib/")
include_directories("${CMAKE_SOURCE_DIR}/Dependencies/GLEW/include/GL/")
Here cmake will finish, but it won't be able to compile, saying classes do not name a type and/or are not declared in this scope.
Any help would be appreciated. I was under the impression that the libGLEW.a was the static library, and all I would have to do is link and compile it along with the headers, but that did not work.
First of all, I forgot to use
make install
after using make the first time, so I was using the incorrect libGLEW.a file.
After including the proper libGLEW.a file, my directory structure had
./Dependencies/GLEW/include/GL/*.h //header files
./Dependencies/GLEW/lib/libGLEW.a //source file
Finally, the TopLevel CMakeLists.txt is changed to include:
add_library(glew STATIC IMPORTED GLOBAL)
set_target_properties(glew PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/Dependencies/GLEW/lib/libGLEW.a )
set_target_properties(glew PROPERTIES INCLUDE_DIRECTORIES ${CMAKE_SOURCE_DIR}/Dependencies/GLEW/include )
If I want to include the library from a lower CMakeLists.txt such as /Dependencies/GLEW/CMakeLists.txt Then I would have to first export the library from there and then import it at the topLevel CMakeLists.txt file.
Now, in order to use glew headers in my project I can just use #include .

My project can find one library header, but not another one

I have two C++ libraries, which I am using on Ubuntu. One of them, let's call it foo, I installed through apt-get, e.g. sudo apt-get install libfoo-dev. The other, let's call it bar, I installed by downloading the source files, and running make install. After these installations, I then have header files from foo in locations such as /usr/include/foo/foo.h, and header files from bar in locations such as /usr/local/include/bar/bar.h. From my knowledge, foo is a dependency of bar.
I then created my own C++ project, and included the line #include "bar/bar.h". But when compiling my project, I get an error saying error: foo.h: No such file or directory. If I click on the error in my debugger, it opens the file bar.h, and highlights the line #include <foo.h>. So, my project is able to find bar.h, but not foo.h. I do not mention either foo or bar in my CMakeLists.txt file.
So my questions are:
How does my project know how to find bar.h, when I have not told it where to find it in CMakeLists.txt?
What do I need to do to get my project to find foo.h and compile properly?
Thank you!
Edit: Here is my CMakeLists.txt file (the foo and bar libraries are none of the ones mentioned here):
cmake_minimum_required(VERSION 2.8.1)
set(CMAKE_CXX_FLAGS "-std=c++11 -O3")
project(Grasping_Simulator)
find_package(OpenGL REQUIRED)
find_package(GLEW REQUIRED)
find_package(GLUT REQUIRED)
find_package(Eigen3 REQUIRED)
find_package(Boost REQUIRED)
find_package(OpenCV REQUIRED)
include_directories(${OPENGL_INCLUDE_DIR} ${GLEW_INCLUDE_DIR} ${GLUT_INCLUDE_DIR} ${EIGEN3_INCLUDE_DIR} ${BOOST_INCLUDE_DIRS} ${OPENCV_INCLUDE_DIRS})
file(GLOB SRCS *.cpp *.h)
add_executable(${PROJECT_NAME} ${SRCS})
target_link_libraries(${PROJECT_NAME} ${GLEW_LIBRARY} ${GLUT_LIBRARY} ${OpenCV_LIBS} pthread GL boost_system)
You need to add the option -I/usr/include/foo/ to your compilation command.
By default, locations such as /usr/include/ and /usr/local/include are already in the include search path. However, your library bar does something naughty by using #include <foo.h>. Really, it should be using things like #include <foo/foo.h> (by the way if you can make this change that would be cleaner). That would allow the compiler to search all its include paths, including the path /usr/include/, and try appending /foo/foo.h - which would succeed. As it stands, there is nothing in the default include path which would work merely by appending /foo.h, so it fails to find it.
EDIT: Given your CMake code above, most likely you need to append a variable that contains the value /usr/include/foo to the include_directories line to achieve the desired effect (this being the inclusion of -I/usr/include/foo/ on the compilation line).

Cmake configuration for multiple sub-libraries in a "packages" directory

Here is a sample project I am trying to build with a "Packages" directory which includes all the libraries to be used in the main code.
I am trying to keep my root cmake file as clean as possible and avoid relative path such as
include_directory(packages/lib1)
but I am struggling. Is there a way of including sub-directories of a directory for the purposes of header inclusion.
First a few minor remarks:
always name the CMake configuration files CMakeLists.txt (because of)
bookmark the documentation on CMake: https://cmake.org/documentation/
Sometimes it's not that easy to read, but very specific once you adopt your head to the "CMake world" ;-)
make yourself comfortable with the scope of CMake variables
include_directories(DIR1 [DIR2 [...]])
Tells CMake where the compiler should look for header files, i.e. -IDIR1 -IDIR2 ....
add_library(NAME [STATIC|SHARED] SOURCES)
This command creates the required compiler commands to create a static or shared library out of a given list of source files. No need to add in the header files. The make target will be called NAME and the library target is known to CMake as NAME.
add_subdirectory(DIR)
Tells CMake to look into DIR and parse the included CMakeLists.txt with all its content.
target_link_libraries(TARGET LIB1 [LIB2 [...]])
Tells CMake to instruct the linker to link LIB1, LIB2, etc. to the TARGET, i.e. -LLIB1 -LLIB2 .... TARGET is a CMake/make target previously defined/created with a call to add_{library,executable,custom_target}.
CMakeLists.txt:
include_directories(libraries)
# a header file in `libraries/lib1/foo.hpp` can be included
# in the whole CMake project by `#include "lib1/foo.hpp"`.
add_subdirectory(libraries)
add_subdirectory(tests)
libraries/CMakeLists.txt:
add_subdirectory(lib1)
add_subdirectory(lib2)
libraries/lib1/CMakeLists.txt:
add_library(lib1 STATIC ${LIB1_SOURCES})
libraries/lib2/CMakeLists.txt:
add_library(lib2 STATIC ${LIB2_SOURCES})
tests/CMakeLists.txt:
add_executable(tests ${TEST_SOURCES})
target_link_libraries(tests lib1 lib2)

Using CMake to statically link to a library outside of the project

I would like to use CMake to link my project to my shared library. The library is only shared between a handful of projects and is rather small, so I would really like to build it before it is linked. Building it every time seems a better idea than having to maintain an up-to-date precompiled version, because I ten to change it together with the project. It is separate, because it contains stuff I will almost certainly need in the next project.
How can I configure CMake to do it?
My current CMakeLists.txt for the relevant project looks like this:
find_package( Boost REQUIRED COMPONENTS unit_test_framework)
include_directories(${BaumWelch_SOURCE_DIR}/../../grzesLib/src
${BaumWelch_SOURCE_DIR}/src
${Boost_INCLUDE_DIRS})
if(CMAKE_COMPILER_IS_GNUCXX)
add_definitions(-g -std=c++11 -Wall -Werror -Wextra -pedantic -Wuninitialized)
endif()
# Create the unit tests executable
add_executable(
baumwelchtests stateindextest.cpp baumiterationtest.cpp baumwelchtest.cpp sampleparameters.cpp sdetest.cpp
# Key includes for setting up Boost.Test
testrunner.cpp
# Just for handy reference
exampletests.cpp
)
# Link the libraries
target_link_libraries( baumwelchtests ${Boost_LIBRARIES} baumwelchlib grzeslib)
but obviously the compilation fails with:
/usr/bin/ld: cannot find -lgrzeslib
You mentioned you'd like to build the library rather than use a precompiled version. If the library has a CMakeList, you should add it using add_subdirectory(path/to/the/library/source/directory). It will then become a subproject of your project and you can use names of its targets normally in your CMakeList.
Note that while the command is called add_subdirectory, it can be an arbitrary directory on disk; it doesn't have to be a subdirectory of the master project's source dir. In case it's not a subdirectory, you have to explicitly specify a binary directory for it as well. Example:
add_subdirectory(/path/to/the/library/source/directory subproject/grzeslib)
The second argument, if given as a relative path, is interpreted relative to CMAKE_CURRENT_BINARY_DIR.