This commit is contained in:
ywxgod 2021-05-24 02:13:26 +08:00
commit 4e6cec9e47
19 changed files with 1419 additions and 1198 deletions

View File

@ -0,0 +1,481 @@
[#]: collector: (lujun9972)
[#]: translator: (mengxinayan)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-13413-1.html)
[#]: subject: (A guide to understanding Linux software libraries in C)
[#]: via: (https://opensource.com/article/21/2/linux-software-libraries)
[#]: author: (Marty Kalin https://opensource.com/users/mkalindepauledu)
用 C 语言理解 Linux 软件库
======
> 软件库是重复使用代码的一种简单而合理的方式。
![](https://img.linux.net.cn/data/attachment/album/202105/22/165307u0n970uivji7kiim.jpg)
软件库是一种是一直以来长期存在的、简单合理的复用代码的方式。这篇文章解释了如何从头开始构建库并使得其可用。尽管这两个示例库都以 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>[克里斯蒂安·哥德巴赫][2]<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 语言程序中必须被精确定义一次的规则。
### 库的源代码
下面是两个库的源代码。这部分代码、头文件、以及两个示例客户程序都可以在 [我的网页][3] 上找到。
```
#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 &gt; 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 InterfaceJNI一个替代品后Java 语言和 C 语言交互也会变的很容易。
--------------------------------------------------------------------------------
via: https://opensource.com/article/21/2/linux-software-libraries
作者:[Marty Kalin][a]
选题:[lujun9972][b]
译者:[萌新阿岩](https://github.com/mengxinayan)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/mkalindepauledu
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/rh_003499_01_linux31x_cc.png?itok=Pvim4U-B (5 pengiuns floating on iceburg)
[2]: https://en.wikipedia.org/wiki/Christian_Goldbach
[3]: https://condor.depaul.edu/mkalin
[4]: http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
[5]: http://www.opengroup.org/onlinepubs/009695399/functions/sqrt.html
[6]: https://openjdk.java.net/projects/panama

View File

@ -0,0 +1,184 @@
[#]: subject: "How to use the Linux sed command"
[#]: via: "https://opensource.com/article/21/3/sed-cheat-sheet"
[#]: author: "Seth Kenlon https://opensource.com/users/seth"
[#]: collector: "lujun9972"
[#]: translator: "MjSeven"
[#]: reviewer: "wxy"
[#]: publisher: "wxy"
[#]: url: "https://linux.cn/article-13417-1.html"
使用 sed 命令进行复制、剪切和粘贴
======
> 了解 sed 的基本用法,然后下载我们的备忘单,方便快速地参考 Linux 流编辑器。
![](https://img.linux.net.cn/data/attachment/album/202105/23/181625abgrg4dsbw4y4fue.jpg)
很少有 Unix 命令像 `sed`、[grep][2] 和 [awk][3] 一样出名,它们经常组合在一起,可能是因为它们具有奇怪的名称和强大的文本解析能力。它们还在一些语法和逻辑上有相似之处。虽然它们都能用于文本解析,但都有其特殊性。本文研究 `sed` 命令,它是一个 <ruby>流编辑器<rt>stream editor</rt></ruby>
我之前写过关于 [sed][4] 以及它的远亲 [ed][5] 的文章。要熟悉 `sed`,对 `ed` 有一点了解是有帮助的,因为这有助于你熟悉缓冲区的概念。本文假定你熟悉 `sed` 的基本知识,这意味着你至少已经运行过经典的 `s/foo/bar` 风格的查找和替换命令。
- 下载我们的免费 [sed 备忘录][6]
### 安装 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 网站 [下载源代码][7]。 安装 GNU sed 的好处是,你可以使用它的额外功能,但是如果需要可移植性,还可以限制它以遵守 sed 的 [POSIX][8] 规范。
MacOS 用户可以在 [MacPorts][9] 或 [Homebrew][10] 上找到 GNU sed。
在 Windows 上,你可以通过 [Chocolatey][12] 来 [安装 GNU sed][11]。
### 了解模式空间和保留空间
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 备忘单][6],然后开始一劳永逸地学习 sed
--------------------------------------------------------------------------------
via: https://opensource.com/article/21/3/sed-cheat-sheet
作者:[Seth Kenlon][a]
选题:[lujun9972][b]
译者:[MjSeven](https://github.com/MjSeven)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/seth
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/linux_penguin_green.png?itok=ENdVzW22 "Penguin with green background"
[2]: https://opensource.com/article/21/3/grep-cheat-sheet
[3]: https://opensource.com/article/20/9/awk-ebook
[4]: https://opensource.com/article/20/12/sed
[5]: https://opensource.com/article/20/12/gnu-ed
[6]: https://opensource.com/downloads/sed-cheat-sheet
[7]: http://www.gnu.org/software/sed/
[8]: https://opensource.com/article/19/7/what-posix-richard-stallman-explains
[9]: https://opensource.com/article/20/11/macports
[10]: https://opensource.com/article/20/6/homebrew-mac
[11]: https://chocolatey.org/packages/sed
[12]: https://opensource.com/article/20/3/chocolatey

View File

@ -0,0 +1,80 @@
[#]: subject: (1Password for Linux Is Officially Here With Brand New Features)
[#]: via: (https://news.itsfoss.com/1password-linux-released/)
[#]: author: (Ankush Das https://news.itsfoss.com/author/ankush/)
[#]: collector: (lujun9972)
[#]: translator: (wxy)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-13416-1.html)
全新 1Password for Linux 正式推出
======
![](https://i0.wp.com/news.itsfoss.com/wp-content/uploads/2021/05/1password-linux-feat.png?w=1200&ssl=1)
1Password 是一个相当不错的密码管理器(尽管不是开源的),在开源社区也有很好的口碑。他们甚至 [为从事开源项目的用户提供免费的团队成员资格][1]。
它的 Linux 桌面客户端已经处于测试阶段,但现在它已经准备好进入黄金时间。
他们已经正式 [宣布][2] 推出 1Password Linux 版,具有完整的桌面体验,可以与你的网络浏览器集成。
它还亮相了一些很快会进入 Android、iOS、Mac 和 Windows **的新功能**
在这里我要安利一下Linux 上的 1Password 值得期待。
### 1Password Linux 桌面客户端
虽然它可以作为浏览器扩展而无需考虑平台,但桌面客户端的出现使体验更好。
![](https://i2.wp.com/news.itsfoss.com/wp-content/uploads/2021/05/1pass-account-dark.png?w=1280&ssl=1)
桌面客户端内置了基于 GTK 主题的**黑暗模式支持**。它还能与 **GNOME、KDE 和你选择的任何其他窗口管理器**很好地整合。
看起来他们也在更多的细节上花费了心思,因此桌面客户端也支持**系统托盘图标**,即使你关闭了它也能保持活跃。
你可以用它直接在你的默认浏览器上自动填入密码。不过,虽然它提到了 **X11 剪贴板集成和支持**,但没有提到 Wayland。
![](https://i2.wp.com/news.itsfoss.com/wp-content/uploads/2021/05/1pass-screenshot.png?w=1280&ssl=1)
它还包括了对 GNOME 钥匙环和 KDE 钱包的支持、内核钥匙环的集成、与系统锁定和闲置服务的集成。
除了这些1Password for Linux 还首次推出了新的功能,这些功能将很快用于其他平台。
* 安全文件附件
* 项目归档和删除功能,以便更好地组织文件
* Watchtower 仪表板,检查和评估你的密码安全状况
* 新的共享细节,查看谁可以访问什么
* 快速查找和智能搜索建议
* 翻新的外观和感觉
如果你想了解该版本以及他们对开源和 Linux 社区的计划,请浏览 [官方公告][2]。
### 在 Linux 中安装 1Password
其官方称,该桌面客户端支持几个 Linux 发行版,包括 Ubuntu、 Debian、 Arch Linux、 Fedora、 CentOS 和 RHEL。你可以得到用来安装的 **.deb** 和 **.rpm** 软件包,或者使用软件包管理器找到它们。
- [下载 1Password for Linux][4]
它也有一个可用的 [snap 包][5],你可以参考我们的 [在 Linux 中使用 snap][6] 的指南。
关于安装的更多信息,你也可以参考 [官方说明][7]。
--------------------------------------------------------------------------------
via: https://news.itsfoss.com/1password-linux-released/
作者:[Ankush Das][a]
选题:[lujun9972][b]
译者:[wxy](https://github.com/wxy)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://news.itsfoss.com/author/ankush/
[b]: https://github.com/lujun9972
[1]: https://news.itsfoss.com/1password-free-subscriptions/
[2]: https://blog.1password.com/welcoming-linux-to-the-1password-family/
[4]: https://1password.com/downloads/linux/
[5]: https://snapcraft.io/1password
[6]: https://itsfoss.com/use-snap-packages-ubuntu-16-04/
[7]: https://support.1password.com/install-linux/

View File

@ -0,0 +1,136 @@
[#]: subject: (Remap your Caps Lock key on Linux)
[#]: via: (https://opensource.com/article/21/5/remap-caps-lock-key-linux)
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
[#]: collector: (lujun9972)
[#]: translator: (wxy)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-13414-1.html)
在 Linux 上重新映射你的大写锁定键
======
> 通过在 GNOME 3 和 Wayland 上重新映射你的键盘,提高你的打字和导航速度,避免重复性压力伤害。
![](https://img.linux.net.cn/data/attachment/album/202105/22/174755hs0dbmm4idl5rbrr.jpg)
对我来说,有许多改变生活的 Linux 时刻,但大多数都在成为现状后淡忘了。有一个 Linux 教给我的键盘小技巧,每次我使用它的时候(也许每天有 1000 次),我都会想起这件事,那就是把大写锁定键转换为 `Ctrl` 键。
我从不使用大写锁定键,但我整天使用 `Ctrl` 键进行复制、粘贴、在 [Emacs][2] 内导航,以及 [调用 Bash][3]、[GNU Screen][4] 或 [tmux][5] 等操作。大写锁定键在我的键盘上占据了宝贵的空间,而将实际上有用的 `Ctrl` 键挤到了难以触及的底部角落。
![手指放在键盘上][6]
*这看起来就痛苦*
重新映射 `Ctrl` 提高了我的打字和导航速度,并可能使我免受重复性压力伤害。
### 消失的控制
系好安全带,这是个过山车式的历史课。
对于像我这样的大写锁定键交换者来说,不幸的是,当 GNOME 3 问世时,它几乎删除了改变 `Ctrl` 键位置的功能。
幸运的是,优秀的 GNOME Tweaks 应用程序带回了这些 “失踪” 的控制面板。
不幸的是,[GNOME 40][8] 没有 GNOME Tweaks 应用程序(还没有?)
另外,不幸的是,过去在 X11 上可以工作的老的 `xmodmap` 技巧在新的 [Wayland 显示服务器][9] 上没有用。
有一小段时间(最多一个下午),我觉得对于那些讨厌大写锁定键的人来说人生都灰暗了。然后我想起我是一个开源的用户,总有一种方法可以解决诸如被忽略的 GUI 控制面板之类的简单问题。
### dconf
GNOME 桌面使用 dconf这是一个存储重要配置选项的数据库。它是 GSettings 的后端GSettings 是 GNOME 系统应用程序需要发现系统偏好时的接口。你可以使用 `gsetting` 命令查询 dconf 数据库,也可以使用 `dconf` 命令直接设置 dconf 的键值。
### GSettings
dconf 数据库不一定是你可能称为可发现的数据库。它是一个不起眼的数据库,你通常不需要去考虑它,它包含了许多通常无需直接交互的数据。然而,如果你想更好地了解 GNOME 所要管理的所有偏好选项,那么浏览它是很有趣的。
你可以用 `list-schemas` 子命令列出所有 dconf 的模式。在浏览了数百个模式之后,你可以使用 [grep][10] 将你的注意力缩小到一些看起来特别相关的东西上,比如 `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 文档][11],你可能会注意到 `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][12] 键(`compose:ralt`)。虽然我相信正在开发中的 GUI 控件可以控制这些选项,但我也不得不承认,能以编程方式设置这些选项的能力是我的荣幸。作为以前没有可靠方法来调整桌面设置的系统的管理员,能够用命令修改我的首选项使得设置新桌面变得快速而容易。
GSettings 提供了很多有用的选项,而且文档也很详尽。如果你有想要改变的东西,可以看看有什么可用的。
--------------------------------------------------------------------------------
via: https://opensource.com/article/21/5/remap-caps-lock-key-linux
作者:[Seth Kenlon][a]
选题:[lujun9972][b]
译者:[wxy](https://github.com/wxy)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/seth
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/emoji-keyboard.jpg?itok=JplrSZ9c (Emoji keyboard)
[2]: https://opensource.com/article/20/12/emacs
[3]: https://opensource.com/article/18/5/bash-tricks#key
[4]: https://opensource.com/article/17/3/introduction-gnu-screen
[5]: https://opensource.com/article/19/6/tmux-terminal-joy
[6]: https://opensource.com/sites/default/files/uploads/bendy-fingers.jpg (Fingers on a keyboard)
[7]: https://creativecommons.org/licenses/by-sa/4.0/
[8]: https://discourse.gnome.org/t/new-gnome-versioning-scheme/4235
[9]: https://wayland.freedesktop.org
[10]: https://opensource.com/downloads/grep-cheat-sheet
[11]: 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
[12]: https://opensource.com/article/17/5/7-cool-kde-tweaks-will-improve-your-life

View File

@ -1,87 +0,0 @@
[#]: subject: (1Password for Linux Is Officially Here With Brand New Features)
[#]: via: (https://news.itsfoss.com/1password-linux-released/)
[#]: author: (Ankush Das https://news.itsfoss.com/author/ankush/)
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
1Password for Linux Is Officially Here With Brand New Features
======
1Password is a pretty good password manager (even though not open-source) and has a good rep in the open-source community as well. They even offer [free team memberships for users working on open-source projects][1].
Its desktop client for Linux was in the beta phase but now it is ready for prime time.
They have officially [announced][2] the availability of 1Password for Linux with a full-blown desktop experience that integrates with your web browser.
It also **debuts with some new features** that will be making its way to Android, iOS, Mac, and Windows soon.
Here, let me highlight what you can expect with 1Password on Linux.
### 1Password Desktop Client for Linux
While it was already available as a browser extension irrespective of the platform, the presence of a desktop client makes the experience better.
![][3]
The desktop client comes baked in with the **dark mode support** based on your GTK theme. It also integrates well with **GNOME, KDE, and any other window manager** of your choice.
Looks like they have paid attention to finer details as well, hence the desktop client also supports **system tray icon** to keep it active even when you have closed it.
You can auto-fill passwords directly on your default browser with it. While it mentions **X11 clipboard integration and support**, theres no mention of Wayland.
![][3]
It also includes support for GNOME Keyring and KDE Wallet, Kernel keyring integration, integration with system lock and idle services.
In addition to these, 1Password for Linux debuts with newly launched features that will be available for other platforms soon:
* Secure file attachments
* Item archiving and deletion features for better document organization
* Watchtower dashboard to check and evaluate your password security health
* New sharing details to see who has access to what
* Quick find and intelligent search suggestions
* Overhauled look and feel
If you are curious to know about the release and their plans for open-source and Linux community, go through the [official announcement post][2].
### Install 1Password in Linux
Officially, the desktop client supports several Linux distributions that include Ubuntu, Debian, Arch Linux, Fedora, CentOS, and RHEL. You get both **.deb** and **.rpm** packages to install or find them using package managers.
[Download 1Password for Linux][4]
It is also available as a [snap package][5]. You can follow our guide on [using snap in Linux][6] for help.
For more information on installation, you may refer to the [official instructions][7] as well.
#### Big Tech Websites Get Millions in Revenue, It's FOSS Got You!
If you like what we do here at It's FOSS, please consider making a donation to support our independent publication. Your support will help us keep publishing content focusing on desktop Linux and open source software.
I'm not interested
--------------------------------------------------------------------------------
via: https://news.itsfoss.com/1password-linux-released/
作者:[Ankush Das][a]
选题:[lujun9972][b]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://news.itsfoss.com/author/ankush/
[b]: https://github.com/lujun9972
[1]: https://news.itsfoss.com/1password-free-subscriptions/
[2]: https://blog.1password.com/welcoming-linux-to-the-1password-family/
[3]: data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjU4NSIgd2lkdGg9Ijc4MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiLz4=
[4]: https://1password.com/downloads/linux/
[5]: https://snapcraft.io/1password
[6]: https://itsfoss.com/use-snap-packages-ubuntu-16-04/
[7]: https://support.1password.com/install-linux/

View File

@ -0,0 +1,92 @@
[#]: subject: (17 true stories about switching to Linux)
[#]: via: (https://opensource.com/article/21/5/switch-to-linux)
[#]: author: (Jen Wike Huger https://opensource.com/users/jen-wike)
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
17 true stories about switching to Linux
======
There are many reasons people start using Linux, but few turn back once
they begin.
![Linux keys on the keyboard for a desktop computer][1]
It's been 30 years since Linus Torvalds created Linux, way back in 1991, as a free alternative to Unix. In that time, it's grown from a niche project to a powerful, widely used operating system that [sustains much of what's essential][2] in modern computing—the cloud, the Internet of Things, supercomputers, the devices that kept students learning during a global pandemic, and much, much more. The Linux community is a passionate, dedicated, and effective advocate for the operating system in all its iterations, and that enthusiasm has translated into steadily increasing adoption. 
There are many reasons and ways people come to Linux, but once they get here, most never turn back to the proprietary systems where they started. So we asked Opensource.com contributors to tell us how they began their tech journey with Linux. Their responses are a diverse and powerful testament about why Linux has withstood the test of time, continuously improving and gaining fans around the world.
* * *
"Curiosity sparked my earliest explorations with Linux. I came to realize very early that Linux can be used in so many ways that support the education of students and teachers whom I worked with every day. Linux and open source software leveled the playing field for many of my students and library patrons. Linux extended the life of hardware platforms that became obsolete by the design of proprietary operating systems. It is a gift that keeps giving every day." —[Don Watkins][3]
"My Linux journey started during my first year at university [in Budapest] in 1994. There was no Gmail or Hotmail at that time; even most of the teachers did not have an email address. Students could apply for one only in their second year. I just arrived back from my high school year in the United States, where I used email, so I wanted to have an email address as soon as I arrived at the university. After a week of asking, I got an email address and an invitation to participate in the facultystudent IT group. The main server was Novell NetWare, and there was a FreeBSD box for experimenting. My task was to install the faculty's first Linux server. For a few months, it was experimental for other members of the group, but soon it became a production server. I really enjoyed learning it while doing it. And once I got a stronger machine at home, I also started using Linux on my desktop too, next to Windows. In '96 I became familiar with SUSE Linux 4.3 and, ever since, SUSE and later openSUSE have been my main OS on the desktop." —[Peter Czanik][4]
"In the ancient times, I owned an Apple IIe. What I didn't like was that Apple seemed to give not quite enough hardware to do what I needed. Furthermore, it was, and still is, a 'closed shop,' where Apple tightly controls not only the software but the hardware it runs on. (All about profits.) The next step was the appearance of GUI environments, and I decided to buy an Amiga and was very happy with it. It actually allowed you to do some things, and you could get lots of free support. Well, we know what happened to Amigas. So then, remaining in my Apple-aversion state (which I continue to this day), I bought a Windows machine... Ohhhhhhh, what a letdown—everything was like a black box. It either worked or didn't and you had no clue as to why. So at this point, I was searching around BBSes and computer magazines and ran across Linux. It didn't take long before I told myself, 'I can do this!' I sent for my Red Hat Linux CDs and I was off and running. I think my first Red Hat Linux was 5.1 or something like that. I still recall the joy I had when I first got X to work properly. It's been computer heaven ever since. I started out with dual-boot setups, partly because of the many driver issues with Linux and various hardware. I'd search around with Windows to find the driver, save it to floppy, then reboot to Linux to install. But it wasn't long before I just bought a new Windows machine and blew away Windows to install Linux." —[Greg Pittman][5]
"I was in high school with a guy named Matt, who was a year ahead of me. We hung out a lot in the electronic music lab, and he also got me hooked up with a gig as a student sysadmin for the campus VAX/VMS and Unix servers. One day, Matt tipped me off to a new Minix alternative circulating on Usenet, and I spent rather too much time getting GCC to build it on my shiny new 386 PC. Unlike Minix, this kernel could legally be distributed in electronic source (and even compiled binary) form, so you didn't have to type it all in from a textbook. We lost touch after he graduated, but Matt went on to lead the Linux Documentation Project and wrote the first edition of _Running Linux_, which has pride of place on my lab bookshelf today, next to my K&amp;R." —[Jeremy Stanley][6]
"I discovered open source as a concept through Creative Commons. Recognizing them as philosophical relatives, I soon discovered that many of the tools I used (e.g., GIMP, Firefox, Audacity) were open source, and you could use an open source operating system. This was scary, but Windows Vista was generally acting up while I was in grad school. Ubuntu's WUBI installer overcame my hesitation to try Linux, and I found myself using it by default. Eventually, Windows hid the Ubuntu install, but the Linux community helped me recover my files, leading me to abandon Windows as my primary OS more than 10 years ago now." —[Kyle R. Conway][7]
"For me, my exposure came from being a poor college kid who couldn't afford a Windows license. I also worked in a bookstore and had a nice discount on Red Hat Linux 5.2. I used it for a little while and then branched out to try various other distributions: Debian, Slackware, and even FreeBSD wouldn't install for one reason or another. I found Gentoo Linux in its 1.0 to 1.2 timeframe which finally worked correctly with my network card (the 'it works with everything' 3Com 3c509 adapter). From there I became a developer, maintaining several packages for the distribution until my retirement in 2007. I certainly would not be where I am today if it were not for that discounted Red Hat Linux 5.2, and who could have thought that some 20 years later, I would be working at the very same Red Hat?" —[Lisa Seelye][8]
"For me, it was a virus in Windows Vista (the whole thing was a virus, to be honest), and my good fortune of acquiring an Ubuntu image around the same time, not really knowing much about Linux or FOSS at all. After figuring out how to install it, I found the experience was excellent: super-fast and completely intuitive for the default programs. So I liked it from an end-user point of view from the off. Then I delved deeper into this thing called 'open source,' started to understand the utility of free software, and have been a supporter ever since." —[Laurence Urhegyi][9]
"I'd been a DOS user since the 1980s, so I didn't mind the command line. When I went to university in 1990, I discovered our Unix lab in the computer science department, and I managed to get an account. Coming from the DOS world, I found Unix pretty easy to pick up. Many of the commands were the same or similar, and Unix provided much more powerful tools like awk and grep and sed. In 1993, I started looking around for something to replace MS-DOS. While I still loved DOS and was at home with the DOS applications, I wanted the power of a Unix system. I asked around on a discussion board system called Usenet, and someone suggested this new thing called Linux. It was a Unix-like operating system, but it could run on my '386 computer. I paid someone $99 to send me the floppies to install SoftLanding Systems Linux 1.03. It worked great. The tagline 'Gentle Touchdowns for DOS Bailouts' proved true, as the installer was very DOS-like. Linux felt just like the big Unix systems in the campus lab, but I could run it on my home computer. And even better, I was able to dual-boot with MS-DOS, so I could still boot back to DOS to run my word processor or spreadsheet. (Linux didn't have many applications in 1993, so I still needed to boot back to DOS to run some things.) I've also shared my [Linux origin story][10] and my history with [SLS Linux][11] on Opensource.com." —[Jim Hall][12]
"I worked in IT at a university, so Linux was around. But it was like all my other relationships at the time—I messed around with it for fun and exploring but made no real commitment. When IBM started a new service called eSecurity (which was one of the first, major ethical hacking services), I got a spot on the first team for EMEA (Europe, Middle East, and Africa). When I arrived, they handed me a 486DX laptop (still have it but, no, it doesn't work). Apparently, the department was way underfunded. It was old even then, and the only thing it could run well was Linux. It also happened to be the OS I needed to do my job as a hacker, so I installed Red Hat and ran with it. Back then we had a saying, 'Linux was made by hackers to be the playground for hackers.' We meant this in a really positive way too. And I still strongly believe you can't work successfully in network security if you don't run Linux." —[Pete Herzog][13]
"It has been so long that I sometimes find it hard to imagine I actually switched from something else. Back in 1996, I'd heard about Linux but never had spare hardware I could run it on. At work, we used a mix of Mac, Unix, and Windows. Then, at the 1996 WWDC, I got an MkLinux CD off Apple that would install on my 601 PowerPC-based Mac at work. The whole idea of having a personal 'Unix-like' workstation was too cool, so I persuaded my boss to let me try it out and never looked back. Within a year, we had Linux and FreeBSD running regularly and the main Office server had migrated off Unix onto a Dell box running Red Hat Linux." —[Steven Ellis][14]
"I switched (the first time) when I went from being a test engineer at IBM to a full-time Java developer at a startup way back in the first internet bubble. It was so much easier to code on at the time. I had to switch back several years later (mostly because I was required to use Windows on the fed contract, AND because WOW had just come out, and it didn't play nice with Wine at the time). I never stopped using it on servers, mind you—that IS how I make a living after all." —[Kevin Sonney][15]
"I've always been a 'power user' in that I like to tweak my software (and hardware—my desktops have always been self-assembled). I used DOS, then Win 3.1 (sparingly), then with Windows 95, I used the GUI more and more. During this time, when I could scrape up enough cash, I'd get more RAM or that 486 with a co-processor or whatever. Usually, the hardware upgrades would cause blue screens and a reinstall. Also, as things would gunk up and slow down, I usually ended up reinstalling everything every six months or so. In my ignorance, I thought this was annoying but normal. I continued this pattern through Windows 2000. Then, when Windows XP was released, I realized that I would have to ask Microsoft for permission (through the new activation 'feature') for my hardware upgrades and cleanup reinstalls. That was the final straw. In 2005, I got a set of Fedora discs, wiped Win2000 off my machine—cold turkey, and never looked back. There were tweaky troubles back in the day getting some hardware to run, but I no longer needed to reinstall for _any_ hardware change! And the computer ran just as well two years later as it did when I installed it! So, I got out of the habit of continual reinstalls, although, these days when I occasionally do a fresh install, it's a 20-minute ordeal instead of the weekend-long process it was with Windows! I started with Fedora with GNOME. Later, I switched to KDE because I liked the look of it. Then when KDE4 broke things I depended on, I tried out Ubuntu. I used that until the Unity debacle, at which point I switched to Linux Mint. That's where I'm at today, and I couldn't be happier!" —[Lee Carpenter][16]
"So I ended up on Linux because I was an annoying teenager. OK, perhaps that requires a bit more explanation. A family friend was a Windows/DOS administrator, and I was always bugging him for how to do different things on my computer. For a while, he was helpful but at a certain point I overwhelmed his desire to be helpful and he started to get rather annoyed with me constantly bugging him about obscure and abstract things that I was trying to do. His solution was to go to a co-worker who was a FreeBSD admin and ask that guy to set up a system for me. His thought process was that since he didn't know anything about FreeBSD, he couldn't help me when I had questions. However, the FreeBSD admin realized that he did not want to become my tech support either, so he installed Slackware. A few weeks later, I was given a system with Slackware on it. I was told how to use the `man` command and then, 'Good luck and have fun.' From that point on, it was just my curiosity of what is this weird 'Linux' thing I was given, how does it work, and what can I do with it." —JT 
"In the mid-'90s, I was an Amiga user. I worked on DOS and Windows, but my personal machines were Amigas. When I went back to school for a degree, I had to learn and work with C, so I bought one of the Amiga compilers but found that it was not readily compatible with the Sun systems at school. Someone at school informed me about Linux, so I got a laptop to use it with, picked my distro, and ordered Slackware CDs (because it sounded neat). I've been a Linux user ever since. (Still like the Amigas when I'm in a retro mood, though.) If I recall, it took me a few days of manually editing modelines to get X working on that old Compaq Armada, but it worked!" —Murph
"As I will always remember, I never switched but was pushed to Linux, no options given nor available, at my first job. It used it only once or twice during academics before getting into my first employment; I knew little about what the Linux-based OS looked like. Though I was fond of C/C++ from my academic time, I only practiced it on Windows XP using Turbo C. It took me a lot of time and learning to get the bare basics, but I am forever happy to have been pushed to Linux." —[Abhishek Tamrakar][17]
"I think I was rebel or divergent all my life. I hate the lack of alternatives. When I met OS/2, I switched to it—but it didn't take long. After I met Linux, I felt like I found my missing piece." —[Hüseyin GÜÇ][18]
"I'm a smidgin disappointed that no one says, 'I pine for the days of Minix-1.1, when men were men and wrote their own device drivers. I was finding it frustrating that everything worked in Minix,' or similar harkening back to the [initial announcement][19]. For me, my only real exposure to computers growing up was as an undergrad in university labs (Vax) playing CircleMUD and doing assigned work for various classes in basic Fortran and C, Apple IIes in my high school 'computer lab,' and my own trusty Spectrum 128K +2 that I had at home. My conversion to Linux happened when I was a college postgrad student in 1997, struggling to get some C code inherited from a prior project that I needed for my research project running on Windows. Someone suggested using the Solaris servers in the lab. The code built the first time, and before I knew it my Windows was mostly xterms and emacs windows running on a Hummingbird XServer. Another student told me it would be easier for me just to run Linux and helped me install (IIRC) Red Hat Linux 5.1 off a _Linux for Dummies_ cover CD. Something about being on my hands and knees trying to read the chipset on my network card, so I could recompile the kernel to get Ethernet working, and being told that if I got my XFree386 config wrong I could burn out my monitor, seemed attractive to me." —[Dave Neary][20]
* * *
What led you to switch to Linux? Please share your experience in the comments!
--------------------------------------------------------------------------------
via: https://opensource.com/article/21/5/switch-to-linux
作者:[Jen Wike Huger][a]
选题:[lujun9972][b]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/jen-wike
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/linux_keyboard_desktop.png?itok=I2nGw78_ (Linux keys on the keyboard for a desktop computer)
[2]: https://opensource.com/article/19/4/top-moments-linux-history
[3]: https://opensource.com/users/don-watkins
[4]: https://opensource.com/users/czanik
[5]: https://opensource.com/users/greg-p
[6]: https://opensource.com/users/fungi
[7]: https://opensource.com/users/kreyc
[8]: https://opensource.com/users/lisa
[9]: https://opensource.com/users/laurence-urhegyi
[10]: https://opensource.com/article/17/5/how-i-got-started-linux-jim-hall-freedos
[11]: https://opensource.com/article/17/8/linux-anniversary
[12]: https://opensource.com/users/jim-hall
[13]: https://opensource.com/users/peteherzog
[14]: https://opensource.com/users/steven-ellis
[15]: https://opensource.com/users/ksonney
[16]: https://opensource.com/users/carpie
[17]: https://opensource.com/users/tamrakar
[18]: https://opensource.com/users/hguc
[19]: https://static.lwn.net/2001/0823/a/lt-release.php3
[20]: https://opensource.com/users/dneary

View File

@ -1,5 +1,5 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: translator: (MjSeven)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )

View File

@ -1,194 +0,0 @@
[#]: subject: (How to use the Linux sed command)
[#]: via: (https://opensource.com/article/21/3/sed-cheat-sheet)
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
[#]: collector: (lujun9972)
[#]: translator: (MjSeven)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
How to use the Linux sed command
======
Learn basic sed usage then download our cheat sheet for a quick
reference to the Linux stream editor.
![Penguin with green background][1]
Few Unix commands are as famous as sed, [grep][2], and [awk][3]. They get grouped together often, possibly because they have strange names and powerful tools for parsing text. They also share some syntactical and logical similarities. And while they're all useful for parsing text, each has its specialties. This article examines the `sed` command, which is a _stream editor_.
I've written before about [sed][4], as well as its distant relative [ed][5]. To get comfortable with sed, it helps to have some familiarity with ed because that helps you get used to the idea of buffers. This article assumes that you're familiar with the very basics of sed, meaning you've at least run the classic `s/foo/bar/` style find-and-replace command.
**[Download our free [sed cheat sheet][6]]**
### Installing sed
If you're using Linux, BSD, or macOS, you already have GNU or BSD sed installed. These are unique reimplementations of the original `sed` command, and while they're similar, there are minor differences. This article has been tested on the Linux and NetBSD versions, so you can use whatever sed you find on your computer in this case, although for BSD sed you must use short options (`-n` instead of `--quiet`, for instance) only.
GNU sed is generally regarded to be the most feature-rich sed available, so you might want to try it whether or not you're running Linux. If you can't find GNU sed (often called gsed on non-Linux systems) in your ports tree, then you can [download its source code][7] from the GNU website. The nice thing about installing GNU sed is that you can use its extra functions but also constrain it to conform to the [POSIX][8] specifications of sed, should you require portability.
MacOS users can find GNU sed on [MacPorts][9] or [Homebrew][10].
On Windows, you can [install GNU sed][11] with [Chocolatey][12].
### Understanding pattern space and hold space
Sed works on exactly one line at a time. Because it has no visual display, it creates a _pattern space_, a space in memory containing the current line from the input stream (with any trailing newline character removed). Once you populate the pattern space, sed executes your instructions. When it reaches the end of the commands, sed prints the pattern space's contents to the output stream. The default output stream is **stdout**, but the output can be redirected to a file or even back into the same file using the `--in-place=.bak` option.
Then the cycle begins again with the next input line.
To provide a little flexibility as you scrub through files with sed, sed also provides a _hold space_ (sometimes also called a _hold buffer_), a space in sed's memory reserved for temporary data storage. You can think of hold space as a clipboard, and in fact, that's exactly what this article demonstrates: how to copy/cut and paste with sed.
First, create a sample text file with this text as its contents:
```
Line one
Line three
Line two
```
### Copying data to hold space
To place something in sed's hold space, use the `h` or `H` command. A lower-case `h` tells sed to overwrite the current contents of hold space, while a capital `H` tells it to append data to whatever's already in hold space.
Used on its own, there's not much to see:
```
$ sed --quiet -e '/three/ h' example.txt
$
```
The `--quiet` (`-n` for short) option suppresses all output but what sed has performed for my search requirements. In this case, sed selects any line containing the string `three`, and copying it to hold space. I've not told sed to print anything, so no output is produced.
### Copying data from hold space
To get some insight into hold space, you can copy its contents from hold space and place it into pattern space with the `g` command. Watch what happens:
```
$ sed -n -e '/three/h' -e 'g;p' example.txt
Line three
Line three
```
The first blank line prints because the hold space is empty when it's first copied into pattern space.
The next two lines contain `Line three` because that's what's in hold space from line two onward.
This command uses two unique scripts (`-e`) purely to help with readability and organization. It can be useful to divide steps into individual scripts, but technically this command works just as well as one script statement:
```
$ sed -n -e '/three/h ; g ; p' example.txt
Line three
Line three
```
### Appending data to pattern space
The `G` command appends a newline character and the contents of the hold space to the pattern space.
```
$ sed -n -e '/three/h' -e 'G;p' example.txt
Line one
Line three
Line three
Line two
Line three
```
The first two lines of this output contain both the contents of the pattern space (`Line one`) and the empty hold space. The next two lines match the search text (`three`), so it contains both the pattern space and the hold space. The hold space doesn't change for the third pair of lines, so the pattern space (`Line two`) prints with the hold space (still `Line three`) trailing at the end.
### Doing cut and paste with sed
Now that you know how to juggle a string from pattern to hold space and back again, you can devise a sed script that copies, then deletes, and then pastes a line within a document. For example, the example file for this article has `Line three` out of order. Sed can fix that:
```
$ sed -n -e '/three/ h' -e '/three/ d' \
-e '/two/ G;p' example.txt
Line one
Line two
Line three
```
* The first script finds a line containing the string `three` and copies it from pattern space to hold space, replacing anything currently in hold space.
* The second script deletes any line containing the string `three`. This completes the equivalent of a _cut_ action in a word processor or text editor.
* The final script finds a line containing `two` and _appends_ the contents of hold space to pattern space and then prints the pattern space.
Job done.
### Scripting with sed
Once again, the use of separate script statements is purely for visual and mental simplicity. The cut-and-paste command works as one script:
```
$ sed -n -e '/three/ h ; /three/ d ; /two/ G ; p' example.txt
Line one
Line two
Line three
```
It can even be written as a dedicated script file:
```
#!/usr/bin/sed -nf
/three/h
/three/d
/two/ G
p
```
To run the script, mark it executable and try it on your sample file:
```
$ chmod +x myscript.sed
$ ./myscript.sed example.txt
Line one
Line two
Line three
```
Of course, the more predictable the text you need to parse, the easier it is to solve your problem with sed. It's usually not practical to invent "recipes" for sed actions (such as a copy and paste) because the condition to trigger the action is probably different from file to file. However, the more fluent you become with sed's commands, the easier it is to devise complex actions based on the input you need to parse.
The important things are recognizing distinct actions, understanding when sed moves to the next line, and predicting what the pattern and hold space can be expected to contain.
### Download the cheat sheet
Sed is complex. It only has a dozen commands, yet its flexible syntax and raw power mean it's full of endless potential. I used to reference pages of clever one-liners in an attempt to get the most use out of sed, but it wasn't until I started inventing (and sometimes reinventing) my own solutions that I felt like I was starting to _actually_ learn sed. If you're looking for gentle reminders of commands and helpful tips on syntax, [download our sed cheat sheet][6], and start learning sed once and for all!
--------------------------------------------------------------------------------
via: https://opensource.com/article/21/3/sed-cheat-sheet
作者:[Seth Kenlon][a]
选题:[lujun9972][b]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/seth
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/linux_penguin_green.png?itok=ENdVzW22 (Penguin with green background)
[2]: https://opensource.com/article/21/3/grep-cheat-sheet
[3]: https://opensource.com/article/20/9/awk-ebook
[4]: https://opensource.com/article/20/12/sed
[5]: https://opensource.com/article/20/12/gnu-ed
[6]: https://opensource.com/downloads/sed-cheat-sheet
[7]: http://www.gnu.org/software/sed/
[8]: https://opensource.com/article/19/7/what-posix-richard-stallman-explains
[9]: https://opensource.com/article/20/11/macports
[10]: https://opensource.com/article/20/6/homebrew-mac
[11]: https://chocolatey.org/packages/sed
[12]: https://opensource.com/article/20/3/chocolatey

View File

@ -2,7 +2,7 @@
[#]: via: (https://opensource.com/article/21/4/context-switching-git)
[#]: author: (Olaf Alders https://opensource.com/users/oalders)
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: translator: (Chao-zhi)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
@ -178,7 +178,7 @@ via: https://opensource.com/article/21/4/context-switching-git
作者:[Olaf Alders][a]
选题:[lujun9972][b]
译者:[译者ID](https://github.com/译者ID)
译者:[Chao-zhi](https://github.com/Chao-zhi)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出

View File

@ -2,7 +2,7 @@
[#]: via: (https://opensource.com/article/21/5/fog-computing)
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: translator: (Gordon-Deng)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )

View File

@ -1,287 +0,0 @@
[#]: subject: (Drop Autotools for CMake)
[#]: via: (https://opensource.com/article/21/5/cmake)
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
[#]: collector: (lujun9972)
[#]: translator: (amwps290)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
Drop Autotools for CMake
======
CMake is a cross-platform suite for building, testing, and packaging
software that's easy to use, even if you've never used a build system
before.
![Someone wearing a hardhat and carrying code ][1]
In my [introduction to Autotools][2], I demonstrated how to manage building and packaging code with GNU Autotools. It's a robust and common platform that integrates easily into many packaging systems, including RPM, APT, [pkgsrc][3], and more. Its syntax and structure can be confusing, but luckily there are alternatives, including the open source [CMake][4] framework.
CMake is a cross-platform suite for building, testing, and packaging software. It uses simple and clearly documented syntax, so it's easy to start using even if you've never used a build system before.
### Install CMake
CMake may already be installed on your Linux system. If not, you can install it with your distribution's package manager:
```
`$ sudo dnf install cmake`
```
On Debian or similar:
```
`$ sudo apt install cmake`
```
For Mac, you can use [MacPorts][5] or [Homebrew][6]:
```
`$ sudo port install cmake`
```
On Windows, you can use [Chocolatey][7] or download a binary directly from the [CMake website][8].
### CMake at work
For developers or users who want to build software from source code, CMake is a quick and easy way to compile and install it. CMake works in stages:
1. First, during the `cmake` step, CMake scans the host system (the computer it's being run on) to discover the default settings. Default settings include where support libraries are located and where new software should be placed on the system.
2. Next, you use your system's `make` command (usually GNU Make on Linux, NetBSD Make on [NetBSD][9], and so on) to build the application, usually by converting human-readable source code into machine language.
3. Finally, during the `make install` step, the built files are copied to the appropriate locations (as detected during the `cmake` stage) on your computer.
It seems simple, and it is when you use CMake.
### CMake portability
CMake is designed with portability in mind. While it can't make your project work across all POSIX platforms (that's up to you, as the coder), it can ensure that the files you've marked for installation get installed to the most sensible locations on a known platform. And because of tools like CMake, it's trivial for power users to customize and override any non-optimal value according to their system's needs.
With CMake, all you have to know is which files need to be installed to what general location. It takes care of everything else. No more custom install scripts that break on any untested operating system.
### Packaging
Like Autotools, CMake is well-supported. Hand a project with CMake over to a distro packager, whether they're packaging an RPM or a DEB or a TGZ (or anything else), and their job is simple and direct. Packaging tools know CMake, so it's likely there will not be any patching, hacking, or adjustments required. In many cases, incorporating a CMake project into a pipeline can be automated.
### How to use CMake
To start using CMake with your project, you need only to create a `CMakeLists.txt` file in your project directory. First, declare the minimum required version of CMake and a project title and version. CMake strives to retain compatibility for as long as possible, but the more you use it and follow its development, the better you'll know what features you rely upon.
```
cmake_minimum_required(VERSION 3.10)
project(Hello VERSION 1.0)
```
As you may already be detecting, the syntax of CMake is a command followed by parameters in parentheses. The capitalized `VERSION` strings aren't arbitrary or just for style; they're valid parameters for the `project` command.
Before continuing, generate a sample `hello world` application in C or C++. For simplicity, I wrote six lines of C code and saved it as `hello.c` (to match the executable I list in `CMakeLists.txt`):
```
#include &lt;stdio.h&gt;
int main() {
   [printf][10]("Hello open source\n");
   return 0;
}
```
Make no mistake, though, CMake is useful beyond just C and C++. It can handle arbitrary files and has lots of commands available to it, so it can help you maintain projects in many different forms.
The CMake website documents all valid built-in commands and their available parameters, so it's easy to uncover the functions you need, no matter what you're trying to do. This is a simple example, though, so the next command you need is essential—you must define for CMake what code you're building:
```
`add_executable(Hello hello.c)`
```
This sets the name of your compiled binary to `Hello`, so functionally, it's the same as running `gcc` with `-o Hello` in your terminal.
In a complex project, you likely have libraries as well as executables. You can add libraries with the `add_library` command.
After you've set what files you want built and marked for installation, you must tell CMake where the finished product should end up once a user installs your application.
In this simple example, only one thing is marked for installation, so you only have to add one `install` line to your `CMakeLists`. The `install` command accepts a few parameters, but in this case, all that's necessary is the `TARGETS` parameter followed by the name of the file to install:
```
`install(TARGETS Hello)`
```
#### Adding files to a CMake project
A software project rarely just delivers code to its users. There's usually some additional data, such as manual or info pages, example projects, or configuration files. You can include arbitrary data in a CMake project using a similar workflow to when you include compiled files: first, add the file to `CMakeLists.txt` and then describe how it is to be installed.
For example, to include a directory called `assets` with your sample application, you use the `file` command, followed by the `COPY` and `DESTINATION` parameters to tell CMake to copy your additional files into your distributable package:
```
`file(COPY assets DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")`
```
The `${CMAKE_CURRENT_BINARY_DIR}` is a special built-in CMake variable representing the path to the directory currently being processed by CMake. In other words, your arbitrary data gets copied to the build directory (this becomes even clearer after you run `cmake`, so watch for this to come up again later).
Because data directories tend to be crowded places (take a look in `/usr/share` if you don't believe me), it's to everyone's benefit for you to create a subdirectory for your own project, preferably with versioning. You can do this by specifying a new directory within `CMAKE_CURRENT_BINARY_DIR` using your chosen project name followed by a special variable named for your project and the `VERSION` you set for it in your project declaration:
```
`file(COPY assets DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/Hello-${Hello_VERSION}")`
```
### Defining install locations
You've defined the file for the build process, so now you must tell CMake where to put it during the install process. Like your main executable, this uses the `install` command:
```
`install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Hello-${Hello_VERSION}" TYPE DATA)`
```
There are some new parameters here. The `DIRECTORY` parameter identifies the data source as a directory (rather than `FILE` or `SCRIPT`, for instance). You're using the same variables as you used when copying the data files into the build location. Additionally, either a `TYPE` or a `DESTINATION` must be provided for `install` (not both). The `TYPE` argument specifies a generic file type, which is placed into a location appropriate to the target system. On Linux, a `TYPE DATA` directory usually gets placed into `/usr/local/share` or `/usr/share`, unless the user or packager has defined a different data location.
That's one of the powerful things about a good build system like CMake. You don't have to worry about exactly where files end up because you know that the user can alert CMake of their preferred defaults and that CMake will build the code to make that work.
### Running CMake
CMake has several interfaces. You can use it from your terminal as a command or an interactive application, or you can use its graphical user interface (GUI) front end. I tend to use the terminal command, but I enjoy the other user experiences just as much (they definitely beat scrubbing through Makefiles in search of obscure variables to redefine).
The first step, familiar to anyone who's built their fair share of open source C++ projects, is to create a `build` directory, change to it, and then run the `cmake ..` command. I'm a lazy typist, so I name my build directory `b`, but you can use whatever makes the most sense to you:
```
$ 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
$
```
This is, more or less, the equivalent of `./configure` in the classic `./configure; make; make install` incantation. A look into your build directory reveals that CMake has generated several new files to help your project come together. There's some CMake data, a regular Makefile (that's 247 lines of code for free, but quite a lot more for complex projects), and the `Hello-1.0` data directory containing the arbitrary non-compiled data distributed with this example application:
```
$ ls
CMakeCache.txt
CMakeFiles
Makefile
Hello-1.0
cmake_install.cmake
```
Next, run the `make` command. This reads the `Makefile` generated by CMake. In this example, the default action for Make is to compile its target, `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
$
```
As you might expect, the `Hello` binary executable now exists in your current build directory. Because it's a simple self-contained application, you can run it for testing purposes:
```
$ ./Hello
Hello open source
$
```
Finally, run `make install` to invoke the install actions of the Makefile. Because I don't want my simple "hello world" application to be installed on my system, I set the `DESTDIR` variable to redirect CMake's target from the root directory (`/`) to a subdirectory in `/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
```
The output confirms its actions, and the application is installed.
### Quick customization
CMake's install prefix (the `CMAKE_INSTALL_PREFIX` variable) defaults to `/usr/local`, but any CMake variable can be customized when you run `cmake` with the `-D` option:
```
$ 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
```
Any variable used by CMake can be customized in this way.
### Interactive CMake
CMake's interactive mode is a friendly and useful method to configure an installation environment. It's a lot to ask your users to know all the possible CMake variables your project uses, so the CMake interactive interface is an easy way for them to discover customization options without looking at Makefiles and CMakeLists.
To invoke an interactive CMake session, use the `ccmake` command. There's not much to see for this simple example project, but a big project like the digital audio workstation [Rosegarden][11] makes the user interface invaluable.
![Rosegarden][12]
(Seth Kenlon, [CC BY-SA 4.0][13])
### More CMake
There's much, much more to CMake. As a developer, I enjoy CMake for its simple syntax and extensive [documentation][14], extensibility, and expediency. As a user, I appreciate CMake for its friendly and helpful error messages and user interfaces. If you're not using a build system for your project, take a look at CMake. You, and anyone trying to package your application later, won't be sorry.
--------------------------------------------------------------------------------
via: https://opensource.com/article/21/5/cmake
作者:[Seth Kenlon][a]
选题:[lujun9972][b]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/seth
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/build_structure_tech_program_code_construction.png?itok=nVsiLuag (Someone wearing a hardhat and carrying code )
[2]: https://opensource.com/article/19/7/introduction-gnu-autotools
[3]: https://opensource.com/article/19/11/pkgsrc-netbsd-linux
[4]: http://cmake.org
[5]: https://opensource.com/article/20/11/macports
[6]: https://opensource.com/article/20/6/homebrew-linux
[7]: https://opensource.com/article/20/3/chocolatey
[8]: https://cmake.org/download
[9]: https://opensource.com/article/19/3/netbsd-raspberry-pi
[10]: http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
[11]: https://opensource.com/article/18/3/make-sweet-music-digital-audio-workstation-rosegarden
[12]: https://opensource.com/sites/default/files/uploads/rosegarden-ccmake.jpg (Rosegarden)
[13]: https://creativecommons.org/licenses/by-sa/4.0/
[14]: https://cmake.org/cmake/help/latest/

View File

@ -2,7 +2,7 @@
[#]: via: (https://jvns.ca/blog/2021/05/17/how-to-look-at-the-stack-in-gdb/)
[#]: author: (Julia Evans https://jvns.ca/)
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: translator: (amwps290)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )

View File

@ -2,7 +2,7 @@
[#]: via: (https://opensource.com/article/21/5/raspberry-pi-cockpit)
[#]: author: (Alan Formy-Duval https://opensource.com/users/alanfdoss)
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: translator: (ShuyRoy)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
@ -146,7 +146,7 @@ via: https://opensource.com/article/21/5/raspberry-pi-cockpit
作者:[Alan Formy-Duval][a]
选题:[lujun9972][b]
译者:[译者ID](https://github.com/译者ID)
译者:[RiaXu](https://github.com/ShuyRoy)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出

View File

@ -2,7 +2,7 @@
[#]: via: (https://opensource.com/article/21/5/what-serverless-java)
[#]: author: (Daniel Oh https://opensource.com/users/daniel-oh)
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: translator: (DCOLIVERSUN)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )

View File

@ -1,139 +0,0 @@
[#]: subject: (Remap your Caps Lock key on Linux)
[#]: via: (https://opensource.com/article/21/5/remap-caps-lock-key-linux)
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
Remap your Caps Lock key on Linux
======
Increase your typing and navigation speed and avoid repetitive stress
injuries by remapping your keyboard on GNOME 3 and Wayland.
![Emoji keyboard][1]
There have been many life-changing Linux moments for me, but most fade into my backstory as they become the status quo. There's one little keyboard trick Linux taught me that I'm reminded of every time I use it (maybe 1,000 times a day), and that's converting the **Caps Lock** key to **Ctrl**.
I never use **Caps Lock**, but I use the **Ctrl** key all day for copying, pasting, navigating within [Emacs][2], and [invoking Bash][3], [GNU Screen][4], or [tmux][5] actions. **Caps Lock** occupies valuable real estate on my keyboard, forcing the actually useful **Ctrl** key down to the awkward-to-reach bottom corner.
![Fingers on a keyboard][6]
This is as painful as it looks. (Seth Kenlon, [CC BY-SA 4.0][7])
Remapping **Ctrl** increased my typing and navigation speed and has probably saved me from repetitive stress injuries.
### The case of the disappearing control
Buckle in, this is a roller coaster of a history lesson:
Unfortunately for **Caps Lock** swappers like me, when GNOME 3 came out, it all but removed the ability to change the location of the **Ctrl** key.
Fortunately, the excellent GNOME Tweaks app brought back these "missing" control panels.
Unfortunately, [GNOME 40][8] has no GNOME Tweaks app (yet?)
Also, unfortunately, the old `xmodmap` hack that used to work on X11 is useless on the new [Wayland display server][9].
For a short while (an afternoon at best), I felt things were looking dim for people who hate **Caps Lock**. Then I remembered I am a user of open source, and there's _always_ a way around something as simple as an overlooked GUI control panel.
### dconf
The GNOME desktop uses dconf, a database that stores important configuration options. It's the backend to GSettings, which is the system GNOME applications interface with when they need to discover system preferences. You can query the dconf database using the `gsetting` command, and you can set dconf key values directly with the `dconf` command.
### GSettings
The dconf database isn't necessarily what you might call discoverable. It's a humble database you're not meant to have to think about, and it holds a lot of data you usually don't have to interact with directly. However, it does use a sensible schema that's fun to browse if you want to better understand all of the preference options GNOME has to manage.
You can list all of dconf's schemas with the `list-schemas` subcommand. After browsing hundreds of schemas, you might use [grep][10] to narrow your focus to something that seems especially relevant, such as `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
```
Whether through a manual search or through [reading GSetting documentation][11], you may notice the `org.gnome.desktop.input-sources` schema, which helps define the keyboard layout. A GSetting schema, by design, contains keys and values.
### Remapping Caps Lock with dconf
The `xkb-options` key contains optional keyboard overrides. To set this key, use `dconf`, converting the dots (`.`) in the schema above to slashes (`/`) because the dconf database requires it:
```
`$ dconf write /org/gnome/desktop/input-sources/xkb-options "['caps:ctrl_modifier']"`
```
I set `caps` to `ctrl_modifier` because I use the **Ctrl** modifier more than any other modifier, but Vim users may prefer to set it to `escape` instead.
### View your setting
The change takes effect immediately and persists across reboots. It's a preference you've defined in GNOME, so it remains in effect until you change it.
You can view the new value in `dconf` with `gsettings`. First, view the available keys:
```
$ gsettings list-keys \
org.gnome.desktop.input-sources
xkb-options
mru-sources
show-all-sources
current
per-window
sources
```
And then view the settings with the `xkb-options` key:
```
$ gsettings get \
org.gnome.desktop.input-sources \
xkb-options
['caps:ctrl_modifier']
```
### Options aplenty
I use this little trick to set **Caps Lock** as well as the [Compose][12] key (`compose:ralt`) on my GNOME 3.4 system. While I believe there are GUI controls in development to control options like these, I also have to admit that the ability to set them programmatically is a luxury I enjoy. As a former admin of systems that had no reliable way to adjust desktop settings, the ability to script my preferences makes setting up a fresh desktop quick and easy.
There are lots of useful options available with GSettings, and the documentation is thorough. If you have something you want to change, take a look at what's available.
--------------------------------------------------------------------------------
via: https://opensource.com/article/21/5/remap-caps-lock-key-linux
作者:[Seth Kenlon][a]
选题:[lujun9972][b]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/seth
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/emoji-keyboard.jpg?itok=JplrSZ9c (Emoji keyboard)
[2]: https://opensource.com/article/20/12/emacs
[3]: https://opensource.com/article/18/5/bash-tricks#key
[4]: https://opensource.com/article/17/3/introduction-gnu-screen
[5]: https://opensource.com/article/19/6/tmux-terminal-joy
[6]: https://opensource.com/sites/default/files/uploads/bendy-fingers.jpg (Fingers on a keyboard)
[7]: https://creativecommons.org/licenses/by-sa/4.0/
[8]: https://discourse.gnome.org/t/new-gnome-versioning-scheme/4235
[9]: https://wayland.freedesktop.org
[10]: https://opensource.com/downloads/grep-cheat-sheet
[11]: 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
[12]: https://opensource.com/article/17/5/7-cool-kde-tweaks-will-improve-your-life

View File

@ -0,0 +1,98 @@
[#]: collector: (lujun9972)
[#]: translator: (hongsofwing)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (Run your favorite Windows applications on Linux)
[#]: via: (https://opensource.com/article/21/2/linux-wine)
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
在你的Linux系统上运行Windows软件
======
WINE是一个让你在Linux系统上运行windows本地程序的开源项目。
![Computer screen with files or windows open][1]
2021年有很多原因让人们比以往更加喜欢Linux系统。在这一系列的文章中我们将分享21个使用Linux系统的理由。下面将介绍如何使用WINE实现从windows系统到Linux系统的无缝转换。
你是否有一个程序只能在windows平台上运行是不是由于某一个程序阻碍了你使用Linux系统如果是这样的话你将会很想了解WINE这是一个开源项目它彻底地改变了了
Windows系统核心库让原生Windows程序能运行在你的Linux系统上。
WINE 的意思是“Wine不是一个模糊测试器”它使用了驱动这项技术的代码。自从1993年以来极客们一直致力于将应用程序的任何WIndows API调用转换成[POSIX][2]
这是一个惊人的编程壮举尤其是这个项目是独立运行的没有微软的帮助至少来讲但是有限制。应用程序离Windows API的核心越来越远WINE就无法预料到应用程序的需求。 有一些供应商可以弥补这一点,特别是[Codeweavers][3] 和[Valve Software][4]。需要得到支持的应用程序的生产商,与进行开发的公司和人没有协调。因此例如在更新软件上,从[WINE headquarters][5]到获得到“黄金”支持地位时,可能会存在一些延迟时间。
However, if you're looking to run a well-known Windows application on Linux, the chances are good that WINE is ready for it.
然而如果你你希望在Linux上运行一个著名的Windows应用程序的时候那么WINE很可能已经准备好了。
### 安装WINE
你可以从Fedora,CentOS Stream,或者RHEL等发型版本的软件储存仓库安装WINE。
```
`$ sudo dnf install wine`
```
在Debian, Linux Mint,Elementary上的安装方法相似
```
`$ sudo apt install wine`
```
WINE不是一个你启动的应用程序它是一个你启动Windows应用程序的后端支持软件。你WINE的第一次打交道很可能发生在你在Linux上启动Windows应用程序时。
### 安装应用程序
[TinyCAD][6]是一个很好的设计电路的开源应用程序但只适用于Windows系统。虽然它是一个小程序但它的确包含了不少.NET组件因此应该对于WINE来说有一点压力。
首先下载TinyCAD的安装程序与Windows安装程序的常见情况一样它是一个EXE文件。下载后双击运行它。
![WINE TinyCAD installation wizard][7]
首先通过WINE安装的步骤就如在Windows上安装软件相同。一般都采用默认方案安装尤其是在使用WINE的时候。WINE的运行环境是独立的隐藏在你的硬件驱动**drive_c**文件中可以让Windows程序如在Windows系统中一般采用管理员的的权限运行在模拟的系统环境中。
![WINE TinyCAD installation and destination drive][8]
WINE TinyCAD 的运行位置
安装后,应用程序通常会为你启动。如果你准备好进行测试,请启动应用程序。
### 运行Windows应用程序
除了安装后立即启动外通常启动WINE应用程序的方式与启动本机Linux应用程序的方式相同。无论你是使用应用程序菜单还是活动屏幕应用程序的名称在WINE中运行的桌面Windows应用程序基本上都被视为Linux上的本机应用程序。
![TinyCAD running with WINE][9]
TinyCAD通过WINE得到运行支持
### 当WINE崩溃时
大多数我在使用WINE运行的应用程序包括TinyCAD或者其他的程序都能正常运行。然而有一些例外情况当你等了几个月后看看WINE的开发人员或者说有游戏软件
是否能赶上开发进度或者说你可以联系Codeweavers这样的供应商了解他们是否销售对于你需要的应用程序支持。
### WINE是“欺骗”但“是有益处”
一些Linux用户认为如果你使用WINE你就是在Linux上“作弊”。也许会有这种感觉但WINE是一个开源项目它允许用户切换到Linux并且仍然可以运行他们工作或爱好所需的应用程序。如果WINE解决了你的问题并让你更加方便的使用Linux系统那么就使用它并接受Linux系统的灵活性。
--------------------------------------------------------------------------------
via: https://opensource.com/article/21/2/linux-wine
作者:[Seth Kenlon][a]
选题:[lujun9972][b]
译者:[hongsofwing](https://github.com/hongsofwing)
校对:[hongsofwing](https://github.com/hongsofwing)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/seth
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/browser_screen_windows_files.png?itok=kLTeQUbY (Computer screen with files or windows open)
[2]: https://opensource.com/article/19/7/what-posix-richard-stallman-explains
[3]: https://www.codeweavers.com/crossover
[4]: https://github.com/ValveSoftware/Proton
[5]: http://winehq.org
[6]: https://sourceforge.net/projects/tinycad/
[7]: https://opensource.com/sites/default/files/wine-tinycad-install.jpg
[8]: https://opensource.com/sites/default/files/wine-tinycad-drive_0.jpg
[9]: https://opensource.com/sites/default/files/wine-tinycad-running.jpg

View File

@ -0,0 +1,109 @@
[#]: subject: (Everything You Need to Know About CentOS Stream)
[#]: via: (https://itsfoss.com/centos-stream-faq/)
[#]: author: (Ankush Das https://itsfoss.com/author/ankush/)
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
Everything You Need to Know About CentOS Stream
======
Recently, [CentOS was killed][1], which existed as a rebuild of Red Hat Enterprise Linux (RHEL). You will still find the availability of CentOS Linux 8 and 7 but their support will end at the end of 2021 and 2024 (maintenance updates) respectively.
CentOS Stream will completely replace CentOS Linux as we know it. But, what is it? Is it meant to replace CentOS? Is it reliable enough?
In this article, we shall discuss everything briefly that you need to know about CentOS Stream.
### What is CentOS Stream?
![][2]
Unlike CentOS Linux, CentOS Stream was introduced as an upstream to Red Hat Enterprise Linux (RHEL). And, it is not a rolling-release distribution.
**CentOS Stream is instead a development version of RHEL.**
For more clarity on how CentOS Stream is developed, Ill recommend you to read one of the [official blog posts on CentOS continuous delivery][3].
Of course, Fedora is yet another upstream, but CentOS Stream has been positioned between RHEL and Fedora Linux.
With CentOS Stream, the CentOS community members can have a bigger potential to influence the development of RHEL.
Considering that CentOS Stream is a distribution that tracks just ahead of RHEL, any significant change in Fedora should be expected to reflect in CentOS Stream while RHEL being the next stop.
### What Problems Does CentOS Stream Solve?
As you know, that the development of RHEL is closed inside Red Hat itself.
Being something that supports an open-source ecosystem, there existed an open contribution gap for the developers and the community to influence or contribute to the development of Red Hat Enterprise Linux.
**For that very reason, CentOS Stream was introduced as a preview version of RHEL or you could call it as a development build of RHEL.**
_CentOS Stream is meant to bridge the gap and let the community contribute and have a say in the direction of development for RHEL._
Of course, looking at it from a business perspective, CentOS Stream aims to encourage RHEL subscriptions but lets not ignore the ease of contribution to RHEL development via CentOS Stream.
In addition to this resolution, CentOS Stream also tries to provide a more stable preview version of RHEL. As per one of their [official blog posts][3], they mentioned the RHEL nightly builds are updates for CentOS Stream, and they try to ensure better stability every day with CentOS Stream.
And, thats a good thing for folks who want to test the upcoming changes in RHEL.
### Is it meant to replace CentOS Linux?
No.
CentOS Linux was a rebuild of RHEL i.e a community edition of RHEL.
But, CentOS Stream is a development version of RHEL, which will include upcoming changes and additions that are meant for RHEL.
So, CentOS Stream is more suitable for folks who want to test their servers if they are future proof (RHEL Ready) and potentially for CentOS Linux users considering that the build is stable enough as per their requirements.
However, it is interesting to note that for some, it may replace CentOS Linux considering that it is not technically a rolling release.
And, if youre someone who does not want to try it, feel free to try the [CentOS alternatives][4] available.
### Migrate from CentOS 8 to CentOS Stream
Fortunately, it is not that tough to update your CentOS system to CentOS Stream. The CentOS team offer a tool to automates removing the CentOS repositories and adding CentOS Stream repos.
You can refer to our [migration guide on LinuxHandbook][5] for further information.
It is always recommended having a backup of your server before you migrate or update your system.
Should you do it? That entirely depends on what you think of CentOS Stream from everything you read about it in this article.
### Migrate from CentOS to Red Hat Enterprise Linux
After receiving a backlash for the sudden discontinuation of CentOS 8, Red Hat announced that it will [give up to 16 RHEL licenses for free to any user][6]. The technical support from Red Hat is not included in this offer.
If you want to take advantage of this offer, you should create an account for the [no-cost RHEL][7]. Afterwards, you may follow this guide to [convert your CentOS to RHEL][8].
### Concluding Thoughts
Personally, I have mixed feelings about CentOS Stream. Yes, it is indeed something that open ups the development of RHEL but if its a replacement for CentOS Linux? I dont think so.
Yes, it will encourage RHEL subscriptions for sure and if youre interested to shape up the development of RHEL, CentOS Stream will be a good option for you.
What do you think about CentOS Stream? Let me know your thoughts in the comments below.
--------------------------------------------------------------------------------
via: https://itsfoss.com/centos-stream-faq/
作者:[Ankush Das][a]
选题:[lujun9972][b]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://itsfoss.com/author/ankush/
[b]: https://github.com/lujun9972
[1]: https://itsfoss.com/centos-stream-fiasco/
[2]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2021/05/CentOS-Stream.jpg?resize=800%2C450&ssl=1
[3]: https://blog.centos.org/2020/12/centos-stream-is-continuous-delivery/
[4]: https://itsfoss.com/rhel-based-server-distributions/
[5]: https://linuxhandbook.com/update-to-centos-stream/
[6]: https://news.itsfoss.com/rhel-no-cost-option/
[7]: https://developers.redhat.com/articles/faqs-no-cost-red-hat-enterprise-linux
[8]: https://access.redhat.com/articles/2360841

View File

@ -1,483 +0,0 @@
[#]: collector: (lujun9972)
[#]: translator: (mengxinayan)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (A guide to understanding Linux software libraries in C)
[#]: via: (https://opensource.com/article/21/2/linux-software-libraries)
[#]: author: (Marty Kalin https://opensource.com/users/mkalindepauledu)
理解 C 语言中的 Linux 软件库指南
======
软件库是一种简单而又明智的方式来复用代码。
![5 pengiuns floating on iceburg][1]
软件库是一种是长期支持的、简单的和明智的方式来复用代码。这篇文章解释了如何从头开始构建库并使得其可用。尽管两个示例库都以 Linux 为例,但创建、发布和使用这些库的步骤也可以应用于类似 Unix 系统。
示例库使用 C 语言编写非常适合该任务。Linux 内核大部分由 C 语言和少量汇编语言编写Windows 和 Linux 的表弟如 macOS 也是如此)。用于输入/输出、网络、字符串处理、数学、安全、数据编码和其他标准系统库等主要由 C 语言编写。所以使用 C 语言编写库就是使用 Linux 的原生语言来编写。除此之外C 被认为高性能在所有高级语言中。
有两个示例(一个使用 C另一个使用 Python来访问库。毫无疑问可以使用 C 语言程序来访问 C 语言编写的库,但是 Python 程序示例说明了一个由 C 语言编写库可以服务于其他编程语言。
### 静态库和动态库对比
Linux 系统存在两种类型库:
* **静态库(也被称为归档库)**在编译过程中的链接阶段静态库会被编译进程序例如C或Rust中。每个程序都有属于自己的一份库的拷贝。静态库有一个显而易见的缺点——当程序需要进行一定改动时例如修复一个bug静态库必须重新链接一次。接下来要介绍的动态库避免了这一缺点。
* **动态库(也被称为共享库)**:动态库首先会在程序编译中的链接阶段被标记,但是应用程序和库代码直到运行时才会进行连接,且库代码不会进入到程序中。系统动态加载器将会把一个共享库和正在运行的程序进行连接,无论该程序是由静态编译如 C 编写,还是有动态解释语言如 Python 编写。因此,动态库不需要麻烦程序便可以进行更新。最后,多个程序可以共享同一个动态库。
通常来说,动态库优于静态库,尽管其复杂性较高和性能较低。下面是两种类型的库如何创建和发布:
1. 库的源代码会被编译进一个或多个目标模块,目标模块可以被包含在库中并且链接到程序的二进制文件中。
2. 目标模块将会被打包成一个文件。对于静态库,标准的文件拓展名是 `.a` 意为”归档“;对于动态库,标准的文件拓展名是 `.so` 意为”共享目标“。对于相同功能的两个示例库,分别发布为 `libprimes.a` (静态库)和 `libshprimes.so` (动态库)。两种库的文件名都使用前缀 `lib` 进行标识。
3. 在标准目录下拷贝一份库文件,使得程序可以轻松地访问到库。无论是静态库还是动态库,一个经典的位置是 `/usr/lib` 或者 `/usr/local/lib`,当让其他地址也是可以的。
构建和发布每种库地具体步骤会在下面详细介绍。首先我将介绍两种库里涉及到的 C 函数。
### 示例库函数
两个示例库都是从五个相同的 C 函数构建而成的,其中四个函数可供客户程序使用。第五函数为其他四个函数的实用功能,它显示了 C 语言怎么支持隐藏信息。每个函数的源代码都足够得短,可以将其存在在单个源文件中,或者多个源文件中(每个文件存储一个函数)
库函数是基本的处理函数,用多种方式处理指数。所有的函数接收非负整数值作为参数:
- `is_prime` 函数测试其单个参数是否为质数。
- `are_coprimes` 函数检查了其两个参数的最大公约数gcd是否为1即是否为互质数。
- `prime_factors`:函数列出其参数的质因数。
- `glodbach`:函数接收一个大于等于 4 的偶数,列出其可以分解为两个质数的和。它也许存在多个符合条件的数对。该函数是以 18 世纪数学家 [克里斯蒂安·哥德巴赫][2] 命名的,他的猜想是任意一个大于 2 的偶数可以分解为两个质数之和,这依旧是数论里最古老未被解决的问题。
工具函数 `gcd` 留在已部署的库文件中,但是没有包含这个函数的文件无法访问此函数。因此,一个使用库的客户程序无法调用 `gcd` 函数。仔细观察 C 函数可以明白这一点。
### 更多关于 C 函数的内容
每个在 C 语言中的函数都有一个存储类,它决定了函数的范围。对于函数,有两种选择。
- 函数默认的存储类是`extern`,它给了函数一个全局域。一个客户端程序可以调用任意 `extern` 修饰的函数在示例库中。下面是一个带有显示 `extern` 声明的 `are_coprimes` 函数定义:
Every function in C has a storage class, which determines the function's scope. For functions there are two options:
```c
extern unsigned are_coprimes(unsigned n1, unsigned n2) {
...
}
```
- 存储类 `static` 将一个函数的的范围限制到函数被定义的文件中。在示例库中,工具函数 `gcd` 是静态的(`static`
```c
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 语言通过函数定义和声明来分别函数这对库来说是重要的。接下来让我们开始了解定义。C语言仅允许命名函数不允许匿名函数并且每个函数需要定义以下内容
- 一个唯一的名字。一个程序的不允许存在两个同名的函数。
- 一个可以为空的参数列表。参数需要指明类型。
- 一个返回值类型例如int代表32位有符号整数当没有返回值时设置为空类型void
- 用一对花括号包围起来的函数主体部分。在一个人为的示例中,函数主体部分可以为空。
程序中的每个函数必须要被定义一次。
下面是库函数 `are_coprimes` 的完整定义:
```c
extern unsigned are_coprimes(unsigned n1, unsigned n2) { /* 定义 */
return 1 == gcd(n1, n2); /* 最大公约数是否为1? */
}
```
函数返回一个布尔值0代表假或者1代表真取决于两个整数参数值的最大公约数是否为1。工具函数 `gcd` 计算两个整数参数 `n1``n2` 的最大公约数。
一个函数声明不同于定义,其不需要主体部分:
```c
extern unsigned are_coprimes(unsigned n1, unsigned n2); /* 声明 */
```
声明在参数列表后用一个分号代表结束,它没有被花括号包围起来的主体部分。一个程序中的一个函数可以被多次声明。
为什么需要声明?在 C 语言中,一个被调用的函数必须对其调用者可见。有多种方式可以提供这样的可见性,具体依赖于编译器如何实现。一个必然可行的方式就是当它们二者位于同一个文件中时,将被调用的函数定义在在它的调用者之前。
```c
void f() {...} /* f 定义在其被调用前 */
void g() { f(); } /* ok */
```
当函数 `f` 被在调用前声明,此时函数 `f` 的定义可以移动到函数 `g` 的下方。
```c
void f(); /* 声明使得函数 f 对调用者可见 */
void g() { f(); } /* ok */
void f() {...} /* 相较于前一种方式,此方式显得更简洁 */
```
但是当如果一个被调用的函数和调用它的函数不在同一个文件中时呢?因为前文提到一个函数在一个程序中需要被定义一次,那么如何使得让一个文件中被定义的函数在另一个文件中可见?
这个问题会影响库,无论是静态库还是动态库。例如在两个质数库中函数被定义在源文件 `primes.c` 中,每个库中都有该函数的二进制拷贝,但是这些定义的函数必须要对使用库的 C 程序可见,该 C 程序有其自身的源文件。
函数声明可以帮助提供跨文件的可见性。对于上述的“质数”例子,它有一个名为 `primes.h` 的头文件,其声明了四个函数使得它们对使用库的 C 程序可见。
```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 语言程序中。
### 库的源代码
下面是两个库的源代码。这部分代码、头文件、以及两个示例客户程序都可以在 [我的网页][3] 上找到。
**库函数**
```c
#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的倍数不会是质数 */
/* check that n is not a multiple of other values < 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` 被编译进一个目标模块。下面是命令,百分号 % 代表系统提示符,两个井字符 # 是我的注释。
```shell
% gcc -c primes.c ## 步骤1静态
```
这一步生成目标对象是二进制文件 `primes.o`。`-c` 标志意味着只编译。
下一步是使用 Linux 的 `ar` 命令将目标对象归档。
```shell
% ar -cvq libprimes.a primes.o ## 步骤2静态
```
`-cvq` 三个标识分别是“创建”、“详细的”、“快速添加(以防新文件没有添加到归档中)”。回忆一下,前文提到过前缀 `lib` 是必须的,而库名确是任意的。当然库的文件名必须是唯一的以避免冲突。
归档已经准备好要被发布:
```shell
% sudo cp libprimes.a /usr/local/lib ## 步骤3静态
```
现在静态库对接下来的客户示例程序是可见的。(包含 `sudo` 可以确保有访问权限将文件拷贝进 `/usr/local/lib` 目录中)
动态库还需要一个或多个对象模块进行打包:
```shell
% gcc primes.c -c -fpic ## 步骤1动态
```
增加的选项 `-fpic` 指示编译器生成与位置无关的代码,这意味着不需要将该二进制模块加载到一个固定的内存位置。在一个拥有多个动态库的系统中这种灵活性是至关重要的。生成的对象模块会略大于静态库生成的对象模块。
下面是从对象模块创建单个库文件的命令:
```shell
% 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` 目录下:
```shell
% sudo cp libshprimes.so.1 /usr/local/lib ## 步骤3动态
```
现在在共享库的逻辑名(`libshprimes.so`)和它的物理文件名(`/usr/local/lib/libshprimes.so.1`)之间设置一个符号链接。最简单的方式是将 `/usr/local/lib` 作为工作目录,在该目录下输入命令:
```shell
% sudo ln --symbolic libshprimes.so.1 libshprimes.so ## 步骤4动态
```
逻辑文件名 `libshprimes.so` 不应该改变,但是符号链接的目标(`libshrimes.so.1`可以根据需要进行更新新的库实现可以是修复了bug提高性能等。
最后一步(一个预防措施)是调用 `ldconfig` 工具来配置系统的动态加载器。这个配置保证了加载器能够找到新发布的库。
```shell
% sudo ldconfig ## 步骤5动态
```
到现在,动态库已为客户准备就绪了,包括接下来的两个示例库。
### 一个使用库的 C 程序
示例 C 程序是一个测试程序,它的源代码以两条 `#include` 指令开始:
```c
#include <stdio.h> /* 标准输入/输出函数 */
#include <primes.h> /* 我的库函数 */
```
文件名两边的尖括号标识可以在编译器的搜索路径中找到这些头文件(对于 primes.h 文件在 `/usr/local/inlcude` 目录下)。如果不包含 `#include`,编译器会抱怨缺少函数的声明,例如`is_prime` 和 `prime_factors` 函数,它们都在两个库中发布。顺便提一句,测试程序的源代码不需要更改即可测试两个库中的每一个库。
相比之下,库的源文件(`primes.c`)使用 `#include` 指令打开以下头文件:
```c
#include <stdio.h>
#include <math.h>
```
`math.h` 头文件是必须的,因为库函数 `prime_factors` 会调用数学函数 `sqrt`,其在标准库 `libm.so` 中。
作为参考,这是测试库程序的源代码:
**测试程序**
```c
#include <stdio.h>
#include <primes.h>
int main() {
/* is_prime */
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");
/* are_coprimes */
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");
/* goldbach */
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开始并且一条编译命令可能包含多个链接标志。下面是一个完整的编译测试程序的编译指令使用动态库作为示例
```shell
% gcc -o tester tester.c -lshprimes -lm
```
第一个链接标志指定了库 `libshprimes.so`,第二个链接标志指定了标准数学库 `libm.so`
链接器是懒惰的,这意味着链接标志的顺序是需要考虑的。例如,调整上述实例中的链接顺序将会产生一个编译时错误:
```shell
% gcc -o tester tester.c -lm -lshprimes ## 危险!
```
链接 `libm.so` 库的标志先出现,但是这个库中没有函数被测试程序显式调用;因此,链接器不会链接到 `math.so` 库。调用 `sqrt` 库函数仅发生在 `libshprimes.so` 库中包含的 `prime_factors` 函数。编译测试程序返回的错误是:
```
primes.c: undefined reference to 'sqrt'
```
因此,链接标志的顺序应该是通知链接器需要 `sqrt` 函数:
```shell
% 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 &gt; 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 程序
Python 不同于 C它不是一个静态编译语言这意味着 Python 客户示例程序必须访问动态版本而非静态版本的质数库。为了能这样做Python 中有众多的支持一个外部语言接口简称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 库之间的接口是简单明了的。
```python
>>> from ctypes import cdll
>>> primes = cdll.LoadLibrary("libshprimes.so") ## logical name
>>> 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 语言库使用复杂的类型如结构体,如果库函数传递和返回指向结构体的指针,那么一个 FFI 比 `ctypes` 更适合作为一个在 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 InterfaceJNI一个替代品后Java 语言和 C 语言交互也会变的很容易。
--------------------------------------------------------------------------------
via: https://opensource.com/article/21/2/linux-software-libraries
作者:[Marty Kalin][a]
选题:[lujun9972][b]
译者:[萌新阿岩](https://github.com/mengxinayan)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/mkalindepauledu
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/rh_003499_01_linux31x_cc.png?itok=Pvim4U-B (5 pengiuns floating on iceburg)
[2]: https://en.wikipedia.org/wiki/Christian_Goldbach
[3]: https://condor.depaul.edu/mkalin
[4]: http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
[5]: http://www.opengroup.org/onlinepubs/009695399/functions/sqrt.html
[6]: https://openjdk.java.net/projects/panama

View File

@ -0,0 +1,231 @@
[#]: subject: "Drop Autotools for CMake"
[#]: via: "https://opensource.com/article/21/5/cmake"
[#]: author: "Seth Kenlon https://opensource.com/users/seth"
[#]: collector: "lujun9972"
[#]: translator: "amwps290"
[#]: reviewer: " "
[#]: publisher: " "
[#]: url: " "
抛弃 Autotools 向 CMake 迈进吧
======
CMake 是一个跨平台的编译,测试和打包软件,即使你以前从来没有使用过构建系统,也可以轻松上手。
![Someone wearing a hardhat and carrying code ][1]
在我以前的文章 [Autotools 入门][2] 一文中,我说明了如何使用 Autotools 来管理和打包代码。这是一个强大且通用的平台,可轻松集成到许多包系统中,包括 RPMAPT[pkgsrc][3] 以及一些其他平台。它的语法和结构可能会令人困惑,但幸运的是,我们还有其他选择,开源的 [CMake][4] 就是其中一个。
CMake 是一个用于构建,测试和打包软件的跨平台套件。 它使用简单且语法比较清晰明了,因此即使您以前从未使用过构建系统,也很容易开始使用。
### 安装 CMake
CMake 可能已经安装在您的 Linux 系统上。 如果没有,您可以使用发行版的程序包管理器进行安装:
```
`$ sudo dnf install cmake`
```
在 Debian 或者其他相似的系统上:
```
`$ sudo apt install cmake`
```
在 Mac 上,你可以使用 [MacPorts][5] 或者 [Homebrew][6] 来安装:
```
`$ sudo port install cmake`
```
在 Windows 上,你可以使用 [Chocolatey][7] 或者直接从 [CMake 网站][8]下载二进制来安装。
### 使用 CMake
对于想要从源代码构建软件的开发人员或用户来说CMake 是一种快速简便的编译和安装方法。 CMake 分阶段工作:
1. 首先,在 `cmake` 步骤中CMake 扫描计算机查看一些默认设置。 默认设置包括库的位置以及在系统上安装软件的位置。
2. 接下来,使用系统上的 `make` 命令(在 Linux 上是 GUN Make,在 [NetBSD][9] 上是 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 &lt;stdio.h&gt;
int main() {
   [printf][10]("Hello open source\n");
   return 0;
}
```
毫无疑问CMake 不仅适用于 C 和 C++。 它可以处理任意文件,并且具有许多可用的命令,因此它可以帮助您维护许多不同形式的项目。
CMake 网站中的文档有所有有效的内置命令及其可用参数,因此无论您要做什么,都可以轻松发现所需的功能。 不过,这是一个简单的示例,因此,您需要的下一个命令是必不可少的——您必须为 CMake 定义要构建的代码:
```
`add_executable(Hello hello.c)`
```
这个命令指定了你编译后的二进制文件的名字。因此,它与您在终端中执行带有 `-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` 后边加上你的项目名字和版本名字来指定一个新目录。
```
`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` 参数指定了数据文件是一个目录(而不是一个文件或者脚本)。你使用了和复制一些额外文件到编译目录时一样的参数。另外, 在 `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` 目录。
```
$ lsCMakeCache.txtCMakeFilesMakefileHello-1.0cmake_install.cmake
```
接下来,运行一下 `make` 命令,这将会读取由 CMake 生成的 `Makefile`。在这个例子中Make 默认的行为就是由源程序 `hello.c` 生成目标文件。
```
$ makeScanning dependencies of target Hello[ 50%] Building C object CMakeFiles/Hello.dir/hello.c.o[100%] Linking C executable Hello[100%] Built target Hello$
```
如您所料,`Hello` 二进制可执行文件现在存在于当前的构建目录中。 因为它是一个简单的自包含应用程序,所以您可以运行一下它看一下效果是否和您想的一致:
```
$ ./HelloHello open source$
```
最后,运行一下 `make install` 来调用 `Makefile` 中的安装步骤。因为我不想让这个简单的 "hello world" 程序安装到我的系统中。因此,我通过设置 `DESTDIR` 变量来将 CMake 的目标位置从根目录(`/`) 变成了它的子目录 `/tmp`:
```
$ mkdir /tmp/dist-hello$ make install DESTDIR=/tmp/dist-hello[100%] Built target HelloInstall 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 HelloInstall 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][11] 这样的大型项目,这将非常有用。
![Rosegarden][12]
(Seth Kenlon, [CC BY-SA 4.0][13])
### CMake 的更多知识
还有很多很多的 CMake 知识需要去了解。作为一个开发者,我非常喜欢他简洁的语法,详尽的文档,可扩展性以及便捷性。作为一个用户我非常喜欢 CMake 友好且实用的错误提示信息还有它的界面,如果您的项目还未开始使用构建系统,看一眼 CMake 吧。您以及以后尝试打包您应用程序的任何人都不会后悔。
--------------------------------------------------------------------------------
via: https://opensource.com/article/21/5/cmake
作者:[Seth Kenlon][a]
选题:[lujun9972][b]
译者:[amwps290](https://github.com/amwps290)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/seth
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/build_structure_tech_program_code_construction.png?itok=nVsiLuag "Someone wearing a hardhat and carrying code "
[2]: https://opensource.com/article/19/7/introduction-gnu-autotools
[3]: https://opensource.com/article/19/11/pkgsrc-netbsd-linux
[4]: http://cmake.org
[5]: https://opensource.com/article/20/11/macports
[6]: https://opensource.com/article/20/6/homebrew-linux
[7]: https://opensource.com/article/20/3/chocolatey
[8]: https://cmake.org/download
[9]: https://opensource.com/article/19/3/netbsd-raspberry-pi
[10]: http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
[11]: https://opensource.com/article/18/3/make-sweet-music-digital-audio-workstation-rosegarden
[12]: https://opensource.com/sites/default/files/uploads/rosegarden-ccmake.jpg "Rosegarden"
[13]: https://creativecommons.org/licenses/by-sa/4.0/
[14]: https://cmake.org/cmake/help/latest/