不同的软件包如何拥有相同的源代码?

我最近学到了使用apt-get source获取任何给定软件包的源代码是多么容易,这样我就可以获取源代码,进行修改并安装自己修改过的软件包。这太棒了!
直到今天,我一直以为每个软件包都有自己的源代码,并且不同的软件包会有不同的源代码。
然而,现在我刚刚发现不同的软件包可以拥有相同的源代码。以下是一个例子:
以下4个软件包似乎具有相同的源代码:
gir1.2-mutter-4
libmutter-4-0
mutter
mutter-common

所有这四个软件都已经安装在我的Ubuntu 19.04电脑上。执行apt-get source gir1.2-mutter-4apt-get source libmutter-4-0命令得到的结果完全相同,对于muttermutter-common软件包也是如此。
以下是我进行验证的步骤:
mkdir a
cd a
apt-get source gir1.2-mutter-4
cd ..
mkdir b
cd b
apt-get source libmutter-4-0
cd ..
diff -r a b

上面最后一行的递归差异没有输出,表明这些目录具有相同的内容。
现在来谈谈我的问题:不同的软件包如何拥有相同的源代码?
假设这是有意为之而不是某种错误,那么这些软件包之间有什么区别,我如何看到这个区别?
可能是这些软件包在源代码的配置和编译方式上有所不同,例如不同的代码部分被包含在不同的软件包中?如果是这样,我在哪里可以找到关于如何配置每个软件包的信息?
编辑:忘记添加了,如果您想要测试这个,请确保首先使用software-properties-gtk启用apt-get source,具体操作请参考这里:https://askubuntu.com/a/857433/874649
编辑2: 感谢大家给出的优秀答案!我还发现这个链接很有帮助 https://askubuntu.com/a/246721/874649 -- 关于 apt-get build-depdpkg-buildpackage 命令,它们非常有用。在修改源代码后,可以使用 dpkg-buildpackage -us -uc 来构建新的.deb文件,这些文件可以用来安装修改过的程序。
3个回答

你把已构建的二进制软件包和这些软件包所构建的底层源代码/软件包搞混了。
你提到的这些软件包都是从同一个源代码/软件包mutter构建而来的。你可以很容易地在packages.ubuntu.com上找到它,搜索你要查看的软件包,然后参考它所指向的"源代码软件包"。在这种情况下就是mutter

enter image description here

从那里开始,我们可以检查Mutter源代码包的Launchpad页面,并看到它构建了许多二进制软件包(编译后的源代码等,用于安装):

enter image description here

这些描述说明了每个软件包包含/安装的内容。重点关注您指定的4个软件包,并使用这些描述:
  • gir1.2-mutter-4 - Mutter的GObject内省数据(用于Mutter和GObject之间的库/数据交互)
  • libmutter-4-0 - Mutter窗口管理器的底层库。 (通常用于插件开发、Mutter集成的开发和编译等)
  • mutter - 实际的Mutter窗口管理器,使用GNOME的窗口管理器库(因此需要GObject)
  • mutter-common - Mutter的共享文件 - 通常是默认配置选项或源软件包构建的所有软件包中共有的项目。
你在软件包列表中看到的是来自相同源代码的“构建软件包”,每个软件包都是在构建/编译时间之后安装的不同项目,并且用于不同的目的。你可以通过下载各个软件包,然后使用p7zip或Ubuntu内置的归档管理器访问它们,以查看软件包本身的内容,并了解每个软件包所包含的差异。但需要注意的是,它们都来自相同的源代码,只是包含了被安装到系统中的不同项目。

1谢谢,这真是非常有启发!理想情况下,我希望能够以命令行方式获取每个软件包的构建说明,现在我已经了解到源代码软件包本身不包含该信息。类似于"apt-get build-instructions mutter"这样的东西——你知道是否有类似的方法吗?以获取实际构建二进制软件包所需的命令列表,例如首先运行configure,然后再运行make,确切地如何执行以生成给定的二进制软件包。 - Elias
3@Elias 这些信息存储在源代码包的 debian/rules 文件中。如果不深入研究代码本身,无法通过命令行获取这些信息。如果你真的对构建系统的工作原理感兴趣,你需要了解更广泛的概念 - Ubuntu 打包(http://packaging.ubuntu.com/html/)和 Debian 打包(https://wiki.debian.org/Packaging)- 因为其中的概念对于理解二进制文件的创建、编译以及实际打包安装在二进制包中的过程至关重要。 - Thomas Ward
2非常好的答案!用非技术术语来说,你可以把数据源想象成一个“建造厨房的计划书”,而软件包就是根据这些计划创建厨房的实际部分。 - Cinderhaze

源代码包和二进制包是分开存在的。每个源代码包可能与多个二进制包相关联。也就是说,可以从同一个源代码包构建多个二进制包。
这种情况经常发生的一种常见方式是,你有一个程序,一个库用于程序的大部分工作,并且用于编译它以及其他(也许是未来)使用该库的程序的头文件。它们都在同一个源代码树中开发和维护,该源代码树用于生成一个源代码包,带有或不带有Debian或Ubuntu的补丁。然后,该源代码包用于构建程序、库和头文件的独立二进制包。
这就是你现在的情况(还有其他一些二进制包)。你在apt source命令中指定了不同的二进制包,但该命令正在下载和解压缩相同的源代码包。
这是因为当你将一个包名传递给apt source,但没有该名称的源代码包时,它会将其视为二进制包的名称,并假设你想要该二进制包对应的源代码包。
Launchpad上的Ubuntu主页上,你可以搜索软件包。Launchpad显示有关源代码软件包的信息(而Ubuntu软件包搜索显示有关二进制软件包的信息)。如果你搜索mutter, 那么正如Thomas Ward所说的那样, 你会找到Ubuntu中mutter源代码软件包的Launchpad页面。这是一种很好的方法来查看哪些二进制软件包对应于一个源代码软件包。在该页面的顶部附近,它说:
Ubuntu中的mutter软件包 gir1.2-mutter-4:Mutter的GObject内省数据 libmutter-4-0:来自Mutter窗口管理器的窗口管理器库 libmutter-4-0-dbgsym:在ubuntu eoan中,libmutter-4-0-dbgsym没有可用的摘要。 libmutter-4-dev:Mutter窗口管理器的开发文件 mutter:使用GNOME的窗口管理器库的示例窗口管理器 mutter-common:Mutter窗口管理器的共享文件 mutter-dbgsym:mutter的调试符号
即使二进制软件包的名称与构建它的源软件包不同,您通常可以通过在Launchpad上搜索二进制软件包来找到该源软件包。
通过检查二进制软件包的名称,您通常可以了解二进制软件包与用于构建它的源软件包之间的关系。
  • lib开头的二进制包通常提供可由多个程序(包括未来的程序)使用的代码库。

  • -dev结尾的二进制包提供头文件,这有助于编译使用这些库的源代码。

  • -dbg-dbgsym结尾的二进制包提供调试符号(因此,即使libmutter-4-0-dbgsym目前不显示摘要,我们也知道它是一个调试符号包)。

  • -common结尾的二进制包往往提供位于/usr/share中的文件,通常是数据文件。这些文件有时实际上是代码,只是以静态和声明性的形式表现出来,但它们也可以提供自然语言(即人类语言)的界面翻译。这种包中可以放入的内容没有太多限制。

    对于 mutter, 近期版本中的 -common 二进制包 包含 模式、按键绑定和文档。 -common 包的一个好处是,由于它们通常不包含任何本机机器代码,因此同一包文件通常适用于所有架构。 (严格来说,这是放置在 /usr/share 中的文件的一个关键要求。)


拿出以下食材:
- 洋葱 - 番茄 - 面包 - 橄榄
这些食材只能做一道菜吗?不是的。你最终吃到的取决于食谱。
每个包装都附带一个食谱,它告诉计算机如何处理这些食材,以制作所需的菜肴。
在某些情况下,多个包装共享相同的食材列表是合理和正常的。当然,在这种情况下,你会期望这些包装来自同一个项目。

6在包的情况下,您有一个单一的食谱(源包及其构建说明),可以生成多个菜肴(二进制包)。 - Stephen Kitt
1@StephenKitt 不要太过字面...类比的重点仍然存在。 - Lightness Races in Orbit