用 C 语言理解 Linux 软件库

Summary: 软件库是重复使用代码的一种简单而合理的方式。

软件库是重复使用代码的一种简单而合理的方式。

# 用 C 语言理解 Linux 软件库

>
> 软件库是重复使用代码的一种简单而合理的方式。
>
>
>

软件库是一种是一直以来长期存在的、简单合理的复用代码的方式。这篇文章解释了如何从头开始构建库并使得其可用。尽管这两个示例库都以 Linux 为例，但创建、发布和使用这些库的步骤也可以应用于其它类 Unix 系统。

这些示例库使用 C 语言编写，非常适合该任务。Linux 内核大部分由 C 语言和少量汇编语言编写（Windows 和 Linux 的表亲如 macOS 也是如此）。用于输入/输出、网络、字符串处理、数学、安全、数据编码等的标准系统库等主要由 C 语言编写。所以使用 C 语言编写库就是使用 Linux 的原生语言来编写。除此之外，C 语言的性能也在一众高级语言中鹤立鸡群。

还有两个来访问这些库的示例<ruby> 客户程序 <rt>  client </rt></ruby>（一个使用 C，另一个使用 Python）。毫无疑问可以使用 C 语言客户程序来访问 C 语言编写的库，但是 Python 客户程序示例说明了一个由 C 语言编写的库也可以服务于其他编程语言。

### 静态库和动态库对比

Linux 系统存在两种类型库：

* **静态库（也被称为归档库）**：在编译过程中的链接阶段，静态库会被编译进程序（例如 C 或 Rust）中。每个客户程序都有属于自己的一份库的拷贝。静态库有一个显而易见的缺点 —— 当库需要进行一定改动时（例如修复一个 bug），静态库必须重新链接一次。接下来要介绍的动态库避免了这一缺点。
* **动态库（也被称为共享库）**：动态库首先会在程序编译中的链接阶段被标记，但是客户程序和库代码在运行之前仍然没有联系，且库代码不会进入到客户程序中。系统的动态加载器会把一个共享库和正在运行的客户程序进行连接，无论该客户程序是由静态编译语言（如 C）编写，还是由动态解释语言（如 Python）编写。因此，动态库不需要麻烦客户程序便可以进行更新。最后，多个客户程序可以共享同一个动态库的单一副本。

通常来说，动态库优于静态库，尽管其复杂性较高而性能较低。下面是两种类型的库如何创建和发布：

1. 库的源代码会被编译成一个或多个目标模块，目标模块是二进制文件，可以被包含在库中并且链接到可执行的二进制中。
2. 目标模块会会被打包成一个文件。对于静态库，标准的文件拓展名是 `.a` 意为“<ruby> 归档 <rt>  archive </rt></ruby>”；对于动态库，标准的文件拓展名是 `.so` 意为“<ruby> 共享目标 <rt>  shared object </rt></ruby>”。对于这两个相同功能的示例库，分别发布为 `libprimes.a` （静态库）和 `libshprimes.so` （动态库）。两种库的文件名都使用前缀 `lib` 进行标识。
3. 库文件被复制到标准目录下，使得客户程序可以轻松地访问到库。无论是静态库还是动态库，典型的位置是 `/usr/lib` 或者 `/usr/local/lib`，当然其他位置也是可以的。

构建和发布每种库的具体步骤会在下面详细介绍。首先我将介绍两种库里涉及到的 C 函数。

### 示例库函数

这两个示例库都是由五个相同的 C 函数构建而成的，其中四个函数可供客户程序使用。第五个函数是其他四个函数的一个工具函数，它显示了 C 语言怎么隐藏信息。每个函数的源代码都很短，可以将这些函数放在单个源文件中，尽管也可以放在多个源文件中（如四个公布的函数都有一个文件）。

这些库函数是基本的处理函数，以多种方式来处理质数。所有的函数接收无符号（即非负）整数值作为参数：

* `is_prime` 函数测试其单个参数是否为质数。
* `are_coprimes` 函数检查了其两个参数的<ruby> 最大公约数 <rt>  greatest common divisor </rt></ruby>（gcd）是否为 1，即是否为互质数。
* `prime_factors`：函数列出其参数的质因数。
* `glodbach`：函数接收一个大于等于 4 的偶数，列出其可以分解为两个质数的和。它也许存在多个符合条件的数对。该函数是以 18 世纪数学家 <ruby>   克里斯蒂安·哥德巴赫  <rt>  Christian Goldbach </rt></ruby> 命名的，他的猜想是任意一个大于 2 的偶数可以分解为两个质数之和，这依旧是数论里最古老的未被解决的问题。

工具函数 `gcd` 留在已部署的库文件中，但是在没有包含这个函数的文件无法访问此函数。因此，一个使用库的客户程序无法调用 `gcd` 函数。仔细观察 C 函数可以明白这一点。

### 更多关于 C 函数的内容

每个在 C 语言中的函数都有一个存储类，它决定了函数的范围。对于函数，有两种选择。

* 函数默认的存储类是 `extern`，它给了函数一个全局域。一个客户程序可以调用在示例库中用 `extern` 修饰的任意函数。下面是一个带有显式 `extern` 声明的 `are_coprimes` 函数定义：

```
extern unsigned are_coprimes(unsigned n1, unsigned n2) {
  ...
}

```
* 存储类 `static` 将一个函数的的范围限制到函数被定义的文件中。在示例库中，工具函数 `gcd` 是静态的（`static`）：

```
static unsigned gcd(unsigned n1, unsigned n2) {
  ...
}

```

只有在 `primes.c` 文件中的函数可以调用 `gcd`，而只有 `are_coprimes` 函数会调用它。当静态库和动态库被构建和发布后，其他的程序可以调用外部的（`extern`）函数，如 `are_coprimes` ，但是不可以调用静态（`static`）函数 `gcd`。静态（`static`）存储类通过将函数范围限制在其他库函数内，进而实现了对库的客户程序隐藏 `gcd` 函数。

在 `primes.c` 文件中除了 `gcd` 函数外，其他函数并没有指明存储类，默认将会设置为外部的（`extern`）。然而，在库中显式注明 `extern` 更加常见。

C 语言区分了函数的<ruby> 定义 <rt>  definition </rt></ruby>和<ruby> 声明 <rt>  declaration </rt></ruby>，这对库来说很重要。接下来让我们开始了解定义。C 语言仅允许命名函数不允许匿名函数，并且每个函数需要定义以下内容：

* 一个唯一的名字。一个程序不允许存在两个同名的函数。
* 一个可以为空的参数列表。参数需要指明类型。
* 一个返回值类型（例如：`int` 代表 32 位有符号整数），当没有返回值时设置为空类型（`void`）。
* 用一对花括号包围起来的函数主体部分。在一个特制的示例中，函数主体部分可以为空。

程序中的每个函数必须要被定义一次。

下面是库函数 `are_coprimes` 的完整定义：

```
extern unsigned are_coprimes(unsigned n1, unsigned n2) { /* 定义 */
  return 1 == gcd(n1, n2); /* 最大公约数是否为 1? */
}

```

函数返回一个布尔值（`0` 代表假，`1` 代表真），取决于两个整数参数值的最大公约数是否为 1。工具函数 `gcd` 计算两个整数参数 `n1` 和 `n2` 的最大公约数。

函数声明不同于定义，其不需要主体部分：

```
extern unsigned are_coprimes(unsigned n1, unsigned n2); /* 声明 */

```

声明在参数列表后用一个分号代表结束，它没有被花括号包围起来的主体部分。程序中的函数可以被多次声明。

为什么需要声明？在 C 语言中，一个被调用的函数必须对其调用者可见。有多种方式可以提供这样的可见性，具体依赖于编译器如何实现。一个必然可行的方式就是当它们二者位于同一个文件中时，将被调用的函数定义在在它的调用者之前。

```
void f() {...}     /* f 定义在其被调用前 */
void g() { f(); }  /* ok */

```

当函数 `f` 被在调用前声明，此时函数 `f` 的定义可以移动到函数 `g` 的下方。

```
void f();         /* 声明使得函数 f 对调用者可见 */
void g() { f(); } /* ok */
void f() {...}    /* 相较于前一种方式，此方式显得更简洁 */

```

但是当如果一个被调用的函数和调用它的函数不在同一个文件中时呢？因为前文提到一个函数在一个程序中需要被定义一次，那么如何使得让一个文件中被定义的函数在另一个文件中可见？

这个问题会影响库，无论是静态库还是动态库。例如在这两个质数库中函数被定义在源文件 `primes.c` 中，每个库中都有该函数的二进制副本，但是这些定义的函数必须要对使用库的 C 程序可见，该 C 程序有其自身的源文件。

函数声明可以帮助提供跨文件的可见性。对于上述的“质数”例子，它有一个名为 `primes.h` 的头文件，其声明了四个函数使得它们对使用库的 C 程序可见。

```
/** 头文件 primes.h：函数声明 **/
extern unsigned is_prime(unsigned);
extern void prime_factors(unsigned);
extern unsigned are_coprimes(unsigned, unsigned);
extern void goldbach(unsigned);

```

这些声明通过为每个函数指定其调用语法来作为接口。

为了客户程序的便利性，头文件 `primes.h` 应该存储在 C 编译器查找路径下的目录中。典型的位置有 `/usr/include` 和 `/usr/local/include`。一个 C 语言客户程序应使用 `#include` 包含这个头文件，并尽可能将这条语句其程序源代码的首部（头文件将会被导入另一个源文件的“头”部）。C 语言头文件可以被导入其他语言（如 Rust 语言）中的 `bindgen`，使其它语言的客户程序可以访问 C 语言的库。

总之，一个库函数只可以被定义一次，但可以在任何需要它的地方进行声明，任一使用 C 语言库的程序都需要该声明。头文件可以包含函数声明，但不能包含函数定义。如果头文件包含了函数定义，那么该文件可能会在一个 C 语言程序中被多次包含，从而破坏了一个函数在 C 语言程序中必须被精确定义一次的规则。

### 库的源代码

下面是两个库的源代码。这部分代码、头文件、以及两个示例客户程序都可以在 [我的网页](https://condor.depaul.edu/mkalin) 上找到。

```
#include <stdio.h>
#include <math.h>

extern unsigned is_prime(unsigned n) {
  if (n <= 3) return n > 1;                   /* 2 和 3 是质数 */
  if (0 == (n % 2) || 0 == (n % 3)) return 0; /* 2 和 3 的倍数不会是质数 */

  /* 检查 n 是否是其他 < n 的值的倍数 */
  unsigned i;
  for (i = 5; (i * i) <= n; i += 6)
    if (0 == (n % i) || 0 == (n % (i + 2))) return 0; /* 不是质数 */

  return 1; /* 一个不是 2 和 3 的质数 */
}

extern void prime_factors(unsigned n) {
  /* 在数字 n 的质因数分解中列出所有 2 */
  while (0 == (n % 2)) {
    printf("%i ", 2);
    n /= 2;
  }

  /* 数字 2 已经处理完成，下面处理奇数 */
  unsigned i;
  for (i = 3; i <= sqrt(n); i += 2) {
    while (0 == (n % i)) {
      printf("%i ", i);
      n /= i;
    }
  }

  /* 还有其他质因数？*/
  if (n > 2) printf("%i", n);
}

/* 工具函数：计算最大公约数 */
static unsigned gcd(unsigned n1, unsigned n2) {
  while (n1 != 0) {
    unsigned n3 = n1;
    n1 = n2 % n1;
    n2 = n3;
  }
  return n2;
}

extern unsigned are_coprimes(unsigned n1, unsigned n2) {
  return 1 == gcd(n1, n2);
}

extern void goldbach(unsigned n) {
  /* 输入错误 */
  if ((n <= 2) || ((n & 0x01) > 0)) {
    printf("Number must be > 2 and even: %i is not.\n", n);
    return;
  }

  /* 两个简单的例子：4 和 6 */
  if ((4 == n) || (6 == n)) {
    printf("%i = %i + %i\n", n, n / 2, n / 2);
    return;
  }

  /* 当 n > 8 时，存在多种可能性 */
  unsigned i;
  for (i = 3; i < (n / 2); i++) {
    if (is_prime(i) && is_prime(n - i)) {
      printf("%i = %i + %i\n", n, i, n - i);
      /* 如果只需要一对，那么用 break 语句替换这句 */
    }
  }
}

```

*库函数*

这些函数可以被库利用。两个库可以从相同的源代码中获得，同时头文件 `primes.h` 是两个库的 C 语言接口。

### 构建库

静态库和动态库在构建和发布的步骤上有一些细节的不同。静态库需要三个步骤，而动态库需要增加两个步骤即一共五个步骤。额外的步骤表明了动态库的动态方法具有更多的灵活性。让我们先从静态库开始。

库的源文件 `primes.c` 被编译成一个目标模块。下面是命令，百分号 `%` 代表系统提示符，两个井字符 `#` 是我的注释。

```
% gcc -c primes.c ## 步骤1（静态）

```

这一步生成目标模块是二进制文件 `primes.o`。`-c` 标志意味着只编译。

下一步是使用 Linux 的 `ar` 命令将目标对象归档。

```
% ar -cvq libprimes.a primes.o ## 步骤2（静态）

```

`-cvq` 三个标识分别是“创建”、“详细的”、“快速添加”（以防新文件没有添加到归档中）的简称。回忆一下，前文提到过前缀 `lib` 是必须的，而库名是任意的。当然，库的文件名必须是唯一的，以避免冲突。

归档已经准备好要被发布：

```
% sudo cp libprimes.a /usr/local/lib ## 步骤3（静态）

```

现在静态库对接下来的客户程序是可见的，示例在后面。（包含 `sudo` 可以确保有访问权限将文件复制进 `/usr/local/lib` 目录中）

动态库还需要一个或多个对象模块进行打包：

```
% gcc primes.c -c -fpic ## 步骤1（动态）

```

增加的选项 `-fpic` 指示编译器生成与位置无关的代码，这意味着不需要将该二进制模块加载到一个固定的内存位置。在一个拥有多个动态库的系统中这种灵活性是至关重要的。生成的对象模块会略大于静态库生成的对象模块。

下面是从对象模块创建单个库文件的命令：

```
% gcc -shared -Wl,-soname,libshprimes.so -o libshprimes.so.1 primes.o ## 步骤2（动态）

```

选项 `-shared` 表明了该库是一个共享的（动态的）而不是静态的。`-Wl` 选项引入了一系列编译器选项，第一个便是设置动态库的 `-soname`，这是必须设置的。`soname` 首先指定了库的逻辑名字（`libshprimes.so`），接下来的 `-o` 选项指明了库的物理文件名字（`libshprimes.so.1`）。这样做的目的是为了保持逻辑名不变的同时允许物理名随着新版本而发生变化。在本例中，在物理文件名 `libshprimes.so.1` 中最后的 1 代表是第一个库的版本。尽管逻辑文件名和物理文件名可以是相同的，但是最佳做法是将它们命名为不同的名字。一个客户程序将会通过逻辑名（本例中为 `libshprimes.so`）来访问库，稍后我会进一步解释。

接下来的一步是通过复制共享库到合适的目录下使得客户程序容易访问，例如 `/usr/local/lib` 目录：

```
% sudo cp libshprimes.so.1 /usr/local/lib ## 步骤3（动态）

```

现在在共享库的逻辑名（`libshprimes.so`）和它的物理文件名（`/usr/local/lib/libshprimes.so.1`）之间设置一个符号链接。最简单的方式是将 `/usr/local/lib` 作为工作目录，在该目录下输入命令：

```
% sudo ln --symbolic libshprimes.so.1 libshprimes.so ## 步骤4（动态）

```

逻辑名 `libshprimes.so` 不应该改变，但是符号链接的目标（`libshrimes.so.1`）可以根据需要进行更新，新的库实现可以是修复了 bug，提高性能等。

最后一步（一个预防措施）是调用 `ldconfig` 工具来配置系统的动态加载器。这个配置保证了加载器能够找到新发布的库。

```
% sudo ldconfig ## 步骤5（动态）

```

到现在，动态库已为包括下面的两个在内的示例客户程序准备就绪了。

### 一个使用库的 C 程序

这个示例 C 程序是一个测试程序，它的源代码以两条 `#include` 指令开始：

```
#include <stdio.h>  /* 标准输入/输出函数 */
#include <primes.h> /* 我的库函数 */

```

文件名两边的尖括号表示可以在编译器的搜索路径中找到这些头文件（对于 `primes.h` 文件来说在 `/usr/local/inlcude` 目录下）。如果不包含 `#include`，编译器会抱怨缺少 `is_prime` 和 `prime_factors` 等函数的声明，它们在两个库中都有发布。顺便提一句，测试程序的源代码不需要更改即可测试两个库中的每一个库。

相比之下，库的源文件（`primes.c`）使用 `#include` 指令打开以下头文件：

```
#include <stdio.h>
#include <math.h>

```

`math.h` 头文件是必须的，因为库函数 `prime_factors` 会调用数学函数 `sqrt`，其在标准库 `libm.so` 中。

作为参考，这是测试库程序的源代码：

```
#include <stdio.h>
#include <primes.h>

int main() {
  /* 是质数 */
  printf("\nis_prime\n");
  unsigned i, count = 0, n = 1000;
  for (i = 1; i <= n; i++) {
    if (is_prime(i)) {
      count++;
      if (1 == (i % 100)) printf("Sample prime ending in 1: %i\n", i);
    }
  }
  printf("%i primes in range of 1 to a thousand.\n", count);

  /* prime_factors */
  printf("\nprime_factors\n");
  printf("prime factors of 12: ");
  prime_factors(12);
  printf("\n");

  printf("prime factors of 13: ");
  prime_factors(13);
  printf("\n");

  printf("prime factors of 876,512,779: ");
  prime_factors(876512779);
  printf("\n");

  /* 是合数 */
  printf("\nare_coprime\n");
  printf("Are %i and %i coprime? %s\n",
         21, 22, are_coprimes(21, 22) ? "yes" : "no");
  printf("Are %i and %i coprime? %s\n",
         21, 24, are_coprimes(21, 24) ? "yes" : "no");

  /* 哥德巴赫 */
  printf("\ngoldbach\n");
  goldbach(11);    /* error */
  goldbach(4);     /* small one */
  goldbach(6);     /* another */
  for (i = 100; i <= 150; i += 2) goldbach(i);

  return 0;
}

```

*测试程序*

在编译 `tester.c` 文件到可执行文件时，难处理的部分时链接选项的顺序。回想前文中提到两个示例库都是用 `lib` 作为前缀开始，并且每一个都有一个常规的拓展后缀：`.a` 代表静态库 `libprimes.a`，`.so` 代表动态库 `libshprimes.so`。在链接规范中，前缀 `lib` 和拓展名被忽略了。链接标志以 `-l` （小写 L）开始，并且一条编译命令可能包含多个链接标志。下面是一个完整的测试程序的编译指令，使用动态库作为示例：

```
% gcc -o tester tester.c -lshprimes -lm

```

第一个链接标志指定了库 `libshprimes.so`，第二个链接标志指定了标准数学库 `libm.so`。

链接器是懒惰的，这意味着链接标志的顺序是需要考虑的。例如，调整上述实例中的链接顺序将会产生一个编译时错误：

```
% gcc -o tester tester.c -lm -lshprimes ## 危险！

```

链接 `libm.so` 库的标志先出现，但是这个库中没有函数被测试程序显式调用；因此，链接器不会链接到 `math.so` 库。调用 `sqrt` 库函数仅发生在 `libshprimes.so` 库中包含的 `prime_factors` 函数。编译测试程序返回的错误是：

```
primes.c: undefined reference to 'sqrt'

```

因此，链接标志的顺序应该是通知链接器需要 `sqrt` 函数：

```
% gcc -o tester tester.c -lshprimes -lm ## 首先链接 -lshprimes

```

链接器在 `libshprimes.so` 库中发现了对库函数 `sqrt` 的调用，所以接下来对数学库 `libm.so`做了合适的链接。链接还有一个更复杂的选项，它支持链接的标志顺序。然而在本例中，最简单的方式就是恰当地排列链接标志。

下面是运行测试程序的部分输出结果：

```
is_prime
Sample prime ending in 1: 101
Sample prime ending in 1: 401
...
168 primes in range of 1 to a thousand.

prime_factors
prime factors of 12: 2 2 3
prime factors of 13: 13
prime factors of 876,512,779: 211 4154089

are_coprime
Are 21 and 22 coprime? yes
Are 21 and 24 coprime? no

goldbach
Number must be > 2 and even: 11 is not.
4 = 2 + 2
6 = 3 + 3
...
32 =  3 + 29
32 = 13 + 19
...
100 =  3 + 97
100 = 11 + 89
...

```

对于 `goldbach` 函数，即使一个相当小的偶数值（例如 18）也许存在多个一对质数之和的组合（在这种情况下，5+13 和 7+11）。因此这种多个质数对是使得尝试证明哥德巴赫猜想变得复杂的因素之一。

### 封装使用库的 Python 程序

与 C 不同，Python 不是一个静态编译语言，这意味着 Python 客户示例程序必须访问动态版本而非静态版本的 `primes` 库。为了能这样做，Python 中有众多的支持<ruby> 外部语言接口 <rt>  foreign function interface </rt></ruby>（FFI）的模块（标准的或第三方的），它们允许用一种语言编写的程序来调用另一种语言编写的函数。Python 中的 `ctypes` 是一个标准的、相对简单的允许 Python 代码调用 C 函数的 FFI。

任何 FFI 都面临挑战，因为对接的语言不大可能会具有完全相同的数据类型。例如：`primes` 库使用 C 语言类型 `unsigned int`，而 Python 并不具有这种类型；因此 `ctypes` FFI 将 C 语言中的 `unsigned int` 类型映射为 Python 中的 `int` 类型。在 `primes` 库中发布的四个 `extern` C 函数中，有两个在具有显式 `ctypes` 配置的 Python 中会表现得更好。

C 函数 `prime_factors` 和 `goldbach` 返回 `void` 而不是返回一个具体类型，但是 `ctypes` 默认会将 C 语言中的 `void` 替换为 Python 语言中的 `int`。当从 Python 代码中调用时，这两个 C 函数会从栈中返回一个随机整数值（因此，该值无任何意义）。然而，可以对 `ctypes` 进行配置，让这些函数返回 `None` （Python 中为 `null` 类型）。下面是对 `prime_factors` 函数的配置：

```
primes.prime_factors.restype = None

```

可以用类似的语句处理 `goldbach` 函数。

下面的交互示例（在 Python3 中）展示了在 Python 客户程序和 `primes` 库之间的接口是简单明了的。

```
>>> from ctypes import cdll

>>> primes = cdll.LoadLibrary("libshprimes.so") ## 逻辑名

>>> primes.is_prime(13)
1
>>> primes.is_prime(12)
0

>>> primes.are_coprimes(8, 24)
0
>>> primes.are_coprimes(8, 25)
1

>>> primes.prime_factors.restype = None
>>> primes.goldbach.restype = None

>>> primes.prime_factors(72)
2 2 2 3 3

>>> primes.goldbach(32)
32 = 3 + 29
32 = 13 + 19

```

在 `primes` 库中的函数只使用一个简单数据类型：`unsigned int`。如果这个 C 语言库使用复杂的类型如结构体，如果库函数传递和返回指向结构体的指针，那么比 `ctypes` 更强大的 FFI 更适合作为一个在 Python 语言和 C 语言之间的平滑接口。尽管如此，`ctypes` 示例展示了一个 Python 客户程序可以使用 C 语言编写的库。值得注意的是，用作科学计算的流行的 `Numpy` 库是用 C 语言编写的，然后在高级 Python API 中公开。

简单的 `primes` 库和高级的 `Numpy` 库强调了 C 语言仍然是编程语言中的通用语言。几乎每一个语言都可以与 C 语言交互，同时通过 C 语言也可以和任何其他语言交互。Python 很容易和 C 语言交互，作为另外一个例子，当 [Panama 项目](https://openjdk.java.net/projects/panama) 成为 Java Native Interface（JNI）一个替代品后，Java 语言和 C 语言交互也会变的很容易。

---

via: <https://opensource.com/article/21/2/linux-software-libraries>

作者：[Marty Kalin](https://opensource.com/users/mkalindepauledu) 选题：[lujun9972](https://github.com/lujun9972) 译者：[萌新阿岩](https://github.com/mengxinayan) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


在 Linux 上重新映射你的大写锁定键

# 在 Linux 上重新映射你的大写锁定键

>
> 通过在 GNOME 3 和 Wayland 上重新映射你的键盘，提高你的打字和导航速度，避免重复性压力伤害。
>
>
>

对我来说，有许多改变生活的 Linux 时刻，但大多数都在成为现状后淡忘了。有一个 Linux 教给我的键盘小技巧，每次我使用它的时候（也许每天有 1000 次），我都会想起这件事，那就是把大写锁定键转换为 `Ctrl` 键。

我从不使用大写锁定键，但我整天使用 `Ctrl` 键进行复制、粘贴、在 [Emacs](https://opensource.com/article/20/12/emacs) 内导航，以及 [调用 Bash](https://opensource.com/article/18/5/bash-tricks#key)、[GNU Screen](https://opensource.com/article/17/3/introduction-gnu-screen) 或 [tmux](https://opensource.com/article/19/6/tmux-terminal-joy) 等操作。大写锁定键在我的键盘上占据了宝贵的空间，而将实际上有用的 `Ctrl` 键挤到了难以触及的底部角落。

*这看起来就痛苦*

重新映射 `Ctrl` 提高了我的打字和导航速度，并可能使我免受重复性压力伤害。

### 消失的控制

系好安全带，这是个过山车式的历史课。

对于像我这样的大写锁定键交换者来说，不幸的是，当 GNOME 3 问世时，它几乎删除了改变 `Ctrl` 键位置的功能。

幸运的是，优秀的 GNOME Tweaks 应用程序带回了这些 “失踪” 的控制面板。

不幸的是，[GNOME 40](https://discourse.gnome.org/t/new-gnome-versioning-scheme/4235) 没有 GNOME Tweaks 应用程序（还没有？）

另外，不幸的是，过去在 X11 上可以工作的老的 `xmodmap` 技巧在新的 [Wayland 显示服务器](https://wayland.freedesktop.org) 上没有用。

有一小段时间（最多一个下午），我觉得对于那些讨厌大写锁定键的人来说人生都灰暗了。然后我想起我是一个开源的用户，总有一种方法可以解决诸如被忽略的 GUI 控制面板之类的简单问题。

### dconf

GNOME 桌面使用 dconf，这是一个存储重要配置选项的数据库。它是 GSettings 的后端，GSettings 是 GNOME 系统应用程序需要发现系统偏好时的接口。你可以使用 `gsetting` 命令查询 dconf 数据库，也可以使用 `dconf` 命令直接设置 dconf 的键值。

### GSettings

dconf 数据库不一定是你可能称为可发现的数据库。它是一个不起眼的数据库，你通常不需要去考虑它，它包含了许多通常无需直接交互的数据。然而，如果你想更好地了解 GNOME 所要管理的所有偏好选项，那么浏览它是很有趣的。

你可以用 `list-schemas` 子命令列出所有 dconf 的模式。在浏览了数百个模式之后，你可以使用 [grep](https://opensource.com/downloads/grep-cheat-sheet) 将你的注意力缩小到一些看起来特别相关的东西上，比如 `org.gnome.desktop`。

```
$ gsettings list-schemas | grep ^org.gnome.desktop
[...]
org.gnome.desktop.background
org.gnome.desktop.privacy
org.gnome.desktop.remote-desktop.vnc
org.gnome.desktop.interface
org.gnome.desktop.default-applications.terminal
org.gnome.desktop.session
org.gnome.desktop.thumbnailers
org.gnome.desktop.app-folders
org.gnome.desktop.notifications
org.gnome.desktop.sound
org.gnome.desktop.lockdown
org.gnome.desktop.default-applications.office

```

无论是通过手动搜索还是通过 [阅读 GSetting 文档](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/using_the_desktop_environment_in_rhel_8/configuring-gnome-at-low-level_using-the-desktop-environment-in-rhel-8)，你可能会注意到 `org.gnome.desktop.input-sources` 模式，它有助于定义键盘布局。从设计上来说，GSetting 模式包含了键和值。

### 用 dconf 重新映射大写字母锁

`xkb-options` 键包含了可选的键盘覆写。要设置这个键值，请使用`dconf`，将上面模式中的点（`.`）转换为斜线（`/`），因为 dconf 数据库需要使用 `/`。

```
$ dconf write /org/gnome/desktop/input-sources/xkb-options "['caps:ctrl_modifier']"

```

我把 `caps` 设置为 `ctrl_modifier`，因为我使用 `Ctrl` 修饰键的次数多于其他修饰键，但 Vim 用户可能喜欢把它设置为 `escape`。

### 查看你的设置

这个改变会立即生效，并在重启后仍然生效。这是你在 GNOME 中定义的首选项，在你改变它之前一直有效。

你可以通过 `gsettings` 查看 dconf 中的新值。首先，查看可用的键：

```
$ gsettings list-keys \
    org.gnome.desktop.input-sources
xkb-options
mru-sources
show-all-sources
current
per-window
sources

```

然后用 `xkb-options` 键名查看设置：

```
$ gsettings get \
    org.gnome.desktop.input-sources \
    xkb-options
['caps:ctrl_modifier']

```

### 选项丰富

我在我的 GNOME 3.4 系统上使用这个小技巧来设置大写锁定键以及 [Compose](https://opensource.com/article/17/5/7-cool-kde-tweaks-will-improve-your-life) 键（`compose:ralt`）。虽然我相信正在开发中的 GUI 控件可以控制这些选项，但我也不得不承认，能以编程方式设置这些选项的能力是我的荣幸。作为以前没有可靠方法来调整桌面设置的系统的管理员，能够用命令修改我的首选项使得设置新桌面变得快速而容易。

GSettings 提供了很多有用的选项，而且文档也很详尽。如果你有想要改变的东西，可以看看有什么可用的。

---

via: <https://opensource.com/article/21/5/remap-caps-lock-key-linux>

作者：[Seth Kenlon](https://opensource.com/users/seth) 选题：[lujun9972](https://github.com/lujun9972) 译者：[wxy](https://github.com/wxy) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


硬核观察 | 大批开源项目逃离 Freenode IRC 网络

Summary: 更多：• 1nm 以下制程获得重大突破 • RHEL 8.4 发布

难得见你们还会提一嘴“自由软件”

来自120.244.128.58的 Firefox 88.0|Android 用户

Freenode什么瓜

来自广东深圳的 Firefox 3.5|Symbian OS Series 60 用户

更多：• 1nm 以下制程获得重大突破 • RHEL 8.4 发布

# 硬核观察 | 大批开源项目逃离 Freenode IRC 网络

### 大批开源项目逃离 Freenode IRC 网络

Freenode IRC 网络已经存在了二十多年，在自由及开源软件项目中非常流行，它用于参与开发讨论、用户支持等等。但现在由于“敌意收购”，大部分志愿者[离开](https://kline.sh/)了该网络。据报道，寻求控制 Freenode IRC 网络的是 VPN 服务商 PIA 的创始人 Andrew Lee。而需要注意的是 PIA 以前还拥有著名的《Linux Journal》，并为各种开源项目做出了贡献/捐款。

不管其中隐情如何，开源项目们争先恐后地[转移](https://www.phoronix.com/scan.php?page=news_item&px=Free-Software-Exits-Freenode)到其他聊天平台，比如前 Freenode 工作人员建立的 Libera.Chat 或其它平台。

>
> 自由软件世界一直固守老旧 IRC 网络、邮件列表，如今面临变局，或许是开源项目实时聊天方式不破不立的新契机。
>
>
>

### 1nm 以下制程获得重大突破

继 IBM 宣称试产 2nm 芯片后，台积电便联合台大、麻省理工宣布研发出一种新型半导体材料半金属铋，在 1nm 以下制程获得重大突破。IBM 的 2nm 试产是通过改进结构实现的，而台积电的 1nm 更多是采用新材料改进了互联接触点。

>
> 虽然一直有看法认为“摩尔定律接近尾声”，但 2nm 与 1nm 接连突破，或许能让摩尔定律再次“延期”。只能说，技术的进阶超乎想象。
>
>
>

### RHEL 8.4 发布

RHEL 8 的最新版本 8.4 发布。在此版本中，带来了英特尔 Tiger Lake 图形支持、扩展的 eBPF 内核功能、主动压缩内存、时间命名空间等等。更多更新内容见发布[公告](https://www.redhat.com/en/blog/stability-plus-innovation-red-hat-enterprise-linux-84-now-ga)。

>
> 嗯，这次应该还会有 CentOS 8.4。
>
>
>


全新 1Password for Linux 正式推出

Summary: 1Password 是一个相当不错的密码管理器（尽管不是开源的）

1Password 是一个相当不错的密码管理器（尽管不是开源的）

# 全新 1Password for Linux 正式推出

1Password 是一个相当不错的密码管理器（尽管不是开源的），在开源社区也有很好的口碑。他们甚至 [为从事开源项目的用户提供免费的团队成员资格](https://news.itsfoss.com/1password-free-subscriptions/)。

它的 Linux 桌面客户端已经处于测试阶段，但现在它已经准备好进入黄金时间。

他们已经正式 [宣布](https://blog.1password.com/welcoming-linux-to-the-1password-family/) 推出 1Password Linux 版，具有完整的桌面体验，可以与你的网络浏览器集成。

它还亮相了一些很快会进入 Android、iOS、Mac 和 Windows **的新功能**。

在这里，我要安利一下，Linux 上的 1Password 值得期待。

### 1Password Linux 桌面客户端

虽然它可以作为浏览器扩展而无需考虑平台，但桌面客户端的出现使体验更好。

桌面客户端内置了基于 GTK 主题的**黑暗模式支持**。它还能与 **GNOME、KDE 和你选择的任何其他窗口管理器**很好地整合。

看起来他们也在更多的细节上花费了心思，因此桌面客户端也支持**系统托盘图标**，即使你关闭了它也能保持活跃。

你可以用它直接在你的默认浏览器上自动填入密码。不过，虽然它提到了 **X11 剪贴板集成和支持**，但没有提到 Wayland。

它还包括了对 GNOME 钥匙环和 KDE 钱包的支持、内核钥匙环的集成、与系统锁定和闲置服务的集成。

除了这些，1Password for Linux 还首次推出了新的功能，这些功能将很快用于其他平台。

* 安全文件附件
* 项目归档和删除功能，以便更好地组织文件
* Watchtower 仪表板，检查和评估你的密码安全状况
* 新的共享细节，查看谁可以访问什么
* 快速查找和智能搜索建议
* 翻新的外观和感觉

如果你想了解该版本以及他们对开源和 Linux 社区的计划，请浏览 [官方公告](https://blog.1password.com/welcoming-linux-to-the-1password-family/)。

### 在 Linux 中安装 1Password

其官方称，该桌面客户端支持几个 Linux 发行版，包括 Ubuntu、 Debian、 Arch Linux、 Fedora、 CentOS 和 RHEL。你可以得到用来安装的 **.deb** 和 **.rpm** 软件包，或者使用软件包管理器找到它们。

* [下载 1Password for Linux](https://1password.com/downloads/linux/)

它也有一个可用的 [snap 包](https://snapcraft.io/1password)，你可以参考我们的 [在 Linux 中使用 snap](https://itsfoss.com/use-snap-packages-ubuntu-16-04/) 的指南。

关于安装的更多信息，你也可以参考 [官方说明](https://support.1password.com/install-linux/)。

---

via: <https://news.itsfoss.com/1password-linux-released/>

作者：[Ankush Das](https://news.itsfoss.com/author/ankush/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[wxy](https://github.com/wxy) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


使用 sed 命令进行复制、剪切和粘贴

# 使用 sed 命令进行复制、剪切和粘贴

>
> 了解 sed 的基本用法，然后下载我们的备忘单，方便快速地参考 Linux 流编辑器。
>
>
>

<img src="content_image/album_202105_23_181625abgrg4dsbw4y4fue.jpg" alt="" title="Penguin with green background">

很少有 Unix 命令像 `sed`、[grep](https://opensource.com/article/21/3/grep-cheat-sheet) 和 [awk](https://opensource.com/article/20/9/awk-ebook) 一样出名，它们经常组合在一起，可能是因为它们具有奇怪的名称和强大的文本解析能力。它们还在一些语法和逻辑上有相似之处。虽然它们都能用于文本解析，但都有其特殊性。本文研究 `sed` 命令，它是一个 <ruby> 流编辑器 <rt>  stream editor </rt></ruby>。

我之前写过关于 [sed](https://opensource.com/article/20/12/sed) 以及它的远亲 [ed](https://opensource.com/article/20/12/gnu-ed) 的文章。要熟悉 `sed`，对 `ed` 有一点了解是有帮助的，因为这有助于你熟悉缓冲区的概念。本文假定你熟悉 `sed` 的基本知识，这意味着你至少已经运行过经典的 `s/foo/bar` 风格的查找和替换命令。

* 下载我们的免费 [sed 备忘录](https://opensource.com/downloads/sed-cheat-sheet)

### 安装 sed

如果你使用的是 Linux、BSD 或 macOS，那么它们已经安装了 GNU 的或 BSD 的 sed。这些是原始 `sed` 命令的独特重新实现。虽然它们很相似，但也有一些细微的差别。本文已经在 Linux 和 NetBSD 版本上进行了测试，所以你可以使用你的计算机上找到的任何 sed，但是对于 BSD sed，你必须使用短选项（例如 `-n` 而不是 `--quiet`）。

GNU sed 通常被认为是功能最丰富的 sed，因此无论你是否运行 Linux，你可能都想要尝试一下。如果在 Ports 树中找不到 GNU sed（在非 Linux 系统上通常称为 gsed），你可以从 GNU 网站 [下载源代码](http://www.gnu.org/software/sed/)。 安装 GNU sed 的好处是，你可以使用它的额外功能，但是如果需要可移植性，还可以限制它以遵守 sed 的 [POSIX](https://opensource.com/article/19/7/what-posix-richard-stallman-explains) 规范。

MacOS 用户可以在 [MacPorts](https://opensource.com/article/20/11/macports) 或 [Homebrew](https://opensource.com/article/20/6/homebrew-mac) 上找到 GNU sed。

在 Windows 上，你可以通过 [Chocolatey](https://opensource.com/article/20/3/chocolatey) 来 [安装 GNU sed](https://chocolatey.org/packages/sed)。

### 了解模式空间和保留空间

sed 一次只能处理一行。因为它没有可视化模式，所以会创建一个 <ruby> 模式空间 <rt>  pattern space </rt></ruby>，这是一个内存空间，其中包含来自输入流的当前行（删除了尾部的任何换行符）。填充模式空间后，sed 将执行你的指令。当命令执行完时，sed 将模式空间中的内容打印到输出流，默认是 **标准输出**，但是可以将输出重定向到文件，甚至使用 `--in-place=.bak` 选项重定向到同一文件。

然后，循环从下一个输入行再次开始。

为了在遍历文件时提供一点灵活性，sed 还提供了<ruby> 保留空间 <rt>  hold space </rt></ruby>（有时也称为 <ruby> 保留缓冲区 <rt>  hold buffer </rt></ruby>），即 sed 内存中为临时数据存储保留的空间。你可以将保留空间当作剪贴板，实际上，这正是本文所演示的内容：如何使用 sed 复制/剪切和粘贴。

首先，创建一个示例文本文件，其内容如下：

```
Line one
Line three
Line two

```

### 复制数据到保留空间

要将内容放置在 sed 的保留空间，使用 `h` 或 `H` 命令。小写的 `h` 告诉 sed 覆盖保留空间中的当前内容，而大写的 `H` 告诉 sed 将数据追加到保留空间中已经存在的内容之后。

单独使用，什么都看不到：

```
$ sed --quiet -e '/three/ h' example.txt
$

```

`--quiet`（缩写为 `-n`）选项禁止显示所有输出，但 sed 执行了我的搜索需求。在这种情况下，sed 选择包含字符串 `three` 的任何行，并将其复制到保留空间。我没有告诉 sed 打印任何东西，所以没有输出。

### 从保留空间复制数据

要了解保留空间，你可以从保留空间复制内容，然后使用 `g` 命令将其放入模式空间，观察会发生什么：

```
$ sed -n -e '/three/h' -e 'g;p' example.txt

Line three
Line three

```

第一个空白行是因为当 sed 第一次复制内容到模式空间时，保留空间为空。

接下来的两行包含 `Line three` 是因为这是从第二行开始的保留空间。

该命令使用两个唯一的脚本（`-e`）纯粹是为了帮助提高可读性和组织性。将步骤划分为单独的脚本可能会很有用，但是从技术上讲，以下命令与一个脚本语句一样有效：

```
$ sed -n -e '/three/h ; g ; p' example.txt

Line three
Line three

```

### 将数据追加到模式空间

`G` 命令会将一个换行符和保留空间的内容添加到模式空间。

```
$ sed -n -e '/three/h' -e 'G;p' example.txt
Line one

Line three
Line three
Line two
Line three

```

此输出的前两行同时包含模式空间（`Line one`）的内容和空的保留空间。接下来的两行与搜索文本（`three`）匹配，因此它既包含模式空间又包含保留空间。第三行的保留空间没有变化，因此在模式空间（`Line two`）的末尾是保留空间（仍然是 `Line three`）。

### 用 sed 剪切和粘贴

现在你知道了如何将字符串从模式空间转到保留空间并再次返回，你可以设计一个 sed 脚本来复制、删除，然后在文档中粘贴一行。例如，将示例文件的 `Line three` 挪至第三行，sed 可以解决这个问题：

```
$ sed -n -e '/three/ h' -e '/three/ d' \
-e '/two/ G;p' example.txt
Line one
Line two
Line three

```

* 第一个脚本找到包含字符串 `three` 的行，并将其从模式空间复制到保留空间，替换当前保留空间中的任何内容。
* 第二个脚本删除包含字符串 `three` 的任何行。这样就完成了与文字处理器或文本编辑器中的 *剪切* 动作等效的功能。
* 最后一个脚本找到包含字符串 `two` 的行，并将保留空间的内容\_追加\_到模式空间，然后打印模式空间。

任务完成。

### 使用 sed 编写脚本

再说一次，使用单独的脚本语句纯粹是为了视觉和心理上的简单。剪切和粘贴命令作为一个脚本同样有效：

```
$ sed -n -e '/three/ h ; /three/ d ; /two/ G ; p' example.txt
Line one
Line two
Line three

```

它甚至可以写在一个专门的脚本文件中：

```
#!/usr/bin/sed -nf

/three/h
/three/d
/two/ G
p

```

要运行该脚本，将其加入可执行权限，然后用示例文件尝试：

```
$ chmod +x myscript.sed
$ ./myscript.sed example.txt
Line one
Line two
Line three

```

当然，你需要解析的文本越可预测，则使用 sed 解决问题越容易。发明 sed 操作（例如复制和粘贴）的“配方”通常是不切实际的，因为触发操作的条件可能因文件而异。但是，你对 sed 命令的使用越熟练，就越容易根据需要解析的输入来设计复杂的动作。

重要的事情是识别不同的操作，了解 sed 何时移至下一行，并预测模式和保留空间包含的内容。

### 下载备忘单

sed 很复杂。虽然它只有十几个命令，但它灵活的语法和原生功能意味着它充满了无限的潜力。为了充分利用 sed，我曾经参考过一些巧妙的单行命令，但是直到我开始发明（有时是重新发明）自己的解决方案时，我才觉得自己真正开始学习 sed 了 。如果你正在寻找命令提示和语法方面的有用技巧，[下载我们的 sed 备忘单](https://opensource.com/downloads/sed-cheat-sheet)，然后开始一劳永逸地学习 sed！

---

via: <https://opensource.com/article/21/3/sed-cheat-sheet>

作者：[Seth Kenlon](https://opensource.com/users/seth) 选题：[lujun9972](https://github.com/lujun9972) 译者：[MjSeven](https://github.com/MjSeven) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


硬核观察 | PowerShell 成为关键安全威胁的首要来源

Summary: 更多：• Python 官方软件包库 PyPI 正被垃圾软件包淹没 • 时隔一年后，Perl 5 发布新版本

这个SPAM的图也太灵魂了XD

# 硬核观察 | PowerShell 成为关键安全威胁的首要来源

### PowerShell 成为关键安全威胁的首要来源

[根据](https://www.esecurityplanet.com/threats/powershell-source-of-third-of-critical-security-threats/)今天在 RSA 大会上发布的思科研究报告，PowerShell 是 2020 年下半年在端点上检测到的关键威胁的首要来源，占比超过了 1/3。PowerShell 成为勒索软件、无文件恶意软件的主要载体。

思科[报告](https://www.cisco.com/c/en/us/products/security/endpoint-security-outcomes-study.html)显示，端点威胁的首要类别是用于利用及利用后任务的双重用途工具。PowerShell Empire、Metasploit 和其他此类工具有合法用途，但它们也已成为攻击者工具包的一部分。

>
> 强力的工具用于恶意用途也是强力的。所以，最起码系统管理员们先将 PowerShell [保护](https://www.esecurityplanet.com/threats/powershell-source-of-third-of-critical-security-threats/)起来吧。
>
>
>

### Python 官方软件包库 PyPI 正被垃圾软件包淹没

PyPI [充斥](https://www.bleepingcomputer.com/news/security/spammers-flood-pypi-with-pirated-movie-links-and-bogus-packages/)着以流行电影命名的垃圾软件包，其通常与提供盗版下载的盗版网站有关。这些软件包都是由一个独特的假名维护者账户发布的，这使得 PyPI 要一次性删除这些软件包和垃圾账户变得非常困难。除了包含垃圾关键词和视频流网站的链接外，这些软件包还包含从合法的 PyPI 软件包中提取的功能代码和作者信息，以[掩盖](https://www.bleepingcomputer.com/news/security/new-linux-macos-malware-hidden-in-fake-browserify-npm-package/)他们的恶意行为。

近几个月来，对 npm、RubyGems 和 PyPI 等开源生态系统的攻击不断升级。恶意威胁者用各种恶意和伪造的软件包[灌满](https://blog.sonatype.com/pypi-and-npm-flooded-with-over-5000-dependency-confusion-copycats)了软件仓库，以传播他们的信息。这成了一场打地鼠比赛。

>
> 公开软件库或许需要改变其上传和审核机制，并引入防范垃圾邮件和防止论坛垃圾信息方面的经验。
>
>
>

### 时隔一年后，Perl 5 发布新版本

将近一年后，Perl 语言[宣布](https://www.nntp.perl.org/group/perl.perl5.porters/2021/05/msg260110.html)发布 Perl 5.34.0。这个版本包含了来自 78 名贡献者的大约 28 万行代码变更。主要变化包括：实验性的 try/catch 语法，正则表达式量词允许空下界，新的八进制语法，性能增强和模块更新等等。

>
> 不能说 Perl 语言社区不努力，28 万行代码，这放在任何一个开源项目里都不少。奈何 Perl 语言已经不时髦了，几乎没有人学了，也没有一个独占领域。
>
>
>


抛弃 Autotools 向 CMake 迈进吧

抗费搁；昧磕；妹氪因斯道

# 抛弃 Autotools 向 CMake 迈进吧

>
> CMake 是一个跨平台的编译、测试和打包软件，即使你以前从来没有使用过构建系统，也可以轻松上手。
>
>
>

在我以前的文章 [Autotools 入门](https://opensource.com/article/19/7/introduction-gnu-autotools) 一文中，我说明了如何使用 Autotools 来管理和打包代码。这是一个强大且通用的平台，可轻松集成到许多打包系统中，包括 RPM、APT、[pkgsrc](https://opensource.com/article/19/11/pkgsrc-netbsd-linux) 等等。它的语法和结构可能会令人困惑，但幸运的是，我们还有其他选择，开源的 [CMake](http://cmake.org) 就是其中一个。

CMake 是一个用于构建、测试和打包软件的跨平台套件。它使用简单而清晰的语法，因此即使你以前从未使用过构建系统，也很容易开始使用。

### 安装 CMake

CMake 可能已经安装在你的 Linux 系统上。如果没有，你可以使用发行版的程序包管理器进行安装：

```
$ sudo dnf install cmake

```

在 Debian 或者其他相似的系统上：

```
$ sudo apt install cmake

```

在 Mac 上，你可以使用 [MacPorts](https://opensource.com/article/20/11/macports) 或者 [Homebrew](https://opensource.com/article/20/6/homebrew-linux) 来安装:

```
$ sudo port install cmake

```

在 Windows 上，你可以使用 [Chocolatey](https://opensource.com/article/20/3/chocolatey) 或者直接从 [CMake 网站](https://cmake.org/download) 下载二进制来安装。

### 使用 CMake

对于想要从源代码构建软件的开发人员或用户来说，CMake 是一种快速简便的编译和安装方法。 CMake 分阶段工作：

1. 首先，在 `cmake` 步骤中，CMake 扫描计算机查看一些默认设置。默认设置包括库的位置以及在系统上安装软件的位置。
2. 接下来，使用系统上的 `make` 命令（在 Linux 上是 GUN Make，在 [NetBSD](https://opensource.com/article/19/3/netbsd-raspberry-pi) 上是 NetBSD Make）来编译程序。这个过程通常是将人类可读的源代码转换成机器语言。
3. 最后，在 `make install` 一步中，那些编译过的文件将被拷贝到（在 `cmake` 步骤中扫描出来的）计算机上合适的位置。

这看起来很简单，当你使用 CMake 时就是这样。

### CMake 的可移植性

CMake 在设计时就考虑了可移植性。虽然它不能使你的项目在所有 POSIX 平台上都能正常工作（这取决于作为开发者的你），但它可以确保将标记为要安装的文件安装到已知平台上最合适的位置。而且由于有了 CMake 之类的工具，对于高级用户而言，根据其系统需求自定义和覆盖任何不合适的选项都很容易。

使用 CMake，你只需要知道将哪些文件安装到哪个常规位置即可。它会照顾其他一切。不再需要自定义安装脚本，它们有可能在任何未经测试的操作系统上失败。

### 打包

像 Autotools 一样，CMake 也得到了很好的打包支持。无论它们是打包成 RPM 还是 DEB 或 TGZ（或其他任何东西），将带有 CMake 的项目交给打包者，他们的工作既简单又直接。打包工具支持 CMake，因此可能不需要进行任何修补或者调整。在许多情况下，可以自动将 CMake 项目整合到工作流中。

### 如何使用 CMake

要在项目中使用 CMake，只需在项目目录中创建 `CMakeLists.txt` 文件。首先，声明最低要求的 CMake 版本以及项目名称和版本。CMake 会努力在尽可能长时间内保持兼容性，但是随着你使用的时间越长，并且关注它最新的开发动态，你就会知道哪些特性是你所依赖的。

```
cmake_minimum_required(VERSION 3.10)

project(Hello VERSION 1.0)

```

如你可能已经看到的那样，CMake 的语法是一个带有括号和参数的命令。大写的 `VERSION` 字符串不是任意的，也不只是格式。它们是 `project` 命令中的有效参数。

在继续之前，先写一个简单的 C 或者 C++ 的 `hello world` 程序。为了简单，我就写了六行 C 代码，并把它保存在 `hello.c` 中（为了匹配我在 `CMakeLists.txt` 中可执行文件的名字）。

```
#include <stdio.h>

int main() {
   printf("Hello open source\n");
   return 0;
}

```

不过，不要搞错了，CMake 不仅适用于 C 和 C++。它可以处理任意文件，并且有许多可用的命令，因此它可以帮助你维护许多不同形式的项目。

CMake 网站中记录了所有有效的内置命令及其可用参数，因此无论你要做什么，都可以轻松发现所需的功能。不过，这是一个简单的示例，因此，你需要的下一个命令是必不可少的 —— 你必须为 CMake 定义要构建的代码：

```
add_executable(Hello hello.c)

```

这个命令指定了你编译后的二进制文件的名字为 `Hello`。因此，它与你在终端中执行带有 `-o Hello` 的 `gcc` 命令是一样的。

在一些比较复杂的项目中，你可能还需要使用库文件，你可以使用 `add library` 命令来链接库文件。

在你设置了你想要构建和标记为安装的文件之后，你必须要告诉 CMake 一旦用户安装了程序，最终的应用程序应该在哪个位置。

在这个简单的例子里，你仅需要做的一件事就是在你的 `CMakeLists.txt` 文件里添加 `install` 命令。`install` 命令接受几个参数。但是在这个例子中，你仅需要使用 `TARGET` 命令来指定你要安装文件的名字。

```
install(TARGETS Hello)

```

### 向 CMake 工程添加一些文件

一个软件项目向用户交付的往往不仅仅只有代码，还有一些其他的文件数据，例如手册或者是信息页、示例项目，或者是配置文件。你可以使用与包含编译文件时类似的工作流程，将任意数据包含在 CMake 项目中：在 `CMakelists.txt` 文件中使用 `file` 命令，然后说明一下这些文件要安装在哪里。

例如，你可以在这个项目中包含一个 `assets` 目录，你可以使用 `file` 命令，后面跟上 `COPY` 和 `DESTINATION` 参数来告诉 CMake 将这些额外的文件复制到你的分发包中。

```
file(COPY assets DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")

```

这个 `${CMAKE_CURRENT_BINARY_DIR}` 变量是一个特殊的 CMake 内置变量，表示 CMake 正在处理的目录。换句话说，你的任何文件都会被复制到编译目录（在你运行 `cmake` 命令后，这个过程会更加清晰，到时候回过头来看一下）。

因为这些额外的数据文件有些杂乱不堪（如果你不信的话，可以看一下 `/usr/share` 这个目录）。对于你自己的项目创建一个子文件夹对谁都有好处。最好也带上版本名字。你可以通过在 `CMAKE_CURRENT_BINARY_DIR` 中指定一个新的目录，使用你选择的项目名称，后面跟一个为你的项目命名的特殊变量和你在项目声明中为它设置的 `VERSION`。

```
file(COPY assets DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/Hello-${Hello_VERSION}")

```

### 定义安装位置

你已经定义你要编译的文件，因此现在你要告诉 CMake 你的程序要安装在哪个位置。比如你的主程序，这个要程使用 `install` 命令：

```
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Hello-${Hello_VERSION}" TYPE DATA)

```

这里有一些新的参数。`DIRECTORY` 参数指定了数据文件是一个目录，而不是一个文件（`FILE`）或者脚本（`SCRIPT`）。你使用的参数和复制一些额外文件到编译目录时是一样。另外，在 `install` 命令中 `TYPE` 或者 `DESTINATION` 必须要指定其一。`TYPE` 参数指定了通用的文件类型，这些文件通常将会被放到合适的位置。在 Linux 系统上，`TYPE DATA` 一般是 `/usr/local/share` 或者 `/usr/share`，除非用户定义了其他的位置。

这是诸如 CMake 之类的良好构建系统的强大功能之一。你不必担心文件的确切位置，因为你知道用户可以更改 CMake 的首选默认设置，并且 CMake 将构建代码以使其正常工作。

### 运行 CMake

CMake 有多种方式来让你执行命令，你可以在终端或者在一个可交互的程序上执行命令，或者你也可以使用它的图形界面（GUI）。我比较偏向于使用终端命令，但是我也喜欢使用一些其他的方式（相比与在 `Makefile` 中查找那些晦涩的变量然后去修改它们更胜一筹）。

对于编译过开源 C++ 项目的任何人，都熟悉的第一步是创建一个 `build` 目录，进入到该目录，然后运行 `cmake ..` 命令。 我是一个懒惰的打字员，所以我将构建目录命名为 `b`，但是你可以使用最合适的方式：

```
$ mkdir b
$ cd b
$ cmake ..
-- The C compiler identification is GNU 11.1.1
-- The CXX compiler identification is GNU 11.1.1
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /var/home/seth/demo-hello/b
$

```

这或多或少相当于经典的 `./configure; make; make install` 中的 `./configure`。看一下你的构建目录，CMake 已经帮你生成了几个新的文件，来让你的项目更完整。这里生成了 CMake 的数据文件、一个常规的 `Makefile` 文件（这是一个免费提供的 247 行的文件，但对于越复杂的项目，行数要多得多），还有一个包含这个示例程序的任意非编译数据的 `Hello-1.0` 目录。

```
$ ls
CMakeCache.txt
CMakeFiles
Makefile
Hello-1.0
cmake_install.cmake

```

接下来，你可以进行构建。你可以使用 CMake 的 `--build` 选项来做这件事，使用当前的构建目录作为源目录。

```
$ cmake --build .
Scanning dependencies of target Hello
[ 50%] Building C object CMakeFiles/Hello.dir/hello.c.o
[100%] Linking C executable Hello
[100%] Built target Hello

```

或者你可以运行 `make` 命令。这将读取由 CMake 生成的 `Makefile` 文件。在这个例子中，`make` 默认的行为就是由源程序 `hello.c` 生成目标文件。

```
$ make
Scanning dependencies of target Hello
[ 50%] Building C object CMakeFiles/Hello.dir/hello.c.o
[100%] Linking C executable Hello
[100%] Built target Hello
$

```

如你所料，`Hello` 二进制可执行文件现在存在于当前的构建目录中。因为它是一个简单的自包含应用程序，所以你可以运行它进行测试：

```
$ ./Hello
Hello open source
$

```

最后，你可以用 `--install` 选项进行安装。因为我不希望我的简单的 “hello world” 应用程序真的被安装到我的系统上，我设置了 `--prefix` 选项，将 CMake 的目标从根目录（`/`）重定向到 `/tmp` 的一个子目录。

```
$ cmake --install . --prefix /tmp/hello/
-- Install configuration: ""
-- Installing: /tmp/dist-hello/usr/local/bin/Hello
-- Installing: /tmp/dist-hello/usr/local/share/Hello-1.0
-- Installing: /tmp/dist-hello/usr/local/share/Hello-1.0/assets/file0
-- Installing: /tmp/dist-hello/usr/local/share/Hello-1.0/assets/file1

```

另外，你也可以运行 `make install` 来调用 `Makefile` 的安装动作。同样，为了避免在我的系统上安装一个演示程序，我在这个例子中设置了 `DESTDIR` 变量，将安装目标重定向到 `/tmp` 的一个子目录：

```
$ mkdir /tmp/dist-hello
$ make install DESTDIR=/tmp/dist-hello
[100%] Built target Hello
Install the project...
-- Install configuration: ""
-- Installing: /tmp/dist-hello/usr/local/bin/Hello
-- Installing: /tmp/dist-hello/usr/local/share/Hello-1.0
-- Installing: /tmp/dist-hello/usr/local/share/Hello-1.0/assets/file0
-- Installing: /tmp/dist-hello/usr/local/share/Hello-1.0/assets/file1

```

看一下输出的内容，来确定它具体的安装位置，这个程序已经安装好了。

### 快速自定义

CMake 的安装前缀（由 `CMAKE_INSTALL_PREFIX` 变量指定）默认是在 `/usr/local` 这个位置，但是所有的 CMake 变量都可以在你运行 `cmake` 命令的时候，加一个 `-D` 选项来改变它。

```
$ cmake -DCMAKE_INSTALL_PREFIX=/usr ..
$ make install DESTDIR=/tmp/dist-hello
$ make install DESTDIR=/tmp/dist-hello
[100%] Built target Hello
Install the project...
-- Install configuration: ""
-- Installing: /tmp/dist-hello/usr/bin/Hello
-- Installing: /tmp/dist-hello/usr/share/Hello-1.0
-- Installing: /tmp/dist-hello/usr/share/Hello-1.0/assets/file0
-- Installing: /tmp/dist-hello/usr/share/Hello-1.0/assets/file1

```

所有由 CMake 使用的变量都可以通过这种方式来修改。

### 交互式的 CMake

CMake 的交互模式是一种用于配置安装环境的友好而有用的方法。要让用户知道该项目使用的所有可能的 CMake 变量是一件工作量很大的事，因此 CMake 交互式界面是他们无需查看 `Makefile` 和 `CMakeLists` 即可发现自定义选项的简便方法。

为了调用这个交互式的 CMake，使用 `ccmake` 命令，在这个简单的项目里没有太多的东西。但是对于像 [Rosegarden](https://opensource.com/article/18/3/make-sweet-music-digital-audio-workstation-rosegarden) 这样的大型项目，这将非常有用。

### CMake 的更多知识

还有很多很多的 CMake 知识需要去了解。作为一个开发者，我非常喜欢它简洁的语法、详尽的文档、可扩展性以及便捷性。作为一个用户我非常喜欢 CMake 友好且实用的错误提示信息还有它的用户界面，如果你的项目还未开始使用构建系统，请了解一下 CMake 吧。你以及以后尝试打包你应用程序的任何人都不会后悔。

---

via: <https://opensource.com/article/21/5/cmake>

作者：[Seth Kenlon](https://opensource.com/users/seth) 选题：[lujun9972](https://github.com/lujun9972) 译者：[amwps290](https://github.com/amwps290) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


4 款值得一试的 Linux 终端多路复用器

# 4 款值得一试的 Linux 终端多路复用器

>
> 比较 tmux、GNU Screen、Konsole 和 Terminator，看看哪个最适合你。
>
>
>

Linux 用户通常需要大量的虚拟视觉空间。一个终端窗口是永远不够的，所以终端有了标签。一个桌面太受限制了，所以有了虚拟桌面。当然，应用程序窗口可以堆叠，但当它们堆叠起来时，又有多大的好处呢？哎呀，即使是后台文本控制台也有 `F1` 到 `F7`，可以在任务之间来回翻转。

有了这么多的多任务处理方式，有人发明了终端 *多路复用器* 的概念就不奇怪了。诚然，这是一个令人困惑的术语。在传统的电子学中，“<ruby> 多路复用器 <rt>  multiplexer </rt></ruby>”是一个接收多个输入信号并将选定的信号转发到单一输出的部件。终端多路复用器的作用正好相反。它从一个输入（人类在键盘上向一个终端窗口打字）接收指令，并将该输入转发给任意数量的输出（例如，一组服务器）。

然后，“多路复用器”一词在美国也是一个流行的术语，指的是有许多屏幕的电影院（与“<ruby> 影城 <rt>  cineplex </rt></ruby>”一词一个意思）。在某种程度上，这很好地描述了终端复用器的作用。它可以在一个框内提供许多屏幕。

不管这个词是什么意思，任何尝试过它的人都有自己的喜好的某一种多路复用器。因此，我决定考察一些流行的终端多路复用器，看看每一个都怎么样。就我的评估标准而言，最低限度，我需要每个多路复用器能够分割*和*堆叠终端窗口。

### tmux

据我所知，是从 tmux 开始使用“多路复用器”这个术语的。它工作的很出色。

它作为一个守护程序运行，这样即使你关闭了正在查看的终端模拟器，你的终端会话仍然处于活动状态。它将你的终端屏幕分割成多个面板，这样你就可以在每个面板上打开独特的终端提示符。

推而广之，这意味着你也可以远程连接到任何数量的系统，并在你的终端中打开它们。利用 tmux 的能力，将输入镜像（或者以电子学术语说是“反向多路复用”）到其他打开的窗格，就能从一个中央命令窗格同时控制几台计算机。

tmux 在 GNU Screen 还只能水平分割的时候就有了垂直分割能力，这吸引了追求最大灵活性的粉丝。而灵活性正是用户在 tmux 中得到的。它可以分割、堆叠、选择和提供服务；几乎没有什么是它做不到的。

#### ? 软件包大小

从软件包中安装 tmux 大约需要 700K，这还不算它所依赖的十几个共享库。

#### ? 控制键

tmux 的默认触发键是 `Ctrl+B`，尽管很容易在其配置文件中重新定义。

#### ⌨ 黑客因子

即使你只是在学习如何使用终端，你也一定会觉得使用 tmux 的人很像黑客。它看起来很复杂，但一旦你了解了正确的键绑定，就很容易使用。它为你提供了很多有用的技巧，让你玩的飞起，而且它是一种快速构建 HUD（抬头显示器）的超简单方法，可以把你需要的所有信息摆在你面前。

### GNU Screen

像 tmux 一样，GNU Screen 也运行一个守护程序，所以即使你关闭了用来启动它的终端，你的 shell 仍然可用。你可以从不同的计算机上连接并共享屏幕。它可以将你的终端屏幕分割成水平或垂直的窗格。

与 tmux 不同的是，GNU Screen 可以通过串行连接进行连接（`screen 9600 /dev/ttyUSB0` 就可以了），通过按键绑定可以方便地发出 `XON` 和 `XOFF` 信号。

与 SSH 会话相比，在串行连接中需要多路复用器的情况可能并不常见，所以大多数用户并不了解 Screen 这个真正特殊的功能。不过，GNU Screen 是一个很棒的多路复用器，有很多有用的选项。而如果你真的需要同时向多个服务器发送信号，还有专门的工具，比如 ClusterSSH 和 [Ansible](https://opensource.com/article/19/2/quickstart-guide-ansible)。

#### ? 软件包大小

从软件包中安装 GNU Screen 大约需要 970K，这还不算它所依赖的十几个共享库。

#### ? 控制键

GNU Screen 的默认触发键是 `Ctrl+A`，这对于熟悉 Bash 快捷键的人来说可能特别烦人。幸运的是，你可以在配置文件中轻松地重新定义这个触发键。

#### ⌨ 黑客因子

当使用 Screen 通过串行连接到你的路由器或你的原型电路板时，你会成为你所有硬件黑客朋友羡慕的对象。

### Konsole

对于没有标榜自己是多路复用器的 Konsole 来说，令人惊讶的是它也是其中一个。它可以使用 Qt 窗格和标签进行必要的窗口分割和堆叠，但它也可以通过“编辑（将输入复制到）”菜单中的一个选项将输入从一个窗格传到另一个（或全部）。

然而，它所最明显缺乏的功能是作为一个守护程序运行以进行远程重新连接的能力。与 tmux 和 GNU Screen 不同，你不能远程连接到运行 Konsole 的机器并加入会话。对于一些管理员来说，这可能不是一个问题。许多管理员用 [VNC](https://en.wikipedia.org/wiki/Virtual_Network_Computing) 连接到机器的次数比用 [SSH](https://en.wikipedia.org/wiki/Secure_Shell_Protocol) 还要多，所以“重新加入”一个会话就像在 VNC 客户端上点击 Konsole 窗口一样简单。

使用 Konsole 作为多路复用器是 KDE 极客们的大招。Konsole 是我使用的第一个 Linux 终端（直到今天，我有时也会按 `Ctrl+N` 来切换新标签），所以有能力使用这个熟悉的终端作为多路复用器是一个很大的便利。这绝不是必要的，因为无论如何 tmux 和 Screen 都可以在 Konsole 里面运行，但是通过让 Konsole 处理窗格，我就不必调整肌肉记忆。这种微妙的功能包容正是 [KDE 的伟大之处](https://opensource.com/article/19/12/linux-kde-plasma)。

#### ? 软件包大小

Konsole 本身大约是 11KB，但它依赖于 105 个 KDE 和 Qt 库，所以实际上，它至少有 50MB。

#### ? 控制键

大多数重要的 Konsole 快捷键以 `Shift+Ctrl` 开始，分割屏幕、打开新标签、复制输入到其他窗格等都是如此。这是 KDE 里的主控台，所以如果你对 Plasma 桌面很熟悉，会感觉快捷键很熟悉。

#### ⌨ 黑客因子

使用 Konsole 作为你的多路复用器让你有资格称自己为 KDE 高级用户。

### Terminator

对于 GNOME 用户来说，Terminator 多路复用器是为他们原本极简的 GNOME 终端增加功能的一个简单方法。除了必要的多路复用功能外，Terminator 还可以向所有打开的窗格广播输入，但和 Konsole 一样，它不会在后台运行以便你可以通过 SSH 重新连接到它。话说回来，由于 GNOME 和 Wayland 让 VNC 变得如此简单，你有可能会觉得没有必要通过 SSH 来恢复终端会话。

如果你愿意，Terminator 可以完全由鼠标驱动。Konsole 通过其主菜单也有同样的能力。有了 Terminator，你可以在 Shell 的任何地方点击右键，弹出相关选项，以水平或垂直分割窗口，将窗格分组作为广播目标，广播输入，关闭窗格，等等。你还可以为所有这些动作配置键盘快捷键，所以在许多方面，你可以形成自己的体验。

我认为自己主要是一个 KDE 用户，所以当我说 Terminator 感觉像一个 KDE 应用时，我其实是一种极大的赞美。Terminator 是一个令人惊讶的可配置的和灵活的应用程序。在许多方面，它体现了开源的力量，把简陋的 GNOME 终端变成了一个强大的多路复用器。

#### ? 软件包大小

Terminator 的安装容量为 2.2MB，其中大部分是 Python 模块。但它依赖于 GTK3 和 GNOME，所以如果你没有运行完整的 GNOME 桌面，可以预料你需要一个更大的安装来拉入这些依赖。

#### ? 控制键

Terminator 的默认控制键没有什么一致性。你可以用 `Alt` 键来执行一些命令，用 `Ctrl` 来执行其他命令，还可以用 `Shift+Ctrl`、`Ctrl+Alt`、`Shift+Super` 等等，还有鼠标。话说回来，这是我试过的最可配置的多路复用器之一，所以只要有想法，稍加努力，你就能设计出适合你的模式。

#### ⌨ 黑客因子

当你使用 Terminator 时，你会觉得自己是最现代、最务实的黑客。由于它的各种极客选项，它是多路复用的最佳选择，而且由于它非常灵活，无论你的手是在键盘上，还是键盘和鼠标并用，你都可以同样轻松地使用它。

### 我全要

还有更多的多路复用器和一些具有类似多路复用能力的应用。你不必非要找到*一个*完全按照你想要的方式完成你需要的所有工作的多路复用器。你可以使用不止一个。事实上，你甚至可以同时使用多个，因为 tmux 和 Screen 实际上是 shell，而 Konsole 和 Terminator 是显示 shell 的终端。对唾手可得的工具感到舒适，而且它们能帮助你管理你的工作空间，使你能有效地工作，才是最重要的。

去尝试一下多路复用器，或者在你喜欢的应用程序中发现类似多路复用器的功能。它可能会改变你看待计算的方式。

---

via: <https://opensource.com/article/21/5/linux-terminal-multiplexer>

作者：[Seth Kenlon](https://opensource.com/users/seth) 选题：[lujun9972](https://github.com/lujun9972) 译者：[wxy](https://github.com/wxy) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


Summary: 更多：• Linux 5.13-rc3 发布，主要是撤销明大的提交 • 安全研究人员艰难攻破了波音 747 的机上娱乐系统

# 硬核观察 | Python 之父对 Rust、Go、Julia 和 TypeScript 的看法

### Python 之父对 Rust、Go、Julia 和 TypeScript 的看法

Python 之父 Guido 在最近一次[新采访](https://www.youtube.com/watch?v=aYbNh3NS7jA)中分享了他对其它编程语言的看法，其中有些很有趣：

* Rust 在一个特定的领域真正改进了 C++，它使绕过编译器的检查变得更加困难。当然，它以一种近乎完美的方式解决了内存分配问题。
* 在所有的新语言中，Go 可能是最像 Python 的 —— 或者至少是在通用的新语言中。
* Julia 有太多的细节看起来与 Python 非常相似。Julia 会在某个小众的地方是优越的，因为它的编译器为你优化了代码，而 Python 可能永远不会这样。
* TypeScript 做了一些 Python 仍在等待解决的事情。我们正在向TypeScript学习。听起来 TypeScript 也在向 Python 学习，就像 JavaScript 在一些领域向 Python 学习一样。

>
> 嗯，作为目前顶级的编程语言神级人物，Guido 的一些看法挺有意思的。如果有机会得到完整的采访脚本，我们会翻译分享给大家。
>
>
>

### Linux 5.13-rc3 发布，主要是撤销明大的提交

Linus Torvalds 如期发布了 Linux 5.13-rc3 内核。他 [说](https://lore.kernel.org/lkml/CAHk-=wiUwtRp+jjCMd9x8O90iD_YHVBQzJoKCsT9e06L7qob3Q@mail.gmail.com/T/#u)，“这是一个非常平静的 RC3 周，至少在纯提交数量上，这是我们在 5.x 系列中最小的 RC3。”

Linux 5.13-rc3 最主要的工作是，撤销了明尼苏达大学研究人员三十几个有问题的补丁，以及因他们的“伪君子提交”研究而引起的清理工作。过去一个月里审查了明尼苏达大学对 Linux 内核的所有补丁，虽然有些补丁部分地解决了真正的问题，但在许多情况下，它们可以进一步改进，或者作用有限。

>
> 终究明大还是丧失了 Linux 内核社区的所有信任，即便是有些补丁属于可撤销也可不撤销的。此事的是非曲直大家各有不同的看法，但是我觉得 Linux 内核社区或许应该考虑如何建立更健壮的代码审核机制。
>
>
>

### 安全研究人员艰难攻破了波音 747 的机上娱乐系统

信息安全公司 PTP 的研究人员在[利用](https://www.theregister.com/2021/05/21/boeing_747_ife_windows_nt4_shell_access/)了一个可追溯到 1999 年的漏洞后，在一架波音 747 客机的机上娱乐系统上建立了一个持久的 shell。[PTP 说](https://www.pentestpartners.com/security-blog/getting-a-persistent-shell-on-a-747-ife/)，“攻破它比我们预期的要困难得多，主要是因为这个机上娱乐系统已经有 25 年的历史了，缺少许多我们认为在最近的系统上理所当然的功能。”该系统是如此古老，其管理服务器运行在 Windows NT4 SP3 上。许多现代工具和技术都不起作用，甚至连 Kali Linux 的前身 Backtrack 也没有成功。最终，研究人员使用 Metasploit 的 TFTP 服务器模块进入机器，获得了命令行访问权，并从那里获得了管理密码的哈希值并将其破解。

>
> 虽然说系统越老漏洞越多，但是过于老的系统，你可能都没有足够工具去破解它。
>
>
>


Git 中上下文切换的 4 种方式

Summary: 比较 Git 中四种切换分支的方法的优缺点。

就是说 worktree 在项目体积超大时才有意义吧

比较 Git 中四种切换分支的方法的优缺点。

# Git 中上下文切换的 4 种方式

>
> 比较 Git 中四种切换分支的方法的优缺点。
>
>
>

<img src="content_image/album_202105_25_091803a6ww3r7yo32oxdzx.jpg" alt="" title="Computer screen with files or windows open">

所有大量使用 Git 的人都会用到某种形式的上下文切换。有时这只会给你的工作流程增加少量的开销，但有时，这可能是一段痛苦的经历。

让我们用以下这个例子来讨论一些常见的上下文切换策略的优缺点：

>
> 假设你在一个名为 `feature-X` 的分支中工作。你刚刚发现你需要解决一个无关的问题。这不能在 `feature-X` 分支中完成。你需要在一个新的分支 `feature-Y` 中完成这项工作。
>
>
>

### 方案 1：暂存 + 分支

解决此问题最常见的工作流程可能如下所示：

1. 停止分支 `feature-X` 上的工作
2. `git stash`
3. `git checkout -b feature-Y origin/main`
4. 一顿鼓捣，解决 `feature-Y` 的问题
5. `git checkout feature-X` 或 `git switch -`
6. `git stash pop`
7. 继续在 `feature-X` 中工作

**优点：** 这种方法的优点在于，对于简单的更改，这是一个相当简单的工作流程。它可以很好地工作，特别是对于小型仓库。

**缺点：** 使用此工作流程时，一次只能有一个工作区。另外，根据你的仓库的状态，使用暂存是一个麻烦的环节。

### 方案 2：WIP 提交 + 分支

这个解决方案和前一个非常相似，但是它使用 WIP（<ruby> 正在进行的工作 <rt>  Work in Progress </rt></ruby>）提交而不是暂存。当你准备好切换回来，而不是弹出暂存时，`git reset HEAD~1` 会展开 WIP 提交，你可以自由地继续，就像之前的方案一样，但不会触及暂存。

1. 停止分支 `feature-X` 上的工作
2. `git add -u`（仅仅添加修改和删除的文件）
3. `git commit -m "WIP"`
4. `git checkout -b feature-Y origin/master`
5. 一顿鼓捣，解决 `feature-Y` 的问题
6. `git checkout feature-X` 或 `git switch -`
7. `git reset HEAD~1`

**优点：** 对于简单的更改，这是一个简单的工作流，也适合于小型仓库。你不需要使用暂存。

**缺点：** 任何时候都只能有一个工作区。此外，如果你或你的代码审阅者不够谨慎，WIP 提交可能会合并到最终产品。

使用此工作流时，你**永远**不要想着将 `--hard` 添加到 `git reset`。如果你不小心这样做了，你应该能够使用 `git reflog` 恢复提交，但是你最好完全避免这种情况发生，否则你会听到心碎的声音。

### 方案 3：克隆一个新仓库

在这个解决方案中，不是创建新的分支，而是为每个新的功能分支创建存储库的新克隆。

**优点：** 你可以同时在多个工作区中工作。你不需要 `git stash` 或者是 WIP 提交。

**缺点：** 需要考虑仓库的大小，因为这可能会占用大量磁盘空间（浅层克隆可以帮助解决这种情况，但它们可能并不总是很合适。）此外，你的仓库克隆将互不可知。因为他们不能互相追踪，所以你必须手动追踪你的克隆的源仓库。如果需要 git 钩子，则需要为每个新克隆设置它们。

### 方案 4：git 工作树

要使用此解决方案，你可能需要了解 `git add worktree`。如果你不熟悉 Git 中的工作树，请不要难过。许多人多年来都对这个概念一无所知。

#### 什么是工作树？

将工作树视为仓库中属于项目的文件。本质上，这是一种工作区。你可能没有意识到你已经在使用工作树了。开始使用 Git 时，你将自动获得第一个工作树。

```
$ mkdir /tmp/foo && cd /tmp/foo
$ git init
$ git worktree list
/tmp  0000000 [master]

```

你可以在以上代码看到，甚至在第一次提交前你就有了一个工作树。接下来去尝试再添加一个工作树到你的项目中吧。

#### 添加一个工作树

想要添加一个新的工作树你需要提供:

1. 硬盘上的一个位置
2. 一个分支名
3. 添加哪些分支

```
$ git clone https://github.com/oalders/http-browserdetect.git
$ cd http-browserdetect/
$ git worktree list
/Users/olaf/http-browserdetect  90772ae [master]

$ git worktree add ~/trees/oalders/feature-X -b oalders/feature-X origin/master
$ git worktree add ~/trees/oalders/feature-Y -b oalders/feature-Y e9df3c555e96b3f1

$ git worktree list
/Users/olaf/http-browserdetect       90772ae [master]
/Users/olaf/trees/oalders/feature-X  90772ae [oalders/feature-X]
/Users/olaf/trees/oalders/feature-Y  e9df3c5 [oalders/feature-Y]

```

与大多数其他 Git 命令一样，你需要在仓库路径下使用此命令。一旦创建了工作树，就有了隔离的工作环境。Git 仓库会跟踪工作树在磁盘上的位置。如果 Git 钩子已经在父仓库中设置好了，那么它们也可以在工作树中使用。

请注意到，每个工作树只使用父仓库磁盘空间的一小部分。在这种情况下，工作树需要只大约三分之一的原始磁盘空间。这这非常适合进行扩展。如果你的仓库达到了千兆字节的级别，你就会真正体会到工作树对硬盘空间的节省。

```
$ du -sh /Users/olaf/http-browserdetect
2.9M

$ du -sh /Users/olaf/trees/oalders/feature-X
1.0M

```

**优点：** 你可以同时在多个工作区中工作。你不需要使用暂存。Git 会跟踪所有的工作树。你不需要设置 Git 钩子。这也比 `git clone` 更快，并且可以节省网络流量，因为你可以在飞行模式下执行此操作。你还可以更高效地使用磁盘空间，而无需借助于浅层克隆。

**缺点：** 这是个需要你额外学习和记忆的新东西，但是如果你能养成使用这个功能的习惯，它会给你丰厚的回报。

#### 额外的小技巧

有很多方式可以清除工作树，最受欢迎的方式是使用 Git 来移除工作树：

```
git worktree remove /Users/olaf/trees/oalders/feature-X

```

如果你喜欢 RM 大法，你也可以用 `rm -rf` 来删除工作树。

```
rm -rf /Users/olaf/trees/oalders/feature-X

```

但是，如果执行此操作，则可能需要使用 `git worktree prune` 清理所有剩余的文件。或者你现在可以跳过清理，这将在将来的某个时候通过 `git gc` 自行完成。

#### 注意事项

如果你准备尝试 `git worktree`，请记住以下几点：

* 删除工作树并不会删除该分支。
* 可以在工作树中切换分支。
* 你不能在多个工作树中同时签出同一个分支。
* 像其他命令一样，`git worktree` 需要从仓库内运行。
* 你可以同时拥有许多工作树。
* 要从同一个本地仓库签出创建工作树，否则它们将互不可知。

#### git rev-parse

最后一点注意：在使用 `git worktree` 时，仓库根所在的位置可能取决于上下文。幸运的是，`git rev parse` 可以让你区分这两者。

* 要查找父仓库的根目录，请执行以下操作：

```
git rev-parse --git-common-dir

```
* 要查找你当前所在仓库的根目录，请执行：

```
git rev-parse --show-toplevel

```

### 根据你的需要选择最好的方法

就像很多事情一样，TIMTOWDI（<ruby> 条条大道通罗马 <rt>  there's more than one way to do it </rt></ruby>）。重要的是你要找到一个适合你需要的工作流程。你的需求可能因手头的问题而异。也许你偶尔会发现自己将 `git worktree` 作为版本控制工具箱中的一个方便工具。

---

via: <https://opensource.com/article/21/4/context-switching-git>

作者：[Olaf Alders](https://opensource.com/users/oalders) 选题：[lujun9972](https://github.com/lujun9972) 译者：[Chao-zhi](https://github.com/Chao-zhi) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


对 JavaScript 构建工具的 6 个预测

# 对 JavaScript 构建工具的 6 个预测

>
> JavaScript 前端工具的生态系统充满着变数和竞争，且只有最好的工具才会存活下来。
>
>
>

<img src="content_image/album_202105_25_112116d5z1lrywl6k25mur.jpg" alt="" title="Magnifying glass on code">

生产中使用的代码与开发中的有所不同. 在生产中，我们需要构建一些能运行得够快、能管理各种依赖关系、能自动执行任务、能加载外部模块等功能的包。而那些将开发中的代码转为生产代码的 [JavaScript](https://www.javascript.com/) 工具我们就称之为 *构建工具。*

我们可以通过各个构建步骤以及其重要性来解释前端代码需要被“构建”的原因。

### 前端代码构建步骤

前端代码的构建涉及下面的四个步骤:

#### 1、转译

通过<ruby> 转译 <rt>  Transpiling </rt></ruby>，开发者可以使用到语言最新、最热门的更新和扩展，并保持浏览器的兼容性等。下面是使用 [Babel](https://babeljs.io/) 的一个例子:

```
// 数组映射中的箭头函数语法
const double = [1, 2, 3].map((num) => num * 2);
// 转译后
const double = [1, 2, 3].map(function(num) {
  return num * 2;
});

```

#### 2、分包

<ruby> 分包 <rt>  Bundling </rt></ruby>是处理所有 `import` 与`require` 语句的过程；找到相匹配的 JavaScript 代码片段、包和库；将它们添加到适当的域中；然后将它们打包到一个大的 JavaScript 文件中。常用的分包器包括 Browserify、Webpack 与 Parcel。

#### 3、压缩

<ruby> 压缩 <rt>  Minifing </rt></ruby>是通过删除空白和代码注释来减少最终的文件大小。在压缩过程中，我们还可以更进一步添加代码混淆步骤，混淆会更改变量名和方法名，使代码变得晦涩难懂，因此一旦代码交付到客户端，它就不是那么容易能让人读懂。下面是一个使用 Grunt 的例子:

```
// 压缩前
const double = [1, 2, 3].map(function(num) {
  return num * 2;
});
// 压缩后
const double=[1,2,3].map(function(num){return num*2;});

```

#### 4、打包

完成上面的所有步骤之后, 我们需要将这些具有兼容性、且经过分包、压缩/混淆过的文件放置到某个地方。<ruby> 打包 <rt>  Packaging </rt></ruby>正是这样一个过程，它将上述步骤所产生的结果放置到开发者指定的某个位置上，这通常是通过打包器完成的。

### 前端构建工具

前端工具及构建工具可以分为以下几类:

* 包管理: NPM、Yarn
* 转译器: Babel 等
* 打包器: Webpack、Parcel、Browserify
* 压缩混淆: UglifyJS、Packer、Minify 等

JavaScript 生态系统中有各种各样的构建工具可以使用，包括下面的这些：

#### Grunt 和 Bower

[Grunt](https://gruntjs.com/) 是作为命令行工具引入的，它仅提供一个脚本来指定和配置相关构建任务。[Bower](https://bower.io/) 作为包管理器，提供了一种客户端包的管理方法而紧追其后。这两者，再加上 NPM，它们经常在一起使用，它们看上去似乎可以满足大多数的自动化需求，但 Grunt 的问题在于它无法提供给开发者配置更复杂任务的自由，而 Bower 使开发者管理的程序包是平常的两倍，因为它将前端包、后台包分开了（例如，Bower 组件与 Node 模块）。

**Grunt 与 Bower 的未来：** Grunt 与 Bower 正在退出 JavaScript 工具生态，但是还有一些替代品。

#### Gulp 和 Browserify

[Gulp](https://gulpjs.com/) 是在 Grunt 发布一年半之后才发布的。但 Gulp 却让大家感到很自然、舒服。用 JavaScript 来写构建脚本与用 JSON 来写相比更自由。你可以在 Gulp 的构建脚本中编写函数、即时创建变量、在任何地方使用条件语句 —— 但就这些，并不能说让我们的感觉变得特别自然和舒适，只能说这只是其中的一个可能的原因。[Browserify](http://browserify.org/) 和 Gulp 可以配合使用，Browserify 允许 NPM 包（用于后端 Node 服务器）被直接带入到前端，就这一点已经直接让 Bower 废了。而正是这种用一个包管理器来处理前后端包的方式让人感到更自然和更好。

**Gulp 的未来：** Gulp 可能会被改进，以便匹配当前流行的构建工具，但这完全取决于创造者的意愿。Gulp 仍在使用中，只是不再像以前那么流行了。

#### Webpack 和 NPM/Yarn 脚本

[Webpack](https://webpack.js.org/) 是现代前端开发工具中最热门的宠儿，它是一个开源的 JavaScript 模块打包器。Webpack 主要是为处理 JavaScript 而创造的，但如果包含相应的加载器，它也可以转换 HTML、CSS 和图片等前端资源。通过 Webpack，你也可以像 Gulp 一样编写构建脚本，并通过 [NPM/Yarn](https://github.com/yarnpkg/yarn) 来执行它们。

**Webpack 的未来：** Webpack 是目前 JavaScript 工具生态系统中最热门的工具，最近几乎所有的 JavaScript 库都在使用 React 和 Webpack。Webpack 目前处于第四个版本，不会很快消失。（LCTT 译注：Webpack 目前已经发布了第五个版本了，且还在火热更新中）

#### Parcel

[Parcel](https://parceljs.org/) 是一个 Web 应用打包器，于 2018 年推出，因其开发者体验而与众不同。Parcel 能利用处理器多核功能提供极快的打包性能，且还零配置。但 Parcel 还是一个新星，对于一些大型应用，其采用率并不高。相比之下，开发人员更喜欢使用 Webpack，因为 Webpack 有更广泛的支持和可定制性。

**Parcel 的未来：** Parcel 非常容易使用，如果你统计打包和构建时间，它会比 Webpack 更快，而且它还提供了更好的开发者体验。Parcel 没有被大量采用的原因可能是它仍然比较新。在前端构建工具的生态系统中，Parcel 的前景会非常光明，它将会存在一段时间。

#### Rollup

[Rollup](https://rollupjs.org/guide/en/) 是 JavaScript 的一个模块分包器，它可将一小段代码编译为更大更复杂的库或应用。Rollup 一般建议用来构建 JavaScript 库，特别是那种导入和依赖的第三方库较少的那种库。

**Rollup 的未来：** Rollup 很酷，且正在被迅速采用。它有很多强大的功能，将在很长一段时间内作为前端工具生态系统的一个组成部分而存在。

### 了解更多

JavaScript 前端工具的生态系统充满着变数和竞争，且只有最好的工具才能存活下来。在不久的将来，我们的构建工具将具有更少（或没有）的配置，更方便的定制化，更好的扩展性的和更好的构建速度。

该用什么样的构建工具用于你的前端项目，你需要根据具体的项目需求来做出决定。至于选择什么样的工具，才是最合适自己的，大多数时候，需要我们自己作出取舍。

更多信息, 请看:

* [JavaScript tooling: The evolution and future of JS/frontend build tools](https://qmo.io/blog/javascript-tooling-the-evolution-and-future-of-js-front-end-build-tools/)
* [Tools and modern workflow for frontend developers](https://blog.logrocket.com/tools-and-modern-workflow-for-front-end-developers-505c7227e917/)
* [Modern frontend: The tools and build process explained](https://medium.com/@trevorpoppen/modern-front-end-the-tools-and-build-process-explained-36641b5c1a53)
* [Best build tools in frontend development](https://www.developerdrive.com/best-build-tools-frontend-development/)

*这篇文章最初发表在 [Shedrack Akintayo 的博客](https://www.sheddy.xyz/posts/javascript-build-tools-past-and-beyond) 上，经许可后重新发表。*

---

via: <https://opensource.com/article/20/11/javascript-build-tools>

作者：[Shedrack Akintayo](https://opensource.com/users/shedrack-akintayo) 选题：[lujun9972](https://github.com/lujun9972) 译者：[ywxgod](https://github.com/ywxgod) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


硬核观察 | Chrome 浏览器曾是谷歌创始人瞒着 CEO 开发的

Summary: 更多：•  华为海思发布首款 RISC-V 开发板 • 勒索团伙 DarkSide 的加盟者指控管理者没付钱就跑路

chrome用的是webkit

是Blink啦，说Webkit的怕不是活在10年前哦

Mac用户活在过去中，思想迂腐老旧

来自广东江门的 Chrome Mobile 71.0|Android 6.0 用户

Mac用户活在过去中，思想迂腐老旧

# 硬核观察 | Chrome 浏览器曾是谷歌创始人瞒着 CEO 开发的

### Chrome 浏览器曾是谷歌创始人瞒着 CEO 开发的

谷歌 CEO 施密特于 2015 年在斯坦福大学的一次演讲中透露，谷歌的两位联合创始人想要构建一个操作系统和浏览器，但是施密特反对，理由是微软肯定会绞杀该项目，所以一切都会是无用功。然后拉里·佩奇和谢尔盖·布林悄悄开发了 Chrome，起点是雇人来改善 Mozilla Firefox 的性能。没想到的是，时隔六个月，施密特被叫到了一个办公室，并且惊讶地得知他们已经发明了 Chrome。

>
> 如今，Chrome 已经成了谷歌最重要的资产之一，几乎统治了整个浏览器市场。
>
>
>

### 华为海思发布首款 RISC-V 开发板

据外媒[消息](https://www.tomshardware.com/news/huaweis-hisilicon-develops-first-risc-v-design-to-overcome-arm-restrictions)，华为海思转向了开源指令集架构 RISC-V，针对鸿蒙操作系统的开发者发布了首款 RISC-V 开发板 [Hi3861](https://device.harmonyos.com/en/docs/start/introduce/oem_wifi_start_des-0000001050168548)。美国在 2019 年将华为加入到了黑名单，禁止向华为出售美国技术，而 ARM 设计包含了美国技术。Hi3861 针对的是物联网市场，而海思传统上其开发面向的是利润更高的智能手机、平板、PC 和嵌入式系统。

>
> 拥抱 RISC-V 就对了！
>
>
>

### 勒索团伙 DarkSide 的加盟者指控管理者没付钱就跑路

DarkSide 通过黑客论坛招募加盟成员，加盟分成比例高达赎金的 75% 到 90%。据统计，在过去 7 个月内，DarkSide 至少赚到了 6000 万美元。而在勒索了美国最大燃油管道公司 500 万美元导致美国进入紧急状态，引发广泛关注的 DarkSide 上周突然宣布终止运营。之后 DarkSide 成员就销声匿迹了。而在地下黑客论坛上，部分 DarkSide 加盟成员投诉 DarkSide 管理者[没付钱就跑路了](https://arstechnica.com/gadgets/2021/05/darkside-ransomware-makers-accused-of-skipping-town-without-paying-affiliates/)。

>
> 这可真是黑吃黑啊。
>
>
>


使用开源工具进行 Linux 内存取证

# 使用开源工具进行 Linux 内存取证

>
> 利用 Volatility 找出应用程序、网络连接、内核模块、文件等方面的情况。
>
>
>

<img src="content_image/album_202105_26_111959fzkhzf7q3qwmhh7z.jpg" alt="" title="Brain on a computer screen">

计算机的操作系统和应用使用主内存（RAM）来执行不同的任务。这种易失性内存包含大量关于运行应用、网络连接、内核模块、打开的文件以及几乎所有其他的内容信息，但这些信息每次计算机重启的时候都会被清除。

<ruby> 内存取证 <rt>  Memory forensics </rt></ruby>是一种从内存中找到和抽取这些有价值的信息的方式。[Volatility](https://github.com/volatilityfoundation/volatility) 是一种使用插件来处理这类信息的开源工具。但是，存在一个问题：在你处理这些信息前，必须将物理内存转储到一个文件中，而 Volatility 没有这种能力。

因此，这篇文章分为两部分：

* 第一部分是处理获取物理内存并将其转储到一个文件中。
* 第二部分使用 Volatility 从这个内存转储中读取并处理这些信息。

我在本教程中使用了以下测试系统，不过它可以在任何 Linux 发行版上工作：

```
$ cat /etc/redhat-release
Red Hat Enterprise Linux release 8.3 (Ootpa)
$
$ uname -r
4.18.0-240.el8.x86_64
$

```

>
> **注意事项：** 部分 1 涉及到编译和加载一个内核模块。不要担心：它并不像听起来那么困难。
>
>
> 一些指南：
>
>
> * 按照以下的步骤。
> * 不要在生产系统或你的主要计算机上尝试任何这些步骤。
> * 始终使用测试的虚拟机（VM）来尝试，直到你熟悉使用这些工具并理解它们的工作原理为止。
>
>
>

### 安装需要的包

在开始之前安装必要的工具。如果你经常使用基于 Debian 的发行版，可以使用 `apt-get` 命令。这些包大多数提供了需要的内核信息和工具来编译代码：

```
$ yum install kernel-headers kernel-devel gcc elfutils-libelf-devel make git libdwarf-tools python2-devel.x86_64-y

```

### 部分 1：使用 LiME 获取内存并将其转储到一个文件中

在开始分析内存之前，你需要一个内存转储供你使用。在实际的取证活动中，这可能来自一个被破坏或者被入侵的系统。这些信息通常会被收集和存储来分析入侵是如何发生的及其影响。由于你可能没有可用的内存转储，你可以获取你的测试 VM 的内存转储，并使用它来执行内存取证。

<ruby> Linux 内存提取器 <rt>  Linux Memory Extractor </rt></ruby>（[LiME](https://github.com/504ensicsLabs/LiME)）是一个在 Linux 系统上获取内存很常用的工具。使用以下命令获得 LiME：

```
$ git clone https://github.com/504ensicsLabs/LiME.git
$
$ cd LiME/src/
$
$ ls
deflate.c  disk.c  hash.c  lime.h  main.c  Makefile  Makefile.sample  tcp.c
$

```

#### 构建 LiME 内核模块

在 `src` 文件夹下运行 `make` 命令。这会创建一个以 .ko 为扩展名的内核模块。理想情况下，在 `make` 结束时，`lime.ko` 文件会使用格式 `lime-<your-kernel-version>.ko` 被重命名。

```
$ make
make -C /lib/modules/4.18.0-240.el8.x86_64/build M="/root/LiME/src" modules
make[1]: Entering directory '/usr/src/kernels/4.18.0-240.el8.x86_64'

<< 删节 >>

make[1]: Leaving directory '/usr/src/kernels/4.18.0-240.el8.x86_64'
strip --strip-unneeded lime.ko
mv lime.ko lime-4.18.0-240.el8.x86_64.ko
$
$
$ ls -l lime-4.18.0-240.el8.x86_64.ko
-rw-r--r--. 1 root root 25696 Apr 17 14:45 lime-4.18.0-240.el8.x86_64.ko
$
$ file lime-4.18.0-240.el8.x86_64.ko
lime-4.18.0-240.el8.x86_64.ko: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), BuildID[sha1]=1d0b5cf932389000d960a7e6b57c428b8e46c9cf, not stripped
$

```

#### 加载LiME 内核模块

现在是时候加载内核模块来获取系统内存了。`insmod` 命令会帮助加载内核模块；模块一旦被加载，会在你的系统上读取主内存（RAM）并且将内存的内容转储到命令行所提供的 `path` 目录下的文件中。另一个重要的参数是 `format`；保持 `lime` 的格式，如下所示。在插入内核模块之后，使用 `lsmod` 命令验证它是否真的被加载。

```
$ lsmod  | grep lime
$
$ insmod ./lime-4.18.0-240.el8.x86_64.ko "path=../RHEL8.3_64bit.mem format=lime"
$
$ lsmod  | grep lime
lime                   16384  0
$

```

你应该看到给 `path` 命令的文件已经创建好了，而且文件大小与你系统的物理内存（RAM）大小相同（并不奇怪）。一旦你有了内存转储，你就可以使用 `rmmod` 命令删除该内核模块：

```
$
$ ls -l ~/LiME/RHEL8.3_64bit.mem
-r--r--r--. 1 root root 4294544480 Apr 17 14:47 /root/LiME/RHEL8.3_64bit.mem
$
$ du -sh ~/LiME/RHEL8.3_64bit.mem
4.0G    /root/LiME/RHEL8.3_64bit.mem
$
$ free -m
              total        used        free      shared  buff/cache   available
Mem:           3736         220         366           8        3149        3259
Swap:          4059           8        4051
$
$ rmmod lime
$
$ lsmod  | grep lime
$

```

#### 内存转储中是什么？

这个内存转储文件只是原始数据，就像使用 `file` 命令可以看到的一样。你不可能通过手动去理解它；是的，在这里边有一些 ASCII 字符，但是你无法用编辑器打开这个文件并把它读出来。`hexdump` 的输出显示，最初的几个字节是 `EmiL`；这是因为你的请求格式在上面的命令行中是 `lime`：

```
$ file ~/LiME/RHEL8.3_64bit.mem
/root/LiME/RHEL8.3_64bit.mem: data
$

$ hexdump -C ~/LiME/RHEL8.3_64bit.mem | head
00000000  45 4d 69 4c 01 00 00 00  00 10 00 00 00 00 00 00  |EMiL............|
00000010  ff fb 09 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000020  b8 fe 4c cd 21 44 00 32  20 00 00 2a 2a 2a 2a 2a  |..L.!D.2 ..*****|
00000030  2a 2a 2a 2a 2a 2a 2a 2a  2a 2a 2a 2a 2a 2a 2a 2a  |****************|
00000040  2a 2a 2a 2a 2a 2a 2a 2a  2a 2a 2a 2a 2a 20 00 20  |************* . |
00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000080  00 00 00 00 00 00 00 00  00 00 00 00 70 78 65 6c  |............pxel|
00000090  69 6e 75 78 2e 30 00 00  00 00 00 00 00 00 00 00  |inux.0..........|
000000a0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
$

```

### 部分 2：获得 Volatility 并使用它来分析你的内存转储

现在你有了要分析的示例内存转储，使用下面的命令获取 Volatility 软件。Volatility 已经用 Python 3 重写了，但是本教程使用的是用 Python 2 写的原始的 Volatility 包。如果你想用 Volatility 3 进行实验，可以从合适的 Git 仓库下载它，并在以下命令中使用 Python 3 而不是 Python 2：

```
$ git clone https://github.com/volatilityfoundation/volatility.git
$
$ cd volatility/
$
$ ls
AUTHORS.txt    contrib      LEGAL.txt    Makefile     PKG-INFO     pyinstaller.spec  resources  tools       vol.py
CHANGELOG.txt  CREDITS.txt  LICENSE.txt  MANIFEST.in  pyinstaller  README.txt        setup.py   volatility
$

```

Volatility 使用两个 Python 库来实现某些功能，所以使用以下命令来安装它们。否则，在你运行 Volatility 工具时，你可能看到一些导入错误；你可以忽略它们，除非你正在运行的插件需要这些库；这种情况下，工具将会报错：

```
$ pip2 install pycrypto
$ pip2 install distorm3

```

#### 列出 Volatility 的 Linux 配置文件

你将要运行的第一个 Volatility 命令列出了可用的 Linux 配置文件，运行 Volatility 命令的主要入口点是 `vol.py` 脚本。使用 Python 2 解释器调用它并提供 `--info` 选项。为了缩小输出，查找以 Linux 开头的字符串。正如你所看到的，并没有很多 Linux 配置文件被列出：

```
$ python2 vol.py --info  | grep ^Linux
Volatility Foundation Volatility Framework 2.6.1
LinuxAMD64PagedMemory          - Linux-specific AMD 64-bit address space.
$

```

#### 构建你自己的 Linux 配置文件

Linux 发行版是多种多样的，并且是为不同架构而构建的。这就是为什么配置文件是必要的 —— Volatility 在提取信息前必须知道内存转储是从哪个系统和架构获得的。有一些 Volatility 命令可以找到这些信息；但是这个方法很费时。为了加快速度，可以使用以下命令构建一个自定义的 Linux 配置文件：

移动到 Volatility 仓库的 `tools/linux`目录下，运行 `make` 命令：

```
$ cd tools/linux/
$
$ pwd
/root/volatility/tools/linux
$
$ ls
kcore  Makefile  Makefile.enterprise  module.c
$
$ make
make -C //lib/modules/4.18.0-240.el8.x86_64/build CONFIG_DEBUG_INFO=y M="/root/volatility/tools/linux" modules
make[1]: Entering directory '/usr/src/kernels/4.18.0-240.el8.x86_64'
<< 删节 >>
make[1]: Leaving directory '/usr/src/kernels/4.18.0-240.el8.x86_64'
$

```

你应该看到一个新的 `module.dwarf` 文件。你也需要 `/boot` 目录下的 `System.map` 文件，因为它包含了所有与当前运行的内核相关的符号：

```
$ ls
kcore  Makefile  Makefile.enterprise  module.c  module.dwarf
$
$ ls -l module.dwarf
-rw-r--r--. 1 root root 3987904 Apr 17 15:17 module.dwarf
$
$ ls -l /boot/System.map-4.18.0-240.el8.x86_64
-rw-------. 1 root root 4032815 Sep 23  2020 /boot/System.map-4.18.0-240.el8.x86_64
$
$

```

要创建一个自定义配置文件，移动回到 Volatility 目录并且运行下面的命令。第一个参数提供了一个自定义 .zip 文件，文件名是你自己命名的。我经常使用操作系统和内核版本来命名。下一个参数是前边创建的 `module.dwarf` 文件，最后一个参数是 `/boot` 目录下的 `System.map` 文件：

```
$
$ cd volatility/
$
$ zip volatility/plugins/overlays/linux/Redhat8.3_4.18.0-240.zip tools/linux/module.dwarf /boot/System.map-4.18.0-240.el8.x86_64
  adding: tools/linux/module.dwarf (deflated 91%)
  adding: boot/System.map-4.18.0-240.el8.x86_64 (deflated 79%)
$

```

现在自定义配置文件就准备好了，所以在前边给出的位置检查一下 .zip 文件是否被创建好。如果你想知道 Volatility 是否检测到这个自定义配置文件，再一次运行 `--info` 命令。现在，你应该可以在下边的列出的内容中看到新的配置文件：

```
$
$ ls -l volatility/plugins/overlays/linux/Redhat8.3_4.18.0-240.zip
-rw-r--r--. 1 root root 1190360 Apr 17 15:20 volatility/plugins/overlays/linux/Redhat8.3_4.18.0-240.zip
$
$
$ python2 vol.py --info  | grep Redhat
Volatility Foundation Volatility Framework 2.6.1
LinuxRedhat8_3_4_18_0-240x64 - A Profile for Linux Redhat8.3_4.18.0-240 x64
$
$

```

#### 开始使用 Volatility

现在你已经准备好去做一些真正的内存取证了。记住，Volatility 是由自定义的插件组成的，你可以针对内存转储来获得信息。命令的通用格式是：

```
python2 vol.py -f <memory-dump-file-taken-by-Lime> <plugin-name> --profile=<name-of-our-custom-profile>

```

有了这些信息，运行 `linux_banner` 插件来看看你是否可从内存转储中识别正确的发行版信息：

```
$ python2 vol.py -f ~/LiME/RHEL8.3_64bit.mem linux_banner --profile=LinuxRedhat8_3_4_18_0-240x64
Volatility Foundation Volatility Framework 2.6.1
Linux version 4.18.0-240.el8.x86_64 ([mockbuild@vm09.test.com][4]) (gcc version 8.3.1 20191121 (Red Hat 8.3.1-5) (GCC)) #1 SMP Wed Sep 23 05:13:10 EDT 2020
$

```

#### 找到 Linux 插件

到现在都很顺利，所以现在你可能对如何找到所有 Linux 插件的名字比较好奇。有一个简单的技巧：运行 `--info` 命令并抓取 `linux_` 字符串。有各种各样的插件可用于不同的用途。这里列出一部分：

```
$ python2 vol.py --info  | grep linux_
Volatility Foundation Volatility Framework 2.6.1
linux_apihooks             - Checks for userland apihooks
linux_arp                  - Print the ARP table
linux_aslr_shift           - Automatically detect the Linux ASLR shift

<< 删节 >>

linux_banner               - Prints the Linux banner information
linux_vma_cache            - Gather VMAs from the vm_area_struct cache
linux_volshell             - Shell in the memory image
linux_yarascan             - A shell in the Linux memory image
$

```

使用 `linux_psaux` 插件检查内存转储时系统上正在运行哪些进程。注意列表中的最后一个命令：它是你在转储之前运行的 `insmod` 命令。

```
$ python2 vol.py -f ~/LiME/RHEL8.3_64bit.mem linux_psaux --profile=LinuxRedhat8_3_4_18_0-240x64
Volatility Foundation Volatility Framework 2.6.1
Pid    Uid    Gid    Arguments
1      0      0      /usr/lib/systemd/systemd --switched-root --system --deserialize 18
2      0      0      [kthreadd]
3      0      0      [rcu_gp]
4      0      0      [rcu_par_gp]
861    0      0      /usr/libexec/platform-python -Es /usr/sbin/tuned -l -P
869    0      0      /usr/bin/rhsmcertd
875    0      0      /usr/libexec/sssd/sssd_be --domain implicit_files --uid 0 --gid 0 --logger=files
878    0      0      /usr/libexec/sssd/sssd_nss --uid 0 --gid 0 --logger=files

<< 删节 >>

11064  89     89     qmgr -l -t unix -u
227148 0      0      [kworker/0:0]
227298 0      0      -bash
227374 0      0      [kworker/u2:1]
227375 0      0      [kworker/0:2]
227884 0      0      [kworker/0:3]
228573 0      0      insmod ./lime-4.18.0-240.el8.x86_64.ko path=../RHEL8.3_64bit.mem format=lime
228576 0      0
$

```

想要知道系统的网络状态吗？运行 `linux_netstat` 插件来找到在内存转储期间网络连接的状态：

```
$ python2 vol.py -f ~/LiME/RHEL8.3_64bit.mem linux_netstat --profile=LinuxRedhat8_3_4_18_0-240x64
Volatility Foundation Volatility Framework 2.6.1
UNIX 18113              systemd/1     /run/systemd/private
UNIX 11411              systemd/1     /run/systemd/notify
UNIX 11413              systemd/1     /run/systemd/cgroups-agent
UNIX 11415              systemd/1
UNIX 11416              systemd/1

<< 删节 >>
$

```

接下来，使用 `linux_mount` 插件来看在内存转储期间哪些文件系统被挂载：

```
$ python2 vol.py -f ~/LiME/RHEL8.3_64bit.mem linux_mount --profile=LinuxRedhat8_3_4_18_0-240x64
Volatility Foundation Volatility Framework 2.6.1
tmpfs                     /sys/fs/cgroup                      tmpfs        ro,nosuid,nodev,noexec
cgroup                    /sys/fs/cgroup/pids                 cgroup       rw,relatime,nosuid,nodev,noexec
systemd-1                 /proc/sys/fs/binfmt_misc            autofs       rw,relatime
sunrpc                    /var/lib/nfs/rpc_pipefs             rpc_pipefs   rw,relatime
/dev/mapper/rhel_kvm--03--guest11-root /                                   xfs          rw,relatime
tmpfs                     /dev/shm                            tmpfs        rw,nosuid,nodev
selinuxfs                 /sys/fs/selinux                     selinuxfs    rw,relatime

<< 删节 >>

cgroup                    /sys/fs/cgroup/net_cls,net_prio     cgroup       rw,relatime,nosuid,nodev,noexec
cgroup                    /sys/fs/cgroup/cpu,cpuacct          cgroup       rw,relatime,nosuid,nodev,noexec
bpf                       /sys/fs/bpf                         bpf          rw,relatime,nosuid,nodev,noexec
cgroup                    /sys/fs/cgroup/memory               cgroup       ro,relatime,nosuid,nodev,noexec
cgroup                    /sys/fs/cgroup/cpuset               cgroup       rw,relatime,nosuid,nodev,noexec
mqueue                    /dev/mqueue                         mqueue       rw,relatime
$

```

好奇哪些内核模块被加载了吗？Volatility 也为这个提供了一个插件 `linux_lsmod`：

```
$ python2 vol.py -f ~/LiME/RHEL8.3_64bit.mem linux_lsmod --profile=LinuxRedhat8_3_4_18_0-240x64
Volatility Foundation Volatility Framework 2.6.1
ffffffffc0535040 lime 20480
ffffffffc0530540 binfmt_misc 20480
ffffffffc05e8040 sunrpc 479232
<< 删节 >>
ffffffffc04f9540 nfit 65536
ffffffffc0266280 dm_mirror 28672
ffffffffc025e040 dm_region_hash 20480
ffffffffc0258180 dm_log 20480
ffffffffc024bbc0 dm_mod 151552
$

```

想知道哪些文件被哪些进程打开了吗？使用 `linux_bash` 插件可以列出这些信息：

```
$ python2 vol.py -f ~/LiME/RHEL8.3_64bit.mem linux_bash --profile=LinuxRedhat8_3_4_18_0-240x64 -v
Volatility Foundation Volatility Framework 2.6.1
Pid      Name                 Command Time                   Command
-------- -------------------- ------------------------------ -------
  227221 bash                 2021-04-17 18:38:24 UTC+0000   lsmod
  227221 bash                 2021-04-17 18:38:24 UTC+0000   rm -f .log
  227221 bash                 2021-04-17 18:38:24 UTC+0000   ls -l /etc/zzz
  227221 bash                 2021-04-17 18:38:24 UTC+0000   cat ~/.vimrc
  227221 bash                 2021-04-17 18:38:24 UTC+0000   ls
  227221 bash                 2021-04-17 18:38:24 UTC+0000   cat /proc/817/cwd
  227221 bash                 2021-04-17 18:38:24 UTC+0000   ls -l /proc/817/cwd
  227221 bash                 2021-04-17 18:38:24 UTC+0000   ls /proc/817/
<< 删节 >>
  227298 bash                 2021-04-17 18:40:30 UTC+0000   gcc prt.c
  227298 bash                 2021-04-17 18:40:30 UTC+0000   ls
  227298 bash                 2021-04-17 18:40:30 UTC+0000   ./a.out
  227298 bash                 2021-04-17 18:40:30 UTC+0000   vim prt.c
  227298 bash                 2021-04-17 18:40:30 UTC+0000   gcc prt.c
  227298 bash                 2021-04-17 18:40:30 UTC+0000   ./a.out
  227298 bash                 2021-04-17 18:40:30 UTC+0000   ls
$

```

想知道哪些文件被哪些进程打开了吗？使用 `linux_lsof` 插件可以列出这些信息：

```
$ python2 vol.py -f ~/LiME/RHEL8.3_64bit.mem linux_lsof --profile=LinuxRedhat8_3_4_18_0-240x64
Volatility Foundation Volatility Framework 2.6.1
Offset             Name                           Pid      FD       Path
------------------ ------------------------------ -------- -------- ----
0xffff9c83fb1e9f40 rsyslogd                          71194        0 /dev/null
0xffff9c83fb1e9f40 rsyslogd                          71194        1 /dev/null
0xffff9c83fb1e9f40 rsyslogd                          71194        2 /dev/null
0xffff9c83fb1e9f40 rsyslogd                          71194        3 /dev/urandom
0xffff9c83fb1e9f40 rsyslogd                          71194        4 socket:[83565]
0xffff9c83fb1e9f40 rsyslogd                          71194        5 /var/log/messages
0xffff9c83fb1e9f40 rsyslogd                          71194        6 anon_inode:[9063]
0xffff9c83fb1e9f40 rsyslogd                          71194        7 /var/log/secure

<< 删节 >>

0xffff9c8365761f40 insmod                           228573        0 /dev/pts/0
0xffff9c8365761f40 insmod                           228573        1 /dev/pts/0
0xffff9c8365761f40 insmod                           228573        2 /dev/pts/0
0xffff9c8365761f40 insmod                           228573        3 /root/LiME/src/lime-4.18.0-240.el8.x86_64.ko
$

```

#### 访问 Linux 插件脚本位置

通过读取内存转储和处理这些信息，你可以获得更多的信息。如果你会 Python，并且好奇这些信息是如何被处理的，可以到存储所有插件的目录，选择一个你感兴趣的，并看看 Volatility 是如何获得这些信息的：

```
$ ls volatility/plugins/linux/
apihooks.py              common.py            kernel_opened_files.py   malfind.py          psaux.py
apihooks.pyc             common.pyc           kernel_opened_files.pyc  malfind.pyc         psaux.pyc
arp.py                   cpuinfo.py           keyboard_notifiers.py    mount_cache.py      psenv.py
arp.pyc                  cpuinfo.pyc          keyboard_notifiers.pyc   mount_cache.pyc     psenv.pyc
aslr_shift.py            dentry_cache.py      ld_env.py                mount.py            pslist_cache.py
aslr_shift.pyc           dentry_cache.pyc     ld_env.pyc               mount.pyc           pslist_cache.pyc
<< 删节 >>
check_syscall_arm.py     __init__.py          lsmod.py                 proc_maps.py        tty_check.py
check_syscall_arm.pyc    __init__.pyc         lsmod.pyc                proc_maps.pyc       tty_check.pyc
check_syscall.py         iomem.py             lsof.py                  proc_maps_rb.py     vma_cache.py
check_syscall.pyc        iomem.pyc            lsof.pyc                 proc_maps_rb.pyc    vma_cache.pyc
$
$

```

我喜欢 Volatility 的理由是他提供了许多安全插件。这些信息很难手动获取：

```
linux_hidden_modules       - Carves memory to find hidden kernel modules
linux_malfind              - Looks for suspicious process mappings
linux_truecrypt_passphrase - Recovers cached Truecrypt passphrases

```

Volatility 也允许你在内存转储中打开一个 shell，所以你可以运行 shell 命令来代替上面所有命令，并获得相同的信息：

```
$ python2 vol.py -f ~/LiME/RHEL8.3_64bit.mem linux_volshell --profile=LinuxRedhat8_3_4_18_0-240x64 -v
Volatility Foundation Volatility Framework 2.6.1
Current context: process systemd, pid=1 DTB=0x1042dc000
Welcome to volshell! Current memory image is:
file:///root/LiME/RHEL8.3_64bit.mem
To get help, type 'hh()'
>>>
>>> sc()
Current context: process systemd, pid=1 DTB=0x1042dc000
>>>

```

### 接下来的步骤

内存转储是了解 Linux 内部情况的好方法。试一试 Volatility 的所有插件，并详细研究它们的输出。然后思考这些信息如何能够帮助你识别入侵或安全问题。深入了解这些插件的工作原理，甚至尝试改进它们。如果你没有找到你想做的事情的插件，那就写一个并提交给 Volatility，这样其他人也可以使用它。

---

via: <https://opensource.com/article/21/4/linux-memory-forensics>

作者：[Gaurav Kamathe](https://opensource.com/users/gkamathe) 选题：[lujun9972](https://github.com/lujun9972) 译者：[RiaXu](https://github.com/ShuyRoy) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


将 Fedora Linux 系统添加到企业域中

Summary: FreeIPA 和 活动目录就是用于这个任务的技术。它们允许系统管理员使用网络中所有实体的目录来管理大量的机器。

# 将 Fedora Linux 系统添加到企业域中

在企业互联网场景中，一般情况下最广泛使用的基于 Linux 的操作系统是 Red Hat Enterprise Linux（RHEL），它主要用于服务器，但也可以用作工作站。Fedora linux 其实也是工作站系统的一个很好的选择，它提供了许多在企业环境中工作的特性，使管理成为一项简单的任务。

当你的工作网络中有许多机器时，你需要一种以集中方式管理用户和机器的方法。[FreeIPA](https://www.freeipa.org/page/Main_Page) 和 <ruby>   活动目录  <rt>  Active Directory </rt></ruby> 就是用于这个任务的技术。它们允许系统管理员使用网络中所有实体的目录来管理大量的机器。

### Fedora 中的活动目录

活动目录在公司环境中非常常见。Fedora 和 RHEL 通过使用 SSSD （<ruby> 系统安全服务守护进程 <rt>  System Security Services Daemon </rt></ruby>）与 FreeIPA 或活动目录等服务很好地集成。SSSD 是一种访问远程目录和身份验证机制的系统服务。使用此软件的计算机能够使用远程凭据进行身份验证，并访问该目录网络中可用的其他服务。

要加入域网络，你需要域管理员的权限才能添加计算机。可以通过在域凭据上设置特殊权限或代表你对该计算机进行预配置。Fedora Linux 有一个在安装时配置机器的选项，叫做<ruby> 企业登录 <rt>  Enterprise Login </rt></ruby>。如果你的计算机网络自动配置为企业域网络，那么你可以直接使用域凭据登录。

如果你的配置不是自动的，或者你已经安装了 Fedora Linux，你可以通过以下几个配置步骤加入一个活动目录域：

1. 设置此计算机的 DNS。要连接到目录服务，首先需要能够解析目录域名。如果你的网络使用 DHCP 设置正确的 DNS，则可以跳过此步骤。
2. 更改你的计算机名称，以反映它将是新域的一部分。编辑文件 `/etc/hostname`，并将机器名更改为 `machinename.my_domain`。
3. 通过执行以下命令加入域：`sudo realm join my_domain -v`（ 用域名称替换 `my_domain`）。

运行此命令后，系统将请求允许加入该域中新计算机的用户的凭据。如果进程中没有错误，则机器将成为域的一部分。

现在，此计算机已成为你的域的一部分，你可以：

* 使用域用户名登录到计算机
* 获取 kerberos 票据以访问域网络中的不同服务
* 访问其他服务，具体取决于域的配置方式

### 使用 Fleet Commander 管理 Fedora Linux

现在这台计算机已经是你的域的一部分了，你可以使用活动目录的域管理员工具来管理它。由于你的计算机没有运行 Windows，因此你只能进行身份验证以及访问网络和目录服务。无法在此计算机上设置与桌面相关的配置。

幸运的是，Fedora 有个工具叫 [Fleet Commander](https://fleet-commander.org/)。

#### 创建配置

Fleet Commander 是一个管理工具，允许你为网络中的所有 Fedora Linux 机器设置桌面配置文件。

这意味着，你可以简单地为 GNOME 桌面、Firefox、Chrome、LibreOffice 和其他支持的软件设置任何配置，然后在登录到选定的用户/组/计算机时以细粒度的方式应用该配置。

要使用这个工具首先安装 `fleet-commander-admin` 软件包：

```
sudo dnf install fleet-commander-admin

```

然后，用浏览器访问 [http://localhost:9090](http://localhost:9090/) 来登录。在左边的菜单中，点击 “Fleet Commander”。

Fleet Commander 有一个工具，可以使用“实时会话”机制直观地设置配置概要文件。它运行一个虚拟机，作为基本机器的模板。你需要手动进行所需的配置更改。然后检查所有配置更改，选择要添加到配置文件中的更改，然后部署它。

#### 管理客户端

在每个 Fedora Linux 或 RHEL 机器中，你都需要安装 Fleet Commander 客户端服务。此服务在用户登录时激活。它在域中搜索应用于当前用户/计算机的配置文件，并应用这个配置。

安装 `fleet-commander-client`：

```
sudo dnf install fleet-commander-client

```

软件将自动检测机器是否是域的一部分。当用户登录时，它将使用应用于该用户的配置文件来设置会话。

---

via: <https://fedoramagazine.org/join-fedora-linux-enterprise-domain/>

作者：[ogutierrez](https://fedoramagazine.org/author/ogutierrez/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[Chao-zhi](https://github.com/Chao-zhi) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


硬核观察 | 微软使用 GPT-3 让你可以用自然语言编码

Summary: 更多：• Google 正式在其设备上推送 Fuchsia OS • 微软将很快发布“下一代 Windows”

因为WP的各种坑，估计很多开发者都对微软的各种奇奇怪怪的Windows敬而远之吧

来自广东深圳的 Firefox 68.0|Windows Phone 10.0 用户

# 硬核观察 | 微软使用 GPT-3 让你可以用自然语言编码

### 微软使用 GPT-3 让你可以用自然语言编码

微软现在正在其无代码/低代码的 Power Apps 服务中[使用](https://techcrunch.com/2021/05/25/microsoft-uses-gpt-3-to-let-you-code-in-natural-language/) OpenAI 的大规模 GPT-3 自然语言模型，将口语文本翻译成其最近发布的 Power Fx 语言的代码。当然，你不可能在只使用自然语言的情况下开发出一个大应用，目前只是将一些低代码开发进一步转变成无代码开发。

>
> 低代码/无代码开发只能用在某些不那么严肃的领域，我认为它甚至不能起到比脚本语言更大的作用。但是这个尝试是好的，毕竟不是每个领域都需要专业程序员。
>
>
>

### Google 正式在其设备上推送 Fuchsia OS

发布于 2018 年的第一代 Nest Hub 正在陆续[收到更新](https://9to5google.com/2021/05/25/google-releases-fuchsia-os-nest-hub/)，将其原本以 Linux 内核为基础的 Cast OS 替代为 Fuchsia OS。这个更新不会带来任何功能上的变化，体验也不会和之前有什么不同，因为其上运行都是 Flutter 应用，用户甚至有可能不会知道自己的设备已经切换到了 Fuchsia OS。

>
> 谷歌从 2016 年就宣布开发 Fuchsia OS，如今才能真正部署到用户设备上，可见即便是开发了 Android 的谷歌，从头开始创造一个操作系统也没那么容易。
>
>
>

### 微软将很快发布“下一代 Windows”

微软 CEO 萨蒂亚·纳德拉在今天上午的 Build 主题演讲中[预告](https://www.windowscentral.com/satya-nadella-teases-big-updates-coming-soon-windows-build-2021)了这一消息，透露了他近几个月一直在测试“下一代 Windows”。微软上周证实，其最初为双屏设备打造的操作系统 Windows 10X 将不再继续独立开发。

>
> 这个所谓的“下一代 Windows” 可能是又一个新的 Windows 世代，莫非会像网友们建议的那样，直接叫“Windows”？
>
>
>


用开源软件保护你的文件的 5 种方法

Summary: 控制你自己的数据，使未经授权的用户无法访问它。

控制你自己的数据，使未经授权的用户无法访问它。

# 用开源软件保护你的文件的 5 种方法

>
> 控制你自己的数据，使未经授权的用户无法访问它。
>
>
>

用户完全有权利关心他们数据的安全和保障。当你在计算机上创建数据时，希望对其进行独家控制是合理的。

有许多方法保护你的文件。在文件系统层面，你可以 [加密你的硬盘](https://opensource.com/article/21/3/encryption-luks) 或 [只是加密一个文件](https://opensource.com/article/21/3/luks-truecrypt)。不过，一个好的办公套件为你提供了更多的选择，我收集了五种我用开源软件保护文件的方法。

### 5 种保护你的文件的方法

#### 1、将文件保存在安全的云存储服务中

自托管一个开源的内容管理系统（CMS）平台可以让你完全控制你的数据。你的所有数据都留在你的服务器上，你可以控制谁可以访问它。

**选项：** [Nextcloud](https://nextcloud.com/)、[ownCloud](https://owncloud.com/)、[Pydio](https://pydio.com/) 和 [Seafile](https://www.seafile.com/en/home/)

所有这些都提供了存储、同步和共享文件和文件夹、管理内容、文件版本等功能。它们可以很容易地取代 Dropbox、Google Drive 和其他专有的云存储，不用将你的数据放在你不拥有、不维护、不管理的服务器上。

上面列出的开源的自托管方式符合 GDPR 和其他保护用户数据的国际法规。它们提供备份和数据恢复选项、审计和监控工具、权限管理和数据加密。

*Pydio 细胞中的审计控制。(来源：[Pydio.com](http://pydio.com))*

#### 2、启用静态、传输和端到端的加密功能

我们经常笼统地谈论数据加密，但在加密文件时有几个方面需要考虑：

* 通过**静态加密**（或磁盘加密），你可以保护存储在你的基础设施内或硬盘上的数据。
* 在使用 HTTPS 等协议时，**传输加密**会保护流量形式的数据。它可以保护你的数据在从一个地方移动到另一个地方时不被拦截和转换。当你把文件上传到你的云端时，这很重要。
* **端到端加密**（E2EE）通过在一端加密，在另一端解密来保护数据。除非有解密密钥，否则任何第三方都无法读取你的文件，即使他们干扰了这个过程并获得了这个文件的权限。

**选项：** CryptPad、ownCloud、ONLYOFFICE 工作区、Nextcloud 和 Seafile

ownCloud、ONLYOFFICE 工作区、Nextcloud 和 Seafile 支持所有三层的加密。但它们在实现端到端加密的方式上有所不同。

* 在 ownCloud 中，有一个 E2EE 插件，允许你对文件夹共享进行加密。
* 在 Nextcloud 中，桌面客户端有一个文件夹级别的选项。
* Seafile 通过创建加密库来提供客户端的 E2EE。
* [ONLYOFFICE 工作区](https://www.onlyoffice.com/workspace.aspx) 不仅允许你在存储和共享文件时对其进行加密，而且还允许你在“私人房间”中实时安全地共同编辑文件。加密数据是自动生成和传输的，并且是自己加密的 —— 你不需要保留或记住任何密码。
* 正如其名称所示，[CryptPad](https://cryptpad.fr/) 是完全私有的。所有的内容都是由你的浏览器进行加密和解密的。这意味着文件、聊天记录和文件在你登录的会话之外是无法阅读的。即使是服务管理员也无法得到你的信息。

*加密的 CryptPad 存储。(来源：[Cryptpad.fr](http://cryptpad.fr))*

#### 3、使用数字签名

数字签名可以让你验证你是文件内容的原作者，并且没有对其进行过修改。

**选项：** LibreOffice Writer、ONLYOFFICE 桌面编辑器、OpenESignForms 和 SignServer

[LibreOffice](https://www.libreoffice.org/) 和 [ONLYOFFICE](https://www.onlyoffice.com/desktop.aspx) 套件提供了一个对文件数字签名的集成工具。你可以添加一个在文档文本中可见的签名行，并允许你向其他用户请求签名。

一旦你应用了数字签名，任何人都不能编辑该文件。如果有人修改文档，签名就会失效，这样你就会知道内容被修改了。

在 ONLYOFFICE 中，你可以在 LibreOffice 中签名 OOXML 文件（例如，DOCX、XLSX、PPTX）作为 ODF 和 PDF。如果你试图在 LibreOffice 中签名一个 OOXML 文件，该签名将被标记为“只有部分文件被签署”。

*ONLYOFFICE 中的数字签名。 (来源：[ONLYOFFICE帮助中心](http://helpcenter.onlyoffice.com))*

[SignServer](https://www.signserver.org/) 和 [Open eSignForms](https://github.com/OpenESignForms) 是免费的电子签名服务，如果你不需要在编辑器中直接签名文件，你可以使用它们。这两个工具都可以让你处理文档，SignServer 还可以让你签名包括 Java 在内的代码，并应用时间戳。

#### 4、添加水印

水印可避免你的内容在未经授权的情况下被重新分发，并保护你的文件可能包含的任何机密信息。

**选项：**Nextcloud 中的 Collabora Online 或 ONLYOFFICE Docs

当与 Nextcloud 集成时，[ONLYOFFICE Docs](https://www.onlyoffice.com/office-for-nextcloud.aspx) 和 [Collabora](https://www.collaboraoffice.com/) 允许你在文件、电子表格和演示文稿中嵌入水印。要激活水印功能，必须以管理员身份登录你的 Nextcloud 实例，并在解决方案的设置页面上进入**安全视图设置**。

你可以使用占位符将默认的水印替换成你自己的文本。在打开文件时，水印将针对每个用户单独显示。你也可以定义组来区分将看到水印的用户，并选择必须显示水印的共享类型。

*水印 (Ksenia Fedoruk, [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/))*

你也可以在 LibreOffice 和 ONLYOFFICE 桌面应用程序中的文档中插入水印。然而，在这种情况下，它只是一个放置在主文本层下的文本或图像，任何人都可以轻易地删除它。

#### 5、用密码保护文件

密码保护允许你安全地存储和交换本地文件。如果有人访问你的桌面或通过电子邮件或其他方法得到受保护的文件，他们不知道密码就无法打开它。

**选项：** Apache OpenOffice、LibreOffice 和 ONLYOFFICE 桌面编辑器

所有这三种解决方案都提供了为你的敏感文件设置密码的能力。

如果一个受保护的文档对你很重要，强烈建议你使用密码管理器保存密码或记住它，因为 LibreOffice、ONLYOFFICE 和 [OpenOffice](https://www.openoffice.org/) 不提供密码恢复选项。因此，如果你忘记或丢失了密码，就没有办法恢复或重置密码并打开文件。

### 你的数据属于你

使用这些方法中的一种或多种来保护你的文件，以保持更安全的在线活动。现在是 21 世纪，计算机太先进了，不能冒险把你的数据交给你无法控制的服务。使用开源，掌握你的数字生活的所有权。

你最喜欢的安全使用文档的工具是什么？请在评论中分享它们。

---

via: <https://opensource.com/article/21/4/secure-documents-open-source>

作者：[Ksenia Fedoruk](https://opensource.com/users/ksenia-fedoruk) 选题：[lujun9972](https://github.com/lujun9972) 译者：[wxy](https://github.com/wxy) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


什么是 Java 的无服务器化？

Summary: Java 仍是开发企业应用程序最流行的语言之一。那么，为什么无服务器开发人员对它望而却步？

# 什么是 Java 的无服务器化？

>
> Java 仍是开发企业应用程序最流行的语言之一。那么，为什么<ruby> 无服务器 <rt>  serverless </rt></ruby>开发人员对它望而却步？
>
>
>

几十年来，企业已经在各类平台上开发了关键业务应用程序，包括物理服务器、虚拟机和云环境。这些应用程序在各行各业都有一个共同点，那就是无论需求如何，它们都需要持续可用（24x7x365），保证稳定性、可靠性和性能。因此，即使实际资源利用率低于 50%，每个企业都必须付出高额成本维护基础架构（如 CPU、内存、磁盘、网络等）。

无服务器架构是为了帮助解决这些问题而产生的。无服务器允许开发人员按需构建和运行应用程序，保证高可用性，不必在多云和混合云环境中管理服务器。在幕后，无服务器拓扑中仍有很多服务器，但它们是从应用程序开发中抽象出来的。相反，云提供商使用无服务器进行资源管理，例如配置、维护、联网和扩展服务器实例。

由于其高效性，无服务器开发模式现在是一些企业的需求，这些企业希望按需启动服务，而不是一直运行服务。

许多新建的开源项目用来在 [Kubernetes](https://opensource.com/article/19/6/reasons-kubernetes) 集群上通过 Linux 容器包来管理无服务器应用程序。CNCF 的《[交互式无服务器全景](https://landscape.cncf.io/serverless?zoom=150)》 是一份关于开源项目、工具、框架和公共云平台的指南，帮助 DevOps 团队处理无服务器应用程序。

开发人员可以编写代码，然后将其快速部署到各种无服务器环境中。然后，无服务器应用程序响应需求，并根据需要自动伸缩扩展。

你可能想知道什么编程语言和运行环境最适合无服务器应用程序开发，以便与上图中的技术集成。这个问题不只一个答案，但是让我们退一步来讨论在企业生产环境中开发业务应用程序最流行的应用程序运行环境：Java。

据 [Developer Economics](https://developereconomics.com/) 称，截至 2020 年第三季度，仍有 800 多万家企业开发人员在使用 Java 来实现其业务需求。然而，根据 2020 年的一项调查，Java（占比 6%）显然不是有前瞻意识的开发人员的首选，他们使用当前云服务做开发。

*来自 NewRelic 无服务器基准报告的数据（Daniel Oh, [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)）*

资源使用、响应时间和延迟在无服务器开发中至关重要。公有云提供商提供的无服务器产品通常是按需计量的，只有在无服务器应用程序启动时，才会通过事件驱动的执行模式收费。因此，当无服务器应用程序闲置或缩减为零时，企业无需支付任何费用。

### 带有容器的 Java 状态

在这种背景下，你可能会问：“*既然现有业务应用程序很可能是在 Java 技术上开发的，那么开发人员为什么不尝试使用 Java 栈进行无服务器应用程序开发呢？*”

隐藏的真相是：很难在新的不可变更的基础设施（例如 Kubernetes 这样的容器平台）中优化 Java 应用程序。

该图描述了 Java 进程与竞争的语言、框架（如 [Node.js](https://nodejs.org/) 和 [Go](https://golang.org/)）之间内存资源使用的差异。Java HotSpot 占用资源最大，其中包括每个<ruby> Java 虚拟机 <rt>  Java Virtual Machine </rt></ruby>（JVM）实例分配的堆内存。中间显示了 Node.js 每个进程要比 Java 小得多。最后，Go 是一种流行的云服务编程语言，因为它的内存消耗最低。

如你所见，当你在这张图从左到右走，你会看到更密的节点。这就是开发人员在云、容器和 Kubernetes 上编写无服务器应用程序时回避 Java（包括 [Spring Boot](https://spring.io/projects/spring-boot)，一种顽固的微服务 Java 框架）的原因。

### 下一步是什么？

企业可以通过实现无服务器应用程序获得明显的好处，但是资源密度问题导致他们避免使用 Java 堆栈在 Kubernetes 上开发无服务器应用程序开发。但是选择其他语言会给全球数百万 Java 开发人员带来学习负担。因此，在本系列的下一篇文章中，我将指导你如何开始使用 Java 无服务器函数，而不是使用其他语言。

---

via: <https://opensource.com/article/21/5/what-serverless-java>

作者：[Daniel Oh](https://opensource.com/users/daniel-oh) 选题：[lujun9972](https://github.com/lujun9972) 译者：[DCOLIVERSUN](https://github.com/DCOLIVERSUN) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


硬核观察 | 腾讯开源代码安全指南

Summary: 更多：• 亚马逊购买了米高梅电影制作公司 • 迪拜发布了自己的数字货币

更多：• 亚马逊购买了米高梅电影制作公司 • 迪拜发布了自己的数字货币

# 硬核观察 | 腾讯开源代码安全指南

大家好，我是小白，今天的硬核观察由我来为大家播报。

老王在接下来的几天，有事需要外出，无法为大家播报硬核观察，所以就由我来替代他，为大家制作硬核观察。

### 腾讯开源代码安全指南

腾讯在 5 月 18 日在 Github 账号 Tencent 下开源了一个名为 SecGuide 的仓库，其中为腾讯整理的不同编程语言的安全指南，帮助开发者了解自己代码中存在的问题，减少出现安全风险的可能。

>
> 腾讯在Github 上参与开源、为社区作出贡献是一件值得鼓励的事情。不过，也希望能够有更多的腾讯内部的开发者、外部的开发者共同来贡献这个安全指南，这样才能真正体现开源社区的价值。而不是仅仅是开源出来就没有了下文。安全面临的问题总是在不断的更新，而我们的安全指南，也应该常看常新。
>
>
>

### 亚马逊购买了米高梅电影制作公司

美国的云计算、电商巨头亚马逊支付了90亿美元购买了经典电影制作公司米高梅。该公司曾制作了我们熟悉的动画《猫和老鼠》、也是 007 系列电影、古墓丽影、霍比特人等一系列经典电影背后的制作公司。

>
> 亚马逊和经典电影公司看起来毫无关联。但其实背后是亚马逊的 Prime Video 近年来持续获得增长的重要一个部分。亚马逊通过购买电影公司，来为自己的 Prime Video 输送血液，让自己影视业务变得愈加红火，并通过自己的电商等业务，让电影的业务可以扩展到电影和电视以外的领域。
>
>
>

### 迪拜发布了自己的数字货币

在过去的一年里，数字货币占尽了风头。但另一方面，也需要注意到，各个国家开始加强了对于数字货币的管控和关注。而迪拜就在最近发布了其自己的数字货币 DubaiCoin。DubaiCoin 将会很快可以用于在线下商店和线上的网站来购买商品和服务，且迪拜政府有打算使用 DubaiCoin 来替代其法币，让其政府成为世界上第一个由区块链驱动的政府。

>
> 区块链的技术应用在更多的领域是一件大好事，但能否真正落地，走出一条自己的路，还需要且看。委内瑞拉就曾想要使用自己的数字货币 Petro 来偿还债务，不知道黄金之城迪拜能否走通这条道路。
>
>
>


3 个值得使用的在 Python 3.1 中发布的特性

Summary: 探索一些未被充分利用但仍然有用的 Python 特性。

探索一些未被充分利用但仍然有用的 Python 特性。

# 3 个值得使用的在 Python 3.1 中发布的特性

>
> 探索一些未被充分利用但仍然有用的 Python 特性。
>
>
>

<img src="content_image/album_202105_27_225101wkeoeqd7bb8ckr8d.jpg" alt="" title="Python programming language logo with question marks">

这是 Python 3.x 首发特性系列文章的第二篇。Python 3.1 于 2009 年首次发布，尽管它已经发布了很长时间，但它引入的许多特性都没有被充分利用，而且相当酷。下面是其中的三个。

### 千位数格式化

在格式化大数时，通常是每三位数放置逗号，使数字更易读（例如，1,048,576 比 1048576 更容易读）。从 Python 3.1 开始，可以在使用字符串格式化函数时直接完成：

```
"2 to the 20th power is {:,d}".format(2**20)

```

```
'2 to the 20th power is 1,048,576'

```

`,d` 格式符表示数字必须用逗号格式化。

### Counter 类

`collections.Counter` 类是标准库模块 `collections` 的一部分，是 Python 中的一个秘密超级武器。它经常在 Python 的面试题的简单解答中首次遇到，但它的价值并不限于此。

例如，在 [Humpty Dumpty 的歌](http://www2.open.ac.uk/openlearn/poetryprescription/humpty-dumptys-recitation.html) 的前八行中找出五个最常见的字母：

```
hd_song = """
In winter, when the fields are white,
I sing this song for your delight.

In Spring, when woods are getting green,
I'll try and tell you what I mean.

In Summer, when the days are long,
Perhaps you'll understand the song.

In Autumn, when the leaves are brown,
Take pen and ink, and write it down.
"""

```

```
import collections

collections.Counter(hd_song.lower().replace(' ', '')).most_common(5)

```

```
[('e', 29), ('n', 27), ('i', 18), ('t', 18), ('r', 15)]

```

### 执行软件包

Python 允许使用 `-m` 标志来从命令行执行模块。甚至一些标准库模块在被执行时也会做一些有用的事情；例如，`python -m cgi` 是一个 CGI 脚本，用来调试网络服务器的 CGI 配置。

然而，直到 Python 3.1，都不可能像这样执行 *软件包*。从 Python 3.1 开始，`python -m package` 将执行软件包中的 `__main__` 模块。这是一个放调试脚本或命令的好地方，这些脚本主要是用工具执行的，不需要很短。

Python 3.0 在 11 年前就已经发布了，但是在这个版本中首次出现的一些功能是很酷的，而且没有得到充分利用。如果你还没使用，那么将它们添加到你的工具箱中。

---

via: <https://opensource.com/article/21/5/python-31-features>

作者：[Moshe Zadka](https://opensource.com/users/moshez) 选题：[lujun9972](https://github.com/lujun9972) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


用这个开源项目在 Linux 上玩复古视频游戏

Summary: ScummVM 是在现代硬件上玩老式视频游戏的最直接的方法之一。

batocera 直接模拟各种游戏机 ，不香吗？

ScummVM 是在现代硬件上玩老式视频游戏的最直接的方法之一。

# 用这个开源项目在 Linux 上玩复古视频游戏

>
> ScummVM 是在现代硬件上玩老式视频游戏的最直接的方法之一。
>
>
>

玩冒险游戏一直是我使用计算机经验的一个重要部分。从最早的基于文本的冒险游戏到 2D 像素艺术、全动态视频和 3D 游戏，冒险游戏类型为我提供了很多美好的回忆。

有时我想重温那些老游戏，但它们很多都是在 Linux 出现之前发布的，那么我如何去重玩这些游戏呢？我使用 [ScummVM](https://www.scummvm.org/)，说实话，这是我最喜欢的开源项目之一。

### 什么是 ScummVM

ScummVM 是一个设计用来在现代硬件上玩老式冒险游戏的程序。ScummVM 最初是为了运行使用<ruby> 卢卡斯艺术 <rt>  LucasArt </rt></ruby>的<ruby> 疯狂豪宅脚本创作工具 <rt>  Script Creation Utility for Maniac Mansion </rt></ruby>（SCUMM）开发的游戏，现在支持许多不同的游戏引擎。它可以支持几乎所有经典的<ruby> 雪乐山娱乐 <rt>  Sierra On-Line </rt></ruby>和卢卡斯艺术的冒险游戏，以及其他发行商的大量冒险游戏。ScummVM 并不支持所有的冒险游戏（目前），但它可以用来玩数百种冒险游戏。ScummVM 可用于多个平台，包括 Windows、macOS、Linux、Android、iOS 和一些游戏机。

### 为什么使用 ScummVM

有很多方法可以在现代硬件上玩老游戏，但它们往往比使用 ScummVM 更复杂。[DOSBox](https://www.dosbox.com/) 可以用来玩 DOS 游戏，但它需要调整设置，使其以正确的速度进行游戏。Windows 游戏可以用 [WINE](https://www.winehq.org/) 来玩，但这需要游戏及其安装程序都与 WINE 兼容。

即使游戏可以在 WINE 下运行，一些游戏仍然不能在现代硬件上很好地运行，因为硬件的速度太快了。这方面的一个例子是《<ruby> 国王密使 6 <rt>  King's Quest VI </rt></ruby>》中的一个谜题，它涉及将点燃的鞭炮带到某个地方。在现代硬件上，鞭炮爆炸的速度太快了，这使得在角色不死很多次的情况下不可能到达正确的位置。

ScummVM 消除了其他玩复古冒险游戏的方法中存在的许多问题。如果是 ScummVM 支持的游戏，那么它的配置和玩都很简单。在大多数情况下，将游戏文件从原始游戏光盘复制到一个目录，并在 ScummVM 中添加该目录，就可以玩该游戏了。对于多张光盘上的游戏，可能需要重命名一些文件以避免文件名冲突。需要哪些数据文件的说明以及任何重命名的说明都记录在 [每个支持的游戏](https://wiki.scummvm.org/index.php?title=Category:Supported_Games) 的 ScummVM 维基页面上。

ScummVM 的一个奇妙之处在于，每一个新版本都会增加对更多游戏的支持。ScummVM 2.2.0 增加了对十几种互动小说解释器的支持，这意味着 ScummVM 现在可以玩数百种基于文本的冒险游戏。ScummVM 的开发分支应该很快就会变成 2.3.0 版本，它整合了 [ResidualVM](https://www.residualvm.org/) 对 3D 冒险游戏的支持，所以现在 ScummVM 可以用来玩《<ruby> 冥界狂想曲 <rt>  Grim Fandango </rt></ruby>》、《神秘岛 3：放逐者Myst III: Exile》和《<ruby> 最长的旅程 <rt>  The Longest Journey </rt></ruby>》。其开发分支最近还增加了对使用 [Adventure Game Studio](https://www.adventuregamestudio.co.uk/) 创建的游戏的支持，这为 ScummVM 增加了成百上千的游戏。

### 如何安装 ScummVM

如果你想从你的 Linux 发行版的仓库中安装 ScummVM，过程非常简单。你只需要运行一个命令。然而，你的发行版可能会提供一个旧版本的 ScummVM，它不像最新版本那样支持许多游戏，所以要记住这一点。

在 Debian/Ubuntu 上安装 ScummVM：

```
sudo apt install scummvm

```

在 Fedora 上安装 ScummVM：

```
sudo dnf install scummvm

```

#### 使用 Flatpak 或 Snap 安装 ScummVM

ScummVM 也可以以 Flatpak 和 Snap 的形式提供。如果你使用这些方式之一，你可以使用以下命令来安装相关的版本，它应该总是 ScummVM 的最新版本。

```
flatpak install flathub org.scummvm.ScummVM

```

或

```
snap install scummvm

```

#### 编译 ScummVM 的开发分支

如果你想尝试 ScummVM 尚未稳定的开发分支中的最新和主要的功能，你可以通过编译 ScummVM 的源代码来实现。请注意，开发分支是不断变化的，所以事情可能不总是正确的。如果你仍有兴趣尝试开发分支，请按照下面的说明进行。

首先，你需要为你的发行版准备必要的开发工具和库，这些工具和库在 ScummVM 维基上的 [编译 ScummVM/GCC](https://wiki.scummvm.org/index.php/Compiling_ScummVM/GCC) 页面列出。

一旦你安装了先决条件，运行以下命令：

```
git clone <https://github.com/scummvm/scummvm.git>
cd scummvm
./configure
make
sudo make install

```

### 向 ScummVM 添加游戏

将游戏添加到 ScummVM 是你在游戏前需要做的最后一件事。如果你的收藏集中没有任何支持的冒险游戏，你可以从 [ScummVM 游戏](https://www.scummvm.org/games/) 页面下载 11 个精彩的游戏。你还可以从 [GOG.com](https://www.gog.com/) 购买许多 ScummVM 支持的游戏。如果你从 [GOG.com](http://GOG.com) 购买了游戏，并需要从 GOG 下载中提取游戏文件，你可以使用 [innoextract](https://constexpr.org/innoextract/) 工具。

大多数游戏需要放在自己的目录中（唯一的例外是由单个数据文件组成的游戏），所以最好先创建一个目录来存储你的 ScummVM 游戏。你可以使用命令行或图形化文件管理器来完成这个工作。在哪里存储游戏并不重要（除了 ScummVM Flatpak，它是一个沙盒，要求游戏存储在 `~/Documents` 目录中）。创建这个目录后，将每个游戏的数据文件放在各自的子目录中。

一旦文件被复制到你想要的地方，运行 ScummVM，并通过点击“Add Game…”将游戏添加到收藏集中，在打开的文件选择器对话框中选择适当的目录，并点击“Choose”。如果 ScummVM 正确检测到游戏，它将打开其设置选项。如果你想的话，你可以从各个标签中选择高级配置选项（也可以在以后通过使用“Edit Game…”按钮进行更改），或者你可以直接点击“OK”，以默认选项添加游戏。如果没有检测到游戏，请查看 ScummVM 维基上的 [支持的游戏](https://wiki.scummvm.org/index.php/Category:Supported_Games) 页面，以了解特定游戏的数据文件可能需要的特殊说明的细节。

现在唯一要做的就是在 ScummVM 的游戏列表中选择游戏，点击“Start”，享受重温旧爱或首次体验经典冒险游戏的乐趣。

---

via: <https://opensource.com/article/21/4/scummvm-retro-gaming>

作者：[Joshua Allen Holm](https://opensource.com/users/holmja) 选题：[lujun9972](https://github.com/lujun9972) 译者：[wxy](https://github.com/wxy) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


硬核观察 | 微软发布其官方的包管理器 winget 1.0

Summary: 更多：• 长期工作每年导致数十万人死亡 • HaveIBeenPwned 服务开源

长期不工作，导致数千万人饿死。

最烦这种瞎鸡抬杠的人，显得自己真的是个大聪明是吧

来自湖北武汉武汉大学测绘学院的 Chrome 90.0|Windows 10 用户

# 硬核观察 | 微软发布其官方的包管理器 winget 1.0

### 微软发布其官方的包管理器 WinGet 1.0

微软在昨天（2021年5月27日）发布了 [WinGet Cli](https://github.com/microsoft/winget-cli/releases/tag/v1.0.11451) 的 1.0 版本，该版本可以实现在 Windows 命令行中安装、更新、卸载软件等操作。

>
> 微软为 Windows 配置包管理器是一个很「Linux」的事情，Windows 的软件安装方式太过多元化不一定适合每一个场景。而 winget 这种官方的工具，想来要比 Chocolatey 之类的第三方工具获得更好的发展。
>
>
>

### 长期工作每年导致数十万人死亡

世界卫生组织和世界劳工组织的一项新研究表明，长时间工作每年导致数十万人死亡。2016年，每周工作超过55小时的带薪工作导致74.5万人死亡，高于2000年的59万人。2016年，约39.8万人死于中风，34.7万人死于心脏病。作者认为，生理应激反应和行为改变（如不健康饮食、睡眠不良和体力活动减少）都是长时间工作对健康产生负面影响的“可想而知”原因。每周工作超过55小时是危险的。与每周工作35-40小时相比，它与中风风险和心脏病风险分别高出35%和17%相关。

>
> 对于我们每一个人来说，奋斗是必要的，但身体是最重要的，切不可丢了西瓜，捡了芝麻。
>
>
>

### HaveIBeenPwned 服务开源

[HaveIBeenPwned](https://github.com/HaveIBeenPwned ) 是一个可以帮助你查询你的邮箱、手机号及相关密码是否泄漏的服务。其创始人 Troy Hunt 将 HaveIBeenPwned 源代码开放在 Github 上。

>
> 近年来的数据安全泄漏事故频发。HaveIBeenPwned的出现可以让我们检测自己是否有密码泄漏；除了 Have I Been Pwned ，你还可以试试 Mozila 推出的 Firefox Monitor。
>
>
>


3 个到今天仍然有用的 Python 3.2 特性

Summary: 探索一些未被充分利用但仍然有用的 Python 特性。

探索一些未被充分利用但仍然有用的 Python 特性。

# 3 个到今天仍然有用的 Python 3.2 特性

>
> 探索一些未被充分利用但仍然有用的 Python 特性。
>
>
>

<img src="content_image/album_202105_28_202023pz86mg88r18o6e22.jpg" alt="" title="Woman using laptop concentrating">

这是 Python 3.x 首发特性系列文章中的第三篇。其中一些 Python 版本已经推出了一段时间。例如，Python 3.2 是在 2011 年首次发布的，但其中引入的一些很酷、很有用的特性仍然没有被使用。下面是其中的三个。

### argparse 子命令

`argparse` 模块首次出现在 Python 3.2 中。有许多用于命令行解析的第三方模块。但是内置的 `argparse` 模块比许多人认为的要强大。

要记录所有的 `argparse` 的特性，那需要专门写系列文章。下面是一个例子，说明如何用 `argparse` 做子命令。

想象一下，一个命令有两个子命令：`negate`，需要一个参数，`multiply`，需要两个参数：

```
$ computebot negate 5
-5
$ computebot multiply 2 3
6

```

```
import argparse

parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()

```

`add_subparsers()` 方法创建一个对象，你可以向其添加子命令。唯一需要记住的技巧是，你需要添加通过 `set_defaults()` 调用的子命令：

```
negate  = subparsers.add_parser("negate")
negate.set_defaults(subcommand="negate")
negate.add_argument("number", type=float)

```

```
multiply  = subparsers.add_parser("multiply")
multiply.set_defaults(subcommand="multiply")
multiply.add_argument("number1", type=float)
multiply.add_argument("number2", type=float)

```

我最喜欢的一个 `argparse` 功能是，因为它把解析和运行分开，测试解析逻辑特别令人愉快。

```
parser.parse_args(["negate", "5"])

```

```
    Namespace(number=5.0, subcommand='negate')

```

```
parser.parse_args(["multiply", "2", "3"])

```

```
    Namespace(number1=2.0, number2=3.0, subcommand='multiply')

```

### contextlib.contextmanager

上下文是 Python 中一个强大的工具。虽然很多人 *使用* 它们，但编写一个新的上下文常常看起来像一门黑暗艺术。有了 `contextmanager` 装饰器，你所需要的只是一个一次性的生成器。

编写一个打印出做某事所需时间的上下文，就像这样简单：

```
import contextlib, timeit

@contextlib.contextmanager
def timer():
    before = timeit.default_timer()
    try:
        yield
    finally:
        after = timeit.default_timer()
        print("took", after - before)

```

你可以这样使用：

```
import time

with timer():
    time.sleep(10.5)

```

```
    took 10.511025413870811`

```

### functools.lru\_cache

有时，在内存中缓存一个函数的结果是有意义的。例如，想象一下经典的问题：“有多少种方法可以用 25 美分、1 美分、2 美分和 3 美分可以来换取 1 美元？”

这个问题的代码可以说是非常简单：

```
def change_for_a_dollar():
    def change_for(amount, coins):
        if amount == 0:
            return 1
        if amount < 0 or len(coins) == 0:
            return 0
        some_coin = next(iter(coins))
        return (
            change_for(amount, coins - set([some_coin]))
            +
            change_for(amount - some_coin, coins)
        )
    return change_for(100, frozenset([25, 10, 5, 1]))

```

在我的电脑上，这需要 13ms 左右：

```
with timer():
    change_for_a_dollar()

```

```
    took 0.013737603090703487`

```

事实证明，当你计算有多少种方法可以做一些事情，比如用 50 美分找钱，你会重复使用相同的硬币。你可以使用 `lru_cache` 来避免重复计算。

```
import functools

def change_for_a_dollar():
    @functools.lru_cache
    def change_for(amount, coins):
        if amount == 0:
            return 1
        if amount < 0 or len(coins) == 0:
            return 0
        some_coin = next(iter(coins))
        return (
            change_for(amount, coins - set([some_coin]))
            +
            change_for(amount - some_coin, coins)
        )
    return change_for(100, frozenset([25, 10, 5, 1]))

```

```
with timer():
    change_for_a_dollar()

```

```
    took 0.004180959425866604`

```

一行的代价是三倍的改进。不错。

### 欢迎来到 2011 年

尽管 Python 3.2 是在 10 年前发布的，但它的许多特性仍然很酷，而且没有得到充分利用。如果你还没使用，那么将他们添加到你的工具箱中。

---

via: <https://opensource.com/article/21/5/python-32>

作者：[Moshe Zadka](https://opensource.com/users/moshez) 选题：[lujun9972](https://github.com/lujun9972) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


将操作系统移植到新的芯片架构的经验

2至少使用一个串行驱动器，里面说“通过串口 接收 数据是不必要的”

# 将操作系统移植到新的芯片架构的经验

>
> 在将嵌入式系统操作系统移植到不同的芯片架构时，RT-Thread 的维护者们从中学到了什么。
>
>
>

曾经有人问我，为什么计算机被称为“计算机”，它们做的事情可远不止计算数字。一台现代的个人电脑可以浏览互联网、播放音频和视频、为视频游戏和电影生成漂亮的图形、模拟和预测复杂的天气模式和流行病风险、将建筑和工程蓝图变为现实等等。

计算机之所以能做到这些，是因为所有这些问题都可以归结为数字方程，而计算机的 CPU —— 其中央处理单元 —— 实际上不过是一个简单的计算器。

为了让 CPU 向硬盘驱动器发送信号以写入数据，或向显示器发送信号以显示图像，它必须接收指令。这些指令是以 “代码” 的形式出现的，这是一种简明的说法，即必须有人写一个 *程序* ，与CPU “说” 同样的语言。CPU 理解的是 *机器语言*，这是一个大多数人都无法理解的比特阵列，大多数人都不可能手动写出来。相反，我们使用像 C、C++、Java、Python 等编程语言。这些语言被解析并编译成机器语言，然后交付给 CPU。

如果你试图用一种它不理解的语言来指示 CPU，它不知道该怎么做。你可以通过尝试用 [x86\_64 RHEL](https://www.redhat.com/en/store/red-hat-enterprise-linux-developer-suite) 镜像启动 [树莓派](https://opensource.com/resources/raspberry-pi) 来体验这种误传尝试的尴尬结果。如果它能工作就好了，但是不能。

### 将一个操作系统移植到一个新的架构上

[RT-Thread 项目](https://opensource.com/article/20/6/open-source-rtos) 为嵌入式系统程序员提供了一个开源的操作系统（OS）。嵌入式领域是非常多样化的，有很多物联网（IoT）、定制工业和业余设备。RT-Thread 的目标是使嵌入式编程对每个人来说都很容易，无论你使用什么设备。有时，这意味着要将一个操作系统移植到一个新的架构上，不管是用于相同架构但指令集略有不同的的芯片，还是用于全新的架构。

一开始处理这个问题可能会有点吓人 —— 你可能不知道从哪里开始或如何开始。这篇文章收集了 RT-Thread 维护者在将 [RTOS](https://www.rt-thread.io/) 移植到新的芯片架构时学到的经验。

### 你在开始之前需要知道什么

这里是一个看似难以逾越的过程的高屋建瓴的观点。这对你的项目来说可能有所不同，但从概念上来说，这是相对普遍的，即使一些具体的细节是不同的：

1. 准备好一个 C 语言的执行环境
2. 确认可以通过串行端口发送和接收字符
3. 确认上下文切换代码可以工作
4. 获取支持的硬件定时器
5. 确认中断程序可以通过串口接收和解析数据

### 执行模式

对于大多数先进的体系结构，操作系统和用户应用程序运行在不同的权限级别上。这可以防止有功能故障的代码影响操作系统的集成和安全。例如，在 ARMv7-A 架构中，操作系统通常在系统模式下运行，而在 ARMv8-A 中，操作系统可以在 EL2 或 EL3 权限级别上运行。

通常情况下，芯片在通电时以最高权限级别执行启动代码。但在此之后，操作系统会将特权级别切换到其目标模式。

#### 1、执行 C 代码

这一步的关键动作是将 <ruby>   块起始符号  <rt>  block starting symbol </rt></ruby>（.bss）部分设置为零，并设置堆栈指针。

在 C 语言的实现中，未初始化的全局变量和静态变量通常存储在 .bss 部分，它不占用存储设备的任何空间。当程序被加载时，相应的空间被分配到内存中，并被初始化为零。当操作系统启动时，它必须自己做这项工作。

另一方面，操作系统必须初始化堆栈空间并设置堆栈指针。由于 C 语言程序在进入和退出函数时在堆栈上保存和恢复局部变量，所以在调用任何 C 函数之前必须设置堆栈指针。RT-Thread 必须为每个新创建的线程做这个步骤。

#### 2、至少使用一个串行驱动器

RT-Thread 通过串口输出信息和日志，这也有助于在移植过程中对代码进行调试。在这个阶段，通过串口 *接收* 数据是不必要的。当我们第一次在串口上看到我们友好的、熟悉的 RT-Thread 的标志时，我们就知道我们走对了路！

#### 3、确认上下文切换逻辑

一个任务的上下文是它的整个执行环境，它包含通用寄存器、程序计数器、堆栈帧的位置等等。当一个新的线程被创建时，RT-Thread 必须手动分配和设置它的上下文，这样调度器就可以切换到新的线程，就像它对其他线程一样。

有三件事需要注意：

* 首先，当 RT-Thread 启动时，默认情况下中断是禁用的。当任务调度器第一次被启用时，它们就会被启用；这个过程是在上下文切换期间用汇编语言实现的。
* 第二，当一个线程退出时，下一个调度将开始，这时拥有的资源会被空闲的线程回收。
* 第三，数据被推入堆栈的顺序必须与从堆栈中弹出数据的顺序一致。

一般来说，你希望正常进入主函数和 msh 控制台。然而，在这个阶段无法实现输入控制，因为串行输入中断还没有实现。当串行中断实现后，就可以进行 msh 输入了。

#### 4、设置定时器

RT-Thread 需要一个定时器来定期产生中断；它被用来计算自系统启动以来所经过的“滴答”。计数器的编号用于提供软件中断功能，并指示内核何时开始调度一个任务。

设置时间片的值可能是一件棘手的事情。它通常是 10ms 到 1ms。如果你在一个慢速的 CPU 上选择一个小的时间片，大部分时间就会花在任务切换上 —— 不利于完成其他事情。

#### 5、确认串口工作正常

在这一步，我们通过串口与 RT-Thread msh 进行交互。我们发送命令，按回车键，然后看着 msh 执行命令并显示结果。

这个过程通常不难实现。不过，有一点要提醒大家。在某些平台上，在处理完串口中断后，别忘了清除中断标志。

一旦串口工作正常，移植过程基本上就完成了。

### 实践

为了将你的项目移植到不同的芯片架构上，你需要非常清楚地了解你所针对的芯片的架构。熟悉你的项目中最关键的部分的底层代码。通过对照芯片的手册结合大量的实际工作经验，你会了解芯片的特权模式、寄存器和编译方法。

如果你没有需要移植到新芯片的项目，请加入我们；RT-Thread 项目总是需要帮助将 RTOS 移植到新的芯片上！作为一个开源项目，RT-Thread 正在改变开源嵌入式编程的面貌。请在 [RT-Thread 俱乐部](https://club.rt-thread.io/)介绍你自己并寻求帮助!

---

本文基于 DEV 社区上的 [如何将操作系统移植到不同的芯片架构上？](https://dev.to/abby06/how-to-port-operating-system-to-different-chip-architecture-3od9)，并经许可转载。

---

via: <https://opensource.com/article/21/5/port-chip-architectures>

作者：[Alan Smithee](https://opensource.com/users/alansmithee) 选题：[lujun9972](https://github.com/lujun9972) 译者：[wxy](https://github.com/wxy) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


Summary: 更多：• Ubuntu 用户被 DMCA 组织滥发 DMCA 通知 • FaceBook 赞助的研究抨击苹果的隐私问题

# 硬核观察 | 阿里云发布第七代云服务器，并全面兼容 X86、ARM、RISC-V 等多种芯片架构

### 阿里云发布第七代云服务器，并全面兼容 X86、ARM、RISC-V等多种芯片架构

今天阿里云在北京召开 2021 阿里云峰会，一句发布多款新品，包括第七云服务器、一站式数据服务平台、湖仓一体 2.0 等；

阿里云智能总裁张建锋表示，阿里云自研的云计算操作系统飞天已经全面兼容 X86、ARM 、RISC-V 芯片架构。

>
> 阿里云作为国内的云计算的先行者， 领头羊，他们的一举一动都会带来行业的跟随，下一步就可以期待各家都对 ARM、RISC-V 等芯片架构的支撑，真正推动 ARM 架构落地服务器领域。
>
>
>

### Ubuntu 用户被 DMCA 组织滥发 DMCA 通知

美国电信公司 Comcast 的一个用户在 Reddit 上透露，他通过 BT 下载了 Ubuntu 官方的 ISO 镜像后收到了 DMCA 侵权通知。

>
> DMCA 全称是千禧年数字版权法，用于保护软件创作者作者的原始权利。但法律无罪，人有罪， 当人将法律用在一些坏的途径上时，这法律就成了恶法。
>
>
>

### FaceBook 赞助的研究抨击苹果的隐私问题

苹果在 iOS 14.5 后为每一个 App 加入了强制的信息追踪弹窗，以允许用户禁止 App 的针对性追踪。而最近，佛罗里达大学莱文学院的丹尼尔 · 索科尔与哈佛大学商学院的朱锋撰写的论文《[Harming Competition and Consumers under the Guise of Protecting Privacy: An Analysis of Apple’s iOS 14 Policy Updates](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3852744)》抨击了这一功能。

>
> 学术沦为资本的工具，可叹可笑。
>
>
>


阿里云以 Apache 2.0 许可证开源 PolarDB 分布式数据库

Summary: 阿里云数据库负责人李飞飞表示：“我们希望将阿里云在数据库技术上积累的丰富经验，通过标准技术组件和系统的方式开放出来，共建开源数据库生态。”

# 阿里云以 Apache 2.0 许可证开源 PolarDB 分布式数据库

5 月 29 日，阿里云开发者大会上，阿里云宣布开源云原生数据库能力，开源关系型数据库 PolarDB for PostgreSQL，将阿里内部沉淀多年的技术分享出来，服务于百万开发者。目前，该项目已在阿里云官网及 [Github](https://github.com/alibaba/PolarDB-for-PostgreSQL) 上发布，后续将引入分布式事务、单机高性能等能力。

阿里云数据库负责人李飞飞表示：

>
> “我们希望将阿里云在数据库技术上积累的丰富经验，通过标准技术组件和系统的方式开放出来，共建开源数据库生态。”
>
>
>

数据库是基础软件中的刚需，与芯片、操作系统并列为“全球技术三大件”。开源模式广受数据库用户欢迎，被认为是互联网场景的标配。

PolarDB 是阿里云自研的数据库产品家族，采用存储计算分离、软硬一体化设计，既拥有分布式设计的低成本优势，又具有集中式的易用性，可满足大规模应用场景需求。计算能力最高可扩展至 1000 核以上，存储容量最高可达 100TB，集群版单库最多可扩展到 16 个节点，性能比 MySQL 高 6 倍。PolarDB 系列产品已连续多年稳定支撑天猫双 11，处理峰值高达创纪录的 1.4亿次/秒。

为满足用户多样化的需求，PolarDB 针对不同的数据库协议开发了不同的兼容版本，包括兼容 MySQL、PostgreSQL 和 Oracle 的版本，及每个版本的分布式形态。

此次阿里云开源的是 PolarDB for PostgreSQL 分布式版，包括数据库内核、相关插件、工具脚本、测试用例以及设计文档，适用于中大型企业核心业务场景。本次开源遵循 Apache 2.0 许可证，以全共享并尊重原作者著作权的模式开源，代码可以修改和再发布。

这让我想起来前一段时间 MariaDB 宣布了将它的分布式 SQL 引擎 Xpand 作为其 DBaaS 服务的 SkySQL 系统引擎之一，然而 Xpand 是一个专有的软件。这引起了业界对开源服务之上的专有服务的隐忧，因为这失去了开源的重要优势 —— 避免供应商锁定。

在业界，开源数据库众多，但是能将分布式能力也开源出来的罕有，而能形成产品级的、可以利用现有数据库基础设施的开源产品更是不多。因此，PolarDB for PostgreSQL 的这次开源可谓是不但给 PostgreSQL 注入了一剂强心针，而且也与 Xpand 这种开源引擎之上的专有服务形成了鲜明对比。

在对李飞飞的采访中，他谈到了为什么要开源 PolarDB：

>
> “我们开源的目的是非常纯粹的，我们在开源这一部分没有任何商业化的目的，就是要把开发者的生态做起来。”
>
>
>

而且，他认为没有必要重新建立一个新的生态，在原本非常繁荣的 PostgreSQL 生态上“助力一把火，让它烧得更旺。我们希望让开发者可以在现有的 PostgreSQL 上做的更好。本质上就是把我们在 PostgreSQL 上积累多年的能力开源出来，回馈给社区，而且以插件的方式。”

而且，为了鼓励社区能参与进来，阿里云也体现了极大的诚意，采用了更加宽松、自由的开源许可证 Apache 2.0，“你可以再开发，你可以商用，都没有问题，我们完全鼓励。”

为什么这样做呢，李飞飞谈到：“通过这样把开发者生态建立起来以后，我们从中获得了什么？我们获得的是开发者对 PostgreSQL 整个大生态的持续的关注和投入，然后最终我们也会从中受益，因为我们会从开发者贡献的代码里面去汲取对我们有用的部分，我相信其他的厂商不管是云厂商数据库厂商可能也会因此受益。但没关系，我们认为水涨船高，只要整个的社区做起来，我们阿里云还一定会是领导者，我们有自信，所以我们愿意去做这件事。”

李飞飞认为：

>
> “我个人认为开源是建立生态的非常关键的一个抓手，非常关键的抓手。它和商业化一定要非常好的平衡，但绝对不是说天然的就是矛盾的两面，矛盾的地方绝对有，不然的话大家不会这么纠结，但是我个人认为要处理好平衡，是需要有非常强的定力和判断力，但你一旦处理好，它并不一定就一定会发展成矛盾体，这是我个人的一个观点。”
>
>
>

我想，这应该就是阿里云坚定开源战略的主要原因之一。

但是同时他也表示，不要走到另外一个极端：

>
> “大家千万不要落到另外一个陷阱里面去，认为‘开源就是灵丹灵丹妙药，开源就能解决问题了’。我个人也是非常反对这个观点，关键还是看你后续社区的运营，是不是真的用心在做这个社区，是不是真的有高质量的贡献出来，让大家真正的从里面能够受益。我觉得这个是后面的挑战。”
>
>
>

根据披露的 PolarDB for PostgreSQL 开源路线图，阿里云是有计划、有步骤的将主要的、完备的部分向社区开放。我想，这将揭幕云原生数据库的新时代。