Gillespie
Gillespie

Reputation: 6561

Scons Explicit Dependency

I have a simple .cpp file that depends on jsoncpp. As a part of my build process I want Scons to untar jsoncpp (if it isn't already) and build it (if it isn't already) before attempting to compile app.cpp since app.cpp depends on some .h files that are zipped up inside of jsoncpp.tar.gz.

This is what I've tried so far:

env = Environment()
env.Program('app', 'app.cpp')
env.Depends('app.cpp', 'jsoncpp')

def build_jsoncpp(target, source, env):
    shutil.rmtree("jsoncpp", ignore_errors=True)
    mytar = tarfile.open(str(source[0]))
    mytar.extractall()
    print("Extracted jsoncpp")

env.Command("jsoncpp", ['jsoncpp.tar.gz'], build_jsoncpp)

However, Scons never prints "Extracted jsoncpp"... it always attempts to compile app.cpp and then promptly fails.

If I were using make, I could simply do something like:

app: jsoncpp.tar.gz
    # Build app

jsoncpp.tar.gz:
    # Extract and build here

And the order would be guaranteed.

Upvotes: 2

Views: 1659

Answers (2)

Kenneth E. Bellock
Kenneth E. Bellock

Reputation: 1056

You should take a look at the UnTarBuilder, as a means to extract a tarfile and have all of the extracted files be properly inserted into the dependency tree. But the following will get what you have working.

You want to avoid explicit dependencies, if possible. One of the many joys of SCons is letting it take care of your dependencies for you. So just list the source file you are depending on as one of the targets of your untar command builder.

To test this I created a tar file called jsoncpp.tar.gz containing just one file, app.cpp, with the following contents.

#include <iostream>
int main() {
    std::cout << "Hello World" << std::endl;
    return 0;
}

And updated your SConstruct to the following.

import shutil
import tarfile

env = Environment()
env.Program('app', 'app.cpp')

def build_jsoncpp(target, source, env):
    shutil.rmtree("jsoncpp", ignore_errors=True)
    mytar = tarfile.open(str(source[0]))
    mytar.extractall()
    print("Extracted jsoncpp")

env.Command(["app.cpp"], ['jsoncpp.tar.gz'], build_jsoncpp)

Because you list the required source file you depend on as a target of your command builder, it will handle the dependencies for you.

And when you run, you will see the following.

>> scons --version
SCons by Steven Knight et al.:
    script: v2.3.4, 2014/09/27 12:51:43, by garyo on lubuntu
    engine: v2.3.4, 2014/09/27 12:51:43, by garyo on lubuntu
    engine path: ['/usr/lib/scons/SCons']
Copyright (c) 2001 - 2014 The SCons Foundation

>> tree
.
├── jsoncpp.tar.gz
└── SConstruct

0 directories, 2 files

>> scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
build_jsoncpp(["app.cpp"], ["jsoncpp.tar.gz"])
Extracted jsoncpp
g++ -o app.o -c app.cpp
g++ -o app app.o
scons: done building targets.

>> tree
.
├── app
├── app.cpp
├── app.o
├── jsoncpp.tar.gz
└── SConstruct

0 directories, 5 files

>> ./app
Hello World

The reason why your code does not work is because you are listing jsoncpp as the target of your untar command builder. Which is not a file that compiling app.cpp will depend on, even if you list that action as an explicit dependency.

While this doesn't exactly answer your question, I hope it provides a solution to what you are trying to accomplish.

Upvotes: 2

dirkbaechle
dirkbaechle

Reputation: 4052

It might help if you aligned the name of your builder function with your argument to the Command() method. ;)

Upvotes: 0

Related Questions