2010-08-20 5 views
10

J'utilise SCons pour construire un projet et j'ai besoin d'ajouter un lien symbolique vers un fichier qu'il installe via env.Install. Quelle commande (s) fera un lien qui est l'équivalent de courir ln -s sur la ligne de commande?Comment créer un lien symbolique avec SCons?

Répondre

8

SCons n'a pas une commande de lien symbolique dédié, mais vous pouvez utiliser os.symlink(src, dst) du module os Python:

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) 

Cela peut ne pas fonctionner correctement sur Windows, je ne l'ai essayé sur Linux.

+0

Pour une raison quelconque, il ne fonctionne pas lorsque vous essayez de créer un lien symbolique dans un subdir, comme "env.Command (saveur + '/ Ressources', 'src/Ressources', SymLink)" où saveur est 'debug' ou 'release'. – Septagram

+1

@Septagram s'il vous plaît voir mon edit –

+0

Ne fonctionne pas pour les fichiers installés – RzR

1

Cela crée un constructeur pour effectuer le travail:

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) 

Encore une fois, cette solution est pour Linux.

+1

Malheureusement, il ne fonctionne pas bien (du tout) sur les répertoires: "TypeError: Répertoire/home/septi/Dropbox/Code/StreetCleaner/src/Ressources trouvées où le fichier attendu .: " – Septagram

+0

@Septagram: Comment réparer le problème de répertoire? –

+0

@ Nordlöw, désolé, mais cela fait un moment et je ne sais pas :(S'il vous plaît essayer d'autres réponses et commenter si vous trouvez quelque chose – Septagram

7

Il semble y avoir peu de progrès dans le code de base SCons pour le support de lien symbolique et je n'ai pas été satisfait d'une solution que j'ai trouvée sur le web. Voici un générateur potentiel qui incorpore des aspects des réponses de Nick et Richq. En outre, il va attraper les changements de nom (en raison de la méthode de l'émetteur) et est aussi agnostique que possible.

Je préfère ce générateur car il fera des liens par rapport au répertoire dans lequel ils sont installés. On pourrait ajouter une option pour forcer le lien à être absolu je suppose, mais je n'ai pas besoin ou je voulais encore.

Actuellement, si le système d'exploitation ne supporte pas les liens symboliques, je passe et je ne fais rien, mais on pourrait utiliser os.copytree() par exemple mais la dépendance devient désordonnée si la source est un répertoire donc l'émetteur devrait faire quelque chose de fantaisie. Je suis prêt pour toute suggestion ici.

On peut mettre le code suivant dans le fichier site_scons/site_tools/symlink.py (avec blanc _ initialisation _.py fichiers dans les endroits appropriés). Ensuite, faites ceci dans le fichier 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

plus Avez-vous écrit un variante pour les liens durs, aussi? Je veux la même interface que builtin 'Install' où le premier argument est un répertoire. –

Questions connexes