CMake and absolute header paths - c++

I'm trying to use CMake to build my C++ project and I have a problem in the header paths.
Since I'm using a lot of classes organized in several directories, all my include statements are with absolute paths (so no need to use "../../") but when try to make the CMake-generated Makefile it just doesn't work.
Does anyone know how to specify in CMakeLists.txt that all the includes are with absolute paths?
My output when trying to make
~/multiboost/BanditsLS/GenericBanditAlgorithmLS.h:45:25: Utils/Utils.h: No such file or directory
~/multiboost/BanditsLS/GenericBanditAlgorithmLS.h:46:35: Utils/StreamTokenizer.h: No such file or directory
My CMakeLists.txt file :
#The following command allows the use of the "file" command
cmake_minimum_required(VERSION 2.6)
#The declaration of the project
project(multiboost)
#This allows recursive parsing of the source files
file(
GLOB_RECURSE
source_files
*
)
list(REMOVE_ITEM source_files ./build/* )
#This indicates the target (the executable)
add_executable(
multiboost
${source_files} #EXCLUDE_FROM_ALL build/
)

You need something like this in CMakeLists.txt:
SET(BASEPATH "${CMAKE_SOURCE_DIR}")
INCLUDE_DIRECTORIES("${BASEPATH}")

set the correct include path: suppose your Utils directory is in /exp/appstat/benbou/multiboost, then cmake (well actually, gcc) has to know this:
include_directories( /exp/appstat/benbou/multiboost )
or it might be more convenient to pass this as an option which is passed on the command line:
include_directories( ${MyProjectRoot} )
cmake -DMyProjectRoot=/exp/appstat/benbou/multiboost

Related

CMake + Qt Creator: Add header files to project files

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
)

CMake with protobuf file in subdirectory

I have seen a lot of similar questions and answers, but until now it seems not so obvious to get it working. I am quite new to CMake and until now everything was easy except the integration with protocol buffers.
I have a project with subdirectories, where each subdirectory has its own CMakeLists.txt
One of the subdirectory contains a .proto file. If the PROTOBUF_GENERATE_CPP macro is executed it generates the sources and the headers files. This macro is invoked from the CMakeLists.txt in the subdirectory containing the .proto file.
It seems however the make file is not invoked because no sources are added to the target. I can not add the sources to the target, because the files do not exist, they exist after generation, so this results in an error when CMake runs.
Setting the file properties to generated seems also not to help. In general, before the build process starts the macro should have been run to generated the source files.
How to do this, any working examples ?
Example:
./src/externals/protodef (from other repository, only contains .proto files)
./src/generated (supposed for the generated c and header files by protoc)
CMakeLists-1 (project root)
cmake_minimum_required (VERSION 2.6)
PROJECT (prototest)
ADD_SUBDIRECTORY("${PROJECT_SOURCE_DIR}/src/externals/protodef")
ADD_SUBDIRECTORY("${PROJECT_SOURCE_DIR}/src")
SET_SOURCE_FILES_PROPERTIES(${PROTO_SOURCES} ${PROTO_HEADERS} PROPERTIES GENERATED TRUE)
ADD_EXECUTABLE(prototest ${PROTO_SOURCES} ${SOURCE} )
TARGET_LINK_LIBRARIES(prototest ${EXTERNAL_LIBS} )
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
CMakeLists-2 (src)
SET(SOURCE ${SOURCE}
${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
PARENT_SCOPE
)
CMakeLists-3 (src/externals/protodef)
SET(PROTOBUF_PATH "D:/protobuf-3.0.0/" )
SET(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "${PROTOBUF_PATH}")
# Changing PROTO_SRCS and PROTO_HDRS does not work for setting the location
# of the generated files.
# Those variable are ignored by CMake for compiling the proto files.
# Using a dedicated CMakeLists.txt and settng CURRENT_BINARY dir is a
# workaround to get them where we want.
SET(GENERATED_DIR ${PROJECT_SOURCE_DIR}/src/generated )
SET(CMAKE_CURRENT_BINARY_DIR ${GENERATED_DIR} )
INCLUDE(FindProtobuf)
FIND_PACKAGE(Protobuf REQUIRED)
PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS${CMAKE_CURRENT_SOURCE_DIR}/test1.proto)
SET( EXTERNAL_LIBS ${PROTOBUF_PATH}/lib/libprotobuf.a PARENT_SCOPE)
# Propagate sources to the parant project
SET(PROTO_SOURCES ${PROTO_SRCS}
PARENT_SCOPE
)
SET(PROTO_HEADERS ${PROTO_HDRS}
PARENT_SCOPE
)
First generate the protobuf files, then add them to a CMake target.
CMakeLists (src) :
# Generate h/cpp proto files (./src/externals/protodef) into ./src/generated folder
PROTOBUF_GENERATE_CPP(...)
# Process subdir
ADD_SUBDIRECTORY(generated)
It seems that PROTOBUF_GENERATE_CPP can only be used in the same subdirectory. A possible workaround is to invoke protoc directly instead :
FILE(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/src/externals/protodef PROTOMODEL_PATH)
FILE(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/src/generated PROTOBINDING_PATH)
FILE(GLOB DATAMODEL_PROTOS "${CMAKE_CURRENT_SOURCE_DIR}/externals/protodef/*.proto")
FOREACH(proto ${DATAMODEL_PROTOS})
FILE(TO_NATIVE_PATH ${proto} proto_native)
EXECUTE_PROCESS(COMMAND ${PROTOBUF_PROTOC_EXECUTABLE} --proto_path=${PROTOMODEL_PATH} --cpp_out=${PROTOBINDING_PATH} ${proto_native}
RESULT_VARIABLE rv)
# Optional, but that can show the user if something have gone wrong with the proto generation
IF(${rv})
MESSAGE("Generation of data model returned ${rv} for proto ${proto_native}")
ENDIF()
ENDFOREACH(proto)
CMakeLists (src/generated) :
## List generated sources files
FILE(GLOB HDRS "*.h")
FILE(GLOB SRCS "*.cc")
ADD_LIBRARY(protoBinding ${HDRS} ${SRCS})
# ${PROTOBUF_LIBRARIES} should be defined by FIND_PACKAGE(Protobuf REQUIRED)
TARGET_LINK_LIBRARIES(protoBinding ${PROTOBUF_LIBRARIES})
This way CMake will first generate the header/source files, and only then add the generated files to a CMake target.
You can then use protoBinding target to link the generated files to an other target (e.g at the end of src's CMakeLists.txt) :
ADD_LIBRARY(myModel ${myFiles})
TARGET_LINK_LIBRARIES(myModel protoBinding)

How to properly use file GLOB?

I'm trying to use GLOB_RECURSE to specify my sources and headers files. Currently, my CMakeLists.txt for a static library is:
project(LinearSystemLib)
file(GLOB_RECURSE ${PROJECT_NAME}_headers ${PROJECT_SOURCE_DIR}/*.h)
file(GLOB_RECURSE ${PROJECT_NAME}_sources ${PROJECT_SOURCE_DIR}/*.cpp)
add_library(
${PROJECT_NAME} STATIC ${${PROJECT_NAME}_headers}
${${PROJECT_NAME}_sources}
)
install(
TARGETS ${PROJECT_NAME}
LIBRARY DESTINATION libs
ARCHIVE DESTINATION archives
)
The library directory looks like this:
LinearSystemLib
CMakeLists.txt
source
LinearSystemLib.cpp
include
LinearSystemLib.h
When I run command cmake .. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug (in the build directory) everything goes ok. Yet, command make it displays the following:
/home/felipe/Documents/Dados/SINMEC/Eclipse/LinearSystemLib/source/LinearSystemLib.cpp:1:29: fatal error: LinearSystemLib.h: No such file or directory
Is my CMakeLists wrong? I don't want to set specify the sources and headers files by name. I'm not finding information about glob_recurse easily.
I can make it work by listing the sources and headers files by name. However, it MUST be done with the glob_recurse or with glob.
I solved my problem, here's what LinearSystemLib directory looks like:
LinearSystemLib
CMakeLists.txt
source
LinearSystemLib.cpp
include
LinearSystemLib.h
The CMakeLists.txt contains:
project(LinearSystemLib)
#INCLUDE DIRECTORIES
include_directories(${CMAKE_SOURCE_DIR}/${PROJECT_NAME}/include)
#SEARCH FOR .CPP AND .H FILES
file(GLOB ${PROJECT_NAME}_headers ${CMAKE_SOURCE_DIR}/${PROJECT_NAME}/include/*.h)
file(GLOB ${PROJECT_NAME}_sources ${CMAKE_SOURCE_DIR}/${PROJECT_NAME}/source/*.cpp)
#ADD LIBRARY
add_library(${PROJECT_NAME} STATIC ${${PROJECT_NAME}_sources})
#DEFINE OUTPUT LOCATION
install(
TARGETS ${PROJECT_NAME}
ARCHIVE DESTINATION static_libs
)
You don't actually NEED to add the .h/.hpp files using GLOB. I did it because otherwise, Visual Studio (or CodeBlocks) wouldn't create a "Header Files" folder on the project menu.
I wasn't properly specifying the path where GLOB would find the files.
${CMAKE_SOURCE_DIR}/${PROJECT_NAME}/source/
You need to add
target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR})
so the correct -I argument is added to your compilation step. Use make VERBOSE=1 to see exactly what commands make is executing.

cmake link subdirectories together

I have the following folder hieararchy in my QT project and I need to use some classes of the Utility folder in the classes of the ImageProcessing folder.
CMAKE file of Utilities:
file(GLOB Utilities_Files *.cpp *.h *.hpp)
# add component
add_library(Utilities ${Utilities_Files})
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
target_link_libraries(Utilities ${OpenCV_LIBRARIES})
CMAKE file of ImageProcessing:
file(GLOB ImageProcessing_FILES *.cpp *.h *.hpp)
# add component
add_library(ImageProcessing ${ImageProcessing_FILES})
include_directories(../Utilities)
target_link_libraries(ImageProcessing Utilities)
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
target_link_libraries(ImageProcessing ${OpenCV_LIBRARIES})
when I try to include classes from Utilities in classes of ImageProcessing:
#include "Utilities/className.h"
The compiler always fails.. Not sure why? It seems there is something missed or misunderstood.
Thanks.
Your line include_directories(../Utilities) adds the path ../Utilities to include directories. However, you include Utilities/className.h in the source file which makes the compiler search for files ./Utilities/className.h and ../Utilities/Utilities/className.h.
Remove one of the Utilities in either include_directories or #include.
include_directories(..)
or
#include "className.h"

how do i build libraries in subdirectories using cmake?

My code is organized like this:
cpp
main.cpp (calls code from dataStructures/ and common/)
CMakeLists.txt (topmost CMakeLists file)
build
common
CMakeLists.txt (should be responsible for building common shared library)
include
utils.h
src
utils.cpp
build
dataStructures
CMakeLists.txt (build dataStructures shared library - dependent on common library)
include
dsLinkedList.h
src
dsLinkedList.cpp
build
build\ directories contain the built target. The actual code can be seen here: https://github.com/brainydexter/PublicCode/tree/master/cpp
As of now, CMakeLists.txt in each of the subdirectories build their own shared libraries. Topmost CMakeLists file then references the libraries and paths like this
Topmost CMakeLists.txt
cmake_minimum_required(VERSION 3.2.2)
project(cpp)
#For the shared library:
set ( PROJECT_LINK_LIBS libcppDS.dylib libcppCommon.dylib)
link_directories( dataStructures/build )
link_directories( common/build )
#Bring the headers, into the project
include_directories(common/include)
include_directories(dataStructures/include)
#Can manually add the sources using the set command as follows:
set(MAINEXEC main.cpp)
add_executable(testDS ${MAINEXEC})
target_link_libraries(testDS ${PROJECT_LINK_LIBS} )
How can I change the topmost CMakeLists.txt to go into subdirectories (common and dataStructures) and build their targets if they haven't been built, without me having to manually build the individual libraries ?
CMakeLists for common :
cmake_minimum_required(VERSION 3.2.2)
project(cpp_common)
set(CMAKE_BUILD_TYPE Release)
#Bring the headers, such as Student.h into the project
include_directories(include)
#However, the file(GLOB...) allows for wildcard additions:
file(GLOB SOURCES "src/*.cpp")
#Generate the shared library from the sources
add_library(cppCommon SHARED ${SOURCES})
dataStructures :
cmake_minimum_required(VERSION 3.2.2)
project(cpp_dataStructures)
set(CMAKE_BUILD_TYPE Release)
#For the shared library:
set ( PROJECT_LINK_LIBS libcppCommon.dylib )
link_directories( ../common/build )
#Bring the headers, such as Student.h into the project
include_directories(include)
include_directories(../common/include/)
#However, the file(GLOB...) allows for wildcard additions:
file(GLOB SOURCES "src/*.cpp")
#Generate the shared library from the sources
add_library(cppDS SHARED ${SOURCES})
Update:
This pull request helped me understand the correct way of doing this:
https://github.com/brainydexter/PublicCode/pull/1
and commitId: 4b4f1d3d24b5d82f78da3cbffe423754d8c39ec0 on my git
You are only missing a simple thing: add_subdirectory.
From the documentation:
add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
Add a subdirectory to the build. The source_dir specifies the directory in which the source CMakeLists.txt and code files are located. If it is a relative path it will be evaluated with respect to the current directory (the typical usage), but it may also be an absolute path. The binary_dir specifies the directory in which to place the output files. If it is a relative path it will be evaluated with respect to the current output directory, but it may also be an absolute path.
http://www.cmake.org/cmake/help/v3.0/command/add_subdirectory.html
It does exactly what you need.