patterncppMinor
CMakeList to compile and link an executable using Boost
Viewed 0 times
compileexecutableusingandcmakelistboostlink
Problem
I'm beginner with CMake and C++ compilation but it's seems that unlike Java I need to be very explicit with my CMakeList.txt in order to link src with correct header and libraries in my project.
Here is my CMakeList.txt
The compilation works well and I get my two executables but I wonder if there is a way less verbose to get the same result?
Here is my CMakeList.txt
cmake_minimum_required(VERSION 3.4)
project(AwesomeScheduler)
include_directories(header)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../bin)
find_package(Boost COMPONENTS system filesystem REQUIRED)
include_directories(${Boost_INCLUDE_DIRS})
set(SOCKET_SOUCE_FILES
src/socket.cpp
header/socket.h)
set(DISPTACHER_SOURCE_FILES
src/dispatcher.cpp
header/dispatcher.h
header/util.h)
set(ENDUSER_SOURCE_FILES
src/end-user.cpp
header/end-user.h
header/util.h)
set(TASKPROPERTIES_SOURCE_FILES
src/task_properties.cpp
header/task_properties.h)
add_executable(Dispatcher ${SOCKET_SOUCE_FILES} ${DISPTACHER_SOURCE_FILES})
add_executable(EndUser ${SOCKET_SOUCE_FILES} ${ENDUSER_SOURCE_FILES} ${TASKPROPERTIES_SOURCE_FILES})
target_link_libraries(EndUser ${Boost_LIBRARIES})The compilation works well and I get my two executables but I wonder if there is a way less verbose to get the same result?
Solution
As commented by @drescherjm and @NicolasHolthaus your example code already looks pretty good. If you are getting less verbose, you will always loose some information.
Minimal Version
To demonstrate this, let's take a look at a minimal version of your code:
I have
Something in Between
Because grouping the source files and adding the header files has its advantages in respect of readability, maintainability and CMake's own abilities during build environment generation, here is what I would have done in the setup you have described here:
Now you have
-
no global include directory anymore, but target specific include directories
-
So it could look something like
References
Minimal Version
To demonstrate this, let's take a look at a minimal version of your code:
cmake_minimum_required(VERSION 3.4)
project(AwesomeScheduler)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/bin")
find_package(Boost REQUIRED COMPONENTS system filesystem)
include_directories(header)
add_executable(Dispatcher src/socket.cpp src/dispatcher.cpp)
add_executable(EndUser src/socket.cpp src/end-user.cpp src/task_properties.cpp)
target_link_libraries(EndUser Boost::system Boost::filesystem)I have
- moved the source files into the
add_executable()calls
- eliminated the header files
- used the
IMPORTEDtargets from Boost, which implicitly declares the header paths also
- done some cosmetic changes to the global settings
- used the more cross-platform
CMAKE_CXX_STANDARDsetting
- using
..from the binary dir looks odd, I assumed something relative to the source dir
Something in Between
Because grouping the source files and adding the header files has its advantages in respect of readability, maintainability and CMake's own abilities during build environment generation, here is what I would have done in the setup you have described here:
cmake_minimum_required(VERSION 3.4)
project(AwesomeScheduler)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/bin")
find_package(Boost REQUIRED COMPONENTS system filesystem)
set(
SOCKET_SOUCE_FILES
src/socket.cpp
header/socket.h
)
set(
ENDUSER_SOURCE_FILES
src/end-user.cpp
header/end-user.h
src/task_properties.cpp
header/task_properties.h
header/util.h
)
set(
DISPTACHER_SOURCE_FILES
src/dispatcher.cpp
header/dispatcher.h
header/util.h
)
add_library(Socket OBJECT ${SOCKET_SOUCE_FILES})
target_include_directories(Socket PUBLIC header)
add_executable(Dispatcher ${DISPTACHER_SOURCE_FILES} $)
target_include_directories(Dispatcher PRIVATE header)
add_executable(EndUser ${ENDUSER_SOURCE_FILES} $)
target_include_directories(Dispatcher PRIVATE header)
target_link_libraries(EndUser Boost::system Boost::filesystem)Now you have
- the possibility to
- add/remove files conditionally to your source file lists
- reuse the lists in calls to e.g.
set_source_files_properties()orsource_group()
- the headers getting checked for availability and added to IDE projects during generation
- the grouping of Socket sources into a object library with e.g. it's own set of target properties to be modified
-
no global include directory anymore, but target specific include directories
- on this small project with only one
headerfolder it might be oversized, but if your code gets larger you should definitely think about the directory structure of your code
-
So it could look something like
AwesomeScheduler/
CMakeLists.txt
Dispatcher/
CMakeLists.txt
src/
dispatcher.cpp
dispatcher.h
EndUser/
CMakeLists.txt
src/
end-user.cpp
end-user.h
lib/
Socket/
CMakeLists.txt
src/
socket.cpp
include/
socket.h
include/
util.hReferences
- FindBoost CMake Module
- https://stackoverflow.com/questions/6594796/how-do-i-make-cmake-output-into-a-bin-dir
- https://stackoverflow.com/questions/10851247/how-to-activate-c-11-in-cmake
- https://stackoverflow.com/questions/2924037/separate-include-and-src-folders-for-application-level-code
- https://stackoverflow.com/questions/2360734/whats-a-good-directory-structure-for-larger-c-projects-using-makefile
- https://stackoverflow.com/questions/36872117/various-libs-in-subfolders-how-do-i-export-them-to-the-parent
Code Snippets
cmake_minimum_required(VERSION 3.4)
project(AwesomeScheduler)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/bin")
find_package(Boost REQUIRED COMPONENTS system filesystem)
include_directories(header)
add_executable(Dispatcher src/socket.cpp src/dispatcher.cpp)
add_executable(EndUser src/socket.cpp src/end-user.cpp src/task_properties.cpp)
target_link_libraries(EndUser Boost::system Boost::filesystem)cmake_minimum_required(VERSION 3.4)
project(AwesomeScheduler)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/bin")
find_package(Boost REQUIRED COMPONENTS system filesystem)
set(
SOCKET_SOUCE_FILES
src/socket.cpp
header/socket.h
)
set(
ENDUSER_SOURCE_FILES
src/end-user.cpp
header/end-user.h
src/task_properties.cpp
header/task_properties.h
header/util.h
)
set(
DISPTACHER_SOURCE_FILES
src/dispatcher.cpp
header/dispatcher.h
header/util.h
)
add_library(Socket OBJECT ${SOCKET_SOUCE_FILES})
target_include_directories(Socket PUBLIC header)
add_executable(Dispatcher ${DISPTACHER_SOURCE_FILES} $<TARGET_OBJECTS:Socket>)
target_include_directories(Dispatcher PRIVATE header)
add_executable(EndUser ${ENDUSER_SOURCE_FILES} $<TARGET_OBJECTS:Socket>)
target_include_directories(Dispatcher PRIVATE header)
target_link_libraries(EndUser Boost::system Boost::filesystem)AwesomeScheduler/
CMakeLists.txt
Dispatcher/
CMakeLists.txt
src/
dispatcher.cpp
dispatcher.h
EndUser/
CMakeLists.txt
src/
end-user.cpp
end-user.h
lib/
Socket/
CMakeLists.txt
src/
socket.cpp
include/
socket.h
include/
util.hContext
StackExchange Code Review Q#127602, answer score: 4
Revisions (0)
No revisions yet.