红帽 6.28 媒体开放日手记

在一个炎热的下午我代表 Linux 中国开源社区参加了 6 月 28 日的红帽媒体开放日。以下内容摘录自该活动，有删节。

![](/data/attachment/album/201807/04/222314c85ha0gwd04l5znd.jpg)

本次参加红帽开放日的主要官方人员如题图，从左到右分别是：

* Fedora 社区工程师 Adam Samalik
* 红帽资深高级云技术官 Thomas Cameron
* ManageIQ 社区负责人 Carol Chen
* 社区活动经理 Jennifer Madriaga
* Fedora 社区负责人 Brian Exelbierd
* CoreOS 及 Prometheus 社区软件工程师 Max Leonard Inden

以下是问题摘录：

### 问题 1

记者：我想问各位社区成员一个问题，大家本身是社区的负责人或者工程师，同时又有红帽的背景，你们怎么把技术能量转换成价值贡献给社区，又怎么将社区开源的服务能力转化给红帽？

Thomas Cameron：这个问题非常好，其实对我们来说这并不是两边。我们想的首先是这个技术先提供给社区，然后社区进一步的开发完善，最后成为供企业可以使用的技术或者软件，开源是红帽的 DNA，对我们来说最重要的一件事是使这些软件取得成功，因此在我们的工作是就某个软件进行研究，或者推动在某个软件上增加什么新的功能的时候，或者要求红帽提供更多的资源。我们想的目的都是一样的，就是先把技术放进社区，然后在这个基础上进一步的开发创新，最终拿出来供企业使用。

### 问题 2

记者：比较一下十年前的开源社区跟今天的开源社区的用户差别，十年前的开源社区是极客在参与这个项目，现在再去社区里看一下，有一些用户级的，他可能遇到使用上的麻烦，可能到社区找一些答案，我们这个产品可能在场景应用当中遇到一些特殊的问题和麻烦，这个时候能不能向这些应用者，向被迫进入社区的人介绍一下咱们的沟通机制和反馈机制是怎么样的？另外一个我看到咱们这个众筹项目正在进行中，不同的项目的沟通机制是什么样的，能不能给用户一个介绍？

![](/data/attachment/album/201807/04/223316xplh1mq2yf1fyuqp.jpg)

Brian Exelbierd：这个问题，涉及到沟通的机制，对任何一个项目来说沟通发生在多个不同的层次上，以 Fedora 社区为例，我们的这些核心贡献者、开发建造软件并且把它们提供出来的开发者，他们在 IRC 里进行沟通交流，但是大量的用户沟通的地点在自己感兴趣的场景或者内容不同发生在不同的地点，有些特别专注于游戏或者某个特定场景，他们都有论坛和交流地点，我们也会提醒我们的人要去不同的地点才能了解到更多用户的反馈意见。

下个问题也是令人兴奋的问题，因为 Fedora 的发布会涉及到很多不同的技术，从最开始社区发展起来的时候，我们就在不同的技术小组间建立了很强的反馈和交流机制，我们在进行测试的时候也会对所有的要素进行测试，比如我们会和 CentOS、OpenCI 这样的项目进行联系看看在哪些点上可以实现很好的集成，在哪些点上可能存在问题，这也是不同项目组之间进行沟通的方式。

Max Leonard Inden：我也想补充一个观点，我们每个项目的沟通方式都是不一样的，但是各个项目之间仍然存在着非常密切的沟通，而且我们大家的态度是一样的：所有的沟通都是受欢迎的，没有人会因为在不合适的地点问了问题而受到责难，我们会欢迎你充分的参与进来，提出问题，这是非常重要的一点。

红帽技术人员：再补充一点，关于您提到的现在的普通用户参与社区比十年前多多了，今天的科技更复杂，解决方案也更复杂，我们上游社区的项目同样更复杂，用户也在试图参与进来，第二，对于开发者而言，他使用的最主要的沟通方式是代码和编码，因为代码是他们的共同语言，虽然有人发布了代码，那么就有人从代码的角度看一看应该怎么对他检查，漏洞怎么进行修改，所以代码对于全世界的开发者来说都是同样的语言。

### 问题 3

记者：红帽愿意帮助我们设立站点下载 ISO 和文件么？当我在用一个红帽的帐户登录网站的时候，我去下载镜像，点按纽会发现有一个衔接，由于我们国家到美国的网速非常慢，整个镜像下载不下来，我们的工作没法进展，我们的解决方案是租一个美国的 VPS，从 VPS 再下载到本地还是会超时，第二个解决方案是再租一个香港 VPS，把这个从美国的拉到香港 VPS，再从香港拉到本地这个时候发现中间这一块又特别慢，想知道红帽有没有相对的解决方案？

![](/data/attachment/album/201807/04/223340kl26juoo8la7ooli.jpg)

Thomas Cameron：我非常理解您的这种沮丧的情绪，而且我们也感觉这样非常麻烦。但是特别坦率的说，这个问题的解决方案涉及到方方面面，它同时是法律问题，监管问题，涉及到条约等各种各样的问题，而我们在座的人没有一个人适合回答这样的问题，因为我们不是相关问题的专家，但是鉴于您有红帽的帐户，我建议您联系一个帐户经理，他会想办法帮您找解决方案，因为我们不想使您得到非常坏的体验，也不想麻烦您建立多个 VPS 的去解决，但是这个问题的最终解决还是需要律师法律团队和网络的工程团队，我们没办法回答，谢谢。

### 问题 4

记者：在 Fedora 社区有不同的区域划分，相互之间的差异化红帽是怎么解决的，在中国的本地化进程是怎样落地的，人员参与和贡献分别是多少？

![](/data/attachment/album/201807/04/223407ubc5t2btii254dd6.jpg)

Brian Exelbierd：我非得站起来回答您的第二个问题不可，因为要给您看一下我穿的体恤，这个体恤是 Fedora 本地化的主题，这是我们第 26 次发布 Fedora 版本的时候做的，主要目的是为了感谢全世界各地为 Fedora 本地化做出贡献的人们，因为确实有很多人都参与进来了，里面有一个泡泡写的是汉语。

我现在回答您问题的第一部分，您讲的非常对，我们 Fedora 是分区域的这个主要是有两个原因，首先是过去为了行政管理的便利做出的安排，因为这样分成不同的区域之后就可以更为容易的，相当于在本地做决定，而且资金的流动也更便利一些，随着全球化的发展，这个重要性降低了。还有第二个原因，您刚才提到差异化，差异性是无处不在的，我们希望在对话的时候，彼此的对话能在一个更适合的地方发生，因而在不同的国家和社区进行对话时所产生的决议有效，毕竟不同区域在文化上是有敏感性的。

回答您的第二个问题，您问到中国有多少贡献者，和他们在在这个社区中多活跃，对这样的问题，我们的回答永远是不够多，因为我们希望任何地方的贡献者都能够更多一些，希望他们更活跃的参与社区的活动。在中国我们也面临这样的挑战，因为中国的这些软件工程师或者相关可能的爱好者，他们本身的工作时间是非常长的，会加很长的班，通勤时间也非常长。这样他们就没有太多的精力投入开源社区的活动，此外中国社会不太重视让学生参与开源活动，大部分学生更专注于把考分弄的更高一点。我们在中国一直希望寻找对开源感兴趣的人，鼓励他们参与进来。不管你面临什么样的用户和场景，我们希望都是有人能够和你进行交流提供帮助的，所以我们非常鼓励大家的参与。

再补充一点，我们的开源社区是非常具有全球性的社区，因此绝不会在中国天然的有哪些情况就使得中国人为社区做贡献特别难，不会有这些情况，比如我本人经常在晚上九点和社区的成员进行交流，因为这个对大部分社区成员来说是最合适的时间。对不少中国人来讲，中国的时区和美国时区差异特别大，但是这一点不会阻止开源社区的交流。

### 问题 5

记者：我想问一个跟开源和闭源有关的问题，从软件开发的角度来讲，开源比闭源好，因为闭源一年更新的速度比较慢，而开源的广泛性和活跃性远远大于闭源，但是从商业角度来讲，开源还是不太成功的，以红帽为例，现在红帽每年的营收跟微软和闭源的软件厂商来讲远远不在一个级别上，从商业的角度讲，开源不那么成熟，作为开源社区的大拿来讲，吸引你们进入开源的热情是你们对技术的偏好，还是你们坚信开源技术未来在商业上有很大的潜质，什么支撑你们在开源领域里努力？

Thomas Cameron：在商业上我们已经比那些闭源的软件厂商要成功了。如果仔细的看一下红帽的财报跟他每年的增长，我们每年平均增长都在 20% 以上，所以从增速的角度来看，我们比所有的闭源软件开发公司做的都要好，所以从商业模式上已经证明了开源可以做的很好。关于为什么我个人会在开源中，这个回答非常简单，因为在这个世界上没有任何其他一个我所知道的行业能够让一个国家、或者一个村子里的人看到代码，并且利用手上的电脑开展相关的工作，没有任何一个其他的行业像开源社区一样把自己知道的一切都告诉别人，而在这个过程中我还拿到一份薪酬，当然我不能代表别人说话，我自己而言我觉得我是全世界最幸运的人，一方面我能够每天都在玩这些最酷的技术，同时还把我所知道的一切告诉任何感兴趣想学习的人，在这个过程中还能拿到工资。

![](/data/attachment/album/201807/04/223550iqyu3rcjc1n0bqz1.jpg)

给大家看一下大臂上的刺青，我觉得几乎没有那个闭源公司的员工会把自己公司的logo刻到自己的身上，但是我这样做了。大概五年前，闭源和开源软件公司之间的冲突还是非常显著的，但是今天我们可以看到所有的闭源软件公司都在采用开源的方法，他们也在发布大量的开源的代码，也就是说他们都看到了开源的模式，协作，为他人提供服务，以及做一切人人们生活变的更好的事情，这个模式是被大家认可的，这个时代是非常不可思议的，著名厂商包括IBM，微软，甲骨文等等，他们都在做开源的事情。

Jennifer Madriaga：我也补充一下，强调一下我们开源的核心是协作，在开源的社区里面，你会发现很多竞争对手同时也是合作的伙伴，我们和 IBM 是很好的伙伴，和微软是很好的伙伴，是 AWS、谷歌都是非常好的伙伴。重要的是没有他们的参与，没有我们的参与，这个行业就不可能取得这么大的成功。我经常到各个社区去，在这个过程中会和其他的组织进行交流，其中不少会被媒体描述为我们的竞争对手。我们也不仅仅和这些公司打交道，我们还和很多大学，非盈利机构进行沟通，这个社区是多样的，而且有大量的互动。开源社区伟大的一点是他特别促进创新，有这样的一个机构，CERN，欧洲原子能组织，他们的每一个软件都是开源的，他们在用 CoreOS、Fedora、Ceph 等，还有 NASA，也使用了大量的开源软件，其实他们是最早发明了 OpenStack，之后在社区得以进一步开发。行业的未来是开源，很多公司为什么用开源，因为他们知道只有用了开源才能保持自己的敏捷性，而且他们也知道自己是没有办法预测未来的，但是如果他们不与时俱进，那么这个公司可能将来就死路一条。

 Adam Samalik：假如你是一个喜欢编代码的人，或者公司让程序员编写代码，如果你在社区里发布过你的代码，并且让其他人为这个代码做出贡献，你立刻会意识到开源的重要性或者价值。拿 Kubernetes 举个例子，它最早是谷歌拿出来的，一开始非常简单，但是大家都看到它的前景，现在有好多公司在为 Kubernetes 做出贡献，Kubernetes 本身也变的更为庞大，而且是非常棒的，但是在开源社区会发生这些事情，你把代码拿出来不是损失了自己的代码，有更多人会对你帮助，会有更多的贡献。

Carol Chen：谈到关系，在去年我们与阿里巴巴建立了伙伴关系，我希望并且认为肯定有更多的中国本地的伙伴关系发展起来。其实看一看 LC3 大会就知道了，有那么多大大小小的本地公司他们都在做开源，而且非常愿意分享自己用开源的经验，所以我想在这方面我们可以真实的看到这个趋势。关于个人的动机，我非常喜欢技术，我喜欢和别人分享东西，我也喜欢给别人参与这些非常酷的项目的机会，我也希望生活能够过的好，而参与开源给了我这一切。

某男：我补充一句关于创新和开源的关系，我们的 CEO 发布了一本新书《开放式创新》，现在我们看到在当今世界上人们面临的问题越来越复杂，对于这些复杂的问题一个公司单独没有办法解决，我们需要很多公司很多人合作，所以开源的平台会是非常重要的，这么多人和企业都可以一起寻找解决方案，所以开源在将来肯定会非常重要的推动创新。

Brian Exelbierd：我要讲的故事跟他们都不一样，我不知道一开始加入开源社区的动机是不是像我的同事那么纯净。 我就记得当时在大学里的朋友来找我，他当时拿着最初的 Linux 的某个版本，我们当时用软盘的复制工具复制了 64 个软盘，当时是希望能用这个东西让我非常糟糕的电脑转的更快一点。

当时我这个同学就说，欧洲有这么一个人在干这个事情，你知道我们都是美国人，住在美国也不太关心，不知道他在欧洲哪儿，但是现在我住在欧洲，知道那些地方在哪儿。当时有一个特别自私的想法，就是想让我的电脑快一点，我也做出了我的第一个贡献，因为我想让这个程序运行得有点差别，想改一下。所以最初这个动机帮助我逐步进入开源社区，当时我还是一个大学生，所以写的代码不太好，当时有代码的审阅人员，他们会看代码给你各种建议帮助你改进，这样逐步的参与动机，自私程度降低了，而更多的希望我能够也做出点贡献，也给其他人提供一些帮助。我们最早的时候有 GRP 系统，厂商根本不问我们用的怎么样，但是在开源社区情况完全不一样，我们跟企业用户沟通，他们会直接说出这个软件存在什么问题，并且他会告诉你我们应该怎么改进。

Max Leonard Inden：我为什么我参加了开源社区，我的同事们讲的非常好，从我的角度来讲是开源让我能够到这儿，让我在大会上发言，并且公开谈论我自己感兴趣的东西，而且能听别人谈。

![](/data/attachment/album/201807/04/224020ywz32ztt5uwi93y3.jpg)

---

听了大家的提问和回答，本人有如下感受：

* 开源在中国需要更多的非程序员的贡献者，来在艺术、营销、文档三个方面做出更多的贡献。
* 文化始终是大于代码的（Culture is bigger than code）。
* 开源本身是跨越了国界、地域、文化，让我们把资源更高效的利用起来让人们的生活更美好（OpenSource making people's life better）。


lua 中神奇的表（table）

Summary: 最近在尝试配置 awesome WM，因此粗略地学习了一下 lua 。 在学习过程中，我完全被 table 在 lua 中的应用所镇住了。

![](/data/attachment/album/201807/05/155958zjef7jp7jpdafy6m.jpg)

最近在尝试配置 awesome WM，因此粗略地学习了一下 lua 。 在学习过程中，我完全被<ruby> 表 <rp>  （ </rp> <rt>  表 </rt> <rp>  ） </rp></ruby>在 lua 中的应用所镇住了。

表在 lua 中真的是无处不在：首先，它可以作为字典和数组来用；此外，它还可以被用于设置闭包环境、模块；甚至可以用来模拟对象和类。

### 字典

表最基础的作用就是当成字典来用。 它的键可以是除了 `nil` 之外的任何类型的值。

```
t={}
t[{}] = "table"                 -- key 可以是表
t[1] = "int"                    -- key 可以是整数
t[1.1] = "double"               -- key 可以是小数
t[function () end] = "function" -- key 可以是函数
t[true] = "Boolean"             -- key 可以是布尔值
t["abc"] = "String"             -- key 可以是字符串
t[io.stdout] = "userdata"       -- key 可以是userdata
t[coroutine.create(function () end)] = "Thread" -- key可以是thread

```

当把表当成字典来用时，可以使用 `pairs` 函数来进行遍历。

```
for k,v in pairs(t) do
  print(k,"->",v)
end

```

运行结果为：

```
1   ->  int
1.1 ->  double
thread: 0x220bb08   ->  Thread
table: 0x220b670    ->  table
abc ->  String
file (0x7f34a81ef5c0)   ->  userdata
function: 0x220b340 ->  function
true    ->  Boolean

```

从结果中你还可以发现，使用 `pairs` 进行遍历时的顺序是随机的，事实上相同的语句执行多次得到的结果是不一样的。

表 中的键最常见的两种类型就是整数型和字符串类型。 当键为字符串时，表 可以当成结构体来用。同时形如 `t["field"]` 这种形式的写法可以简写成 `t.field` 这种形式。

### 数组

当键为整数时，表 就可以当成数组来用。而且这个数组是一个 **索引从 1 开始** 、没有固定长度、可以根据需要自动增长的数组。

```
a = {}
for i=0,5 do                    -- 注意，这里故意写成了i从0开始
  a[i] = 0
end

```

当将表当成数组来用时，可以通过长度操作符 `#` 来获取数组的长度：

```
print(#a)

```

结果为：

```
5

```

你会发现， lua 认为数组 `a` 中只有 5 个元素，到底是哪 5 个元素呢？我们可以使用使用 `ipairs` 对数组进行遍历：

```
for i,v in ipairs(a) do
  print(i,v)
end

```

结果为：

```
1   0
2   0
3   0
4   0
5   0

```

从结果中你会发现 `a` 的 0 号索引并不认为是数组中的一个元素，从而也验证了 lua 中的数组是从 **1 开始索引的**。

另外，将表当成数组来用时，一定要注意索引不连贯的情况，这种情况下 `#` 计算长度时会变得很诡异。

```
a = {}
for i=1,5 do
  a[i] = 0
end
a[8] = 0                        -- 虽然索引不连贯，但长度是以最大索引为准
print(#a)
a[100] = 0                      -- 索引不连贯，而且长度不再以最大索引为准了
print(#a)

```

结果为：

```
8
8

```

而使用 `ipairs` 对数组进行遍历时，只会从 1 遍历到索引中断处。

```
for i,v in ipairs(a) do
  print(i,v)
end

```

结果为：

```
1   0
2   0
3   0
4   0
5   0

```

### 环境（命名空间）

lua 将所有的全局变量/局部变量保存在一个常规表中，这个表一般被称为全局或者某个函数（闭包）的环境。

为了方便，lua 在创建最初的全局环境时，使用全局变量 `_G` 来引用这个全局环境。因此，在未手工设置环境的情况下，可以使用 `-G[varname]` 来存取全局变量的值。

```
for k,v in pairs(_G) do
  print(k,"->",v)
end

```

```
rawequal    ->  function: 0x41c2a0
require ->  function: 0x1ea4e70
_VERSION    ->  Lua 5.3
debug   ->  table: 0x1ea8ad0
string  ->  table: 0x1ea74b0
xpcall  ->  function: 0x41c720
select  ->  function: 0x41bea0
package ->  table: 0x1ea4820
assert  ->  function: 0x41cc50
pcall   ->  function: 0x41cd10
next    ->  function: 0x41c450
tostring    ->  function: 0x41be70
_G  ->  table: 0x1ea2b80
coroutine   ->  table: 0x1ea4ee0
unpack  ->  function: 0x424fa0
loadstring  ->  function: 0x41ca00
setmetatable    ->  function: 0x41c7e0
rawlen  ->  function: 0x41c250
bit32   ->  table: 0x1ea8fc0
utf8    ->  table: 0x1ea8650
math    ->  table: 0x1ea7770
collectgarbage  ->  function: 0x41c650
rawset  ->  function: 0x41c1b0
os  ->  table: 0x1ea6840
pairs   ->  function: 0x41c950
arg ->  table: 0x1ea9450
table   ->  table: 0x1ea5130
tonumber    ->  function: 0x41bf40
io  ->  table: 0x1ea5430
loadfile    ->  function: 0x41cb10
error   ->  function: 0x41c5c0
load    ->  function: 0x41ca00
print   ->  function: 0x41c2e0
dofile  ->  function: 0x41cbd0
rawget  ->  function: 0x41c200
type    ->  function: 0x41be10
getmetatable    ->  function: 0x41cb80
module  ->  function: 0x1ea4e00
ipairs  ->  function: 0x41c970

```

从 lua 5.2 开始，可以通过修改 `_ENV` 这个值（**lua 5.1 中的 `setfenv` 从 5.2 开始被废除**）来设置某个函数的环境，从而让这个函数中的执行语句在一个新的环境中查找全局变量的值。

```
a=1                             -- 全局变量中a=1
local env={a=10,print=_G.print} -- 新环境中a=10,并且确保能访问到全局的print函数
function f1()
  local _ENV=env
  print("in f1:a=",a)
  a=a*10                        -- 修改的是新环境中的a值
end

f1()
print("globally:a=",a)
print("env.a=",env.a)

```

```
in f1:a=    10
globally:a= 1
env.a=  100

```

另外，新创建的闭包都继承了创建它的函数的环境。

### 模块

lua 中的模块也是通过返回一个表来供模块使用者来使用的。 这个表中包含的是模块中所导出的所有东西，包括函数和常量。

定义模块的一般模板为：

```
module(模块名, package.seeall)

```

其中 `module(模块名)` 的作用类似于：

```
local modname = 模块名
local M = {}                    -- M即为存放模块所有函数及常数的table
_G[modname] = M
package.loaded[modname] = M
setmetatable(M,{__index=_G})    -- package.seeall可以使全局环境_G对当前环境可见
local _ENV = M                  -- 设置当前的运行环境为 M，这样后续所有代码都不需要限定模块名了，所定义的所有函数自动变成M的成员
<函数定义以及常量定义>

return M                        -- module函数会帮你返回module table，而无需手工返回

```

### 对象

lua 中之所以可以把表当成对象来用是因为：

1. 函数在 lua 中是一类值，你可以直接存取表中的函数值。 这使得一个表既可以有自己的状态，也可以有自己的行为：

```
Account = {balance = 0}
function Account.withdraw(v)
  Account.balance = Account.balance - v
end

```
2. lua 支持闭包，这个特性可以用来模拟对象的私有成员变量：

```
function new_account(b)
  local balance = b
  return {withdraw = function (v) balance = balance -v end,
          get_balance = function () return balance end
  }
end

a1 = new_account(1000)
a1.withdraw(10)
print(a1.get_balance())

```

```
990

```

不过，上面第一种定义对象的方法有一个缺陷，那就是方法与 `Account` 这个名称绑定死了。 也就是说，这个对象的名称必须为 `Accout` 否则就会出错。

```
a = Account
Account = nil
a.withdraw(10)                  -- 会报错，因为Accout.balance不再存在

```

为了解决这个问题，我们可以给 `withdraw` 方法多一个参数用于指向对象本身。

```
Account = {balance=100}
function Account.withdraw(self,v)
  self.balance = self.balance - v
end
a = Account
Account = nil
a.withdraw(a,10)                  -- 没问题，这个时候 self 指向的是a，因此会去寻找 a.balance
print(a.balance)

```

```
90

```

不过由于第一个参数 `self` 几乎总是指向调用方法的对象本身，因此 lua 提供了一种语法糖形式 `object:method(...)` 用于隐藏 `self` 参数的定义及传递。这里冒号的作用有两个，其在定义函数时往函数中地一个参数的位置添加一个额外的隐藏参数 `sef`, 而在调用时传递一个额外的隐藏参数 `self` 到地一个参数位置。 即 `function object:method(v) end` 等价于 `function object.method(self,v) end`, `object:method(v)` 等价于 `object.method(object,v)`。

### 类

当涉及到类和继承时，就要用到元表和元方法了。事实上，对于 lua 来说，对象和类并不存在一个严格的划分。

当一个对象被另一个表的 `__index` 元方法所引用时，表就能引用该对象中所定义的方法，因此也就可以理解为对象变成了表的类。

类定义的一般模板为:

```
function 类名:new(o)
  o = o or {}
  setmetatable(o,{__index = self})
  return o
end

```

或者：

```
function 类名:new(o)
  o = o or {}
  setmetatable(o,self)
  self.__index = self
  return o
end

```

相比之下，第二种写法可以多省略一个表。

另外有一点我觉得有必要说明的就是 lua 中的元方法是在元表中定义的，而不是对象本身定义的，这一点跟其他面向对象的语言比较不同。


4 种用于构建嵌入式 Linux 系统的工具

>
> 了解 Yocto、Buildroot、 OpenWRT，和改造过的桌面发行版以确定哪种方式最适合你的项目。
>
>
>

![](/data/attachment/album/201807/06/095532wzz9flhboh6anfcw.jpg)

Linux 被部署到比 Linus Torvalds 在他的宿舍里开发时所预期的更广泛的设备。令人震惊的支持了各种芯片，使得Linux 可以应用于大大小小的设备上：从 [IBM 的巨型机](https://en.wikipedia.org/wiki/Linux_on_z_Systems)到不如其连接的端口大的[微型设备](http://www.picotux.com/)，以及各种大小的设备。它被用于大型企业数据中心、互联网基础设施设备和个人的开发系统。它还为消费类电子产品、移动电话和许多物联网设备提供了动力。

在为桌面和企业级设备构建 Linux 软件时，开发者通常在他们的构建机器上使用桌面发行版，如 [Ubuntu](https://www.ubuntu.com/) 以便尽可能与被部署的机器相似。如 [VirtualBox](https://www.virtualbox.org/) 和 [Docker](https://www.docker.com/) 这样的工具使得开发、测试和生产环境更好的保持了一致。

### 什么是嵌入式系统？

维基百科将[嵌入式系统](https://en.wikipedia.org/wiki/Embedded_system)定义为：“在更大的机械或电气系统中具有专用功能的计算机系统，往往伴随着实时计算限制。”

我觉得可以很简单地说，嵌入式系统是大多数人不认为是计算机的计算机。它的主要作用是作为某种设备，而不被视为通用计算平台。

嵌入式系统编程的开发环境通常与测试和生产环境大不相同。它们可能会使用不同的芯片架构、软件堆栈甚至操作系统。开发工作流程对于嵌入式开发人员与桌面和 Web 开发人员来说是非常不同的。通常，其构建后的输出将包含目标设备的整个软件映像，包括内核、设备驱动程序、库和应用程序软件（有时也包括引导加载程序）。

在本文中，我将对构建嵌入式 Linux 系统的四种常用方式进行纵览。我将介绍一下每种产品的工作原理，并提供足够的信息来帮助读者确定使用哪种工具进行设计。我不会教你如何使用它们中的任何一个；一旦缩小了选择范围，就有大量深入的在线学习资源。没有任何选择适用于所有情况，我希望提供足够的细节来指导您的决定。

### Yocto

[Yocto](https://yoctoproject.org/) 项目 [定义](https://www.yoctoproject.org/about/)为“一个开源协作项目，提供模板、工具和方法，帮助您为嵌入式产品创建定制的基于 Linux 的系统，而不管硬件架构如何。”它是用于创建定制的 Linux 运行时映像的配方、配置值和依赖关系的集合，可根据您的特定需求进行定制。

完全公开：我在嵌入式 Linux 中的大部分工作都集中在 Yocto 项目上，而且我对这个系统的认识和偏见可能很明显。

Yocto 使用 [Openembedded](https://www.openembedded.org/) 作为其构建系统。从技术上讲，这两个是独立的项目；然而，在实践中，用户不需要了解区别，项目名称经常可以互换使用。

Yocto 项目的输出大致由三部分组成：

* **目标运行时二进制文件：**这些包括引导加载程序、内核、内核模块、根文件系统映像。以及将 Linux 部署到目标平台所需的任何其他辅助文件。
* **包流：**这是可以安装在目标上的软件包集合。您可以根据需要选择软件包格式（例如，deb、rpm、ipk）。其中一些可能预先安装在目标运行时二进制文件中，但可以构建用于安装到已部署系统的软件包。
* **目标 SDK：**这些是安装在目标平台上的软件的库和头文件的集合。应用程序开发人员在构建代码时使用它们，以确保它们与适当的库链接

#### 优点

Yocto 项目在行业中得到广泛应用，并得到许多有影响力的公司的支持。此外，它还拥有一个庞大且充满活力的开发人员[社区](https://www.yoctoproject.org/community/)和[生态系统](https://www.yoctoproject.org/ecosystem/participants/)。开源爱好者和企业赞助商的结合的方式有助于推动 Yocto 项目。

获得 Yocto 的支持有很多选择。如果您想自己动手，有书籍和其他培训材料。如果您想获得专业知识，有许多有 Yocto 经验的工程师。而且许多商业组织可以为您的设计提供基于 Yocto 的 Turnkey 产品或基于服务的实施和定制。

Yocto 项目很容易通过 [层](https://layers.openembedded.org/layerindex/branch/master/layers/) 进行扩展，层可以独立发布以添加额外的功能，或针对项目发布时尚不可用的平台，或用于保存系统特有定制功能。层可以添加到你的配置中，以添加未特别包含在市面上版本中的独特功能；例如，“[meta-browser](https://layers.openembedded.org/layerindex/branch/master/layer/meta-browser/)” 层包含 Web 浏览器的清单，可以轻松为您的系统进行构建。因为它们是独立维护的，所以层可以按不同的时间发布（根据层的开发速度），而不是跟着标准的 Yocto 版本发布。

Yocto 可以说是本文讨论的任何方式中最广泛的设备支持。由于许多半导体和电路板制造商的支持，Yocto 很可能能够支持您选择的任何目标平台。主版本 Yocto [分支](https://yoctoproject.org/downloads)仅支持少数几块主板（以便达成合理的测试和发布周期），但是，标准工作模式是使用外部主板支持层。

最后，Yocto 非常灵活和可定制。您的特定应用程序的自定义可以存储在一个层进行封装和隔离，通常将要素层特有的自定义项存储为层本身的一部分，这可以将相同的设置同时应用于多个系统配置。Yocto 还提供了一个定义良好的层优先和覆盖功能。这使您可以定义层应用和搜索元数据的顺序。它还使您可以覆盖具有更高优先级的层的设置；例如，现有清单的许多自定义功能都将保留。

#### 缺点

Yocto 项目最大的缺点是学习曲线陡峭。学习该系统并真正理解系统需要花费大量的时间和精力。 根据您的需求，这可能对您的应用程序不重要的技术和能力投入太大。 在这种情况下，与一家商业供应商合作可能是一个不错的选择。

Yocto 项目的开发时间和资源相当高。 需要构建的包（包括工具链，内核和所有目标运行时组件）的数量相当不少。 Yocto 开发人员的开发工作站往往是大型系统。 不建议使用小型笔记本电脑。 这可以通过使用许多提供商提供的基于云的构建服务器来缓解。 另外，Yocto 有一个内置的缓存机制，当它确定用于构建特定包的参数没有改变时，它允许它重新使用先前构建的组件。

#### 建议

为您的下一个嵌入式 Linux 设计使用 Yocto 项目是一个强有力的选择。 在这里介绍的选项中，无论您的目标用例如何，它都是最广泛适用的。 广泛的行业支持，积极的社区和广泛的平台支持使其成为必须设计师的不错选择。

### Buildroot

[Buildroot](https://buildroot.org/) 项目定义为“通过交叉编译生成嵌入式 Linux 系统的简单、高效且易于使用的工具。”它与 Yocto 项目具有许多相同的目标，但它注重简单性和简约性。一般来说，Buildroot 会禁用所有软件包的所有可选编译时设置（有一些值得注意的例外），从而生成尽可能小的系统。系统设计人员需要启用适用于给定设备的设置。

Buildroot 从源代码构建所有组件，但不支持按目标包管理。因此，它有时称为固件生成器，因为镜像在构建时大部分是固定的。应用程序可以更新目标文件系统，但是没有机制将新软件包安装到正在运行的系统中。

Buildroot 输出主要由三部分组成：

* 将 Linux 部署到目标平台所需的根文件系统映像和任何其他辅助文件
* 适用于目标硬件的内核，引导加载程序和内核模块
* 用于构建所有目标二进制文件的工具链。

#### 优点

Buildroot 对简单性的关注意味着，一般来说，它比 Yocto 更容易学习。核心构建系统用 Make 编写，并且足够短以便开发人员了解整个系统，同时可扩展到足以满足嵌入式 Linux 开发人员的需求。 Buildroot 核心通常只处理常见用例，但它可以通过脚本进行扩展。

Buildroot 系统使用普通的 Makefile 和 Kconfig 语言来进行配置。 Kconfig 由 Linux 内核社区开发，广泛用于开源项目，使得许多开发人员都熟悉它。

由于禁用所有可选的构建时设置的设计目标，Buildroot 通常会使用开箱即用的配置生成尽可能最小的镜像。一般来说，构建时间和构建主机资源的规模将比 Yocto 项目的规模更小。

#### 缺点

关注简单性和最小化启用的构建方式意味着您可能需要执行大量的自定义来为应用程序配置 Buildroot 构建。此外，所有配置选项都存储在单个文件中，这意味着如果您有多个硬件平台，则需要为每个平台进行每个定制更改。

对系统配置文件的任何更改都需要全部重新构建所有软件包。与 Yocto 相比，这个问题通过最小的镜像大小和构建时间得到了一定的解决，但在你调整配置时可能会导致构建时间过长。

中间软件包状态缓存默认情况下未启用，并且不像 Yocto 实施那么彻底。这意味着，虽然第一次构建可能比等效的 Yocto 构建短，但后续构建可能需要重建许多组件。

#### 建议

对于大多数应用程序，使用 Buildroot 进行下一个嵌入式 Linux 设计是一个不错的选择。如果您的设计需要多种硬件类型或其他差异，但由于同步多个配置的复杂性，您可能需要重新考虑，但对于由单一设置组成的系统，Buildroot 可能适合您。

### OpenWRT/LEDE

[OpenWRT](https://openwrt.org/) 项目开始为消费类路由器开发定制固件。您当地零售商提供的许多低成本路由器都可以运行 Linux 系统，但可能无法开箱即用。这些路由器的制造商可能无法提供频繁的更新来解决新的威胁，即使他们这样做，安装更新镜像的机制也很困难且容易出错。 OpenWRT 项目为许多已被其制造商放弃的设备生成更新的固件镜像，让这些设备焕发新生。

OpenWRT 项目的主要交付物是可用于大量商业设备的二进制镜像。它有网络可访问的软件包存储库，允许设备最终用户将新软件添加到他们的系统中。 OpenWRT 构建系统是一个通用构建系统，它允许开发人员创建自定义版本以满足他们自己的需求并添加新软件包，但其主要重点是目标二进制文件。

#### 优点

如果您正在为商业设备寻找替代固件，则 OpenWRT 应位于您的选项列表中。它的维护良好，可以保护您免受制造商固件无法解决的问题。您也可以添加额外的功能，使您的设备更有用。

如果您的嵌入式设计专注于网络，则 OpenWRT 是一个不错的选择。网络应用程序是 OpenWRT 的主要用例，您可能会发现许多可用的软件包。

#### 缺点

OpenWRT 对您的设计限制很多（与 Yocto 和 Buildroot 相比）。如果这些决定不符合您的设计目标，则可能需要进行大量的修改。

在部署的设备中允许基于软件包的更新是很难管理的。按照其定义，这会导致与您的 QA 团队测试的软件负载不同。此外，很难保证大多数软件包管理器的原子安装，以及错误的电源循环可能会使您的设备处于不可预知的状态。

#### 建议

OpenWRT 是爱好者项目或商用硬件再利用的不错选择。它也是网络应用程序的不错选择。如果您需要从默认设置进行大量定制，您可能更喜欢 Buildroot 或 Yocto。

### 桌面发行版

设计嵌入式 Linux 系统的一种常见方法是从桌面发行版开始，例如 [Debian](https://www.debian.org/) 或 [Red Hat](https://www.redhat.com/)，并删除不需要的组件，直到安装的镜像符合目标设备的占用空间。这是 [Raspberry Pi](https://www.raspberrypi.org/) 平台流行的 [Raspbian](https://www.raspbian.org/)发行版的方法。

#### 优点

这种方法的主要优点是熟悉。通常，嵌入式 Linux 开发人员也是桌面 Linux 用户，并且精通他们的选择发行版。在目标上使用类似的环境可能会让开发人员更快地入门。根据所选的分布，可以使用 apt 和 yum 等标准封装工具安装许多其他工具。

可以将显示器和键盘连接到目标设备，并直接在那里进行所有的开发。对于不熟悉嵌入式空间的开发人员来说，这可能是一个更为熟悉的环境，无需配置和使用棘手的跨开发平台设置。

大多数桌面发行版可用的软件包数量通常大于前面讨论的嵌入式特定的构建器可用软件包数量。由于较大的用户群和更广泛的用例，您可能能够找到您的应用程序所需的所有运行时包，这些包已经构建并可供使用。

#### 缺点

将目标平台作为您的主要开发环境可能会很慢。运行编译器工具是一项资源密集型操作，根据您构建的代码的多少，这可能会严重妨碍您的性能。

除了一些例外情况，桌面发行版的设计并不适合低资源系统，并且可能难以充分裁剪目标映像。同样，桌面环境中的预设工作流程对于大多数嵌入式设计来说都不理想。以这种方式获得可再现的环境很困难。手动添加和删除软件包很容易出错。这可以使用特定于发行版的工具进行脚本化，例如基于 Debian 系统的 [debootstrap](https://wiki.debian.org/Debootstrap)。为了进一步提高[可再现性](https://wiki.debian.org/Debootstrap)，您可以使用配置管理工具，如 [CFEngine](https://cfengine.com/)（我的雇主 [Mender.io](http://Mender.io) 完整披露了 这一工具）。但是，您仍然受发行版提供商的支配，他们将更新软件包以满足他们的需求，而不是您的需求。

#### 建议

对于您打算推向市场的产品，请谨慎使用此方法。这对于爱好者应用程序来说是一个很好的模型；但是，对于需要支持的产品，这种方法很可能会遇到麻烦。虽然您可能能够获得更快的起步，但从长远来看，您可能会花费您的时间和精力。

### 其他考虑

这个讨论集中在构建系统的功能上，但通常有非功能性需求可能会影响您的决定。如果您已经选择了片上系统（SoC）或电路板，则您的选择很可能由供应商决定。如果您的供应商为特定系统提供板级支持包（BSP），使用它通常会节省相当多的时间，但请研究 BSP 的质量以避免在开发周期后期发生问题。

如果您的预算允许，您可能需要考虑为目标操作系统使用商业供应商。有些公司会为这里讨论的许多选项提供经过验证和支持的配置，除非您拥有嵌入式 Linux 构建系统方面的专业知识，否则这是一个不错的选择，可以让您专注于核心能力。

作为替代，您可以考虑为您的开发人员进行商业培训。这可能比商业操作系统供应商便宜，并且可以让你更加自给自足。这是快速找到您选择的构建系统基础知识的学习曲线。

最后，您可能已经有一些开发人员拥有一个或多个系统的经验。如果你的工程师有倾向性，当你做出决定时，肯定值得考虑。

### 总结

构建嵌入式 Linux 系统有多种选择，每种都有优点和缺点。将这部分设计放在优先位置至关重要，因为在以后的过程中切换系统的成本非常高。除了这些选择之外，还有新的系统在开发中。希望这次讨论能够为评估新的系统（以及这里提到的系统）提供一些背景，并帮助您为下一个项目做出坚实的决定。

---

via: <https://opensource.com/article/18/6/embedded-linux-build-tools>

作者：[Drew Moseley](https://opensource.com/users/drewmoseley) 选题：[lujun9972](https://github.com/lujun9972) 译者：[LHRChina](https://github.com/LHRChina) 校对：[wxy](https://github.com/wxy)

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


Linux 上的五个开源益智游戏

Summary: 用这些有趣好玩的游戏来测试你的战略能力。

用这些有趣好玩的游戏来测试你的战略能力。

>
> 用这些有趣好玩的游戏来测试你的战略能力。
>
>
>

![](/data/attachment/album/201807/06/101051t97eexcgecvju9z7.jpg)

游戏一直是 Linux 的弱点之一。由于 Steam、GOG 和其他将商业游戏引入多种操作系统的努力，这种情况近年来有所改变，但这些游戏通常不是开源的。当然，这些游戏可以在开源操作系统上玩，但对于纯粹开源主义者来说还不够好。

那么，一个只使用开源软件的人，能否找到那些经过足够打磨的游戏，在不损害其开源理念的前提下，提供一种可靠的游戏体验呢？当然可以。虽然开源游戏历来不太可能与一些借由大量预算开发的 AAA 商业游戏相匹敌，但在多种类型的开源游戏中，有很多都很有趣，可以从大多数主要 Linux 发行版的仓库中安装。即使某个特定的游戏没有被打包成特定的发行版本，通常也很容易从项目的网站上下载该游戏以便安装和游戏。

这篇文章着眼于益智游戏。我已经写过[街机风格游戏](https://opensource.com/article/18/1/arcade-games-linux)和[棋牌游戏](https://opensource.com/article/18/3/card-board-games-linux)。 在之后的文章中，我计划涉足赛车，角色扮演、战略和模拟经营游戏。

### Atomix

![](/data/attachment/album/201807/06/101052de8p7gbk0ygs49e2.png)

[Atomix](https://wiki.gnome.org/action/raw/Apps/Atomix) 是 1990 年在 Amiga、Commodore 64、MS-DOS 和其他平台发布的 [Atomix](https://en.wikipedia.org/w/index.php?title=Atomix_(video_game)) 益智游戏的开源克隆。Atomix 的目标是通过连接原子来构建原子分子。单个原子可以向上、向下、向左或向右移动，并一直朝这个方向移动，直到原子撞上一个障碍物——水平墙或另一个原子。这意味着需要进行规划，以确定在水平上构建分子的位置，以及移动单个部件的顺序。第一关是一个简单的水分子，它由两个氢原子和一个氧原子组成，但后来的关卡是更复杂的分子。

要安装 Atomix，请运行以下命令:

* 在 Fedora： `dnf install atomix`
* 在 Debian/Ubuntu： `apt install atomix`

### Fish Fillets - Next Generation

![](/data/attachment/album/201807/06/101054l6j4hjcmackzp66a.png)

[Fish Fillets - Next Generation](http://fillets.sourceforge.net/index.php) 是游戏 Fish fillet 的 Linux 移植版本，它于 1998 年在 Windows 发布，源代码在 2004 年以 GPL 许可证发布。游戏中，两条鱼试图将物体移出道路来通过不同的关卡。这两条鱼有不同的属性，所以玩家需要为每个任务挑选合适的鱼。较大的鱼可以移动较重的物体，但它更大，这意味着它不适合较小的空隙。较小的鱼可以适应那些较小的间隙，但它不能移动较重的物体。如果一个物体从上面掉下来，两条鱼都会被压死，所以玩家在移动棋子时要小心。

要安装 Fish fillet——Next Generation，请运行以下命令:

* 在 Fedora：`dnf install fillets-ng`
* 在 Debian/Ubuntu： `apt install fillets-ng`

### Frozen Bubble

![](/data/attachment/album/201807/06/101055l1clclvdg9s8rl9l.png)

[Frozen Bubble](http://www.frozen-bubble.org/home/) 是一款街机风格的益智游戏，从屏幕底部向屏幕顶部的一堆泡泡射击。如果三个相同颜色的气泡连接在一起，它们就会被从屏幕上移除。任何连接在被移除的气泡下面但没有连接其他任何东西的气泡也会被移除。在拼图模式下，关卡的设计是固定的，玩家只需要在泡泡掉到屏幕底部的线以下前将泡泡从游戏区域中移除。该游戏街机模式和多人模式遵循相同的基本规则，但也有不同，这增加了多样性。Frozen Bubble 是一个标志性的开源游戏，所以如果你以前没有玩过它，玩玩看。

要安装 Frozen Bubble，请运行以下命令：

* 在 Fedora： `dnf install frozen-bubble`
* 在 Debian/Ubuntu： `apt install frozen-bubble`

### Hex-a-hop

![](/data/attachment/album/201807/06/101055losg916i066sozbb.png)

[Hex-a-hop](http://hexahop.sourceforge.net/index.html) 是一款基于六角形瓦片的益智游戏，玩家需要将所有的绿色瓦片从水平面上移除。瓦片通过移动被移除。由于瓦片在移动后会消失，所以有必要规划出穿过水平面的最佳路径，以便在不被卡住的情况下移除所有的瓦片。但是，如果玩家使用的是次优路径，会有撤销功能。之后的关卡增加了额外的复杂性，包括需要跨越多次的瓦片和使玩家跳过一定数量的六角弹跳瓦片。

要安装 Hex-a-hop，请运行以下命令：

* 在 Fedora： `dnf install hex-a-hop`
* 在 Debian/Ubuntu： `apt install hex-a-hop`

### Pingus

![](/data/attachment/album/201807/06/101056vzqs8u5aisnty46q.png)

[Pingus](https://pingus.seul.org/index.html) 是 [Lemmings](http://en.wikipedia.org/wiki/Lemmings) 的开源克隆。这不是一个精确的克隆，但游戏非常相似。小动物（Lemmings 里是旅鼠，Pingus 里是企鹅）通过关卡入口进入关卡，开始沿着直线行走。玩家需要使用特殊技能使小动物能够到达关卡的出口而不会被困住或者掉下悬崖。这些技能包括挖掘或建桥。如果有足够数量的小动物进入出口，这个关卡将成功完成，玩家可以进入下一个关卡。Pingus 为标准的 Lemmings 添加了一些额外的特性，包括一个世界地图和一些在原版游戏中没有的技能，但经典 Lemmings 游戏的粉丝们在这个开源版本中仍会感到自在。

要安装 Pingus，请运行以下命令：

* 在 Fedora： `dnf install pingus`
* 在 Debian/Ubuntu： `apt install pingus`

我漏掉你最喜欢的开源益智游戏了吗? 请在下面的评论中分享。

---

via: <https://opensource.com/article/18/6/puzzle-games-linux>

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

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


使用 LSWC 在 Linux 中自动更改壁纸

Summary: 这是一个小脚本，可以在 Linux 桌面上定期自动更改壁纸。

这是一个小脚本，可以在 Linux 桌面上定期自动更改壁纸。

>
> 简介：这是一个小脚本，可以在 Linux 桌面上定期自动更改壁纸。
>
>
>

顾名思义，LittleSimpleWallpaperChanger （LSWC）是一个小脚本，可以定期地随机更改壁纸。

我知道在“外观”或“更改桌面背景”设置中有一个随机壁纸选项。但那是随机更改预置的壁纸而不是你添加的壁纸。

因此，在本文中，我们将看到如何使用 LittleSimpleWallpaperChanger 设置包含照片的随机桌面壁纸。

### Little Simple Wallpaper Changer (LSWC)

[LittleSimpleWallpaperChanger](https://github.com/LittleSimpleWallpaperChanger/lswc) （LSWC） 是一个非常轻量级的脚本，它在后台运行，从用户指定的文件夹中更改壁纸。壁纸以 1 至 5 分钟的随机间隔变化。该软件设置起来相当简单，设置完后，用户就可以不用再操心了。

![Little Simple Wallpaper Changer to change wallpapers in Linux](/data/attachment/album/201807/07/140202q045bz1cqug47t4z.jpg)

#### 安装 LSWC

[点此链接下载 LSWC](https://github.com/LittleSimpleWallpaperChanger/lswc/raw/master/Lswc.zip)。压缩文件的大小约为 15KB。

* 进入下载位置。
* 右键单击下载的 .zip 文件，然后选择“在此处解压”。
* 打开解压后的文件夹，右键单击并选择“在终端中打开”。
* 在终端中复制粘贴命令 `bash ./README_and_install.sh` 并按回车键。
* 然后会弹出一个对话框，要求你选择包含壁纸的文件夹。单击它，然后选择你存放壁纸的文件夹。
* 就是这样。然后重启计算机。

![Little Simple Wallpaper Changer for Linux](/data/attachment/album/201807/07/140203q1zg8u6gu1wf11mt.jpg)

#### 使用 LSWC

安装时，LSWC 会要求你选择包含壁纸的文件夹。因此，我建议你在安装 LSWC 之前创建一个文件夹并将你想要的壁纸全部移动到那。或者你可以使用图片文件夹中的“壁纸”文件夹。**所有壁纸都必须是 .jpg 格式。**

你可以添加更多壁纸或从所选文件夹中删除当前壁纸。要更改壁纸文件夹位置，你可以从以下文件中编辑壁纸的位置。

```
.config/lswc/homepath.conf

```

#### 删除 LSWC

打开终端并运行以下命令以停止 LSWC：

```
pkill lswc

```

在文件管理器中打开家目录，然后按 `Ctrl+H` 显示隐藏文件，接着删除以下文件：

* `.local` 中的 `scripts` 文件夹
* `.config` 中的 `lswc` 文件夹
* `.config/autostart` 中的 `lswc.desktop` 文件

这就完成了。创建自己的桌面背景幻灯片。LSWC 非常轻巧，易于使用。安装它然后忘记它。

LSWC 功能不是很丰富，但这是有意的。它做了它打算做的事情，那就是更换壁纸。如果你想要一个自动下载壁纸的工具试试 [WallpaperDownloader](https://itsfoss.com/wallpaperdownloader-linux/)。

请在下面的评论栏分享你对这个漂亮的小软件的想法。别忘了分享这篇文章。干杯。

---

via: <https://itsfoss.com/little-simple-wallpaper-changer/>

作者：[Aquil Roshan](https://itsfoss.com/author/aquil/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

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


为什么 Python 开发人员应该使用 Pipenv

看官网也没看明白这玩意.

两个问题

1. Pipfile 和 Pipfile.lock 里面的 pip 源地址, pipenv install 的时候怎么才能让他自己替换成阿里的, 官网的 --pypi-mirror 还有 url 选项都不好使啊

2. 想弄一个一模一样的环境,  迁移的时候, 具体什么步骤, 两个文件移哪个, 实验了好多遍, 不得其法呀

恰巧最近在用, 有大神知道的么??

>
> 只用了一年， Pipenv 就变成了管理软件包依赖关系的 Python 官方推荐资源。
>
>
>

![](/data/attachment/album/201807/07/142824cermze96p8tzaznb.jpg)

Pipenv 是由 Kenneth Reitz 在一年多前创建的“面向开发者而生的 Python 开发工作流”，它已经成为管理软件包依赖关系的 [Python 官方推荐资源](https://packaging.python.org/tutorials/managing-dependencies/#managing-dependencies)。但是对于它解决了什么问题，以及它如何比使用 `pip` 和 `requirements.txt` 文件的标准工作流更有用处，这两点仍然存在困惑。在本月的 Python 专栏中，我们将填补这些空白。

### Python 包安装简史

为了理解 Pipenv 所解决的问题，看一看 Python 包管理如何发展十分有用的。

让我们回到第一个 Python 版本，这时我们有了 Python，但是没有干净的方法来安装软件包。

然后有了 [Easy Install](http://peak.telecommunity.com/DevCenter/EasyInstall)，这是一个可以相对容易地安装其他 Python 包的软件包，但它也带来了一个问题：卸载不需要的包并不容易。

[pip](https://packaging.python.org/tutorials/installing-packages/#use-pip-for-installing) 登场，绝大多数 Python 用户都熟悉它。`pip` 可以让我们安装和卸载包。我们可以指定版本，运行 `pip freeze > requirements.txt` 来输出一个已安装包列表到一个文本文件，还可以用相同的文本文件配合 `pip install -r requirements.txt` 来安装一个应用程序需要的所有包。

但是 `pip` 并没有包含将软件包彼此隔离的方法。我们可能会开发使用相同库的不同版本的应用程序，因此我们需要一种方法来实现这一点。随之而来的是[虚拟环境](https://packaging.python.org/tutorials/installing-packages/#creating-virtual-environments)，它使我们能够为我们开发的每个应用程序创建一个小型的、隔离的环境。我们已经看到了许多管理虚拟环境的工具：[virtualenv](https://virtualenv.pypa.io/en/stable/)、 [venv](https://docs.python.org/3/library/venv.html)、 [virtualenvwrapper](https://virtualenvwrapper.readthedocs.io/en/latest/)、 [pyenv](https://github.com/pyenv/pyenv)、 [pyenv-virtualenv](https://github.com/pyenv/pyenv-virtualenv)、 [pyenv-virtualenvwrapper](https://github.com/pyenv/pyenv-virtualenvwrapper) 等等。它们都可以很好地使用 `pip` 和 `requirements.txt` 文件。

### 新方法：Pipenv

Pipenv 旨在解决几个问题：

首先，需要 `pip` 库来安装包，外加一个用于创建虚拟环境的库，以及用于管理虚拟环境的库，再有与这些库相关的所有命令。这些都需要管理。Pipenv 附带包管理和虚拟环境支持，因此你可以使用一个工具来安装、卸载、跟踪和记录依赖性，并创建、使用和组织你的虚拟环境。当你使用它启动一个项目时，如果你还没有使用虚拟环境的话，Pipenv 将自动为该项目创建一个虚拟环境。

Pipenv 通过放弃 `requirements.txt` 规范转而将其移动到一个名为 [Pipfile](https://github.com/pypa/pipfile) 的新文档中来完成这种依赖管理。当你使用 Pipenv 安装一个库时，项目的 `Pipfile` 会自动更新安装细节，包括版本信息，还有可能的 Git 仓库位置、文件路径和其他信息。

其次，Pipenv 希望能更容易地管理复杂的相互依赖关系。你的应用程序可能依赖于某个特定版本的库，而那个库可能依赖于另一个特定版本的库，这些依赖关系如海龟般堆叠起来。当你的应用程序使用的两个库有冲突的依赖关系时，你的情况会变得很艰难。Pipenv 希望通过在一个名为 `Pipfile.lock` 的文件中跟踪应用程序相互依赖关系树来减轻这种痛苦。`Pipfile.lock` 还会验证生产中是否使用了正确版本的依赖关系。

另外，当多个开发人员在开发一个项目时，Pipenv 很方便。通过 `pip` 工作流，凯西可能会安装一个库，并花两天时间使用该库实现一个新功能。当凯西提交更改时，他可能会忘记运行 `pip freeze` 来更新 `requirements.txt` 文件。第二天，杰米拉取凯西的改变，测试就突然失败了。这样会花费好一会儿才能意识到问题是在 `requirements.txt` 文件中缺少相关库，而杰米尚未在虚拟环境中安装这些文件。

因为 Pipenv 会在安装时自动记录依赖性，如果杰米和凯西使用了 Pipenv，`Pipfile` 会自动更新并包含在凯西的提交中。这样杰米和凯西就可以节省时间并更快地运送他们的产品。

最后，将 Pipenv 推荐给在你项目上工作的其他人，因为它使用标准化的方式来安装项目依赖项和开发和测试的需求。使用 `pip` 工作流和 `requirements.txt` 文件意味着你可能只有一个 `requirements.txt` 文件，或针对不同环境的多个 `requirements.txt` 文件。例如，你的同事可能不清楚他们是否应该在他们的笔记本电脑上运行项目时是运行 `dev.txt` 还是 `local.txt`。当两个相似的 `requirements.txt` 文件彼此不同步时它也会造成混淆：`local.txt` 是否过时了，还是真的应该与 `dev.txt` 不同？多个 `requirements.txt` 文件需要更多的上下文和文档，以使其他人能够按照预期正确安装依赖关系。这个工作流程有可能会混淆同时并增加你的维护负担。

使用 Pipenv，它会生成 `Pipfile`，通过为你管理对不同环境的依赖关系，可以避免这些问题。该命令将安装主项目依赖项：

```
pipenv install

```

添加 `--dev` 标志将安装开发/测试的 `requirements.txt`：

```
pipenv install --dev

```

使用 Pipenv 还有其他好处：它具有更好的安全特性，以易于理解的格式绘制你的依赖关系，无缝处理 `.env` 文件，并且可以在一个文件中自动处理开发与生产环境的不同依赖关系。你可以在[文档](https://docs.pipenv.org/)中阅读更多内容。

### 使用 Pipenv

使用 Pipenv 的基础知识在官方 Python 包管理教程[管理应用程序依赖关系](https://packaging.python.org/tutorials/managing-dependencies/)部分中详细介绍。要安装 Pipenv，使用 `pip`：

```
pip install pipenv

```

要安装在项目中使用的包，请更改为项目的目录。然后安装一个包（我们将使用 Django 作为例子），运行：

```
pipenv install django

```

你会看到一些输出，表明 Pipenv 正在为你的项目创建一个 `Pipfile`。

如果你还没有使用虚拟环境，你还会看到 Pipenv 的一些输出，说明它正在为你创建一个虚拟环境。

然后，你将看到你在安装包时常看到的输出。

为了生成 `Pipfile.lock` 文件，运行：

```
pipenv lock

```

你也可以使用 Pipenv 运行 Python 脚本。运行名为 `hello.py` 的上层 Python 脚本：

```
pipenv run python hello.py

```

你将在控制台中看到预期结果。

启动一个 shell，运行：

```
pipenv shell

```

如果你想将当前使用 `requirements.txt` 文件的项目转换为使用 Pipenv，请安装 Pipenv 并运行：

```
pipenv install requirements.txt

```

这将创建一个 Pipfile 并安装指定的 `requirements.txt`。考虑一下升级你的项目！

### 了解更多

查看 Pipenv 文档，特别是 [Pipenv 的基本用法](https://docs.pipenv.org/basics/)，以帮助你进一步学习。Pipenv 的创建者 Kenneth Reitz 为 Pipenv 在最近的 PyTennessee 发表了一篇演讲：“[Python 依赖管理的未来](https://www.pytennessee.org/schedule/presentation/158/)”。这次演讲没有被记录下来，但他的[幻灯片](https://speakerdeck.com/kennethreitz/the-future-of-python-dependency-management)有助于理解 Pipenv 所做的以及解决的问题。

---

via: <https://opensource.com/article/18/2/why-python-devs-should-use-pipenv>

作者：[Lacey Williams Henschel](https://opensource.com/users/laceynwilliams), [Jeff Triplett](https://opensource.com/users/jefftriplett) 译者：[MjSeven](https://github.com/MjSeven) 校对：[wxy](https://github.com/wxy)

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


JavaScript 路由器

![](/data/attachment/album/201807/07/144603n00b0ma2bmlmnx0l.jpg)

构建单页面应用（SPA）有许多的框架/库，但是我希望它们能少一些。我有一个解决方案，我想共享给大家。

```
class Router {
    constructor() {
        this.routes = []
    }

    handle(pattern, handler) {
        this.routes.push({ pattern, handler })
    }

    exec(pathname) {
        for (const route of this.routes) {
            if (typeof route.pattern === 'string') {
                if (route.pattern === pathname) {
                    return route.handler()
                }
            } else if (route.pattern instanceof RegExp) {
                const result = pathname.match(route.pattern)
                if (result !== null) {
                    const params = result.slice(1).map(decodeURIComponent)
                    return route.handler(...params)
                }
            }
        }
    }
}
const router = new Router()

router.handle('/', homePage)
router.handle(/^\/users\/([^\/]+)$/, userPage)
router.handle(/^\//, notFoundPage)

function homePage() {
    return 'home page'
}

function userPage(username) {
    return `${username}'s page`
}

function notFoundPage() {
    return 'not found page'
}

console.log(router.exec('/')) // home page
console.log(router.exec('/users/john')) // john's page
console.log(router.exec('/foo')) // not found page

```

使用它你可以为一个 URL 模式添加处理程序。这个模式可能是一个简单的字符串或一个正则表达式。使用一个字符串将精确匹配它，但是如果使用一个正则表达式将允许你做一些更复杂的事情，比如，从用户页面上看到的 URL 中获取其中的一部分，或者匹配任何没有找到页面的 URL。

我将详细解释这个 `exec` 方法 … 正如我前面说的，URL 模式既有可能是一个字符串，也有可能是一个正则表达式，因此，我首先来检查它是否是一个字符串。如果模式与给定的路径名相同，它返回运行处理程序。如果是一个正则表达式，我们与给定的路径名进行匹配。如果匹配成功，它将获取的参数传递给处理程序，并返回运行这个处理程序。

### 工作示例

那个例子正好记录到了控制台。我们尝试将它整合到一个页面，看看它是什么样的。

```
<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Router Demo</title>
 <link rel="shortcut icon" href="data:,">
 <script src="/main.js" type="module"></script>
</head>
<body>
 <header>
 <a href="/">Home</a>
 <a href="/users/john_doe">Profile</a>
 </header>
 <main></main>
</body>
</html>

```

这是 `index.html`。对于单页面应用程序来说，你必须在服务器侧做一个特别的工作，因为所有未知的路径都将返回这个 `index.html`。在开发时，我们使用了一个 npm 工具调用了 [serve](https://npm.im/serve)。这个工具去提供静态内容。使用标志 `-s`/`--single`，你可以提供单页面应用程序。

使用 [Node.js](https://nodejs.org/) 和安装的 npm（它与 Node 一起安装），运行：

```
npm i -g serve
serve -s

```

那个 HTML 文件将脚本 `main.js` 加载为一个模块。在我们渲染的相关页面中，它有一个简单的 `<header>` 和一个 `<main>` 元素。

在 `main.js` 文件中：

```
const main = document.querySelector('main')
const result = router.exec(location.pathname)
main.innerHTML = result

```

我们调用传递了当前路径名为参数的 `router.exec()`，然后将 `result` 设置为 `main` 元素的 HTML。

如果你访问 `localhost` 并运行它，你将看到它能够正常工作，但不是预期中的来自一个单页面应用程序。当你点击链接时，单页面应用程序将不会被刷新。

我们将在每个点击的链接的锚点上附加事件监听器，防止出现缺省行为，并做出正确的渲染。因为一个单页面应用程序是一个动态的东西，你预期要创建的锚点链接是动态的，因此要添加事件监听器，我使用的是一个叫 [事件委托](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_delegation) 的方法。

我给整个文档附加一个点击事件监听器，然后去检查在锚点上（或内部）是否有点击事件。

在 `Router` 类中，我有一个注册回调的方法，在我们每次点击一个链接或者一个 `popstate` 事件发生时，这个方法将被运行。每次你使用浏览器的返回或者前进按钮时，`popstate` 事件将被发送。

为了方便其见，我们给回调传递与 `router.exec(location.pathname)` 相同的参数。

```
class Router {
    // ...
    install(callback) {
        const execCallback = () => {
            callback(this.exec(location.pathname))
        }

        document.addEventListener('click', ev => {
            if (ev.defaultPrevented
                || ev.button !== 0
                || ev.ctrlKey
                || ev.shiftKey
                || ev.altKey
                || ev.metaKey) {
                return
            }

            const a = ev.target.closest('a')

            if (a === null
                || (a.target !== '' && a.target !== '_self')
                || a.hostname !== location.hostname) {
                return
            }

            ev.preventDefault()

            if (a.href !== location.href) {
                history.pushState(history.state, document.title, a.href)
                execCallback()
            }
        })

        addEventListener('popstate', execCallback)
        execCallback()
    }
}

```

对于链接的点击事件，除调用了回调之外，我们还使用 `history.pushState()` 去更新 URL。

我们将前面的 `main` 元素中的渲染移动到 `install` 回调中。

```
router.install(result => {
 main.innerHTML = result
})

```

#### DOM

你传递给路由器的这些处理程序并不需要返回一个字符串。如果你需要更多的东西，你可以返回实际的 DOM。如：

```
const homeTmpl = document.createElement('template')
homeTmpl.innerHTML = `
 <div class="container">
 <h1>Home Page</h1>
 </div>
`

function homePage() {
 const page = homeTmpl.content.cloneNode(true)
 // You can do `page.querySelector()` here...
 return page
}

```

现在，在 `install` 回调中，你可以去检查 `result` 是一个 `string` 还是一个 `Node`。

```
router.install(result => {
    if (typeof result === 'string') {
        main.innerHTML = result
    } else if (result instanceof Node) {
        main.innerHTML = ''
        main.appendChild(result)
    }
})

```

这些就是基本的功能。我希望将它共享出来，因为我将在下篇文章中使用到这个路由器。

我已经以一个 [npm 包](https://www.npmjs.com/package/@nicolasparada/router) 的形式将它发布了。

---

via: <https://nicolasparada.netlify.com/posts/js-router/>

作者：[Nicolás Parada](https://nicolasparada.netlify.com/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[qhwdw](https://github.com/qhwdw) 校对：[wxy](https://github.com/wxy)

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


Python 字节码介绍

>
> 了解 Python 字节码是什么，Python 如何使用它来执行你的代码，以及知道它是如何帮到你的。
>
>
>

![](/data/attachment/album/201807/08/072357fqngnbmjjqqbkkvk.jpg)

如果你曾经编写过 Python，或者只是使用过 Python，你或许经常会看到 Python 源代码文件——它们的名字以 `.py` 结尾。你可能还看到过其它类型的文件，比如以 `.pyc` 结尾的文件，或许你可能听说过它们就是 Python 的 “<ruby> 字节码 <rt>  bytecode </rt></ruby>” 文件。（在 Python 3 上这些可能不容易看到 —— 因为它们与你的 `.py` 文件不在同一个目录下，它们在一个叫 `__pycache__` 的子目录中）或者你也听说过，这是节省时间的一种方法，它可以避免每次运行 Python 时去重新解析源代码。

但是，除了 “噢，原来这就是 Python 字节码” 之外，你还知道这些文件能做什么吗？以及 Python 是如何使用它们的？

如果你不知道，那你走运了！今天我将带你了解 Python 的字节码是什么，Python 如何使用它去运行你的代码，以及知道它是如何帮助你的。

### Python 如何工作

Python 经常被介绍为它是一个解释型语言 —— 其中一个原因是在程序运行时，你的源代码被转换成 CPU 的原生指令 —— 但这样的看法只是部分正确。Python 与大多数解释型语言一样，确实是将源代码编译为一组虚拟机指令，并且 Python 解释器是针对相应的虚拟机实现的。这种中间格式被称为 “字节码”。

因此，这些 `.pyc` 文件是 Python 悄悄留下的，是为了让它们运行的 “更快”，或者是针对你的源代码的 “优化” 版本；它们是你的程序在 Python 虚拟机上运行的字节码指令。

我们来看一个示例。这里是用 Python 写的经典程序 “Hello, World!”：

```
def hello()
    print("Hello, World!")

```

下面是转换后的字节码（转换为人类可读的格式）：

```
2           0 LOAD_GLOBAL              0 (print)
            2 LOAD_CONST               1 ('Hello, World!')
            4 CALL_FUNCTION            1

```

如果你输入那个 `hello()` 函数，然后使用 [CPython](https://github.com/python/cpython) 解释器去运行它，那么上述列出的内容就是 Python 所运行的。它看起来可能有点奇怪，因此，我们来深入了解一下它都做了些什么。

### Python 虚拟机内幕

CPython 使用一个基于栈的虚拟机。也就是说，它完全面向栈数据结构的（你可以 “推入” 一个东西到栈 “顶”，或者，从栈 “顶” 上 “弹出” 一个东西来）。

CPython 使用三种类型的栈：

1. <ruby> 调用栈 <rt>  call stack </rt></ruby>。这是运行 Python 程序的主要结构。它为每个当前活动的函数调用使用了一个东西 —— “<ruby> 帧 <rt>  frame </rt></ruby>”，栈底是程序的入口点。每个函数调用推送一个新的帧到调用栈，每当函数调用返回后，这个帧被销毁。
2. 在每个帧中，有一个<ruby> 计算栈 <rt>  evaluation stack </rt></ruby> （也称为<ruby> 数据栈 <rt>  data stack </rt></ruby>）。这个栈就是 Python 函数运行的地方，运行的 Python 代码大多数是由推入到这个栈中的东西组成的，操作它们，然后在返回后销毁它们。
3. 在每个帧中，还有一个<ruby> 块栈 <rt>  block stack </rt></ruby>。它被 Python 用于去跟踪某些类型的控制结构：循环、`try` / `except` 块、以及 `with` 块，全部推入到块栈中，当你退出这些控制结构时，块栈被销毁。这将帮助 Python 了解任意给定时刻哪个块是活动的，比如，一个 `continue` 或者 `break` 语句可能影响正确的块。

大多数 Python 字节码指令操作的是当前调用栈帧的计算栈，虽然，还有一些指令可以做其它的事情（比如跳转到指定指令，或者操作块栈）。

为了更好地理解，假设我们有一些调用函数的代码，比如这个：`my_function(my_variable, 2)`。Python 将转换为一系列字节码指令：

1. 一个 `LOAD_NAME` 指令去查找函数对象 `my_function`，然后将它推入到计算栈的顶部
2. 另一个 `LOAD_NAME` 指令去查找变量 `my_variable`，然后将它推入到计算栈的顶部
3. 一个 `LOAD_CONST` 指令去推入一个实整数值 `2` 到计算栈的顶部
4. 一个 `CALL_FUNCTION` 指令

这个 `CALL_FUNCTION` 指令将有 2 个参数，它表示那个 Python 需要从栈顶弹出两个位置参数；然后函数将在它上面进行调用，并且它也同时被弹出（对于函数涉及的关键字参数，它使用另一个不同的指令 —— `CALL_FUNCTION_KW`，但使用的操作原则类似，以及第三个指令 —— `CALL_FUNCTION_EX`，它适用于函数调用涉及到参数使用 `*` 或 `**` 操作符的情况）。一旦 Python 拥有了这些之后，它将在调用栈上分配一个新帧，填充到函数调用的本地变量上，然后，运行那个帧内的 `my_function` 字节码。运行完成后，这个帧将被调用栈销毁，而在最初的帧内，`my_function` 的返回值将被推入到计算栈的顶部。

### 访问和理解 Python 字节码

如果你想玩转字节码，那么，Python 标准库中的 `dis` 模块将对你有非常大的帮助；`dis` 模块为 Python 字节码提供了一个 “反汇编”，它可以让你更容易地得到一个人类可读的版本，以及查找各种字节码指令。[`dis` 模块的文档](https://docs.python.org/3/library/dis.html) 可以让你遍历它的内容，并且提供一个字节码指令能够做什么和有什么样的参数的完整清单。

例如，获取上面的 `hello()` 函数的列表，可以在一个 Python 解析器中输入如下内容，然后运行它：

```
import dis
dis.dis(hello)

```

函数 `dis.dis()` 将反汇编一个函数、方法、类、模块、编译过的 Python 代码对象、或者字符串包含的源代码，以及显示出一个人类可读的版本。`dis` 模块中另一个方便的功能是 `distb()`。你可以给它传递一个 Python 追溯对象，或者在发生预期外情况时调用它，然后它将在发生预期外情况时反汇编调用栈上最顶端的函数，并显示它的字节码，以及插入一个指向到引发意外情况的指令的指针。

它也可以用于查看 Python 为每个函数构建的编译后的代码对象，因为运行一个函数将会用到这些代码对象的属性。这里有一个查看 `hello()` 函数的示例：

```
>>> hello.__code__
<code object hello at 0x104e46930, file "<stdin>", line 1>
>>> hello.__code__.co_consts
(None, 'Hello, World!')
>>> hello.__code__.co_varnames
()
>>> hello.__code__.co_names
('print',)

```

代码对象在函数中可以以属性 `__code__` 来访问，并且携带了一些重要的属性：

* `co_consts` 是存在于函数体内的任意实数的元组
* `co_varnames` 是函数体内使用的包含任意本地变量名字的元组
* `co_names` 是在函数体内引用的任意非本地名字的元组

许多字节码指令 —— 尤其是那些推入到栈中的加载值，或者在变量和属性中的存储值 —— 在这些元组中的索引作为它们参数。

因此，现在我们能够理解 `hello()` 函数中所列出的字节码：

1. `LOAD_GLOBAL 0`：告诉 Python 通过 `co_names` （它是 `print` 函数）的索引 0 上的名字去查找它指向的全局对象，然后将它推入到计算栈
2. `LOAD_CONST 1`：带入 `co_consts` 在索引 1 上的字面值，并将它推入（索引 0 上的字面值是 `None`，它表示在 `co_consts` 中，因为 Python 函数调用有一个隐式的返回值 `None`，如果没有显式的返回表达式，就返回这个隐式的值 ）。
3. `CALL_FUNCTION 1`：告诉 Python 去调用一个函数；它需要从栈中弹出一个位置参数，然后，新的栈顶将被函数调用。

“原始的” 字节码 —— 是非人类可读格式的字节 —— 也可以在代码对象上作为 `co_code` 属性可用。如果你有兴趣尝试手工反汇编一个函数时，你可以从它们的十进制字节值中，使用列出 `dis.opname` 的方式去查看字节码指令的名字。

### 字节码的用处

现在，你已经了解的足够多了，你可能会想 “OK，我认为它很酷，但是知道这些有什么实际价值呢？”由于对它很好奇，我们去了解它，但是除了好奇之外，Python 字节码在几个方面还是非常有用的。

首先，理解 Python 的运行模型可以帮你更好地理解你的代码。人们都开玩笑说，C 是一种 “可移植汇编器”，你可以很好地猜测出一段 C 代码转换成什么样的机器指令。理解 Python 字节码之后，你在使用 Python 时也具备同样的能力 —— 如果你能预料到你的 Python 源代码将被转换成什么样的字节码，那么你可以知道如何更好地写和优化 Python 源代码。

第二，理解字节码可以帮你更好地回答有关 Python 的问题。比如，我经常看到一些 Python 新手困惑为什么某些结构比其它结构运行的更快（比如，为什么 `{}` 比 `dict()` 快）。知道如何去访问和阅读 Python 字节码将让你很容易回答这样的问题（尝试对比一下： `dis.dis("{}")` 与 `dis.dis("dict()")` 就会明白）。

最后，理解字节码和 Python 如何运行它，为 Python 程序员不经常使用的一种特定的编程方式提供了有用的视角：面向栈的编程。如果你以前从来没有使用过像 FORTH 或 Fator 这样的面向栈的编程语言，它们可能有些古老，但是，如果你不熟悉这种方法，学习有关 Python 字节码的知识，以及理解面向栈的编程模型是如何工作的，将有助你开拓你的编程视野。

### 延伸阅读

如果你想进一步了解有关 Python 字节码、Python 虚拟机、以及它们是如何工作的更多知识，我推荐如下的这些资源：

* [Python 虚拟机内幕](https://leanpub.com/insidethepythonvirtualmachine)，它是 Obi Ike-Nwosu 写的一本免费在线电子书，它深入 Python 解析器，解释了 Python 如何工作的细节。
* [一个用 Python 编写的 Python 解析器](http://www.aosabook.org/en/500L/a-python-interpreter-written-in-python.html)，它是由 Allison Kaptur 写的一个教程，它是用 Python 构建的 Python 字节码解析器，并且它实现了运行 Python 字节码的全部构件。
* 最后，CPython 解析器是一个开源软件，你可以在 [GitHub](https://github.com/python/cpython) 上阅读它。它在文件 `Python/ceval.c` 中实现了字节码解析器。[这是 Python 3.6.4 发行版中那个文件的链接](https://github.com/python/cpython/blob/d48ecebad5ac78a1783e09b0d32c211d9754edf4/Python/ceval.c)；字节码指令是由第 1266 行开始的 `switch` 语句来处理的。

学习更多内容，参与到 James Bennett 的演讲，[有关字节的知识：理解 Python 字节码](https://us.pycon.org/2018/schedule/presentation/127/)，将在 [PyCon Cleveland 2018](https://us.pycon.org/2018/) 召开。

---

via: <https://opensource.com/article/18/4/introduction-python-bytecode>

作者：[James Bennett](https://opensource.com/users/ubernostrum) 选题：[lujun9972](https://github.com/lujun9972) 译者：[qhwdw](https://github.com/qhwdw) 校对：[wxy](https://github.com/wxy)

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


Sosreport：收集系统日志和诊断信息的工具

Summary: 它是一个从类 Unix 操作系统中收集系统配置详细信息和诊断信息的工具。

它是一个从类 Unix 操作系统中收集系统配置详细信息和诊断信息的工具。

![](/data/attachment/album/201807/08/093729btevwc3iyv23euvc.png)

如果你是 RHEL 管理员，你可能肯定听说过 **Sosreport** ：一个可扩展、可移植的支持数据收集工具。它是一个从类 Unix 操作系统中收集系统配置详细信息和诊断信息的工具。当用户提出支持服务单时，他/她必须运行此工具并将由 Sosreport 工具生成的结果报告发送给 Red Hat 支持人员。然后，执行人员将根据报告进行初步分析，并尝试找出系统中的问题。不仅在 RHEL 系统上，你可以在任何类 Unix 操作系统上使用它来收集系统日志和其他调试信息。

### 安装 Sosreport

Sosreport 在 Red Hat 官方系统仓库中，因此你可以使用 Yum 或 DNF 包管理器安装它，如下所示。

```
$ sudo yum install sos

```

要么，

```
$ sudo dnf install sos

```

在 Debian、Ubuntu 和 Linux Mint 上运行：

```
$ sudo apt install sosreport

```

### 用法

安装后，运行以下命令以收集系统配置详细信息和其他诊断信息。

```
$ sudo sosreport

```

系统将要求你输入系统的一些详细信息，例如系统名称、案例 ID 等。相应地输入详细信息，然后按回车键生成报告。如果你不想更改任何内容并使用默认值，只需按回车键即可。

我的 CentOS 7 服务器的示例输出：

```
sosreport (version 3.5)

This command will collect diagnostic and configuration information from
this CentOS Linux system and installed applications.

An archive containing the collected information will be generated in
/var/tmp/sos.DiJXi7 and may be provided to a CentOS support
representative.

Any information provided to CentOS will be treated in accordance with
the published support policies at:

https://wiki.centos.org/

The generated archive may contain data considered sensitive and its
content should be reviewed by the originating organization before being
passed to any third party.

No changes will be made to system configuration.

Press ENTER to continue, or CTRL-C to quit.

Please enter your first initial and last name [server.ostechnix.local]:
Please enter the case id that you are generating this report for []:

Setting up archive ...
Setting up plugins ...
Running plugins. Please wait ...

Running 73/73: yum...
Creating compressed archive...

Your sosreport has been generated and saved in:
/var/tmp/sosreport-server.ostechnix.local-20180628171844.tar.xz

The checksum is: 8f08f99a1702184ec13a497eff5ce334

Please send this file to your support representative.

```

如果你不希望系统提示你输入此类详细信息，请如下使用批处理模式。

```
$ sudo sosreport --batch

```

正如你在上面的输出中所看到的，生成了一个归档报告并保存在 `/var/tmp/sos.DiJXi7` 中。在 RHEL 6/CentOS 6 中，报告将在 `/tmp` 中生成。你现在可以将此报告发送给你的支持人员，以便他可以进行初步分析并找出问题所在。

你可能会担心或想知道报告中的内容。如果是这样，你可以通过运行以下命令来查看它：

```
$ sudo tar -tf /var/tmp/sosreport-server.ostechnix.local-20180628171844.tar.xz

```

要么，

```
$ sudo vim /var/tmp/sosreport-server.ostechnix.local-20180628171844.tar.xz

```

请注意，上述命令不会解压存档，而只显示存档中的文件和文件夹列表。如果要查看存档中文件的实际内容，请首先使用以下命令解压存档：

```
$ sudo tar -xf /var/tmp/sosreport-server.ostechnix.local-20180628171844.tar.xz

```

存档的所有内容都将解压当前工作目录中 `ssosreport-server.ostechnix.local-20180628171844/` 目录中。进入目录并使用 `cat` 命令或任何其他文本浏览器查看文件内容：

```
$ cd sosreport-server.ostechnix.local-20180628171844/

$ cat uptime
17:19:02 up 1:03, 2 users, load average: 0.50, 0.17, 0.10

```

有关 Sosreport 的更多详细信息，请参阅手册页。

```
$ man sosreport

```

就是这些了。希望这些有用。还有更多好东西。敬请关注！

干杯！

---

via: <https://www.ostechnix.com/sosreport-a-tool-to-collect-system-logs-and-diagnostic-information/>

作者：[SK](https://www.ostechnix.com/author/sk/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

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


将你的树莓派打造成一个 Tor 中继节点

Summary: 在此教程中学习如何将你的旧树莓派打造成一个完美的 Tor 中继节点。

在此教程中学习如何将你的旧树莓派打造成一个完美的 Tor 中继节点。

>
> 在此教程中学习如何将你的旧树莓派打造成一个完美的 Tor 中继节点。
>
>
>

![](/data/attachment/album/201807/08/095040irm37me7umm7721c.jpg)

你是否和我一样，在第一代或者第二代树莓派发布时买了一个，玩了一段时间就把它搁置“吃灰”了。毕竟，除非你是机器人爱好者，否则一般不太可能去长时间使用一个处理器很慢的、并且内存只有 256 MB 的计算机。这并不是说你不能用它去做一件很酷的东西，但是在工作和其它任务之间，我还没有看到用一些旧的物件发挥新作用的机会。

然而，如果你想去好好利用它并且不想花费你太多的时间和资源的话，可以将你的旧树莓派打造成一个完美的 Tor 中继节点。

### Tor 中继节点是什么

在此之前你或许听说过 [Tor 项目](https://www.torproject.org/)，如果恰好你没有听说过，我简单给你介绍一下，“Tor” 是 “The Onion Router（洋葱路由器）” 的缩写，它是用来对付在线追踪和其它违反隐私行为的技术。

不论你在互联网上做什么事情，都会在你的 IP 包通过的设备上留下一些数字“脚印”：所有的交换机、路由器、负载均衡，以及目标网络记录的来自你的原始会话的 IP 地址，以及你访问的互联网资源（通常是它的主机名，[即使是在使用 HTTPS 时](https://en.wikipedia.org/wiki/Server_Name_Indication#Security_implications)）的 IP 地址。如过你是在家中上互联网，那么你的 IP 地址可以直接映射到你的家庭所在地。如果你使用了 VPN 服务（[你应该使用](https://www.linux.com/blog/2017/10/tips-secure-your-network-wake-krack)），那么你的 IP 地址映射到你的 VPN 提供商那里，而 VPN 提供商是可以映射到你的家庭所在地的。无论如何，有可能在某个地方的某个人正在根据你访问的网络和在网站上呆了多长时间来为你建立一个个人的在线资料。然后将这个资料进行出售，并与从其它服务上收集的资料进行聚合，然后利用广告网络进行赚钱。至少，这是乐观主义者对如何利用这些数据的一些看法 —— 我相信你还可以找到更多的更恶意地使用这些数据的例子。

Tor 项目尝试去提供一个解决这种问题的方案，使它们不可能（或者至少是更加困难）追踪到你的终端 IP 地址。Tor 是通过让你的连接在一个由匿名的入口节点、中继节点和出口节点组成的匿名中继链上反复跳转的方式来实现防止追踪的目的：

1. **入口节点** 只知道你的 IP 地址和中继节点的 IP 地址，但是不知道你最终要访问的目标 IP 地址
2. **中继节点** 只知道入口节点和出口节点的 IP 地址，以及既不是源也不是最终目标的 IP 地址
3. **出口节点** 仅知道中继节点和最终目标地址，它是在到达最终目标地址之前解密流量的节点

中继节点在这个交换过程中扮演一个关键的角色，因为它在源请求和目标地址之间创建了一个加密的障碍。甚至在意图偷窥你数据的对手控制了出口节点的情况下，在他们没有完全控制整个 Tor 中继链的情况下仍然无法知道请求源在哪里。

只要存在大量的中继节点，你的隐私被会得到保护 —— 这就是我为什么真诚地建议你，如果你的家庭宽带有空闲的时候去配置和运行一个中继节点。

#### 考虑去做 Tor 中继时要记住的一些事情

一个 Tor 中继节点仅发送和接收加密流量 —— 它从不访问任何其它站点或者在线资源，因此你不用担心有人会利用你的家庭 IP 地址去直接浏览一些令人担心的站点。话虽如此，但是如果你居住在一个提供<ruby> 匿名增强服务 <rt>  anonymity-enhancing services </rt></ruby>是违法行为的司法管辖区的话，那么你还是不要运营你的 Tor 中继节点了。你还需要去查看你的互联网服务提供商的服务条款是否允许你去运营一个 Tor 中继。

### 需要哪些东西

* 一个带完整外围附件的树莓派（任何型号/代次都行）
* 一张有 [Raspbian Stretch Lite](https://www.raspberrypi.org/downloads/raspbian/) 的 SD 卡
* 一根以太网线缆
* 一根用于供电的 micro-USB 线缆
* 一个键盘和带 HDMI 接口的显示器（在配置期间使用）

本指南假设你已经配置好了你的家庭网络连接的线缆或者 ADSL 路由器，它用于运行 NAT 转换（它几乎是必需的）。大多数型号的树莓派都有一个可用于为树莓派供电的 USB 端口，如果你只是使用路由器的 WiFi 功能，那么路由器应该有空闲的以太网口。但是在我们将树莓派设置为一个“配置完不管”的 Tor 中继之前，我们还需要一个键盘和显示器。

### 引导脚本

我改编了一个很流行的 Tor 中继节点引导脚本以适配树莓派上使用 —— 你可以在我的 GitHub 仓库 <https://github.com/mricon/tor-relay-bootstrap-rpi> 上找到它。你用它引导树莓派并使用缺省的用户 `pi` 登入之后，做如下的工作：

```
sudo apt-get install -y git
git clone https://github.com/mricon/tor-relay-bootstrap-rpi
cd tor-relay-bootstrap-rpi
sudo ./bootstrap.sh

```

这个脚本将做如下的工作：

1. 安装最新版本的操作系统更新以确保树莓派打了所有的补丁
2. 将系统配置为无人值守自动更新，以确保有可用更新时会自动接收并安装
3. 安装 Tor 软件
4. 告诉你的 NAT 路由器去转发所需要的端口（端口一般是 443 和 8080，因为这两个端口最不可能被互联网提供商过滤掉）上的数据包到你的中继节点

脚本运行完成后，你需要去配置 `torrc` 文件 —— 但是首先，你需要决定打算贡献给 Tor 流量多大带宽。首先，在 Google 中输入 “[Speed Test](https://www.google.com/search?q=speed+test)”，然后点击 “Run Speed Test” 按钮。你可以不用管 “Download speed” 的结果，因为你的 Tor 中继能处理的速度不会超过最大的上行带宽。

所以，将 “Mbps upload” 的数字除以 8，然后再乘以 1024，结果就是每秒多少 KB 的宽带速度。比如，如果你得到的上行带宽是 21.5 Mbps，那么这个数字应该是：

```
21.5 Mbps / 8 * 1024 = 2752 KBytes per second

```

你可以限制你的中继带宽为那个数字的一半，并允许突发带宽为那个数字的四分之三。确定好之后，使用喜欢的文本编辑器打开 `/etc/tor/torrc` 文件，调整好带宽设置。

```
RelayBandwidthRate 1300 KBytes
RelayBandwidthBurst 2400 KBytes

```

当然，如果你想更慷慨，你可以将那几个设置的数字调的更大，但是尽量不要设置为最大的出口带宽 —— 如果设置的太高，它会影响你的日常使用。

你打开那个文件之后，你应该去设置更多的东西。首先是昵称 —— 只是为了你自己保存记录，第二个是联系信息，只需要一个电子邮件地址。由于你的中继是运行在无人值守模式下的，你应该使用一个定期检查的电子邮件地址 —— 如果你的中继节点离线超过 48 个小时，你将收到 “Tor Weather” 服务的告警信息。

```
Nickname myrpirelay
ContactInfo you@example.com

```

保存文件并重引导系统去启动 Tor 中继。

### 测试它确认有 Tor 流量通过

如果你想去确认中继节点的功能，你可以运行 `arm` 工具：

```
sudo -u debian-tor arm

```

它需要一点时间才显示，尤其是在老板子上。它通常会给你显示一个表示入站和出站流量（或者是错误信息，它将有助于你去排错）的柱状图。

一旦你确信它运行正常，就可以将键盘和显示器拔掉了，然后将树莓派放到地下室，它就可以在那里悄悄地呆着并到处转发加密的比特了。恭喜你，你已经帮助去改善隐私和防范在线的恶意跟踪了！

通过来自 Linux 基金会和 edX 的免费课程 ["Linux 入门"](https://training.linuxfoundation.org/linux-courses/system-administration-training/introduction-to-linux)  来学习更多的 Linux 知识。

---

via: <https://www.linux.com/blog/intro-to-linux/2018/6/turn-your-raspberry-pi-tor-relay-node>

作者：[Konstantin Ryabitsev](https://www.linux.com/users/mricon) 选题：[lujun9972](https://github.com/lujun9972) 译者：[qhwdw](https://github.com/qhwdw) 校对：[wxy](https://github.com/wxy)

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


迁移到 Linux：使用 sudo

Summary: sudo 机制可以让你轻松以普通用户偶尔执行管理任务。让我们来学习一下。

sudo 机制可以让你轻松以普通用户偶尔执行管理任务。让我们来学习一下。

>
> sudo 机制可以让你轻松以普通用户偶尔执行管理任务。让我们来学习一下。
>
>
>

![](/data/attachment/album/201807/09/180426anjij9nn8tjni7w7.jpg)

本文是我们关于迁移到 Linux 的系列文章的第五篇。如果你错过了之前的那些，你可以在这里赶上：

* [第1部分 - 入门介绍](/article-9212-1.html)
* [第2部分 - 磁盘、文件和文件系统](/article-9213-1.html)
* [第3部分 - 图形操作环境](/article-9293-1.html)
* [第4部分 - 命令行](/article-9565-1.html)

你可能一直想了解 Linux。也许它在你的工作场所使用，如果你每天使用它，你的工作效率会更高。或者，也许你想在家里的某些计算机上安装 Linux。无论是什么原因，这一系列文章都是为了让过渡更容易。

与许多其他操作系统一样，Linux 支持多用户。它甚至支持多个用户同时登录。

用户帐户通常会被分配一个可以存储文件的家目录。通常这个家目录位于：

```
/home/<login name>

```

这样，每个用户都有存储自己的文档和其他文件的独立位置。

### 管理任务

在传统的 Linux 安装中，常规用户帐户无权在系统上执行管理任务。典型的安装 Linux 的系统会要求用户以管理员身份登录以执行某些任务，而不是为每个用户分配权限以执行各种任务。

Linux 上的管理员帐户称为 root。

### Sudo 解释

从历史上看，要执行管理任务，必须以 root 身份登录，执行任务，然后登出。这个过程有点乏味，所以很多人以 root 登录并且整天都以管理员身份工作。这种做法可能会导致灾难性的后果，例如，意外删除系统中的所有文件。当然，root 用户可以做任何事情，因此没有任何保护措施可以防止有人意外地执行影响很大的操作。

创建 `sudo` 工具是为了使你更容易以常规用户帐户登录，偶尔以 root 身份执行管理任务，而无需登录、执行任务然后登出。具体来说，`sudo` 允许你以不同的用户身份运行命令。如果你未指定特定用户，则假定你指的是 root 用户。

`sudo` 可以有复杂的设置，允许用户有权限使用 `sudo` 运行某些命令，而其他的不行。通常，安装的桌面系统会使创建的第一个帐户在 `sudo` 中有完全的权限，因此你作为主要用户可以完全管理 Linux 安装。

### 使用 Sudo

某些安装 Linux 的系统设置了 `sudo`，因此你仍需要知道 root 帐户的密码才能执行管理任务。其他人，设置 `sudo` 输入自己的密码。这里有不同的哲学。

当你尝试在图形环境中执行管理任务时，通常会打开一个要求输入密码的对话框。输入你自己的密码（例如，在 Ubuntu 上）或 root 帐户的密码（例如，Red Hat）。

当你尝试在命令行中执行管理任务时，它通常只会给你一个 “permission denied” 错误。然后你在前面用 `sudo` 重新运行命令。例如：

```
systemctl start vsftpd
Failed to start vsftpd.service: Access denied

sudo systemctl start vsftpd
[sudo] password for user1:

```

### 何时使用 Sudo

以 root 身份运行命令（在 `sudo` 或其他情况下）并不总是解决权限错误的最佳解决方案。虽然将以 root 身份运行会消除 “permission denied” 错误，但有时最好寻找根本原因而不是仅仅解决症状。有时文件拥有错误的所有者和权限。

当你在尝试一个需要 root 权限来执行操作的任务或者程序时使用 `sudo`。如果文件恰好由另一个用户（包括 root 用户）拥有，请不要使用 `sudo`。在第二种情况下，最好正确设置文件的权限。

通过 Linux 基金会和 edX 的免费[“Linux 介绍”](https://training.linuxfoundation.org/linux-courses/system-administration-training/introduction-to-linux)课程了解有关 Linux 的更多信息。

---

via: <https://www.linux.com/blog/learn/2018/3/migrating-linux-using-sudo>

作者：[John Bonesio](https://www.linux.com/users/johnbonesio) 选题：[lujun9972](https://github.com/lujun9972) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

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


五个最热门的开源机器学习 JavaScript 框架

>
> 如果你是一位想要深入机器学习的 JavaScript 程序员或想成为一位使用 JavaScript 的机器学习专家，那么这些开源框架也许会吸引你。
>
>
>

![](/data/attachment/album/201807/09/182213tquw1qihuyf5cnwq.jpg)

开源工具的涌现使得开发者能够更加轻松地开发应用，这一点使机器学习领域本身获得了极大增长。（例如，AndreyBu，他来自德国，在机器学习领域拥有五年以上的经验，他一直在使用各种各样的开源框架来创造富有魅力的机器学习项目。）

虽然 Python 是绝大多数的机器学习框架所采用的语言，但是 JavaScript 也并没有被抛下。JavaScript 开发者可以在浏览器中使用各种框架来训练和部署机器学习模型。

下面是 JavaScript 中最热门五个机器学习框架

### 1、 TensorFlow.js

[TensorFlow.js](https://js.tensorflow.org/) 是一个开源库，它使你能在浏览器中完整地运行机器学习程序，它是 Deeplearn.js 的继承者，Deeplearn.js 不再更新了。TensorFlow.js 在 Deeplearn.js 功能的基础上进行了改善，使你能够充分利用浏览器，得到更加深入的机器学习经验。

通过这个开源库，你可以在浏览器中使用有各种功能的、直观的 API 来定义、训练和部署模型。除此之外，它自动提供 WebGL 和 Node.js 的支持。

如果您有了一个已经训练过的模型，你想要导入到浏览器中。TensorFlow.js 可以让你做到这一点，你也可以在不离开浏览器的情况下重新训练已有的模型。

### 2、 机器学习工具库

现在有很多在浏览器中提供广泛的机器学习功能的资源型开源工具，这个[机器学习工具库](https://github.com/mljs/ml)就是这些开源工具的集合。这个工具库为好几种机器学习算法提供支持，包括非监督式学习、监督式学习、数据处理、人工神经网络（ANN）、数学和回归。

如果你以前使用 Python，现在想找类似于 Scikit-learn 的，能在浏览器中使用 JavaScript 进行机器学习的工具，这套工具会满足你的要求。

### 3、 Keras.js

[Keras.js](https://transcranial.github.io/keras-js/#/) 是另外一个热门的开源框架，它使你能够在浏览器中运行机器学习模型，它使用 WebGL 来提供 GPU 模式的支持。如果你有使用 Node.js 的模型，你就只能在 GPU 模式下运行它。Keras.js 还为使用任意后端框架的模型训练提供支持，例如 Microsoft Cognitive Toolkit (CNTK) 。

一些 Keras 模型可以部署在客户端浏览器上，包括 Inception v3 (训练在 ImageNet 上)，50 层冗余网络(训练在 ImageNet 上)，和卷积变化自动编码器(训练在 MNIST 上)。

### 4、 Brain.js

机器学习里的概念非常重要，它可能会使刚开始进入这个领域的人们气馁，这个领域里的学术用语和专业词汇可能会使初学者感到崩溃，而解决以上问题的能力就是 [Brain.js](https://github.com/BrainJS/brain.js) 的优势所在。它是开源的，基于 JavaScript 的框架，简化了定义、训练和运行神经网络的流程。

如果你是一个 JavaScript 开发者，并且在机器学习领域是完全的新手，Brain.js 能减低你学习的难度曲线。它可以和 Node.js 一起使用，或者运行在客户端浏览器里来训练机器学习模型。Brain.js 支持部分类型的神经网络，包括前馈式网络、Ellman 网络，和门循环单元网络。

### 5、 STDLib

[STDLib](https://stdlib.io/) 是一个基于 JavaScript 和 Node.js 应用的开源库，如果您正在寻找一种在浏览器中运行，支持科学和数字化的基于 web 的机器学习应用，STDLib 能满足你的需要。

这个库能提供全面而先进的数学和统计学上的功能，来帮助你构建高性能的机器学习模型。你同样也可以使用它丰富的功能来构建应用程序和其他的库。除此之外，如果你想要一个数据可视化和探索性数据分析的框架 —— STDLib，你，值得拥有。

### 总结

如果你是一个 JavaScript 开发者，并且打算深入研究令人兴奋的机器学习世界，或者说，你是一个机器学习方面的专家，打算开始尝试使用 JavaScript ，那么上述的开源框架会激起您的兴趣。

你有知道其他的，提供在浏览器里运行机器学习功能的开源库吗？请在下面的评论区里告诉我们。

---

via: <https://opensource.com/article/18/5/machine-learning-javascript-frameworks>

作者：[Dr.Michael J.Garbade](https://opensource.com/users/drmjg) 选题：[lujun9972](https://github.com/lujun9972) 译者：[hopefully2333](https://github.com/hopefully2333) 校对：[wxy](https://github.com/wxy)

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


3 款 Linux 桌面的日记程序

Summary: 用轻量、灵活的数字日记工具来记录你的活动。

用轻量、灵活的数字日记工具来记录你的活动。

>
> 用轻量、灵活的数字日记工具来记录你的活动。
>
>
>

![](/data/attachment/album/201807/09/183600deix08fxlsm8xmpi.jpeg)

保持记日记的习惯，即使是不定期地记，也可以带来很多好处。这不仅是治疗和宣泄，而且还可以很好地记录你所在的位置以及你去过的地方。它可以帮助你展示你在生活中的进步，并提醒你自己做对了什么，做错了什么。

无论你记日记的原因是什么，都有多种方法可以做到这一点。你可以使用传统的笔和纸，也可以使用基于 Web 的程序，或者你可以使用[简单的文本文件](https://plaintextproject.online/2017/07/19/journal.html)。

另一种选择是使用专门的日记程序。Linux 桌面有几种非常灵活且非常有用的日记工具。我们来看看其中的三个。

### RedNotebook

![](/data/attachment/album/201807/09/183612yr9tq9eqipu8rar0.png)

在这里描述的三个日记程序中，[RedNotebook](http://rednotebook.sourceforge.net) 是最灵活的。大部分灵活性来自其模板。这些模板可让你记录个人想法或会议记录、计划旅程或记录电话。你还可以编辑现有模板或创建自己的模板。

你可以使用与 Markdown 非常相似的标记语言来记录日记。你还可以在日记中添加标签，以便于查找。只需在程序的左窗格中单击或输入标记，右窗格中将显示相应日记的列表。

最重要的是，你可以将全部、部分或仅一个日记导出为纯文本、HTML、LaTeX 或 PDF。在执行此操作之前，你可以通过单击工具栏上的“预览”按钮了解日志在 PDF 或 HTML 中的显示情况。

总的来说，RedNotebook 是一款易于使用且灵活的程序。它需要习惯，但一旦你这样做，它是一个有用的工具。

### Lifeograph

![](/data/attachment/album/201807/09/183613k9odu69dssdry9dp.png)

[Lifeograph](http://lifeograph.sourceforge.net/wiki/Main_Page) 与 RedNotebook 有相似的外观和感觉。它没有那么多功能，但 Lifeograph 也够了。

该程序通过保持简单和整洁性来简化记日记这件事。你有一个很大的区域可以记录，你可以为日记添加一些基本格式。这包括通常的粗体和斜体，以及箭头和高亮显示。你可以在日记中添加标签，以便更好地组织和查找它们。

Lifeograph 有一个我觉得特别有用的功能。首先，你可以创建多个日记 - 例如，工作日记和个人日记。其次是密码保护你的日记的能力。虽然该网站声称 Lifeograph 使用“真正的加密”，但没有关于它的详细信息。尽管如此，设置密码仍然会阻止大多数窥探者。

### Almanah Diary

![](/data/attachment/album/201807/09/183613lkzuvzkq5a5cjms0.png)

[Almanah Diary](https://wiki.gnome.org/Apps/Almanah_Diary) 是另一种非常简单的日记工具。但不要因为它缺乏功能就丢掉它。虽简单，但足够。

有多简单？它差不多只是一个包含了日记输入和日历的区域而已。你可以做更多的事情 —— 比如添加一些基本格式（粗体、斜体和下划线）并将文本转换为超链接。Almanah 还允许你加密日记。

虽然有一个可以将纯文本文件导入该程序的功能，但我无法使其正常工作。尽管如此，如果你喜欢一个简单，能够快速记日记的软件，那么 Almanah 日记值得一看。

### 命令行怎么样？

如果你不想用 GUI 则可以不必用。命令行是保存日记的绝佳选择。

我尝试过并且喜欢的是 [jrnl](http://maebert.github.com/jrnl/)。或者你可以使用[此方案](http://tamilinux.wordpress.com/2007/07/27/writing-short-notes-and-diaries-from-the-cli/)，它使用命令行别名格式化并将日记保存到文本文件中。

你有喜欢的日记程序吗？请留下评论，随意分享。

---

via: <https://opensource.com/article/18/6/linux-journaling-applications>

作者：[Scott Nesbitt](https://opensource.com/users/scottnesbitt) 选题：[lujun9972](https://github.com/lujun9972) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

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


迁移到 Linux：安装软件

>
> 所有的 Linux 打包系统和工具都会让人迷惑，但是这篇面向初学者的教程可以帮助你搞明白。
>
>
>

![](/data/attachment/album/201807/10/074348az6w8n990m0r9vfv.jpg)

如你所见，众所瞩目的 Linux 已经用在互联网，以及 Arduino、Beagle 和树莓派主板等设备上，或许你正在考虑是时候尝试一下 Linux 了。本系列将帮助你成功过渡到 Linux。如果你错过了本系列的早期文章，可以在这里找到它们：

* [第1部分 - 入门介绍](/article-9212-1.html)
* [第2部分 - 磁盘、文件和文件系统](/article-9213-1.html)
* [第3部分 - 图形操作环境](/article-9293-1.html)
* [第4部分 - 命令行](/article-9565-1.html)
* [第5部分 - 使用 sudo](/article-9819-1.html)

### 安装软件

要在你的计算机上获得新软件，通常的方法是从供应商处获得软件产品，然后运行一个安装程序。过去，软件产品会出现在像 CD-ROM 或 DVD 一样的物理媒介上，而现在我们经常从互联网上下载软件产品。

使用 Linux，安装软件就像在你的智能手机上安装一样。如同你的手机应用商店一样，在 Linux 上有个提供开源软件工具和程序的<ruby> 中央仓库 <rt>  central repository </rt></ruby>，几乎任何你想要的程序都会出现在可用软件包列表中以供你安装。

每个程序并不需要运行单独的安装程序，而是你可以使用 Linux 发行版附带的软件包管理工具。（这里说的 Linux 发行版就是你安装的 Linux，例如 Ubuntu、Fedora、Debian 等）每个发行版在互联网上都有它自己的集中存储库（称为仓库），它们存储了数千个预先构建好的应用程序。

你可能会注意到，在 Linux 上安装软件有几种例外情况。有时候，你仍然需要去供应商那里获取他们的软件，因为该程序不存在于你的发行版的中央仓库中。当软件不是开源和/或自由软件的时候，通常就是这种情况。

另外请记住，如果你想要安装一个不在发行版仓库中的程序时，事情就不是那么简单了，即使你正在安装自由及开源程序。这篇文章没有涉及到这些更复杂的情况，请遵循在线的指引。

有了所有的 Linux 包管理系统和工具，接下来干什么可能仍然令人困惑。本文应该有助于澄清一些事情。

### 包管理

目前在 Linux 发行版中有几个相互竞争的用于管理、安装和删除软件的包管理系统。每个发行版都选择使用了一个<ruby> 包管理工具 <rt>  package management tools </rt> <rt> </rt></ruby>。Red Hat、Fedora、CentOS、Scientific Linux、SUSE 等使用 Red Hat 包管理（RPM）。Debian、Ubuntu、Linux Mint 等等都使用 Debian 包管理系统，简称 DPKG。还有一些其它包管理系统，但 RPM 和 DPKG 是最常见的。

![](/data/attachment/album/201807/10/074349h8z4m8vbjwjjvf1t.png)

*图 1: Package installers*

无论你使用的软件包管理是什么，它们通常都是一组构建于另外一种工具之上的工具（图 1）。最底层是一个命令行工具，它可以让你做任何与安装软件相关的一切工作。你可以列出已安装的程序、删除程序、安装软件包文件等等。

这个底层工具并不总是最方便使用的，所以通常会有一个命令行工具，它可以使用单个命令在发行版的中央仓库中找到软件包，并下载和安装它以及任何依赖项。最后，通常会有一个<ruby> 图形应用程序 <rt>  graphical application </rt> <rt> </rt></ruby>，可以让你使用鼠标选择任何想要的内容，然后单击 “install” 按钮即可。

![](/data/attachment/album/201807/10/074350jt5layn6y5tr5d85.png)

*图 2: PackageKit*

对于基于 Red Hat 的发行版，包括 Fedora、CentOS、Scientific Linux 等，它们的底层工具是 rpm，高级工具叫做 dnf（在旧系统上是 yum）。图形安装程序称为 PackageKit（图 2），它可能在系统管理菜单下显示名字为 “Add/Remove Software（添加/删除软件）”。

![](/data/attachment/album/201807/10/074350rzfpjljwc4hmmogc.png)

*图 3: Ubuntu Software*

对于基于 Debian 的发行版，包括 Debian、Ubuntu、Linux Mint、Elementary OS 等，它们的底层命令行工具是 dpkg，高级工具称为 apt。在 Ubuntu 上管理已安装软件的图形工具是 Ubuntu Software（图 3）。对于 Debian 和 Linux Mint，图形工具称为<ruby> 新立得 <rt>  Synaptic </rt></ruby>，它也可以安装在 Ubuntu 上。

你也可以在 Debian 相关发行版上安装一个基于文本的图形化工具 aptitude。它比 <ruby> 新立得 <rt>  synaptic </rt></ruby>更强大，并且即使你只能访问命令行也能工作。如果你想通过各种选项进行各种“骚”操作，你可以试试这个，但它使用起来比新立得更复杂。其它发行版也可能有自己独特的工具。

### 命令行工具

在 Linux 上安装软件的在线说明通常描述了在命令行中键入的命令。这些说明通常更容易理解，并且将命令复制粘贴到命令行窗口中，可以在不出错的情况下一步步进行。这与下面的说明相反：“打开这个菜单，选择这个程序，输入这个搜索模式，点击这个标签，选择这个程序，然后点击这个按钮”，这经常让你在各种操作中迷失。

有时你正在使用的 Linux 没有图形环境，因此熟悉从命令行安装软件包是件好事。表 1 和表 2 列出了基于 RPM 和 DPKG 系统的一下常见操作及其相关命令。

![](/data/attachment/album/201807/10/074350vktazttszjgiyott.png)

![](/data/attachment/album/201807/10/074351a5gbmi1ngm5mob5y.png)

请注意 SUSE，它像 RedHat 和 Fedora 一样使用 RPM，却没有 dnf 或 yum。相反，它使用一个名为 zypper 的程序作为高级命令行工具。其他发行版也可能有不同的工具，例如 Arch Linux 上的 pacman 或 Gentoo 上的 emerge。有很多包管理工具，所以你可能需要查找哪个适用于你的发行版。

这些技巧应该能让你更好地了解如何在新的 Linux 中安装程序，以及更好地了解 Linux 中各种软件包管理方式如何相互关联。

通过 Linux 基金会和 edX 的免费 [“Linux 入门”](https://training.linuxfoundation.org/linux-courses/system-administration-training/introduction-to-linux)课程了解有关 Linux 的更多信息。

---

via: <https://www.linux.com/blog/learn/2018/3/migrating-linux-installing-software>

作者：[JOHN BONESIO](https://www.linux.com/users/johnbonesio) 译者：[MjSeven](https://github.com/MjSeven) 校对：[pityonline](https://github.com/pityonline), [wxy](https://github.com/wxy)

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


如何在 Arch Linux 中查找已安装的专有软件包？

Summary: 它将基于 Arch 系统中的所有安装包与 Parabola 的软件包 blacklist 和 aur-blacklist 进行比较，然后显示出你的斯托曼自由指数（“自由/总计”比分）。

![](/data/attachment/album/201807/10/080816o0dnrwvfrfdsdvxv.jpg)

你是狂热的自由软件支持者吗？你目前在使用任何基于 Arch 的 Linux 发行版吗？我有一个小小的提示送给你！现在，你可以轻松地在 Arch Linux 及其变体（如 Antergos、Manjaro Linux 等）中找到已安装的专有软件包。你无需在已安装软件包的网站中参考其许可细节，也无需使用任何其它外部工具来查明软件包是自由的还是专有的。（LCTT 译注：其实下面还是借助了一个外部程序）

### 在 Arch Linux 中查找已安装的专有软件包

一位开发人员开发了一个名为 “[Absolutely Proprietary](https://github.com/vmavromatis/absolutely-proprietary)” 的实用程序，它是一种用于基于 Arch 发行版的专有软件包检测器。它将基于 Arch 系统中的所有安装包与 Parabola 的软件包 [blacklist](https://git.parabola.nu/blacklist.git/plain/blacklist.txt) 和 [aur-blacklist](https://git.parabola.nu/blacklist.git/plain/aur-blacklist.txt) 进行比较，然后显示出你的<ruby> 斯托曼自由指数 <rt>  Stallman Freedom Index </rt></ruby>（“自由/总计”比分）。此外，你可以将该列表保存到文件中，并与其他系统/用户共享或比较。

在安装之前，确保你安装了 Python 和 Git。

然后，`git clone` 仓库：

```
git clone https://github.com/vmavromatis/absolutely-proprietary.git

```

这条命令将会下载所有内容到你当前工作目录中的 `absolutely-proprietary` 目录。

进入此目录：

```
cd absolutely-proprietary

```

接着，使用以下命令查找已安装的专有软件：

```
python main.py

```

这条命令将会下载 `blacklist.txt`、`aur-blacklist.txt`，并将本地已安装的软件包与远程软件包进行比较并显示其指数。

以下是在我的 Arch Linux 桌面的示例输出：

```
Retrieving local packages (including AUR)...
Downloading https://git.parabola.nu/blacklist.git/plain/blacklist.txt
Downloading https://git.parabola.nu/blacklist.git/plain/aur-blacklist.txt
Comparing local packages to remote...
=============================================
47 ABSOLUTELY PROPRIETARY PACKAGES INSTALLED
=============================================

Your GNU/Linux is infected with 47 proprietary packages out of 1370 total installed.
Your Stallman Freedom Index is 96.57

+------------------------|---------|--------------------|---------------------------------------------------------------------------------------------+
| Name | Status | Libre Alternatives | Description |
+------------------------|---------|--------------------|---------------------------------------------------------------------------------------------+
| chromium-pepper-flash | nonfree | | proprietary Google Chrome EULA, missing sources |
+------------------------|---------|--------------------|---------------------------------------------------------------------------------------------+
| faac | nonfree | | [FIXME:description] is a GPL'ed package, but has non free code that can't be distributed und|
+------------------------|---------|--------------------|---------------------------------------------------------------------------------------------+
| libunrar | nonfree | | part of nonfree unrar, Issue442 |
+------------------------|---------|--------------------|---------------------------------------------------------------------------------------------+
| opera | nonfree | | nonfree, nondistributable, built from binary installers, etc |
+------------------------|---------|--------------------|---------------------------------------------------------------------------------------------+
| shutter | nonfree | | need registered user to download (and access website) the source code and depends perl-net-d|
+------------------------|---------|--------------------|---------------------------------------------------------------------------------------------+
| ttf-ms-fonts | nonfree | | |
+------------------------|---------|--------------------|---------------------------------------------------------------------------------------------+
| ttf-ubuntu-font-family | nonfree | | Ubuntu font license considered non-free by DFSG and Fedora |
+------------------------|---------|--------------------|---------------------------------------------------------------------------------------------+
| unace | nonfree | | license forbids making competing ACE archivers from unace |
+------------------------|---------|--------------------|---------------------------------------------------------------------------------------------+
| unrar | nonfree | unar | |
| | | fsf | |
| | | unrar | |
+------------------------|---------|--------------------|---------------------------------------------------------------------------------------------+
| virtualbox | nonfree | | contains BIOS which needs a nonfree compiler to build from source (OpenWatcom compiler), doe|
+------------------------|---------|--------------------|---------------------------------------------------------------------------------------------+
| wordnet | nonfree | | |
+------------------------|---------|--------------------|---------------------------------------------------------------------------------------------+

Save list to file? (Y/n)

```

![](/data/attachment/album/201807/10/080818k88t8g88o83vq1t1.png)

如你所见，我的系统中有 47 个专有软件包。就像我说的那样，我们可以将它保存到文件中稍后查看。为此，当提示你将列表保存在文件时，请按 `y`。然后按 `y` 接受默认值，或按 `n` 以你喜欢的格式和位置来保存它。

```
Save list to file? (Y/n) y
Save as markdown table? (Y/n) y
Save it to (/tmp/tmpkuky_082.md): y
The list is saved at /home/sk/absolutely-proprietary/y.md

You can review it from the command line
using the "less -S /home/sk/absolutely-proprietary/y.md"
or, if installed, the "most /home/sk/absolutely-proprietary/y.md" commands

```

你可能已经注意到，我只有 **nonfree** 包。它还会显示另外两种类型的软件包，例如 semifree、 uses-nonfree。

* **nonfree**：这个软件包是公然的非自由软件。
* **semifree**：这个软件包大部分是自由的，但包含一些非自由软件。
* **uses-nonfree**：这个软件包依赖、推荐或不恰当地与其他自由软件或服务集成。

该使用程序的另一个显著特点是它不仅显示了专有软件包，而且还显示这些包的替代品。

希望这有些帮助。我很快就会在这里提供另一份有用的指南。敬请关注！

干杯!

资源：

* [Absolutely Proprietary](https://github.com/vmavromatis/absolutely-proprietary)

---

via: <https://www.ostechnix.com/find-installed-proprietary-packages-arch-linux/>

作者：[SK](https://www.ostechnix.com/author/sk/) 译者：[MjSeven](https://github.com/MjSeven) 校对：[wxy](https://github.com/wxy)

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


如何在 20 分钟内发布一个正式的 ERC20 通证

Summary: 在这篇教程中，我准备指导你部署你自己的 ERC20 通证到实际的以太坊网络上去。

![](/data/attachment/album/201807/10/222045hwhg7mp7w766v7dz.jpg)

这段时间以来，以太坊通证很流行。这些通证可以用来代表现实世界的各种价值单位：[黄金](https://digix.global/)、 [谎言](https://www.cnbc.com/2017/08/28/burger-king-russia-cryptocurrency-whoppercoin.html)、 [猫咪](https://www.cryptokitties.co/) 甚至是类似 [公司股票](https://www.investopedia.com/terms/i/initial-coin-offering-ico.asp) 一样的东西。迄今为止，人们已经募集了 [20 亿美元的通证](https://www.forbes.com/sites/chancebarnett/2017/09/23/inside-the-meteoric-rise-of-icos/#57ac46d95670)。那些通证是以 [ERC20](https://theethereum.wiki/w/index.php/ERC20_Token_Standard) 为标准的，人们可以轻松地在钱包之间进行交易。在这篇教程中，我准备指导你部署你自己的 ERC20 通证到真实的以太坊网络上去。

事先准备：

* 一个文本编辑器（[Atom](https://atom.io/) 不错，不过我喜欢 [Vim](http://www.vim.org/)）
* 对命令行和终端（模拟器）有起码的了解。Mac 内置的应用“终端”就很好，不过我喜欢 [iTerm2](https://www.iterm2.com/)
* Chrome 浏览器
* [Node.js 8](https://nodejs.org/)（或更高版本）
* 你的通证的名字。我的准备叫做 HamburgerCoin（汉堡币）

你需要做的第一件事是安装 [MetaMask](https://metamask.io/)。访问 [Metamask 网站](https://metamask.io/) 并点击“Get Chrome Extention”。

Metamask 可以让你通过 Chrome 在以太坊上进行交易。它依靠运行着公开以太坊节点的 [Infura](https://infura.io/) ，所以你不用自己运行以太坊全节点。如果你颇具探索精神，你也可以下载和安装 [Mist](https://github.com/ethereum/mist/releases) 以替代它。运行 Mist 就可以让你运行你自己的以太坊节点。运行自己的节点你就需要将你的计算机与该网络进行同步，这需要不短的时间。从技术上讲这更安全，因为这样你不必信任 Infura 来处理你的交易。Infura 可以忽略你的交易而干预你，但是它并不能偷走你的钱。因为安装 Metamask 比 Mist 更快也更简单，所以我假设你在下面的教程中使用 Metamask。

接着你需要安装 [truffle](http://truffleframework.com/)：

```
 $ npm install -g truffle

```

现在为你自己的新通证创建一个新目录，cd 到其中并初始化你的 truffle 项目。

```
$ mkdir hamburger-coin
$ cd hamburger-coin
$ truffle init

```

很好，你的 truffle 项目已经设置好了！

现在来创建我们的通证。首先我们需要安装 [OpenZepplin](https://github.com/OpenZeppelin) 框架。OpenZepplin 框架包括了大量预先构建好的合约，包括我们要部署的 ERC20 通证合约。

（只需要按下回车接受默认值即可）

```
$ npm init
package name: (hamburger-coin)
version: (1.0.0)
description:
entry point: (truffle.js)
test command:
git repository:
keywords:
author:
license: (ISC)
About to write to /Users/masonf/src/hamburger-coin/package.json:

{
  "name": "hamburger-coin",
  "version": "1.0.0",
  "description": "",
  "main": "truffle.js",
  "directories": {
    "test": "test"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

Is this ok? (yes) yes
$ npm install zeppelin-solidity

```

现在我们可以创建我们的通证合约了。创建一个 `contracts/HamburgerCoin.sol` 文件并加入如下内容：

```
pragma solidity ^0.4.18;
import "zeppelin-solidity/contracts/token/StandardToken.sol";

contract HamburgerCoin is StandardToken {
  string public name = "HamburgerCoin";
  string public symbol = "HBC";
  uint public decimals = 2;
  uint public INITIAL_SUPPLY = 10000 * (10 ** decimals);

  function HamburgerCoin() public {
    totalSupply_ = INITIAL_SUPPLY;
    balances[msg.sender] = INITIAL_SUPPLY;
  }
}

```

（LCTT 译注：上述合约内容中指定了合约的名称、符号和供应量。在 ERC20 当中，通证的供应量其实是整数，上述合约中通证的实际供应量是 10000 \* 100 个，出于显示 2 位小数的需求，你在合约浏览器、钱包软件中看到和操作的 1 个通证，实际上在交易中是以 100 个进行的。）

OpenZepplin 的 `StandardToken` 是一个标准的 ERC20 通证。如果你感兴趣，你可以看看它的 [源代码](https://github.com/OpenZeppelin/zeppelin-solidity/tree/master/contracts/token) 以了解是如何工作的。

实际上并不太复杂。该合约有一个 [地址到余额](https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/token/BasicToken.sol#L15) 的映射（LCTT 译注：你可以理解为哈希、关联数组），它也有一个 [允许转账](https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/token/StandardToken.sol#L17) 的列表。你可以看做是支票。你可以写张支票，但是直到它被兑付前，钱并不会被转账。

如果有人要转走一些资金，你可以在合约上调用 [approve](https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/token/StandardToken.sol#L48) 方法，设置你要发送的通证数量。这就像是写支票一样。

然后调用 [transferFrom](https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/token/StandardToken.sol#L26) 会实际进行转账。

我们可以从头写这些合约，但是最好采用经过完备的社区测试的合约。从头写一个 ERC20 通证那就是另外一篇文章了。

试着运行 `compile` 来编译我们的合约：

```
$ truffle compile
Compiling ./contracts/HamburgerCoin.sol...
Compiling zeppelin-solidity/contracts/math/SafeMath.sol...
Compiling zeppelin-solidity/contracts/ownership/Ownable.sol...
Compiling zeppelin-solidity/contracts/token/BasicToken.sol...
Compiling zeppelin-solidity/contracts/token/ERC20.sol...
Compiling zeppelin-solidity/contracts/token/ERC20Basic.sol...
Compiling zeppelin-solidity/contracts/token/MintableToken.sol...
Compiling zeppelin-solidity/contracts/token/StandardToken.sol...
Writing artifacts to ./build/contracts Next you'll need to add a migration file which will tell truffle how to deploy your contract.

```

接下来我们需要增加一个 truffle [迁移](http://truffleframework.com/docs/getting_started/migrations)。

创建 `migrations/2_deploy_hamburgercoin.js` 文件并添加如下内容：

```
var HamburgerCoin = artifacts.require("./HamburgerCoin.sol");

module.exports = function(deployer) {
  deployer.deploy(HamburgerCoin);
};

```

现在让我们配置 truffle 以能够使用 Infura 公共节点。如果我们要部署到公共节点，那就需要钱包的私钥。我们可以将该私钥包含在我们的源代码当中，但是如果任何人可以访问你的源代码（和版本库），他就能够偷走我们所有的汉堡币！要避免这种情况，我们会使用 [dotenv](https://github.com/motdotla/dotenv) node.js 模块。（LCTT 译注：dotenv 用于存储机密信息的文件 .env 是以 “.” 开头的，默认不会进入版本库，当然，如果有人能查看你全部的项目文件，你的私钥还是会被泄露。）

让我们安装部署到 Infura 所需的所有模块。

```
npm install --save-dev dotenv truffle-wallet-provider ethereumjs-wallet

```

（LCTT 译注：可能安装过程中会有很多警告，大多应该是属于定义了未使用的变量和方法的编译警告，可以忽略。）

现在编辑 `truffle.js` 并（原样）加入如下内容：

```
require('dotenv').config();
const Web3 = require("web3");
const web3 = new Web3();
const WalletProvider = require("truffle-wallet-provider");
const Wallet = require('ethereumjs-wallet');

var mainNetPrivateKey = Buffer.from(process.env["MAINNET_PRIVATE_KEY"], "hex")
var mainNetWallet = Wallet.fromPrivateKey(mainNetPrivateKey);
var mainNetProvider = new WalletProvider(mainNetWallet, "https://mainnet.infura.io/");

var ropstenPrivateKey = Buffer.from(process.env["ROPSTEN_PRIVATE_KEY"], "hex")
var ropstenWallet = Wallet.fromPrivateKey(ropstenPrivateKey);
var ropstenProvider = new WalletProvider(ropstenWallet, "https://ropsten.infura.io/");

module.exports = {
  networks: {
    development: {
      host: "localhost",
      port: 8545,
      network_id: "*" // Match any network id
    },
    ropsten: {
      provider: ropstenProvider,
      // You can get the current gasLimit by running
      // truffle deploy --network rinkeby
      // truffle(rinkeby)> web3.eth.getBlock("pending", (error, result) =>
      //   console.log(result.gasLimit))
      gas: 4600000,
      gasPrice: web3.toWei("20", "gwei"),
      network_id: "3",
    },
    mainnet: {
      provider: mainNetProvider,
      gas: 4600000,
      gasPrice: web3.toWei("20", "gwei"),
      network_id: "1",
    }
  }
};

```

（LCTT 译注：原文采用 `new Buffer` 来获取私钥设置，但 node.js 升级后，废弃了 `new Buffer` 这种用法，运行时会发出警告，所以上面我修改为使用 `Buffer.from` 。）

接下来我们从 Metamask 中得到我们的私钥：

1. 点击你的 Chrome 窗口右上角的狐狸图标。
2. 点击 “Account 1” 右侧的省略号。
3. 点击 “Export Private Key”。
4. 输入你的密码。
5. 点击该文字以复制私钥到剪贴板。

然后打开 `.env`文件，并像下面这样贴入你的私钥（对于 Ropsten 测试网和 Mainnet 主网，你的私钥是一样的）：

```
ROPSTEN_PRIVATE_KEY="123YourPrivateKeyHere"
MAINNET_PRIVATE_KEY="123YourPrivateKeyHere"

```

接下来，让我们部署到 Ropsten 以太坊测试网。

以太坊测试网是一个你可以测试合约的地方。此外还有 [Kovan](https://kovan-testnet.github.io/website/) 和 [Rinkeby](https://www.rinkeby.io/) 测试网。我在这个教程中选择 Ropsten 是因为现在很容易得到 Ropsten 的测试 ETH。这些测试网都类似，你可以使用任何一个你喜欢的，但是在此教程当中我假设你在使用 Ropsten。访问 <https://faucet.metamask.io/> 以得到一些测试 ETH。从 faucet 得到一些 ETH 后，你就可以部署了。

```
$ truffle deploy --network ropsten
Compiling ./contracts/HamburgerCoin.sol...
Compiling ./contracts/Migrations.sol...
Compiling zeppelin-solidity/contracts/math/SafeMath.sol...
Compiling zeppelin-solidity/contracts/token/BasicToken.sol...
Compiling zeppelin-solidity/contracts/token/ERC20.sol...
Compiling zeppelin-solidity/contracts/token/ERC20Basic.sol...
Compiling zeppelin-solidity/contracts/token/StandardToken.sol...
Writing artifacts to ./build/contracts

Using network 'ropsten'.

Running migration: 1_initial_migration.js
  Deploying Migrations...
  ... 0xc2bbe6bf5a7c7c7312c43d65de4c18c51c4d620d5bf51481ea530411dcebc499
  Migrations: 0xd827b6f93fcb50631edc4cf8e293159f0c056538
Saving successful migration to network...
  ... 0xe6f92402e6ca0b1d615a310751568219f66b9d78b80a37c6d92ca59af26cf475
Saving artifacts...
Running migration: 2_deploy_contracts.js
  Deploying HamburgerCoin...
  ... 0x02c4d47526772dc524851fc2180b338a6b037500ab298fa2f405f01abdee21c4
  HamburgerCoin: 0x973b1a5c753a2d5d3924dfb66028b975e7ccca51
Saving artifacts...

```

在 “Saving aritfacts” 上面的这行即是你的合约的新地址。

复制并黏贴该地址到 [Ropsten Etherscan 搜索框](https://ropsten.etherscan.io/)，你就能看到你新部署的合约。

现在你可以在任何 ERC20 兼容的钱包，如 [Mist](https://github.com/ethereum/mist) 、[MyEtherWallet](https://www.myetherwallet.com/)（LCTT 译注：或 ImToken 这样的手机应用）里面使用你的通证了。

为了这篇教程，我构建了一个名为 [Etherface](http://etherface.io/) 的钱包来做演示。

首先你需要添加你的通证到 Etherface：

1. 访问 <http://etherface.io/> 。
2. 确认你在 Metamask 中选择了 “Ropsten” 网络。
3. 点击 “Tokens”。
4. 点击右上角的加号按钮。
5. 输入上面的合约地址。

如果你有朋友想要一些汉堡币，你现在就可以发送给他们了。如果没有，你也可以在你的两个账号间测试转账：

1. 在 Metamask 中点击 “切换账号”按钮（在右上角），并改变你的账号为 “Account 2”。
2. 点击 “Account 2” 右边的省略号，然后选择 “Copy Address to clipboard”。
3. 切换回 “Account 1”，这很重要！否则交易会失败。
4. 在 Etherface 中你的余额下点击 “Send”。
5. 黏贴 “Account 2” 的地址。
6. 输入你要发送的数量。
7. Metamask 会弹出确认窗口，点击 “Submit”。
8. 等大约 15-30 秒。
9. 你的 “Account 1” 的余额应该会减少，“Account 2” 现在会有了一些汉堡币！

最后，让我们来部署到主网（LCTT 译注：这会花费你真实的 ETH，你可以通过查看前面部署到 Ropsten 的合约信息中了解花费了多少 gas，以相应估计实际要花费多少 ETH）：

```
$ truffle deploy --network mainnet

```

你可以如前面一样加你的通证到 Etherface ，并发送你新打造的通证给你的朋友们了！


GNU GPL 许可证常见问题解答（六）

![](/data/attachment/album/201807/10/230420x3sqqwzvvswiss4w.png)

本文由高级咨询师薛亮据自由软件基金会（FSF）的[英文原文](https://www.gnu.org/licenses/gpl-faq.html)翻译而成，这篇常见问题解答澄清了在使用 GNU 许可证中遇到许多问题，对于企业和软件开发者在实际应用许可证和解决许可证问题时具有很强的实践指导意义。

1. [关于 GNU 项目、自由软件基金会（FSF）及其许可证的基本问题](/article-9062-1.html)
2. [对于 GNU 许可证的一般了解](/article-8834-1.html)
3. [在您的程序中使用 GNU 许可证](/article-8761-1.html)
4. [依据GNU许可证分发程序](/article-9222-1.html)
5. [在编写其他程序时采用依据 GNU 许可证发布的程序](/article-9448-1.html)
6. 将作品与依据 GNU 许可证发布的代码相结合
7. 关于违反 GNU 许可证的问题

### 6 将作品与依据 GNU 许可证发布的代码相结合

#### 6.1 GPL v3 是否与 GPL v2 兼容？

不兼容。许多要求已经从 GPL v2 变为 GPL v3，这意味 GPL v2 中的精确要求并不体现在 GPL v3 中，反之亦然。例如，GPL v3 的终止条件比 GPL v2 的终止条件更为宽泛，因此与 GPL v2 的终止条件不同。

由于这些差异，两个许可证不兼容：如果您试图将依据 GPL v2 发布的代码与依据 GPL v3 发布的代码组合，则将违反 GPL v2 的第 6 部分。

但是，如果代码依据 GPL “v2 或更高版本”发布，则与 GPL v3 兼容，因为 GPL v3 是其允许的选项之一。

#### 6.2 GPL v2 是否有提供安装信息的要求？

GPL v3 明确要求再分发中包含完整的必要的“安装信息”。GPL v2 不使用该术语，但它需要再分发中包含用于控制可编译和安装可执行文件的脚本以及完整和相应的源代码。这涵盖了 GPL v3 中称为“安装信息”的部分内容，但不包括所有内容。因此，GPL v3 对安装信息的要求较强。

#### 6.3 各种 GNU 许可证之间如何相互兼容？

各种 GNU 许可证彼此之间具有广泛的兼容性。下面是唯一的一种您不能将遵循两种 GNU 许可证的代码结合起来的情况：将遵循旧版本许可证的代码与遵循该许可证新版本的代码进行结合。

以下是 GNU 许可证的各种结合的详细兼容性矩阵，以便为特定情况提供易于使用的参考。它假设有人依据其中一个许可证编写了一些软件，而您希望以某种方式将该软件的代码结合到您要发布的项目（您自己的原始作品或其他人的软件的修改版本）中。在表顶部的列中找到项目的许可证，并在左侧的一行中找到其他代码的许可证。它们交叉的单元格会告诉您这种结合是否被允许。

当我们说“复制代码”时，我们的意思就是：您正在从一个源代码中获取一段代码（无论是否修改），并将其插入到自己的程序中，从而基于第一部分代码形成一个作品。当您编译或运行代码时，“使用库”意味着您不直接复制任何源代码，而是通过链接、导入或其他典型机制将源代码绑定在一起。

矩阵中每个标明 GPL v3 的地方，其关于兼容性的声明也同样适用于 AGPL v3。

**兼容性矩阵**

|  |  |
| --- | --- |
|   | 我希望依据以下许可证许可我的代码 |
| 仅 GPL v2 | GPL v2 或更高版本 | GPL v3 或更高版本 | 仅 LGPL v2.1 | LGPL v2.1 或更高版本 | LGPL v3 或更高版本 |
| 我希望复制遵循右侧许可证的代码： | 仅 GPL v2 | 可以 | 可以 【2】 | 不可以 | 可以，结合作品只能遵循GPL v2 【7】 | 可以，结合作品只能遵循GPL v2 【7】【2】 | 不可以 |
| GPL v2 或更高版本 | 可以 【1】 | 可以 | 可以 | 可以，结合作品需遵循GPL v2或更高版本 【7】 | 可以，结合作品需遵循GPL v2或更高版本 【7】 | 可以，结合作品需遵循GPL v3 【8】 |
| GPL v3 | 不可以 | 可以，结合作品需遵循GPL v3 【3】 | 可以 | 可以，结合作品需遵循GPL v3 【7】 | 可以，结合作品需遵循GPL v3 【7】 | 可以，结合作品需遵循GPL v3 【8】 |
| 仅 LGPL v2.1 | 可以，需依据GPL v2传递复制后代码 【7】 | 可以，需依据GPL v2或更高版本传递复制后代码 【7】 | 可以，需依据GPL v3传递复制后代码 【7】 | 可以 | 可以 【6】 | 可以，需依据GPL v3传递复制后代码 【7】【8】 |
| LGPL v2.1 或更高版本 | 可以，需依据GPL v2传递复制后代码 【7】【1】 | 可以，需依据GPL v2或更高版本传递复制后代码 【7】 | 可以，需依据GPL v3传递复制后代码 【7】 | 可以 【5】 | 可以 | 可以 |
| LGPL v3 | 不可以 | 可以，结合作品需遵循GPL v3 【8】【3】 | 可以，结合作品需遵循GPL v3 【8】 | 可以，结合作品需遵循GPL v3 【7】【8】 | 可以，结合作品需遵循LGPL v3 【4】 | 可以 |
| 我希望使用遵循右侧许可证的库： | 仅 GPL v2 | 可以 | 可以 【2】 | 不可以 | 可以，结合作品只能遵循GPL v2 【7】 | 可以，结合作品只能遵循GPL v2 【7】【2】 | 不可以 |
| GPL v2 或更高版本 | 可以 【1】 | 可以 | 可以 | 可以，结合作品需遵循GPL v2或更高版本 【7】 | 可以，结合作品需遵循GPL v2或更高版本 【7】 | 可以，结合作品需遵循GPL v3 【8】 |
| GPL v3 | 不可以 | 可以，结合作品需遵循GPL v3 【3】 | 可以 | 可以，结合作品需遵循GPL v3 【7】 | 可以，结合作品需遵循GPL v3 【7】 | 可以，结合作品需遵循GPL v3 【8】 |
| 仅LGPL v2.1 | 可以 | 可以 | 可以 | 可以 | 可以 | 可以 |
| LGPL v2.1 或更高版本 | 可以 | 可以 | 可以 | 可以 | 可以 | 可以 |
| LGPL v3 | 不可以 | 可以，结合作品需遵循GPL v3 【9】 | 可以 | 可以 | 可以 | 可以 |

**角注：**

1. 在这种情况下，当结合代码时，您必须遵守 GPL v2 的条款。您不能适用更高版本的条款。
2. 在这种情况下，您可以依据 GPL v2 或更高版本发布您的项目（您的原始作品和/或您收到并修改的作品），请注意，您使用的其他代码仍然只能遵循 GPL v2。只要您的项目依赖于该代码，您将无法将项目的许可证升级到 GPL v3 或更高版本，整个作品（您的项目和其他代码的任意结合）只能依据 GPL v2 的条款传递。
3. 如果您有能力依据 GPL v2 或任何更高版本发布项目，您可以选择依据 GPL v3 或更高版本发布该项目，一旦您执行此操作，您就可以结合依据 GPL v3 发布的代码。
4. 如果您有能力依据 LGPL v2.1 或任何更高版本发布项目，您可以选择依据 LGPL v3 或更高版本发布该项目，一旦您这样做，您就可以结合依据 LGPL v3 发布的代码。
5. 在这种情况下结合代码时，您必须遵守 LGPL v2.1 的条款。您不能适用更高版本 LGPL 中的条款。
6. 如果这样做，只要项目包含仅依据 LGPL v2.1 发布的代码，您将无法将项目的许可证升级到 LGPL v3 或更高版本。
7. LGPL v2.1 允许您将遵循自 GPL v2 之后任何版本 GPL 的代码进行重新许可。如果在这种情况下可以将遵循 LGPL 的代码切换为使用适当版本的 GPL（如表所示），则可以进行此种结合。
8. LGPL v3 是 GPL v3 加上在这种情况下可以忽略的额外权限。
9. 由于 GPL v2 不允许与 LGPL v3 结合，因此在这种情况下，您必须依据 GPL v3 的条款传递项目，因为它允许此种结合。

#### 6.4 <ruby> “聚合” <rp>  （ </rp> <rt>  aggregate </rt> <rp>  ） </rp></ruby>与其他类型的“修改版本”有什么区别？（同 2.25）

“聚合”由多个单独的程序组成，分布在同一个 CD-ROM 或其他媒介中。GPL 允许您创建和分发聚合，即使其他软件的许可证不是自由许可证或与 GPL 不兼容。唯一的条件是，发布“聚合”所使用的许可证不能禁止用户去行使“聚合”中每个程序对应的许可证所赋予用户的权利。

两个单独的程序还是一个程序有两个部分，区分的界限在哪里？这是一个法律问题，最终由法官决定。我们认为，适当的判断标准取决于通信机制（exec、管道、rpc、共享地址空间内的函数调用等）和通信的语义（哪些信息被互换）。

如果模块们被包含在相同的可执行文件中，则它们肯定是被组合在一个程序中。如果模块们被设计为在共享地址空间中链接在一起运行，那么几乎肯定意味着它们组合成为一个程序。

相比之下，管道、套接字和命令行参数是通常在两个独立程序之间使用的通信机制。所以当它们用于通信时，模块们通常是单独的程序。但是，如果通信的语义足够亲密，交换复杂的内部数据结构，那么也可以视为这两个部分合并成了一个更大的程序。

#### 6.5 我在使用 GPL 程序的源代码时是否具有<ruby> “合理使用” <rp>  （ </rp> <rt>  fair use </rt> <rp>  ） </rp></ruby>权限？（同 4.17）

是的，您有。“合理使用”是在没有任何特别许可的情况下允许的使用。由于您不需要开发人员的许可来进行这种使用，无论开发人员在许可证或其他地方对此怎么说，您都可以执行此操作，无论该许可证是 GNU GPL 还是其他自由软件许可证。

但是，请注意，没有全世界范围普适的合理使用原则；什么样的用途被认为“合理”因国而异。

#### 6.6 美国政府可否对遵循 GPL 的程序进行改进并发布？（同 3.14）

可以。如果这些改进是由美国政府雇员在雇佣期间编写的，那么这些改进属于公有领域。不过，GNU GPL 仍然涵盖了整体的改进版本。在这种情况下没有问题。

如果美国政府使用承包商来完成这项工作，那么改进本身可以被 GPL 覆盖。

#### 6.7 GPL 对于与其所覆盖的作品进行静态或动态链接的模块有不同的要求吗？

没有。将 GPL 覆盖的作品静态或动态地链接到其他模块是基于 GPL 覆盖的作品构建结合作品。因此，GNU GPL 的条款和条件将覆盖整个结合作品。另请参阅：6.24 如果我在 GPL 软件中使用了与 GPL 不兼容的库，会出现什么法律问题？

#### 6.8 LGPL 对于与其所覆盖的作品进行静态或动态链接的模块有不同的要求吗？

为了遵守 LGPL（任何现有版本：v2、v2.1 或 v3）：

（1）如果您静态链接到 LGPL 库，您还必须以对象（不一定是源代码）格式提供应用程序，以便用户有机会修改库并重新链接应用程序。

（2）如果您动态链接*已经存在于用户计算机上*的 LGPL 库，则不需要传递库的源代码。另一方面，如果您自己将可执行的 LGPL 库与您的应用程序一起传递，无论是静态还是动态链接，还必须以 LGPL 所提供的方式之一来传递库的源代码。

#### 6.9 如果库依据 GPL（而不是 LGPL）发布，这是否意味着使用它的任何软件必须遵循 GPL 或与 GPL 兼容的许可证？

是的，因为程序实际上与库进行了链接。因此，GPL 的条款适用于整个结合作品。与库链接的软件模块可能遵循与GPL兼容的不同许可证，但整体作品必须遵循 GPL。另见：“2.23 许可证与 GPL 兼容是什么意思？”

#### 6.10 您有一个遵循 GPL 的程序，我想将它与我的代码进行链接，来构建一个专有程序。那么事实上，我链接到您的程序意味着我必须让我的程序遵循 GPL 许可证？

不完全是。这意味着您必须依据与 GPL 兼容的许可证（更准确地说，与您链接的结合作品中所有其他代码所适用的一个或多个 GPL 版本相兼容）发布您的程序。然后，结合作品本身就可以遵循这些 GPL 版本。

#### 6.11 如果是这样的话，有没有机会依据 LGPL 获得您的程序许可？

您可以这么要求，但绝大多数的作者都会坚定不移地说不。GPL 的想法是，如果要将我们的代码包含在程序中，您的程序也必须是自由软件。GPL 的意图是给您施加压力，让您以能够使其成为我们社区一部分的方式来发布您的程序。

您始终拥有不使用我们代码的合法选择。

#### 6.12 我们构建专有软件的项目不能使用遵循 GPL 的某个 GNU 程序。您会为我们提供例外吗？ 这将意味着该程序拥有更多用户。

对不起，我们没有这样的例外。这样做是不对的。

最大化用户数量不是我们的目标。相反，我们正在努力为尽可能多的用户提供至关重要的自由。一般来说，专有软件项目是阻碍而不是实现软件自由的原因。

我们偶尔提供许可证例外来协助一个依据 GPL 以外的许可证生产自由软件的项目。不过，我们必须看到一个很好的理由，即这个项目为什么会推动自由软件的发展。

我们有时也会改变软件包的分发条款，这显然是为自由软件事业服务的正确方法；但是我们对此非常谨慎，所以您必须向我们展示非常有说服力的理由。

#### 6.13 如果一个编程语言解释器是依据 GPL 发布的，这是否意味着由它解释的程序必须遵循与 GPL 兼容的许可证？

当解释器只是解释一种语言时，答案是否定的。被解释程序对于解释器来说只是数据；根据版权法，像GPL这样的自由软件许可证不能限制您使用解释器的数据。您可以使用任何数据（被解释程序），以任何您喜欢的方式运行它，并且没有任何要求规定您必须将数据授权给任何人。

然而，当解释器被扩展以向<ruby> 其他程序 <rp>  （ </rp> <rt>  facilities </rt> <rp>  ） </rp></ruby>（通常但不一定是库）提供<ruby> “绑定” <rp>  （ </rp> <rt>  bindings </rt> <rp>  ） </rp></ruby>时，被解释程序通过这些绑定有效地与其使用的程序相关联。因此，如果这些程序是依据 GPL 发布的，则使用它们的被解释程序必须以与 GPL 兼容的方式发布。JNI（Java Native Interface）是这种绑定机制的一个例子；以这种方式访问的库与调用它们的 Java 程序动态链接。这些库也与解释器联系在一起。如果解释器与这些库静态链接，或者如果它被设计为[与这些特定库动态链接](https://www.gnu.org/licenses/gpl-faq.html#GPLPluginsInNF)，那么也需要以与 GPL 兼容的方式发布。

另一个类似且非常常见的情况是为库提供解释器，它们能够自我解释。例如，Perl 带有许多 Perl 模块，Java 实现带有许多 Java 类。这些库和调用它们的程序总是动态链接在一起。

结果是，如果您选择在程序中使用遵循 GPL 的 Perl 模块或 Java 类，则必须以与 GPL 兼容的方式发布该程序，无论结合后的 Perl 或 Java 程序所依之运行的 Perl 或 Java 解释器中使用什么样的许可证。

#### 6.14 如果编程语言解释器遵循与 GPL 不兼容的许可证，我可以在其上运行遵循 GPL 的程序吗？

当解释器解释一种语言时，答案是肯定的。被解释程序对于解释器来说只是数据；GPL 不会限制您处理程序时所使用的工具。

然而，当解释器被扩展以向<ruby> 其他程序 <rp>  （ </rp> <rt>  facilities </rt> <rp>  ） </rp></ruby>（通常但不一定是库）提供“绑定”时，被解释程序通过这些绑定有效地与其使用的程序相关联。JNI（Java Native Interface）是此种程序的一个例子；以这种方式访问的库与调用它们的 Java 程序动态链接。

因此，如果这些程序是依据与 GPL 不兼容的许可证发布的，则情况就像以任何其他方式跟与 GPL 不兼容的库链接。这意味着：

1. 如果您正在编写代码并将其依据 GPL 发布，您可以声明一个<ruby> 明确例外 <rp>  （ </rp> <rt>  explicit exception </rt> <rp>  ） </rp></ruby>，允许将其链接到与 GPL 不兼容的程序。
2. 如果您依据 GPL 编写并发布程序，并且专门设计了与这些程序配合使用的功能，人们可以将其作为<ruby> 隐性例外 <rp>  （ </rp> <rt>  implicit exception </rt> <rp>  ） </rp></ruby>，允许它们与这些程序进行链接。但是，如果这只是你的打算的话，最好明确地这么说。

您不能把别人遵循 GPL 的代码用于这种方式，或者添加这样的例外。只有该代码的版权所有者才能添加例外。

#### 6.15 如果我将一个模块添加到遵循 GPL 的程序中，我必须使用 GPL 作为我的模块的许可证吗？

GPL 规定，整个结合后的程序必须依据 GPL 发布。所以你的模块必须可以依据 GPL 进行使用。

但是，您可以提供使用您代码的额外授权。如果您愿意，您可以依据比 GPL 更为宽松但与 GPL 兼容的许可证发布模块。许可证列表页面提供了与 [GPL 兼容许可证](https://www.gnu.org/licenses/license-list.html)的部分列表。

#### 6.16 什么时候程序和插件会被认为是单一的结合程序？

这取决于主程序如何调用其插件。如果主程序使用 `fork` 和 `exec` 来调用插件，并通过共享复杂的数据结构或来回传送复杂的数据结构来建立<ruby> 密切通信 <rp>  （ </rp> <rt>  intimate communication </rt> <rp>  ） </rp></ruby>，可以使它们成为一个单一的结合程序。如果主程序使用简单的 `fork` 和 `exec` 来调用插件并且不建立它们之间的密切通信，插件被认为是一个单独的程序。

如果主程序动态地链接插件，并且它们彼此进行函数调用并共享数据结构，我们相信它们形成了一个单一的结合程序，它必须被视为主程序和插件的扩展。如果主程序动态地链接插件，但是它们之间的通信仅限于使用某些选项调用插件的“main”功能，并等待它返回，这是一种<ruby> 临界案例 <rp>  （ </rp> <rt>  borderline case </rt> <rp>  ） </rp></ruby>。

使用共享内存与复杂数据结构进行通信几乎等同于动态链接。

#### 6.17 如果我写了一个用于遵循 GPL 程序的插件，那么对可用于分发我的插件的许可证有什么要求？

请参阅 “6.16 什么时候程序和插件会被认为是单一的结合程序 ？”以确定插件和主程序是否被视为单个结合程序，以及何时将其视为单独的作品。

如果主程序和插件是单个结合程序，则这意味着您必须依据 GPL 或与 GPL 兼容的自由软件许可证授权插件，并以符合 GPL 的方式将源代码进行分发。与其插件分开的主程序对插件没有要求。

#### 6.18 在为非自由程序编写插件时，可以应用 GPL 许可证吗？

请参阅 “6.16 什么时候程序和插件会被认为是单一的结合程序？”以确定插件和主程序是否被视为单个结合程序，以及何时被视为单独的程序。

如果它们组成单一的结合程序，这意味着遵循 GPL 的插件与非自由主程序的结合将违反 GPL。但是，您可以通过向插件的许可证添加例外声明来解决该法律问题，并允许将其与非自由主程序链接。

另请参阅正在编写的[使用非自由库的自由软件的问题](https://www.gnu.org/licenses/gpl-faq.html#FSWithNFLibs)。

#### 6.19 我可以发布一个旨在加载遵循 GPL 的插件的非自由程序吗？

请参阅 “6.16 什么时候程序和插件会被认为是单一的结合程序？”以确定插件和主程序是否被视为单个结合程序，以及何时被视为单独的程序。

如果它们组成单一的结合程序，则主程序必须依据 GPL 或与 GPL 兼容的自由软件许可证发布，并且当主程序为了与这些插件一起使用而被分发时，必须遵循 GPL 的条款。

然而，如果它们是单独的作品，则插件的许可证对主程序没有要求。

另请参阅正在编写的[使用非自由库的自由软件的问题](https://www.gnu.org/licenses/gpl-faq.html#FSWithNFLibs)。

#### 6.20 我想将遵循 GPL 的软件纳入我的专有系统。我只依据 GPL 给予我的权限来使用该软件。我可以这样做吗？（同 5.6）

您不能将遵循 GPL 的软件纳入专有系统。GPL 的目标是授予每个人复制、再分发、理解和修改程序的自由。如果您可以将遵循 GPL 的软件整合到非自由系统中，则可能会使遵循 GPL 的软件不再是自由软件。

包含遵循 GPL 程序的系统是该 GPL 程序的扩展版本。GPL 规定，如果它最终发布的话，任何扩展版本的程序必须依据 GPL 发布。这有两个原因：确保获得软件的用户获得自己应该拥有的自由，并鼓励人们回馈他们所做的改进。

但是，在许多情况下，您可以将遵循 GPL 的软件与专有系统一起分发。要有效地做到这一点，您必须确保自由和非自由程序之间的通信<ruby> 保持一定距离 <rp>  （ </rp> <rt>  arms length </rt> <rp>  ） </rp></ruby>，而不是将它们有效地结合成一个程序。

这种情况与“纳入”遵循 GPL 的软件之间的区别，是一部分实质和一部分形式的问题。实质上是这样的：如果两个程序结合起来，使它们成为一个程序的两个部分，那么您不能将它们视为两个单独的程序。所以整个作品必须遵循 GPL。

如果这两个程序保持良好的分离，就像编译器和内核，或者像编辑器和shell一样，那么您可以将它们视为两个单独的程序，但是您必须恰当执行。这个问题只是一个形式问题：您如何描述您在做什么。为什么我们关心这个？因为我们想确保用户清楚地了解软件集合中遵循 GPL 的软件的自由状态。

如果人们分发遵循 GPL 的软件，将其称为系统（用户已知其中一部分为专有软件）的“一部分”，用户可能不确定其对遵循GPL的软件所拥有的权利。但是如果他们知道他们收到的是一个自由程序加上另外一个程序，那么他们的权利就会很清楚。

#### 6.21 我想将遵循 GPL 的软件纳入我的专有系统。我是否可以通过在 GPL 覆盖的部分和专有部分之间，放置一个遵循与 GPL 兼容的宽松许可证（如 X11 许可证）的<ruby> “封装” <rp>  （ </rp> <rt>  wrapper </rt> <rp>  ） </rp></ruby>模块来实现？

不可以，X11 许可证与 GPL 兼容，因此您可以向遵循 GPL 的程序添加一个模块，并让其遵循 X11 许可证。但是，如果要将它们整合到一个更大的程序中，那么这个整体将包含 GPL 覆盖的部分，所以它必须在 GNU GPL 下作为一个整体获得许可。

专有模块 A 仅通过遵循 X11 许可证的模块 B 与遵循 GPL 的模块 C 通信，该事实在法律上是无关紧要的；重要的是模块 C 包含在整体作品中。

#### 6.22 我可以编写使用非自由库的自由软件吗？

如果您这样做，您的程序将无法在一个自由的环境中完全使用。如果您的程序依赖于一个非自由库来做某件工作，那么在自由软件世界里就不能做这个工作。如果这依赖于一个非自由库来运行，它不能是自由操作系统（例如 GNU）的一部分；这完全成为了自由软件世界里的禁区。

所以请考虑：你可以找到一种方法来完成这项工作，而不使用这个库吗？你可以为该库编写一个自由软件替代选择吗？

如果程序已经使用非自由库编写，那么改变决定也许已经太晚了。您也可以按照目前状态来发布程序，而不是不发布。但是请在 README 文件中提到，对非自由库的需求是一个缺点，并建议更改程序以便在没有非自由库的情况下执行相同的工作。请建议任何想要在程序上进行大量进一步工作的人首先将其从依赖非自由库中解脱出来。

请注意，将某些非自由库与遵循 GPL 的自由软件相结合也可能存在法律问题。有关更多信息，请参阅有关 [GPL 软件与和其不兼容库的问题](https://www.gnu.org/licenses/gpl-faq.html#GPLIncompatibleLibs)。

#### 6.23 我可以将遵循 GPL 的程序与专有系统库链接吗？

每个版本的 GPL 相对于其<ruby> 左版 <rp>  （ </rp> <rt>  copyleft </rt> <rp>  ） </rp></ruby>都有一个例外，通常称为系统库例外。如果您要使用的与 GPL 不兼容的库符合系统库的标准，则使用它们不需要做特别的工作；分发整个程序的源代码的要求不包括那些库，即使您分发包含它们的链接可执行文件。

作为<ruby> “系统库” <rp>  （ </rp> <rt>  system library </rt> <rp>  ） </rp></ruby>的标准在不同版本的 GPL 之间有所不同。GPL v3 在第 1 节中明确定义“系统库”，将其从<ruby> “相应源代码” <rp>  （ </rp> <rt>  Corresponding Source </rt> <rp>  ） </rp></ruby>的定义中排除。GPL v2 在第 3 部分的末尾进行，处理这个问题略有不同。

#### 6.24 如果我在遵循 GPL 的软件中使用了与 GPL 不兼容的库，会出现什么法律问题？

如果您希望程序与未被系统库例外所涵盖的库链接，则需要提供许可来执行此操作。以下是您可以使用的两个许可证通知示例；一个用于 GPL v3，另一个用于 GPL v2。在这两种情况下，您应该将此文本放在您授予此权限的每个文件中。

只有该程序的版权持有人才能合法地按照这些条款发布其软件。如果您自己编写了整个程序，假设您的雇主或学校没有声明版权，您就是版权所有者，因此您可以授权该例外。但是，如果您想在代码中使用其他作者的其他遵循GPL的程序的一部分，那么您无法将例外授权给他们。您必须获得这些程序的版权所有者的批准。

当其他人修改程序时，他们不需要为他们的代码设置同样的例外——是否这样做是他们自己的选择。

如果您打算链接的库不是自由软件，请参阅[使用非自由库编写自由软件部分](https://www.gnu.org/licenses/gpl-faq.html#FSWithNFLibs)。

如果您使用 GPL v3，您可以通过在第 7 节下授予额外权限来实现此目标。以下许可证通知将会执行此操作。您必须使用适合您程序的文本替换括号中的所有文本。如果不是每个人都可以为您打算链接的库分发源代码，则应该删除大括号中的文本；否则，只需删除大括号。

>
> Copyright (C) [年份] [著作权人名称]
>
>
> 本程序为自由软件；您可以根据自由软件基金会发布的 GNU GPL 许可证的条款再分发和/或修改它；无论是依据本许可证的版本3，或（根据您的选择）任何更高版本。
>
>
> 本程序基于希望其有用的目标而分发，但**不提供任何担保**；甚至也**没有适销性或适用于特定用途的默示担保**。有关详细信息，请参阅 GNU GPL 许可证。
>
>
> 您应该已经收到本程序以及 GNU GPL 许可证的副本；如果没有，请参阅 <http://www.gnu.org/licenses>。
>
>
> 依据 GNU GPL v3 第7节的额外许可
>
>
> 如果您通过将[与库的名称]（或库的修改版本）链接或结合来修改本程序，或任何被覆盖的作品，其中包含被[库许可证的名称]的条款所覆盖的部分，则该程序的许可人授予您额外许可来传递所产出的作品。{这种结合的非源代码形式的相应源代码应包括所使用的[库名称]部分的源代码以及被覆盖的作品的源代码。}
>
>
>

如果您使用 GPL v2，您可以为许可证条款提供自己的例外。以下许可证通知将这样做。同样，您必须使用适合您程序的文本替换括号中的所有文本。如果不是每个人都可以为您打算链接的库分发源代码，则应该删除大括号中的文本；否则，只需删除大括号。

>
> Copyright (C) [年份] [著作权人名称]
>
>
> 本程序为自由软件；您可以根据自由软件基金会发布的 GNU GPL 许可证的条款再分发和/或修改它；无论是依据许可证的 v2，或（根据您的选择）任何更高版本。
>
>
> 本程序基于希望其有用的目标而分发，但**不提供任何担保**；甚至也**没有适销性或适用于特定用途的默示担保**。有关详细信息，请参阅 GNU GPL 许可证。
>
>
> 您应该已经收到本程序以及 GNU GPL 许可证的副本；如果没有，请参阅 <http://www.gnu.org/licenses>。
>
>
> 将[您的程序名称]与其他模块静态或动态链接是以[您的程序名称]为基础构建结合作品。因此，GNU GPL 许可证的条款和条件将覆盖整个结合作品。
>
>
> 另外，作为一个特殊例外，[您的程序名称]的版权持有人可以让您将[您的程序名称]与依据 GNU LGPL 发布的自由程序或库以及依据[库的许可证名称]标准发布的[库名称]中包含的代码相结合（或具有相同许可证的此类代码的修改版本）。您可以按照[您的程序名称]所依据的 GNU GPL 的条款和其他有关代码的许可证复制和分发此系统{前提是当 GNU GPL 要求分发源代码时将其他代码的源代码包含在内}。
>
>
> 注意，对[您的程序名称]做出修改版本的人没有义务为其修改版本授予此特殊例外；是否这样做是他们自己的选择。GNU GPL 许可证允许发布一个没有此例外的修改版本；该例外也使得发布一个带有该例外的修改版本成为可能。
>
>
>

#### 6.25 我正在使用 Microsoft Visual C ++（或 Visual Basic）编写 Windows 应用程序，我将依据 GPL 发布它。依据GPL，是否允许将我的程序与 Visual C ++（或 Visual Basic）运行时库动态链接？

您可以将您的程序链接到这些库，并将编译后的程序分发给其他程序。执行此操作时，运行时库是 GPL v3 所定义的“系统库”。这意味着您不需要担心将库的源代码包含在程序的相应源代码中。GPL v2 在第 3 节中提供了类似的例外。

您可能不会随同您的程序以编译后的 DLL 形式分发这些库。为了防止不道德的分发者试图将系统库例外作为漏洞进行利用，GPL 表示，只有库不与程序本身一起分发，库才能被认定为系统库。如果您随同您的程序分发 DLL，则它们将不再符合此例外的资格；那么遵守 GPL 的唯一方法就是提供它们的源代码，而您无法做到。

可以编写只在 Windows 上运行的自由程序，但这不是一个好主意。这些程序将被 Windows <ruby>   “围困”  <rp>  （ </rp> <rt>  trapped </rt> <rp>  ） </rp></ruby>，因此对自由软件世界的贡献为零。

#### 6.26 我想修改遵循 GPL 的程序，并将它们与 Money Guzzler Inc. 的可移植性库链接。我无法分发这些库的源代码，因此，任何想要更改这些版本的用户都必须单独获取这些库。为什么 GPL 不允许这样做？

有两个原因。第一、一般性的原因。如果我们允许 A 公司制作一个专有文件，B 公司分发与该文件相关的遵循 GPL 的软件，其效果等同于将 GPL 撕开一个大洞。对于保持 GPL 软件各种修改和扩展的源代码来说，这如同一张署名空白纸。

让所有用户能够访问源代码是我们的主要目标之一，所以这个结果绝对是我们想要避免的。

更具体地说，根据我们对条款的理解，与 Money Guzzler 库链接的程序版本不会是真正的自由软件——它们不会附带完整的让用户能够更改和重新编译程序的源代码。

#### 6.27 如果模块 Q 的许可证具有与 GPL 不兼容的要求，但是只有当 Q 自身分发时，而不是在较大程序中包含 Q 时，该要求才适用，是否可以使得该许可证与 GPL 兼容？可以将 Q 与遵循 GPL 的程序结合使用吗？

如果程序 P 依据 GPL 被发布，这意味着“任何和所有部分”都可以依据 GPL 进行使用。如果您集成了模块 Q，并依据 GPL 发布结合程序 P + Q，则表示可以依据 GPL 使用 P + Q 的任何部分。P + Q 的一部分是 Q，所以依据 GPL 发布 P + Q 意味着，Q 的任何部分可以依据 GPL 进行使用。换句话说，依据 GPL 获得 P + Q 的用户可以删除 P，所以 Q 仍然遵循 GPL。

如果模块 Q 的许可证允许您授予该许可，则其与 GPL 兼容。否则，它不与 GPL 兼容。

如果 Q 的许可证在不明确的条件下表示，您必须在自己再分发 Q 时做某些事情（与 GPL 不兼容），那么不允许您依据 GPL 分发Q。因此，您也不能依据 GPL 发布 P + Q。所以您不能将 P 与 Q 进行链接或结合。

#### 6.28 在面向对象的语言（如 Java）中，如果我在不修改的情况下使用遵循 GPL 的类，并对其进行子类化，GPL 会以什么方式影响较大的程序？

子类化将会创建衍生作品。因此，当您创建遵循 GPL 的类的子类时，GPL 的条款会影响整个程序。

#### 6.29 分发一个意图链接到 Linux 内核的非自由驱动程序会违反 GPL 吗？

Linux（GNU / Linux 操作系统中的内核）依据 GNU GPL v2 进行分发。分发一个意图链接 Linux 的非自由驱动程序违反 GPL 吗？

是的，这是一种违规行为，因为这样做形成了更大的结合作品。用户期望把这些片段放在一起的事实并不会改变任何事情。

在代码实体部分拥有版权的 Linux 的每个贡献者都可以执行 GPL，我们鼓励他们对那些分发非自由 Linux 驱动程序的人采取行动。

#### 6.30 如何允许在受控接口下将专有模块与我的 GPL 库链接起来？

在声明该文件依据 GNU GPL 进行分发的文本末尾，将以下文本添加到软件包中每个文件的许可证通知中：

>
> 将 ABC 与其他模块静态或动态链接是基于 ABC 创建结合作品。因此，GNU GPL 许可证的条款和条件将覆盖整个结合作品。
>
>
> 作为一个特殊的例外，ABC 的版权所有者可以将 ABC 程序与自由软件程序或依据 GNU LGPL 发布的库以及通过 ABCDEF 界面与 ABC 通信的独立模块相结合。您可以根据 ABC 的 GNU GPL 条款和其他代码的许可证复制和分发此系统，前提是您在 GNU GPL 需要分发源代码时提供该代码的源代码，并且您没有修改 ABCDEF 界面。
>
>
> 请注意，制作 ABC 修改版本的人没有义务为其修改版本授予此特殊例外；是否这样做是他们自己的选择。GNU GPL 许可证允许发布不含此例外的修改版本；此例外也使得发布一个带有该例外的修改版本成为可能。如果您修改了 ABCDEF 界面，此例外不适用于您修改的 ABC 版本，并且您必须在分发修改后的版本时删除此例外。
>
>
> 此例外是依据 GNU GPL 许可证第3版（“GPL v3”）第7节的额外权限。
>
>
>

此例外允许通过指定接口（“ABCDEF”）与遵循不同许可证的模块进行链接，同时确保用户仍然会按照 GPL 通常的方式接收源代码。

只有该程序的版权持有者才能合法授权此例外。如果您自己编写了整个程序，假设您的雇主或学校没有声明版权，您就是版权所有者，因此您可以授权该例外。但是，如果您想在代码中使用其他作者的其他遵循 GPL 程序的一部分，那么您无法对他们的例外进行授权。您必须获得这些程序的版权所有者的批准。

#### 6.31 考虑这种情况：1）X 发布遵循 GPL 的项目的 V1 版本。2）基于对 V1 的修改和新代码开发，Y 对 V2 的改进做出贡献。3）X 想将 V2 转换为非 GPL 许可证。X 需要 Y 的许可吗？

需要。Y 需要依据 GNU GPL 发布其版本，因为它基于 X 的版本 V1。没有任何要求规定 Y 为其代码适用任何其他许可。因此，X 必须获得 Y 的许可才能依据另一个许可证发布该代码。

#### 6.32 我已经编写了一个与许多不同组件链接的应用程序，它们具有不同的许可证。我对我的程序有什么许可要求感到很困惑。您能告诉我可以使用哪些许可证吗？

为了回答这个问题，我们需要看一下你的程序使用的每个组件的列表，该组件的许可证和一个简短的（几句话应该足够）说明你的库如何使用该组件的描述。两个例子是：

* 为了让我的软件工作，它必须链接到遵循 LGPL 的 FOO 库。
* 我的软件进行系统调用（使用我建立的命令行）来运行 BAR 程序，该程序遵循 GPL，“具有允许与 QUUX 链接的特殊例外”。

#### 6.33 可以在依据与 GPL 不兼容的许可证进行许可的文档中使用遵循 GPL 的源代码片段吗？

如果片段足够小，依据“合理使用”或类似的法律，您可以将它们纳入其中，那么可以。否则，不可以。

---

译者介绍：薛亮，集慧智佳知识产权咨询公司高级咨询师，擅长专利检索、专利分析、竞争对手跟踪、FTO 分析、开源软件知识产权风险分析，致力于为互联网企业、高科技公司提供知识产权咨询服务。

![](/data/attachment/album/201801/10/210130rsis334kss4esehz.jpg)


如何在 Fedora 上安装 Pipenv

![](/data/attachment/album/201807/11/150156gtptutmuktkpo85p.jpg)

Pipenv 的目标是将打包界（bundler、composer、npm、cargo、yarn 等）最好的东西带到 Python 世界来。它试图解决一些问题，并简化整个管理过程。

目前，Python 程序依赖项的管理有时似乎是一个挑战。开发人员通常为每个新项目创建一个[虚拟环境](https://packaging.python.org/tutorials/installing-packages/#creating-virtual-environments)，并使用 [pip](https://developer.fedoraproject.org/tech/languages/python/pypi-installation.html) 将依赖项安装到其中。此外，他们必须将已安装的软件包的集合保存到 `requirements.txt` 文件中。我们看到过许多旨在自动化此工作流程的工具和包装程序。但是，仍然需要结合多个程序，并且 `requirements.txt` 格式本身并不适用于更复杂的场景。

### 一个统治它们的工具

Pipenv 可以正确地管理复杂的相互依赖关系，它还提供已安装包的手动记录。例如，开发、测试和生产环境通常需要一组不同的包。过去，每个项目需要维护多个 `requirements.txt`。Pipenv 使用 [TOML](https://github.com/toml-lang/toml) 语法引入了新的 [Pipfile](https://github.com/pypa/pipfile) 格式。多亏这种格式，你终于可以在单个文件中维护不同环境的多组需求。

在将第一行代码提交到项目中仅一年后，Pipenv 已成为管理 Python 程序依赖关系的官方推荐工具。现在它终于在 Fedora 仓库中提供。

### 在 Fedora 上安装 Pipenv

在全新安装 Fedora 28 及更高版本后，你只需在终端上运行此命令即可安装 Pipenv：

```
$ sudo dnf install pipenv

```

现在，你的系统已准备好在 Pipenv 的帮助下开始使用新的 Python 3 程序。

重要的是，虽然这个工具为程序提供了很好的解决方案，但它并不是为处理库需求而设计的。编写 Python 库时，不需要固定依赖项。你应该在 `setup.py` 文件中指定 `install_requires`。

### 基本依赖管理

首先为项目创建一个目录：

```
$ mkdir new-project && cd new-project

```

接下来是为此项目创建虚拟环境：

```
$ pipenv --three

```

这里的 `-three` 选项将虚拟环境的 Python 版本设置为 Python 3。

安装依赖项：

```
$ pipenv install requests
Installing requests…
Adding requests to Pipfile's [packages]…
Pipfile.lock not found, creating…
Locking [dev-packages] dependencies…
Locking [packages] dependencies…

```

最后生成 lockfile：

```
$ pipenv lock
Locking [dev-packages] dependencies…
Locking [packages] dependencies…
Updated Pipfile.lock (b14837)

```

你还可以检查依赖关系图：

```
$ pipenv graph
- certifi [required: >=2017.4.17, installed: 2018.4.16]
- chardet [required: <3.1.0,>=3.0.2, installed: 3.0.4]
- idna [required: <2.8,>=2.5, installed: 2.7]
- urllib3 [required: >=1.21.1,<1.24, installed: 1.23]

```

有关 Pipenv 及其命令的更多详细信息，请参见[文档](https://docs.pipenv.org/)。

---

via: <https://fedoramagazine.org/install-pipenv-fedora/>

作者：[Michal Cyprian](https://fedoramagazine.org/author/mcyprian/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

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


你应该了解的 6 个开源 AI 工具

Summary: 让我们来看看几个任何人都能用的自由开源的 AI 工具。

让我们来看看几个任何人都能用的自由开源的 AI 工具。

>
> 让我们来看看几个任何人都能用的自由开源的 AI 工具。
>
>
>

![](/data/attachment/album/201807/12/102642bb79nfs178o7dd1m.jpg)

在开源领域，不管你的想法是多少的新颖独到，先去看一下别人是否已经做成了这个概念，总是一个很明智的做法。对于有兴趣借助不断成长的<ruby> 人工智能 <rt>  Artificial Intelligence </rt></ruby>（AI）的力量的组织和个人来说，许多优秀的工具不仅是自由开源的，而且在很多的情况下，它们都已经过测试和久经考验的。

在领先的公司和非盈利组织中，AI 的优先级都非常高，并且这些公司和组织都开源了很有价值的工具。下面的举例是任何人都可以使用的自由开源的 AI 工具。

### Acumos

[Acumos AI](https://www.acumos.org/) 是一个平台和开源框架，使用它可以很容易地去构建、共享和分发 AI 应用。它规范了运行一个“开箱即用的”通用 AI 环境所需要的<ruby> 基础设施栈 <rt>  infrastructure stack </rt></ruby>和组件。这使得数据科学家和模型训练者可以专注于它们的核心竞争力，而不用在无止境的定制、建模，以及训练一个 AI 实现上浪费时间。

Acumos 是 [LF 深度学习基金会](https://www.linuxfoundation.org/projects/deep-learning/) 的一部分，它是 Linux 基金会中的一个组织，它支持在人工智能、<ruby> 机器学习 <rt>  machine learning </rt></ruby>、以及<ruby> 深度学习 <rt>  deep learning </rt></ruby>方面的开源创新。它的目标是让这些重大的新技术可用于开发者和数据科学家，包括那些在深度学习和 AI 上经验有限的人。LF 深度学习基金会 [最近批准了一个项目生命周期和贡献流程](https://www.linuxfoundation.org/blog/lf-deep-learning-foundation-announces-project-contribution-process/)，并且它现在正接受项目贡献的建议。

### Facebook 的框架

Facebook [开源了](https://code.facebook.com/posts/1687861518126048/facebook-to-open-source-ai-hardware-design/) 其中心机器学习系统，它设计用于做一些大规模的人工智能任务，以及一系列其它的 AI 技术。这个工具是经过他们公司验证使用的平台的一部分。Facebook 也开源了一个叫 [Caffe2](https://venturebeat.com/2017/04/18/facebook-open-sources-caffe2-a-new-deep-learning-framework/) 的深度学习和人工智能的框架。

### CaffeOnSpark

**说到 Caffe**。 Yahoo 也在开源许可证下发布了它自己的关键的 AI 软件。[CaffeOnSpark 工具](http://yahoohadoop.tumblr.com/post/139916563586/caffeonspark-open-sourced-for-distributed-deep) 是基于深度学习的，它是人工智能的一个分支，在帮助机器识别人类语言，或者照片、视频的内容方面非常有用。同样地，IBM 的机器学习程序 [SystemML](https://systemml.apache.org/) 可以通过 Apache 软件基金会自由地共享和修改。

### Google 的工具

Google 花费了几年的时间开发了它自己的 [TensorFlow](https://www.tensorflow.org/) 软件框架，用于去支持它的 AI 软件和其它预测和分析程序。TensorFlow 是你可能都已经在使用的一些 Google 工具背后的引擎，包括 Google Photos 和在 Google app 中使用的语言识别。

Google 开源了两个 [AIY 套件](https://www.techradar.com/news/google-assistant-sweetens-raspberry-pi-with-ai-voice-control)，它可以让个人很容易地使用人工智能，它们专注于计算机视觉和语音助理。这两个套件将用到的所有组件封装到一个盒子中。该套件目前在美国的 Target 中有售，并且它是基于开源的树莓派平台的 —— 有越来越多的证据表明，在开源和 AI 交集中将发生非常多的事情。

### H2O.ai

我 [以前介绍过](https://www.linux.com/news/sparkling-water-bridging-open-source-machine-learning-and-apache-spark) H2O.ai，它在机器学习和人工智能领域中占有一席之地，因为它的主要工具是自由开源的。你可以获取主要的 H2O 平台和 Sparkling Water，它与 Apache Spark 一起工作，只需要去 [下载](http://www.h2o.ai/download) 它们即可。这些工具遵循 Apache 2.0 许可证，它是一个非常灵活的开源许可证，你甚至可以在 Amazon Web 服务（AWS）和其它的集群上运行它们，而这仅需要几百美元而已。

### Microsoft 入局

“我们的目标是让 AI 大众化，让每个人和组织获得更大的成就，“ Microsoft CEO 萨提亚·纳德拉 [说](https://blogs.msdn.microsoft.com/uk_faculty_connection/2017/02/10/microsoft-cognitive-toolkit-cntk/)。因此，微软持续迭代它的 [Microsoft Cognitive Toolkit](https://www.microsoft.com/en-us/cognitive-toolkit/)（CNTK）。它是一个能够与 TensorFlow 和 Caffe 去竞争的一个开源软件框架。Cognitive Toolkit 可以工作在 64 位的 Windows 和 Linux 平台上。

Cognitive Toolkit 团队的报告称，“Cognitive Toolkit 通过允许用户去创建、训练，以及评估他们自己的神经网络，以使企业级的、生产系统级的 AI 成为可能，这些神经网络可能跨多个 GPU 以及多个机器在大量的数据集中高效伸缩。”

---

从来自 Linux 基金会的新电子书中学习更多的有关 AI 知识。Ibrahim Haddad 的 [开源 AI：项目、洞察和趋势](https://www.linuxfoundation.org/publications/open-source-ai-projects-insights-and-trends/) 调查了 16 个流行的开源 AI 项目—— 深入研究了他们的历史、代码库、以及 GitHub 的贡献。 [现在可以免费下载这个电子书](https://www.linuxfoundation.org/publications/open-source-ai-projects-insights-and-trends/)。

---

via: <https://www.linux.com/blog/2018/6/6-open-source-ai-tools-know>

作者：[Sam Dean](https://www.linux.com/users/sam-dean) 选题：[lujun9972](https://github.com/lujun9972) 译者：[qhwdw](https://github.com/qhwdw) 校对：[pityonline](https://github.com/pityonline), [wxy](https://github.com/wxy)

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