SCons: Отдельные каталоги сборки отладки / выпуска с иерархической сборкой - PullRequest
4 голосов
/ 27 августа 2011

Я только начал учиться использовать SCons, ожидая, что это решит некоторые из моих проблем с make.Я создаю исходную иерархию, чтобы понять основы SCons.

Давайте начнем с этой структуры папок:

  • test / foo: содержит main.cpp, main.h
  • test / bar: содержит собственный main.cpp, main.h
  • test / common: содержит utils.cpp и utils.h, используемые как foo, так и bar
  • test /external / moo: исходный код некоторой внешней библиотеки, содержащей «configure», которая создает «Makefile» (без использования SCons), поэтому SCons должен вызвать «make» после «configure»;Я подозреваю, что эта часть может быть сложной, когда используются каталоги сборки
  • test / build / debug: сборка dir для отладки
  • test / build / release: сборка dir для выпуска

Вот что я хотел бы сделать:

  • Имеется два типа сборок: отладка / выпуск, где единственное отличие состоит в том, что отладка задает -DDEBUG для g ++

  • Использовать каталоги сборки, чтобы в моем исходном дереве не создавались файлы .o.Давайте назовем эти каталоги сборки "build / debug" и "build / release"

  • Возможность вызывать ./configure и make для другого проекта, который не использует SCons, с последующим связыванием libmoo.a он производит с моим проектом

  • Должны ли сборки быть абсолютно параллельными (scons -j9 для 8-ядерного?)

  • Есть некоторыенезависимый от отладки / выпуска способ указания библиотек для связи.Что-то вроде:

    env.Program(target='foo', source=['foo/main.cpp', '#build/(DEBUG_OR_RELEASE)/lib/libsomething.a'])
    

Как бы выглядели базовые файлы SConstruct / SConscript для выполнения вышеуказанного?Даже простые указатели в правильных направлениях тоже были бы хороши!

Заранее спасибо: -)

Ответы [ 3 ]

6 голосов
/ 30 августа 2011

Я делаю это для сборок для нескольких платформ (а не для отладки / выпуска), но концепция та же. Основная идея заключается в том, что вам нужно 2 файла в корне проекта - SConstruct для настройки каталогов сборки (или «альтернативных каталогов», как они известны в scons), а затем SConscript, который описывает фактические шаги сборки.

В файле SConstruct вы должны указать каталог вариантов и соответствующий ему каталог исходного кода:

SConscript(dirs='.',
           variant_dir=variant_dir,
           duplicate=False,
           exports="env")

Теперь вы хотите, чтобы option_dir зависел от флага. Вы бы использовали AddOption или Переменные, чтобы сделать это. Вот один пример полной SConstruct верхнего уровня, чтобы сделать это:

# build with `scons --debug-build` for debug.
AddOption(
    '--debug-build',
    action='store_true',
    help='debug build',
    default=False)

env = Environment()

if GetOption('debug_build'):
    env.ParseFlags('-DDEBUG')
    variant_dir = 'build/debug'
else:
    variant_dir = 'build/release'

SConscript(dirs='.',
           variant_dir=variant_dir,
           duplicate=False,
           exports="env")

AddOption проще всего использовать, но если вы используете переменные, вы можете кэшировать результат между запусками, вместо того, чтобы каждый раз произносить "scons --debug-build".

Все настройки каталогов и связанные с ними помехи находятся в SConstruct. Теперь файл SConscript довольно прост и ему не нужно беспокоиться о каталогах сборки.

Import('env')

env.Program(target='foo_prog', source=['foo/main.cpp', 'lib/libmoo.a'])
# foo_prog since foo already exists as the name of the directory...

Это самый простой способ настроить разные каталоги сборки без каких-либо странных ошибок. Он также довольно гибкий - вы можете добавлять различные сборки платформы, просто изменив «env» в скрипте верхнего уровня, не изменяя фактическое ядро ​​сборки.

Единственный гаечный ключ в работах по вашему вопросу - это способ компиляции проектов в стиле автоконф непосредственно из SCons. Самый простой способ, вероятно, с парой вызовов Command (), но SCons любит знать о входах и выходах каждого шага, так что это может быть хакерским. Кроме того, вы должны полагаться на сборку autoconf с правильной настройкой VPATH - некоторые проекты не будут работать, если вы попытаетесь скомпилировать вне исходного кода. В любом случае, способ компиляции проектов autoconf будет выглядеть примерно так:

import os
Import('env')

# get the path to the configure script from the "moo" source directory
conf = env.File('moo/configure').srcnode().abspath

# Create the "moo" build directory in the build dir
build_dir = env.Dir('.').path
moo_dir = os.path.join(build_dir, 'moo')
Mkdir(moo_dir)

# run configure from within the moo dir
env.Command('moo/Makefile', 'moo/Makefile.am',
    conf, chdir=moo_dir)
# run make in the moo dir
env.Command('moo/libmoo.a', 'moo/Makefile',
    'make', chdir=moo_dir)

env.Program(target='foo_prog', source=['foo/main.cpp', 'moo/libmoo.a'])

Выполнение шага настройки из исходного каталога, когда текущий рабочий каталог находится где-то в иерархии сборки, неудобно. Шаг make не так сложен, но все же нужно знать о текущем каталоге сборки. Поскольку вы указываете «libmoo.a» в качестве выходных данных шага make и libmoo.a в качестве входных данных для программы, все зависимости просто работают, поэтому параллельная сборка работает нормально. Параллельные сборки ломаются только тогда, когда вы слишком много выдумываете зависимости.

1 голос
/ 09 января 2016

Я знаю, что это старый вопрос, я просто хочу добавить альтернативу:

  • , чтобы иметь возможность узнать текущий вариант в файле сценария (не только в родительском)
  • и для возможности построения нескольких вариантов в одной команде scons

В файле sconstruct (родительском) мы определяем ListVariable с именем variants со спискомварианты, которые мы разрешаем (например, ['release', 'debug']).

Затем, чтобы иметь возможность узнать текущий вариант в файле sconscript, мы просто зациклили опцию, которую мы определили, и экспортировали ее в sconscript.

Я использую genv в качестве имени переменной для записи global environment :

# sconstruct
opts = Variables()
opts.AddVariables(
    ListVariable('variants', 'list of variants to build', 'all', names = ['debug','release']),
)

genv = Environment( options = opts )

for variant in genv['variants']:
    SConscript('sconscript', exports=['genv', 'variant'], variant_dir='#build/'+variant, duplicate=False)

В файле sconscript мы Clone de genv имы можем использовать переменную variant, чтобы выполнить настройку в локальной среде env:

# sconscript
Import('*')
import os.path

env = genv.Clone()    

if variant == 'debug':
    env.Append( CPPFLAGS = ['/Zi'])

src     = 'src/hello.cpp'
app,ext = os.path.splitext(os.path.basename(src))

obj = env.Object ('obj/'+app, src)
bin = env.Program('bin/'+app, obj)

Использование ListVariable позволяет нам вызывать

scons variants=release

или

scons variants=debug

или

scons variants=all

Эта последняя команда (и команда по умолчанию) создает все варианты.

0 голосов
/ 23 октября 2013

В Wiki SCons есть хорошее решение для определения нескольких режимов сборки ('debug', 'release'):

http://www.scons.org/wiki/SconstructMultiple

Вот так будет выглядеть файл richq SConstruct:

#get the mode flag from the command line
#default to 'release' if the user didn't specify
mymode = ARGUMENTS.get('mode', 'release')

#check if the user has been naughty: only 'debug' or 'release' allowed
if not (mymode in ['debug', 'release']):
    print "Error: expected 'debug' or 'release', found: " + mymode
    Exit(1)

#tell the user what we're doing
print '**** Compiling in ' + mymode + ' mode...'

env = Environment()

if mode == 'debug':
    env.Append(CPPDEFINES = ['DEBUG'])
    variant_dir = 'build/debug'
else:
    variant_dir = 'build/release'

SConscript(dirs = '.', variant_dir = variant_dir, duplicate = False, exports = "env")

Затем вы звоните scons mode=release (или просто scons, поскольку релиз является режимом по умолчанию), или scons mode=debug.

...