Avoiding unnecessary rebuilds with Automake

Jean-Yves Lefort <[email protected]> Tue, 6 Dec 2005 12:47:25 +0100
Newsgroups gmane.comp.gnome.devtools.gob.general
Message-ID <[email protected]>

This is a multi-part message in MIME format.

[email protected]
Content-Type: multipart/signed; protocol="application/pgp-signature";
 micalg="PGP-SHA1";
 boundary="Signature=_Tue__6_Dec_2005_12_47_25_+0100_nihAuSVr4LVDHIZg"

--Signature=_Tue__6_Dec_2005_12_47_25_+0100_nihAuSVr4LVDHIZg
Content-Type: multipart/mixed;
 boundary="Multipart=_Tue__6_Dec_2005_12_47_25_+0100_xHZEwbVbhE1JYIuf"


--Multipart=_Tue__6_Dec_2005_12_47_25_+0100_xHZEwbVbhE1JYIuf
Content-Type: text/plain; charset=US-ASCII
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

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 =3D foo.gob foo.gob.stamp foo.c foo.h foo-private.h
BUILT_SOURCES =3D foo.gob.stamp
MAINTAINERCLEANFILES =3D foo.gob.stamp

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

--=20
Jean-Yves Lefort

[email protected]
http://lefort.be.eu.org/

--Multipart=_Tue__6_Dec_2005_12_47_25_+0100_xHZEwbVbhE1JYIuf
Content-Type: text/plain;
 name="gob2-2.0.12-notouch.diff"
Content-Disposition: attachment;
 filename="gob2-2.0.12-notouch.diff"
Content-Transfer-Encoding: quoted-printable

--- 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 @@
=20
 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 =3D NULL;
 FILE *devnull =3D NULL;
=20
+gboolean no_touch =3D FALSE;
 gboolean no_touch_headers =3D FALSE;
 gboolean for_cpp =3D FALSE;
 gboolean no_gnu =3D FALSE;
@@ -3045,14 +3050,11 @@
 {
 	char *outfile, *outfileh, *outfileph;
=20
-	if ( ! for_cpp)
-		outfile =3D g_strconcat (fullfilebase, ".c", NULL);
-	else
-		outfile =3D g_strconcat (fullfilebase, ".cc", NULL);
-	if (no_touch_headers)
-		outfileh =3D g_strconcat (fullfilebase, ".h#gob#", NULL);
-	else
-		outfileh =3D g_strconcat (fullfilebase, ".h", NULL);
+	outfilebase =3D g_strconcat (fullfilebase, for_cpp ? ".cc" : ".c", NULL);
+	outfile =3D g_strconcat(outfilebase, no_touch ? "#gob#" : "", NULL);
+
+	outfilehbase =3D g_strconcat (fullfilebase, ".h");
+	outfileh =3D g_strconcat(outfilehbase, no_touch_headers ? "#gob#" : "", N=
ULL);
=20
 	if ((privates > 0 || protecteds > 0 ||
 	     private_header =3D=3D PRIVATE_HEADER_ALWAYS) &&
@@ -3060,8 +3062,10 @@
 		char sep[2] =3D {0,0};
 		if (file_sep !=3D 0)
 			sep[0] =3D file_sep;
-		outfileph =3D g_strconcat (fullfilebase, sep, "private.h", NULL);
+		outfilephbase =3D g_strconcat (fullfilebase, sep, "private.h", NULL);
+		outfileph =3D g_strconcat (outfilephbase, no_touch ? "#gob#" : "", NULL);
 	} else {
+		outfilephbase =3D NULL;
 		outfileph =3D NULL;
 	}
=20
@@ -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);
=20
 	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 =3D FALSE;
 		} else if(strcmp(argv[i], "--for-cpp")=3D=3D0) {
 			for_cpp =3D TRUE;
+		} else if(strcmp(argv[i], "--no-touch")=3D=3D0) {
+			no_touch =3D TRUE;
+			no_touch_headers =3D TRUE;
 		} else if(strcmp(argv[i], "--no-touch-headers")=3D=3D0) {
 			no_touch_headers =3D TRUE;
 		} else if(strcmp(argv[i], "--ondemand-private-header")=3D=3D0) {
@@ -4283,35 +4290,79 @@
 #endif
 }
=20
-/* 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 =3D g_strconcat(fullfilebase, ".h#gob#", NULL);
-	char *hf =3D g_strconcat(fullfilebase, ".h", NULL);
-	struct stat s;
-	if(stat(hf, &s) =3D=3D 0) {
-		char *s;
-		s =3D g_strdup_printf("cmp '%s' '%s' > /dev/null", hf, hfnew);
-		if(system(s) =3D=3D 0) {
-			if(unlink(hfnew) !=3D 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 =3D g_strconcat (old_filename, "#gob#", NULL);
+	FILE *old_f;
+	gboolean equal =3D FALSE;
+
+	old_f =3D fopen (old_filename, "r");
+	if (old_f) {
+		FILE *new_f;
+		gboolean error =3D FALSE;
+
+		new_f =3D 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 =3D fread (new_buf, 1, sizeof (new_buf), new_f);
+				if (ferror (new_f)) {
+					error =3D TRUE;
+					error_printf (GOB_ERROR, 0,
+						      "Can't read %s: %s",
+						      new_filename,
+						      g_strerror (errno));
+					break;
+				}
+
+				old_n =3D fread (old_buf, 1, sizeof (old_buf), old_f);
+				if (ferror (old_f)
+				    || feof (new_f) !=3D feof (old_f)
+				    || new_n !=3D old_n
+				    || memcmp (new_buf, old_buf, new_n) !=3D 0)
+					break;
+
+				if (feof (new_f)) {
+					equal =3D 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) !=3D 0) {
+			error_printf (GOB_ERROR, 0, "Can't remove %s: %s",
+				      old_filename, g_strerror (errno));
+			goto end;
 		}
-		g_free(s);
-		if(unlink(hf) !=3D 0)
-			error_printf(GOB_ERROR, 0,
-				     "Can't remove old header file");
-	}
-	if(rename(hfnew, hf) !=3D 0)
-		error_printf(GOB_ERROR, 0,
-			     "Can't rename new header file");
-	g_free(hfnew);
-	g_free(hf);
+	}
+
+	if (equal) {
+		if (unlink (new_filename) !=3D 0)
+			error_printf (GOB_ERROR, 0, "Can't remove %s: %s",
+				      new_filename, g_strerror (errno));
+	} else {
+		if (rename (new_filename, old_filename) !=3D 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);
 }
=20
 int
@@ -4413,9 +4464,15 @@
 			fclose (outph);
 	}
=20
-	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);
+	}
 =09
 	return 0;
 }

--Multipart=_Tue__6_Dec_2005_12_47_25_+0100_xHZEwbVbhE1JYIuf--

--Signature=_Tue__6_Dec_2005_12_47_25_+0100_nihAuSVr4LVDHIZg
Content-Type: application/pgp-signature

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2 (FreeBSD)

iD8DBQFDlXpOyzD7UaO4AGoRApGvAJ0Tlu9Kbz4+X0Fxi9QZk3k+EV5D+ACdHjIm
RkyalGXspbLJ8B4sVcmLluA=
=o8xS
-----END PGP SIGNATURE-----

--Signature=_Tue__6_Dec_2005_12_47_25_+0100_nihAuSVr4LVDHIZg--


[email protected]
Content-Type: text/plain; charset=us-ascii; name="footer"
Content-Transfer-Encoding: 8bit

--
to unsubscribe:
send mail to [email protected] with "unsubscribe gob-list" in the subject

[email protected]