(I hope you don't mind my truncation.)

Looking at the source for rdmd, I see:

private @property string myOwnTmpDir()
{

 version (Posix)
 {
     import core.sys.posix.unistd;
     auto tmpRoot = format("/tmp/.rdmd-%d", getuid());
 }

..
}

which is used literally everywhere that the tmpfile is mentioned.
/tmp/.rdmd-userid is literally hardcoded into rdmd.

I've been tracing rdmd for a few minutes, and it appears that the
version on github
does write anything to the current directory unless you specifically ask
it to(deps, etc).
I can submit a pull request for rdmd to check the current directory and
default to myOwnTmpDir if it is readonly.
Or we could always fork rdmd. It should be using the boost license and
it'd be an excellent starting point.

The executable and the object are both written to myOwnTmpDir afaict.

I just tested and you are right. The version that ships with DMD 2.060
keeps the source directory clean if it has to (unfortunately in that
case dependency tracking seems to get disabled but that's acceptable).

path:
https://github.com/D-Programming-Language/tools/blob/master/rdmd.d#L394
ignoring the error when failing to create the deps file:
https://github.com/D-Programming-Language/tools/blob/master/rdmd.d#L466

But since 2.059 still has the full issue, that copy logic probably has
to stay for a bit longer to not throw someone off who is not living on
the cutting edge.

I do not know if it is still true, but since rdmd claims that it 'may
get folded into dmd',
It might be a good idea to support it 'officially' as long as it does
what is needed...
But that is your call to make.

I was about to write a reasoning why rdmd is bad right now.. but rdmd
was improved recently and now compiles only once instead of making a
separate compile just to get the dependencies, reducing the arguments
against it to one ;)

So the only issue remaining is that local/string imports are not
tracked. In this case, if there is time, a hybrid solution may work to
improve the situation. A possible approach could be to collect the time
stamps of all .dt files and only when one of them changes is rdmd
invoked with --force.

rdmd also supports the --compiler=[anything] and gdc builds and installs
gdmd by default.
my version of ldc also includes a ldmd2 wrapper by default, although I
do not know if it is built with ldc like gdc.

It looks like everything includes a "map dmd opts to our opts" mode, so
that's a very good thing for us at least.

This would just still mean that rdmd has to be distributed or at least
needs some instructions for gdc/ldc - but maybe thats OK for someone who
is probably used to such customizations. A setting for the compiler in
/etc/vibe/vibe.conf, defaulting to 'dmd', would be a good idea anyways.

I submitted a pull request for the changes.
Also the DFeed server is not having a good time with it's database.
I cc'd info@rejectedsoftware just in case.

Whew! I was worried that I just wasn't understanding things. =P
I obviously missed it's teething phase.

I think right now most people who install ldc or gdc are like me:
You already have the reference implementation, you're just curious to see
how well the reference implementation compares to other backends. So far
it's pretty favorable. dmd has the fastest compilation times.

You could not recompile everything every time with gdc... I now must go
time the differences...
...And gdc does NOT like something here.
...And ldc likes it even LESS.

Shrugs, I know that neither of them are fully caught up with the
complexity of dmd, (scoped imports, etc..)
I might also have outdated versions since I like recompiling them by hand.

ldc did catch a import core.sys.windows that probably needs to be
version'd though.