3
\$\begingroup\$

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?

\$\endgroup\$
  • 2
    \$\begingroup\$ I wonder if there is a way less verbose to get the same result? In my opinion not really. There is globbing which can save you from typing a few file names but I would not bother. When you get to larger projects (I have ones with 1000s of source files) you may use functions and macros in CMake however for a simple example like this it would not help. \$\endgroup\$ – drescherjm Apr 30 '16 at 21:21
  • \$\begingroup\$ Thank you for your answer, I am now wondering why g ++ is not able to automatically link headers files that are specified in the "cpp" sources ? \$\endgroup\$ – melkir Apr 30 '16 at 22:20
  • 2
    \$\begingroup\$ You do not need to specify the headers if you do not plan to use an IDE for your project. I primarily use Visual Studio for my projects and if I do not specify the headers they do not show up in the solution view (making it harder to navigate in the ide) however the code will build fine. \$\endgroup\$ – drescherjm Apr 30 '16 at 22:26
  • 2
    \$\begingroup\$ honestly it's a pretty good looking, readable cmake file. \$\endgroup\$ – Nicolas Holthaus May 1 '16 at 0:20
  • \$\begingroup\$ I agree. What you have is about right, not too simple, not too complex. \$\endgroup\$ – doug65536 May 5 '16 at 23:34
4
\$\begingroup\$

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_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)

Now you have

  • the possibility to
  • 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

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.