开发者

Why does output of fltk-config truncate arguments to gcc?

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 addi开发者_运维知识库ng 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?


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)


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 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: 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') )
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜