See http://distcc.samba.org/faq.html#gdb
This is ftp://ftp.gtk.org/pub/users/timj/patches/distcc-line3.diff
rediffed against distcc-2.18.3, with one tiny bugfix;
here's the bugfix (as a unified diff against postproc.c):
+#if 0
strcpy (dirname + dl, pp_source_name);
+#else
+ /* Original patch appended pp_source_name, but
+ * that was wrong if it contained a directory part;
+ * if dir was /foo and source_name was bar/bletch,
+ * it caused embedded paths of form /foo/bar/bar/blech.c
+ */
+ dirname[dl] = 0;
+#endif
diff -Naur distcc-2.18.3/Makefile.in distcc-2.18.3-postproc/Makefile.in
--- distcc-2.18.3/Makefile.in 2004-10-23 22:05:48.000000000 -0700
+++ distcc-2.18.3-postproc/Makefile.in 2005-12-10 13:09:08.000000000 -0800
@@ -165,6 +165,7 @@
src/rpc.o src/tempfile.o src/bulk.o src/help.o src/filename.o \
src/lock.o \
src/netutil.o \
+ src/postproc.o \
src/pump.o \
src/sendfile.o \
src/safeguard.o src/snprintf.o src/timeval.o \
@@ -232,6 +233,7 @@
src/mon.c src/mon-notify.c src/mon-text.c \
src/mon-gnome.c \
src/ncpus.c src/netutil.c \
+ src/postproc.c \
src/prefork.c src/pump.c \
src/remote.c src/renderer.c src/rpc.c \
src/safeguard.c src/sendfile.c src/setuid.c src/serve.c \
@@ -243,6 +245,7 @@
HEADERS = src/access.h \
+ src/postproc.h \
src/bulk.h \
src/clinet.h src/compile.h \
src/daemon.h \
diff -Naur distcc-2.18.3/src/compile.c distcc-2.18.3-postproc/src/compile.c
--- distcc-2.18.3/src/compile.c 2004-10-01 17:47:07.000000000 -0700
+++ distcc-2.18.3-postproc/src/compile.c 2005-12-10 13:09:08.000000000 -0800
@@ -44,6 +44,7 @@
#include "lock.h"
#include "timeval.h"
#include "compile.h"
+#include "postproc.h"
/**
@@ -154,6 +155,8 @@
/* FIXME: argv_stripped is leaked. */
+ if ((ret = dcc_post_process_set_source(input_fname)) != 0)
+ goto fallback;
if ((ret = dcc_compile_remote(argv_stripped,
input_fname,
cpp_fname,
diff -Naur distcc-2.18.3/src/postproc.c distcc-2.18.3-postproc/src/postproc.c
--- distcc-2.18.3/src/postproc.c 1969-12-31 16:00:00.000000000 -0800
+++ distcc-2.18.3-postproc/src/postproc.c 2005-12-10 13:09:39.000000000 -0800
@@ -0,0 +1,375 @@
+/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*-
+ *
+ * distcc -- A simple distributed compiler system
+ * $Header: $
+ *
+ * Copyright (C) 2002 by Tim Janik
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include "config.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "distcc.h"
+#include "trace.h"
+#include "assert.h"
+#include "postproc.h"
+
+
+typedef unsigned char uchar;
+
+/* buffered input */
+#define BUFFER_SIZE 4000
+typedef struct {
+ int fd;
+ uchar *bound;
+ uchar buffer[BUFFER_SIZE + 1];
+ uchar *text;
+} PPInput;
+
+static inline int peek_char (PPInput *inp)
+{
+ if (inp->text < inp->bound)
+ return *inp->text;
+ else if (inp->fd >= 0) {
+ int count;
+ uchar *buffer = inp->buffer;
+ do
+ count = read (inp->fd, buffer, BUFFER_SIZE);
+ while (count == -1 && (errno == EINTR || errno == EAGAIN));
+ if (count < 1) {
+ inp->fd = -1;
+ return EOF;
+ } else {
+ inp->text = buffer;
+ inp->bound = buffer + count;
+ return *inp->text;
+ }
+ } else
+ return EOF;
+}
+
+static inline int get_char (PPInput *inp)
+{
+ int c = peek_char (inp);
+ if (c != EOF)
+ inp->text++;
+ return c;
+}
+
+static void unget_char (PPInput *inp,
+ uchar c)
+{
+ /* we only allow unget backs after a non-EOF get_char() */
+ assert (inp->text > inp->buffer);
+ inp->text--;
+ inp->text[0] = c;
+}
+
+
+/* buffered output */
+typedef struct {
+ int fd;
+ uchar *p;
+ uchar buffer[BUFFER_SIZE + 1];
+} PPOutput;
+
+static void flush_output (PPOutput *out)
+{
+ int count, n = out->p - out->buffer;
+ errno = 0;
+ if (n) {
+ do
+ count = write (out->fd, out->buffer, n);
+ while (count == -1 && (errno == EINTR || errno == EAGAIN));
+ if (count != n)
+ rs_log_error ("failed to write %u bytes: %s", n, strerror (errno));
+ }
+ out->p = out->buffer;
+}
+
+static inline void write_char (PPOutput *out,
+ int ch)
+{
+ *(out->p++) = ch;
+ if (out->p - out->buffer >= BUFFER_SIZE)
+ flush_output (out);
+}
+
+
+/* source file path name */
+static char *pp_source_name = NULL;
+
+/* rarely triggered. post processed output usually doesn't
+ * contain comments (an exception would be gcc -E -C)
+ */
+static void post_process_comment_rest (PPInput *inp,
+ PPOutput *out,
+ int term /* must be '\n' or '/' */)
+{
+ int seenast = FALSE;
+ /* read up to \n or * followed by / */
+ while (1) {
+ int c = get_char (inp);
+ switch (c) {
+ case EOF:
+ return; /* broken input */
+ case '*':
+ write_char (out, c);
+ seenast = TRUE;
+ break;
+ case '/':
+ write_char (out, c);
+ if (seenast && term == c)
+ return;
+ break;
+ case '\n':
+ write_char (out, c);
+ if (term == c)
+ return;
+ seenast = FALSE;
+ break;
+ default:
+ write_char (out, c);
+ seenast = FALSE;
+ break;
+ }
+ }
+}
+
+/* process the rest of a string, after the initial '\'' or '\"' has been read */
+static inline void post_process_string_rest (PPInput *inp,
+ PPOutput *out,
+ int term /* must be '\"' or '\'' */)
+{
+ int escape = FALSE;
+ while (1) {
+ int c = get_char (inp);
+ switch (c) {
+ case EOF:
+ return; /* broken input */
+ case '\\':
+ write_char (out, c);
+ escape = !escape;
+ break;
+ case '\"':
+ case '\'':
+ write_char (out, c);
+ if (c == term && !escape)
+ return;
+ escape = FALSE;
+ break;
+ default:
+ write_char (out, c);
+ escape = FALSE;
+ break;
+ }
+ }
+}
+
+/* handle the case where a line starts with '#' which indicates
+ * preprocessor instructions. the ones to care about here are
+ * '# 3 "files/foo.c"', i.e. source file references. those are
+ * patched up to only contain absolute pathnames.
+ */
+static int post_process_hashcross (PPInput *inp,
+ PPOutput *out,
+ const char *pathprefix)
+{
+ int c;
+ /* check whether here comes a #-line directive, hash already parsed.
+ * we need to return the last char processed for our caller to update state.
+ */
+
+ /* read up spaces */
+ c = get_char (inp);
+ while (c == ' ' || c == '\t') {
+ write_char (out, c);
+ c = get_char (inp);
+ }
+ /* read up digits */
+ while (c >= '0' && c <= '9') {
+ write_char (out, c);
+ c = get_char (inp);
+ }
+ /* read up spaces */
+ while (c == ' ' || c == '\t') {
+ write_char (out, c);
+ c = get_char (inp);
+ }
+ /* read up double quote */
+ if (c != '\"')
+ goto abort;
+ write_char (out, c);
+ c = get_char (inp);
+ /* here it comes: if c is a slash, we got an absolute
+ * pathname. otherwise we insert our prefix and handle
+ * the rest as an ordinary string.
+ */
+ if (c != '/') {
+ const char *p = pathprefix;
+ while (*p)
+ write_char (out, *p++);
+ }
+ unget_char (inp, c);
+ post_process_string_rest (inp, out, '\"');
+ return '\"';
+
+ abort:
+ if (c != EOF)
+ write_char (out, c);
+ return c;
+}
+
+static void post_process (PPInput *inp,
+ PPOutput *out,
+ const char *pathprefix)
+{
+ int seennewline = TRUE;
+ int lastc, c = '\n';
+ while (1) {
+ lastc = c;
+ c = get_char (inp);
+ switch (c) {
+ case EOF:
+ return;
+ case '\n':
+ write_char (out, c);
+ seennewline = TRUE;
+ break;
+ case '#':
+ write_char (out, c);
+ if (seennewline) {
+ c = post_process_hashcross (inp, out, pathprefix);
+ if (c == EOF)
+ return;
+ }
+ seennewline = c == '\n';
+ break;
+ case ' ':
+ case '\t':
+ write_char (out, c);
+ /* preserve seennewline */
+ break;
+ case '*':
+ write_char (out, c);
+ if (lastc == '/') {
+ post_process_comment_rest (inp, out, '/');
+ c = '/';
+ }
+ seennewline = FALSE;
+ break;
+ case '\"': case '\'':
+ write_char (out, c);
+ post_process_string_rest (inp, out, c);
+ seennewline = FALSE;
+ break;
+ default:
+ write_char (out, c);
+ seennewline = FALSE;
+ break;
+ }
+ }
+}
+
+int dcc_post_process (const char *in_fname,
+ char **out_fname)
+{
+ char *p, *dirname;
+ PPOutput out = { -1, 0, { 0, } };
+ PPInput inp = { -1, 0, { 0, }, 0 };
+ int ret;
+
+ rs_trace("dcc_post_process(%s,)", in_fname);
+ if ((ret = dcc_make_tmpnam ("ppline", ".i", out_fname)))
+ return ret;
+
+ inp.fd = open (in_fname, O_RDONLY);
+ if (inp.fd < 0) {
+ rs_log_error ("opening input \"%s\" failed: %s", in_fname, strerror (errno));
+ return -1;
+ }
+
+ out.p = out.buffer;
+ out.fd = open (*out_fname, O_CREAT | O_TRUNC | O_WRONLY, 0644);
+ if (out.fd < 0) {
+ rs_log_error ("opening output \"%s\" failed: %s", *out_fname, strerror (errno));
+ close (inp.fd);
+ return -1;
+ }
+
+ if (!pp_source_name)
+ pp_source_name = strdup ("");
+
+ /* figure slash terminated directory name */
+ if (pp_source_name[0] == '/') {
+ dirname = strdup (pp_source_name);
+ } else {
+ int dl, sl = strlen (pp_source_name);
+ char cdirbuf[8192];
+ char *cdir = getcwd (cdirbuf, sizeof (cdirbuf));
+ if (!cdir)
+ return -1;
+ dl = strlen (cdir);
+ dirname = malloc (dl + 1 + sl + 1);
+ strcpy (dirname, cdir);
+ dirname[dl++] = '/';
+#if 0
+ strcpy (dirname + dl, pp_source_name);
+#else
+ /* Original patch appended pp_source_name, but
+ * that was wrong if it contained a directory part;
+ * if dir was /foo and source_name was bar/bletch,
+ * it caused embedded paths of form /foo/bar/bar/blech.c
+ */
+ dirname[dl] = 0;
+#endif
+ }
+ p = strrchr (dirname, '/');
+ if (p)
+ p[1] = 0;
+ rs_trace("dcc_post_process: pp_source_name %s, setting dirname to %s", pp_source_name, dirname);
+
+ post_process (&inp, &out, dirname);
+ flush_output (&out);
+ free (dirname);
+
+ close (inp.fd);
+ if (close (out.fd)) {
+ rs_log_error ("flushing output %s failed: %s\n", *out_fname, strerror (errno));
+ return -1;
+ }
+ return 0;
+}
+
+int dcc_post_process_set_source (const char *source_name)
+{
+ rs_trace("dcc_post_process_set_source(%s)", source_name ? source_name : "");
+ if (pp_source_name)
+ free (pp_source_name);
+ pp_source_name = source_name ? strdup (source_name) : NULL;
+ return 0;
+}
diff -Naur distcc-2.18.3/src/postproc.h distcc-2.18.3-postproc/src/postproc.h
--- distcc-2.18.3/src/postproc.h 1969-12-31 16:00:00.000000000 -0800
+++ distcc-2.18.3-postproc/src/postproc.h 2005-12-10 13:09:08.000000000 -0800
@@ -0,0 +1,28 @@
+/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*-
+ *
+ * distcc -- A simple distributed compiler system
+ * $Header: $
+ *
+ * Copyright (C) 2002 by Tim Janik
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+/* postproc.c */
+int dcc_post_process_set_source (const char *source_name);
+int dcc_post_process (const char *in_fname,
+ char **out_fname);
+
diff -Naur distcc-2.18.3/src/remote.c distcc-2.18.3-postproc/src/remote.c
--- distcc-2.18.3/src/remote.c 2004-10-23 22:05:49.000000000 -0700
+++ distcc-2.18.3-postproc/src/remote.c 2005-12-10 13:09:08.000000000 -0800
@@ -48,6 +48,7 @@
#include "lock.h"
#include "compile.h"
#include "bulk.h"
+#include "postproc.h"
/*
@@ -183,6 +184,7 @@
int ssh_status;
off_t doti_size;
struct timeval before, after;
+ char *pp_fname;
if (gettimeofday(&before, NULL))
rs_log_warning("gettimeofday failed");
@@ -208,7 +210,9 @@
if ((ret = dcc_wait_for_cpp(cpp_pid, status, input_fname)))
goto out;
- if ((ret = dcc_x_file(to_net_fd, cpp_fname, "DOTI", host->compr, &doti_size)))
+ if ((ret = dcc_post_process(cpp_fname, &pp_fname)))
+ goto out;
+ if ((ret = dcc_x_file(to_net_fd, pp_fname, "DOTI", host->compr, &doti_size)))
goto out;
rs_trace("client finished sending request to server");