How would I include asio library using CMake?
Asked Answered
I

1

4

I am trying to work on a project for a class and I want to use CMake to build the project. My current project looks like

|-bin
|-CMakeLists.txt
|-include
 |-asio-1.12.2
 |-chat_message.hpp
 |-chat_message.cpp
 |-CMakeLists.txt
|-src
 |-Server.cpp

although my Server.cpp needs asio.hpp that is in /include/asio-1.12.2/include. The professor has a makefile that compiles it with the flags -DASIO_STANDALONE -Wall -O0 -g -std=c++11 -I./include -I./include/asio-1.12.2/include. My CMakeLists files look like this: ./CMakeLists.txt

CMAKE_MINIMUM_REQUIRED(VERSION 3.12)
PROJECT(Server VERSION 0.0.1)
SET(CPP_STANDARD 11)
SET(CPP_STANDARD_REQUIRED True)
ADD_SUBDIRECTORY(include)
ADD_EXECUTABLE(Server src/Server.cpp)
TARGET_LINK_LIBRARIES(
   Server PRIVATE
   chat_message
   asio
)

./include/CMakeLists.txt

ADD_LIBRARY(
   chat_message
   chat_message.cpp
   chat_message.hpp
)
ADD_LIBRARY(
   asio
   asio-1.12.2/include/asio.cpp
   asio-1.12.2/include/asio.hpp
)
TARGET_INCLUDE_DIRECTORIES(
   chat_message PUBLIC "${CMAKE_SOURCE_DIR}/include"
   asio PUBLIC "${CMAKE_SOURCE_DIR}/include/asio-1.12.2/include"
)

How would I link the asio header file to the Server.cpp file WITH the flags needed?

Icao answered 8/3, 2020 at 22:17 Comment(1)
Note, that the only target is affected by target_include_directories command is the target denoted by the first argument. For process two targets you need to call target_include_directories twice.Exosmosis
H
5

First of all, as Tzyvarev pointed out in the comments, you must split the target_include_directories() command into two separate commands. This will then propagate asio and chat_message's include directories to your Server target, which will turn add the correct include flags to the compiler flags.

Note: I'd recommend switching from CMAKE_SOURCE_DIR to CMAKE_CURRENT_SOURCE_DIR and altering your paths accordingly to make your life slightly easier if in future you decide to change your project structure, as you will usually keep a CMakeLists.txt file in the same directory as the sources for a target it creates.

The -DASIO_STANDALONE option can be added with a target_compile_definitions() call:

target_compile_definitions(asio PUBLIC ASIO_STANDALONE)

Note you do not need the -D - CMake will generate the correct compiler flag for you. Also, since this is a requirement for the asio target and all its consumers will need it, it should be added to that, rather than its consumers - it will then propagate to dependencies as needed.

In your CMakeLists.txt you have set the CPP_STANDARD and CPP_STANDARD_REQUIRED variables. The one's you're after are CMAKE_CXX_STANDARD and CMAKE_CXX_STANDARD_REQUIRED respectively.

This will set the flag for all targets throughout your project.

There are different ways to add the error, optimization and debug symbols flags and which one you use depends on your use case. The following is not an exhaustive list.

  • If you want everyone who builds the library to have these, irrespectively of build configuration (debug/release/etc), you set the CMAKE_CXX_FLAGS variable in your CMakeLists.txt
  • If you want everyone to have the flags, but only in certain build types, set the CMAKE_CXX_FLAGS_<CONFIG> variable, where <CONFIG> is the build type selected (DEBUG/RELEASE/MINSIZEREL/RELWITHDEBINFO are available by default)
  • If you don't want to force the flags upon everyone, before invoking CMake you can set the CXXFLAGS environment variable. But note that according to documentation this will be ineffective if CMAKE_CXX_FLAGS is set in your CMake scripts.
  • If you want to add flags to a single target, you can call target_compile_options on it, and set the appropriate visibility option to enable/disable propagation to consumers.

However in general you do need to think about portability when using these. For example GCC may support a certain flag which in Clang could be different.

Edit to address this comment

Since the header-only ASIO library does not like being compiled with the compiler definition mentioned above, there are two ways to address it:

Remove the ASIO_STANDALONE compiler flag

This will be the easiest thing to do from your point of view, but as a knock-on effect it will require you to have Boost installed on your system, as not having the flag above will cause the pre-processor to go through some Boost includes. There may be other effects, but this is the first one I encountered before moving on to the solution below.

Keep the flag, and use a CMake interface library

add_library() can allow you to add a target that does not actually produce any compiled objects/libraries/executables, but simply a logical CMake target that can posses properties just like any other ones - include directories, link libraries, etc. So as a minimum you could do this:

add_library(asio INTERFACE)
target_compile_options(asio INTERFACE ASIO_STANDALONE)
target_include_directories(asio INTERFACE <dir where asio.hpp lives>)
target_link_libraries(asio INTERFACE <threads>)  # Using ASIO requires you link your final executable/library with your system's threading library (e.g. pthread on linux)

Then when you link another target with it like

target_link_libraries(any_lib PRIVATE asio)

any_lib will inherit all properties required to build with ASIO.

The solution you choose will be dictated by your use case, but if you have to do it the same way as your professor, then go the INTERFACE library route.

Hutner answered 9/3, 2020 at 11:24 Comment(2)
Everything suggested here has helped me thank you for it all. Only thing it is spitting it out now is the error: "Do not compile Asio library source with ASIO_HEADER_ONLY defined" @HutnerIcao
@Icao OK I think I know what's up, I'll edit my answer to help you fix itHutner

© 2022 - 2024 — McMap. All rights reserved.