UPDATE:我不再用我的实际计划的内容更新这个帖子了,因为它们已经发生了很大的变化(单元测试现在是用doctest完成的,代码覆盖率也包括在内,等等)。这篇文章仍然是完整的,应该足以作为新C++14项目的起点。
最近,我决定创建一个C++14对象模板,我计划在我的所有C++项目中使用该模板。我在这里使用的构建系统生成器是CMake。这是我在制定这个计划时的目标:
以下是我的项目结构:
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 in 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 in 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 in 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 in 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)以下是我想从这次审查中得到回答的问题:
src中的一个文件需要src/resources/中的一个文件。那么这个文件将在哪里安装呢?在bin还是其他地方?(充满疑问)发布于 2021-09-23 07:47:28
没有什么需要改进的。我希望看到实际的TARGET名称而不是Project-Name,但总的来说,这是一个可读性好、结构良好的CMake项目。最小的CMake版本3.1是从过去的爆炸,但如果没有使用和/或必要的最近的特性,看到适当的最小版本是很好的。这点值得尊敬!
是的,除了一个选项,即BUILD_TESTS和测试部分:
if (BUILD_TESTS)
add_subdirectory(third_party/catch)
include(CTest)
enable_testing()
add_subdirectory(test)
endif (BUILD_TESTS)CTest模块本身包含一个选项BUILD_TESTING,并调用enable_testing() if BUILD_TESTING=ON。虽然这只记录在CMake 3.15及以上中,但它一直是活动的至少自2005年以来。因此,可以将上述部分简化为
include(CTest)
if(BUILD_TESTING)
add_subdirectory(third_party/catch)
add_subdirectory(test)
endif (BUILD_TESTING)然后,我们也可以摆脱我们自己的option(BUILD_TESTS ...)。
不是很多。CMake语法总是受个人偏好的影响。我发现你的配置很容易读懂,也很容易浏览,所以我说它是非常好的。所有其他的“改进”都是我个人的喜好。该偏好的一部分是在短块上去掉endif(...)中的表达式;但这只是我的偏好。
是的,但是您的编译器检查比必要的要多一些。CMake提供MSVC检查Microsoft (++)是否处于活动状态。因此,您可以将测试放宽到
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 (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")https://codereview.stackexchange.com/questions/189489
复制相似问题