diff --git a/README.md b/README.md index e971816..0d7fd8f 100644 --- a/README.md +++ b/README.md @@ -129,9 +129,9 @@ Key files and folders contained in this repository: ## Versions -The current release of hxzmq is 1.4.0, compatable with libzmq-2.1.4 or any later 2.1.x version (latest tested in 2.1.8). The latest released hxzmq package shall also be available in the [haxelib repository] [4], accessable via the [haxelib tool] [5] which is included in the standard haXe distribution. +The current release of hxzmq on the master branch is compatable with libzmq-3.1.0 or any later 3.1.x version (latest tested in 3.1.0). The latest released hxzmq package shall also be available in the [haxelib repository] [4], accessable via the [haxelib tool] [5] which is included in the standard haXe distribution. -This version of hxzmq has also been tested against [php-zmq v0.7.0] [13] +A version of hxzmq compatable with the libzmq 2.1.x version is archived on the 2.1.x branch of the hxzmq git repository. ## Building and Installation diff --git a/build.xml b/build.xml index 7525b2f..590a76e 100644 --- a/build.xml +++ b/build.xml @@ -9,7 +9,7 @@ - + @@ -17,10 +17,10 @@ - + - + diff --git a/haxelib.xml b/haxelib.xml index 7c912e4..dfbddbf 100644 --- a/haxelib.xml +++ b/haxelib.xml @@ -5,5 +5,5 @@ Haxe language binding for the ZeroMQ socket library - Re-built ndll against v2.1.8 of the libzmq library + Added experimental support for ZMQ v3.x.x diff --git a/ndll/Linux/hxzmq.ndll b/ndll/Linux/hxzmq.ndll index 04a29a2..9456304 100755 Binary files a/ndll/Linux/hxzmq.ndll and b/ndll/Linux/hxzmq.ndll differ diff --git a/ndll/Mac64/hxzmq.ndll b/ndll/Mac64/hxzmq.ndll index 9f37e9e..5c93575 100755 Binary files a/ndll/Mac64/hxzmq.ndll and b/ndll/Mac64/hxzmq.ndll differ diff --git a/ndll/Windows/hxzmq.ndll b/ndll/Windows/hxzmq.ndll index 1f63813..dd2ea97 100644 Binary files a/ndll/Windows/hxzmq.ndll and b/ndll/Windows/hxzmq.ndll differ diff --git a/org/zeromq/ZLoop.hx b/org/zeromq/ZLoop.hx index 66696a0..b7c874d 100644 --- a/org/zeromq/ZLoop.hx +++ b/org/zeromq/ZLoop.hx @@ -208,7 +208,7 @@ class ZLoop rebuildPollset(); } try { - rc = poller.poll(ticklessTimer() * 1000); + rc = poller.poll(ticklessTimer() * ZMQ.ZMQ_POLL_MSEC()); } catch (e:ZMQException) { #if !php if (ZMQ.isInterrupted()) { diff --git a/org/zeromq/ZMQ.hx b/org/zeromq/ZMQ.hx index eaeb5c6..b0f870e 100644 --- a/org/zeromq/ZMQ.hx +++ b/org/zeromq/ZMQ.hx @@ -33,10 +33,12 @@ enum SocketType { ZMQ_SUB; ZMQ_REQ; ZMQ_REP; - ZMQ_ROUTER; // Replaces XREQ in 2.1.4 - ZMQ_DEALER; // Replaces XREP in 2.1.4 + ZMQ_ROUTER; + ZMQ_DEALER; ZMQ_PULL; ZMQ_PUSH; + ZMQ_XPUB; + ZMQ_XSUB; } /** @@ -75,16 +77,20 @@ enum SendReceiveFlagType { * See: http://api.zeromq.org/master:zmq-setsockopt */ enum SocketOptionsType { - ZMQ_HWM; // Set high water mark - ZMQ_SWAP; // Set disk offload size + + ZMQ_SNDHWM; // Set send buffer high water mark + ZMQ_RCVHWM; // Set receive buffer high water mark + ZMQ_MAXMSGSIZE; // Limits the size of the inbound message + ZMQ_MULTICAST_HOPS; // Sets the time-to-live field in every multicast packet sent from this socket + ZMQ_RCVTIMEO; // Sets the timeout for receive operation on the socket (msecs) + ZMQ_SNDTIMEO; // Sets the timeout for send operation on the socket (msecs) + ZMQ_HWM; // Set high water mark (eumulated in ZMQ v3+) ZMQ_AFFINITY; // Set I/O thread affinity ZMQ_IDENTITY; // Set socket identity ZMQ_SUBSCRIBE; // Establish message filter ZMQ_UNSUBSCRIBE; // Remove message filter ZMQ_RATE; // Set multicast data rate ZMQ_RECOVERY_IVL; // Set multicast recovery interval - ZMQ_RECOVERY_IVL_MSEC; // Set multicast recovery interval in milliseconds - ZMQ_MCAST_LOOP; // Control multicast loop-back ZMQ_SNDBUF; // Set kernel transmit buffer size ZMQ_RCVBUF; // Set kernel receive buffer size ZMQ_LINGER; // Set linger period for socket shutdown @@ -95,12 +101,7 @@ enum SocketOptionsType { ZMQ_FD; // Retrieve file descriptor associated with the socket ZMQ_EVENTS; // Retrieve socket event state (bitmask use ZMQ_POLLIN and ZMQ_POLLOUT) ZMQ_TYPE; // Retrieves type of socket -} -enum DeviceType { - ZMQ_QUEUE; - ZMQ_FORWARDER; - ZMQ_STREAMER; } /** @@ -116,29 +117,32 @@ class ZMQ { // Values for flags in ZMQSocket's send and recv functions. public static var bytesSocketOptionTypes:Array = [ - ZMQ_IDENTITY, ZMQ_SUBSCRIBE, - ZMQ_UNSUBSCRIBE + ZMQ_UNSUBSCRIBE, + ZMQ_IDENTITY ]; public static var int64SocketOptionTypes:Array = [ + ZMQ_MAXMSGSIZE, + ZMQ_AFFINITY + ]; + + public static var intSocketOptionTypes:Array = + [ + ZMQ_SNDHWM, + ZMQ_RCVHWM, + ZMQ_MULTICAST_HOPS, + ZMQ_RCVTIMEO, + ZMQ_SNDTIMEO, ZMQ_HWM, - ZMQ_SWAP, - ZMQ_AFFINITY, ZMQ_RATE, ZMQ_RECOVERY_IVL, - ZMQ_RECOVERY_IVL_MSEC, - ZMQ_MCAST_LOOP, ZMQ_SNDBUF, ZMQ_RCVBUF, - ZMQ_RCVMORE - ]; - - public static var intSocketOptionTypes:Array = - [ - ZMQ_LINGER, + ZMQ_RCVMORE, ZMQ_RECONNECT_IVL, ZMQ_RECONNECT_IVL_MAX, + ZMQ_LINGER, ZMQ_BACKLOG, ZMQ_FD, // Only int on POSIX systems ZMQ_EVENTS, @@ -159,6 +163,12 @@ class ZMQ { return _hx_zmq_ZMQ_POLLERR(); } + // Multiplying factor for Poller.poll() method calls to handle + // units change in ZMQ3 from microsecs to millisecs + public static inline function ZMQ_POLL_MSEC():Int { + return _hx_zmq_ZMQ_POLL_MSEC(); + } + /** * Gets complete 0MQ library version * @return 0MQ library version in form MMmmpp (MM=major, mm=minor, pp=patch) @@ -248,6 +258,10 @@ class ZMQ { _hx_zmq_ZMQ_PULL(); case ZMQ_PUSH: _hx_zmq_ZMQ_PUSH(); + case ZMQ_XPUB: + _hx_zmq_ZMQ_XPUB(); + case ZMQ_XSUB: + _hx_zmq_ZMQ_XSUB(); default: null; } @@ -262,12 +276,20 @@ class ZMQ { public static function socketOptionTypeNo(option:SocketOptionsType):Int { return { switch(option) { + case ZMQ_SNDHWM: + _hx_zmq_ZMQ_SNDHWM(); + case ZMQ_RCVHWM: + _hx_zmq_ZMQ_RCVHWM(); + case ZMQ_MAXMSGSIZE: + _hx_zmq_ZMQ_MAXMSGSIZE(); + case ZMQ_MULTICAST_HOPS: + _hx_zmq_ZMQ_MULTICAST_HOPS(); + case ZMQ_SNDTIMEO: + _hx_zmq_ZMQ_SNDTIMEO(); + case ZMQ_RCVTIMEO: + _hx_zmq_ZMQ_RCVTIMEO(); case ZMQ_LINGER: _hx_zmq_ZMQ_LINGER(); - case ZMQ_HWM: - _hx_zmq_ZMQ_HWM(); - case ZMQ_SWAP: - _hx_zmq_ZMQ_SWAP(); case ZMQ_AFFINITY: _hx_zmq_ZMQ_AFFINITY(); case ZMQ_IDENTITY: @@ -280,10 +302,6 @@ class ZMQ { _hx_zmq_ZMQ_RATE(); case ZMQ_RECOVERY_IVL: _hx_zmq_ZMQ_RECOVERY_IVL(); - case ZMQ_RECOVERY_IVL_MSEC: - _hx_zmq_ZMQ_RECOVERY_IVL_MSEC(); - case ZMQ_MCAST_LOOP: - _hx_zmq_ZMQ_MCAST_LOOP(); case ZMQ_SNDBUF: _hx_zmq_ZMQ_SNDBUF(); case ZMQ_RCVBUF: @@ -419,27 +437,6 @@ class ZMQ { } } - /** - * Converts a ZMQ DeviceType enum value into underlying device number. - * Used for call to zmq_device - * @param device - * @return - */ - public static function deviceTypeToDevice(device: DeviceType):Int { - return { - switch (device) { - case ZMQ_QUEUE: - _hx_zmq_ZMQ_QUEUE(); - case ZMQ_FORWARDER: - _hx_zmq_ZMQ_FORWARDER(); - case ZMQ_STREAMER: - _hx_zmq_ZMQ_STREAMER(); - default: - 0; - } - } - } - /** * Sets up interrupt signal handling. * Use isInterrupted() to subsequently test for interruption @@ -472,6 +469,10 @@ class ZMQ { private static var _hx_zmq_catch_signals = Lib.load("hxzmq", "hx_zmq_catch_signals", 0); private static var _hx_zmq_interrupted = Lib.load("hxzmq", "hx_zmq_interrupted", 0); + private static var _hx_zmq_ZMQ_POLL_MSEC = Lib.load("hxzmq", "hx_zmq_ZMQ_POLL_MSEC", 0); + #end + + #if (neko || cpp) private static var _hx_zmq_ZMQ_PUB = Lib.load("hxzmq", "hx_zmq_ZMQ_PUB", 0); private static var _hx_zmq_ZMQ_SUB = Lib.load("hxzmq", "hx_zmq_ZMQ_SUB", 0); private static var _hx_zmq_ZMQ_PAIR = Lib.load("hxzmq", "hx_zmq_ZMQ_PAIR", 0); @@ -481,20 +482,29 @@ class ZMQ { private static var _hx_zmq_ZMQ_ROUTER = Lib.load("hxzmq", "hx_zmq_ZMQ_ROUTER", 0); private static var _hx_zmq_ZMQ_PULL = Lib.load("hxzmq", "hx_zmq_ZMQ_PULL", 0); private static var _hx_zmq_ZMQ_PUSH = Lib.load("hxzmq", "hx_zmq_ZMQ_PUSH", 0); + private static var _hx_zmq_ZMQ_XREQ = Lib.load("hxzmq", "hx_zmq_ZMQ_XREQ", 0); + private static var _hx_zmq_ZMQ_XREP = Lib.load("hxzmq", "hx_zmq_ZMQ_XREP", 0); + private static var _hx_zmq_ZMQ_XPUB = Lib.load("hxzmq", "hx_zmq_ZMQ_XPUB", 0); + private static var _hx_zmq_ZMQ_XSUB = Lib.load("hxzmq", "hx_zmq_ZMQ_XSUB", 0); + + private static var _hx_zmq_ZMQ_SNDHWM = Lib.load("hxzmq", "hx_zmq_ZMQ_SNDHWM", 0); + private static var _hx_zmq_ZMQ_RCVHWM = Lib.load("hxzmq", "hx_zmq_ZMQ_RCVHWM", 0); + private static var _hx_zmq_ZMQ_MAXMSGSIZE = Lib.load("hxzmq", "hx_zmq_ZMQ_MAXMSGSIZE", 0); + private static var _hx_zmq_ZMQ_MULTICAST_HOPS = Lib.load("hxzmq", "hx_zmq_ZMQ_MULTICAST_HOPS", 0); + private static var _hx_zmq_ZMQ_SNDTIMEO = Lib.load("hxzmq", "hx_zmq_ZMQ_SNDTIMEO", 0); + private static var _hx_zmq_ZMQ_RCVTIMEO = Lib.load("hxzmq", "hx_zmq_ZMQ_RCVTIMEO", 0); + #end + +#if (neko || cpp) private static var _hx_zmq_ZMQ_LINGER = Lib.load("hxzmq", "hx_zmq_ZMQ_LINGER", 0); - private static var _hx_zmq_ZMQ_HWM = Lib.load("hxzmq", "hx_zmq_ZMQ_HWM", 0); private static var _hx_zmq_ZMQ_RCVMORE = Lib.load("hxzmq", "hx_zmq_ZMQ_RCVMORE", 0); private static var _hx_zmq_ZMQ_SUBSCRIBE = Lib.load("hxzmq", "hx_zmq_ZMQ_SUBSCRIBE", 0); private static var _hx_zmq_ZMQ_UNSUBSCRIBE = Lib.load("hxzmq", "hx_zmq_ZMQ_UNSUBSCRIBE", 0); - private static var _hx_zmq_ZMQ_SWAP = Lib.load("hxzmq", "hx_zmq_ZMQ_SWAP", 0); private static var _hx_zmq_ZMQ_AFFINITY = Lib.load("hxzmq", "hx_zmq_ZMQ_AFFINITY", 0); private static var _hx_zmq_ZMQ_IDENTITY = Lib.load("hxzmq", "hx_zmq_ZMQ_IDENTITY", 0); - private static var _hx_zmq_ZMQ_RATE = Lib.load("hxzmq", "hx_zmq_ZMQ_RATE", 0); private static var _hx_zmq_ZMQ_RECOVERY_IVL = Lib.load("hxzmq", "hx_zmq_ZMQ_RECOVERY_IVL", 0); - private static var _hx_zmq_ZMQ_RECOVERY_IVL_MSEC = Lib.load("hxzmq", "hx_zmq_ZMQ_RECOVERY_IVL_MSEC", 0); - private static var _hx_zmq_ZMQ_MCAST_LOOP = Lib.load("hxzmq", "hx_zmq_ZMQ_MCAST_LOOP", 0); private static var _hx_zmq_ZMQ_SNDBUF = Lib.load("hxzmq", "hx_zmq_ZMQ_SNDBUF", 0); private static var _hx_zmq_ZMQ_RCVBUF = Lib.load("hxzmq", "hx_zmq_ZMQ_RCVBUF", 0); private static var _hx_zmq_ZMQ_RECONNECT_IVL = Lib.load("hxzmq", "hx_zmq_ZMQ_RECONNECT_IVL", 0); @@ -503,7 +513,7 @@ class ZMQ { private static var _hx_zmq_ZMQ_FD = Lib.load("hxzmq", "hx_zmq_ZMQ_FD", 0); private static var _hx_zmq_ZMQ_EVENTS = Lib.load("hxzmq", "hx_zmq_ZMQ_EVENTS", 0); private static var _hx_zmq_ZMQ_TYPE = Lib.load("hxzmq", "hx_zmq_ZMQ_TYPE", 0); - + private static var _hx_zmq_ZMQ_POLLIN = Lib.load("hxzmq", "hx_zmq_ZMQ_POLLIN", 0); private static var _hx_zmq_ZMQ_POLLOUT = Lib.load("hxzmq", "hx_zmq_ZMQ_POLLOUT", 0); private static var _hx_zmq_ZMQ_POLLERR = Lib.load("hxzmq", "hx_zmq_ZMQ_POLLERR", 0); @@ -527,12 +537,10 @@ class ZMQ { private static var _hx_zmq_EFSM = Lib.load("hxzmq", "hx_zmq_EFSM", 0); private static var _hx_zmq_ENOCOMPATPROTO = Lib.load("hxzmq", "hx_zmq_ENOCOMPATPROTO", 0); private static var _hx_zmq_ETERM = Lib.load("hxzmq", "hx_zmq_ETERM", 0); - - private static var _hx_zmq_ZMQ_QUEUE = Lib.load("hxzmq", "hx_zmq_ZMQ_QUEUE", 0); - private static var _hx_zmq_ZMQ_FORWARDER = Lib.load("hxzmq", "hx_zmq_ZMQ_FORWARDER", 0); - private static var _hx_zmq_ZMQ_STREAMER = Lib.load("hxzmq", "hx_zmq_ZMQ_STREAMER", 0); - - #elseif php +#end + + +#if php // Load functions and constants from php-zmq @@ -583,6 +591,14 @@ class ZMQ { private static function _hx_zmq_ZMQ_PULL():Int {return untyped __php__('ZMQ::SOCKET_PULL');} private static function _hx_zmq_ZMQ_PUSH():Int {return untyped __php__('ZMQ::SOCKET_PUSH');} + // TODO: Replace stubs with ZMQ3 PHP bindings + private static var _hx_zmq_ZMQ_SNDHWM():Int {return untyped __php__('ZMQ::SOCKET_PUB');}; + private static var _hx_zmq_ZMQ_RCVHWM():Int {return untyped __php__('ZMQ::SOCKET_PUB');}; + private static var _hx_zmq_ZMQ_MAXMSGSIZE():Int {return untyped __php__('ZMQ::SOCKET_PUB');}; + private static var _hx_zmq_ZMQ_MULTICAST_HOPS():Int {return untyped __php__('ZMQ::SOCKET_PUB');}; + private static var _hx_zmq_ZMQ_SNDTIMEO():Int {return untyped __php__('ZMQ::SOCKET_PUB');}; + private static var _hx_zmq_ZMQ_RCVTIMEO():Int {return untyped __php__('ZMQ::SOCKET_PUB');}; + private static function _hx_zmq_ZMQ_LINGER():Int {return untyped __php__('ZMQ::SOCKOPT_LINGER');} private static function _hx_zmq_ZMQ_HWM():Int {return untyped __php__('ZMQ::SOCKOPT_HWM');} @@ -655,6 +671,6 @@ class ZMQ { private static inline function _hx_zmq_ZMQ_FORWARDER():Int { return untyped __php__('ZMQ::DEVICE_FORWARDER'); } private static inline function _hx_zmq_ZMQ_STREAMER():Int { return untyped __php__('ZMQ::DEVICE_STREAMER'); } - #end +#end } diff --git a/org/zeromq/ZMQDevice.hx b/org/zeromq/ZMQDevice.hx index d7e3352..3c3d09d 100644 --- a/org/zeromq/ZMQDevice.hx +++ b/org/zeromq/ZMQDevice.hx @@ -25,50 +25,15 @@ import org.zeromq.ZMQ; /** * Wraps ZMQ zmq_device method call. - * Creates in-built ZMQ devices that run in the current thread of execution + * Creates in-built ZMQ devices that run in the current thread of execution. + * + * DEPRECATED in 3.1.x branch */ + class ZMQDevice { - - /** - * Constructor. - * Creates a new ZMQ device and immediately starts its in-built loop. - * Will continue unless process is interrupted, when it returns a ETERM ZMQ_Exception. - * @param type A valid DeviceType - * @param frontend Front end socket, bound or connected to by clients - * @param backend Back end socket, bound or connected to workers - */ - public function new(type:DeviceType, frontend:ZMQSocket, backend:ZMQSocket) - { - if (frontend == null || frontend.closed) { - throw new ZMQException(EINVAL); - } - if (backend == null || backend.closed) { - throw new ZMQException(EINVAL); - } - if (type == null) { - throw new ZMQException(EINVAL); - } -#if (neko || cpp) - try { - // This will continue to execute until current thread or process is terminated - var rc = _hx_zmq_device(ZMQ.deviceTypeToDevice(type), frontend._socketHandle, backend._socketHandle); - } catch (e:Int) { - throw new ZMQException(ZMQ.errNoToErrorType(e)); - } catch (e:Dynamic) { - Lib.rethrow(e); - } -#elseif php - var _typenum = ZMQ.deviceTypeToDevice(type); - var _frontend_handle = frontend._socketHandle; - var _backend_handle = backend._socketHandle; - var r = untyped __php__('new ZMQDevice($_typenum, $_frontend_handle, $_backend_handle)'); -#end - + public function new() { + throw new ZMQException(ENOTSUP); } -#if (neko || cpp) - private static var _hx_zmq_device = Lib.load("hxzmq", "hx_zmq_device", 3); - -#end } \ No newline at end of file diff --git a/org/zeromq/ZMQSocket.hx b/org/zeromq/ZMQSocket.hx index 58b798d..b39a543 100644 --- a/org/zeromq/ZMQSocket.hx +++ b/org/zeromq/ZMQSocket.hx @@ -443,11 +443,9 @@ class ZMQSocket public function hasReceiveMore():Bool { if (_socketHandle == null || closed) return false; var r = getsockopt(ZMQ_RCVMORE); -#if (neko || cpp) - return (r != null && r.lo == 1); -#elseif php + // In ZMQ 3+, RCVMORE is now an int value, not int64 return (r != null && r == 1); -#end + } /** diff --git a/org/zeromq/ZThread.hx b/org/zeromq/ZThread.hx index ba31368..d6f0c69 100644 --- a/org/zeromq/ZThread.hx +++ b/org/zeromq/ZThread.hx @@ -74,7 +74,8 @@ untyped __php__(' var pipe = ctx.createSocket(ZMQ_PAIR); if (pipe == null) return null; - pipe.setsockopt(ZMQ_HWM, { hi:0, lo:1 } ); + pipe.setsockopt(ZMQ_SNDHWM, 1); + pipe.setsockopt(ZMQ_RCVHWM, 1); var uuid = generateuuid(8); var pipeUUID = bytesToHex(uuid); // Creates a 16char uuidstring, based on a 8-byte uuid @@ -83,7 +84,8 @@ untyped __php__(' var forkCtx = ZContext.shadow(ctx); forkCtx.main = false; var forkPipe = forkCtx.createSocket(ZMQ_PAIR); - forkPipe.setsockopt(ZMQ_HWM, { hi:0, lo:1 } ); + forkPipe.setsockopt(ZMQ_SNDHWM, 1); + forkPipe.setsockopt(ZMQ_RCVHWM, 1); #if (neko || cpp) pipe.bind("inproc://zctx-pipe-" + pipeUUID); diff --git a/org/zeromq/test/TestAll.hx b/org/zeromq/test/TestAll.hx index 3dd8c8d..e93fc82 100644 --- a/org/zeromq/test/TestAll.hx +++ b/org/zeromq/test/TestAll.hx @@ -35,12 +35,13 @@ class TestAll runner.add(new TestVersion()); runner.add(new TestContext()); runner.add(new TestError()); + runner.add(new TestXPubXSub()); runner.add(new TestSocket()); runner.add(new TestPubSub()); runner.add(new TestMultiPartMessage()); runner.add(new TestReqRep()); runner.add(new TestPoller()); - // + // org.zeromq.remoting package tests runner.add(new TestZMQRemoting()); diff --git a/org/zeromq/test/TestMultiPartMessage.hx b/org/zeromq/test/TestMultiPartMessage.hx index fa63b4f..6a04c05 100644 --- a/org/zeromq/test/TestMultiPartMessage.hx +++ b/org/zeromq/test/TestMultiPartMessage.hx @@ -46,13 +46,14 @@ class TestMultiPartMessage extends BaseTest pair.s1.sendMsg(msg3); // last part of multipart message // Receive multipart message - var i:Int = 1; + var i:Int = 0; do { + i++; var b:Bytes = pair.s2.recvMsg(); // Blocking call assertEquals(Std.string(i), b.toString().charAt(7)); - i++; + } while (pair.s2.hasReceiveMore()); - assertTrue(i == 4); // 3 parts received + assertEquals(3, i); // 3 parts received } catch (e:ZMQException) { trace("ZMQException #:" + e.toString()); diff --git a/org/zeromq/test/TestPoller.hx b/org/zeromq/test/TestPoller.hx index 5d79fe8..c8b3c2c 100644 --- a/org/zeromq/test/TestPoller.hx +++ b/org/zeromq/test/TestPoller.hx @@ -22,6 +22,9 @@ package org.zeromq.test; import haxe.io.Bytes; import neko.Sys; import haxe.Stack; +import org.zeromq.ZContext; +import org.zeromq.ZMQContext; +import org.zeromq.ZMsg; import org.zeromq.ZMQ; import org.zeromq.ZMQPoller; @@ -93,6 +96,84 @@ class TestPoller extends BaseTest } } + public function testPollingReqRepZMQ3() { + var pollinout:Int = ZMQ.ZMQ_POLLIN() | ZMQ.ZMQ_POLLOUT(); + var ctx:ZContext; + var req:ZMQSocket, rep:ZMQSocket; + var poller:ZMQPoller; + var numSocks; + + try { + // ** Test tcp req/rep poller revents + var randomPort:Int = Math.round(Math.random() * 18000) + 2000; + ctx = new ZContext(); + req = ctx.createSocket(ZMQ_REQ); + rep = ctx.createSocket(ZMQ_REP); + req.bind("tcp://*:"+randomPort); + rep.connect("tcp://localhost:"+randomPort); + Sys.sleep(0.1); // Allow sockets time to connect + poller = new ZMQPoller(); + poller.registerSocket(req, pollinout); + poller.registerSocket(rep, pollinout); + numSocks = poller.poll(10 * ZMQ.ZMQ_POLL_MSEC()); + assertEquals(1, numSocks); + ctx.destroy(); + + } catch (e:ZMQException) { + trace("ZMQException #:" + e.errNo + ", str:" + e.str()); + trace (Stack.toString(Stack.exceptionStack())); + assertTrue(false); + } + + try { + // ** Test ipc req/rep poller revents + ctx = new ZContext(); + req = ctx.createSocket(ZMQ_REQ); + rep = ctx.createSocket(ZMQ_REP); + req.bind("ipc:///tmp/poller"); + rep.connect("ipc:///tmp/poller"); + Sys.sleep(0.1); // Allow sockets time to connect + poller = new ZMQPoller(); + poller.registerSocket(req, pollinout); + poller.registerSocket(rep, pollinout); + numSocks = poller.poll(10 * ZMQ.ZMQ_POLL_MSEC()); + assertEquals(1, numSocks); + ctx.destroy(); + } catch (e:ZMQException) { + if (e.err != ErrorType.EPROTONOSUPPORT) { + // Only assert test has failed if the exception is not "Protocol Not Supported". + // On Windows, ipc is not supported by ZeroMQ. + trace("ZMQException #:" + e.errNo + ", str:" + e.str()); + trace (Stack.toString(Stack.exceptionStack())); + assertTrue(false); + } + } + + try { + // ** Test inproc req/rep poller revents + ctx = new ZContext(); + req = ctx.createSocket(ZMQ_REQ); + rep = ctx.createSocket(ZMQ_REP); + req.bind("inproc://test.poller"); + rep.connect("inproc://test.poller"); + Sys.sleep(0.1); // Allow sockets time to connect + poller = new ZMQPoller(); + poller.registerSocket(req, pollinout); + poller.registerSocket(rep, pollinout); + numSocks = poller.poll(10 * ZMQ.ZMQ_POLL_MSEC()); + assertEquals(1, numSocks); + ctx.destroy(); + + assertTrue(true); + + } catch (e:ZMQException) { + trace("ZMQException #:" + e.errNo + ", str:" + e.str()); + trace (Stack.toString(Stack.exceptionStack())); + assertTrue(false); + } + + } + public function testPollingReqRep() { var pair:SocketPair = createBoundPair(ZMQ_REP, ZMQ_REQ); @@ -104,15 +185,21 @@ class TestPoller extends BaseTest poller.registerSocket(pair.s1, pollinout); poller.registerSocket(pair.s2, pollinout); - var numSocks = poller.poll(); - assertEquals(1, numSocks); // Only one revent bitmask with an event - assertEquals(2, poller.getSize()); + var numSocks = poller.poll(10 * ZMQ.ZMQ_POLL_MSEC()); + //trace ("rep:poller.pollin(1):" + poller.pollin(1) + ", poller.pollout(1):" + poller.pollout(1)); + //trace ("req:poller.pollin(2):" + poller.pollin(2) + ", poller.pollout(2):" + poller.pollout(2)); + + assertEquals(1, numSocks); // Only one revent bitmask with an event + // Had to change this from 1 when upgrading to ZMQ 3.1 + assertEquals(2, poller.getSize()); assertTrue(poller.noevents(1)); // REP socket s1 no events assertTrue(poller.pollout(2)); // REQ socket s2 should be ready for writing // Make sure s2 REQ socket immediately goes into state 0 after send pair.s2.sendMsg(Bytes.ofString("msg1")); numSocks = poller.poll(); + //trace ("rep:poller.pollin(1):" + poller.pollin(1) + ", poller.pollout(1):" + poller.pollout(1)); + //trace ("req:poller.pollin(2):" + poller.pollin(2) + ", poller.pollout(2):" + poller.pollout(2)); assertTrue(poller.noevents(2)); // Make sure that s1 goes into POLLIN state after a sleep() diff --git a/org/zeromq/test/TestReqRep.hx b/org/zeromq/test/TestReqRep.hx index 6386d30..fc84b1b 100644 --- a/org/zeromq/test/TestReqRep.hx +++ b/org/zeromq/test/TestReqRep.hx @@ -37,7 +37,7 @@ import org.zeromq.test.BaseTest; class TestReqRep extends BaseTest { - public function TODOtestBasicReqRep() { + public function testBasicReqRep() { var pair:SocketPair; try { pair = createBoundPair(ZMQ_REQ, ZMQ_REP); diff --git a/org/zeromq/test/TestSocket.hx b/org/zeromq/test/TestSocket.hx index 0ee14e4..f42d1f5 100644 --- a/org/zeromq/test/TestSocket.hx +++ b/org/zeromq/test/TestSocket.hx @@ -31,7 +31,7 @@ import org.zeromq.test.BaseTest; /** * Haxe test class focused on the ZMQSocket haxe binding class * - * Assumes a baseline ZMQ version of 2.1.4 (ie. some tests may not work if run against any earlier versions of the libzmq library) + * Assumes a baseline ZMQ version of 3.x.x (ie. some tests may not execute or compile if run against any earlier versions of the libzmq library) */ class TestSocket extends BaseTest { @@ -95,6 +95,14 @@ class TestSocket extends BaseTest var r:Int = pair.s1.getsockopt(ZMQ_EVENTS); assertEquals(ZMQ.ZMQ_POLLOUT(), r); assertRaisesZMQException(function() { pair.s1.setsockopt(ZMQ_EVENTS, 2 ^ 7 - 1); }, EINVAL); + + pair.s1.setsockopt(ZMQ_LINGER, 0); + r = pair.s1.getsockopt(ZMQ_SNDHWM); + assertTrue(r == 0); // Test default HWM is 0 for a new socket + pair.s2.setsockopt(ZMQ_SNDHWM, 10 ); + var r:Int = pair.s2.getsockopt(ZMQ_SNDHWM); + assertEquals(10, r); + #end assertEquals(ZMQ.socketTypeNo(ZMQ_PUB), pair.s1.getsockopt(ZMQ_TYPE)); assertEquals(ZMQ.socketTypeNo(ZMQ_SUB), pair.s2.getsockopt(ZMQ_TYPE)); @@ -118,24 +126,14 @@ class TestSocket extends BaseTest try { pair = createBoundPair(ZMQ_PUB, ZMQ_SUB); -#if (neko || cpp) - pair.s1.setsockopt(ZMQ_LINGER, 0); - r = pair.s1.getsockopt(ZMQ_HWM); - assertTrue(r.lo == 0); // Test default HWM is 0 for a new socket - assertTrue(r.hi == 0); - pair.s2.setsockopt(ZMQ_HWM, { hi:128, lo:128 } ); // (128 * 2^32)+128 - var r:ZMQInt64Type = pair.s2.getsockopt(ZMQ_HWM); - assertTrue(r.lo == 128); - assertTrue(r.hi == 128); +#if (neko || cpp) + pair.s1.setsockopt(ZMQ_MAXMSGSIZE, { hi:10, lo:100 } ); + r = pair.s1.getsockopt(ZMQ_MAXMSGSIZE); + assertEquals(10, r.hi); + assertEquals(100, r.lo); + r = pair.s1.getsockopt(ZMQ_AFFINITY); assertEquals(0, r.lo); - r = pair.s1.getsockopt(ZMQ_SWAP); - assertTrue(r.lo == 0); - assertTrue(r.hi == 0); - pair.s1.setsockopt(ZMQ_SWAP, { hi:1, lo:255 } ); // (1 * 2^32) + 255 bytes - r = pair.s1.getsockopt(ZMQ_SWAP); - assertTrue(r.lo == 255); - assertTrue(r.hi == 1); #elseif php pair.s1.setsockopt(ZMQ_LINGER, 0); r = pair.s1.getsockopt(ZMQ_HWM); diff --git a/org/zeromq/test/TestXPubXSub.hx b/org/zeromq/test/TestXPubXSub.hx new file mode 100644 index 0000000..fdc3be6 --- /dev/null +++ b/org/zeromq/test/TestXPubXSub.hx @@ -0,0 +1,84 @@ +/** + * (c) 2011 Richard J Smith + * + * This file is part of hxzmq + * + * hxzmq is free software; you can redistribute it and/or modify it under + * the terms of the Lesser GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * hxzmq 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 + * Lesser GNU General Public License for more details. + * + * You should have received a copy of the Lesser GNU General Public License + * along with this program. If not, see . + */ + +package org.zeromq.test; + +import haxe.io.Bytes; +import haxe.io.BytesBuffer; +import haxe.Stack; +import neko.Sys; +import org.zeromq.ZMsg; + +import org.zeromq.ZMQ; +import org.zeromq.ZMQSocket; +import org.zeromq.ZMQException; +import org.zeromq.test.BaseTest; + +/** + * This class sets up tests for the XPUB and XSUB socket types + * introduced in 0MQ3 + */ +class TestXPubXSub extends BaseTest +{ + + public function testSubscriptionForwarding() { + + try { + var pair:SocketPair = createBoundPair(ZMQ_XPUB, ZMQ_XSUB); + _sockets.add(pair.s1); + _sockets.add(pair.s2); + + pair.s2.setsockopt(ZMQ_RCVTIMEO, 100); // Timeout blocking recv on XSUB socket at 100msecs. + // Used for filtered-out test below + + // Subscribe to prefix "A" + var subscription:BytesBuffer = new BytesBuffer(); + subscription.addByte(1); // Subscribe + subscription.add(Bytes.ofString("A")); + pair.s2.sendMsg(subscription.getBytes()); + + Sys.sleep(0.1); // Give time for XPUB socket to receive subscription + var sent = new ZMsg(); + sent.addString("A"); + sent.addString("I want to receive this"); + sent.send(pair.s1); + + var msg:ZMsg = ZMsg.recvMsg(pair.s2); // this is a blocking call + assertTrue(msg.first().streq("A")); + assertTrue(msg.last().streq("I want to receive this")); + + // Send a message to XSUB socket that should not meet its subscription + sent = new ZMsg(); + sent.addString("B"); + sent.addString("I don't want to receive this"); + sent.send(pair.s1); + + // This call should time out + msg = null; + msg = ZMsg.recvMsg(pair.s2); + assertTrue(msg == null); + + } catch (e:ZMQException) { + trace("ZMQException #:" + e.errNo + ", str:" + e.str()); + trace (Stack.toString(Stack.exceptionStack())); + assertTrue(false); + } + } + +} \ No newline at end of file diff --git a/org/zeromq/test/TestZThread.hx b/org/zeromq/test/TestZThread.hx index 8c8350e..835a201 100644 --- a/org/zeromq/test/TestZThread.hx +++ b/org/zeromq/test/TestZThread.hx @@ -45,12 +45,12 @@ class TestZThread extends BaseTest private function attachedThreadTest(ctx:ZContext, pipe:ZMQSocket, args:Dynamic) { // Create a new socket to check it'll be automatically deleted var newSocket = ctx.createSocket(ZMQ_PUSH); - trace ("newSocket created"); + //trace ("newSocket created"); // Wait for our parent to ping us and pong back var ping = pipe.recvMsg(); - trace ("ping received:" + ping.toString()); + //trace ("ping received:" + ping.toString()); pipe.sendMsg(Bytes.ofString("pong")); - trace ("pipe sent pong"); + //trace ("pipe sent pong"); } public function testZThreadDetach() { @@ -68,14 +68,14 @@ class TestZThread extends BaseTest // Create a new attached thread and let it run var pipe:ZMQSocket = ZThread.attach(ctx, attachedThreadTest, "foo"); - trace ("Now send ping"); + //trace ("Now send ping"); pipe.sendMsg(Bytes.ofString("ping")); var pong = pipe.recvMsg(); - trace ("pong received:" + pong.toString()); + //trace ("pong received:" + pong.toString()); assertEquals(pong.toString(), "pong"); // Everything should be cleanly closed now - trace ("exiting"); + //trace ("exiting"); try { ctx.destroy(); } catch (e:ZMQException) { diff --git a/src/Device.cpp b/src/Device.cpp index 4e9e894..5a52ce6 100644 --- a/src/Device.cpp +++ b/src/Device.cpp @@ -34,9 +34,14 @@ value hx_zmq_device (value type_, value frontend_, value backend_) { val_check_kind(frontend_, k_zmq_socket_handle); val_check_kind(backend_, k_zmq_socket_handle); +#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0) + int rc = -1; + int err = ENOTSUP; +#else int rc = zmq_device(val_int(type_), val_data(frontend_), val_data(backend_)); int err = zmq_errno(); - +#endif + if (rc != 0) { val_throw(alloc_int(err)); return alloc_null(); diff --git a/src/Poller.cpp b/src/Poller.cpp index 26e7250..af817c3 100644 --- a/src/Poller.cpp +++ b/src/Poller.cpp @@ -98,4 +98,16 @@ value hx_zmq_poll (value sockets_, value events_, value timeout_) { } -DEFINE_PRIM (hx_zmq_poll, 3); \ No newline at end of file +DEFINE_PRIM (hx_zmq_poll, 3); + +value hx_zmq_ZMQ_POLL_MSEC() +{ +#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0) + + return alloc_int(1); +#else + return alloc_int(1000); +#endif +} + +DEFINE_PRIM( hx_zmq_ZMQ_POLL_MSEC,0); \ No newline at end of file diff --git a/src/Socket.cpp b/src/Socket.cpp index bd656e5..c9b3771 100644 --- a/src/Socket.cpp +++ b/src/Socket.cpp @@ -368,13 +368,17 @@ value hx_zmq_send(value socket_handle_, value msg_data, value flags) { gc_enter_blocking(); // Send +#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0) + rc = zmq_sendmsg (val_data(socket_handle_), &message, val_int(flags)); +#else rc = zmq_send (val_data(socket_handle_), &message, val_int(flags)); +#endif err = zmq_errno(); gc_exit_blocking(); // If NOBLOCK, but cant send message now, close message first before quitting - if (rc != 0 && err == EAGAIN) { + if (rc == -1 && err == EAGAIN) { rc = zmq_msg_close (&message); err = zmq_errno(); if (rc != 0) { @@ -384,7 +388,7 @@ value hx_zmq_send(value socket_handle_, value msg_data, value flags) { return alloc_null(); } - if (rc != 0) { + if (rc == -1) { val_throw(alloc_int(err)); rc = zmq_msg_close (&message); err = zmq_errno(); @@ -427,13 +431,16 @@ value hx_zmq_rcv(value socket_handle_, value flags) { } gc_enter_blocking(); - + +#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0) + rc = zmq_recvmsg (val_data(socket_handle_), &message, val_int(flags)); +#else rc = zmq_recv (val_data(socket_handle_), &message, val_int(flags)); - +#endif gc_exit_blocking(); err = zmq_errno(); - if (rc != 0 && err == EAGAIN) { + if (rc == -1 && err == EAGAIN) { rc = zmq_msg_close (&message); err = zmq_errno(); if (rc != 0) { @@ -443,7 +450,7 @@ value hx_zmq_rcv(value socket_handle_, value flags) { return alloc_null(); } - if (rc != 0) { + if (rc == -1) { rc = zmq_msg_close (&message); int err1 = zmq_errno(); if (rc != 0) { diff --git a/src/ZMQ.cpp b/src/ZMQ.cpp index 03cd78a..4e1c523 100644 --- a/src/ZMQ.cpp +++ b/src/ZMQ.cpp @@ -121,67 +121,88 @@ value hx_zmq_ZMQ_PUSH() } DEFINE_PRIM( hx_zmq_ZMQ_PUSH,0); -/* ******* Socket Option Types **********/ -value hx_zmq_ZMQ_LINGER() +#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0) + +/* New Socket Types introduced in 0MQ 3 */ + +value hx_zmq_ZMQ_XREQ() { - return alloc_int(ZMQ_LINGER); + return alloc_int(ZMQ_XREQ); } -DEFINE_PRIM( hx_zmq_ZMQ_LINGER,0); +DEFINE_PRIM( hx_zmq_ZMQ_XREQ,0); -value hx_zmq_ZMQ_HWM() +value hx_zmq_ZMQ_XREP() { - return alloc_int(ZMQ_HWM); + return alloc_int(ZMQ_XREP); } +DEFINE_PRIM( hx_zmq_ZMQ_XREP,0); -DEFINE_PRIM( hx_zmq_ZMQ_HWM,0); +value hx_zmq_ZMQ_XPUB() +{ + return alloc_int(ZMQ_XPUB); +} +DEFINE_PRIM( hx_zmq_ZMQ_XPUB,0); -value hx_zmq_ZMQ_RCVMORE() +value hx_zmq_ZMQ_XSUB() { - return alloc_int(ZMQ_RCVMORE); + return alloc_int(ZMQ_XSUB); } -DEFINE_PRIM( hx_zmq_ZMQ_RCVMORE,0); +DEFINE_PRIM( hx_zmq_ZMQ_XSUB,0); -value hx_zmq_ZMQ_SUBSCRIBE() +#endif +/* ******* Socket Option Types **********/ + +#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0) + +value hx_zmq_ZMQ_MAXMSGSIZE() { - return alloc_int(ZMQ_SUBSCRIBE); + return alloc_int(ZMQ_MAXMSGSIZE); } -DEFINE_PRIM( hx_zmq_ZMQ_SUBSCRIBE,0); +DEFINE_PRIM( hx_zmq_ZMQ_MAXMSGSIZE,0); + +value hx_zmq_ZMQ_SNDHWM() +{ + return alloc_int(ZMQ_SNDHWM); +} +DEFINE_PRIM( hx_zmq_ZMQ_SNDHWM,0); -value hx_zmq_ZMQ_UNSUBSCRIBE() +value hx_zmq_ZMQ_RCVHWM() { - return alloc_int(ZMQ_UNSUBSCRIBE); + return alloc_int(ZMQ_RCVHWM); } -DEFINE_PRIM( hx_zmq_ZMQ_UNSUBSCRIBE,0); +DEFINE_PRIM( hx_zmq_ZMQ_RCVHWM,0); -value hx_zmq_ZMQ_IDENTITY() +value hx_zmq_ZMQ_MULTICAST_HOPS() { - return alloc_int(ZMQ_IDENTITY); + return alloc_int(ZMQ_MULTICAST_HOPS); } -DEFINE_PRIM( hx_zmq_ZMQ_IDENTITY,0); +DEFINE_PRIM( hx_zmq_ZMQ_MULTICAST_HOPS,0); -value hx_zmq_ZMQ_SWAP() +value hx_zmq_ZMQ_RCVTIMEO() { - return alloc_int(ZMQ_SWAP); + return alloc_int(ZMQ_RCVTIMEO); } -DEFINE_PRIM( hx_zmq_ZMQ_SWAP,0); +DEFINE_PRIM( hx_zmq_ZMQ_RCVTIMEO,0); -value hx_zmq_ZMQ_AFFINITY() +value hx_zmq_ZMQ_SNDTIMEO() { - return alloc_int(ZMQ_AFFINITY); + return alloc_int(ZMQ_SNDTIMEO); } -DEFINE_PRIM( hx_zmq_ZMQ_AFFINITY,0); +DEFINE_PRIM( hx_zmq_ZMQ_SNDTIMEO,0); -value hx_zmq_ZMQ_RATE() +#else + +value hx_zmq_ZMQ_HWM() { - return alloc_int(ZMQ_RATE); + return alloc_int(ZMQ_HWM); } -DEFINE_PRIM( hx_zmq_ZMQ_RATE,0); +DEFINE_PRIM( hx_zmq_ZMQ_HWM,0); -value hx_zmq_ZMQ_RECOVERY_IVL() +value hx_zmq_ZMQ_SWAP() { - return alloc_int(ZMQ_RECOVERY_IVL); + return alloc_int(ZMQ_SWAP); } -DEFINE_PRIM( hx_zmq_ZMQ_RECOVERY_IVL,0); +DEFINE_PRIM( hx_zmq_ZMQ_SWAP,0); value hx_zmq_ZMQ_RECOVERY_IVL_MSEC() { @@ -195,6 +216,61 @@ value hx_zmq_ZMQ_MCAST_LOOP() } DEFINE_PRIM( hx_zmq_ZMQ_MCAST_LOOP,0); +#endif + +#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(2,1,0) + +value hx_zmq_ZMQ_IDENTITY() +{ + return alloc_int(ZMQ_IDENTITY); +} +DEFINE_PRIM( hx_zmq_ZMQ_IDENTITY,0); + +value hx_zmq_ZMQ_RECOVERY_IVL() +{ + return alloc_int(ZMQ_RECOVERY_IVL); +} +DEFINE_PRIM( hx_zmq_ZMQ_RECOVERY_IVL,0); + +value hx_zmq_ZMQ_LINGER() +{ + return alloc_int(ZMQ_LINGER); +} +DEFINE_PRIM( hx_zmq_ZMQ_LINGER,0); + + +#endif + +value hx_zmq_ZMQ_RCVMORE() +{ + return alloc_int(ZMQ_RCVMORE); +} +DEFINE_PRIM( hx_zmq_ZMQ_RCVMORE,0); + +value hx_zmq_ZMQ_SUBSCRIBE() +{ + return alloc_int(ZMQ_SUBSCRIBE); +} +DEFINE_PRIM( hx_zmq_ZMQ_SUBSCRIBE,0); + +value hx_zmq_ZMQ_UNSUBSCRIBE() +{ + return alloc_int(ZMQ_UNSUBSCRIBE); +} +DEFINE_PRIM( hx_zmq_ZMQ_UNSUBSCRIBE,0); + +value hx_zmq_ZMQ_AFFINITY() +{ + return alloc_int(ZMQ_AFFINITY); +} +DEFINE_PRIM( hx_zmq_ZMQ_AFFINITY,0); + +value hx_zmq_ZMQ_RATE() +{ + return alloc_int(ZMQ_RATE); +} +DEFINE_PRIM( hx_zmq_ZMQ_RATE,0); + value hx_zmq_ZMQ_SNDBUF() { return alloc_int(ZMQ_SNDBUF); @@ -243,6 +319,7 @@ value hx_zmq_ZMQ_TYPE() } DEFINE_PRIM( hx_zmq_ZMQ_TYPE,0); +/* ******* POLLER OPTIONS **********/ value hx_zmq_ZMQ_POLLIN() { return alloc_int(ZMQ_POLLIN); @@ -278,6 +355,8 @@ value hx_zmq_SNDMORE() } DEFINE_PRIM( hx_zmq_SNDMORE,0); + + /* ******* Exception Codes *************/ value hx_zmq_EINVAL() { @@ -382,6 +461,7 @@ value hx_zmq_ETERM() DEFINE_PRIM( hx_zmq_ETERM,0); /* ******* ZMQ Devices *************/ +#if ZMQ_VERSION < ZMQ_MAKE_VERSION(3,0,0) value hx_zmq_ZMQ_QUEUE() { return alloc_int(ZMQ_QUEUE); @@ -398,3 +478,4 @@ value hx_zmq_ZMQ_STREAMER() } DEFINE_PRIM( hx_zmq_ZMQ_STREAMER, 0); +#endif diff --git a/test/buildMac64.hxml b/test/buildMac64.hxml index e710c28..1f3913f 100644 --- a/test/buildMac64.hxml +++ b/test/buildMac64.hxml @@ -16,11 +16,11 @@ -debug -lib hxzmq -main org.zeromq.test.TestAll ---next +#--next # Build PHP unit test target for Mac64 --cp .. --php out-php/Mac64 --debug ---remap neko:php --lib hxzmq --main org.zeromq.test.TestAll +#-cp .. +#-php out-php/Mac64 +#-debug +#--remap neko:php +#-lib hxzmq +#-main org.zeromq.test.TestAll