Martin Pool wrote: > On 25 Jul 2002, joerg.beyer@email.de wrote: > Dear Joerg, > > You should be able to simply chain ccache and distcc > > CC='ccache distcc gcc' > > Also, if you wish, you can put the ccache cache on a NFS filesystem. > > If you have ideas for improvement of course they are welcome. > Hi Martin, I have a patch, that kind of "proofs", that a distcc run did fine. I wanted to test if all machines produce always the same *.o file, since my machine setup differs. For this test, I compile the source files not only on one remove machine, but on all remote machine. This is only enabled if the envvar DISTCC_PROFBUILD is set. The patch could of course be improved, e.g. the diagnostics are always printed to stderr - it could be written to the logfile instead. hope this helps Joerg diff -bur distcc-0.6/src/bulk.c distcc/src/bulk.c --- distcc-0.6/src/bulk.c Thu Jun 13 07:14:21 2002 +++ distcc/src/bulk.c Tue Jul 30 16:58:03 2002 @@ -189,3 +189,55 @@ return 0; } + +static ssize_t read_block(int fd, char* buffer, ssize_t max_size) +{ + ssize_t bytes_read = 0; + while(max_size>0) { + int rc = read(fd, buffer, max_size); + if (rc == 0) { + return bytes_read; + } + if (rc>0) { + max_size -= rc; + bytes_read += rc; + } + return -1; + } + /* never reached */ + return -1; +} + +int compare_files(const char* fn1, const char* fn2) +{ + char buffer1[10240]; + char buffer2[10240]; + ssize_t size1, size2; + int fd1, fd2; + + fd1 = open(fn1, O_RDONLY); + if(fd1<0) return -1; + fd2 = open(fn2, O_RDONLY); + if(fd1<0) { + close(fd1); + return -1; + } + do { + if ((size1 = read_block(fd1,buffer1, sizeof(buffer1))) > 0) { + size2 = read_block(fd1,buffer1, sizeof(buffer1)); + if (size1 != size2) + goto error; + + if (memcmp(buffer1, buffer2, size1) != 0) + goto error; + } + }while(size1>0); + + close(fd1); + close(fd2); + return 0; +error: + close(fd1); + close(fd2); + return -1; +} diff -bur distcc-0.6/src/distcc.c distcc/src/distcc.c --- distcc-0.6/src/distcc.c Fri Jul 12 03:34:03 2002 +++ distcc/src/distcc.c Tue Jul 30 16:59:08 2002 @@ -52,6 +52,7 @@ #include "exitcode.h" #include "util.h" #include "clinet.h" +#include "hosts.h" /* for trace.c */ const char *rs_program_name = "distcc"; @@ -166,7 +167,7 @@ } if (dcc_x_file(fd, cpp_fname, "DOTI", NULL)) - return -1; + fprintf(stderr, "%s:%d\n",__FILE__,__LINE__); tcp_cork_sock(fd, 0); rs_trace("client finished sending request to server"); @@ -174,8 +175,10 @@ if (dcc_r_result_header(fd) || dcc_r_cc_status(fd, status) || dcc_r_fd(fd, STDERR_FILENO, "SERR", NULL) - || dcc_r_fd(fd, STDOUT_FILENO, "SOUT", NULL)) + || dcc_r_fd(fd, STDOUT_FILENO, "SOUT", NULL)) { + fprintf(stderr, "%s:%d\n",__FILE__,__LINE__); return -1; + } /* Only try to retrieve the .o file if the compiler completed * successfully */ @@ -321,6 +324,87 @@ } } +/* + * build an object file on all possible machines and compare + * them. if everything went fine, than all object file must + * be equal copies. + * + * this is not for normal operation but for testing. + */ +static int dcc_proof_build(char *argv[], int *status) +{ + char *input_fname, *output_fname, *cpp_fname; + pid_t cpp_pid = 0; + int ret; + char *buildhost; + int must_be_local = 0; + struct dcc_hostdef *hostlist, *h; + int n_hosts; + int build_rc = 0; + char local_dot_o_file[512]; /* should be enough */ + snprintf(local_dot_o_file, sizeof(local_dot_o_file), "distcc__local__tmp_objfile_%d.o", getpid()); + + if (dcc_scan_args(argv, &input_fname, &output_fname, &argv) != 0) { + /* we need to scan the arguments even if we already know it's local, so that + * we can pick up distcc client options. */ + must_be_local = 1; + } + printf("%s:%d> in '%s' out '%s'\n", __FILE__, __LINE__, input_fname, output_fname); + + if (must_be_local) { + /* This one returns -1 for jobs that can't be remote. */ + return dcc_compile_local(argv); + } else { + fprintf(stderr, "%s:%d> will compile local\n", __FILE__, __LINE__); + if ((ret = dcc_compile_local(argv))) { + fprintf(stderr, "local compile failed\n"); + return ret; + } + fprintf(stderr, "%s:%d> have compiled\n", __FILE__, __LINE__); + + /* TODO: for rename(2) to succeed, both files need to + * be on the same filesystem. */ + if(rename(output_fname, local_dot_o_file)) { + perror("rename"); + assert(0); + } + fprintf(stderr, "%s:%d> have renamed '%s' -> '%s'\n", __FILE__, __LINE__, output_fname, local_dot_o_file); + + if ((ret = dcc_parse_hosts_env(&hostlist, &n_hosts)) != 0) { + return ret; + } + + for (h = hostlist; h; h = h->next) { + buildhost = h->hostname; + cpp_pid = 0; + if ((ret = dcc_cpp_maybe(argv, input_fname, &cpp_fname, &cpp_pid) != 0)) + return ret; + + if ((ret = dcc_compile_remote(argv, cpp_fname, output_fname, + cpp_pid, buildhost, status)) != 0) { + fprintf(stderr, "remote compile of '%s' on host '%s' failed\n", + input_fname, buildhost); + build_rc = 1; + } + if(dcc_critique_status(*status, argv[0], buildhost)) { + fprintf(stderr, "remote compile on host '%s' ended " + "with status: %d\n", buildhost, *status); + build_rc = 1; + } + if(compare_files(output_fname, local_dot_o_file)) { + fprintf(stderr, "error: files '%s' and '%s' differ.\n", + output_fname, local_dot_o_file); + build_rc = 1; + } + fprintf(stderr, "%s:%d> remove '%s'\n", __FILE__, __LINE__, output_fname); + unlink(output_fname); + + } + rename(local_dot_o_file, output_fname); + + } + return 0; +} static void dcc_set_trace_from_env(void) { @@ -365,6 +449,10 @@ dcc_show_version("distcc"); exit(0); } + + if (getenv("DISTCC_PROFBUILD")) { + dcc_exit(dcc_proof_build(&argv[1], &status)); + } dcc_exit(dcc_build_somewhere(&argv[1], &status)); } diff -bur distcc-0.6/src/distcc.h distcc/src/distcc.h --- distcc-0.6/src/distcc.h Wed Jul 10 07:11:16 2002 +++ distcc/src/distcc.h Tue Jul 30 15:02:02 2002 @@ -120,7 +120,7 @@ /* bulk.c */ int dcc_open_read(const char *fname, int *ifd, off_t *fsize); - +int compare_files(const char* fn1, const char* fn2); /* hosts.c */ int dcc_parse_hosts_env(struct dcc_hostdef **ret_list,