最近,我决定创建一个C ++ 14 oroject我计划用于所有C ++项目的模板。我在这里使用的构建系统生成器是CMake。设置时,这是我的目标:
该项目应使用MSVC,GCC和Clang进行编译。
我可以在所有平台上测试代码。
我可以在所有平台上安装目标。
我可以使用Doxygen在所有平台上生成文档。
这是我的项目结构:
project-name/
├── CMakeLists.txt
├── cmake
│ └── Modules
│ └── ParseAndAddCatchTests.cmake
├── doc
│ ├── CMakeLists.txt
│ ├── Doxyfile.in
│ └── main_page.md
├── include
│ └── project-abbr
│ ├── config.hpp <-- Contains project versioning
│ └── factorial.hpp
├── src
│ ├── CMakeLists.txt
│ ├── factorial.cpp
│ └── main.cpp
├── test
│ ├── CMakeLists.txt
│ ├── factorial_test.cpp
│ └── test_runner.cpp
└── third_party
└── catch
└── CMakeLists.txt
这是我的顶级
CMakeLists.txt
:cmake_minimum_required(VERSION 3.1)
if (POLICY CMP0048)
cmake_policy(SET CMP0048 NEW)
endif (POLICY CMP0048)
project(Project-Name VERSION 0.1.0)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# Options
option(BUILD_TESTS "Build test executable" OFF)
option(GEN_DOCS "Generate documentation" OFF)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "Setting build type to 'Release' as no build type was specified")
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the build type (Debug/Release)" FORCE)
endif (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Werror")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2")
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /WX")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /O2")
endif(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
include_directories(include)
add_subdirectory(src)
if (BUILD_TESTS)
add_subdirectory(third_party/catch)
include(CTest)
enable_testing()
add_subdirectory(test)
endif (BUILD_TESTS)
if (GEN_DOCS)
add_subdirectory(doc)
endif (GEN_DOCS)
# Install the project header files into the appropriate directory
# Other installs are in src/CMakeLists.txt
install(DIRECTORY include/ DESTINATION include)
CMakeLists.txt
中的src
:add_executable(Project-Name main.cpp) # The main executable
add_library(Project-Name-lib hello_world.cpp factorial.cpp) # A library for tests
SET_TARGET_PROPERTIES(Project-Name-lib PROPERTIES PREFIX "") # Remove the lib prefix
target_link_libraries(Project-Name Project-Name-lib) # Link our sources to the executable
install(TARGETS Project-Name DESTINATION bin)
install(TARGETS Project-Name-lib
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin
)
CMakeLists.txt
中的test
:set(TEST_SOURCES factorial_test.cpp hello_world_test.cpp)
add_executable(test_runner test_runner.cpp ${TEST_SOURCES})
target_link_libraries(test_runner Project-Name-lib)
target_include_directories(test_runner PRIVATE ${CATCH_INCLUDE_DIR} ${COMMON_INCLUDES})
include(ParseAndAddCatchTests)
ParseAndAddCatchTests(test_runner)
CMakeLists.txt
中的third_party/catch
(摘自官方文档,并略有修改):include(ExternalProject)
find_package(Git REQUIRED)
ExternalProject_Add(
catch
PREFIX ${CMAKE_BINARY_DIR}/catch
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
TIMEOUT 10
UPDATE_COMMAND ${GIT_EXECUTABLE} pull
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
LOG_DOWNLOAD ON
)
# Expose required variable (CATCH_INCLUDE_DIR) to parent scope
ExternalProject_Get_Property(catch source_dir)
set(CATCH_INCLUDE_DIR ${source_dir}/single_include CACHE INTERNAL "Path to include folder for Catch")
CMakeLists.txt
中的doc
:find_package(Doxygen)
if (DOXYGEN_FOUND)
set(DOXYGEN_IN Doxyfile.in)
set(DOXYGEN_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
configure_file(${DOXYGEN_IN} ${DOXYGEN_OUT} @ONLY)
add_custom_target(doc
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
VERBATIM
)
else (DOXYGEN_FOUND)
message(FATAL_ERROR "Doxygen needs to be installed to generate documentation!")
endif (DOXYGEN_FOUND)
这里是我想从这次评论中得到回答的问题:
我在建立项目方面遵循最佳实践吗?
我的CMake语法是否可以通过任何方式改进?
我的代码是否适合Clang,GCC和MSVC? (我已经使用Travis CI和Appveyor进行了测试,但是我只需要确定一下)
我是否正确地在正确的目录中安装了所有目标? ?假设
src
中的文件需要src/resources/
中的文件。那么该文件将安装在哪里?在bin
或其他地方? (完整的问题)
评论
是ParseAndAddCatchTests.cmake故意遗漏了吗?另外,您是否要支持其他c ++编译器,或仅支持这三个编译器?@hoffmale ParseAndAddCatchTests.cmake由Catch提供,我对该文件的逐字用法使我忽略了它。我的主要目标是支持这3个编译器,但是我不介意我是否能够支持更多...;)
作为参考,这里是ParseAndAddCatchTests.cmake。