使用scons进行文化编程

时间:2013-10-25 17:00:19

标签: scons literate-programming noweb

使用noweb,我想从noweb输入文件生成文档文件(或源文件)**。nw

从手上我会做那样的事情:

notangle my_program.nw > my_program.cpp
g++ -c my_program.o my_program.cpp
ln -o myapp ... my_program.o ...

现在我想问一下我是否可以使用scons来实现自动化。

想象一下,我的项目目录是$ MYPROJECT。我们有“$ MYPROJECT / SConstruct”。 现在我定义了一个scons工具“tangle.py”(简称为“noweb.py”)。 这里我们有“$ MYPROJECT / site_scons / site_tools / tangle.py”

import SCons.Builder

def cpp_emit (target,source, env):
    # I dont know what to do here ... please help
    return (target,source)

# Tangle to .cpp
__noweb_tangle_builder = SCons.Builder.Builder(
    action='/usr/bin/notangle $SOURCES >$TARGET',
    suffix='.cpp',
    src_suffix='.nw',
    emitter=cpp_emit)

# -----------------------
def generate(env):
    env['BUILDERS']['tangle']= __noweb_tangle_builder

def exists(env):
    return 1

此工具从nw文件生成cpp文件。

但是,如果我做了像

这样的事情
def cpp_emit (target,source, env):
    new_source=target[0].name
    new_target=new_source.rstrip(".cpp")+".o"
    target.append(new_target)
    source.append(new_source)
    return (target, source)

我进入了一个依赖圈子。 SCons将查找并中止错误消息。

做......

def cpp_emit (target,source, env):
    new_source=target[0].name

    # someprogram.cpp -> someprogram.o
    new_target=new_source.rstrip(".cpp")+".o" 

    # lets avoid dependency cycle
    t = [] 
    t.append(new_target)
    source.append(new_source)
    # oops, we dropped target test.cpp. It wont be generated.
    return (t, source) 

...该工具将停止从nw文件生成cpp文件。 (Cpp目标下降)

您是否知道使用scons进行文字编程的工作方式?

谢谢你的阅读。


伦纳德

2 个答案:

答案 0 :(得分:1)

似乎您尝试添加object文件而不实际编译cpp文件。

我做了一个小例子,应该有助于澄清情况。基本上,由于您在对Builder的调用中配置了后缀和src_suffix,因此SCons正确设置了源和目标,并且您不需要发射器。

def cpp_emit (target,source, env):
    for t in target:
        print 'Emitter target: %s' % (t)
    for s in source:
        print 'Emitter source: %s' % (s.name)

    return (target,source)

# Tangle to .cpp
builder = Builder(
    action='/home/notroot/projects/sandbox/Emitter/builder.sh $SOURCES $TARGET',
    suffix='.cc',
    src_suffix='.nw',
    emitter=cpp_emit)

env = Environment()
env['BUILDERS']['tangle'] = builder

tangleTarget = env.tangle(target='main.cc', source='main.nw')
env.Object(source=tangleTarget)

这是输出:

$ scons
scons: Reading SConscript files ...
Emitter target: main.cc
Emitter source: main.nw
scons: done reading SConscript files.
scons: Building targets ...
/home/notroot/projects/sandbox/Emitter/builder.sh main.nw main.cc
g++ -o main.o -c main.cc
scons: done building targets.

$ scons -c
scons: Reading SConscript files ...
Emitter target: main.cc
Emitter source: main.nw
scons: done reading SConscript files.
scons: Cleaning targets ...
Removed main.cc
Removed main.o
scons: done cleaning targets.

我做了以下操作让Builder生成cc文件并进行编译,但它不会清除object文件。

import os

def cpp_emit(target,source, env):
    for s in source:
        print 'Emitter source: %s' % (s.name)
    for t in target:
        print 'Emitter target: %s' % (t)

    return (target,source)

def build_function(target, source, env):
    # Code to build "target" from "source"
    for t in target:
        print 'Builder target: %s' % (t.name)
    for s in source:
        print 'Builder source: %s' % (s.name)

    buildStr='/home/notroot/projects/sandbox/Emitter/builder.sh %s %s' % (source[0].name, target[0].name)
    os.system(buildStr)

    trgt = env.Object(source=target[0])

    # return 0 or None upon success
    return None

# Tangle to .cc and .o
builder = Builder(
    action=build_function,
    suffix='.cc',
    src_suffix='.nw',
    emitter=cpp_emit)

env = Environment()
env['BUILDERS']['tangle'] = builder

tangleTarget = env.tangle(target='main.cc', source='main.nw')

这是输出:

$ scons
scons: Reading SConscript files ...
Emitter source: main.nw
Emitter target: main.cc
scons: done reading SConscript files.
scons: Building targets ...
build_function(["main.cc"], ["main.nw"])
Builder target: main.cc
Builder source: main.nw
scons: done building targets.

$ scons -c
scons: Reading SConscript files ...
Emitter source: main.nw
Emitter target: main.cc
scons: done reading SConscript files.
scons: Cleaning targets ...
Removed main.cc
scons: done cleaning targets.

在第二个示例中,如果将目标文件添加为目标,则会出现以下错误(正确地说是这样)

scons: *** [main.cc] Multiple ways to build the same target were specified for: main.o  (from ['main.nw'] and from ['main.cc'])

答案 1 :(得分:1)

这是我创建的工具。请注意使用env['BUILDERS']['Object'].src_builder允许env.Program()接受noweb文件。

# site_cons/site_tools/tangle.py
import SCons.Builder

__all__=['generate', 'exists']

tangle_builder = SCons.Builder.Builder(
    action='$NOTANGLE $SOURCES > $TARGET',
    suffix = '.cpp',
    src_suffix = '.nw')

def generate(env):
    env['NOTANGLE'] = exists(env)
    env['BUILDERS']['Tangle'] = tangle_builder
    if 'Object' in env['BUILDERS']:
        env['BUILDERS']['Object'].src_builder.append('Tangle')

def exists(env):
    if 'NOTANGLE' in env:
        return env['NOTANGLE']
    return env.WhereIs('notangle')

及其用途:

# SConstruct
env = Environment(tools=['default', 'tangle'])
env.Program('my_program.nw')

以上是SConstruct的输出:

$ scons -Q
/usr/bin/notangle my_program.nw > my_program.cpp
g++ -o my_program.o -c my_program.cpp
g++ -o my_program my_program.o
$ scons -c
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Cleaning targets ...
Removed my_program.cpp
Removed my_program.o
Removed my_program
scons: done cleaning targets.