views:

38

answers:

2

I'm trying to build an application I've downloaded which uses the SCONS "make replacement" and the Fast Light Tool Kit Gui.

The SConstruct code to detect the presence of fltk is:

guienv = Environment(CPPFLAGS = '')
guiconf = Configure(guienv)

if not guiconf.CheckLibWithHeader('lo', 'lo/lo.h','c'):
    print 'Did not find liblo for OSC, exiting!'
    Exit(1)

if not guiconf.CheckLibWithHeader('fltk', 'FL/Fl.H','c++'):
    print 'Did not find FLTK for the gui, exiting!'
    Exit(1)

Unfortunately, on my (Gentoo Linux) system, and many others (Linux distributions) this can be quite troublesome if the package manager allows the simultaneous install of FLTK-1 and FLTK-2.

I have attempted to modify the SConstruct file to use fltk-config --cflags and fltk-config --ldflags (or fltk-config --libs might be better than ldflags) by adding them like so:

guienv.Append(CPPPATH = os.popen('fltk-config --cflags').read())
guienv.Append(LIBPATH = os.popen('fltk-config --ldflags').read())

But this causes the test for liblo to fail! Looking in config.log shows how it failed:

scons: Configure: Checking for C library lo...
gcc -o .sconf_temp/conftest_4.o -c "-I/usr/include/fltk-1.1 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_THREAD_SAFE -D_REENTRANT"
gcc: no input files
scons: Configure: no

How should this really be done?

And to complete my answer, how do I remove the quotes from the result of os.popen( 'command').read()?

EDIT The real question here is why does appending the output of fltk-config cause gcc to not receive the filename argument it is supposed to compile?

+1  A: 

This is quite a complex problem with no quick answer

I have referred to the instructions for using pkg-config with scons at http://www.scons.org/wiki/UsingPkgConfig. The following question is also helpful http://stackoverflow.com/questions/377017/test-if-executable-exists-in-python.

But we need to go a little bit further with these.

So after much investigation I discovered os.popen('command').read() does not trim the trailing newline '\n' which is what caused the truncation of the arguments sent to GCC.

We can use str.rstrip() to remove the trailing '\n'.

Secondly, as config.log shows, the arguments which fltk-config provides, SCONS wraps up in double quotes before giving them to GCC. I'm not exactly sure of the specifics but this is because the output of fltk-config (via os.popen) contains space characters.

We can use something like strarray = str.split(" ", str.count(" ")) to split the output into substrings where the space characters occur.

It is also worth noting that we were attempting to append the fltk-config --ldflags to the wrong variable within the GUI environment, they should have been added to LINKFLAGS.

Unfortunately this is only half way to the solution.

What we need to do is:

  • Find the full path of an executable on the system
  • Pass arguments to an executable and capture its output
  • Convert the output into a suitable format to append to the CPPFLAGS and LINKFLAGS.

So I have defined some functions to help...

1) Find full path of executable on system: ( see: http://stackoverflow.com/questions/377017/test-if-executable-exists-in-python )

def ExecutablePath(program):
    def is_exe(fpath):
        return os.path.exists(fpath) and os.access(fpath, os.X_OK)
    fpath, fname = os.path.split(program)
    if fpath:
        if is_exe(program):
            return program
    else:
        for path in os.environ["PATH"].split(os.pathsep):
            exe_file = os.path.join(path, program)
            if is_exe(exe_file):
                return exe_file
    return None

1b) We also need to test for executable existence:

def CheckForExecutable(context, program):
    context.Message( 'Checking for program %s...' %program )
    if ExecutablePath(program):
        context.Result('yes')
    return program
    context.Result('no')

2) Pass arguments to executable and place the output into an array:

def ExecutableOutputAsArray(program, args):
    pth = ExecutablePath(program)
    pargs = shlex.split('%s %s' %(pth, args))
    progout = subprocess.Popen( pargs , stdout=subprocess.PIPE).communicate()[0]
    flags = progout.rstrip()
    return flags.split(' ', flags.count(" "))

Some usage:

guienv.Append(CPPFLAGS =  ExecutableOutputAsArray('fltk-config', '--cflags') )
guienv.Append(LINKFLAGS = ExecutableOutputAsArray('fltk-config', '--ldflags') )
guienv.Append(LINKFLAGS = ExecutableOutputAsArray('pkg-config', '--libs liblo') )
James Morris
+1  A: 

There are 2 similar ways to do this: 1)

conf = Configure(env)
status, _ = conf.TryAction("fltk-config --cflags")
if status:
  env.ParseConfig("fltk-config --cflags")
else:
  print "Failed fltk"

2)

  try:
    env.ParseConfig("fltk-config --cflags")
  except (OSError):
    print 'failed to run fltk-config you sure fltk is installed !?'
    sys.exit(1)
imran.fanaswala
Oh boy. It works. If you add these into conditions for testing if the above two lines succeed, I will accept this as the correct answer. Cheers.
James Morris
I've tried this and it seems to work:`if not guienv.ParseConfig("fltk-config --cflags"): print 'failed to run fltk-config you sure fltk is installed !?' Exit(1)`
James Morris
But I'd just like to make sure that is correct, as I don't have a system *without* FLTK installed to test right now.
James Morris
Imran, thanks for these, I've tried both, but have only succeeded in getting the first version to work.
James Morris