Sunday, March 13, 2022

V2EX - 技术

V2EX - 技术


Git 部分命令提示 memory allocation of ... bytes failed

Posted: 13 Mar 2022 05:51 AM PDT

今天突然发现我在本地的任何一个仓库下 git diffgit log 都会提示:

memory allocation of 324400560136122233 bytes failed 

有哪位老哥知道是哪里出了问题吗?怎么排查?

网上搜了一圈感觉都不相关,是我姿势不对?

环境:macOS Monterey 12.2.1 ,git version 2.35.1

现在用的是 windows10,不想重装系统,想着升级到 11,但是又没有 tmp2.0,这个可以解决吗

Posted: 13 Mar 2022 05:14 AM PDT

现在用的是 windows10 ,不想重装系统,想着升级到 11 ,但是又没有 tmp2.0 ,这个可以解决吗

Pixel 4a5G 莫名变砖放冰箱冷藏后就好了

Posted: 13 Mar 2022 05:01 AM PDT

前年下半年 4300 多入手了一台 pixel 4a 5G ,正常用,没刷过机没维修过。

昨天早上突然死机,什么反应都没有,以为变砖了,于是干脆入了一台 Pixel6 。

昨晚拿起一直在充的 4a 5G ,有点热,突发奇想,于是放冰箱冷藏了半小时,遛狗回来就自动开机了。😄

但现在时不时黑屏,不过有震动有铃声能充电,就是不亮屏,随机过一阵子又自动亮,亮不亮纯粹看它心情😭

另外还有一个巨大的困扰就是,昨天入手的 6 现在不能新绑定 google 账号了,可能是昨天新增了几十个各种 app 账号,4a 5G 也是不能新增,这种问题有谁能破解吗?

有无懂计算机网络的 V 友,问一个单臂旁网关(N1 盒子)端口转发的问题

Posted: 13 Mar 2022 04:53 AM PDT

网络拓扑图如下,N1 盒子里是 openwrt HG9hF7YAQlZP32e

我的目的是,通过公网 IP 11.22.33.44:55900 访问我内网的电脑 B 上的 apple vnc (端口是 5900 )

但是现在的情况是:

  1. 通过电脑 C ,11.22.33.44:55900 ,可以连接
  2. 通过电脑 C ,192.168.1.1:55900 ,可以连接
  3. 通过电脑 A ,11.22.33.44:55900 ,无法连接,但是 telnet 可以连上去
  4. 通过电脑 A ,192.168.1.4:55900 ,无法连接,telnet 连接不上去
  5. 通过电脑 D ,11.22.33.44:55900 ,无法连接,但是 telnet 可以连上去
  6. 通过电脑 D ,192.168.1.4:55900 ,无法连接,telnet 连接不上去

如果我在主路由里面的端口映射改成 55900->192.168.1.5:5900, 也就是说,不走两次端口转发,只走一次主路由的端口转发,那么,出现的症状仍然和上面 1-6 一样

我觉得问题不在 N1 的端口转发,N1 的端口转发功能是正常的。

是不是我这个网络拓扑逻辑有什么问题?

但是网上也可看到有人这么配置是成功的,例如 https://www.youtube.com/watch?v=GP1ot3oQCaE

这是 openwrt 的详细配置:

xLYpW7Tje9zlkJ6

xQ47oJqb8yTDXPm

9c1MrqtRHyECeTk

一张证书引发的噱案

Posted: 13 Mar 2022 04:48 AM PDT

- 引 -

我也没想到在神策数据这大半年能遇到好几次和证书相关的问题。

- 起 -

2021 年 9 月 3 号,一个新客户接入到我们的 SaaS 系统。在某个环节,我们会给客户发个 HTTPS 请求,没想到竟然遇到了个 SSLHandshakeException:

Caused by: javax.net.ssl.SSLHandshakeException: ... unable to find valid certification path to requested target

在服务器上用 curl 试一把,也报错:

$ curl -v https://some.domain/ CAfile: /etc/pki/tls/certs/ca-bundle.crt ... curl: (60) Peer's Certificate issuer is not recognized. 

但用浏览器打开这个 URL ,却是没问题的,这说明问题应该出在我们的服务器端。

- 析 -

我们知道,HTTPS 是靠证书保证通信安全的;但客户端如何保证服务端给的证书是可信的呢?

由于证书总是由某个证书颁发机构( Certificate issuer ,或 Certificate Authority ,简写成 CA )签发的,如果我们事先将一批可信的证书颁发机构存储在本地,就可以在发起请求的时候判断证书是否可信了。

有时情况会更复杂一些:某些机构不在我们的列表里,但他的证书是由我们信任的某个机构颁发的,我们也认为他是可信的,因此他颁发的证书也是可信的。

于是这就构成了一个信任链,链的末端是「根证书颁发机构」( Root CA ),这些机构通常是国际上公认可靠的大型机构,或者国家权威机关背书的机构。

理解了这点,就可以推测,应当是我们服务器上的机构列表没有及时更新;只要把该客户证书的颁发机构加入本地的列表就应该能解决该问题。

- 解 -

再细看上面 curl 命令的输出,有一行 CAfile: /etc/pki/tls/certs/ca-bundle.crt,这就是 curl 使用到的证书颁发机构列表。

www.baidu.com 为例,我们可以通过如下命令获取客户证书的信任链:

$ openssl s_client -showcerts -servername server -connect www.baidu.com:443 > cacert.pem 

在得到的 cacert.pem 中,我们可以看到如下内容(略作简化):

Certificate chain  0 s:/CN=baidu.com    i:/CN=GlobalSign Organization Validation CA - SHA256 - G2  -----BEGIN CERTIFICATE----- MIIKQDCCCSigAwIBAgIMEZhyT2Z0o9Yhv76iMA0GCSqGSIb3DQEBCwUAMGYxCzAJ ...(略)... n3XcFtwQLBY9Iuqh8Mn7vtiv5k2azdGsYhZcFBCBAeUoRhDC -----END CERTIFICATE-----   1 s:/CN=GlobalSign Organization Validation CA - SHA256 - G2    i:/OU=Root CA/CN=GlobalSign Root CA  -----BEGIN CERTIFICATE----- MIIEaTCCA1GgAwIBAgILBAAAAAABRE7wQkcwDQYJKoZIhvcNAQELBQAwVzELMAkG ...(略)... K1pp74P1S8SqtCr4fKGxhZSM9AyHDPSsQPhZSZg= -----END CERTIFICATE-----  ...(略)... 

可以看到里面有两段用 --BEGIN CERTIFICATE----END CERTIFICATE-- 包起来的 base64 编码字符串,这就是被编码为 PEM 格式( Privacy Enhanced Mail )的证书了(有时也会用 .crt 作为扩展名)。

在 BEGIN 前面有一些摘要,可以帮助我们了解证书的内容,比如 s:/CN=baidu.com 表示这个证书的主体( s 即 subject )是 baidu.com ( CN 即 common name ),i:/CN=GlobalSign 表示它的颁发机构( i 即 issuer )是 GlobalSign 。

因此可以看到,这个 cacert.pem 实际上包含了两个证书,一个是百度使用的证书,另一个是颁发该证书的 GlobalSign 这个机构( CA )自己的证书。

通过 curl --cacert cacert.pem https://www.baidu.com 我们可以确认,这个信任链能用来验证 www.baidu.com 的证书(实际上我们只需要里面第二个证书,将第一个证书删除,不影响 curl 的执行)。

回到该客户的情况,我们用相同的方法取得客户证书颁发机构的证书,将它放到 /etc/pki/ca-trust/source/anchors/ 目录,执行 update-ca-trust 将其加入到证书列表中,就可以正常使用 curl 命令来请求了。

- 然 -

没有「但是」的文章不是好文章。

curl 正常了,但是我们的 Java 代码依然报错,这说明 java 和 curl 使用了不同的 CA 列表。

问题倒是好解决,简单搜索一下,就了解到 jre 的证书是存放在 $JAVA_HOME/jre/lib/security/cacerts 这个文件里,需要使用专门的 keytool 工具来更新它:

$ keytool -import -trustcacerts -file cacert.pem -alias 证书颁发机构的名称 -keystore $JAVA_HOME/jre/lib/security/cacerts  Enter keystore password:  changeit (这是 jre 自带的默认密码)  Certificate was added to keystore 

再次验证,Java 代码就可以正常运行了。

注:如果想要单独验证某个证书,可以这样

  • (1) 先创建一个空的 keyStore (密码为 storePassword ):
$ keytool -genkeypair -alias boguscert -storepass storePassword -keypass secretPassword -keystore keystore -dname "CN=Developer" $ keytool -delete -alias boguscert -storepass storePassword -keystore emptyStore.keystore 
  • (2) 添加证书到该 keyStore:
$ keytool -import -trustcacerts -file cacert.pem -alias 机构名称 -keystore keystore 
  • (3) 指定 keyStore 启动 java 程序:
$ java -Djavax.net.ssl.trustStore=keystore -Djavax.net.ssl.trustStorePassword=storePassword -cp $CLASS_PATH CLASS_NAME 

- 劫 -

不巧的是,这周又遇到了一个证书信任的问题,这次是客户的环境向我们的服务器发起请求,报了相同的错误。

有了前车之鉴,上面这些命令执行起来可谓得心应手,但是这次却不灵了。

排查过程比较琐碎,也因为陷入思维定势而走了一些弯路,但其实原因很简单,这里就不卖关子了。

这家客户是一家泛金融类的企业,其生产环境的网络安全级别非常高,不仅有严格的外网访问限制,而且针对所有 https 请求都会默认劫持,用一个自签名证书返回错误信息。

经过与客户沟通,将神策数据的域名添加到白名单后,问题得以解决。

- 故事 -

讲完了事故,再讲讲故事。

非对称加密、证书、信任链这一系列发明,构成了现在 web 通信安全的基石,很难想象如果没有这些基础设施,现在互联网还能做些什么。

但是这里隐藏了一个大 bug:我们凭什么相信本地这些证书颁发机构是可信的?

至少有三种情况会打破这个假设:

  • 本地 CA 列表被污染

可能你的电脑 /手机被病毒导入了 CA 证书;或者你自己可能就做过这个事情,比如公司网管要求添加公司的自签名证书,又或者你为了能使用 Charles 来抓 https 请求,导入了它自签名的 Root CA 证书。

  • 机构的私钥泄漏

我没有在公开渠道查到相关的事故(倒是有一个代理商把客户证书的私钥给泄漏了);如果某个机构的私钥泄漏,这家机构应该离倒闭也不远了。

  • 看起来正经的机构也可能不正经

各国政府控制的 CA 机构大概都干过些「不干净」的事情(至少有这种冲动),有一些被发现了,有一些还没有。出于本文的安全考虑,这里就不展开细节了。此外,「不被政府控制」的那些机构,就一定干净么?说到底,机构总是被所在国管辖的,当遇到政府行政命令的时候,不一定有反抗的能力。

综上,理论上并不存在 100% 可靠的通信安全方案。

如果你的应用对通信安全要求非常严格,连本地的 CA 列表都不相信,可以考虑加入更多的手段来提高通信的安全等级。

简单一点的场景(例如 app 不想被抓包破解协议),可以自己校验服务器的证书(证书指纹,或者自己指定证书颁发机构列表);要求更高的场景(例如需要访问内部控制系统),可以给客户端颁发证书,浏览器会在请求时提供证书用于校验,感兴趣的话可以参考 这个不太完善的项目

- 收 -

结尾照例做一个小结:

  1. HTTPS 是基于证书链来保证通信安全的;
  2. 信任的基石是本地的证书颁发机构( CA )列表;
  3. 可以通过向本地列表添加 CA 证书的方式来解决需要信任的证书;
  4. 本地的 CA 不一定都是可信的;
  5. 可以通过更严格的校验,或者客户端证书来加强通信的安全等级。

最后,神策在北京、上海、成都、武汉、深圳等多地均在招聘开发、产品、QA 等岗位,感兴趣的小伙伴欢迎私信勾搭;也可以点击我的 内推链接 查看 JD 并投递简历。

关注公众号,查看更多历史文章

   ▄▄▄▄▄▄▄   ▄      ▄▄▄▄ ▄▄▄▄▄▄▄      █ ▄▄▄ █ ▄▀ ▄ ▀██▄ ▀█▄ █ ▄▄▄ █      █ ███ █  █  █  █▀▀▀█▀ █ ███ █      █▄▄▄▄▄█ ▄ █▀█ █▀█ ▄▀█ █▄▄▄▄▄█      ▄▄▄ ▄▄▄▄█  ▀▄█▀▀▀█ ▄█▄▄   ▄        ▄█▄▄▄▄▄▀▄▀▄██   ▀ ▄  █▀▄▄▀▄▄█      █ █▀▄▀▄▄▀▀█▄▀█▄▀█████▀█▀▀█ █▄       ▀▀  █▄██▄█▀  █ ▀█▀ ▀█▀ ▄▀▀▄█      █▀ ▀ ▄▄▄▄▄▄▀▄██  █ ▄████▀▀ █▄      ▄▀▄▄▄ ▄ ▀▀▄████▀█▀  ▀ █▄▄▄▀▄█      ▄▀▀██▄▄  █▀▄▀█▀▀ █▀ ▄▄▄██▀ ▀       ▄▄▄▄▄▄▄ █ █▀ ▀▀   ▄██ ▄ █▄▀██      █ ▄▄▄ █ █▄ ▀▄▀ ▀██  █▄▄▄█▄  ▀      █ ███ █ ▄ ███▀▀▀█▄ █▀▄ ██▄ ▀█      █▄▄▄▄▄█ ██ ▄█▀█  █ ▀██▄▄▄  █▄   

程序员的人生不要设限

Posted: 13 Mar 2022 04:34 AM PDT

接上次发的帖子讨论,我觉得程序员的人生不应该给自己设限.

比如我是后端程序员,前端就不接触和学习或者前端人员就不接触学习其它的技术.

上面的做法无疑降低了自己的竞争性,一个程序员应该是努力培养自己多方面的东西,比如根据需要学习相关技术, 或者学习市场、运营相关知识,努力扩展自己的上限,不要给自己设置限制.当前就业环境可能要求我们精通某项技术然后去扭螺丝钉,但是如果离开这个公司,作为个体我能做什么.培养不依赖公司依然能让自己活下去的技术和能力很重要.单一技能可能会让我们没有太多选择性,最终越来越没有竞争里.多方面的技能会让我们在未来面对裁员或各种大环境变化的场景从容应对甚至可以快速切换职业角色.

总结一句话,人生不设限,努力扩展上限.不要当一颗随时可能被替换的螺丝钉.

睡醒有感 2022.03.13

apt 安装软件时会验证每个包的签名吗?为什么下载软件包走 http 传输,是出于性能考虑吗?

Posted: 13 Mar 2022 04:30 AM PDT

Go 语言写的 KV 引擎 NutsDB 的前生今世 & 招募开发者共建 NutsDB

Posted: 13 Mar 2022 03:11 AM PDT

昨天我写了一篇微信公众号文章,来自我的公众号『太白技术』,标题《那些年我做的开源项目之 KV 引擎( NutsDB )》

原文地址:

https://mp.weixin.qq.com/s/jrx9AHt49WP913CxiY7ewQ

NutsDB 是什么

NutsDB 是笔者在 2019 年 1 月份开源的,截止今天已经开源三年有余。它是一款简单的、高性能的纯 Go 语言开发的内嵌型 KV 引擎,支持基本的 Get 、Put 、Delete 操作、TTL ,还支持类似 Redis 的 List 、Set 、Sorted Set ,还支持 ACID 的事务。截止本文发布,最新版本是 v0.7.1 。

Star 增长趋势

目前 NutsDB 已经接近 2k 的 star

里程碑事件

具体见: https://github.com/xujiajun/nutsdb/blob/master/CHANGELOG.md

  • v0.1.0 ( 2019-2-28 )支持 Put 、Get 、Delete 、TTL 、Range Scanning 等
  • v0.2.0 ( 2019-3-05 )支持 List 、Set 、Sorted Set 等
  • v0.3.0 ( 2019-3-11 )支持 sync 等
  • v0.4.0 ( 2019-3-15 )支持 mmap 方式等
  • v0.5.0 ( 2019-11-28 )修复一些 bug & 支持 GetAll()等
  • v0.6.0 ( 2021-03-21 )支持 put 带时间戳&支持正则的 PrefixSearchScan 等
  • v0.7.0 ( 2022-03-06) 支持内存模式运行、支持 IterateBuckets 遍历 bucket 等

被用在生产环境

https://github.com/xujiajun/nutsdb/issues/27

被开源项目使用(部分)

内容摘自: https://github.com/xujiajun/nutsdb/issues/27

更多,大概还有 100+项目使用: 详见链接: https://github.com/xujiajun/nutsdb/network/dependents?package_id=UGFja2FnZS0yMjY0ODU0MDM5

招募开发者共建

我知道 v 站上卧虎藏龙,希望有兴趣的 v 友,来参与进 NutsDB 的贡献。

我专门开了一个 issue: https://github.com/xujiajun/nutsdb/issues/116

我发现我做 nutsdb 精力和能力都不够,我希望能吸引更多开发者,特别是这方面专业的,nutsdb 发展还很早期,等你的加入,现在加入门槛非常低,只要你会 go ,甚至不会也没事,学一下就好,最主要你有热情,有意愿,有学习力,这个项目非常有潜力,让我们一起打造一个知名项目!有想法联系我报名!

主要方向:

  • 1 、数据库引擎方向
  • 2 、工具生态如 cli 、可视化工具等
  • 3 、文档建设等

我们一起讨论确定做的事情,然后按照节奏推进,可以慢一点没事。

加群

欢迎加群,如果已经过期,加我个人微信( xujiajun1234567 ),备注:nutsdb ,我拉你进群

Xmake 和 C/C++ 包管理

Posted: 12 Mar 2022 11:54 PM PST

Xmake 是一个基于 Lua 的轻量级跨平台构建工具,关于 Xmake 与构建系统的介绍,我们已经在之前的文章中做了详细的介绍:C/C++ 构建系统,我用 xmake

如果大家已经对 Xmake 已经有了大概的了解,就会知道,它不仅仅是一个构建工具,还内置了对 C/C++ 包管理的支持,我们也可以把 Xmake 理解为:

Xmake = Build backend + Project Generator + Package Manager 

经过几年的持续迭代,Xmake 对 C/C++ 包管理的支持不断完善,也新增了不少实用的包管理特性,因此,在本文中,我们对其做一些总结,希望对大家有所帮助。

构建系统与包管理

C++ 的生态比较繁杂,这其中也有一定历史原因,不管如何,官方没有提供原生的包管理支持,对我们开发者来说,使用第三方 C++ 依赖库多少存在很多不便。

其实,现在已经有很多强大的 C/C++ 包管理器,最知名,用的最多的有:vcpkg, conan, conda 等等,它们虽然很强大,但是有一个共同的问题:构建工具对它们没有提供原生的支持。

由于 CMake 对它们没有提供内置支持,想在 CMake 中使用它们集成依赖包非常繁琐,并且集成和使用的方式都不一致。

在 CMake 中使用 Conan

在 CMake 中使用 conan 集成 C/C++ 包,我们需要提供额外的 CMake Wrapper 脚本,以类似插件的方式注入进自己的工程中去。

cmake_minimum_required(VERSION 3.5) project(FormatOutput CXX)  list(APPEND CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR}) list(APPEND CMAKE_PREFIX_PATH ${CMAKE_BINARY_DIR})  add_definitions("-std=c++11")  if(NOT EXISTS "${CMAKE_BINARY_DIR}/conan.cmake")   message(STATUS "Downloading conan.cmake from https://github.com/conan-io/cmake-conan")   file(DOWNLOAD "https://raw.githubusercontent.com/conan-io/cmake-conan/v0.16.1/conan.cmake"                 "${CMAKE_BINARY_DIR}/conan.cmake"                 EXPECTED_HASH SHA256=396e16d0f5eabdc6a14afddbcfff62a54a7ee75c6da23f32f7a31bc85db23484                 TLS_VERIFY ON) endif()  include(${CMAKE_BINARY_DIR}/conan.cmake)  conan_cmake_configure(REQUIRES fmt/6.1.2                       GENERATORS cmake_find_package)  conan_cmake_autodetect(settings)  conan_cmake_install(PATH_OR_REFERENCE .                     BUILD missing                     REMOTE conancenter                     SETTINGS ${settings})  find_package(fmt)  add_executable(main main.cpp) target_link_libraries(main fmt::fmt) 

为了集成一个包,需要额外配置很多的脚本。

在 CMake 中使用 Vcpkg

在 CMake 中使用 vcpkg 集成包,我们也需要额外注入一个工具链脚本文件。

cmake -B [build directory] -S . -DCMAKE_TOOLCHAIN_FILE=[path to vcpkg]/scripts/buildsystems/vcpkg.cmake cmake --build [build directory] 

另外,还有一个问题,就是我们还需要额外自己调用 vcpkg install [packages] 命令,去安装包。

这其中每一个环节,对于用户来讲都需要额外的探索过程,没法做到真正的一键编译。

想象下,用户下载了一个集成了 vcpkg 包的 cmake 项目,想要编译通过,除了项目配置,还需要做哪些额外的事情:

  1. 安装 vcpkg
  2. 执行 vcpkg install xxx 安装里面需要的包
  3. 执行 cmake 传递 vcpkg.cmake 脚本给 cmake ,进行工程配置

在 CMake 中使用 FetchContent

提供了 FetchContent 模式来管理依赖,但似乎是源码拉取,而且必须依赖也是基于 CMake 维护构建的,另外,我们需要对每个依赖项,配置 url, 版本等各种包信息。

cmake_minimum_required(VERSION 3.14) project(fetchContent_example CXX)  include(FetchContent)  FetchContent_Declare(         DocTest         GIT_REPOSITORY "https://github.com/onqtam/doctest"         GIT_TAG "932a2ca50666138256dae56fbb16db3b1cae133a" ) FetchContent_Declare(         Range-v3         GIT_REPOSITORY "https://github.com/ericniebler/range-v3"         GIT_TAG "4d6a463bca51bc316f9b565edd94e82388206093" )  FetchContent_MakeAvailable(DocTest Range-v3)  add_executable(${PROJECT_NAME} src/main.cpp) target_link_libraries(${PROJECT_NAME} doctest range-v3) 

在 Meson 中使用依赖包

Meson 很强大,并且也提供了自带的包管理支持,但是想要在 Meson 中使用其他包管理器,例如 vcpkg/conan 等等同样很繁琐,并没有提供原生支持。

在 Xmake 中使用依赖包

Xmake 不仅提供了内置的 xmake-repo 内置的包管理仓库,可以直接集成使用里面的包,还支持以相同的集成方式,去快速集成 vcpkg/conan 等第三方的依赖包。

集成一个内置依赖包只需要几行配置:

add_requires("zlib 1.2.11") target("test")     add_files("src/*.c")     add_packages("zlib") 

集成一个 vcpkg 包,仅仅只需要加上对应的包管理器命名空间,集成方式完全相同:

add_requires("vcpkg::zlib 1.2.11") target("test")     add_files("src/*.c")     add_packages("vcpkg::zlib") 

集成一个 conan 包,或者 conda, homebrew, pacman, apt, clib 等第三方包,也只需要改成 conan::zlib 就行了,用户可以随意切换包源。

另外,Xmake 会自动帮你调用 vcpkg/conan install 安装命令去安装依赖包,然后集成它们,不需要用户做任何其他事情,仅仅只需要执行 xmake 一键编译。

C/C++ 包太少?

觉得 Xmake 内置的包仓库里面的包太少么?完全没关系,理论上,你可以通过 Xmake 使用整个 C/C++ 生态 90% 的常用依赖包,就是因为 Xmake 可以快速从各种其他包管理器中集成包来使用。

目前 Xmake 支持的包源有以下这些:

  • Official package repository xmake-repo (tbox >1.6.1)
  • Official package manager Xrepo
  • User-built repositories
  • Conan (conan::openssl/1.1.1g)
  • Conda (conda::libpng 1.3.67)
  • Vcpkg (vcpkg:ffmpeg)
  • Homebrew/Linuxbrew (brew::pcre2/libpcre2-8)
  • Pacman on archlinux/msys2 (pacman::libcurl)
  • Apt on ubuntu/debian (apt::zlib1g-dev)
  • Clib (clib::clibs/bytes@0.0.4)
  • Dub (dub::log 0.4.3)
  • Portage on Gentoo/Linux (portage::libhandy)
  • Nimble for nimlang (nimble::zip >1.3)
  • Cargo for rust (cargo::base64 0.13.0)

基本上,这些仓库基本已经覆盖了 C/C++ 用户日常所需的所有包。

作者从写这篇文章开始,统计了下 vcpkg/conan/xmake-repo 仓库的包数量:

  • vcpkg: 1859
  • conan: 1218
  • xmake-repo: 651

可以看到,目前 Xmake 内置仓库的包数量,已经快要接近 vcpkg/conan 了,也不少了,我们也在不断的收录新的包进来。

但是这完全没有关系,因为我们可以使用任意包仓库中的包。

如果在 CMake 中使用 vcpkg ,我们只能使用 1859 个包。 如果在 CMake 中使用 conan ,我们只能使用 1218 个包。

而如果在 Xmake 中使用包,我们可以使用 651 (xmake-repo) + vcpkg/conan (1k+) + more (conda, homebrew, pacman, apt, clib ...) 中的包。

甚至,C/C++ 包不够,其他语言的包也可以拿过来用,例如:Xmake 也支持从 dub/cargo 等 Dlang/Rust 的包管理器中拉取包,给 C/C++ 项目使用。

Xmake 内置包管理集成

除了接入第三方包管理,我们也更推荐优先使用集成 xmake-repo 内置仓库中提供的包,Xmake 会提供更多特性支持。

因此,如果用户需要的包还没被收录,可以先尝试提交到 xmake-repo 进来。

接下来,我们系统介绍下,集成内置包的一些特性。

语义版本设置

Xmake 的依赖包管理是完全支持语义版本选择的,例如:"~1.6.1",对于语义版本的具体描述见:https://semver.org/

比如下面一些语义版本写法:

add_requires("tbox 1.6.*", "pcre 1.3.x", "libpng ^1.18") add_requires("libpng ~1.16", "zlib 1.1.2 || >=1.2.11 <1.3.0") 

当然,如果我们对当前的依赖包的版本没有特殊要求,那么可以直接这么写:

add_requires("tbox", "libpng", "zlib") 

这会使用已知的最新版本包,或者是 master 分支的源码编译的包,如果当前包有 git repo 地址,我们也能指定特定分支版本:

add_requires("tbox master") add_requires("tbox dev") 

Xmake 的语义版本支持,在几年前就已经很好的支持,而 vcpkg 也仅仅在最近一年才通过清单模式勉强支持它。

即使现在,vcpkg 对版本语义的支持也很受限,只能支持 >=1.0, 1.0 等几种版本模式,想要选择任意版本的包,比如 >=1.0 <1.5 等复杂版本条件的包,vcpkg 还是无法支持。

可选包设置

如果指定的依赖包当前平台不支持,或者编译安装失败了,那么 Xmake 会编译报错,这对于有些必须要依赖某些包才能工作的项目,这是合理的。 但是如果有些包是可选的依赖,即使没有也可以正常编译使用的话,可以设置为可选包:

add_requires("tbox", {optional = true}) 

使用系统库

默认的设置,Xmake 会去优先检测系统库是否存在(如果没设置版本要求),如果用户完全不想使用系统库以及第三方包管理提供的库,那么可以设置:

add_requires("tbox", {system = false}) 

而如果配置成:

add_requires("tbox", {system = true}) 

就是仅仅查找使用系统库,不会去远程下载安装它,这类似于 CMake 的 find_package ,但是集成方式更加简单一致。

使用调试版本的包

如果我们想同时源码调试依赖包,那么可以设置为使用 debug 版本的包(当然前提是这个包支持 debug 编译):

add_requires("tbox", {debug = true}) 

启用包的可选特性

我们也可以安装带有指定特性的包,比如安装开启了 zlib 和 libx265 的 ffmpeg 包。

add_requires("ffmpeg", {configs = {zlib = true, libx265 = true}}) 

传递额外的编译选项

我们也可以传递额外的编译选项给包:

add_requires("spdlog", {configs = {cxflags = "-Dxxx"}}) 

独立的包管理命令 Xrepo

Xrepo 是一个基于 Xmake 的跨平台 C/C++ 包管理器。

它是一个独立于 Xmake 的命令程序,用于辅助用户去管理依赖包,类似 vcpkg/conan ,但相比它们,有额外多了一些实用的特性,我们会简单介绍一些。

多仓库管理

除了可以直接从官方仓库:xmake-repo 检索安装包之外, 我们还可以添加任意多个自建的仓库,甚至可以完全隔离外网,仅仅在公司内部网络维护私有包的安装集成。

只需要通过下面的命令,添加上自己的仓库地址:

$ xrepo add-repo myrepo https://github.com/mygroup/myrepo 

基本使用

$ xrepo install zlib tbox 

安装指定版本包

完整支持 Semantic Versioning (语义版本)。

$ xrepo install "zlib 1.2.x" $ xrepo install "zlib >=1.2.0" 

安装指定平台包

$ xrepo install -p iphoneos -a arm64 zlib $ xrepo install -p android [--ndk=/xxx] zlib $ xrepo install -p mingw [--mingw=/xxx] zlib $ xrepo install -p cross --sdk=/xxx/arm-linux-musleabi-cross zlib 

安装调试版本包

$ xrepo install -m debug zlib 

安装动态库版本包

$ xrepo install -k shared zlib 

安装指定配置包

$ xrepo install -f "vs_runtime=MD" zlib $ xrepo install -f "regex=true,thread=true" boost 

安装第三方包管理器的包

$ xrepo install brew::zlib $ xrepo install vcpkg::zlib $ xrepo install conan::zlib/1.2.11 

查看包的库使用信息

$ xrepo fetch pcre2 {   {     linkdirs = {       "/usr/local/Cellar/pcre2/10.33/lib"     },     links = {       "pcre2-8"     },     defines = {       "PCRE2_CODE_UNIT_WIDTH=8"     },     includedirs = "/usr/local/Cellar/pcre2/10.33/include"   } } 
$ xrepo fetch --ldflags openssl -L/Users/ruki/.xmake/packages/o/openssl/1.1.1/d639b7d6e3244216b403b39df5101abf/lib -lcrypto -lssl 
$ xrepo fetch --cflags openssl -I/Users/ruki/.xmake/packages/o/openssl/1.1.1/d639b7d6e3244216b403b39df5101abf/include 
$ xrepo fetch -p [iphoneos|android] --cflags "zlib 1.2.x" -I/Users/ruki/.xmake/packages/z/zlib/1.2.11/df72d410e7e14391b1a4375d868a240c/include 
$ xrepo fetch --cflags --ldflags conan::zlib/1.2.11 -I/Users/ruki/.conan/data/zlib/1.2.11/_/_/package/f74366f76f700cc6e991285892ad7a23c30e6d47/include -L/Users/ruki/.conan/data/zlib/1.2.11/_/_/package/f74366f76f700cc6e991285892ad7a23c30e6d47/lib -lz 

导入导出安装后的包

xrepo 可以快速导出已经安装后的包,包括对应的库文件,头文件等等。

$ xrepo export -o /tmp/output zlib 

也可以在其他机器上导入之前导出的安装包,实现包的迁移。

$ xrepo import -i /xxx/packagedir zlib 

搜索支持的包

$ xrepo search zlib "pcr*"     zlib:       -> zlib: A Massively Spiffy Yet Delicately Unobtrusive Compression Library (in xmake-repo)     pcr*:       -> pcre2: A Perl Compatible Regular Expressions Library (in xmake-repo)       -> pcre: A Perl Compatible Regular Expressions Library (in xmake-repo) 

另外,现在还可以从 vcpkg, conan, conda 以及 apt 等第三方包管理器中搜索它们的包,只需要加上对应的包命名空间就行,例如:

$ xrepo search vcpkg::pcre The package names:     vcpkg::pcre:       -> vcpkg::pcre-8.44#8: Perl Compatible Regular Expressions       -> vcpkg::pcre2-10.35#2: PCRE2 is a re-working of the original Perl Compatible Regular Expressions library 
$ xrepo search conan::openssl The package names:     conan::openssl:       -> conan::openssl/1.1.1g:       -> conan::openssl/1.1.1h: 

包虚拟环境管理

我们可以通过在当前目录下,添加 xmake.lua 文件,定制化一些包配置,然后进入特定的包 shell 环境。

add_requires("zlib 1.2.11") add_requires("python 3.x", "luajit") 
$ xrepo env shell > python --version > luajit --version 

在 Xmake 中集成第三方构建系统

在 Xmake 中集成 Cmake 项目

Xmake 并不打算分裂 C/C++ 生态,它能很好和兼容复用现有 cmake/autoconf/meson 维护的项目,比如可以将一些其他使用 CMake 维护的代码库,直接本地集成进来,参与混合编译。

也就是说,Xmake 不会强制用户将所有的项目重新 port 到 xmake.lua ,现有的 CMake 项目,一样可以快速集成到 Xmake 项目中去。

例如,我们有如下项目结构:

├── foo │   ├── CMakeLists.txt │   └── src │       ├── foo.c │       └── foo.h ├── src │   └── main.c ├── test.lua └── xmake.lua 

foo 目录下是一个使用 CMake 维护的静态库,而根目录下使用了 Xmake 来维护,我们可以在 xmake.lua 中通过定义 package("foo") 包来描述如何构建 foo 代码库。

add_rules("mode.debug", "mode.release")  package("foo")     add_deps("cmake")     set_sourcedir(path.join(os.scriptdir(), "foo"))     on_install(function (package)         local configs = {}         table.insert(configs, "-DCMAKE_BUILD_TYPE=" .. (package:debug() and "Debug" or "Release"))         table.insert(configs, "-DBUILD_SHARED_LIBS=" .. (package:config("shared") and "ON" or "OFF"))         import("package.tools.cmake").install(package, configs)     end)     on_test(function (package)         assert(package:has_cfuncs("add", {includes = "foo.h"}))     end) package_end()  add_requires("foo")  target("demo")     set_kind("binary")     add_files("src/main.c")     add_packages("foo") 

其中,我们通过 set_sourcedir() 来设置 foo 包的代码目录位置,然后通过 import 导入 package.tools.cmake 辅助模块来调用 cmake 构建代码,xmake 会自动获取生成的 libfoo.a 和对应的头文件。

!> 如果仅仅本地源码集成,我们不需要额外设置 add_urlsadd_versions

关于包的配置描述,详情见:包描述说明

定义完包后,我们就可以通过 add_requires("foo")add_packages("foo") 来集成使用它了,就跟集成远程包一样的使用方式。

另外,on_test 是可选的,如果想要严格检测包的编译安装是否成功,可以在里面做一些测试。

完整例子见:Library with CMakeLists

在 Xmake 中集成 Meson 项目

Xmake 支持集成更多其他构建系统维护的第三方源码库,比如 Meson ,仅仅只需要导入使用 package.tools.meson 辅助构建模块调用 meson 来构建它们。

例如,我们从 xmake-repo 仓库中挑选一个使用 meson 构建的包作为例子:

package("harfbuzz")     set_sourcedir(path.join(os.scriptdir(), "3rd/harfbuzz"))     add_deps("meson")     on_install(function (package)         local configs = {"-Dtests=disabled", "-Ddocs=disabled", "-Dbenchmark=disabled", "-Dcairo=disabled", "-Dfontconfig=disabled", "-Dglib=disabled", "-Dgobject=disabled"}         table.insert(configs, "-Ddefault_library=" .. (package:config("shared") and "shared" or "static"))         import("package.tools.meson").install(package, configs)     end) 

在 Xmake 中集成 Autoconf 项目

我们也可以使用 package.tools.autoconf 来本地集成带有 autoconf 维护的第三方代码库。

package("libev")     set_sourcedir(path.join(os.scriptdir(), "3rd/libev"))     on_install(function (package)         import("package.tools.autoconf").install(package)     end) 

package.tools.autoconfpackage.tools.cmake 模块都是可以支持 mingw/cross/iphoneos/android 等交叉编译平台和工具链的,xmake 会自动传递对应的工具链进去,用户不需要做任何其他事情。

在 Xmake 中集成 Gn 项目

我们也可以使用 package.tools.gn 来本地集成带有 GN 维护的第三方代码库。

package("skia")     set_sourcedir(path.join(os.scriptdir(), "3rd/skia"))     add_deps("gn", "ninja")     on_install(function (package)         import("package.tools.gn").install(package)     end) 

这里有完整的脚本例子:Skia with GN

在 Xmake 中查找使用 CMake/C++ 包

现在 CMake 已经是事实上的标准,所以 CMake 提供的 find_package 已经可以查找大量的系统库和模块,我们也可以完全复用 CMake 的这部分生态来扩充 xmake 对包的集成。

只需要像集成 vcpkg/conan 包那样,将包命名空间改成 cmake:: 就可以了。

add_requires("cmake::ZLIB", {alias = "zlib", system = true}) target("test")     set_kind("binary")     add_files("src/*.c")     add_packages("zlib") 

我们指定 system = true 告诉 xmake 强制从系统中调用 cmake 查找包,如果找不到,不再走安装逻辑,因为 cmake 没有提供类似 vcpkg/conan 等包管理器的安装功能,只提供了包查找特性。

指定版本

add_requires("cmake::OpenCV 4.1.1", {system = true}) 

指定组件

add_requires("cmake::Boost", {system = true, configs = {components = {"regex", "system"}})} 

预设开关

add_requires("cmake::Boost", {system = true, configs = {components = {"regex", "system"},                                              presets = {Boost_USE_STATIC_LIB = true}}}) 

相当于内部调用 find_package 查找包之前,在 CMakeLists.txt 中预定义一些配置,控制 find_package 的查找策略和状态。

set(Boost_USE_STATIC_LIB ON) -- will be used in FindBoost.cmake find_package(Boost REQUIRED COMPONENTS regex system) 

设置环境变量

add_requires("cmake::OpenCV", {system = true, configs = {envs = {CMAKE_PREFIX_PATH = "xxx"}}}) 

指定自定义 FindFoo.cmake 模块脚本目录

mydir/cmake_modules/FindFoo.cmake

add_requires("cmake::Foo", {system = true, configs = {moduledirs = "mydir/cmake_modules"}}) 

在 Cmake 中集成 Xrepo 依赖包

除了可以在 Xmake 中集成 CMake 项目,我们也可以在 CMake 中直接集成 Xmake/Xrepo 提供的包,只需要使用 xrepo-cmake 提供的 CMake Wrapper 。

例如:

cmake_minimum_required(VERSION 3.13.0) project(foo)  # Download xrepo.cmake if not exists in build directory. if(NOT EXISTS "${CMAKE_BINARY_DIR}/xrepo.cmake")     message(STATUS "Downloading xrepo.cmake from https://github.com/xmake-io/xrepo-cmake/")     # mirror https://cdn.jsdelivr.net/gh/xmake-io/xrepo-cmake@main/xrepo.cmake     file(DOWNLOAD "https://raw.githubusercontent.com/xmake-io/xrepo-cmake/main/xrepo.cmake"                   "${CMAKE_BINARY_DIR}/xrepo.cmake"                   TLS_VERIFY ON) endif()  # Include xrepo.cmake so we can use xrepo_package function. include(${CMAKE_BINARY_DIR}/xrepo.cmake)  xrepo_package("zlib")  add_executable(example-bin "") target_sources(example-bin PRIVATE     src/main.cpp ) xrepo_target_packages(example-bin zlib) 

添加带有配置的包

我们,也可以跟在 Xmake 中一样,定制包的可选特性。

xrepo_package("gflags 2.2.2" CONFIGS "shared=true,mt=true")  add_executable(example-bin "") target_sources(example-bin PRIVATE     src/main.cpp ) xrepo_target_packages(example-bin gflags) 

使用来自第三个存储库的包

除了从 Xmake 官方维护的存储库安装软件包之外,我们也可以直接在 CMake 中使用它来安装来自第三方仓库的包,只需将仓库名称添加为命名空间即可。

例如:vcpkg::zlib, conan::pcre2

xrepo_package("conan::gflags/2.2.2") xrepo_package("conda::gflags 2.2.2") xrepo_package("vcpkg::gflags") xrepo_package("brew::gflags") 

通过这种方式,我们将在 CMake 中集成使用 vcpkg/conan 包的方式进行了统一,并且额外提供了自动包安装特性,以及对 homebrew/conda 等其他包仓库的支持。

Spring Cloud Gateway 返回多个 access-control-allow-origin

Posted: 12 Mar 2022 10:07 PM PST

如下图所示,OPTIONS 请求的 Response Headers 中存在两个 access-control-allow-headers 、access-control-allow-methods 、access-control-allow-origin 。

我看了Doubled CORS headers after upgrade to Greenwich · Issue #728 · spring-cloud/spring-cloud-gateway,加上了DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin这个 filter ,但是并没有效果,还是存在两个 headers 。

我尝试过"去除 downstream 的 CORS 配置,保留 gateway 的",结果还是存在两个 headers 。我尝试过"去除 gateway 的 CORS 配置,保留 downstream 的",结果是 header 都没有了,如下图所示:

实在想不明白是哪里出现问题了🤐,看看大家有没有点头绪。

有办法安全地让 Docker 容器动态编辑主机 iptables DROP 规则吗?

Posted: 12 Mar 2022 09:19 PM PST

最近服务器经常被 CC 攻击,IP 经常变,手动封一次过几小时换几个 IP 又来了。于是想写一个脚本,每分钟扫描一次 Nginx 日志,发现异常 IP 就调用 iptables DROP (感觉直接 DROP 比返回 403 效果更好,而且我不想让 Nginx 执行 Lua 脚本,感觉不太安全)(另外如果未来加了不能套 Nginx 的自己写协议的服务也能用)但这样必须在主机上以 root 用户身份跑一个脚本,还动态根据包含用户输入的日志内容调用 iptables ,攻击面又增加了,万一用户构造了一个特殊的 payload ,我的程序没有正常过滤,直接拼接进 iptables 命令,攻击者就可以逃逸到主机了,比在容器内让 Nginx 跑 Lua 脚本还不安全。请问有办法安全地让 Docker 容器动态编辑主机 iptables DROP 规则吗?

请问下 Steam deck Linux 系统怎么装 .exe 中文补丁?

Posted: 12 Mar 2022 08:01 PM PST

如题,我的 steam deck 到了,从来没接触过 Linux 系统,想给如龙极和二之国 2 装汉化补丁但是发现都是.exe 格式,试了把补丁添加到 steam 上用 proton 运行均失败,下了 wine 能打开但是无法定位到游戏安装路径,甚至把整个游戏文件夹都拷到 windows 电脑上来打补丁,但是补丁居然不识别我的游戏文件夹,实在没办法了,希望大家支支招!

NAS 下的 wifi6 速度测试还可以,云剪辑可行

Posted: 12 Mar 2022 04:06 PM PST

背景

上次打算是做一个 nas ,主要是用来云剪辑的。到目前主要是进行相关验证,首先如果要用小主机做 nas ,必须要有 nvme 的插槽,因为有这样的插槽就可以转 5sata 。否则就要有 minipcie 或者 M.2 A+E 的 无线网卡( pcie 协议的),然后把 pcie 转 nvme 卡,然后再从 nvme 转 5sata ,网上都有这样的配件卖。

过程

这次组装 nas ,把 M.2 B-key M-key ,M.2 AKey Ekey ,minipcie 。msata 。nvme ,ngff ,m.2 sata 各种乱七八糟的接口,每个插槽接口形状,协议等都搞明白了,差点逝去,实在是太乱了🤮。还有 pcie 的 2.0 3.0 X1 X2 等了解清楚了。

目前测试问题不大,测试了 2 个 sata 。买了一个 wifi6 TPlink-xdr3040 ,一个 2.5g 口,暂时用不上,因为主机是千兆口的。macbook air m1,wifi6 1200Mbps ,上传速度最大到 95MB/s ,基本稳定在 80-90MB/s ,没有办法测试有线,周一晚上跟别人借一个 USB 网卡回来再试试吧。而下载速度稍微慢一些一般在 70-85 左右,最大也到过 90+。不确定瓶颈在哪里,大概率是那个 wifi6 的能力了。

另外测试了 window 10 系统下自带的 smb 共享,大概是 40MB/s 左右,这不知道啥情况😳。在这样的速度下,进行云剪辑,拖动不卡,但是剪辑的时候 点击某个时间点的视频播放就慢 0.5+秒,也能玩。

目前在 wifi6 下进行剪辑是没问题的,在故事情节时间线上,移动播放头不会卡。但是点击播放头,会有 0.3 秒的延迟,点击延迟一下再播放。整体还是非常满意,日常剪辑是没问题了。我剪辑的是 1080p 。在剪辑的过程中,其实流量并不大,大概 5-8MB/s ,可知影响云剪辑的流畅程度只要是延迟,之前三星手机共享出来的 smb 卡是因为 ping 的延迟太高了,尤其有数据传输的时候,10-30ms ,而 wifi6 ,则保持在 4-8ms ,基本上不会卡。

还有上次说的拿大电容当 ups ,这个东西还没进行测试,应该问题不大,主要自己的手工不给力,家里没啥可利用的东西,东西一样一样的买,效率低,导致我的 nas 制作很慢,等机箱到了,再进行测试。不过我界面上手动进行群晖关机,好像需要 10 多秒😂,感觉不妙呀。

BTW: 用的是群晖 nas ,真的挺不错的,私有云还是很香的。不管是同步相册,还是 drive ,非常的舒服,配合外网 frp 或者 ddns 真的太舒服了。想尝试的,推荐 2 盘位,下载点电影,还有 drive 同步,存储的东西不要太方便了,香,推荐大家尝试。

小坑的地方

硬盘叠一起(间隙 3mm )如果没有散热风扇会挺热的。拷贝数据就更热,导致群晖的存储池都报错,异常了,重启后校验了正常。待机的时候硬盘也热,不知道是不是因为的电源 12.5V 导致的,头大。十几块的劣质电源,电压测试出 12.5+v ,卖家还说正常的+-0.5 ,我表示怀疑。。

还有 nas 关机后,如果我 12V dc 电源还插着硬盘,那么硬盘还是会转的?不是关机了么,怎么回事。。window 下也是,只要插有电源,硬盘就会转。难道硬盘的供电是由 主板进行提供的吗?

群晖的各种套件的 APP 走的地址和端口很恶心,一会儿 5000 ,一会儿 80 ,尤其走 5000 端口的,用不了域名呀,还要我打开 5000 的端口防火墙?。。有小伙伴知道怎么解决吗?还有设置 https 的话,好像是走 5001 ,还是 5006 的,我顶你个肺。。目前手机 app 可以通过域名+https 访问 photo 和 drive ,其实也够用了。其他的用电脑走隧道代理等问题不大。

end

安卓 11 已 root 怎么卸载系统 app

Posted: 12 Mar 2022 10:37 AM PST

使用老手机上的系统应用卸载器不管用了。

No comments:

Post a Comment