Использование scons для грамотного программирования
Используя 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
Этот инструмент генерирует cpp-файл из nw-файла.
Но если я сделаю что-то вроде
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)
... инструмент прекратит генерировать файл cpp из файла nw. (Цель Cpp упала)
Знаете ли вы рабочий способ использовать scons для грамотного программирования?
Спасибо за чтение.
Леонард
2 ответа
Вот инструмент, который я создал. Обратите внимание на использование 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.
Похоже, вы пытаетесь добавить object
файл без фактической компиляции cpp
файл.
Я сделал небольшой пример, который должен помочь прояснить ситуацию. По сути, поскольку вы настроили суффикс и src_suffix в вызове Builder, источники и цели правильно настроены 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'])