Crystal-lang:如果由 Crystal 或 clang 生成,为什么 LLVM "hello.bc" 不一样?

Crystal-lang: why is the LLVM "hello.bc" not the same if generated by Crystal or by clang?

这是我的第一个 Whosebug 问题:-)

我的背景:

事实: - crystal-lang 正在编译并且 运行 没有任何问题 - 运行宁 x86_64

请多多关照,我的底层语言知识还不多。

根据我的理解,当我们使用 LLVM 编译和 运行 一个基本的 hello.c 文件时,它如下所示:

hello.c :

#include
int main() {
  printf("hello world\n");
  return 0;
}

shell :

$ clang -O3 -emit-llvm hello.c -c -o hello.bc
$ llc hello.bc -o hello.s
$ gcc hello.s -o hello.native
$ ./hello.native

这来自 LLVM 示例)

我的观点是,我们可以生成一个非常短的 hello.bc 文件(128 行),可以 运行 使用以下方法以较慢的方式使用:

$ lli hello.bc

但是当我尝试从 hello.cr 文件和 运行 生成类似的 hello.bc 时,就像我对 hello.c 文件所做的那样:

hello.cr :

puts "hello world"

shell :

$ crystal build hello.cr --emit llvm-bc --release
$ llc hello.bc -o hello.s

我注意到了什么:

据我所知,LLVM 是可移植的,所有前端语言都会生成一个中间 *.bc,然后可以将其编译为任何架构。

我的问题是:

谢谢!

一切都如其所愿。 Crystal 有一个 运行 时间库,即使您没有包含任何内容,它也始终存在。这是 运行 Crystal 程序所必需的。

C 示例除了对 printf 的系统调用外几乎没有包含任何其他内容。这就是编译后的 ASM 也非常小的原因。

Crystal 简单的 puts 调用背后有更多内容。它基于用于处理异步 IO、并发、信号处理、垃圾收集等的库。其中一些库完全在 Crystal 标准库中实现,一些使用直接嵌入到二进制文件中的其他库 (libgc) 或仍然需要来自系统的动态库 (libpcre , libpthread).

任何 Crystal 程序都默认带有此 运行 时间库。甚至是一个空程序。这通常完全没有引起注意,因为较大的程序无论如何最终都会需要这些东西,并且 运行time 库的编译二进制大小小于 500 KB(在发布模式下)。 像你这样的小程序并不真的需要所有这些来打印一个字符串。但是 Crystal 运行 时间需要这些库。

注意:您可以编译 Crystal 程序 而无需 这些默认库。但这意味着您不能使用 Crystal stdlib 中的 anything 并且您基本上必须使用 Crystal 语法编写 C 代码(或实现您自己的 stdlib):

require "lib_c"
require "c/stdio"

LibC.printf pointerof("hello world".@c)

这可以用 --prelude=empty 选项编译,它将生成一个小得多的 ASM,大致类似于 C 示例。