Why does Scons care that my target is read-only, and how can I convince it to ignore it?
I'm trying to put together a debug build of a particularly difficult project layout. One of the things I need to do is to copy recently built DLLs over existing DLLs that are under Source Safe's control, and are therefore read-only. I was hoping to use Scons to manage this, but Scons errors out if your target is read-only. Part of my command is to set it to readable, but my command never executes because scons errors out first. Is there anyway to override this behavior?
Here's a demonstration. As you can see, my "turn off the read-only bit" command never gets run if the read-only bit is set:
C:\scs\dev\test>type Sconstruct
env = Environment()
env.Command(
"b.txt", "a.txt",
[
r"if exist $TARGET c:\windows\system32\attrib -r $TARGET",
Copy("$TARGET", "$SOURCE")
]
)
C:\scs\dev\test>echo "test" > a.txt
C:\scs\dev\test>scons -Q b.txt
if exist b.txt c:\windows\system32\attrib -r b.txt
Copy("b.txt", "a.txt")
C:\scs\dev\test>echo "test2" > a.txt
C:\scs\dev\test>attrib +r b.txt
C:\scs\dev\test>scons -Q b.txt
scons: *** [b.txt] C:\scs\dev\test\b.txt: Access is denied
Update
OK - I've figured this out by stepping though Scons as it was running. Looks like Scons deletes targets before building them (see _rmv_existing
in FS.py, also this page in the scons documentation page). If you encounter this problem, you can mark the target as "Precious", but you'll still have trouble if开发者_如何转开发 you use "-c".
No real good solution here. Oh well.
use NoClean(target) to disable deleting of generated files while running scons -c
.
This is a Windows-specific issue related to this question. Python os.unlink()/os.remove()
raise exception on Windows, when a file is read-only, but they won't on Linux. To have consistent behavior, I resorted to monkey-patching os.unlink(). This covers all the issues I found so far in building and cleaning (-c
option).
import os, stat
def _os_force_unlink(path):
"""Monkey-patch for os.unlink() to enable removing read-only files.
Need for consistency between platforms: os.unlink raises exception on Windows
(but not on Linux), when path is read-only.
Unfixed SCons bug: http://scons.tigris.org/issues/show_bug.cgi?id=2693
SCons uses os.unlink in several places. To avoid patching multiple functions,
we patch the os function and use the lucky fact that os.remove does the same,
so we can still get the normal OS behavior. SCons also uses os.remove(),
but not in places that affect this particular issue, so os.remove() stays as is.
Note: this affects os.unlink() in all user code that runs in context of this set-up.
"""
if not os.access(path, os.W_OK):
os.chmod(path, stat.S_IWRITE)
return os.remove(path)
# Put this in some common place, like top of SConstruct
if <determine that platform is Windows>
# Sufficient for SCons 2.5.0. We may need to patch more, if future SCons changes things
os.unlink = _os_force_unlink
More on monkey-patching: https://filippo.io/instance-monkey-patching-in-python/
精彩评论