C++ 工程依赖管理新方向:CMake & Git

本文内容中提及的 CMake 均指提倡 target-based properties 的 modern cmake,而非史前版本的 legacy cmake。

The Right Way: 源码依赖

对于 C++ 工程而言,只要 ABI 的问题还存在,源码依赖就是最稳妥最普适最可靠的依赖引入方式;即使这些引入的源码在构建中会单独编译成(动/静态)库。

同时,GitHub 成为开源文化社区的标杆后,获取实现了某一功能的第三方库的源代码的难度大大降低。

因此个人倾向上:只要允许,都应该以特定版本的源码引入的方式去依赖一个第三方库。

事实上,Google Facebook 这些大厂内部实行的 monorepo 也是源码依赖的一种实现方式,因为某个工程需要的依赖源码都可以一并获取到。

在使用 CMake 作为构建系统的工程体系下,要以源码依赖的方式添加一个子工程只需要使用 add_subdirectory() 添加目标工程的顶层目录(根 CMakeLists.txt 所在的目录)。

Git Submodule: 一次不完美的尝试

我的个人项目 KBase 和 ezio,在此之前都是通过 git submodule 的方式引入自己需要的依赖源代码,然后通过

  • Visual Studio 子工程添加到解决方案(Windows 平台)
  • CMake add_subdirectory() 建联(*nix 平台)

依赖的版本管理直接复用 submodule 提供的特性。

Read More

Monthly Read Posts in Jan 2019

Programming Languages

Fun with(out) keyword explicit

Read More

调整 ezio 的 TCPConnection 状态事件

上上周的时候给 ezio 做了一个调整,稍微修改了一下 TCPConnection 对外暴露的几个状态变化的事件。

起因是在写 example/chat-client 的时候,因为主线程单独跑了一个事件循环从 stdin 中读取用户输入,所以 ChatClient 以及内部的 TCPClient 是跑在另外的工作线程上。

因为那个时候 TCPClient 之对外暴露了 connection 和 disconnection 的事件回调(这两个事件还统一成了一个 on_connection()),所以自然选择在 disconnection 的时候进行退出主循环的操作。

但是这个时候会出现:

  • 主循环结束后立马析构 ChatClient,连同内部的 TCPClient 一起销毁。因为这部分代码跑在主线程上,所以不会和工作线程有任何 coordination。
  • TCPClient 会在触发 on_connection() 来表明连接断开后会继续做一些内部清理工作;然而因为前面已经将 TCPClient 析构了,导致 UAF

而当时为了解决这个问题,采用的 workaround 时,ChatClient::OnConnection() 在发现连接断开后,通过 RunTaskAfter() 的方式延后执行 EventLoop::Quit()

这个做法非常丑陋而且不可靠。

Read More

来一口 golang 做的玻璃渣

转到后端差不多也快三个月了,拿 golang 糊代码的时间算上自己平时写的一些练手 demo 加起来差不多也有一个月。

这将近一个月的时间过来差不多能体会到 golang 的设计精髓,那就是:simple & stupid, being convenient as the first class support.

换句话说就是:短平快糙猛,满口玻璃渣,怎么方便怎么来。

所以接下来不免俗地是吐槽 golang 设计的内容。

吐槽不考虑 PLT 上的设计,纯粹从日常堆业务逻辑出发。毕竟理论的东西我一个鶸也不懂,且 golang 的设计目的就是方便应届毕业生快速堆业务代码。

以下吐槽点的顺序为自己在实际中遇到的顺序逆序。

Flaky Goroutines

golang 里起一个 goroutine 很方便,但是目前感觉 goroutine 太过于 flaky,有点飘。一旦没用 chan struct{} 或者 sync.WaitGroup ”固定好“,就总有一种这玩意儿是不是已经脱离自己手心的感觉。

另外不知道是不是很多用 golang 的人之前都是 php / python 的背景,相当一部分人其实对 goroutine-safe 没有什么概念。不过严格来说这个不是 golang 自身的问题。

Cannot assign to fields within short declaration notation

代码段

1
2
3
4
5
6
7
8
9
10
11
12
13
func foobar() (bool, error) {
return true, nil
}

func main() {
var err error
ok, err := foobar()
if err != nil {
fmt.Println("error")
} else {
fmt.Println(ok)
}
}

是合法的,因为 ok 之前并没有被定义,所以这里 err 可以蹭着使用 :=

Read More

Monthly Read Posts in Dec 2018

Programming Languages

init functions in Go

这篇 post 总结起来就是深入浅出。


The importance of knowing STL algorithms

能熟练运用 STL algorithms 是一个 experienced c++ programmer 的基本要求。

另外里面提到了使用 algorithms 的两个 pitfalls,其中一个是滥用 for_each(),这个确实有点意思。

Read More

虚拟机 Linux Mint 磁盘扩容

之前在虚拟机里创建 mint 时磁盘就给了 20G 的 SSD,最近发现可用容量捉襟见肘,必须要扩容一波。

摸索了一下发现给虚拟机里的 linux 磁盘扩容并不是那么简单直白,至少有几个坑,所以稍微做了一些记录,以备日后不时之需。

Step 0:通过虚拟机给系统增加磁盘容量

这一步比较简单,VMWare 的话直接在虚拟机属性里可以进行 expand;VirtualBox 应该类似。

Read More

放弃给 ezio 加 SIGINT Handler

原本的计划是今天给 ezio 加上 SIGINT 的处理:自动退出运行的 EventLoop,让程序自主正常退出;但是在实现 Windows 版本的过程中发现了一些问题,最后思考再三,决定放弃整个特性。

Read More