问题
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?
回答1:
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.
来源:https://stackoverflow.com/questions/60592615/how-would-i-include-asio-library-using-cmake