Uber configure.ac/Makefile.am and configure.ac/Makefile.am for lib/php and compiler

Modified TProtocol.h et al to take collection size as unsigned int.  This removes need to cast STL's default size_t to signed int and is more correct, since collection sizes cannot be < 0 by definition

Moved compiler/Makefile to compiler/cpp.mk so it doesn't get trashed by automake

    


git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@664766 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/bootstrap.sh b/bootstrap.sh
new file mode 100755
index 0000000..fe07add
--- /dev/null
+++ b/bootstrap.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+
+subdirs="compiler lib/cpp lib/php"
+
+rm -rf \
+AUTHORS \
+COPYING \
+ChangeLog \
+INSTALL \
+Makefile.am \
+Makefile \
+Makefile.in \
+Makefile.orig \
+NEWS \
+README \
+aclocal.m4 \
+autom4te.cache \
+autoscan.log \
+config.guess \
+config.h \
+config.hin \
+config.log \
+config.status \
+config.sub \
+configure \
+configure.scan \
+depcomp \
+.deps \
+install-sh \
+.libs \
+libtool \
+ltmain.sh \
+Makefile.in \
+missing
+
+echo "SUBDIRS = ${subdirs}" > Makefile.am
+
+aclocal
+touch NEWS README AUTHORS ChangeLog
+autoconf
+automake -ac
+
+for subdir in ${subdirs}; do 
+    if [ -x "${subdir}/bootstrap.sh" ]; then 
+	cwd="`pwd`"
+	cd ${subdir}
+	./bootstrap.sh
+	cd ${cwd}
+    fi
+done
+
diff --git a/compiler/Makefile.am b/compiler/Makefile.am
new file mode 100644
index 0000000..8b84d0a
--- /dev/null
+++ b/compiler/Makefile.am
@@ -0,0 +1,2 @@
+install-exec-hook:
+	$(PYTHON) setup.py install install_scripts --install-dir=$(bindir)
diff --git a/compiler/bootstrap.sh b/compiler/bootstrap.sh
new file mode 100755
index 0000000..11f41a9
--- /dev/null
+++ b/compiler/bootstrap.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+rm -rf \
+AUTHORS \
+COPYING \
+ChangeLog \
+INSTALL \
+Makefile \
+Makefile.in \
+Makefile.orig \
+NEWS \
+README \
+aclocal.m4 \
+autom4te.cache \
+autoscan.log \
+config.guess \
+config.h \
+config.hin \
+config.log \
+config.status \
+config.sub \
+configure \
+configure.scan \
+depcomp \
+.deps \
+install-sh \
+.libs \
+libtool \
+ltmain.sh \
+Makefile.in \
+missing
+
+aclocal
+touch NEWS README AUTHORS ChangeLog
+autoconf
+automake -ac
diff --git a/compiler/configure.ac b/compiler/configure.ac
new file mode 100644
index 0000000..dcc7bf2
--- /dev/null
+++ b/compiler/configure.ac
@@ -0,0 +1,13 @@
+AC_PREREQ(2.59)
+
+AC_INIT([compiler], [1.0])
+
+AC_CONFIG_AUX_DIR([.])
+
+AM_INIT_AUTOMAKE
+
+AM_PATH_PYTHON(2.4,, :)
+
+AC_CONFIG_FILES([Makefile])
+
+AC_OUTPUT
diff --git a/compiler/Makefile b/compiler/cpp.mk
similarity index 100%
rename from compiler/Makefile
rename to compiler/cpp.mk
diff --git a/compiler/src/cpp_generator.py b/compiler/src/cpp_generator.py
index ba3380e..97a5f36 100644
--- a/compiler/src/cpp_generator.py
+++ b/compiler/src/cpp_generator.py
@@ -871,15 +871,22 @@
    ${keyType} key;
    ${valueType} elem;
    uint32_t xfer = 0;
+   """+CPP_PROTOCOL_TTYPE+""" keyType;
+   """+CPP_PROTOCOL_TTYPE+""" valueType;
 
-   xfer += iprot->readU32(itrans, count);
+   xfer += iprot->readMapBegin(itrans, keyType, valueType, count);
 
+   /* XXX
+      Should we assert that read key and value type are correct? */
+   
    for(uint32_t ix = 0; ix < count; ix++) {
        ${keyReaderCall};
        ${valueReaderCall};
        value.insert(std::make_pair(key, elem));
    }
 
+   xfer += iprot->readMapEnd(itrans);
+
    return xfer;
 }
 """)
@@ -889,12 +896,14 @@
 
    uint32_t xfer = 0;
 
-   xfer += oprot->writeU32(otrans, value.size());
+   xfer += oprot->writeMapBegin(otrans, ${keyWireType}, ${valueWireType}, value.size());
 
    for(${declaration}::const_iterator ix = value.begin(); ix != value.end(); ++ix) {
        ${keyWriterCall};
        ${valueWriterCall};
    }
+
+   xfer += oprot->writeMapEnd(otrans);
    return xfer;
 }
 """)
@@ -905,6 +914,12 @@
    uint32_t count;
    ${valueType} elem;
    uint32_t xfer = 0;
+   """+CPP_PROTOCOL_TTYPE+""" valueType;
+
+   xfer += iprot->read${protocolSuffix}Begin(itrans, valueType, count);
+
+   /* XXX
+      Should we assert that read value type is correct? */
 
    xfer+= iprot->readU32(itrans,  count);
 
@@ -912,6 +927,8 @@
        ${valueReaderCall};
        value.${insert}(elem);
    }
+
+   xfer += iprot->read${protocolSuffix}End(itrans);
    return xfer;
 }
 """)
@@ -921,11 +938,14 @@
 
    uint32_t xfer = 0;
 
-   xfer+= oprot->writeU32(otrans, value.size());
+   xfer+= oprot->write${protocolSuffix}Begin(otrans, ${valueWireType}, value.size());
 
    for(${declaration}::const_iterator ix = value.begin(); ix != value.end(); ++ix) {
        ${valueWriterCall};
    }
+
+   xfer+= oprot->write${protocolSuffix}End(otrans);
+
    return xfer;
 }
 """)
@@ -949,11 +969,14 @@
 
     else:
 	if isinstance(collection, ListType):
+	    protocolSuffix="List"
 	    insert="push_back"
 	else:
+	    protocolSuffix="Set"
 	    insert="insert"
 
         return CPP_READ_LIST_DEFINITION.substitute(suffix=suffix, declaration=toCTypeDeclaration(collection),
+						   protocolSuffix=protocolSuffix,
                                                    valueReaderCall=valueReaderCall,
                                                    valueType=toCTypeDeclaration(collection.valueType),
 						   insert=insert)
@@ -966,22 +989,36 @@
 
     if isinstance(collection, MapType):
         keyWriterCall = toWriterCall("ix->first", collection.keyType)
+	keyWireType = toWireType(collection.keyType)
         valueWriterCall = toWriterCall("ix->second", collection.valueType)
 
     else:
 	valueWriterCall= toWriterCall("*ix", collection.valueType)
 
+    valueWireType = toWireType(collection.valueType)
+
     if isinstance(collection, MapType):
         return CPP_WRITE_MAP_DEFINITION.substitute(suffix=suffix, declaration=toCTypeDeclaration(collection),
-                                                  keyType=toCTypeDeclaration(collection.keyType),
-                                                  keyWriterCall=keyWriterCall,
-                                                  valueType=toCTypeDeclaration(collection.valueType),
-                                                  valueWriterCall=valueWriterCall)
+						   keyType=toCTypeDeclaration(collection.keyType),
+						   keyWireType=keyWireType,
+						   keyWriterCall=keyWriterCall,
+						   valueType=toCTypeDeclaration(collection.valueType),
+						   valueWireType=valueWireType,
+						   valueWriterCall=valueWriterCall)
 
     else:
+	if isinstance(collection, ListType):
+	    protocolSuffix = "List"
+	elif isinstance(collection, SetType):
+	    protocolSuffix = "Set"
+	else:
+	    raise Exception, "Unknown collection type "+str(type(collection))+":"+str(collection)
+	    
         return CPP_WRITE_LIST_DEFINITION.substitute(suffix=suffix, declaration=toCTypeDeclaration(collection),
-                                                   valueWriterCall=valueWriterCall,
-                                                   valueType=toCTypeDeclaration(collection.valueType))
+						    protocolSuffix=protocolSuffix,
+						    valueWireType=valueWireType,
+						    valueWriterCall=valueWriterCall,
+						    valueType=toCTypeDeclaration(collection.valueType))
 
 
 CPP_READ_STRUCT_DEFINITION = Template("""
diff --git a/compiler/src/php_generator.py b/compiler/src/php_generator.py
index e68a4f7..71b1fd3 100644
--- a/compiler/src/php_generator.py
+++ b/compiler/src/php_generator.py
@@ -329,8 +329,6 @@
 
         result+= self.toReadStructEnd()
 
-        result+= self.indent()+"return "+value+";\n"
-
         return result
 
     def toReadCollection(self, value, collection):
@@ -631,12 +629,17 @@
 
 	result+= self.indent()+"}\n"
 
+	result+= self.reader.toReadMessageEnd()
+
+	if not isVoidType(function.returnType()):
+	    result+= self.indent()+"return "+resultVar.name+"->success;\n"
+	else:
+	    result+= self.indent()+"return;\n"
+
 	self.indent-= 1
 
 	self.oldScope()
 
-	result+= self.reader.toReadMessageEnd()
-
 	result+= self.indent()+"}\n"
 	
 	return result
diff --git a/compiler/src/thrift b/compiler/src/thrift
index 39bdb16..6c252d9 100644
--- a/compiler/src/thrift
+++ b/compiler/src/thrift
@@ -1,16 +1,20 @@
 #!python
 import sys
-from thrift import cpp_generator
 from thrift import generator
+from thrift import cpp_generator
+from thrift import php_generator
 from thrift import parser
 
-def thrift(source, cpp=False, perl=False, php=False, python=False, java=False, ruby=False, debug=False):
+def thrift(source, cpp=False, java=False, perl=False, php=False, python=False, ruby=False, debug=False):
 
     generators = []
 
     if cpp:
 	generators.append(cpp_generator.CPPGenerator())
     
+    if php:
+	generators.append(php_generator.PHPGenerator())
+    
     p = parser.Parser(debug=debug)
 
     p.parse(source, False)
@@ -37,6 +41,9 @@
     if "--cpp" in args:
 	cpp = True
 	args.remove("--cpp")
+    if "--php" in args:
+	php = True
+	args.remove("--php")
     if "--debug" in args:
 	debug = True
 	args.remove("--debug")
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..54f1960
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,13 @@
+AC_PREREQ(2.59)
+
+AC_INIT([thrift], [1.0])
+
+AC_CONFIG_AUX_DIR([.])
+
+AM_INIT_AUTOMAKE
+
+AC_CONFIG_FILES([Makefile])
+
+AC_CONFIG_SUBDIRS([compiler lib/cpp lib/php])
+
+AC_OUTPUT
diff --git a/lib/cpp/configure.ac b/lib/cpp/configure.ac
index b854ebd..d571ba0 100644
--- a/lib/cpp/configure.ac
+++ b/lib/cpp/configure.ac
@@ -1,6 +1,6 @@
 AC_PREREQ(2.59)
 
-AC_INIT(thrift, 1.0)
+AC_INIT(thriftcpp, 1.0)
 
 AC_CONFIG_SRCDIR(src/Thrift.h)
 
diff --git a/lib/cpp/src/protocol/TBinaryProtocol.cc b/lib/cpp/src/protocol/TBinaryProtocol.cc
index 3cd11ba..f2fbe87 100644
--- a/lib/cpp/src/protocol/TBinaryProtocol.cc
+++ b/lib/cpp/src/protocol/TBinaryProtocol.cc
@@ -48,11 +48,11 @@
 uint32_t TBinaryProtocol::writeMapBegin(shared_ptr<TTransport> out,
                                         const TType keyType,
                                         const TType valType,
-                                        const int32_t size) const {
+                                        const uint32_t size) const {
   return
     writeByte(out, (uint8_t)keyType) +
     writeByte(out, (uint8_t)valType) +
-    writeI32(out, (int32_t)size);
+    writeU32(out, (uint32_t)size);
 }
 
 uint32_t TBinaryProtocol::writeMapEnd(shared_ptr<TTransport> out) const {
@@ -61,10 +61,10 @@
 
 uint32_t TBinaryProtocol::writeListBegin(shared_ptr<TTransport> out,
                                          const TType elemType,
-                                         const int32_t size) const {
+                                         const uint32_t size) const {
   return
     writeByte(out, (uint8_t) elemType) +
-    writeI32(out, (int32_t)size);
+    writeU32(out, (int32_t)size);
 }
 
 uint32_t TBinaryProtocol::writeListEnd(shared_ptr<TTransport> out) const {
@@ -73,10 +73,10 @@
 
 uint32_t TBinaryProtocol::writeSetBegin(shared_ptr<TTransport> out,
                                         const TType elemType,
-                                        const int32_t size) const {
+                                        const uint32_t size) const {
   return
     writeByte(out, (uint8_t)elemType) +
-    writeI32(out, (int32_t)size);
+    writeU32(out, (int32_t)size);
 }
 
 uint32_t TBinaryProtocol::writeSetEnd(shared_ptr<TTransport> out) const {
@@ -200,14 +200,14 @@
 uint32_t TBinaryProtocol::readMapBegin(shared_ptr<TTransport> in,
                                        TType& keyType,
                                        TType& valType,
-                                       int32_t& size) const {
+                                       uint32_t& size) const {
   uint8_t k, v;
   uint32_t result = 0;
   result += readByte(in, k);
   keyType = (TType)k;
   result += readByte(in, v);
   valType = (TType)v;
-  result += readI32(in, size);
+  result += readU32(in, size);
   return result;
 }
 
@@ -217,12 +217,12 @@
 
 uint32_t TBinaryProtocol::readListBegin(shared_ptr<TTransport> in,
                                         TType& elemType,
-                                        int32_t& size) const {
+                                        uint32_t& size) const {
   uint8_t e;
   uint32_t result = 0;
   result += readByte(in, e);
   elemType = (TType)e;
-  result += readI32(in, size);
+  result += readU32(in, size);
   return result;
 }
 
@@ -232,12 +232,12 @@
 
 uint32_t TBinaryProtocol::readSetBegin(shared_ptr<TTransport> in,
                                        TType& elemType,
-                                       int32_t& size) const {
+                                       uint32_t& size) const {
   uint8_t e;
   uint32_t result = 0;
   result += readByte(in, e);
   elemType = (TType)e;
-  result += readI32(in, size);
+  result += readU32(in, size);
   return result;
 }
 
@@ -318,8 +318,8 @@
 uint32_t TBinaryProtocol::readString(shared_ptr<TTransport> in,
                                      string& str) const {
   uint32_t result;
-  int32_t size;
-  result = readI32(in, size);
+  uint32_t size;
+  result = readU32(in, size);
 
   // Use the heap here to prevent stack overflow for v. large strings
   uint8_t *b = new uint8_t[size];
diff --git a/lib/cpp/src/protocol/TBinaryProtocol.h b/lib/cpp/src/protocol/TBinaryProtocol.h
index 480182d..7780f16 100644
--- a/lib/cpp/src/protocol/TBinaryProtocol.h
+++ b/lib/cpp/src/protocol/TBinaryProtocol.h
@@ -49,19 +49,19 @@
   uint32_t writeMapBegin(shared_ptr<TTransport> out,
 			  const TType keyType,
 			  const TType valType,
-			  const int32_t size) const;
+			  const uint32_t size) const;
 
   uint32_t writeMapEnd(shared_ptr<TTransport> out) const;
 
   uint32_t writeListBegin(shared_ptr<TTransport> out,
 			   const TType elemType,
-			   const int32_t size) const;
+			   const uint32_t size) const;
 
   uint32_t writeListEnd(shared_ptr<TTransport> out) const;
 
   uint32_t writeSetBegin(shared_ptr<TTransport> out,
 			  const TType elemType,
-			  const int32_t size) const;
+			  const uint32_t size) const;
 
   uint32_t writeSetEnd(shared_ptr<TTransport> out) const;
 
@@ -119,19 +119,19 @@
   uint32_t readMapBegin(shared_ptr<TTransport> in,
 			 TType& keyType,
 			 TType& valType,
-			 int32_t& size) const;
+			 uint32_t& size) const;
 
   uint32_t readMapEnd(shared_ptr<TTransport> in) const;
 
   uint32_t readListBegin(shared_ptr<TTransport> in,
 			  TType& elemType,
-			  int32_t& size) const;
+			  uint32_t& size) const;
   
   uint32_t readListEnd(shared_ptr<TTransport> in) const;
 
   uint32_t readSetBegin(shared_ptr<TTransport> in,
 			 TType& elemType,
-			 int32_t& size) const;
+			 uint32_t& size) const;
 
   uint32_t readSetEnd(shared_ptr<TTransport> in) const;
 
diff --git a/lib/cpp/src/protocol/TProtocol.h b/lib/cpp/src/protocol/TProtocol.h
index 7dbb4a0..38c5347 100644
--- a/lib/cpp/src/protocol/TProtocol.h
+++ b/lib/cpp/src/protocol/TProtocol.h
@@ -103,19 +103,19 @@
   virtual uint32_t writeMapBegin(shared_ptr<TTransport> out,
 				 const TType keyType,
 				 const TType valType,
-				 const int32_t size) const = 0;
+				 const uint32_t size) const = 0;
 
   virtual uint32_t writeMapEnd(shared_ptr<TTransport> out) const = 0;
   
   virtual uint32_t writeListBegin(shared_ptr<TTransport> out,
 				  const TType elemType,
-				  const int32_t size) const = 0;
+				  const uint32_t size) const = 0;
 
   virtual uint32_t writeListEnd(shared_ptr<TTransport> out) const = 0;
 
   virtual uint32_t writeSetBegin(shared_ptr<TTransport> out,
 				 const TType elemType,
-				 const int32_t size) const = 0;
+				 const uint32_t size) const = 0;
 
   virtual uint32_t writeSetEnd(shared_ptr<TTransport> out) const = 0;
 
@@ -172,19 +172,19 @@
   virtual uint32_t readMapBegin(shared_ptr<TTransport> in,
 				TType& keyType,
 				TType& valType,
-				int32_t& size) const = 0;
+				uint32_t& size) const = 0;
 
   virtual uint32_t readMapEnd(shared_ptr<TTransport> in) const = 0;
 
   virtual uint32_t readListBegin(shared_ptr<TTransport> in,
 				 TType& elemType,
-				 int32_t& size) const = 0;
+				 uint32_t& size) const = 0;
 
   virtual uint32_t readListEnd(shared_ptr<TTransport> in) const = 0;
 
   virtual uint32_t readSetBegin(shared_ptr<TTransport> in,
 				TType& elemType,
-				int32_t& size) const = 0;
+				uint32_t& size) const = 0;
 
   virtual uint32_t readSetEnd(shared_ptr<TTransport> in) const = 0;
 
@@ -273,7 +273,7 @@
         uint32_t result = 0;
         TType keyType;
         TType valType;
-        int32_t i, size;
+        uint32_t i, size;
         result += readMapBegin(in, keyType, valType, size);
         for (i = 0; i < size; i++) {
           result += skip(in, keyType);
@@ -286,7 +286,7 @@
       {
         uint32_t result = 0;
         TType elemType;
-        int32_t i, size;
+        uint32_t i, size;
         result += readSetBegin(in, elemType, size);
         for (i = 0; i < size; i++) {
           result += skip(in, elemType);
@@ -298,7 +298,7 @@
       {
         uint32_t result = 0;
         TType elemType;
-        int32_t i, size;
+        uint32_t i, size;
         result += readListBegin(in, elemType, size);
         for (i = 0; i < size; i++) {
           result += skip(in, elemType);
diff --git a/lib/cpp/src/test/Makefile b/lib/cpp/src/test/Makefile
index 73206cd..9b15095 100644
--- a/lib/cpp/src/test/Makefile
+++ b/lib/cpp/src/test/Makefile
@@ -38,7 +38,7 @@
 debug: stress-test-debug
 
 stubs: StressTest.thrift
-	$(THRIFT) --cpp StressTest.thrift
+	$(THRIFT) --cpp --php StressTest.thrift
 
 stress-test-debug: stubs
 	g++ -o stress-test $(DCFL) main.cc cpp-gen/StressTest.cc
diff --git a/lib/cpp/src/test/StressTest.thrift b/lib/cpp/src/test/StressTest.thrift
index 89e2f9b..3d2f9d8 100644
--- a/lib/cpp/src/test/StressTest.thrift
+++ b/lib/cpp/src/test/StressTest.thrift
@@ -7,5 +7,9 @@
   u16 echoU16(u16 arg),
   u32 echoU32(u32 arg),
   u64 echoU64(u64 arg),
+  string echoString(string arg),
+  list<byte>  echoList(list<byte> arg),
+  set<byte>  echoSet(set<byte> arg),
+  map<byte, byte>  echoMap(map<byte, byte> arg),
 }
 
diff --git a/lib/cpp/src/test/main.cc b/lib/cpp/src/test/main.cc
index 51ac38a..69a6eb0 100644
--- a/lib/cpp/src/test/main.cc
+++ b/lib/cpp/src/test/main.cc
@@ -34,6 +34,10 @@
   uint16_t echoU16(uint16_t arg) {return arg;}
   uint32_t echoU32(uint32_t arg) {return arg;}
   uint64_t echoU64(uint64_t arg) {return arg;}
+  string echoString(string arg) {return arg;}
+  list<uint8_t> echoList(list<uint8_t> arg) {return arg;}
+  set<uint8_t> echoSet(set<uint8_t> arg) {return arg;}
+  map<uint8_t, uint8_t> echoMap(map<uint8_t, uint8_t> arg) {return arg;}
 };
 
 class ClientThread: public Runnable {
@@ -107,17 +111,20 @@
   size_t workerCount = 4;
   size_t clientCount = 10;
   size_t loopCount = 10000;
+  bool runServer = true;
 
-     ostringstream usage;
+  ostringstream usage;
 
   usage <<
-    argv[0] << " [--port=<port number>] [--server-type=<server-type>] [--protocol-type=<protocol-type>] [--workers=<worker-count>]" << endl <<
-
-    "\t\tserver-type\t\ttype of server, \"simple\" or \"thread-pool\".  Default is " << serverType << endl <<
-
-    "\t\tprotocol-type\t\ttype of protocol, \"binary\", \"ascii\", or \"xml\".  Default is " << protocolType << endl <<
-
-    "\t\tworkers\t\tNumber of thread pools workers.  Only valid for thread-pool server type.  Default is " << workerCount << endl;
+    argv[0] << " [--port=<port number>] [--server] [--server-type=<server-type>] [--protocol-type=<protocol-type>] [--workers=<worker-count>] [--clients=<client-count>] [--loop=<loop-count>]" << endl <<
+    "\tclients        Number of client threads to create - 0 implies no clients, i.e. server only.  Default is " << clientCount << endl <<
+    "\thelp           Prints this help text." << endl <<
+    "\tloop           The number of remote thrift calls each client makes.  Default is " << loopCount << endl <<
+    "\tport           The port the server and clients should bind to for thrift network connections.  Default is " << port << endl <<
+    "\tserver         Run the Thrift server in this process.  Default is " << runServer << endl <<
+    "\tserver-type    Type of server, \"simple\" or \"thread-pool\".  Default is " << serverType << endl <<
+    "\tprotocol-type  Type of protocol, \"binary\", \"ascii\", or \"xml\".  Default is " << protocolType << endl <<
+    "\tworkers        Number of thread pools workers.  Only valid for thread-pool server type.  Default is " << workerCount << endl;
     
   map<string, string>  args;
   
@@ -143,10 +150,27 @@
 
   try {
 
+    if(!args["clients"].empty()) {
+      clientCount = atoi(args["clients"].c_str());
+    }
+
+    if(!args["help"].empty()) {
+      cerr << usage.str();
+      return 0;
+    }
+
+    if(!args["loop"].empty()) {
+      loopCount = atoi(args["loop"].c_str());
+    }
+
     if(!args["port"].empty()) {
       port = atoi(args["port"].c_str());
     }
 
+    if(!args["server"].empty()) {
+      runServer = args["server"] == "true";
+    }
+
     if(!args["server-type"].empty()) {
       serverType = args["server-type"];
       
@@ -164,138 +188,141 @@
       workerCount = atoi(args["workers"].c_str());
     }
 
-    if(!args["clients"].empty()) {
-      clientCount = atoi(args["clients"].c_str());
-    }
-
-    if(!args["loop"].empty()) {
-      loopCount = atoi(args["loop"].c_str());
-    }
   } catch(exception& e) {
     cerr << e.what() << endl;
     cerr << usage;
   }
 
-  // Dispatcher
-  shared_ptr<TBinaryProtocol> binaryProtocol(new TBinaryProtocol);
-
-  shared_ptr<Server> server(new Server(binaryProtocol));
-
-  // Options
-  shared_ptr<TServerOptions> serverOptions(new TServerOptions());
-
-  // Transport
-  shared_ptr<TServerSocket> serverSocket(new TServerSocket(port));
-
-  // ThreadFactory
-
   shared_ptr<PosixThreadFactory> threadFactory = shared_ptr<PosixThreadFactory>(new PosixThreadFactory());
 
-  shared_ptr<Thread> serverThread;
+  if(runServer) {
 
-  if(serverType == "simple") {
+    // Dispatcher
+    shared_ptr<TBinaryProtocol> binaryProtocol(new TBinaryProtocol);
 
-    serverThread = threadFactory->newThread(shared_ptr<Runnable>(new TSimpleServer(server, serverOptions, serverSocket)));
+    shared_ptr<Server> server(new Server(binaryProtocol));
 
-  } else if(serverType == "thread-pool") {
+    // Options
+    shared_ptr<TServerOptions> serverOptions(new TServerOptions());
 
-    shared_ptr<ThreadManager> threadManager = ThreadManager::newSimpleThreadManager(workerCount);
+    // Transport
+    shared_ptr<TServerSocket> serverSocket(new TServerSocket(port));
 
-    threadManager->threadFactory(threadFactory);
+    // ThreadFactory
 
-    threadManager->start();
+    shared_ptr<Thread> serverThread;
 
-    serverThread = threadFactory->newThread(shared_ptr<TServer>(new TThreadPoolServer(server,
-										      serverOptions,
-										      serverSocket,
-										      threadManager)));
+    if(serverType == "simple") {
+      
+      serverThread = threadFactory->newThread(shared_ptr<Runnable>(new TSimpleServer(server, serverOptions, serverSocket)));
+      
+    } else if(serverType == "thread-pool") {
+
+      shared_ptr<ThreadManager> threadManager = ThreadManager::newSimpleThreadManager(workerCount);
+
+      threadManager->threadFactory(threadFactory);
+
+      threadManager->start();
+
+      serverThread = threadFactory->newThread(shared_ptr<TServer>(new TThreadPoolServer(server,
+											serverOptions,
+											serverSocket,
+											threadManager)));
+    }
+
+    cerr << "Starting the server on port " << port << endl;
+
+    serverThread->start();
+    
+    // If we aren't running clients, just wait forever for external clients
+
+    if(clientCount == 0) {
+      serverThread->join();
+    }
   }
 
-  cerr << "Starting the server on port " << port << endl;
+  if(clientCount > 0) {
 
-  serverThread->start();
+    Monitor monitor;
 
-  Monitor monitor;
+    size_t threadCount = 0;
 
-  size_t threadCount = 0;
+    set<shared_ptr<Thread> > clientThreads;
 
-  set<shared_ptr<Thread> > clientThreads;
-
-  for(size_t ix = 0; ix < clientCount; ix++) {
+    for(size_t ix = 0; ix < clientCount; ix++) {
     
-    shared_ptr<TSocket> socket(new TSocket("127.0.01", port));
-    shared_ptr<TBufferedTransport> bufferedSocket(new TBufferedTransport(socket, 2048));
-    shared_ptr<TBinaryProtocol> binaryProtocol(new TBinaryProtocol());
-    shared_ptr<ServiceClient> serviceClient(new ServiceClient(bufferedSocket, binaryProtocol));
+      shared_ptr<TSocket> socket(new TSocket("127.0.01", port));
+      shared_ptr<TBufferedTransport> bufferedSocket(new TBufferedTransport(socket, 2048));
+      shared_ptr<TBinaryProtocol> binaryProtocol(new TBinaryProtocol());
+      shared_ptr<ServiceClient> serviceClient(new ServiceClient(bufferedSocket, binaryProtocol));
     
-    clientThreads.insert(threadFactory->newThread(shared_ptr<ClientThread>(new ClientThread(bufferedSocket, serviceClient, monitor, threadCount, loopCount))));
-  }
+      clientThreads.insert(threadFactory->newThread(shared_ptr<ClientThread>(new ClientThread(bufferedSocket, serviceClient, monitor, threadCount, loopCount))));
+    }
   
-  for(std::set<shared_ptr<Thread> >::const_iterator thread = clientThreads.begin(); thread != clientThreads.end(); thread++) {
-    (*thread)->start();
-  }
+    for(std::set<shared_ptr<Thread> >::const_iterator thread = clientThreads.begin(); thread != clientThreads.end(); thread++) {
+      (*thread)->start();
+    }
 
-  cerr << endl;
-
-  long long time00;
-  long long time01;
+    long long time00;
+    long long time01;
   
-  {Synchronized s(monitor);
-    threadCount = clientCount;
+    {Synchronized s(monitor);
+      threadCount = clientCount;
     
-    cerr << "Launch "<< clientCount << " client threads" << endl;
+      cerr << "Launch "<< clientCount << " client threads" << endl;
     
-    time00 =  Util::currentTime();
+      time00 =  Util::currentTime();
     
-    monitor.notifyAll();
+      monitor.notifyAll();
+      
+      while(threadCount > 0) {
+	monitor.wait();
+      }
     
-    while(threadCount > 0) {
-      monitor.wait();
+      time01 =  Util::currentTime();
     }
-    
-    time01 =  Util::currentTime();
-  }
   
-  long long firstTime = 9223372036854775807LL;
-  long long lastTime = 0;
+    long long firstTime = 9223372036854775807LL;
+    long long lastTime = 0;
 
-  double averageTime = 0;
-  long long minTime = 9223372036854775807LL;
-  long long maxTime = 0;
+    double averageTime = 0;
+    long long minTime = 9223372036854775807LL;
+    long long maxTime = 0;
   
-  for(set<shared_ptr<Thread> >::iterator ix = clientThreads.begin(); ix != clientThreads.end(); ix++) {
+    for(set<shared_ptr<Thread> >::iterator ix = clientThreads.begin(); ix != clientThreads.end(); ix++) {
       
-    shared_ptr<ClientThread> client = dynamic_pointer_cast<ClientThread>((*ix)->runnable());
+      shared_ptr<ClientThread> client = dynamic_pointer_cast<ClientThread>((*ix)->runnable());
       
-    long long delta = client->_endTime - client->_startTime;
+      long long delta = client->_endTime - client->_startTime;
       
-    assert(delta > 0);
+      assert(delta > 0);
 
-    if(client->_startTime < firstTime) {
-      firstTime = client->_startTime;
-    }
+      if(client->_startTime < firstTime) {
+	firstTime = client->_startTime;
+      }
       
-    if(client->_endTime > lastTime) {
-      lastTime = client->_endTime;
-    }
+      if(client->_endTime > lastTime) {
+	lastTime = client->_endTime;
+      }
       
-    if(delta < minTime) {
-      minTime = delta;
-    }
+      if(delta < minTime) {
+	minTime = delta;
+      }
       
-    if(delta > maxTime) {
-      maxTime = delta;
-    }
+      if(delta > maxTime) {
+	maxTime = delta;
+      }
       
-    averageTime+= delta;
+      averageTime+= delta;
+    }
+    
+    averageTime /= clientCount;
+    
+    
+    cout <<  "workers :" << workerCount << ", client : " << clientCount << ", loops : " << loopCount << ", rate : " << (clientCount * loopCount * 1000) / ((double)(time01 - time00)) << endl;
+    
+    cerr << "done." << endl;
   }
-    
-  averageTime /= clientCount;
-    
-
-  cout <<  "workers :" << workerCount << ", client : " << clientCount << ", loops : " << loopCount << ", rate : " << (clientCount * loopCount * 1000) / ((double)(time01 - time00)) << endl;
-    
-  cerr << "done." << endl;
 
   return 0;
 }
diff --git a/lib/php/Makefile.am b/lib/php/Makefile.am
new file mode 100644
index 0000000..23208d9
--- /dev/null
+++ b/lib/php/Makefile.am
@@ -0,0 +1,17 @@
+thrift_SCRIPTS = src/Thrift.php
+
+protocol_SCRIPTS = src/protocol/TProtocol.php \
+                   src/protocol/TBinaryProtocol.php \
+                   src/protocol/TType.php
+
+transport_SCRIPTS = src/transport/TTransport.php \
+                    src/transport/TBufferedTransport.php \
+                    src/transport/TChunkedTransport.php \
+                    src/transport/TSocket.php
+
+thriftdir = $(prefix)/php/thrift
+
+protocoldir = $(thriftdir)/protocol
+
+transportdir = $(thriftdir)/transport
+
diff --git a/lib/php/bootstrap.sh b/lib/php/bootstrap.sh
new file mode 100755
index 0000000..11f41a9
--- /dev/null
+++ b/lib/php/bootstrap.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+rm -rf \
+AUTHORS \
+COPYING \
+ChangeLog \
+INSTALL \
+Makefile \
+Makefile.in \
+Makefile.orig \
+NEWS \
+README \
+aclocal.m4 \
+autom4te.cache \
+autoscan.log \
+config.guess \
+config.h \
+config.hin \
+config.log \
+config.status \
+config.sub \
+configure \
+configure.scan \
+depcomp \
+.deps \
+install-sh \
+.libs \
+libtool \
+ltmain.sh \
+Makefile.in \
+missing
+
+aclocal
+touch NEWS README AUTHORS ChangeLog
+autoconf
+automake -ac
diff --git a/lib/php/configure.ac b/lib/php/configure.ac
new file mode 100644
index 0000000..d32321e
--- /dev/null
+++ b/lib/php/configure.ac
@@ -0,0 +1,11 @@
+AC_PREREQ(2.59)
+
+AC_INIT([thriftphp], [1.0])
+
+AC_CONFIG_AUX_DIR([.])
+
+AM_INIT_AUTOMAKE
+
+AC_CONFIG_FILES([Makefile])
+
+AC_OUTPUT
diff --git a/test/cpp/Makefile b/test/cpp/Makefile
index cec9699..f95401c 100644
--- a/test/cpp/Makefile
+++ b/test/cpp/Makefile
@@ -22,7 +22,10 @@
 include_flags = $(patsubst %,-I%, $(include_paths))
 
 # Tools
-THRIFT = python ../../compiler/src/thrift.py ~/ws/thrift/dev/test/ThriftTest.thrift
+ifndef THRIFT
+THRIFT = thrift
+endif # THRIFT
+
 CC     = g++
 LD     = g++