2010-08-20 18 views

Odpowiedz

8

SCons nie posiada dedykowanego polecenia dowiązania symbolicznego, ale można użyć os.symlink(src, dst) z modułu Pythona 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) 

ta może nie działać poprawnie w systemie Windows, ja tylko próbowałem go na Linuksie.

+0

Z jakiegoś powodu nie działa podczas próby utworzenia dowiązania wewnątrz podkatalogu, jak "env.Command (flavor +"/Resources "," src/Resources ", SymLink)" gdzie smak jest "debugowania" lub "wydania". – Septagram

+1

@Septagram zobacz moją edycję –

+0

Nie działa dla zainstalowanych plików – RzR

1

Stwarza to budowniczy, aby wykonać zadanie:

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) 

Ponownie, jest to rozwiązanie dla systemu Linux.

+1

Niestety, nie działa dobrze (w ogóle) na katalogach: "TypeError: Directory/home/septi/Dropbox/Code/StreetCleaner/src/Resources found where file expected .: " – Septagram

+0

@Septagram: Jak naprawić problem z katalogiem? –

+0

@ Nordlöw, przepraszam, ale minęło trochę czasu i nie wiem :(Proszę wypróbować inne odpowiedzi i komentarze, jeśli coś znajdziecie – Septagram

7

Wygląda na to, że w podstawowym kodzie SCons występuje niewielki postęp w zakresie obsługi dowiązań symbolicznych i nie byłem zadowolony z żadnego rozwiązania znalezionego w Internecie. Oto potencjalny konstruktor, który zawiera aspekty zarówno odpowiedzi Nicka, jak i Richqa. Dodatkowo będzie przechwytywał zmiany nazw (ze względu na metodę emitera) i jest tak samo agnostyczny, jak mogłem go uzyskać.

Preferuję ten program budujący, ponieważ spowoduje on utworzenie linków względem katalogu, w którym są zainstalowane. Można dodać opcję, aby wymusić link absolutnie, jak sądzę, ale nie potrzebowałem tego jeszcze.

Obecnie, jeśli system operacyjny nie obsługuje dowiązań symbolicznych, po prostu przekazuję i nic nie robię, ale można użyć os.copytree() na przykład jednak zależność staje się niepotrzebna, jeśli źródło jest katalogiem, więc emiter musiałby zrób coś wyjątkowego. Jestem gotów na wszelkie sugestie tutaj.

Można umieścić następujący kod do pliku site_scons/site_tools/symlink.py (z pustą _ startowych _.py pliki w odpowiednich miejscach). Wtedy to zrobić w pliku 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 
+0

Czy napisał wariant dla twardych linków, jak również? Chcę ten sam interfejs co wbudowany 'Install', gdzie pierwszym argumentem jest katalog. –

Powiązane problemy