This is the mail archive of the java@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: I can make your gcj-compiled binaries much smaller.


> Oh yeah, and it's a great thing.  Trouble is, you're threatening to
> make static linkage useful!  That means people will use it, and then
> ... we have support headaches.
Why does it make support worse? 

I haven't dug into all the code yet, as I am waiting for my paperwork to
come through. (I was hoping to work out the rmi part, seems fun as it
coincides with my scjd assignment)

I did find static linkage a lot easier to port apps. The bzipped size of
a static ant is just 3 MB, and it reduces startup time immensely (like
400%). I know classes get left out if you use a static library to link
the binary, but I just passed all the object files to the linker. The
only classes that can gcj can 'forget' are from the gcj distribution
itself, which are supposed to be contained withing the libgcj-3.x.jar
isn't it? I haven't got any problems with a 9 MB big ant actually. At
the moment it's the only way to circumvent small glitches in the libgcj
dso and distribute a binary that will 'just work'. 

I just can't expect people (friends etc.) to get the gcc sources or
checkout cvs, patch it themselves, and recompile libjava. I reworked the
object compilation script to be more simple and generic and it works for
me. 

Is there anyway to checkout if external sources are already included in
the libjava distribution, so you can leave them out during compilation
and linking (assuming the interfaces are compatible)? 

The only way I can think of at the moment is just feed a small java
executable like:

public static void main(String[] args) {
try { Class.forName(args[0]) } catch (Exception e) { System.exit(1); }
System.exit(0);
}

And use that in a compilation script to check out whether or not the
script (or makefile script) should include a class during compilation.
Is there another way?

I tend to avoid Java classes all together, they just give me headaches
about not being able to merge the code (haven't checked it out yet).

At the moment I use a script that only generates the native objects, and
I link manually. I don't know whether it's of any use, but I included it
in the posting. I found the -O flags a bit useless for the java
applications as most of them aren't very computational intensive (they
just do a lot :D), no significant difference was found to drive an Ant
build statically built with either -Os or -O0, but it does cut down the
binary with 3 MB.

> I'm not opposed to your plans.  However, they raise some, er,
> interesting questions...
Please explain. I'd like to know.

> Andrew.


--- The college graduate is presented with a sheepskin to cover his
intellectual nakedness. -- Robert M. Hutchins
#!/bin/bash
declare CLASSPATH="" SOURCEPATH="" PACKAGES=""

# main execution
main() {
	checkArgs $@
	environment $@
	compile $@
}

# environment settings
environment() {
	unset CLASSPATH
	classpath $@
	echo Using GCJFLAGS:
	echo ---------------
	if [ -z GCJFLAGS ]; 
	then 
		GCJFLAGS="-g0 -pipe -Os -Wno-deprecated -fno-pedantic" 
	fi
	echo $GCJFLAGS
}

# simple usage explanation if arguments fail sanity
printUsage() {
echo SimpleGCJ compile v.0.0.0.1
echo ""
echo This is a simple script, that expects two things:
echo "There exists a directory that contains the sourcetree <src>"
echo "There exists a directory that will contain the objectcode <obj>"
echo ""
echo EXAMPLE:
echo
echo	./compile sources/ objects/ 
echo
echo ENVIRONMENT:
echo ""
echo GCJFLAGS, e.g.:
echo ""
echo "(bash) 	export GCJFLAGS=-g0 -pipe -Os -mcpu=athlon -march=athlon"
echo "(csh) 	set env GCJFLAGS=-ggdb -pipe -falign-jumps=32"
echo ""
echo NOTE:
echo ""
echo In the example above, the sources directories, contain other directories
echo that are not part of any java package namespace. So sources/
echo could contain A/ B/ C/, which are not top level package names, the 
echo actual tree for each source starts at sources/A/toppackage/ etc.
echo ""
}

# sanity check for arguments
checkArgs() {
if [ $# != 2 ] ||  [ ! -d $1 ] || [ ! -d $2 ]
then
  printUsage ; exit 1
fi
}

# compile a single package contained in $1/<dir>/
packageCompile() {
	local -i count=0; local -i skipped=0; local i j k o;
	# sources
	F=`find $1 -type f -name "*.java"`
	C=`echo $F | wc -w`
	echo Package: $1, $C source files
	for i in $F 
	do 
		j=`echo ${i#$1} | sed "s/^\/*//g" | sed "s/\.java/\.o/g" | sed "s/\//\./g"`
		o=${2%%/}/$j
		if [ ! -f $o ] || [ $i -nt $o ]
		then
			gcj $GCJFLAGS -o $o $i $SOURCEPATH --classpath $CLASSPATH -c 2>>ERROR
			count=count+1
			echo $i
		else 
			skipped=skipped+1
		fi
	done 
	echo Compiled $count files, skipped $skipped files
	echo ""
	# resources
	F=`find $1 -type f -name "*[^java$|^diff$]" | sed "s/.*CVS.*//g" | sed "s/.*html$//g"`
	C=`echo $F | wc -w` ; count=0; skipped=0;
	echo Package: $1, $C resource files
  for i in $F
	do
		j=`echo ${i#$1}`; j=${j##/} ; k=`echo ${j} | sed "s/\//\./g"`
		o=${2%/}/${k}_resource.o
		if [ ! -f $o ] || [ $i -nt $o ] 
		then
			gcj $GCJFLAGS --resource $j $i -o $o -c -v 2>>ERROR
			count=count+1
		else
			skipped=skipped+1
		fi
	done
	echo Compiled $count files, skipped $skipped files
  echo ""
}

# build classpath from all packages in $1/*
classpath() {
	for i in `find ${1%%/}/* -type d -maxdepth 0`
	do
		CLASSPATH=$i:$CLASSPATH
		SOURCEPATH="-B$i $SOURCEPATH"
		PACKAGES="$i $PACKAGES"
	done
	echo Using CLASSPATH:
	echo ----------------
	echo $CLASSPATH
	echo ""
	echo "Using SOURCEPATH (-Bpath):"
	echo --------------------------
	echo $SOURCEPATH
	echo ""
}

compile() {
	echo ""
	echo Compiling sourcetree $1 to $2
	echo ---------------------`echo $1 | sed "s/./-/g"`----`echo $2 | sed "s/./-/g"`
	for i in $PACKAGES
	do
		echo ""; packageCompile $i $2
	done
}

main $@

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]