HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

CMakeList to compile and link an executable using Boost

Submitted by: @import:stackexchange-codereview··
0
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

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:

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 IMPORTED targets from Boost, which implicitly declares the header paths also



  • done some cosmetic changes to the global settings



  • used the more cross-platform CMAKE_CXX_STANDARD setting



  • 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() or source_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 header folder 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.h


References

  • 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.h

Context

StackExchange Code Review Q#127602, answer score: 4

Revisions (0)

No revisions yet.