Paul,
I don't understand why you say "I don't know of any portable way of determining whether stdout is going to /dev/null, or not" and "However, it's moot because I don't think we can detect it". It's simple to detect this on a Unix-like host (see sample script below) and my contention is that this is "plenty portable enough". The concepts of /dev/null and device/inode both go right back to the very first days of Unix so I think it's almost certain that any Unix-derived or -inspired platform is going to support both. Put differently, I think any system supported by GNU make will have both or neither. But let's imagine a system that has just one of the two: for systems that don't have /dev/null, what's the problem? It can't be locked if it's not there and any system that does implement /dev/null will certainly implement it with the traditional semantics. Native Windows doesn't have /dev/null (and Eli confirms that this can't happen there), Cygwin emulates both, etc. I believe both preconditions are easily detectable at configure time.
Bottom line, the odds of any platform that supports a lockable /dev/null not having st_ino in a stat structure, at least an emulated one, seem vanishingly small to me. Do you know of a platform where the strategy of "implement the special case for /dev/null if possible or retain current semantics if not" breaks down?
David
$ cat /tmp/null-vs-stdout
#!/usr/bin/env python3
import os
import sys
for path in sys.argv[1:]:
p = os.stat(path)
s = os.fstat(sys.stdout.fileno())
if p.st_ino == s.st_ino and p.st_dev == s.st_dev:
sys.stderr.write('IS stdout: %s\n' % path)
else:
sys.stderr.write('not stdout: %s\n' % path)
$ python3 /tmp/null-vs-stdout /dev/null
not stdout: /dev/null
$ python3 /tmp/null-vs-stdout /dev/null > /dev/null
IS stdout: /dev/null