分类 技术 下的文章

从调试器中获取函数调用关系。

在我的 上一篇文章 中,我展示了如何使用 debuginfo 在当前指令指针(IP)和包含它的函数或行之间进行映射。该信息对于显示 CPU 当前正在执行的代码很有帮助。不过,如果能显示更多的有关当前函数调用栈及其正在执行语句的上下文对我们定位问题来说也是十分有助的。

例如,将空指针作为参数传递到函数中而导致非法内存访问的问题,只需查看当前执行函数行,即可发现该错误是由尝试通过空指针进行访问而触发的。但是,你真正想知道的是导致空指针访问的函数调用的完整上下文,以便确定该空指针最初是如何传递到该函数中的。此上下文信息由回溯提供,可以让你确定哪些函数可能对空指针参数负责。

有一点是肯定的:确定当前活动的函数调用栈不是一项简单的操作。

函数激活记录

现代编程语言具有局部变量,并允许函数可以调用自身的递归。此外,并发程序具有多个线程,这些线程可能同时运行相同的函数。在这些情况下,局部变量不能存储在全局位置。对于函数的每次调用,局部变量的位置必须是唯一的。它的工作原理如下:

  • 每次调用函数时,编译器都会生成函数激活记录,以将局部变量存储在唯一位置。
  • 为了提高效率,处理器堆栈用于存储函数激活记录。
  • 当函数被调用时,会在处理器堆栈的顶部为该函数创建一条新的函数激活记录。
  • 如果该函数调用另一个函数,则新的函数激活记录将放置在现有函数激活记录之上。
  • 每次函数返回时,其函数激活记录都会从堆栈中删除。

函数激活记录的创建是由函数中称为“ 序言 prologue ”的代码创建的。函数激活记录的删除由函数“ 尾声 epilogue ”处理。函数体可以利用堆栈上为其预留的内存来存储临时值和局部变量。

函数激活记录的大小可以是可变的。对于某些函数,不需要空间来存储局部变量。理想情况下,函数激活记录只需要存储调用 函数的函数的返回地址。对于其他函数,除了返回地址之外,可能还需要大量空间来存储函数的本地数据结构。帧大小的可变导致编译器使用帧指针来跟踪函数激活帧的开始。函数序言代码具有在为当前函数创建新帧指针之前存储旧帧指针的额外任务,并且函数尾声必须恢复旧帧指针值。

函数激活记录的布局方式、调用函数的返回地址和旧帧指针是相对于当前帧指针的恒定偏移量。通过旧的帧指针,可以定位堆栈上下一个函数的激活帧。重复此过程,直到检查完所有函数激活记录为止。

优化复杂性

在代码中使用显式帧指针有几个缺点。在某些处理器上,可用的寄存器相对较少。具有显式帧指针会导致使用更多内存操作。生成的代码速度较慢,因为帧指针必须位于寄存器中。具有显式帧指针可能会限制编译器可以生成的代码,因为编译器可能不会将函数序言和尾声代码与函数体混合。

编译器的目标是尽可能生成快速代码,因此编译器通常会从生成的代码中省略帧指针。正如 Phoronix 的基准测试 所示,保留帧指针会显着降低性能。不过省略帧指针也有缺点,查找前一个调用函数的激活帧和返回地址不再是相对于帧指针的简单偏移。

调用帧信息

为了帮助生成函数回溯,编译器包含 DWARF 调用帧信息(CFI)来重建帧指针并查找返回地址。此补充信息存储在执行的 .eh_frame 部分中。与传统的函数和行位置信息的 debuginfo 不同,即使生成的可执行文件没有调试信息,或者调试信息已从文件中删除,.eh_frame 部分也位于可执行文件中。 调用帧信息对于 C++ 中的 throw-catch 等语言结构的操作至关重要。

CFI 的每个功能都有一个帧描述条目(FDE)。作为其步骤之一,回溯生成过程为当前正在检查的激活帧找到适当的 FDE。将 FDE 视为一张表,每一行代表一个或多个指令,并具有以下列:

  • 规范帧地址(CFA),帧指针指向的位置
  • 返回地址
  • 有关其他寄存器的信息

FDE 的编码旨在最大限度地减少所需的空间量。FDE 描述了行之间的变化,而不是完全指定每一行。为了进一步压缩数据,多个 FDE 共有的起始信息被分解出来并放置在通用信息条目(CIE)中。 这使得 FDE 更加紧凑,但也需要更多的工作来计算实际的 CFA 并找到返回地址位置。该工具必须从未初始化状态启动。它逐步遍历 CIE 中的条目以获取函数条目的初始状态,然后从 FDE 的第一个条目开始继续处理 FDE,并处理操作,直到到达覆盖当前正在分析的指令指针的行。

调用帧信息使用实例

从一个简单的示例开始,其中包含将华氏温度转换为摄氏度的函数。 内联函数在 CFI 中没有条目,因此 f2c 函数的 __attribute__((noinline)) 确保编译器将 f2c 保留为真实函数。

#include <stdio.h>

int __attribute__ ((noinline)) f2c(int f)
{
    int c;
    printf("converting\n");
    c = (f-32.0) * 5.0 /9.0;
    return c;
}

int main (int argc, char *argv[])
{
    int f;
    scanf("%d", &f);
    printf ("%d Fahrenheit = %d Celsius\n",
            f, f2c(f));
    return 0;
}

编译代码:

$ gcc -O2 -g -o f2c f2c.c

.eh_frame 部分展示如下:

$ eu-readelf -S f2c |grep eh_frame
[17] .eh_frame_hdr  PROGBITS   0000000000402058 00002058 00000034  0 A  0   0  4
[18] .eh_frame      PROGBITS   0000000000402090 00002090 000000a0  0 A  0   0  8

我们可以通过以下方式获取 CFI 信息:

$ readelf --debug-dump=frames  f2c > f2c.cfi

生成 f2c 可执行文件的反汇编代码,这样你可以查找 f2cmain 函数:

$ objdump -d f2c > f2c.dis

f2c.dis 中找到以下信息来看看 f2cmain 函数的执行位置:

0000000000401060 <main>:
0000000000401190 <f2c>:

在许多情况下,二进制文件中的所有函数在执行函数的第一条指令之前都使用相同的 CIE 来定义初始条件。 在此示例中, f2cmain 都使用以下 CIE:

00000000 0000000000000014 00000000 CIE
  Version:                   1
  Augmentation:              "zR"
  Code alignment factor: 1
  Data alignment factor: -8
  Return address column: 16
  Augmentation data:         1b
  DW_CFA_def_cfa: r7 (rsp) ofs 8
  DW_CFA_offset: r16 (rip) at cfa-8
  DW_CFA_nop
  DW_CFA_nop

本示例中,不必担心增强或增强数据条目。由于 x86\_64 处理器具有 1 到 15 字节大小的可变长度指令,因此 “代码对齐因子” 设置为 1。在只有 32 位(4 字节指令)的处理器上,“代码对齐因子” 设置为 4,并且允许对一行状态信息适用的字节数进行更紧凑的编码。类似地,还有 “数据对齐因子” 来使 CFA 所在位置的调整更加紧凑。在 x86\_64 上,堆栈槽的大小为 8 个字节。

虚拟表中保存返回地址的列是 16。这在 CIE 尾部的指令中使用。 有四个 DW_CFA 指令。第一条指令 DW_CFA_def_cfa 描述了如果代码具有帧指针,如何计算帧指针将指向的规范帧地址(CFA)。 在这种情况下,CFA 是根据 r7 (rsp)CFA=rsp+8 计算的。

第二条指令 DW_CFA_offset 定义从哪里获取返回地址 CFA-8 。在这种情况下,返回地址当前由堆栈指针 (rsp+8)-8 指向。CFA 从堆栈返回地址的正上方开始。

CIE 末尾的 DW_CFA_nop 进行填充以保持 DWARF 信息的对齐。 FDE 还可以在末尾添加填充以进行对齐。

f2c.cfi 中找到 main 的 FDE,它涵盖了从 0x40160 到(但不包括)0x401097main 函数:

00000084 0000000000000014 00000088 FDE cie=00000000 pc=0000000000401060..0000000000401097
  DW_CFA_advance_loc: 4 to 0000000000401064
  DW_CFA_def_cfa_offset: 32
  DW_CFA_advance_loc: 50 to 0000000000401096
  DW_CFA_def_cfa_offset: 8
  DW_CFA_nop

在执行函数中的第一条指令之前,CIE 描述调用帧状态。然而,当处理器执行函数中的指令时,细节将会改变。 首先,指令 DW_CFA_advance_locDW_CFA_def_cfa_offsetmain401060 处的第一条指令匹配。 这会将堆栈指针向下调整 0x18(24 个字节)。 CFA 没有改变位置,但堆栈指针改变了,因此 CFA 在 401064 处的正确计算是 rsp+32。 这就是这段代码中序言指令的范围。 以下是 main 中的前几条指令:

0000000000401060 <main>:
  401060:    48 83 ec 18      sub        $0x18,%rsp
  401064:    bf 1b 20 40 00   mov        $0x40201b,%edi

DW_CFA_advance_loc 使当前行应用于函数中接下来的 50 个字节的代码,直到 401096。CFA 位于 rsp+32,直到 401092 处的堆栈调整指令完成执行。DW_CFA_def_cfa_offset 将 CFA 的计算更新为与函数入口相同。这是预期之中的,因为 401096 处的下一条指令是返回指令 ret,并将返回值从堆栈中弹出。

  401090:    31 c0        xor        %eax,%eax
  401092:    48 83 c4 18  add        $0x18,%rsp
  401096:    c3           ret

f2c 函数的 FDE 使用与 main 函数相同的 CIE,并覆盖 0x411900x4011c3 的范围:

00000068 0000000000000018 0000006c FDE cie=00000000 pc=0000000000401190..00000000004011c3
  DW_CFA_advance_loc: 1 to 0000000000401191
  DW_CFA_def_cfa_offset: 16
  DW_CFA_offset: r3 (rbx) at cfa-16
  DW_CFA_advance_loc: 29 to 00000000004011ae
  DW_CFA_def_cfa_offset: 8
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop

可执行文件中 f2c 函数的 objdump 输出:

0000000000401190 <f2c>:
  401190:    53                       push   %rbx
  401191:    89 fb                    mov    %edi,%ebx
  401193:    bf 10 20 40 00           mov    $0x402010,%edi
  401198:    e8 93 fe ff ff           call   401030 <puts@plt>
  40119d:    66 0f ef c0              pxor   %xmm0,%xmm0
  4011a1:    f2 0f 2a c3              cvtsi2sd %ebx,%xmm0
  4011a5:    f2 0f 5c 05 93 0e 00     subsd  0xe93(%rip),%xmm0        # 402040 <__dso_handle+0x38>
  4011ac:    00 
  4011ad:    5b                       pop    %rbx
  4011ae:    f2 0f 59 05 92 0e 00     mulsd  0xe92(%rip),%xmm0        # 402048 <__dso_handle+0x40>
  4011b5:    00 
  4011b6:    f2 0f 5e 05 92 0e 00     divsd  0xe92(%rip),%xmm0        # 402050 <__dso_handle+0x48>
  4011bd:    00 
  4011be:    f2 0f 2c c0              cvttsd2si %xmm0,%eax
  4011c2:    c3                       ret

f2c 的 FDE 中,函数开头有一个带有 DW_CFA_advance_loc 的单字节指令。在高级操作之后,还有两个附加操作。DW_CFA_def_cfa_offset 将 CFA 更改为 %rsp+16DW_CFA_offset 表示 %rbx 中的初始值现在位于 CFA-16(堆栈顶部)。

查看这个 fc2 反汇编代码,可以看到 push 用于将 %rbx 保存到堆栈中。 在代码生成中省略帧指针的优点之一是可以使用 pushpop 等紧凑指令在堆栈中存储和检索值。 在这种情况下,保存 %rbx 是因为 %rbx 用于向 printf 函数传递参数(实际上转换为 puts 调用),但需要保存传递到函数中的 f 初始值以供后面的计算使用。4011aeDW_CFA_advance_loc 29字节显示了 pop %rbx 之后的下一个状态变化,它恢复了 %rbx 的原始值。 DW_CFA_def_cfa_offset 指出 pop 将 CFA 更改为 %rsp+8

GDB 使用调用帧信息

有了 CFI 信息,GNU 调试器(GDB) 和其他工具就可以生成准确的回溯。如果没有 CFI 信息,GDB 将很难找到返回地址。如果在 f2c.c 的第 7 行设置断点,可以看到 GDB 使用此信息。GDB在 f2c 函数中的 pop %rbx 完成且返回值不在栈顶之前放置了断点。

GDB 能够展开堆栈,并且作为额外收获还能够获取当前保存在堆栈上的参数 f

$ gdb f2c
[...]
(gdb) break f2c.c:7
Breakpoint 1 at 0x40119d: file f2c.c, line 7.
(gdb) run
Starting program: /home/wcohen/present/202207youarehere/f2c
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
98
converting

Breakpoint 1, f2c (f=98) at f2c.c:8
8            return c;
(gdb) where
#0  f2c (f=98) at f2c.c:8
#1  0x000000000040107e in main (argc=<optimized out>, argv=<optimized out>)
        at f2c.c:15

调用帧信息

DWARF 调用帧信息为编译器提供了一种灵活的方式来包含用于准确展开堆栈的信息。这使得可以确定当前活动的函数调用。我在本文中提供了简要介绍,但有关 DWARF 如何实现此机制的更多详细信息,请参阅 DWARF 规范

(题图:MJ/4004d7c7-8407-40bd-8aa8-92404601dba0)


via: https://opensource.com/article/23/3/gdb-debugger-call-frame-active-function-calls

作者:Will Cohen 选题:lkxed 译者:jrglinux 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

Ubuntu 可能默认安装了 Snap,但你仍然可以使用 Flatpak 通用软件包。

Linux 世界有三种“通用”打包格式,允许在“任何” Linux 发行版上运行:Snap、Flatpak 和 AppImage。

Ubuntu 内置了 Snap,但大多数发行版和开发人员都避免使用它,因为它的闭源性质。他们更喜欢 Fedora 的 Flatpak 打包系统

作为 Ubuntu 用户,你并不局限于 Snap。你还可以在 Ubuntu 系统上使用 Flatpak。

在本教程中,我将讨论以下内容:

  • 在 Ubuntu 上启用 Flatpak 支持
  • 使用 Flatpak 命令来管理包
  • 从 Flathub 获取包
  • 将 Flatpak 软件包添加到软件中心

听起来很令人兴奋? 让我们一一看看。

在 Ubuntu 上安装 Flatpak

你可以使用以下命令轻松安装 Flatpak:

sudo apt install flatpak

对于 Ubuntu 18.04 或更早版本,请使用 PPA:

sudo add-apt-repository ppa:flatpak/stable
sudo apt update
sudo apt install flatpak

添加 Flathub 仓库

你已在 Ubuntu 系统中安装了 Flatpak 支持。但是,如果你尝试安装 Flatpak 软件包,你将收到 “No remote refs found” 错误。这是因为没有添加 Flatpak 仓库,因此 Flatpak 甚至不知道应该从哪里获取应用。

Flatpak 有一个名为 “Flathub” 的集中仓库,可以从此处找到并下载许多 Flatpak 应用。

你应该添加 Flathub 仓库来访问这些应用。

flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo

Install Flatpak in latest versions of Ubuntu and then add Flathub repo

安装并配置 Flatpak 后,重启你的系统。否则,已安装的 Flatpak 应用将不会在你的系统菜单上可见。

不过,你始终可以通过运行以下命令来运行 Flatpak 应用:

flatpak run <package-name>

常用 Flatpak 命令

现在你已经安装了 Flatpak 打包支持,是时候学习包管理所需的一些最常见的 Flatpak 命令了。

搜索包

如果你知道应用名称,请使用 Flathub 网站或使用以下命令:

flatpak search <package-name>

Search for a package using Flatpak Search command

? 除了搜索 Flatpak 包之外,在其他情况下, 指的是正确的 Flatpak 包名称,例如 com.raggesilver.BlackBox(上面截图中的应用 ID)。你还可以使用应用 ID 的最后一个词 Blackbox

安装 Flatpak 包

以下是安装 Flatpak 包的语法:

flatpak install <remote-repo> <package-name>

由于几乎所有时候你都会从 Flathub 获取应用,因此远程仓库将是 flathub

flatpak install flathub <package-name>

Install a package after searching for its name

在极少数情况下,你可以直接从开发人员的仓库安装 Flatpak 包,而不是 Flathub。在这种情况下,你可以使用如下语法:

flatpak install --from https://flathub.org/repo/appstream/com.spotify.Client.flatpakref

从 flatpakref 安装包

这是可选的,也很少见。但有时,你会获得应用的 .flatpakref 文件。这不是离线安装。.flatpakref 包含有关从何处获取包的必要详细信息。

要从此类文件安装,请打开终端并运行:

flatpak install <path-to-flatpakref file>

Install a Flatpak package from Flatpakref file

从终端运行 Flatpak 应用

再说一遍,这是你不会经常做的事情。大多数情况下,你将在系统菜单中搜索安装应用并从那里运行该应用。

但是,你也可以使用以下命令从终端运行它们:

flatpak run <package-name>

列出已安装的 Flatpak 软件包

想要查看你的系统上安装了哪些 Flatpak 应用? 像这样列出它们:

flatpak list

List all the installed Flatpak packages on your system

卸载 Flatpak 包

你可以通过以下方式删除已安装的 Flatpak 包:

flatpak uninstall <package-name>

如果你想清除不再需要的剩余包和运行时,请使用:

flatpak uninstall --unused

Remove a Flatpak package and later, if there is any unused runtimes or packages, remove them

它可能会帮助你 在 Ubuntu 上节省一些磁盘空间

Flatpak 命令总结

以下是你在上面学到的命令的快速摘要:

用途命令
搜索包flatpak search
安装包flatpak install
列出已安装的包flatpak list
从 flatpakref 安装flatpak install <package-name.flatpakref>
卸载软件包flatpak uninstall
卸载未使用的运行时和包flatpak uninstall --unused

使用 Flathub 探索 Flatpak 包

我知道通过命令行搜索 Flatpak 包并不是最好的体验,这就是 Flathub 网站 的用武之地。

你可以在 Flathub 上浏览 Flatpak 应用,它提供了更多详细信息,例如经过验证的发布商、下载总数等。

你还将在应用页面底部获得安装应用所需的命令。

额外信息:使用支持 Flatpak 软件包的软件中心

你可以将 Flatpak 包添加到 GNOME 软件中心,并使用它以图形方式安装软件包。

有一个专用插件可以将 Flatpak 添加到 GNOME 软件中心。

? 从 Ubuntu 20.04 开始,Ubuntu 默认的软件中心是 Snap Store,并且不支持 Flatpak 集成。因此,安装以下软件包将产生两个软件中心:一个 Snap 和另一个 DEB。

When you install GNOME Software Flatpak plugin in Ubuntu, a DEB version of GNOME Software is installed. So you will have two software center application

sudo apt install gnome-software-plugin-flatpak

Installing GNOME Software Plugin in Ubuntu

总结

你在这里学到了很多东西。你学习了在 Ubuntu 中启用 Flatpak 支持并通过命令行管理 Flatpak 软件包。你还了解了与软件中心的集成。

我希望你现在对 Flatpaks 感觉更舒服一些。既然你发现了三个通用软件包之一,那么再 了解一下 Appimages 怎么样?

如果你有疑问或遇到任何问题,请告诉我。

(题图:MJ/d03886af-9b7f-401e-a964-da0e5d6531a2)


via: https://itsfoss.com/flatpak-ubuntu/

作者:Abhishek Prakash 选题:lkxed 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

了解 Llama 2 和 GPT-4 之间的主要区别,它们是自然语言处理的领先巨头。揭示它们的优势、劣势以及它们如何塑造语言技术的未来。

在撰写内容时,有两个关键因素至关重要,“ 困惑度 perplexity ”和“ 爆发性 burstiness ”。困惑度衡量文本的复杂程度。而爆发性则比较句子的变化程度。人类倾向于以较大的爆发性写作,例如长句或复杂句与短句并存。人工智能生成的句子往往更加均一。

在自然语言处理领域,Llama 2 和 GPT-4 是两个杰出的参与者,吸引了研究人员和爱好者的关注。这些大型语言模型展示出独特的功能和特点。

虽然 GPT-4 由 OpenAI 已经发布一段时间,但 Meta 与微软合作推出了 Llama 2,这是 LLaMa 扩展语言模型的改进版本。

让我们深入探讨这两个模型之间的关键区别,以了解它们的特点之所在。

Llama 2:简单易用

Llama 2 是其前身 LLaMa 的升级版本,以其简洁高效的特点震撼了科技界。尽管它支持的语言范围较窄,仅包括 20 种语言,但其性能令人印象深刻,可以与 GPT-4、Claude 或 Bard 等重量级模型相媲美。令人惊讶的是,尽管参数比 GPT-3 模型少,但 Llama 2 可以在单个 GPU 上高效运行,使其成为各种应用的更便捷选择。

Llama 2 真正的特点是它专门训练于公开可获得的数据集,使其对研究人员和开发人员更加可用。更为引人注目的是,尽管仅在 1,000 个精确提示的相对较小数据集上进行训练,它依然实现了有竞争力的结果。

GPT-4

在 2023 年 3 月,OpenAI 自豪地推出了其最新的创作——GPT-4,这一力作轰动了语言模型领域。GPT-4 在许多任务中表现卓越,包括专业医学和法律考试,展示了其多功能和高水平的能力。

GPT-4 的一个显著特点是相对于之前的版本,它能够扩展最大输入长度。这个增强功能使其能够处理更加广泛和复杂的语言数据,为自然语言理解和生成开辟了新的可能性。

此外,GPT-4 拥有广泛的语言支持,支持 26 种语言。这种多样的语言能力扩大了其在全球范围内的覆盖和适用性,使其成为多语言项目和应用的首选。

区别:Llama 2 与 GPT-4

在比较 Llama 2 和 GPT-4 时,我们可以看到两个模型都有各自独特的优缺点。Llama 2 以其简洁高效的特点脱颖而出,尽管其数据集较小且语言支持有限,但其表现卓越。其易用性和有竞争力的结果使其成为某些应用的有力选择。

另一方面,GPT-4 在各种任务上的出色表现和广泛的语言支持使其成为更复杂和多样化项目的强大选择。然而,关于其模型架构和训练数据集的详细信息缺乏,还有一些问题尚待回答。

下表显示了两个模型的一些基准分数(以及其他热门模型):

基准测试 样本数 Shot GPT-3.5GPT-4PaLMPaLM-2-LLlama 2
MMLU (5 样本)7078.386.186.4
TriviaQA (1 样本)69.33337.581.4
Natural Questions (1 样本)68.937.552.385
GSM8K (8 样本)8556.556.887
HumanEval (0 样本)48.19256.751.2
BIG-Bench Hard (3 样本)29.356.826.229.9

常见问题解答

1、Llama 2 和 GPT-4 的主要区别是什么?

主要区别在于设计和性能。Llama 2 注重简洁高效,而 GPT-4 具有扩展的输入长度和广泛的语言支持。

2、哪个模型更适合多语言模型?

GPT-4 适用于多语言项目,因为它支持 26 种语言,为全球应用提供了更广泛的范围。

3、Llama 2 可以运行在单个 GPU 上吗?

是的,Llama 2 可以在单个 GPU 上有效运行,使其成为各种应用的实用选择。

4、Llama 2 支持多少种语言?

Llama 2 支持 20 种语言,虽然比 GPT-4 稍少,但仍覆盖了相当广泛的语言范围。

5、GPT-4 是否有可用的基准测试?

不幸的是,没有提及 GPT-4 的具体基准测试,因此对其性能还有一些问题没有答案。

结论

Llama 2 和 GPT-4 代表了自然语言处理领域的前沿进展。尽管数据集较小,Llama 2 以其简洁性、易用性和有竞争力的性能令人印象深刻。另一方面,GPT-4 的多功能性、高水平和广泛的语言支持使其成为处理复杂项目的杰出选择。这两个模型对自然语言处理的发展做出了重要贡献,为语言技术在我们生活中发挥更加重要的作用铺平了道路。

基准测试参考:

(题图:MJ/60e112f7-3399-49fd-9157-c6b03de5efea)


via: https://www.debugpoint.com/llama-2-vs-gpt-4/

作者:Arindam 选题:lkxed 译者:ChatGPT 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

想在 Ubuntu 上运行仅限 Windows 的软件?Wine 就是你的朋友。学习在 Ubuntu Linux 中安装 Wine。

只要稍加努力,你可以使用 Wine 来 在 Linux 上运行 Windows 应用程序 。当你必须在 Linux 上运行一个仅有 Windows 版本的应用程序时,Wine 是一个你可以尝试的工具。

请注意:你不能使用 Wine 来运行每一个 Windows 游戏或软件。请浏览 已支持的应用程序的数据库。评估为白金级或黄金级的软件更有可能与 Wine 一起平稳的运行。

如果你已经找到一个仅有 Windows 版本的软件,并且 Wine 也很好地支持它,现在希望使用它,这篇教程将帮助你在 Ubuntu 上安装 Wine 。

? 如果你在此之前已经安装了 Wine ,你应该完全地移除它,以避免一些冲突。此外,你应该参考它的 下载页面 来获取特定 Linux 发行版的附加说明。

在 Ubuntu 上安装 Wine

这里有很多方法来在你的系统上安装 Wine 。几乎所有的 Linux 发行版都在它们的软件包存储库中提供 Wine 。

大多数的时候,Wine 的最新稳定版本都可以通过软件包存储库获得。

  • 从 Ubuntu 的存储库中安装 Wine(简单,但是可能不是最新的版本)
  • 从 Wine 的存储库中安装 Wine(稍微复杂一些,但是提供最新的版本)

请耐心等待,按照步骤逐步安装和 Wine 。这里有一些相关的步骤。

? 请记住,Wine 会安装很多很多的软件包。你将看到一份庞大的软件包列表,安装大小差不多 1.3 GB 。

Wine download and installed size

方法 1. 从 Ubuntu 安装 Wine(简单)

Wine 可以在 Ubuntu 的官方存储库中获得,你可以在那里简单地安装它。不过,这种方法获取的版本可能不能最新的。

即使你正在使用一个 64 位的 Ubuntu 安装,你也想要在你的发行版上添加 32 位架构的支持,这将有利于你安装特殊的软件。

输入下面的命令:

sudo dpkg --add-architecture i386

接下来,安装 Wine 使用:

sudo apt update
sudo apt install wine

方法 2: 从 Wine 的存储库安装最新的版本

Wine 是一个日新月异的程序。因此,始终建议安装 Wine 的最新稳定版本,以获取更多软件的支持。

首先,移除已存在的 Wine 安装。

步骤 1: 确保添加 32 位架构支持:

sudo dpkg --add-architecture i386

步骤 2: 下载和添加存储库密钥:

sudo mkdir -pm755 /etc/apt/keyrings
sudo wget -O /etc/apt/keyrings/winehq-archive.key https://dl.winehq.org/wine-builds/winehq.key

步骤 3: 现在,下载 WineHQ 源文件文件。

? 这个步骤取决于你正在使用的 Ubuntu 或 Mint 的版本。请 检查你的 Ubuntu 版本Mint 版本 。在你掌握这些信息后,分别使用针对你的相对应的版本的命令。

针对 Ubuntu 23.04 Lunar Lobster ,使用下面的命令:

sudo wget -NP /etc/apt/sources.list.d/ https://dl.winehq.org/wine-builds/ubuntu/dists/lunar/winehq-lunar.sources

如果你持有 Ubuntu 22.04 或 Linux Mint 21.X 系列,使用下面的命令:

sudo wget -NP /etc/apt/sources.list.d/ https://dl.winehq.org/wine-builds/ubuntu/dists/jammy/winehq-jammy.sources

如果你正在运行 Ubuntu 20.04 或 Linux Mint 20.X 系列,使用:

sudo wget -NP /etc/apt/sources.list.d/ https://dl.winehq.org/wine-builds/ubuntu/dists/focal/winehq-focal.sources

Ubuntu 18.04 或 Linux Mint 19.X 系列用户,可以使用下面的命令来添加源文件文件:

sudo wget -NP /etc/apt/sources.list.d/ https://dl.winehq.org/wine-builds/ubuntu/dists/bionic/winehq-bionic.sources

在完成后,更新软件包信息和安装 Wine 的稳定版本软件包。

sudo apt install --install-recommends winehq-stable

如果你现有开发版本或暂存版本,相应地使用 winehq-develwinehq-staging

初始化 Wine 配置

在 Wine 安装后,运行下面的命令:

winecfg

这将创建用于安装 Windows 应用程序的 虚拟的 C: 驱动器

C: Drive created by winecfg in Home directory

在按照这些步骤时,有时,你可能在文件管理器的邮件菜单中找不到 “ 使用 Wine Windows 程序加载器打开 Open With Wine Windows Program Loader ” 的选项。

在这种情况下,通过 创建软链接 到适当的目录来修复它:

sudo ln -s /usr/share/doc/wine/examples/wine.desktop /usr/share/applications/

然后,重新启动你的系统来获取更改。

使用 Wine 来运行 Windows 应用程序

在你安装 Wine 并通过运行 winecfg 将其配置后, 现在是安装 Windows 应用程序的时间了。

在这里,7Zip.exe 文件是用于演示目的的。我知道我应该使用一个更好的示例,因为 7Zip 在 Linux 上是可获得的。不过,对于其它的应用程序来说,接下来的流程是相同的。

首先,从它的 官方下载页面 下载 7Zip 文件。

现在,在该文件上右键单击,并选择“使用 Wine Windows 程序加载器打开”选项:

Open 7zip exe file using Wine WIndows Program Loader in Nemo file manager

这将提示我们安装该文件。单击 “ 安装 Install ” 并让其完成。在完成后,你可以像其它的一些原生应用程序一样打开 7zip 。

Open 7Zip from Ubuntu Activities Overview

你可以使用 wine uninstaller 命令来卸载任意已安装的应用程序。

这里是一篇关于在 Linux 上 使用 Wine 来运行 Windows 软件 的专业教程。

从 Ubuntu 中移除 Wine

如果你没有发现 Wine 有趣,或者,如果 Wine 不能正确地运行你想要的应用程序,你可能需要卸载 Wine 。为此,按照下面的步骤。

通过 Ubuntu 存储库移除已安装的 Wine

为通过存储库移除已安装的 Wine ,首先运行:

sudo apt remove --purge wine

更新你的软件包信息:

sudo apt update

现在,使用 autoclean 命令来清理本地存储库中已检索取回的几乎不再有用的软件包文件。

sudo apt-get autoclean
sudo apt-get clean

移除那些已安装但不再需要的软件包:

sudo apt autoremove

现在,重新启动系统。

如果 Wine 存储库移除 Wine 安装

移除已安装的 wine-stable 软件包。

sudo apt remove --purge wine-stable

更新你的软件包信息:

sudo apt update

现在,使用 autocleanclean 命令来清理本地存储库中已检索取回的几乎不再有用的软件包文件。

sudo apt-get autoclean
sudo apt-get clean

移除先前添加的源文件文件。使用你的相对应的发行版文件夹。在这里,使用的是 Ubuntu 22.04 。

sudo rm /etc/apt/sources.list.d/winehq-jammy.sources

在这移除后,更新你的系统信息:

sudo apt update

可选,如果你希望的话,移除你先前添加的密钥文件。

sudo rm /etc/apt/keyrings/winehq-archive.key

现在,手动移除剩余的一些的文件。

还有一些关于使用 Wine 的问题?

你也可以翻阅我们关于使用 Wine 的教程。它应该能回答你可能想要解决的问题。

没有比 Wine 工程的网站更好的地方了。它们有一个专业的常见问题解答页面:

Wine 的 FAQ

如果你还有问题,你可以浏览 它们的维基 来查看详细的 文档 或者在 它们的论坛 中询问你的疑问。

或者,如果你不介意花一些钱,你可以选择 CrossOver 。它基本上就是 Wine ,但是有高级的支持。你也可以联系他们的团队来解决你的问题。

我的意见是,在你不能找到一款你必需使用的替换软件时,你应该求助于 Wine 。事实上,在这种情况下,不能保证与 Wine 一起工作。

但是,Wine 为从 Windows 迁移到 Linux 提供了一些希望。


via: https://itsfoss.com/install-wine-ubuntu/

作者:Abhishek Prakash 选题:lkxed 译者:robsean 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

cat 命令的用途不仅仅是显示文件内容。

cat 命令用于打印文本文件的文件内容。至少,大多数 Linux 用户都是这么做的,而且没有什么问题。

cat 实际上代表 “ 连接 concatenate ”,创建它是为了 合并文本文件。但只要有一个参数,它就会打印文件内容。因此,它是用户在终端中读取文件而无需任何其他选项的首选。

在 Linux 中使用 cat 命令

要使用 cat 命令,你必须遵循给定的命令语法:

cat [options] Filename(s)

这里:

  • [options] 用于修改 cat 命令的默认行为,例如使用 -n 选项获取每行的数字。
  • Filename 是你输入要使用的文件的文件名的位置。

为了简单起见,我将在本指南中使用名为 Haruki.txt 的文本文件,其中包含以下文本行:

Hear the Wind Sing (1979)
Pinball, 1973 (1980)
A Wild Sheep Chase (1982)
Hard-Boiled Wonderland and the End of the World (1985)
Norwegian Wood (1987)
Dance Dance Dance (1990)
South of the Border, West of the Sun (1992)
The Wind-Up Bird Chronicle (1994)
Sputnik Sweetheart (1999)
Kafka on the Shore (2002)
After Dark (2004)
1Q84 (2009-2010)
Colorless Tsukuru Tazaki and His Years of Pilgrimage (2013)
Men Without Women (2014)
Killing Commendatore (2017)

那么,在没有任何选项的情况下使用时,输出会是什么? 好吧,让我们看一下:

cat Haruki.txt

use cat command in Linux

正如你所看到的,它打印了整个文本文件!

但你可以做的远不止这些。让我向你展示一些实际例子。

1、创建新文件

大多数 Linux 用户使用 touch 命令来 创建新文件,但使用 cat 命令也可以完成相同的操作!

在这种场景下,cat 命令比 touch 命令有一个优势,因为你可以在创建文件时向文件添加文本。听起来很酷。不是吗?

为此,你需要使用 cat 命令,将文件名附加到 > 后面,如下所示:

cat > Filename

例如,在这里,我创建了一个名为 NewFile.txt 的文件:

cat > NewFile.txt

当你这样做了,就会有一个闪烁的光标要求你写一些东西,最后,你可以使用 Ctrl + d 来保存更改。

如果你想创建一个空文件,则只需按 Ctrl + d 而不进行任何更改。

Using cat command

这就好了!现在,你可以使用 ls 命令来显示 当前工作目录的内容

use the ls command to list the contents of the current working directory

2、将文件内容复制到另一个文件

考虑一个场景,你要将 FileA 的文件内容重定向到 FileB

当然,你可以复制和粘贴。但是如果有几百或几千行怎么办?

简单。你可以使用 cat 命令来重定向数据流。为此,你必须遵循给定的命令语法:

cat FileA > FileB
? 如果使用上述语法重定向文件内容,它将删除 FileB 的文件内容,然后重定向 FileA 的文件内容。

例如,我将使用两个文本文件 FileAFileB,其中包含以下内容:

check the file contents using the cat command

现在,如果我使用从 FileAFileB 的重定向,它将删除 FileB 的数据,然后重定向 FileA 的数据:

cat FileA > FileB

redirect the file content using the cat command

同样,你可以对多个文件执行相同的操作:

cat FileA FileB > FileC

redirect file content of multiple files using the cat command

可以看到,上面的命令删除了 FileC 的数据,然后重定向了 FileAFileB 的数据。

3、将一个文件的内容附加到另一个文件

有时你想要将数据附加到现有数据,在这种情况下,你必须使用 >> 而不是单个 >

cat FileA >> FileB

例如,在这里,我将把两个文件 FileAFileB 重定向到 FileC

cat FileA.txt FileB.txt >> FileC.txt

redirect file content without overriding using the cat command

如你所见,它保留了 FileC.txt 的数据,并将数据附加在末尾。

? 你可以使用 >> 向现有文件添加新行。使用 cat >> filename 并开始添加所需的文本,最后使用 Ctrl+D 保存更改。

4、显示行数

你可能会遇到这样的情况,你想查看行数,这可以使用 -n 选项来实现:

cat -n File

例如,在这里,我将 -n 选项与 Haruki.txt 一起使用:

get the number of the lines in the cat command

5、删除空行

在文本文档中留下多个空白行? cat 命令将为你修复它!

为此,你所要做的就是使用 -s 标志。

但使用 -s 标志有一个缺点。你仍然留有一行空白:

remove blank lines with the cat command

正如你所看到的,它有效,但结果接近预期。

那么如何删除所有空行呢? 通过管道将其传递给 grep 命令:

cat File | grep -v '^$'

这里,-v 标志将根据指定的模式过滤掉结果,'^$' 是匹配空行的正则表达式。

以下是我在 Haruki.txt 上使用它时的结果:

cat Haruki.txt | grep -v '^$'

remove all the blank lines in text files using the cat command piped with grep regular expression

当获得完美的输出,你可以将其重定向到文件以保存输出:

cat Haruki.txt | grep -v '^$' > File

save output of cat command by redirection

这就是你到目前为止所学到的

以下是我在本教程中解释的内容的快速摘要:

命令描述
cat <Filename>将文件内容打印到终端。
cat >File创建一个新文件。
cat FileA > FileBFileB 的文件内容将被 FileA 覆盖。
cat FileA >> FileBFileA 的文件内容将附加到 FileB 的末尾。
cat -n File显示行数,同时省略文件的文件内容。
`cat Filemore`cat 命令通过管道连接到 more 命令以处理大文件。请记住,它不能让你向上滚动!
`cat Fileless`cat 命令通过管道传输到 less 命令,这与上面类似,但它允许你双向滚动。
`cat Filegrep -v '^$'`从文件中删除所有空行。

?️ 练习时间

如果你学到了新东西,用不同的可能性来执行它是最好的记忆方式。

为此,你可以使用 cat 命令进行一些简单的练习。它们将是超级基本的,就像 cat 一样是最基本的命令之一

出于练习目的,你可以 使用 GitHub 上的文本文件

  • 如何使用 cat 命令创建空文件?
  • cat 命令生成的输出重定向到新文件 IF.txt
  • 能否将三个或更多文件输入重定向到一个文件? 如果是,该如何做?

(题图:MJ/f06c9b9c-689e-4a67-abe9-0487e26bd34b)


via: https://itsfoss.com/cat-command/

作者:Sagar Sharma 选题:lkxed 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

在本指南中,你将了解如何在 Linux 主机(例如使用 KVM 的 Fedora、Ubuntu 或 Linux Mint)下运行的 Windows 客户机之间共享文件夹。

virt-manager 应用(带有 libvirt)和软件包提供了一组灵活的工具来管理 Linux 中的虚拟机。它是自由开源的,用于 KVM 虚拟机和其他虚拟机管理程序。

在上一篇文章中,我解释了 如何在 Linux 客户机和 Linux 主机之间共享文件夹。然而,当你尝试使用 Windows 客户机和 Linux 主机创建共享文件夹时,这是一个有点困难和复杂的过程。因为两种操作系统的工作方式不同,需要进行大量配置。

按照下面提到的说明在 Windows 客户机和 Linux 主机之间共享文件夹。

关于 virtiofs 的说明

共享文件和文件夹由名为 virtiofs 的 libvirt 共享文件系统提供支持。它提供了访问主机上目录树的所有功能和参数。由于大多数 virt-manager 虚拟机配置都会转换为 XML,因此共享文件/文件夹也可以由 XML 文件指定。

注意:如果你正在寻求在两台 Linux 计算机(客户机和主机)之间使用 KVM 进行文件共享,请 阅读此文

使用 KVM 在 Windows 客户机和 Linux 主机之间共享文件夹

以下说明假设你已在任何 Linux 主机的 virt-manager 中安装了 Windows。如果没有,你可以阅读有关如何在 Linux 中安装 Windows 的完整指南。

在 virt-manager 中设置挂载标签

首先,确保你的客户虚拟机已关闭。从 virt-manager GUI 中,选择虚拟机并单击“ 打开 Open ”以调出控制台设置。

打开控制台设置

单击工具栏中显示虚拟硬件详细信息的图标。然后单击左侧面板上的“ 内存 Memory ”。

选择选项“ 启用共享内存 Enable shared memory ”。单击“ 应用 Apply ”。

确保 XML 在 XML 选项卡中显示 <access mode="shared"/>,如下所示。

<memoryBacking>
    <source type="memfd"/>
    <access mode="shared"/>
  </memoryBacking>

启用共享内存

单击底部的“ 添加硬件 Add hardware ”。

从添加新硬件窗口的左侧面板中选择“ 文件系统 Filesystem ”。

然后在详细信息选项卡中选择 “ 驱动 Driver ” 为 “virtiofs”。单击“ 浏览 browse > 浏览本地 browse local ”并从 Linux 系统中选择主机路径

在“ 目标路径 Target path ”中,输入你想要的任何名称。它只是一个文件标签,将在挂载过程中使用。目标路径中的此名称将作为 Windows 中的驱动器挂载,即资源管理器中的我的电脑。

我已添加 “linux\_pictures” 作为目标挂载标签。

因此,如果我想访问图片文件夹(/home/debugpoint/Pictures),示例设置可能如下:

为 Windows 添加文件系统挂载

单击“ 完成 Finish ”。

上述配置的 XML 设置如下。你可以在 XML 选项卡中找到它。

<filesystem type="mount" accessmode="passthrough">
  <driver type="virtiofs"/>
  <source dir="/home/debugpoint/Pictures"/>
  <target dir="linux_pictures"/>
  <address type="pci" domain="0x0000" bus="0x05" slot="0x00" function="0x0"/>
</filesystem>

在 virt-manager 主窗口中,右键单击 Windows 虚拟机,然后单击“ 运行 Run ”启动虚拟机。如果未显示虚拟机,请单击“显示图形控制台”(工具栏中的监视器图标)。

设置 WinFSP – 适用于 Windows 的 FUSE

确保 Windows 虚拟机(客户机)正在运行。

首先,我们需要安装 WinFSP(Windows File System Proxy)– FUSE for Windows。这使你能够毫无困难地挂载任何类 UNIX 文件系统。

从客户 Windows 计算机打开 WinFSP 的 GitHub 页面。

下载 WinFSP 安装程序

下载 WinFSP .msi 安装程序。

在 Windows 虚拟机上安装软件包。安装软件包时请确保选择 “Core”。完成安装。

WinFSP 设置

创建 VirtIO-FS 服务

进入 stable-virtio 文件夹,从以下地址下载 virtio-win-guest-tools.exe

下载 virtio-win-guest-tools

下载客户机工具

在 Windows 虚拟机上安装软件包。

Virtio-Win-driver 安装

安装完成后,重启 Windows 虚拟机。

重启后,在开始菜单中搜索打开“设备管理器”。

进入系统设备并查找 “VirtIO FS 设备”。它应该被识别并且驱动程序应该由 Red Hat 签名。

注意:(可选)如果你看到感叹号,即未检测到驱动程序,请按照 此处 说明下载 ISO 文件、安装它并手动检测驱动程序。

Make sure the Virt IO driver is signed and installed

打开开始菜单并搜索“服务”。

向下滚动找到 “VirtIO-FS Service”。右键单击并单击“开始”启动该服务。

或者,你可以以管理员身份从 PowerShell/命令提示符运行以下命令来启动服务。

sc create VirtioFsSvc binpath="C:\Program Files\Virtio-Win\VioFS\virtiofs.exe" start=auto depend="WinFsp.Launcher/VirtioFsDrv" DisplayName="Virtio FS Service"
sc start VirtioFsSvc

启动 Virt IO 服务

服务启动后,打开资源管理器,你应该看到你在上面第一步中创建的挂载标签,该标签应映射为 Z 驱动器。见下图。

挂载标签在 Windows 中映射为 Z 驱动器

你现在可以根据需要使用修改后的权限访问整个 Linux 文件夹。

以下是在 Linux Mint 和 Windows 客户虚拟机中访问的同一文件夹的并排比较。

访问和共享 Windows 客户机和 Linux 主机中的文件夹

总结

我希望你现在能够在 Windows 客户机和 Linux 主机系统之间共享文件夹。本文在 Linux Mint 中测试了上述方法。它应该也适用于 Ubuntu、Fedora。

如果上述方法有效,请在下面发表评论以造福他人。

参考

(题图:MJ/91c30453-5939-4368-b885-c4cb84e732bf)


via: https://www.debugpoint.com/kvm-share-folder-windows-guest/

作者:Arindam 选题:lkxed 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出