3k star 项目 learning-cmake 点评

2024-06-18 05:36

本文主要是介绍3k star 项目 learning-cmake 点评,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

3k star 项目 learning-cmake 点评

Author: ChrisZZ
Time: 2024.06.17

文章目录

  • 3k star 项目 learning-cmake 点评
    • 概要
    • hello-world
    • hello-world-clear
    • hello-world-lib
    • curl
    • hello-module
    • config-file
    • hunter-simple
    • boost
    • 总结

概要

这次我们分析 github 上搜索 cmake 排名第三的项目 https://github.com/Akagi201/learning-cmake . 第一名是 cmake 源码的镜像, 第二名是上次分析过的 cmake-examples.

从目录结构和 README.md 来看,内容不多,覆盖范围较少,内容简单, 新人应该也可以在第一次看的时候,看懂大部分内容:

LICENSE
README.md
boost
config-file
curl
docs
hello-module
hello-world
hello-world-clear
hello-world-lib
hello-world-shared
hunter-simple

接下来我们逐个目录阅读和点评。

hello-world

C 风格的示例代码。 打印了 PROJECT_BINARY_DIR 和 PROJECT_SOURCE_DIR. 坦白说个人觉得这两个目录应该换成 CMAKE_BINARY_DIR 和 CMAKE_SOURE_DIR, cmake 用户也应该逐渐淡化 project 的概念。 cmake 里的 project 对应到 Visual Studio 里的 solution, 而 Visual Studio 里的 project 对应到 CMake 里的 target, 这不免让初学者迷惑。 而且 modern cmake 强调面向 target , project 相关的变量个人建议少用。

hello-world-clear

“分离了源文件和输出文件”, 这是原作者的说明(的中文翻译), 但是我没看出来哪里有分离。 主要差别是增加了三次 INSTALL() 命令的调用, 安装了文件、程序、目录。

搞得有点过于形式化了, 不够脚踏实地, 应该创建静态库 hello,安装 hello 的库和可执行文件; 或者只安装 hello-world 可执行程序。

hello-world-lib

创建了库目标 hello_static 和 hello_shared, 然后分别执行安装。 本意是好的, 但是同时安装静态库和动态库, 这是给自己增加难度,也重复编译了相同的代码, 很别扭。 建议改造, 要么是在调用 cmake 时候, 通过控制 BUILD_SHARED_LIBS 来控制; 要么是在 CMakeLists.txt 里创建 object 目标,再分别创建静态库和动态库。

curl

这是一个 find_package() 的使用案例。

里面使用 if/else/endif 的写法过于陈旧了,得批评一下。

if(CURL_FOUND)include_directories(${CURL_INCLUDE_DIR})target_link_libraries(curltest ${CURL_LIBRARY})
else(CURL_FOUND)message(FATAL_ERROR "CURL library not found")
endif(CURL_FOUND)

应当改为

if(CURL_FOUND)include_directories(${CURL_INCLUDE_DIR})target_link_libraries(curltest ${CURL_LIBRARY})
else()message(FATAL_ERROR "CURL library not found")
endif()

另外, 指定的 cmake 最小版本竟然是 2.8.4, 去死吧老古董。

cmake_minimum_required(VERSION 2.8.4)

起码应该改为

cmake_minimum_required(VERSION 3.5)

hello-module

展示了使用 FindHELLO.cmake 文件, 来让 find_package(HELLO) 找到包的案例。 这个目录是10年前添加的, 10年过去了, cmake 官方的 cmake tutorial 里竟然都还没有这样的例子。 只能说, 没有最差, 只有更差。

这个目录的写法, 适合初学者了解 find_package 用法中的其中一个情况。 不过这其实仍然是 cmake 官方设计的不太好导致用户要学习的一个糟粕, 实际上目前已经不推荐用户自己写 FindXXX.cmake 了, 推荐写法是用户通过 cmake 生成 xxx-config.cmake 文件, 通过 find_package(xxx CONFIG) 来查询包。

config-file

本意是好的,展示使用 configure_file(), 在 configure 阶段生成 .h 文件, 里面的宏定义也是 configure 阶段生成,供 C/C++ 代码使用。

不太好的地方: 大小写不当。

CONFIGURE_FILE(${CMAKE_MODULE_PATH}/build.h.in ${CMAKE_BINARY_DIR}/build.h)
CONFIGURE_FILE(${CMAKE_MODULE_PATH}/config.h.in ${CMAKE_BINARY_DIR}/config.h)

应该改为

configure_file(${CMAKE_MODULE_PATH}/build.h.in ${CMAKE_BINARY_DIR}/build.h)
configure_file(${CMAKE_MODULE_PATH}/config.h.in ${CMAKE_BINARY_DIR}/config.h)
OPTION( WITH_FOO "Enable FOO support" ON )
OPTION( WITH_BAR "Enable BAR component" OFF )
SET( BAZ 18 )

应该改为

option(WITH_FOO "Enable FOO support" ON)
option(WITH_BAR "Enable BAR component" OFF)
set(BAZ 18)

hunter-simple

介绍了使用 hunter 这个简易的包管理器, 来导入和使用 gtest。

include("cmake/HunterGate.cmake")
HunterGate(URL "https://github.com/ruslo/hunter/archive/v0.18.16.tar.gz"SHA1 "6cbca2b0e7605ad8ea22ee3527850996436f71b8"
)

实话说这个写法真的挺雷人的, 凭啥要用什么版本的包, 要显式写出 SHA1 呢?作为一个包管理器, 只能说 Hunter 还是过于简陋, 导致用户的代码很丑很难写。

### Download dependencies ###
hunter_add_package(GTest)### Find dependencies ###
find_package(GTest CONFIG REQUIRED) # GTest::main

这两句中规中矩。

### Targets ###
add_executable(hunter_simple module.cc module_test.cc)
target_link_libraries(hunter_simple PUBLIC GTest::main)### Testing ###
enable_testing()
add_test(NAME SimpleTest COMMAND hunter_simple)

这些也中规中矩, 不过比 CMake 官方的 CMake Tutorial 里的在 CMakeLists.txt 里写单元测试 case 的写法要靠谱、实用多了。

boost

使用 boost 库的例子. 这位作者可能是写一些服务器后端、网络的选手。

project(boost_demo)
cmake_minimum_required(VERSION 3.0) # 这里应该改用 3.5find_package(Boost REQUIRED) # 很好, REQUIRED 用对了
include_directories(${Boost_INCLUDE_DIR}) # 糟糕, 应该用 target_include_directories()
link_directories(${Boost_LIBRARY_DIRS}) # 太糟糕! 绝对不能使用 link_libraries(). 会影响后续 target_include_directories() 等
set(Boost_USE_STATIC_LIBS        OFF) # 还行
set(Boost_USE_MULTITHREADED      ON)  # 还行 
set(Boost_USE_STATIC_RUNTIME     OFF) # 还行
set(BOOST_ALL_DYN_LINK           ON) # 还行add_executable(${PROJECT_NAME} main.cpp) # 可以
target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES}) # 还行

总的来说, 对于6年前的 commit, 即使是6年前点评, 也还是凑合,更别提2024年点评了。

总结

这个项目的例子不多, 应该是上传的比较早, 获得的 star 和内容丰富程度以及质量, 并不成比例。

对于 cmake 初学者, 应该可以快速看懂每个目录的内容, 但是不建议效仿, 而是应该问问自己: 这么多糟糕的地方, 自己能看出多少,改进多少?

这篇关于3k star 项目 learning-cmake 点评的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1071435

相关文章

Maven项目中集成数据库文档生成工具的操作步骤

《Maven项目中集成数据库文档生成工具的操作步骤》在Maven项目中,可以通过集成数据库文档生成工具来自动生成数据库文档,本文为大家整理了使用screw-maven-plugin(推荐)的完... 目录1. 添加插件配置到 pom.XML2. 配置数据库信息3. 执行生成命令4. 高级配置选项5. 注意事

eclipse如何运行springboot项目

《eclipse如何运行springboot项目》:本文主要介绍eclipse如何运行springboot项目问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目js录当在eclipse启动spring boot项目时出现问题解决办法1.通过cmd命令行2.在ecl

SpringBoot项目Web拦截器使用的多种方式

《SpringBoot项目Web拦截器使用的多种方式》在SpringBoot应用中,Web拦截器(Interceptor)是一种用于在请求处理的不同阶段执行自定义逻辑的机制,下面给大家介绍Sprin... 目录一、实现 HandlerInterceptor 接口1、创建HandlerInterceptor实

Maven项目打包时添加本地Jar包的操作步骤

《Maven项目打包时添加本地Jar包的操作步骤》在Maven项目开发中,我们经常会遇到需要引入本地Jar包的场景,比如使用未发布到中央仓库的第三方库或者处理版本冲突的依赖项,本文将详细介绍如何通过M... 目录一、适用场景说明​二、核心操作命令​1. 命令格式解析​2. 实战案例演示​三、项目配置步骤​1

golang实现动态路由的项目实践

《golang实现动态路由的项目实践》本文主要介绍了golang实现动态路由项目实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习... 目录一、动态路由1.结构体(数据库的定义)2.预加载preload3.添加关联的方法一、动态路由1

Spring 缓存在项目中的使用详解

《Spring缓存在项目中的使用详解》Spring缓存机制,Cache接口为缓存的组件规范定义,包扩缓存的各种操作(添加缓存、删除缓存、修改缓存等),本文给大家介绍Spring缓存在项目中的使用... 目录1.Spring 缓存机制介绍2.Spring 缓存用到的概念Ⅰ.两个接口Ⅱ.三个注解(方法层次)Ⅲ.

一文教你Java如何快速构建项目骨架

《一文教你Java如何快速构建项目骨架》在Java项目开发过程中,构建项目骨架是一项繁琐但又基础重要的工作,Java领域有许多代码生成工具可以帮助我们快速完成这一任务,下面就跟随小编一起来了解下... 目录一、代码生成工具概述常用 Java 代码生成工具简介代码生成工具的优势二、使用 MyBATis Gen

springboot项目redis缓存异常实战案例详解(提供解决方案)

《springboot项目redis缓存异常实战案例详解(提供解决方案)》redis基本上是高并发场景上会用到的一个高性能的key-value数据库,属于nosql类型,一般用作于缓存,一般是结合数据... 目录缓存异常实践案例缓存穿透问题缓存击穿问题(其中也解决了穿透问题)完整代码缓存异常实践案例Red

SpringBoot项目中Redis存储Session对象序列化处理

《SpringBoot项目中Redis存储Session对象序列化处理》在SpringBoot项目中使用Redis存储Session时,对象的序列化和反序列化是关键步骤,下面我们就来讲讲如何在Spri... 目录一、为什么需要序列化处理二、Spring Boot 集成 Redis 存储 Session2.1

springboot+vue项目怎么解决跨域问题详解

《springboot+vue项目怎么解决跨域问题详解》:本文主要介绍springboot+vue项目怎么解决跨域问题的相关资料,包括前端代理、后端全局配置CORS、注解配置和Nginx反向代理,... 目录1. 前端代理(开发环境推荐)2. 后端全局配置 CORS(生产环境推荐)3. 后端注解配置(按接口