The reference doc was ambiguous for some points, which gets summarized here:
Q: How is the Command parameter of open_port() passed to the ErlDriverEntry .start callback ?
A: The Command is a string, and the first word (whitespace-separated) must be the name of the driver. The whole string, including the driver name, is passed to the callback.
Q: If I send a list of binaries to the port, can I expect to get every one of them separately with the outputv callback ? How does the SysIOVec struct work ?
A: NO. Small binaries, and presumably sub binaries spliced from a common one, may get merged in the resulting ErlIOVec. I've written this to iterate over an ErlIOVec. The doc defines:
typedef struct { int vsize; int size; SysIOVec* iov; ErlDrvBinary** binv;
and does not define (because it is platform-dependant, but in this case we want Unix):
typedef struct { char *iov_base; size_t iov_len; }
size is the total byte size of the whole ErlIOVec. vsize is the number of chunks (which may not match the number of binaries in the original iolist). iov and binv both are arrays of size vsize.
binv references the parent refc binaries (so the same binary can appear twice, and you may not be interested in all its data). Use this to manipulate the refcounter of the binary if you need to keep the data around.
Q: Is it OK to define the outputv callback and not output one ?
A: yes, you will receive an IOVec with a single chunk
Q: Why does open_port seemingly randomly fail with "bad argument" ?
A: It will if you try to open a driver that is not loaded. Now, erl_ddll is smart and remembers who loaded which driver, and will unload a driver when it is not needed anymore. If you are testing from the shell, getting an uncaught exception will terminate the shell process and start a new one, which may cause your driver to get unloaded.
Q: Why is erl_ddll:load/2 asking for a path ? What is a reasonable value to provide ?
A: According to the OTP doc, the standard way is to use code:priv_dir(app_name)