Search code examples
pythonscons

scons is ignoring file destination path?


I'm seeing some weird behaviour from scons 2.3.0. Perhaps I'm just Doing It Wrong™, but this seems like it ought to be sensible...

destinations = [base_dir+'lib/', base_dir+'tree/usr/local/lib/']
boost_ver = '1.63.0'
boost_libs = (x for x in env['LIBS'] if 'boost_' in x)
# eg. 'boost_thread', 'boost_system'

for dest in destinations:
    for lib_name in boost_libs:
        lib_so = 'lib'+lib_name+'.so'
        lib_so_ver = lib_so+'.'+boost_ver

        env.Command(dest+lib_so_ver, libsrc+lib_so_ver, Copy("$TARGET","$SOURCE"))
        env.Command(dest+lib_so, dest+lib_so_ver, SymLink)

The point being to take the named libraries and copy them from libsrc to each of the destinations, recreating the non-versioned symlink as it goes. (base_dir and libsrc are absolute paths, though base_dir points inside the scons output tree.)

This works fine for a single destination, but the copying or linking never occurs for any other destinations. I've tried adding explicit dependencies with env.Depends; I've tried assigning the result to variables and using that later; nothing seems to work.

If I look at the output of --tree, invariably only the files in the first destination are listed; any subsequent ones never are. (If I change the order they're listed in, then whatever is now first is the only one listed.)

If I add an alias target for each destination, and make it Depends on the result of the commands, then both alias targets appear in the tree but only the first one has sub-items; whichever appears second always has no children.

Even if I explicitly specify the second alias target on the command line, it does nothing and prints no children in the --tree. Only by re-ordering the destinations can I get it to do anything -- and then of course the other one stops working.

Basically, it appears to be acting like only one action is possible for any given input file, and just completely ignoring any attempts to use a source file multiple times, without even so much as a warning. Which just seems nuts.


Solution

  • Turns out this wasn't an issue with Scons, but with Python. The Real Problem™ is this definition:

    boost_libs = (x for x in env['LIBS'] if 'boost_' in x)
    

    For whatever reason (clearly my python-fu is not high enough) this results in the inner for loop above executing only once for the first destination.

    The solution is to use square brackets instead:

    boost_libs = [x for x in env['LIBS'] if 'boost_' in x]
    

    This correctly executes the inner loop for every destination.