Bug 32619 - -static-libgcj includes entire gnu classpath (>30MB executable from 95byte source)
Summary: -static-libgcj includes entire gnu classpath (>30MB executable from 95byte so...
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: libgcj (show other bugs)
Version: 4.2.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2007-07-04 02:28 UTC by Aaron Wood
Modified: 2007-07-05 07:03 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Aaron Wood 2007-07-04 02:28:45 UTC
Using the 20070501 prerelease of gcc 4.2.0, to compile the following sample app:

public class Foo
{
public static void main(String args[])
{
System.out.println("Hello.");
}
}

with the following command-line:

/usr/local/bin/gcj -v -save-temps -o Foo -static-libgcj --main=Foo Foo.java

yeilds a 35MB executable:

-rwxr-xr-x 1 aaron aaron 35M 2007-07-03 19:12 Foo*

compiler output:

Using built-in specs.
Reading specs from /usr/local/lib/gcc/i686-pc-linux-gnu/4.2.0/../../../libgcj.spec
rename spec startfile to startfileorig
rename spec lib to liborig
Target: i686-pc-linux-gnu
Configured with: ./configure 
Thread model: posix
gcc version 4.2.0 20070501 (prerelease)
 /usr/local/libexec/gcc/i686-pc-linux-gnu/4.2.0/jc1 Foo.java -fhash-synchronization -fno-use-divide-subroutine -fuse-boehm-gc -fnon-call-exceptions -fkeep-inline-functions -quiet -dumpbase Foo.java -mtune=generic -auxbase Foo -g1 -version -o Foo.s
GNU Java version 4.2.0 20070501 (prerelease) (i686-pc-linux-gnu)
        compiled by GNU C version 4.2.0 20070501 (prerelease).
GGC heuristics: --param ggc-min-expand=64 --param ggc-min-heapsize=64499
Class path starts here:
    ./
    /usr/local/share/java/libgcj-4.2.0.jar/ (system) (zip)
 as --traditional-format -V -Qy -o Foo.o Foo.s
GNU assembler version 2.17.50 (i486-linux-gnu) using BFD version 2.17.50 20070103 Ubuntu
 /usr/local/libexec/gcc/i686-pc-linux-gnu/4.2.0/jvgenmain Foomain Foomain.i
 /usr/local/libexec/gcc/i686-pc-linux-gnu/4.2.0/cc1 Foomain.i -quiet -dumpbase Foomain.c -mtune=generic -g1 -version -fdollars-in-identifiers -o Foomain.s
GNU C version 4.2.0 20070501 (prerelease) (i686-pc-linux-gnu)
        compiled by GNU C version 4.2.0 20070501 (prerelease).
GGC heuristics: --param ggc-min-expand=64 --param ggc-min-heapsize=64499
Compiler executable checksum: 14e4aa58d7d80bfc23a75bbd5755fd63
 as --traditional-format -V -Qy -o Foomain.o Foomain.s
GNU assembler version 2.17.50 (i486-linux-gnu) using BFD version 2.17.50 20070103 Ubuntu
 /usr/local/libexec/gcc/i686-pc-linux-gnu/4.2.0/collect2 --eh-frame-hdr -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o Foo /usr/lib/crt1.o /usr/lib/crti.o /usr/local/lib/gcc/i686-pc-linux-gnu/4.2.0/crtbegin.o -L/usr/local/lib/gcc/i686-pc-linux-gnu/4.2.0 -L/usr/local/lib/gcc/i686-pc-linux-gnu/4.2.0/../../.. Foomain.o Foo.o -lgcc_s -lgcc -non_shared -lgcj -call_shared -lm -lpthread -lrt -ldl -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/local/lib/gcc/i686-pc-linux-gnu/4.2.0/crtend.o /usr/lib/crtn.o

==============

It appears as if the linker isn't removing uncalled functions from the resulting binary.  I will try to build this the old way as well, to see if I get the same issue there.
Comment 1 Aaron Wood 2007-07-04 02:40:20 UTC
Same behavior with the "old style" method:

> gcj -c Foo.java
> gcj --main=Foo -save-temps Foo.java
> gcc -o Foo2 Foo.o Foomain.i -shared-libgcc -Wl,-non_shared -lgcj -Wl,-call_shared -lsupc++ -Wl,--as-needed -lz -lgcc_s -lpthread -lc -lm -ldl -lrt -Wl,--no-as-needed

Also yields a 35MB binary.

Stripping debug symbols drops it to 18MB, full stripping drops it to 11MB.
Comment 2 Andrew Pinski 2007-07-04 03:23:54 UTC
And this is not a bug, the library just got bigger.  You know that your 95 byte source pulls in all of locale, all of thread, most of the java.lang classes in fact.
Comment 3 Marco Trudel 2007-07-04 06:59:51 UTC
This is an old discussion and comes up in the mailinglist regularly. The most promising approach is to explicitly exclude parts of the class library. JNC (http://jnc.mtsystems.ch/) supports excluding the GUI stuff (AWT/Swing) and JCE what already leads to a great size reduction (since these will be pulled into every binary).

BTW, here the FAQ entry for your question from the JNC website:

Why are the binaries so big?
As JNC evolves, it supports more and more classes of the Java API. The problem now is, that the Java API classes are heavily interconnected; a simple "Hello World" application uses the security manager which uses AWT which uses... Because of this, you will always have a big part of the classlibrary in your binaries.
For Java, this is not a problem. Endusers require to have the JVM, thus having all classes anyway. For native compilation, this is a bigger problem because it's not just a bug that can be fixed. The design of Java doesn't fit into the concept of native compilation (concerning the size of binaries).
Since JNC 0.9, you can exclude parts of the class library if you don't need them and thus drastically reduce the size of your binaries.
Comment 4 Aaron Wood 2007-07-04 19:22:44 UTC
Marco,

thanks for the pointer to JNC.  I'm targeting an embedded platform, with only 32MB of storage, so reducing the classes needed is mandatory.

From the size of the executable, it looked like the linker had just failed to prune uncalled code.  (since libgcj is ~30MB on it's own).

Is there a way to pull a report from the linker to determine what methods/classes are left behind and which are included?  I did a check with strings and saw all sorts of classes that I'm sure I'm not using (java.util.zip.ZipInputStream for instance).
Comment 5 Marco Trudel 2007-07-05 07:03:22 UTC
With "-Wl,-Map,/tmp/TheLinkMap.txt" you get a list of the objects that have been included from libgcj.a.