[Scons-users] Linking a subset of common object files

Viktor Dick viktordick86 at gmail.com
Thu Apr 28 08:14:01 EDT 2016


On 2016-04-28 09:53, Ale Strooisma wrote:
> This makes me think: this is precisely the kind of problem I use a smart
> build system for! Now I realize that figuring out the dependencies for
> linking is non-trivial. I noticed however that for each object file that
> needs to be linked, the main source file depends (directly or
> indirectly) on the a header file with the same name, save for the
> extension. And a dependency tree for those header files exists. Is there
> a way to use this?

Hi,
I attached my solution, reduced to the relevant parts. Maybe you find it
helpful.

Regards,
Viktor
-------------- next part --------------
######## Initialization: set up environments and parse options #######
import os, subprocess, threading

#create the environments (with compiler flags etc.)
env = Environment()

#Now this is somewhat of a hack. The project follows the convention that if
# some function is declared in foo.h, the implementation is found in foo.cpp.
# Therefore, the list of object files that have to be linked together to create
# a specific executable can be obtained automatically. This complete tree has to be
# obtained with each call of scons, since the build tree has to be complete before the first
# element is built. Therefore, as a compromise, the scan for each needed file is done in a
# separate thread to speed things up.

#mapping of files that also have to be linked for each source file
deps = dict()
started = set() #set of files for which a scan was already started
lock = threading.Lock()

#we use 'g++ -MM' to obtain the list of .h files that are included
args=["g++","-MM", "-Isrc"]
class Scan(threading.Thread):
    def __init__(self,filename):
        threading.Thread.__init__(self)
        self.filename = filename
    def run(self):
        global started
        out = subprocess.Popen(args+[self.filename], stdout=subprocess.PIPE,universal_newlines=True).communicate()[0]
        files = [f[:-1]+"cpp" for f in out.split() if f.endswith(".h")]
        files = set([f for f in files if f != self.filename and os.path.exists(f)])
        subthreads = [] #new files that were found and will be scanned after adding them to the dict
        with lock:
            deps[self.filename] = set(files) #only level 1 dependencies, no recursion yet
            files -= started #only those that have not been started yet
            started |= files
        for f in files:
            st = Scan(f)
            st.start()
            subthreads.append(st)
        for st in subthreads:
            st.join()
            
threads = []
progs = Glob('src/main_*.cpp', strings=True)

# start scan with main files, recursing further down
for f in progs:
    t = Scan(f)
    threads.append(t)
    t.start()
for t in threads:
    t.join()

# now collect everything that needs to be linked for some target
def collect(f):
    result = set()
    todo = set([f])
    while len(todo)>0:
        e = todo.pop()
        if e in deps and e not in result:
            todo.update(deps[e])
        result.add(e)
    return list(result)


for f in progs:
    b = 'bin/'+os.path.basename(f)[5:-4]
    env.Program(b, collect(f))
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: OpenPGP digital signature
URL: <https://pairlist4.pair.net/pipermail/scons-users/attachments/20160428/8be0a7a2/attachment.pgp>


More information about the Scons-users mailing list