利用坚果云自动备份文件

坚果云提供了 webdav 协议,可以用 rclone 进行文件的上传。

  1. 登录坚果云 https://www.jianguoyun.com/#/safety 添加应用,获得密码
  2. 安装 rclone
  3. rclone config 添加坚果云配置,按照提示一步一步来就行,依次填写
    1. name: 随便填,下面与 jianguoyun 为例,后面传输文件的时候会用到该字段
    2. Storage: 选 WebDav
    3. url: 填坚果云地址 https://dav.jianguoyun.com/dav/
    4. vendor: 选 other
    5. user: 填自己的坚果云账户
    6. password: 填前面步骤中获取的应用密码,非坚果云账户密码
  4. 测试 rclone lsd jianguoyun: 如果能显示网盘的信息,就表示配置成功

上传文件

1
rclone copy /path/to/local jianguoyun:/path/to/remote

坚果云免费用户每月只提供 1G 上传流量

申请 ssl 证书

Let’s Encrypt 提供免费的 SSL/TLS 证书,Certbot 是官方推荐的自动化客户端,用于申请和续期证书。

  1. 服务器安装 certbot
  2. 域名解析,将域名解析到服务器上
  3. certbot 申请证书 (需要先停止该服务器上的 80 端口的服务)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    sudo certbot certonly -d  www.winn.cc --nginx
    Saving debug log to /var/log/letsencrypt/letsencrypt.log
    Requesting a certificate for www.winn.cc

    Successfully received certificate.
    Certificate is saved at: /etc/letsencrypt/live/www.winn.cc/fullchain.pem
    Key is saved at: /etc/letsencrypt/live/www.winn.cc/privkey.pem
    This certificate expires on 2025-07-23.
    These files will be updated when the certificate renews.
    Certbot has set up a scheduled task to automatically renew this certificate in the background.
  4. 第三步中的路径是个符号链接,用 realpath 获取真实文件路径
  5. 部署
  6. 到期时候执行 sudo certbot renew 即可更新证书。(需要先停止 80 端口服务)

ubuntu20.04 react开发

1
2
3
4
5
6
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt install -y nodejs
node -v
sudo corepack enable
sudo npm install -g yarn
yarn -v

C++ 包管理方案

为什么 C++ 没有一个统一的包管理器

很多主流语言都有自己的包管理方案,比如 Python 的 pip, JavaScript 的 npm, Java中的 Maven 等,但是 C++ 并没有一个统一的包管理方案,归根到底有一定的历史原因。C++ 标准在不断地演进,C++98,C++03,到现代的C++11/14/17/20等,每个版本都引入一些新特性,在这些标准当中引入一个官方的包管理器要考虑到前后兼容性和现有系统的影响。另外 C++ 的生态系统非常庞大和多样化,涵盖了不同的编译器,操作系统,硬件平台等,一个官方的 C++ 管理器平台如何实现需要各个社区达成一致,制定一个统一的标准,这是一个复杂且需要时间的过程。

没有包管理器的开发环境是怎样的

首先,项目规模不大的话,有没有包管理器是影响不大的,选定好平台,安装或者自己编译需要的库一直用发下去就可以了。

但如果项目规模变大可能就会出现问题,依赖项管理困难,团队成员可能需要手动,安装和管理各种依赖和第三方库。进而会导致另外一个问题,版本控制和一致性,每个团队成员手动管理依赖项的时候,可能会使用不同版本的库或者工具,增加代码的不稳定性,出现一些潜在的BUG。

同时手动维护依赖会导致很多流程无法自动化,CI/CD等无法实施 随着团队规模变大,需要投入更大的时间和精力去管理这些流程,慢慢就会变得不可持续。

包管理的各个阶段

  1. 原生拷贝。各个团队成员直接拷贝代码或者库文件给他人使用,且没有版本管理。
  2. 加入版本管理。每个团队维护好自己的代码库,通过CI自动构建,供别人下载使用。
  3. 加入依赖管理。提供一定的策略,获取递归的获取代码库所有依赖。
  4. 解决依赖冲突。当设计到依赖冲突的时候,提供策略解决冲突问题。
  5. 多平台支持。支持不同的架构,操作系统。

一种包管理平台的设计思路

Conan, 一个开源的C++包管理器工具,虽然没有被大规模普及,但是它的一些策略和方案,可以用来学习。

首先一个 C++ 包需要有哪些属性,一个软件包最终都是编译成二进制,所以就要考虑二进制库文件有哪些属性,首先是二进制包是怎么来的

  1. 构建包的体系架构(x86/arm/???),操作系统(Linux/Windows/MacOS/???), 编译器(gcc/clang/msvc/???), 编译器版本,等平台的属性。
  2. 编译选项,比如静态库还是动态库,某些编译选项等包自定义的一些属性。
  3. 依赖项。依赖哪些项目,对项目的依赖粒度,比如是否限制大版本或者小版本。

如果只管理二进制包,即编译之后的库文件,只需要上面这些属性就可以了。同一个版本比如 OpenCV/3.4.2 在不同架构,操作系统,编译器,编译选项下可能会产生数十个版本。其他用户下载固定包的时候也会带上自己的平台属性,然后找到对应的包传递给客户即可。有上面的匹配机制,就保证下载下来的一定是兼容的。

如果不想直接管理二进制库,想要通过管理源代码的方式管理各个平台的二进制库还需要更复杂的策略,比如获取源代码的方式,构建方式,打包方式等。

模板元编程,斐波那契数列

定义一个模板结构体,模板参数是个常量,结构体有个成员 v,用于存储斐波那契数。

1
2
3
4
template<int N>
struct Fib {
static constexpr int v = Fib<N-1>::v + Fib<N-2>::v;
};

注意, constexpr 用于声明一个常量表达式,明确告知编译器,该表达式可以在编译时期计算出结果。

然后针对 Fib<1> 和 Fib<2> 进行模板特化

1
2
3
4
5
6
7
8
9
template <>
struct Fib<1>{
static constexpr int v = 1;
};

template <>
struct Fib<2>{
static constexpr int v = 1;
};

然后 Fib<N>::v 就是编译期确定的斐波那契数。

下面是完整的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

#include <iostream>

template<int N>
struct Fib {
static const int v = Fib<N-1>::v + Fib<N-2>::v;
};

template <>
struct Fib<1>{
static const int v = 1;
};

template <>
struct Fib<2>{
static const int v = 1;
};

template <int Start, int End>
void print(){
if constexpr (End >= Start){
std::cout << Fib<Start>::v << std::endl;
print<Start + 1,End>();
}
}

int main(int argc, char **argv){
print<1,10>();
return 0;
}