我正在使用SCons构建项目,需要通过env.Install添加一个符号链接到它正在安装的文件。什么命令会创建一个等同于在命令行上运行ln -s
的链接?
答案 0 :(得分:8)
SCons没有专用的符号链接命令,但您可以使用Python的os.symlink(src, dst)
模块中的os
:
import os
env = Environment()
def SymLink(target, source, env):
os.symlink(os.path.abspath(str(source[0])), os.path.abspath(str(target[0])))
env.Command("file.out", "file.in", SymLink)
这可能无法在Windows上正常运行,我只在Linux上尝试过。
答案 1 :(得分:7)
用于符号链接支持的SCons核心代码似乎没有什么进展,我对网上找到的任何解决方案都不满意。这是一个潜在的建设者,它结合了Nick's和richq的答案。此外,它将捕获名称更改(由于发射器方法),并且与我可以获得的平台无关。
我更喜欢这个构建器,因为它会创建相对于它们所在目录的链接。我可以添加一个选项来强制链接是绝对的,但我还没有需要或想要它。
目前,如果操作系统不支持符号链接,我只是传递并且什么都不做,但是可以使用os.copytree()例如,如果源是一个目录,那么依赖变得混乱,所以发射器需要做一些奇特的东西。我在这里有任何建议。
可以将以下代码放入文件 site_scons / site_tools / symlink.py (其中包含空白 _ init _。py 文件适当的地方)。然后在SConstruct文件中执行此操作:
SConstruct:
env = Environment()
env.Tool('symlink')
env.SymLink('link_name.txt', 'real_file.txt')
symlink.py:
import os
from os import path
from SCons.Node import FS
from SCons.Script import Action, Builder
def generate(env):
'''
SymLink(link_name,source)
env.SymLink(link_name,source)
Makes a symbolic link named "link_name" that points to the
real file or directory "source". The link produced is always
relative.
'''
bldr = Builder(action = Action(symlink_builder,symlink_print),
target_factory = FS.File,
source_factory = FS.Entry,
single_target = True,
single_source = True,
emitter = symlink_emitter)
env.Append(BUILDERS = {'SymLink' : bldr})
def exists(env):
'''
we could test if the OS supports symlinks here, or we could
use copytree as an alternative in the builder.
'''
return True
def symlink_print(target, source, env):
lnk = path.basename(target[0].abspath)
src = path.basename(source[0].abspath)
return 'Link: '+lnk+' points to '+src
def symlink_emitter(target, source, env):
'''
This emitter removes the link if the source file name has changed
since scons does not seem to catch this case.
'''
lnk = target[0].abspath
src = source[0].abspath
lnkdir,lnkname = path.split(lnk)
srcrel = path.relpath(src,lnkdir)
if int(env.get('verbose',0)) > 3:
ldir = path.relpath(lnkdir,env.Dir('#').abspath)
if rellnkdir[:2] == '..':
ldir = path.abspath(ldir)
print ' symbolic link in directory: %s' % ldir
print ' %s -> %s' % (lnkname,srcrel)
try:
if path.exists(lnk):
if os.readlink(lnk) != srcrel:
os.remove(lnk)
except AttributeError:
# no symlink available, so we remove the whole tree? (or pass)
#os.rmtree(lnk)
print 'no os.symlink capability on this system?'
return (target, source)
def symlink_builder(target, source, env):
lnk = target[0].abspath
src = source[0].abspath
lnkdir,lnkname = path.split(lnk)
srcrel = path.relpath(src,lnkdir)
if int(env.get('verbose',0)) > 4:
print 'target:', target
print 'source:', source
print 'lnk:', lnk
print 'src:', src
print 'lnkdir,lnkname:', lnkdir, lnkname
print 'srcrel:', srcrel
if int(env.get('verbose',0)) > 4:
print 'in directory: %s' % path.relpath(lnkdir,env.Dir('#').abspath)
print ' symlink: %s -> %s' % (lnkname,srcrel)
try:
os.symlink(srcrel,lnk)
except AttributeError:
# no symlink available, so we make a (deep) copy? (or pass)
#os.copytree(srcrel,lnk)
print 'no os.symlink capability on this system?'
return None
答案 2 :(得分:1)
这会创建一个构建器来执行作业:
mylib = env.SharedLibrary("foobar", SRCS)
builder = Builder(action = "ln -s ${SOURCE.file} ${TARGET.file}", chdir = True)
env.Append(BUILDERS = {"Symlink" : builder})
mylib_link = env.Symlink("_foobar.so", mylib)
env.Default(mylib)
env.Default(mylib_link)
同样,这个解决方案适用于Linux。
答案 3 :(得分:0)
如果您想直接向外壳发布命令并了解操作系统,也可以使用subprocess
。
例如:subprocess.call(['ln', '-s', '</src/path>', '</dest/path>'])
答案 4 :(得分:0)
除了 Nicks 解决方案之外,您还可以通过使用文件作为目录名称载体来添加目录符号链接。这不是最干净的解决方案,调试路径名很痛苦,但这很有效:
def symlink_last(target_source_env):
src = os.path.basename(os.path.dirname(str(source[0])))
link = "deliverables/last"
print "Symlinking "+ src + "as" + link
os.symlink(src, link)
BUILD_TARGETS.append('link')
install_dir = "deliverables/subdir"
carrier_file = "filename"
builder = Builder(action = symlink_last, chdir=False)
env.Append(BUILDERS={ "Symlink" : builder })
env.Alias(target="link", source=env.Symlink(dir="deliverables", source = install_dir + carrier_file)
这将创建一个指向名为 deliverables/subdir
的 deliverables/last
的链接,前提是文件 deliverables/subdir/filename
存在。