2010-08-20 8 views
10

Ich verwende SCons zum Erstellen eines Projekts und muss einen symbolischen Link zu einer Datei hinzufügen, die über env.Install installiert wird. Mit welchen Befehlen wird eine Verknüpfung erstellt, die der Ausführung von ln -s in der Befehlszeile entspricht?Wie erstellt man eine symbolische Verbindung mit SCons?

Antwort

8

SCons keinen eigenen symbolischen Link-Befehl haben, aber Sie können os Modul os.symlink(src, dst) von Python verwenden:

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) 

Dies kann nicht richtig unter Windows arbeiten, habe ich versucht, es nur auf Linux.

+0

Aus irgendeinem Grund, es funktioniert nicht, wenn Sie einen symbolischen Link in einem subdir zu schaffen versuchen, wie "env.Command (Flavor + '/ Resources', 'src/Resources', SymLink)" wobei Flavor 'debug' oder 'release' ist. – Septagram

+1

@Septagram siehe meine Bearbeitung –

+0

Arbeitet nicht für installierte Dateien – RzR

1

Dies schafft einen Builder den Job auszuführen:

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) 

Auch diese Lösung für Linux.

+1

Leider funktioniert es nicht gut (überhaupt) auf Verzeichnisse: "TypeError: Verzeichnis/home/septi/Dropbox/Code/StreetCleaner/src/Ressourcen wo Datei gefunden erwartet .: " – Septagram

+0

@Septagram: Wie behebe ich das Verzeichnisproblem? –

+0

@ Nordlöw, tut mir leid, aber es ist eine Weile her und ich weiß nicht :(Bitte versuchen Sie andere Antworten und kommentieren, wenn Sie etwas finden. – Septagram

7

Es scheint nur wenig Fortschritt im Kerncode von SCons für die Unterstützung von symbolischen Links zu geben und ich war mit keiner der Lösungen zufrieden, die ich im Internet gefunden habe. Hier ist ein potenzieller Erbauer, der Aspekte der Antworten von Nick und richq enthält. Außerdem wird es Namensänderungen (aufgrund der Emitter-Methode) erfassen und ist so plattformunabhängig, wie ich es bekommen könnte.

Ich bevorzuge diesen Builder, weil es Links relativ zu dem Verzeichnis macht, in dem sie installiert sind. Man könnte eine Option hinzufügen, um die Verbindung zu zwingen, absolut zu sein, nehme ich an, aber ich habe das noch nicht gebraucht oder gewollt.

Derzeit, wenn das Betriebssystem keine Symlinks unterstützt, überlasse ich einfach nichts, aber man könnte zB os.copytree() verwenden, aber die Abhängigkeit wird unordentlich, wenn die Quelle ein Verzeichnis ist, das der Emitter benötigen würde Mach etwas Fantastisches. Ich bin für irgendwelche Vorschläge hier.

Man kann den folgenden Code in die Datei setzen site_scons/site_tools/symlink.py (mit leeren _ init _.py Dateien an den entsprechenden Stellen). Dann tun dies in der SConstruct Datei:

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 
+0

Sie geschrieben haben Variante auch für harte Links, ich möchte die gleiche Schnittstelle wie 'Install', wo das erste Argument ein Verzeichnis ist. –

Verwandte Themen