I am currently trying to deepen my understanding regarding CMake. I try to use http://libqglviewer.com/introduction.html]LibQGLViewer as a Third-Party library in a C++ Project of mine.
The CMakeLists.txt in the associated subdirectory looks like the following where the part, I have questions is the add_libary section and some header and source files were omitted for clarity
cmake_minimum_required (VERSION 3.5.1 FATAL_ERROR)
set(target_name QGLViewerQt5)
project(${target_name})
message(STATUS "BUILDING QGLViewer-2.7.0 FROM SOURCE!")
set(BASE_DIR QGLViewer)
set(VRENDER_DIR VRender)
set(CMAKE_AUTOMOC ON)
set(QGLheaders
${BASE_DIR}/camera.h
${BASE_DIR}/config.h
${BASE_DIR}/${VRENDER_DIR}/AxisAlignedBox.h
${BASE_DIR}/${VRENDER_DIR}/Exporter.h
)
set(QGLsources
${BASE_DIR}/camera.cpp
${BASE_DIR}/${VRENDER_DIR}/Exporter.cpp
)
add_library(${target_name} ${QGLsources} ${QGLheaders})
target_include_directories(${target_name}
PUBLIC .
)
target_link_libraries(${target_name}
${OPENGL_LIBRARIES}
Qt5::Core
Qt5::Widgets
Qt5::Xml
Qt5::OpenGL
)
set(CMAKE_AUTOMOC OFF)
install(TARGETS ${target_name} DESTINATION lib)
My Application runs and everything is fine.
However, I read that one should only include the source files with add_library and then use target_include_directories to consider the associated header files. So I changes the above part to
add_library(${target_name} SHARED ${QGLsources})
target_include_directories(${target_name}
PUBLIC
${PROJECT_SOURCE_DIR}/QGLViewer
${PROJECT_SOURCE_DIR}/QGLViewer/VRender
)
but now, I get an error trying to make my project
fatal error: QGLViewer/qglviewer.h: No such file or directory
compilation terminated.
can you please tell me
What exactly does PUBLIC . do? I know what PUBLIC does but what does the point mean?
Why does it not work as before?
thank you in advance
PS: The folder structure is as follows
Firts one, target_include_directories() has following syntax according official docs target_include_directories(<target> [SYSTEM] [BEFORE]
<INTERFACE|PUBLIC|PRIVATE> [items1...] [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...]) as you see there few keywords might be used:
PRIVATE: adds directories to INCLUDE_DIRECTORIES property of <target>
INTERFACE: adds directories to INTERFACE_INCLUDE_DIRECTORIES property of <target>
PUBLIC: adds directories to INCLUDE_DIRECTORIES and INTERFACE_INCLUDE_DIRECTORIES properties of <target>
What about those properties:
INCLUDE_DIRECTORIES - contains list of directories to search header files you used in project
INTERFACE_INCLUDE_DIRECTORIES - contains list of directories to search header files too, but it has transitivity, that means you able to inherit your include directories to project linked through target_link_libraries()
Second one, your code doesn't work because you are using another include folders paths, your source file must be contain something like #include <QGLViewer/qglviewer.h> but since you do not include root folder anymore (. in your previous code), but linking QGLViewer directly - you must type #include <qglviewer.h>. Fix it for each #include you are using or add ${PROJECT_SOURCE_DIR} to target_include_directories instead.
Related
I have the following folder structure in my c++ project
*--build
|---(building cmake here)
|
*--main.cpp
|
*--CMakeLists.txt (root)
|
*--modules
|---application
|------app.h
|------app.cpp
|------CMakeLists.txt
And the code below for both CMakeLists.txt files:
CMakeLists.txt (module)
cmake_minimum_required(VERSION 3.15.2)
file(GLOB APPLICATION_HEADERS *.h *.hpp)
file(GLOB APPLICATION_SRC *.c *.cpp)
add_library(app_lib STATIC
${APPLICATION_HEADERS}
${APPLICATION_SRC})
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_LIST_DIR})
CMakeLists.txt (root)
cmake_minimum_required(VERSION 3.15.2)
project(main)
enable_language(C CXX)
#set directories
set(CMAKE_BINARY_DIR build)
set(CMAKE_CONFIGURATION_TYPES UNIX)
set(CMAKE_MODULES_DIR ${SOURCE_DIR}/cmake)
add_executable(${PROJECT_NAME} main.cpp)
# Build sub-modules
include_directories(modules/application)
add_subdirectory(modules/application)
find_library(MY_APP_LIB app_lib REQUIRED)
target_link_libraries(${PROJECT_NAME} PUBLIC ${MY_APP_LIB})
However, when I do cmake .. in my build directory, it seems like my app library just doesn't build and it doesn't link to it. I end up with the following error:
CMake Error at CMakeLists.txt:80 (find_library):
Could not find MY_APP_LIB using the following names: app_lib
I tried looking at other stackoverflow questions but it seems like I'm missing something. Any help is appreciated!
Thanks!
You don't need to use find_* to locate the library. In fact you cannot locate the library this way, since find_library searches the file system for the library during configuration, i.e. before anything gets compiled.
There's good news though: If the targets are created in the same cmake project, you can simply use the name of the cmake target as parameter for target_link_libraries:
...
add_library(app_lib STATIC
${APPLICATION_HEADERS}
${APPLICATION_SRC})
# note: this should be a property of the library, not of the target created in the parent dir
target_include_directories(app_lib PUBLIC .)
...
add_subdirectory(modules/application)
target_link_libraries(${PROJECT_NAME} PUBLIC app_lib)
You don't need to do find_library for your own targets, just link directly to app_lib:
target_link_libraries(${PROJECT_NAME} PUBLIC app_lib)
To have my .cpp and .h files a little bit sorted up pending on their responsibilitie I decided to put them into seperate folders
I used the following structure:
root
|
-CMakeLists.txt [rootCmakeList]
src
|
-main.cpp
.......|
....... math
.......|
.......-CMakeLists.txt[mathCmakeList]
.......-Algebra.h
.......-Algebra.cpp
.......XML[xmlCmakeList]
.......|
.......-CMakeLists.txt
.......-AwesomeXML.h
.......-AwesomeXML.cpp
The [rootCmakeList] looks:
cmake_minimum_required(VERSION 3.11.3)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_CXX_FLAGS_DEBUG "-g")
project(myProject)
#add exectuable
add_executable(myProject src/main.cpp)
target_include_directories(myProject PUBLIC "${src/XML}")
target_include_directories(myProject PUBLIC "${src/math}")
add_subdirectory(src/XML)
add_subdirectory(src/math)
target_link_libraries(myProject xml)#needed?
target_link_libraries(myProject math)#needed?
The [mathCmakeList] looks:
include_directories(${myProject}src/math)
add_library(math Algebra.cpp)
The [xmlCmakeList] looks:
include_directories(${myProject}src/xml)
add_library(xml AwesomeXML.cpp)
So far so good and no problems. But if I want to #include Algebra.h into
AweseomeXML.cpp I can not find the file.
To being honest I am not even sure if the cmake command add_library and target_link_libraries makes really sense here because I do not want to create own libraries of it just want to tidy up a little bit my files pending on their topic.
myProject doesn't seem to be a variable you set. Furthermore if you properly set up the library targets, you won't need to add any of the include directories to myProject manually.
First set up the CMakeLists.txt file for math, since it doesn't depend on other projects. I recommend moving headers linking libraries use to a subdirectory. I myself usually use include and any path that you want the linking library to use in #includes starts there. Set the include dirs in a way that adds them to the INTERFACE_INCLUDE_DIRECTORIES target property of math.
add_library(math Algebra.cpp
include/Algebra.h # for IDEs
)
target_include_directories(math # should be static here, since you don't want to deploy the lib by itself
PUBLIC include # available to both math and linking libs
PRIVATE . # only available to math; only necessary, if there are "private" headers
)
Then do the same thing for xml, but since you're using functionality from math, you need to link it giving you access to its include dirs automatically, since they are available via INTERFACE_INCLUDE_DIRECTORIES:
add_library(xml STATIC
AwesomeXML.cpp
include/AwesomeXML.h
)
target_include_directories(xml PUBLIC include)
target_link_libraries(xml PRIVATE math) # change PRIVATE to PUBLIC, if Algebra.h is included in a public header
Now at the toplevel we should make sure that any dependencies of a target are available before the target is defined. Also linking a lib gives you access to their respective public include directories and the public include dirs of dependencies linked publicly:
cmake_minimum_required(VERSION 3.11.3)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_CXX_FLAGS_DEBUG "-g")
project(myProject)
add_subdirectory(src/math)
add_subdirectory(src/XML)
#add exectuable
add_executable(myProject src/main.cpp)
target_link_libraries(myProject PRIVATE math xml)
If I have .h and .cpp files in the directory src, where the .cpp files include the .h files, using these commands in CMake:
aux_source_directory(src SRC_LIST)
add_executable(${PROJECT_NAME} ${SRC_LIST})
And opening that CMake file in Qt Creator, gets all the files (sources + headers) in the list of project files (the file tree on the left by default).
Now, on the other hand, if I put all the .h files in a directory include, and use this:
include_directories(include)
aux_source_directory(src SRC_LIST)
add_executable(${PROJECT_NAME} ${SRC_LIST})
The header files disappear from the project files!
How can I keep the header files in that directory, and still have them listed in Qt Creator's project files?
You shouldn't use aux_source_directory() for your task. That command is for something different. Just list the source files (or put them in a variable).
You shouldn't use include_directory() for defining include directories any more. This command will just populate the -I flag of the compiler. Define a variable with the header files and add that to the executable.
In case you don't want to list every file manually, use file(GLOB ...). But be aware of the caveats mentioned frequently all over the web with using that command.
Afterwards, tell CMake to populate the -I flag only for that executable with the include directory. That way, other targets don't get polluted by includes, they shouldn't use.
set(SOURCES
src/main.cpp
src/whatever.cpp)
set(HEADERS
include/whatever.h)
add_executable(${PROJECT_NAME} ${SOURCES} ${HEADERS})
target_include_directories(${PROJECT_NAME} PUBLIC include)
I add my header files always explicit to avoid any surprise.
But on MacOS using QtCreator 4.2.0 and cmake 3.7.1 I can't reproduce your issue.
However I recommend to use following structure to know which files are within project and to trigger update of cmake's data during update of CMakeLists.txt.
In project/CMakeLists.txt:
add_subdirectory(src)
include_directory(include)
add_executable(foo ${SRC_LIST})
In project/src/CMakeLists.txt:
set(SRC_LIST
${SRC_LIST}
${CMAKE_CURRENT_SOURCE_DIR}/a.cpp
${CMAKE_CURRENT_SOURCE_DIR}/b.cpp
PARENT_SCOPE
)
I have a set of files that I want to make into a library and then use that library in another project. This it how it looks like right now
cmake_minimum_required(VERSION 2.8)
aux_source_directory(. SRC_LIST)
SET(CMAKE_CXX_FLAGS "-std=c++11 -fopenmp -fPIC")
add_library (helperlibs lib1.cpp lib2.cpp lib3.cpp lib4.cpp )
INSTALL(TARGETS helperlibs
DESTINATION "${HOME}/lib"
)
INSTALL(FILES lib1.h lib2.h lib3.h lib4.h helperheader.h
DESTINATION "${HOME}/include/helperlibs"
)
In this code Lib4 depends on Lib1-3 and Lib3 depends on Lib1-2 and Lib2 depends on Lib1. Each of these cpp files also depend on a helperheader.h file that contains some definitions and structs.
In my project I have the following CMake file
cmake_minimum_required(VERSION 2.8)
aux_source_directory(. SRC_LIST)
SET( CMAKE_CXX_FLAGS "-std=c++11 -fopenmp -fPIC")
SET(MYINCS ${HOME}/include/helperlibs)
SET(MYLIBDIR ${HOME}/lib)
SET(MYLIBS ${MYLIBDIR}/libhelperlibs.a )
include_directories(${MYINCS})
add_executable(main main.cpp)
target_link_libraries(main ${MYLIBS})
So what I am wondering if you want to create a static library and link to from a another project using cmake is this the way you should write?
Embed the search paths into the library target as properties and create an export.
This way executables in the same build tree will find the library and its include files without you having to specify paths (they become implicit).
I needed to read the cmake documentation carefully a few times before it dawned on me how it should work.
http://www.cmake.org/cmake/help/v3.0/manual/cmake-packages.7.html#creating-packages
http://www.cmake.org/cmake/help/v3.0/manual/cmake-buildsystem.7.html
excerpt from a live example:
add_library(trustportal-util ${CMAKE_CURRENT_LIST_FILE} ${_source_files} ${_disabled_source_files} )
target_link_libraries(trustportal-util ${Boost_LIBRARIES})
if(APPLE)
find_library(SECURITY_FRAMEWORK Security)
target_link_libraries(trustportal-util ${SECURITY_FRAMEWORK})
else()
find_library(LIB_SSL ssl)
find_library(LIB_CRYPTO crypto)
target_link_libraries(trustportal-util ${LIB_SSL} ${LIB_CRYPTO})
endif()
target_compile_definitions(trustportal-util PUBLIC BOOST_MOVE_USE_STANDARD_LIBRARY_MOVE)
target_include_directories(trustportal-util PUBLIC ${Boost_INCLUDE_DIRS})
target_include_directories(trustportal-util PRIVATE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
target_include_directories(trustportal-util SYSTEM PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
install(TARGETS trustportal-util
EXPORT trustportal-utilExport
DESTINATION lib
INCLUDES DESTINATION include
)
INSTALL(EXPORT trustportal-utilExport DESTINATION lib)
One option is to do what you are currently doing where you place the includes and libs in a common location, perhaps /usr/include and /usr/lib on linux, or ${HOME} on both Windows/Linux, up to you.
Another option is available if you use git. You can include the project inside another using submodules. Then use include_directory(${submodule}) and build and link directly for every project. The advantage of this approach is that dependencies are more localised. One problem with this method is if you recursively do this, you may end up with duplicates of some projects and cmake will complain that two libraries have the same name.
I'm trying to use cmake to build my little project using protocol buffers.
There's a root directory with a number of subdirectories with a number of libraries and executables. My first thought was to have my .proto-files in a subdirectory, but when I read this answer I made a library out of it instead. But when I try to include a messages header in my executable it can't find it.
Error message:
fatal error: msgs.pb.h: No such file or directory
#include "msgs.pb.h"
^
compilation terminated.
I'm running it by creating a dir "build" and then "cmake .. && make" from inside it.
I've looked and it seems the generated files get put in build/messages, so I could do include_directories(build/messages) but that doesn't seem...proper. Is there a proper way of doing this with protobuf? The reason I want the messages file in their own folder is they they'll be used in a lot of different small executables.
Any other general tips for improvements to my CMake-structure is also appreciated :)
Directories:
root
messages
core
server
root/CMakeLists.txt:
project(lillebror)
cmake_minimum_required(VERSION 2.8)
cmake_policy(SET CMP0015 NEW)
set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
find_package(Boost COMPONENTS date_time log thread system)
find_package(Protobuf REQUIRED)
if(Boost_FOUND)
add_definitions(-std=c++11)
add_subdirectory(messages)
add_subdirectory(core)
add_subdirectory(server)
add_subdirectory(testserver)
endif()
messages/CMakeLists.txt:
file(GLOB ProtoFiles "${CMAKE_CURRENT_SOURCE_DIR}/*.proto")
PROTOBUF_GENERATE_CPP(ProtoSources ProtoHeaders ${ProtoFiles})
add_library(messages STATIC ${ProtoSources} ${ProtoHeaders})
target_link_libraries(messages ${Boost_LIBRARIES} ${PROTOBUF_LIBRARY})
core/CMakeLists.txt:
aux_source_directory(src SRC_LIST)
add_library(core STATIC ${SRC_LIST})
target_link_libraries(core messages ${Boost_LIBRARIES})
server/CMakeLists.txt:
aux_source_directory(src SRC_LIST)
include_directories(../messages) <---- I thought this would sove my problem
include_directories(../core/src)
link_directories(../core/build)
add_executable(server ${SRC_LIST})
target_link_libraries(server core ${Boost_LIBRARIES})
server/main.cpp:
#include "msgs.pb.h"
int main()
{
return 0;
}
I think the problem here is that the PROTOBUF_GENERATE_CPP function sets up the .pb.h and .pb.cc files to exist in the build tree, not in the source tree.
This is good practice (not polluting the source tree), but it means that your call include_directories(../messages) is adding the wrong value to the search paths. This is adding the source directory "root/messages", whereas you want "[build root]/messages".
You could probably just replace that line with:
include_directories(${CMAKE_BINARY_DIR}/messages)
However, a more robust, maintainable way might be to set the required include path inside the messages/CMakeLists.txt. To expose this value to the parent scope, this would need to either use set(... PARENT_SCOPE) or:
set(ProtobufIncludePath ${CMAKE_CURRENT_BINARY_DIR}
CACHE INTERNAL "Path to generated protobuf files.")
Then in the top-level CMakeLists.txt, you can do:
include_directories(${ProtobufIncludePath})
If your messages library itself needs to #include the generated protobuf files (this would be normal), then it too should have a similar include_directories call.
Having said all that, if you can specify CMake v2.8.12 as the minimum, you can use the target_include_directories command instead.
In messages/CMakeLists.txt after the add_library call, you'd simply do:
target_include_directories(messages PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
Then any other target which depends on messages automatically has the appropriate "messages" include dirs added to its own - you don't need to explicitly call include_directories at all.