4

我的大部分开发都是在 Java 中进行的,在那里我习惯于拥有一个运行时、一个编译器和一个构建工具。所以现在我正在尝试进入 .NET 世界,特别是使用 VSCode、Ionide 插件和 F#,来构建一个 F# 程序。我很难理解与 Java 构建过程的直接比较。到目前为止,这是我的粗略理解:

  • JRE -> .NET 运行时?
  • JDK 工具 -> Microsoft Build Tools 2015 其中包括 F# 编译器和其他工具?
  • Paket -> 行家?
  • FAKE -> <build>pom.xml 中的 Maven 部分?
  • paket.dependencies 和 paket.references -> <dependencies>pom.xml 中的 maven 部分?
  • *.*proj 文件 -> ???

我真的对 *proj 文件感到困惑。我认为这与 MSBuild 有关。但我很困惑,因为我认为 FAKE 是 MSBuild 的替代品,但我见过的一些 FAKE 示例引用了这个文件并将其传递给 MSBuildRelease 任务。

另外,为什么 paket 需要依赖项引用文件?

我希望有人可以确认、澄清、添加或任何上述内容,以达到我迄今为止的理解水平。非常感激!

编辑:

我知道这个问题很复杂,而且不是很具体。感谢大家抽出宝贵的时间来梳理它并回答你能回答的问题。我很感激。

4

3 回答 3

6

由于尚未有人回答您问题的 Paket 部分,因此我将解决该问题。

在一个 Git 存储库中,您可能有多个项目。例如,为您的主要代码和您的测试创建一个单独的项目是一种非常常见的模式(如此普遍,以至于ProjectScaffold 存储库是这样设置的,因为这是大多数人想要的)。在您的MyApp.fsproj文件中,您可能不希望引用 NUnit 或 XUnit,但您确实希望MyApp.Tests.fsproj文件中有这些引用。

paket.dependencies文件是每个存储库一个,它列出了存储库中的任何项目想要使用的所有包。这些文件,复数,每个项目一个,并且与它们对应的文件位于同一目录中。他们列出了项目想要引用的包。因此,在与位于同一目录中的文件中,您将列出 NUnit 或 XUnit — 但您不会与 .位于同一目录中的文件中列出单元测试库。paket.references.fsprojpaket.referencesMyApp.Tests.fsprojpaket.referencesMyApp.fsproj

如果您的 Git 存储库中只有一个项目,那么就不需要单独的文件paket.dependenciespaket.references文件,因为它们可以组合成一个同时满足两种目的的文件。但是,一旦您.fsproj在单个存储库中有多个文件,那么依赖项和引用之间的分离就变得很有用,因为您可以将所有依赖项列在paket.dependencies存储库根目录中的单个文件中,但为每个项目提供自己的paket.references文件,以便它只能引用它特别需要的依赖项子集。

于 2017-03-26T01:14:32.907 回答
5

让我尝试一一解决这些问题...

问:*proj 文件有什么用?

这些*proj文件是 MSBuild 的本地语言(如果您使用的是 Mono ,则为 xbuild )。在最简单的情况下,他们只是列出所有要编译的文件以及对他们使用的其他项目的所有引用。还有一些其他属性,比如目标平台、CPU 架构等。最初的想法是一个*proj文件产生一个编译汇编单元(又名“DLL”,大致对应于 JAR)。这在很大程度上仍然是正确的,但并非总是如此。例如,TypeScript 项目可以生成多个 JS 文件。

但是 MSBuild 的核心架构使这些文件非常灵活。它们基本上建立在插件系统(称为“任务”)上,其中每个任务都做一些特定的事情。框中包含许多任务,例如“编译 C# 文件”或“输出到日志”,但您也可以添加自己的,或以包的形式安装一些,或全局安装。另外,MSBuild 的核心允许一些技巧,比如变量(某种)、循环(某种)和分支(近似),以至于您实际上可以完全在一个*proj文件。这一切背后的最初想法是 MSBuild 将成为整个构建过程的主要工具,不需要其他工具。对于简单的玩具项目,它有点像:当您只需要将一堆文件编译为 DLL 时,MSBuild 可以出色地完成这项工作。即使是不那么简单的项目,人们也试图完全在*proj文件中完成整个构建。即使是现在,也有一些项目可以做到这一点。

然而,随着时间的推移,很明显用 XML 编写高级构建逻辑是如此棘手和落后,以至于它很快变得无法维护。因此出现了一堆专门用于实现高级构建逻辑的工具。这让我...

问:FAKE 不是 MSBuild 的替代品吗?

是的。嗯,不,实际上不是。也许。有点儿。

正如我上面所说,可以在 MSBuild 中编写整个构建逻辑:编译、复制、压缩(在需要时)、捆绑(如果需要)、打包(在适当时)和发布(在合法时:-)。但是编写起来非常尴尬,并且很快变得无法维护。

输入 FAKE:在 FAKE 中,您完全在 F# 中编写构建过程的整个逻辑。这意味着您可以使用库、抽象、高阶函数、特殊类型——真正的高级语言的所有优点。您可以使用 glob 模式指定源文件列表,使用 FscHelper 调用 F# 编译器,使用XUnitHelper运行测试,使用Paket helper打包和发布,部署到 Azure,甚至在 Slack 上通知您的队友——所有这些都无需离开舒适的功能上的好处。

但是有一个问题:构建脚本无法通过工具进行分析。
因为它是一个真正的程序,而不是一种数据格式,IDE 不知道如何从中提取源文件列表,或者如何添加新文件;包管理器不知道在哪里插入对包的引用,等等。
另一方面,MSBuild 文件是可分析性的定义:它们是 XML,并且对于去往何处有严格的标准。

于是它变成了:我们使用 MSBuild 指定一些严格但简单的属性,然后使用 FAKE 脚本来“驱动”更高级别的构建逻辑——例如运行测试、生成文档、发布、部署等。指定文件列表并直接调用 F# 编译器,我们的构建脚本只调用 MSBuild。

问:为什么 Paket 需要引用依赖?

简而言之:因为我们通常一次处理多个编译单元(又名“项目”)(我们将这样的项目系统称为“解决方案”),并且当一个解决方案下的不同项目使用不同版本时,我们不喜欢它相同的包裹:冲突比比皆是,我们的头脑爆炸了。因此,我们为整个解决方案指定一个包列表(在“依赖项”中),然后每个项目都可以选择它实际使用的那些(在“引用”中)。

长篇大论@rmunn 的出色回答更详细地讨论了这一点。

同样有趣的是:“本机”.NET 包管理器 NuGet 实际上没有这个属性。NuGet 下的每个项目都有自己的、完全独立的包列表。而这种令人头疼的版本冲突确实会发生。在大型解决方案上,常常令人沮丧。这是Paket优越的众多原因之一。

于 2017-03-26T03:30:08.910 回答
0

我在 Windows 平台上。我的(旧)版本附带的 F-Sharp 编译器是 Microsoft 的编译器,名为 Fsc.exe。我这样使用它:Fsc.exe HelloWorld.fs.

我最近开始使用 Fake。在我的 Fake build 脚本中有一个命令,MSBuild它调用 MSBuild,而 MSBuild 又调用 Fsc.exe。所以从某种意义上说,所有额外的包装都在那里,所以我需要输入更少的内容(Fsc 的参数字符串很容易最终有点长,有工具来确保参数是“正确的”很好) .

.fsproj 文件是一个文件,其中包含 MSBuild 用来发送到 Fsc 的信息。该文件也可以通过例如 Visual Studio 读取,以便您的文件在 (Visual Studio) 编辑器中显示为一个项目。

于 2017-03-26T00:35:49.593 回答