Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SCons: How to call a self defined python function in scons script and make right dependency

Tags:

python

scons

I write a python function such as replace strings and called in scons script.

def Replace(env, filename, old, new):
    with open(filename,"r+") as f:
    d = f.read()
    d = d.replace(old, new)
    f.truncate(0)
    f.seek(0)
    f.write(d)
    f.close()
env.AddMethod(Replace,'Replace')

In SConscript

lib = env.SharedLibrary('lib', object, extra_libs)
tmp = env.Command([],[],[env.Replace(somefile, 'A', 'b')] )
env.Depends(tmp,lib )

What i expect is to run the Replace() method after the lib built. but scons always run the Replace() in the first round script parsing phrase. it seems i am missing some dependency.

like image 814
firer Avatar asked Oct 10 '22 10:10

firer


1 Answers

I believe that you're probably looking for builders that execute python functions.

The tricky bit is that SCons doesn't really want to work the way you're forcing it to. Build actions should be repeatable and non-destructive, in your code you're actually destroying the original contents of somefile. Instead, you can use the target/source paradigm and some kind of template file to achieve the same result.

import os
import re

def replace_action(target, source, env):
    # NB. this is a pretty sloppy way to write a builder, but
    #     for things that are used internally or infrequently
    #     it should be more than sufficient
    assert( len(target) == 1 )
    assert( len(source) == 1 )
    srcf = str(source[0])
    dstf = str(target[0])
    with open(srcf, "r") as f:
        contents = f.read()
        # In cases where this builder fails, check to make sure you
        # have correctly added REPLST to your environment
        for old, new in env['REPLST']:
            contents = re.sub( old, new, contents )
        with open( dstf, "w") as outf:
            outf.write(contents)

replace_builder = Builder(action = replace_action)

env = Environment( ENV = os.environ )
env.Append( BUILDERS = {'Replace' : replace_builder } )
b = env.Replace( 'somefile', ['somefile.tmpl'], REPLST=[('A','b')] )
lib = env.SharedLibrary('lib', object + [b], extra_libs )

Note that in my testing, the replace function wasn't playing nicely with multi-line data, so I've just swapped to using full regular expressions (re.sub). This is probably slower, but offers significantly more flexibility.

like image 110
Andrew Walker Avatar answered Oct 22 '22 13:10

Andrew Walker