Wednesday, June 24, 2015

Correct SCons variantdir and emitters

I'm using SCons to build my C++ stuff across platforms and as usual, my build config is gradually getting more complex. I always like to have build output in a separate directory, for cleanliness. I use a VariantDir command to do that. The problem is that variant dirs are always a bit tricky to understand and do properly, so here are some notes on how to avoid screwing up.

Use the Node, Luke!

Items in the SCons build tree are represented as Nodes, not only plain file names. In the case of an output into your VariantDir, the node will remember the output path (such as build/file.o) as well as the original source input path (file.o) and for both of these, it also knows the absolute path. These properties are something you'll always want to see when debugging.

print n.abspath

print n.srcnode().abspath

See the section File and Directory Nodes for specific property documentation.

Use the Emitters, Leia!

SCons is a little obsessive and really likes to keep track of everything. It likes to know what files come in and what will fall out. With this information, it can make sure everything is properly rebuilt on any change and it can nicely clean your directory with the -c switch.

If you need to call some external command, it's a good idea to provide this information to SCons so that it knows what will happen. In my build, I need to generate header files for JNI classes using javah. The built-in tool doesn't really work for me because it needs Java compilation first so I ended up writing my own.

The file and class names in Java are tightly coupled, you can pretty much just do 

file = clsname.replace('.', '/') + '.java'

to find the source file for a class. I'm using this fact to make my emitter. I take great care to have the correct .java files listed as the source for the Builder. Having only the directory just doesn't cut it, I have to Glob() in subdirs too. To have a good idea of what's happening, I first debug-print my source and target nodes in the emitter:

def emit_javah(target, source, env):
    print 'emit source', [x.abspath for x in source]
    print 'emit target orig', [x.abspath for x in target]

The emitted target node doesn't need to have an absolute path or contain the VariantDir name, that should be handled by SCons. Just imagine you are building in the same directory and return a relative path.


  1. Really this article is truly one of the best in article history and am a collector of old "items" and sometimes read new items if i find them interesting which is one that I found quite fascinating and should be part of my collection. Very good work!
    Data Scientist Course in Gurgaon

  2. I am hoping the same best effort from you in the future as well and in fact your creative writing skills has inspired me.
    Data Science Course near me

  3. I would like to say that this blog really convinced me to do it and thanks for informative post and bookmarked to check out new things of your post…
    Data Science Institute in Noida

  4. Nice Post thank you very much for sharing such a useful information and will definitely saved and revisit your site and i have bookmarked to check out new things frm your post.
    Data Science Course

  5. Just a shine from you here and have never expected anything less from you and have not disappointed me at all which i guess you will continue the quality work. Great post.
    Data Science Training in Gurgaon

  6. Interesting post. which i wondered about this issue so thanks for posting and very good article which is a really very nice and useful article. Thank you
    Data Science Course in Noida