[MAD SCIENCE EXPERIMENT]: Replace some libtool functionality with handcoded C

Mohan Embar gnustuff@thisiscool.com
Wed Dec 3 10:00:00 GMT 2003


Hi People,

Tonight I scratched an itch that I've been wanting to scratch for almost
a year. And it felt nice.

I wanted to see how much faster the libgcj build would go if I took
libtool out of the picture for some of the pieces.

I am too tired to do timings and don't guarantee that I'll express myself
coherently, but I'll give it a go. I have absolutely no clue if I'm going
down the right path - that's why this is a mad science experiment. This
is "tested" on the i686-pc-linux-gnu native compiler only. It's very far
from polished, but I'm submitting this in patch-style format anyway.

I added a new configure flag called --enable-libgcj-ltwrapper. If set,
the libjava configure process looks for a file called ltwrapper-${host}.c
and attempts to compile it using ${CC_FOR_BUILD} or gcc if the former
isn't defined. (Unfortunately, we don't have access to make variables
as far as I can tell, so CC_FOR_BUILD has to be set by hand if desired.)

(The disadvantage of building this executable at configure time means that
subsequent changes to the source won't be picked up after configury is complete,
but I think that this is okay given the purpose of this executable.)

If everything goes well, then this wrapper executable intercepts all
calls to libtool and can either pass through to libtool or handle
the call itself. Currently, I only treat the case of --tag=GCJ &&
--mode=compile. I could have easily done the --tag=CXX case too,
but this is a proof of concept.

After the configure process and compiling of the initial classfiles
(using --enable-libgcj-multifile to do these all at once, of course)
and .cc files, the build kicks into high gear. I watched the entire
build in fascination the first time around, but didn't do any timings.
I think it screams, but would be interested in observations from
others.

How does this sound? For me, it's so far out that there must be
something wrong with my approach, but it's pretty cool and I'm
having fun.

(Reglancing at the patch, I see that I left things as AC_MSG_ERROR
instead of changing back to AC_MSG_WARNING.)

-- Mohan
http://www.thisiscool.com/
http://www.animalsong.org/

ChangeLog
2003-12-03  Mohan Embar  <gnustuff@thisiscool.com>

	* Makefile.am: Use LTWRAPPER_EXE instead of default
	LIBTOOL if LTWRAPPER is true.
	* configure.in: Added support for new configure flag
	--enable-libgcj-ltwrapper.
	* ltwrapper-i686-pc-linux-gnu.c: New platform-specific
	libtool wrapper.
	* configure: Rebuilt.
	* Makefile.in: Rebuilt.
	* gcj/Makefile.in: Rebuilt.
	* include/config.h.in: Rebuilt.
	* include/Makefile.in: Rebuilt.
	* testsuite/Makefile.in: Rebuilt.
	
Index: Makefile.am
===================================================================
RCS file: /cvs/gcc/gcc/libjava/Makefile.am,v
retrieving revision 1.336
diff -u -2 -r1.336 Makefile.am
--- Makefile.am	25 Nov 2003 01:57:27 -0000	1.336
+++ Makefile.am	3 Dec 2003 07:54:42 -0000
@@ -90,4 +90,9 @@
 GCJ_WITH_FLAGS = $(GCJ) --encoding=UTF-8 -Wno-deprecated
 
+# Do we have a wrapper program around libtool?
+if LTWRAPPER
+LIBTOOL = ./@LTWRAPPER_EXE@
+endif
+
 GCJCOMPILE = $(LIBTOOL) --tag=GCJ --mode=compile $(GCJ_WITH_FLAGS) -fclasspath= -fbootclasspath=$(here) $(JC1FLAGS) -MD -MT $@ -MF $(@:.lo=.d) -c
 GCJLINK = $(LIBTOOL) --tag=GCJ --mode=link $(GCJ) -L$(here) $(JC1FLAGS) $(LDFLAGS) -o $@
Index: configure.in
===================================================================
RCS file: /cvs/gcc/gcc/libjava/configure.in,v
retrieving revision 1.176
diff -u -2 -r1.176 configure.in
--- configure.in	2 Dec 2003 22:26:45 -0000	1.176
+++ configure.in	3 Dec 2003 07:55:14 -0000
@@ -98,4 +98,37 @@
 AM_CONDITIONAL(ONESTEP, test "$enable_libgcj_multifile" = yes)
 
+# Do we support a portable C wrapper around libtool?
+AC_ARG_ENABLE(libgcj-ltwrapper,
+[  --enable-libgcj-ltwrapper
+                          allow compilation of several files at once],
+[case "${enableval}" in
+  yes) enable_libgcj_ltwrapper=yes ;;
+  no)  enable_libgcj_ltwrapper=no ;;
+  *) AC_MSG_ERROR(bad value ${enableval} for --enable-libgcj-ltwrapper) ;;
+esac],[enable_libgcj_ltwrapper=no])
+
+# If they want to use any wrapper, we can only use it
+# if it both exists and builds successfully. We build it
+# with the build compiler.
+if test $enable_libgcj_ltwrapper = yes; then
+  # We're guilty until proven innocent.
+  enable_libgcj_ltwrapper=no
+  LTWRAPPER_EXE=ltwrapper-${host}
+  ltwrapper_cfile=${LTWRAPPER_EXE}.c
+  if test -f ${srcdir}/${ltwrapper_cfile}; then
+    ${CC_FOR_BUILD-gcc} -o ${LTWRAPPER_EXE} ${srcdir}/${ltwrapper_cfile}
+    if test "$?" != "0"; then
+      AC_MSG_ERROR(Ignoring --enable-ltwrapper because build of ${ltwrapper_cfile} failed.)
+    else
+      enable_libgcj_ltwrapper=yes
+    fi
+  else
+    AC_MSG_ERROR(Ignoring --enable-ltwrapper because ${ltwrapper_cfile} not found.)
+  fi
+fi
+
+AM_CONDITIONAL(LTWRAPPER, test "$enable_libgcj_ltwrapper" = yes)
+AC_SUBST(LTWRAPPER_EXE)
+
 # What is the native OS API for MinGW?
 AC_ARG_WITH(win32-nlsapi,
Index: ltwrapper-i686-pc-linux-gnu.c
===================================================================
--- ltwrapper-i686-pc-linux-gnu.c	2003-12-03 02:08:36.000000000 -0600
+++ ltwrapper-i686-pc-linux-gnu.c	2003-12-03 02:54:24.000000000 -0600
@@ -0,0 +1,228 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#ifdef WIN32
+
+#include <direct.h>
+#define MKDIR(x) _mkdir(x)
+
+#else
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#define MKDIR(x) mkdir(x, 0755)
+
+#endif
+
+#define DEFAULT_LIBTOOL "/bin/sh ./libtool "
+#define GCJ_TAG "--tag=GCJ"
+#define COMPILE_MODE "--mode=compile"
+
+static void
+createDirectory (const char* dir)
+{
+  int ret;
+  
+  ret = MKDIR (dir);
+  
+  if (ret != 0 && errno != EEXIST)
+    {
+      perror ("error creating directory");
+      exit (ret);
+    }
+  else if (ret == 0)
+    printf ("created directory %s\n", dir);
+}
+
+static void
+invoke (const char* cmd)
+{
+  int ret = 0;
+  
+  printf("%s\n", cmd);
+  ret = system (cmd);
+  if (ret != 0)
+    exit (ret);
+}
+
+static void
+addArg(char** ppsz, const char* arg)
+{
+  char *psz = *ppsz;
+  char ch;
+  int hasSpace = strchr (arg, ' ') != 0;
+  
+  if (hasSpace)
+    *psz++ = '\"';
+  while ((ch = *arg++))
+    {
+      if (ch == '\"' || ch == '\\')
+        *psz++ = '\\';
+      *psz++ = ch;
+    }
+  if (hasSpace)
+    *psz++ = '\"';
+  *psz++ = ' ';
+  *psz = '\0';
+  
+  *ppsz = psz;
+}
+
+static int
+findArg (int argc, char* argv[], const char* pcszArg)
+{
+  int i;
+  for (i = 1; i < argc; ++i)
+    {
+      if (!strcmp (argv[i], pcszArg))
+        return i;
+    }
+    
+  fprintf(stderr, "argument \"%s\" not found", pcszArg);
+  exit(1);
+  
+  return -1;
+}
+
+static const char*
+dir_part (char* buf, const char* pathname)
+{
+  int i, len;
+
+  len = strlen(pathname);
+  *buf = '\0';
+  
+  for (i = len-1; i >= 0; --i)
+    {
+      if (pathname[i] == '/')
+        break;
+    }
+    
+  if (i >= 0)
+    {
+      strncpy(buf, pathname, i);
+      buf[i] = '\0';
+    }
+    
+  return buf;
+}
+
+static const char*
+base_part (char* buf, const char* pathname)
+{
+  int i, len;
+
+  len = strlen(pathname);
+  *buf = '\0';
+  
+  for (i = len-1; i >= 0; --i)
+    {
+      if (pathname[i] == '/')
+        break;
+    }
+    
+  if (i >= 0)
+    {
+      char* psz = buf;
+
+      ++i;
+      while (i < len && pathname[i] != '.')
+        *psz++ = pathname[i++];
+        
+      *psz = '\0';
+    }
+    
+  return buf;
+}
+
+static int
+compileJava (int argc, char* argv[])
+{
+  char cmdline[20000];
+  char *pszSave, *psz = cmdline;
+  int i;
+  char piclibdir[1000], dirpart[1000], basepart[1000], temp_buf[1000];
+  int nMinC;
+  int nRetCode;
+  FILE* lofile;
+  
+  nMinC = findArg (argc, argv, "-c");
+  
+  /* Add all arguments up to and including -c */
+  for (i=3; i <= nMinC; ++i)
+    addArg (&psz, argv[i]);
+    
+  /* Add the source file */
+  addArg (&psz, argv[nMinC + 3]);
+  
+  /* Take a checkpoint so we can reuse our command line for
+     the second invocation. */
+  pszSave = psz;
+  
+  /* Do the pic invocation. */
+  sprintf (piclibdir, "%s/.libs", dir_part (dirpart, argv[nMinC + 2]));
+  createDirectory (piclibdir);
+  
+  addArg (&psz, "-fPIC");
+  addArg (&psz, "-o");
+  sprintf (temp_buf, "%s/%s.o", piclibdir,
+           base_part (basepart, argv[nMinC + 3]));
+  addArg (&psz, temp_buf);
+  invoke (cmdline);
+  
+  /* Do the non-pic invocation. */
+  psz = pszSave;
+  addArg (&psz, "-o");
+  sprintf (temp_buf, "%s/%s.o", dirpart, basepart);
+  addArg (&psz, temp_buf);
+  addArg (&psz, ">/dev/null");
+  addArg (&psz, "2>&1");
+  invoke (cmdline);
+  
+  /* Create the .lo file */
+  /* FIXME: Put all the header junk in the comments. */
+  sprintf (temp_buf, "%s/%s.lo", dirpart, basepart);
+  lofile = fopen (temp_buf, "w");
+  if (!lofile)
+    {
+      fprintf (stderr, "error writing %s\n", temp_buf);
+      exit (1);
+    }
+  fprintf (lofile, "# Generated by GNU libtool yada yada\n");
+  fprintf (lofile, "pic_object='.libs/%s.o'\n", basepart);
+  fprintf (lofile, "non_pic_object='%s.o'\n", basepart);
+  fclose (lofile);
+  
+  return 0;
+}
+
+static int
+invokeRealLibtool (int argc, char* argv[])
+{
+  char cmdline[20000];
+  char* psz = cmdline;
+  int i;
+  
+  strcpy (psz, DEFAULT_LIBTOOL);
+  psz += strlen (DEFAULT_LIBTOOL);
+  
+  for (i = 1; i < argc; ++i)
+    addArg (&psz, argv[i]);
+
+  invoke (cmdline);
+  
+  return 0;
+}
+
+int
+main (int argc, char* argv[])
+{
+  if (argc < 3 || strcmp (argv[1], GCJ_TAG)
+      || strcmp (argv[2], COMPILE_MODE))
+    return invokeRealLibtool (argc, argv);
+  else
+    return compileJava (argc, argv);
+}





More information about the Java-patches mailing list