Avoiding unnecessary rebuilds with Automake

View: New views
1 Messages — Rating Filter:   Alert me  

Avoiding unnecessary rebuilds with Automake

by Jean-Yves Lefort :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

The attached patch:

  - adds a --no-touch option, which prevents all files (not just the
    public header) from being touched unless they have changed
  - while here, checks if a file has changed without cmp(1)
  - removes the timestamp from .c comment headers

It helps avoiding unnecessary rebuilds when GOB is used from Automake,
thanks to the following trick (the manual page should be updated):

foo_SOURCES = foo.gob foo.gob.stamp foo.c foo.h foo-private.h
BUILT_SOURCES = foo.gob.stamp
MAINTAINERCLEANFILES = foo.gob.stamp

%.gob.stamp: %.gob
        @GOB2@ --no-touch $<
        @touch $@

--
Jean-Yves Lefort

jylefort@...
http://lefort.be.eu.org/

--- src/main.c.orig Tue Dec  6 11:08:37 2005
+++ src/main.c Tue Dec  6 12:30:23 2005
@@ -25,6 +25,7 @@
 #include <glib.h>
 #include <time.h>
 #include <stdio.h>
+#include <errno.h>
 #include <string.h>
 #include <unistd.h>
 #include <stdlib.h>
@@ -54,6 +55,9 @@
 
 char *filebase;
 char *fullfilebase;
+static char *outfilebase;
+static char *outfilehbase;
+static char *outfilephbase;
 static char *funcbase;
 static char *pfuncbase;
 static char *macrobase;
@@ -99,6 +103,7 @@
 FILE *outph = NULL;
 FILE *devnull = NULL;
 
+gboolean no_touch = FALSE;
 gboolean no_touch_headers = FALSE;
 gboolean for_cpp = FALSE;
 gboolean no_gnu = FALSE;
@@ -3045,14 +3050,11 @@
 {
  char *outfile, *outfileh, *outfileph;
 
- if ( ! for_cpp)
- outfile = g_strconcat (fullfilebase, ".c", NULL);
- else
- outfile = g_strconcat (fullfilebase, ".cc", NULL);
- if (no_touch_headers)
- outfileh = g_strconcat (fullfilebase, ".h#gob#", NULL);
- else
- outfileh = g_strconcat (fullfilebase, ".h", NULL);
+ outfilebase = g_strconcat (fullfilebase, for_cpp ? ".cc" : ".c", NULL);
+ outfile = g_strconcat(outfilebase, no_touch ? "#gob#" : "", NULL);
+
+ outfilehbase = g_strconcat (fullfilebase, ".h");
+ outfileh = g_strconcat(outfilehbase, no_touch_headers ? "#gob#" : "", NULL);
 
  if ((privates > 0 || protecteds > 0 ||
      private_header == PRIVATE_HEADER_ALWAYS) &&
@@ -3060,8 +3062,10 @@
  char sep[2] = {0,0};
  if (file_sep != 0)
  sep[0] = file_sep;
- outfileph = g_strconcat (fullfilebase, sep, "private.h", NULL);
+ outfilephbase = g_strconcat (fullfilebase, sep, "private.h", NULL);
+ outfileph = g_strconcat (outfilephbase, no_touch ? "#gob#" : "", NULL);
  } else {
+ outfilephbase = NULL;
  outfileph = NULL;
  }
 
@@ -3675,16 +3679,13 @@
 static void
 print_file_comments(void)
 {
- time_t curtime;
- time(&curtime);
  out_printf(outh, "/* Generated by GOB (v%s)"
    "   (do not edit directly) */\n\n", VERSION);
  if(outph)
  out_printf(outph, "/* Generated by GOB (v%s)"
    "   (do not edit directly) */\n\n", VERSION);
- out_printf(out, "/* Generated by GOB (v%s) on %s"
-   "   (do not edit directly) */\n\n",
-   VERSION, ctime(&curtime));
+ out_printf(out, "/* Generated by GOB (v%s)"
+   "   (do not edit directly) */\n\n", VERSION);
 
  out_printf(out, "/* End world hunger, donate to the World Food Programme, http://www.wfp.org */\n\n");
 }
@@ -4075,6 +4076,9 @@
  "\t--no-extern-c           Never print extern \"C\" into the "
         "header\n"
  "\t--no-gnu                Never use GNU extentions\n"
+ "\t--no-touch              Don't touch output files unless they "
+                          "really\n"
+ "\t                        changed (implies --no-touch-headers)\n"
  "\t--no-touch-headers      Don't touch headers unless they "
                           "really changed\n"
  "\t--always-private-header Always create a private header "
@@ -4172,6 +4176,9 @@
  exit_on_warn = FALSE;
  } else if(strcmp(argv[i], "--for-cpp")==0) {
  for_cpp = TRUE;
+ } else if(strcmp(argv[i], "--no-touch")==0) {
+ no_touch = TRUE;
+ no_touch_headers = TRUE;
  } else if(strcmp(argv[i], "--no-touch-headers")==0) {
  no_touch_headers = TRUE;
  } else if(strcmp(argv[i], "--ondemand-private-header")==0) {
@@ -4283,35 +4290,79 @@
 #endif
 }
 
-/* this is a somewhat ugly hack, but it appears to work */
 static void
-compare_and_move_header(void)
+compare_and_move (const char *old_filename)
 {
- char *hfnew = g_strconcat(fullfilebase, ".h#gob#", NULL);
- char *hf = g_strconcat(fullfilebase, ".h", NULL);
- struct stat s;
- if(stat(hf, &s) == 0) {
- char *s;
- s = g_strdup_printf("cmp '%s' '%s' > /dev/null", hf, hfnew);
- if(system(s) == 0) {
- if(unlink(hfnew) != 0)
- error_printf(GOB_ERROR, 0,
-     "Can't remove new header file");
- g_free(hfnew);
- g_free(hf);
- g_free(s);
- return;
+ char *new_filename = g_strconcat (old_filename, "#gob#", NULL);
+ FILE *old_f;
+ gboolean equal = FALSE;
+
+ old_f = fopen (old_filename, "r");
+ if (old_f) {
+ FILE *new_f;
+ gboolean error = FALSE;
+
+ new_f = fopen (new_filename, "r");
+ if (new_f) {
+ char new_buf[1024];
+ char old_buf[1024];
+
+ while (TRUE) {
+ size_t new_n;
+ size_t old_n;
+
+ new_n = fread (new_buf, 1, sizeof (new_buf), new_f);
+ if (ferror (new_f)) {
+ error = TRUE;
+ error_printf (GOB_ERROR, 0,
+      "Can't read %s: %s",
+      new_filename,
+      g_strerror (errno));
+ break;
+ }
+
+ old_n = fread (old_buf, 1, sizeof (old_buf), old_f);
+ if (ferror (old_f)
+    || feof (new_f) != feof (old_f)
+    || new_n != old_n
+    || memcmp (new_buf, old_buf, new_n) != 0)
+ break;
+
+ if (feof (new_f)) {
+ equal = TRUE;
+ break;
+ }
+ }
+ } else
+ error_printf (GOB_ERROR, 0, "Can't open %s: %s",
+      new_filename, g_strerror (errno));
+
+ fclose (old_f);
+ fclose (new_f);
+
+ if (error)
+ goto end;
+
+ if (! equal && unlink (old_filename) != 0) {
+ error_printf (GOB_ERROR, 0, "Can't remove %s: %s",
+      old_filename, g_strerror (errno));
+ goto end;
  }
- g_free(s);
- if(unlink(hf) != 0)
- error_printf(GOB_ERROR, 0,
-     "Can't remove old header file");
- }
- if(rename(hfnew, hf) != 0)
- error_printf(GOB_ERROR, 0,
-     "Can't rename new header file");
- g_free(hfnew);
- g_free(hf);
+ }
+
+ if (equal) {
+ if (unlink (new_filename) != 0)
+ error_printf (GOB_ERROR, 0, "Can't remove %s: %s",
+      new_filename, g_strerror (errno));
+ } else {
+ if (rename (new_filename, old_filename) != 0)
+ error_printf (GOB_ERROR, 0, "Can't rename %s to %s: %s",
+      new_filename, old_filename,
+      g_strerror (errno));
+ }
+
+ end:
+ g_free (new_filename);
 }
 
 int
@@ -4413,9 +4464,15 @@
  fclose (outph);
  }
 
- if (no_touch_headers &&
-    ! no_write)
- compare_and_move_header ();
+ if (! no_write) {
+ if (no_touch) {
+ compare_and_move (outfilebase);
+ if (outfilephbase)
+ compare_and_move (outfilephbase);
+ }
+ if (no_touch_headers)
+ compare_and_move (outfilehbase);
+ }
 
  return 0;
 }


--
to unsubscribe:
send mail to minimalist@... with "unsubscribe gob-list" in the subject

attachment0 (194 bytes) Download Attachment