我很惊讶地发现,即使是这样简单的程序:
print_string "Hello world !\n";
当使用一些相当激进的选项(使用 musl
)通过 ocamlopt
静态编译为本机代码时,在我的系统上仍然约为 ~190KB。
$ ocamlopt.opt -compact -verbose -o helloworld \
-ccopt -static \
-ccopt -s \
-ccopt -ffunction-sections \
-ccopt -fdata-sections \
-ccopt -Wl \
-ccopt -gc-sections \
-ccopt -fno-stack-protector \
helloworld.ml && { ./helloworld ; du -h helloworld; }
+ as -o 'helloworld.o' '/tmp/camlasm759655.s'
+ as -o '/tmp/camlstartupfc4271.o' '/tmp/camlstartup5a7610.s'
+ musl-gcc -Os -o 'helloworld' '-L/home/vaab/.opam/4.02.3+musl+static/lib/ocaml' -static -s -ffunction-sections -fdata-sections -Wl -gc-sections -fno-stack-protector '/tmp/camlstartupfc4271.o' '/home/vaab/.opam/4.02.3+musl+static/lib/ocaml/std_exit.o' 'helloworld.o' '/home/vaab/.opam/4.02.3+musl+static/lib/ocaml/stdlib.a' '/home/vaab/.opam/4.02.3+musl+static/lib/ocaml/libasmrun.a' -static -lm
Hello world !
196K helloworld
如何从ocamlopt获得最小的二进制文件?
像今天的限制(iot,android,alpine VM等)这样简单的程序的大小为190KB
太大了,并且与简单的C程序相比(约为~6KB),或者直接编写ASM并调整一些东西以获得可工作的二进制文件,可以约为150B。我天真地认为,我可以简单地放弃C
来编写简单的静态程序,执行微不足道的操作,并在编译后获得一些简单的汇编代码,其大小不会比等效的C程序差太远。这是可能的吗?
我认为我理解的内容:
当删除gcc的-s
以获得有关二进制文件中剩余内容的一些提示时,我可以注意到许多ocaml
符号,并且我也有点读到ocamlrun
的某些环境变量即使在这种形式下也应该被解释。就像ocamlopt
所说的“本地编译”是将ocamlrun
和程序的非本地bytecode
打包在一个文件中并使其可执行。这不完全是我预期的。显然,我错过了一些重要的要点。但如果是这种情况,我会很感兴趣为什么它不是我预期的。
其他编译成本地代码的语言也有相同的问题:留下一些天真的用户(如我自己),他们大致上有着相同的问题:
- Go:Go编译后可执行文件巨大的原因
- Rust:为什么Rust可执行文件如此巨大?
我也尝试了Haskell,但是没有任何修改,所有语言的编译器都会为“hello world”程序生成超过700KB的二进制文件(在进行调整之前,Ocaml也是如此)。