Java 开发人员需要帮助来理解 F# 中的 .NET 生成过程



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

  • JRE -> .NET Runtime?
  • JDK 工具 -> Microsoft 构建工具 2015 包括 F# 编译器和其他工具?
  • 帕克特->专家?
  • 假的 -> maven 在 pom.xml 中的<build>部分?
  • paket.dependencies 和 paket.references -> Maven 在 pom.xml 中的<dependencies>部分?
  • *
  • .*项目文件 -> ???

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

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

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

编辑:

我知道这个问题很复杂,不是很具体。 谢谢大家抽出宝贵时间去研究它,并回答你们的能力。 我很感激。

由于还没有人回答您问题的 Paket 部分,我将解决这个问题。

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

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

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

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

问:*项目文件有什么用?

*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 帮助程序打包和发布,部署到 Azure,甚至在 Slack 上通知你的队友 - 所有这些都不会离开功能优势的舒适感。

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

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

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

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

长篇大论:@rmunn的出色回答更详细地讨论了这个问题。

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

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

我最近开始使用Fake。在我的 Fake 构建脚本中,有一个命令MSBuild调用 MSBuild,而 MSBuild 又调用 Fsc.exe。所以从某种意义上说,所有这些额外的打包都在那里,所以我需要少打字(Fsc 的参数字符串很容易最终有点长,而且很高兴有工具来确保参数是"正确的")。

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

相关内容

  • 没有找到相关文章

最新更新