Distributed Compilation
by Vadim Zaliva


Example 1: 
# mDNSResponder conf file
#
#    name type domain port text record
     rover _ssh._tcp local. 22
     rover _distcc-RH9._tcp local. 3632



Listing One

--- mDNSResponder.old 2004-06-02 17:16:03.000000000 -0700
+++ /etc/init.d/mDNSResponder 2004-06-02 17:45:47.000000000 
                                                    -0700@@ -12,7 +12,7 @@
  # processname: mDNSResponder
  # config:
  -OTHER_MDNSRD_OPTS=""
  +OTHER_MDNSRD_OPTS="-f /etc/mDNSResponder.conf"

  # Source function library.
 . /etc/init.d/functions
@@ -24,7 +24,7 @@
  start() {
         echo -n $"Starting mDNSResponder... "
-        /usr/local/bin/mDNSResponder $OTHER_MDNSRD_OPTS
+        /usr/bin/mDNSResponder $OTHER_MDNSRD_OPTS
         RETVAL=$?
         echo      return $RETVAL


Listing Two

/*
* Copyright 2003, 2004, 2004 Porchdog Software. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
* THIS SOFTWARE IS PROVIDED BY PORCHDOG SOFTWARE ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE HOWL PROJECT OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* The views and conclusions contained in the software and
* documentation are those of the authors and should not be
* interpreted as representing official policies, either expressed or
* implied, of Porchdog Software.
* -------------------------------------------------------------------
* mDNSlookup is quick hack, based on mDNSBrowse example from HOWL package.
* Main changes:
* 1. introduced timeout parameter
* 2. less-verbose output (do not report some packets, do not print TXT records)
* To compile on Linux use following command:
* cc -I/usr/include/howl mDNSlookup.c -o mDNSlookup -lhowl -lpthread -lrt
* Vadim Zaliva
*/
#include <howl.h>
#include <stdio.h>
#include <time.h>

static sw_result HOWL_API lookup_resolver(
   sw_discovery_resolve_handler handler,
   sw_discovery discovery,
   sw_discovery_resolve_id id,
   sw_const_string name,
   sw_const_string type,
   sw_const_string domain,
   sw_ipv4_address address,
   sw_port port,
   sw_const_string text_record_string,
   sw_octets text_record,
   sw_ulong text_record_len,
   sw_opaque extra)
{
   char name_buf[16];
   sw_discovery_stop_resolve(discovery, id);
   printf("%s %s %s %s %d\n", name, type, domain,
   sw_ipv4_address_name(address, name_buf, 16), port
   );
   return SW_OKAY;
}
static sw_result HOWL_API lookup_browser(
   sw_discovery_browse_handler handler,
   sw_discovery discovery,
   sw_discovery_browse_id id,
   sw_discovery_browse_status status,
   sw_const_string name,
   sw_const_string type,
   sw_const_string domain,
   sw_opaque extra)
{
   sw_discovery_resolve_id rid;
   if(status==SW_DISCOVERY_BROWSE_ADD_SERVICE)
   {
   if(sw_discovery_resolve(discovery, name, type, domain, NULL, 
                                lookup_resolver, NULL, &rid) != SW_OKAY)
      {
         fprintf(stderr, "resolve failed\n");
         return -1;
      }
   }
   return SW_OKAY;
}
main(int argc, char **argv)
{
   sw_discovery discovery ;
   sw_result result ;
   sw_discovery_browse_id id ;
   sw_salt salt ;
   sw_ulong timeout ;
   if(argc == 3)
   {
      char *e;
      timeout=strtol(argv[2], &e, 10);
      if(*e)
      {
         fprintf(stderr, "Invalid timeout value. 
                                     Should be number in milliseconds!\n");
         fprintf(stderr, "Usage: mDNSlookup <type> [timeout]\n");
         return -1;
      }
   } else if(argc != 2)
   {
      fprintf(stderr, "Usage: mDNSlookup <type> [timeout]\n");
      return -1;
   } else  
      timeout = 0L;
   if((result = sw_discovery_init(&discovery)) != SW_OKAY)
   {
      fprintf(stderr, "sw_discovery_init failed: %d\n", result);
      return -1;
   }
   if(sw_discovery_browse(discovery, argv[1], NULL, NULL, 
                              lookup_browser, NULL, &id) != SW_OKAY)
   {
      fprintf(stderr, "sw_discovery_browse_services failed: %d\n", result);
      return -1;
   }
   if(sw_discovery_salt(discovery, &salt)!= SW_OKAY)
   {
      fprintf(stderr, "sw_discovery_salt failed: %d\n", result);
      return -1;
   }
   if(timeout == 0L)
   {
      /* No timeout - wait forever. */
      sw_discovery_run(discovery);
   } else
   {
   /*
      Correct code should be:

      while(timeout != 0L)
      sw_salt_step(salt, &timeout);

      but sw_salt_step() does not modify 
      timeout value (this bug was reported to authors).
   */
   /*
   So, we have to do a workaround, using
   POSIX 1003.1b Section 14 (Clocks and Timers) API:
   */
   struct timespec start;
   clock_gettime(CLOCK_REALTIME, &start);
   while(1)
   {
         struct timespec now;
         clock_gettime(CLOCK_REALTIME, &now);
         long waited = (1000L*now.tv_sec+now.tv_nsec/1000000L) -
                (1000L*start.tv_sec+start.tv_nsec/1000000L);
         if(waited>=timeout)
            break;
         sw_ulong remain=timeout-waited;
         sw_salt_step(salt, &remain);
      }
   }
   return 0;
}


Listing Three

(a) distcc_on

#!/bin/sh
# Enables distributed compilation using DistCC
ln -s /usr/local/bin/distcc_wrapper ~/bin/c++
ln -s /usr/local/bin/distcc_wrapper ~/bin/cc
ln -s /usr/local/bin/distcc_wrapper ~/bin/g++
ln -s /usr/local/bin/distcc_wrapper ~/bin/gcc

(b) distcc_off

#!/bin/sh
# Disables distributed compilation using DistCC
rm -f ~/bin/c++ ~/bin/cc ~/bin/g++ ~/bin/gcc

(c) distcc_status

#!/bin/sh
# Shows if distributed compilation using DistCC is enabled
if [ -f ~/bin/c++ ] ; then 
   echo "distcc is ON"
else
   echo "discc is OFF"
fi

(d) distcc_nhosts

#!/bin/sh
# Prints number of hosts availiabe in compile farm
# Output of this script intended to be used with -j option of GNU make.
# By default we return number twice as much as hosts found in compile
# farm, plus one (to handle empty compile farm).
MDNS_TIMEOUT=200
SERVICE_NAME=_distcc-RH9._tcp
ADD_NHOSTS=1
MULTIPLY_NHOSTS=2
echo $(($ADD_NHOSTS+$((`mDNSlookup "$SERVICE_NAME" $MDNS_TIMEOUT | wc -l`+$MULTIPLY_NHOSTS))))

(e) distcc_wrapper

#!/bin/sh
#
# DistCC wrapper to use Rendezvous to discover compile
# farm machines. Should not be run directly by user.
MDNS_TIMEOUT=200
ADD_HOSTS_BEFORE=
ADD_HOSTS_AFTER=
SERVICE_NAME=_distcc-RH9._tcp
DYNAMIC_HOSTS=`mDNSlookup "$SERVICE_NAME" $MDNS_TIMEOUT | 
                                        awk '{printf "%s:%s ",$4,$5;}'`
export DISTCC_HOSTS="$ADD_HOSTS_BEFORE $DYNAMIC_HOSTS $ADD_HOSTS_AFTER"
export DISTCC_NHOSTS=`echo "$DISTCC_HOSTS" | wc -w`
echo $DISTCC_HOSTS
#export DISTCC_VERBOSE=1
exec distcc /usr/bin/c++ $*







5


