> Why is a.out of "hello world" 1.2 MB big? Is there anything one can do
> to minimize the size of the executables?
>
tubenose=% 6g helloworld.go
tubenose=% ls -l helloworld.6
-rw-r--r-- 1 r eng 2140 Oct 28 16:13 helloworld.6
tubenose=% 6l helloworld.6
tubenose=% ls -l 6.out
-rwxr-xr-x 1 r eng 190458 Oct 28 16:14 6.out
tubenose=%
Don't know what system you're on but your number is excessive.
-rob
Go programs are bigger than, say, C programs because they contain a run-time system and full type info. If you use fmt, for example, that pulls in a lot of data. Modern computing is like that. There's also been some recent changes to support GDB that add yet more data to the binary. Modern computing is like that.
-rob
The reason the binary is so big is that fmt does a lot of clever
stuff, and depends on the io, os, reflect, strconv, strings, unicode,
and utf8 packages. Each of them may have their own dependencies.
fmt.Println does some runtime inspection of its arguments to determine
how they should be formatted. The removal of the unused code paths is
hard because, as far as the compiler can tell through static analysis,
all the dependences are necessary.
That's not to say that it can't get better. Given enough time and
effort, it's certainly possible to bring the binary size down. (And,
indeed, some recent changes to the linker brought the binary size down
by about 30%.) It's a matter of priorities, and this matter is fairly
low on the list.
Andrew
That's correct. With the exception of C libraries that can be linked
dynamically using a tool called cgo, all Go code is statically linked.
> But still, it seems overly excessive to have a 1.2 MB "hello world"
> executable. Your 190458 bytes seem modest in comparison!
It does seem excessive compared to a minimal C program that does the
same thing, but once you see what the Go runtime and fmt can do for
you it's not quite so shocking.
> I downloaded and installed the go tools today, this is my first ever
> experience with go, i'm interested :)
Welcome! :-)
If you have more questions you can either ask this mailing list (as
you have done), or try the IRC channel #go-nuts on irc.freenode.net.
Andrew
When I build a fmt.Println hello world on Linux,
readelf -S shows the following sizes.
228867 .text
717164 .rodata
9560 .data
388132 .gosymtab
19712 .gopclntab
Most of the bulk is the read-only data, which includes
large tables and reflection data.
For example, package fmt uses package strings,
which uses the Unicode tables for strings.ToLower,
but fmt doesn't call strings.ToLower, so those tables
should be omitted. But because the master map for
the tables gets generated by code rather than laid
out as compile-time data, the implicit init function for
the strings package causes that data to be kept.
If we provided the linker with a list of the initializations
and the order to run them in, then it could discard the
unused data a little better. About 180 kB is due to
the Unicode tables. Another 740 kB is due to the
reflection tables that define the types in the runtime
itself (you can reflect on reflection!). These need to
be made smaller; the next time we iterate on the
reflection interface we will do that.
Another example is that if you refer to a type using
an interface or reflection, then you're referring to its
type descriptor, which has a list of its methods, for
use in dynamic interface checks and reflection.
That can drag in code that might otherwise go unused.
For example, fmt.Println calls fmt.Fprintln passing
os.Stdout as an io.Writer (interface) value. That means
the type information for *os.File is being passed, which
means that all the methods on *os.File are referred to
and thus linked into the binary. So (*os.File).Close is
in the binary even though it is never called, because
the compiler and linker cannot see that fmt doesn't,
say, do a dynamic check to see whether the argument
to fmt.Fprintln is an io.Closer.
Russ
I doubt it. Unless you also changed fmt.Println to println.
Russ
> That's correct. With the exception of C libraries that can be linked
> dynamically using a tool called cgo, all Go code is statically linked.
By the way, is there some documentation about how cgo works? It seems
to me that the binaries created by the Go compilers do not actually
follow the libc ABI, so it is a bit curious that you can link in DSOs
which depend more or less intimately on GNU libc.
Yes, and actually libc is linked in as well, otherwise it'd be pretty
hard to make C programs work. The cross-calling between the two
conventions is done in assembly.
--
Gustavo Niemeyer
http://niemeyer.net
http://niemeyer.net/blog
http://niemeyer.net/twitter