проблемы зависимости scons в иерархической сборке с вариантами dirs - PullRequest
1 голос
/ 19 января 2012

Я новичок в scons и у меня проблемы с зависимостями scons в иерархической сборке с каталогом вариантов.

Я могу воспроизвести проблему в сокращенной среде, которая состоит из 2 подкаталогов в каталоге SConscript (moduleAи moduleB) следующим образом:

.
|-- SConstruct
|-- file.conf
|-- moduleA
|   |-- SConscript
|   `-- conf2cc
`-- moduleB
    |-- SConscript
    `-- fileB.cc

Вот последовательность действий, которые необходимо выполнить:

  1. moduleA выполняет сценарий оболочки: conf2cc, input: $ projRootDir / file.conf, output: moduleA / $ variableDir / source.cc
  2. moduleA компилирует source.cc и создает moduleA / $ variableDir / libmoduleA.a
  3. moduleB необходимо скопировать moduleA / $ optionDir / source.cc to moduleB / source.cc
  4. moduleB необходимо скомпилировать moduleB / source.cc и moduleB / fileB.cc в свою библиотеку libmoduleB.a

Вполне возможно, что я делаю несколькоздесь что-то не так.Например, я знаю, что я не использую $ TARGET / $ SOURCE в moduleA Command (), но это нарочно, поскольку скрипту нужны абсолютные пути и scons не удаляет ведущий '#'

ПроблемаУ меня есть это Command () в модуле B (шаг 3 выше) никогда не выполняется.

Вот файлы SConstruct и SConscript:

Sconstruct

import os

env = Environment()
env['variantDir'] = 'linux'  # for this example, just make variantDir = linux
modules = ['moduleA', 'moduleB']

for dir in modules:
    SConscript(
        os.path.join(dir, 'SConscript'),
        variant_dir = os.path.join(dir, env['variantDir']),
        exports = ['env'],
        duplicate = 0)

moduleA /Sconscript

import os

Import('env')

scriptInput   = '#file.conf'
sourceFile    = os.path.join('#moduleA', env['variantDir'],  'source.cc')
conf2ccScript = File('#moduleA/conf2cc').abspath

# The script needs abspaths for input and output, not the scons '#' prepended
# the script syntax is: script <inputFile> <outputFile>
cmd = '%s %s %s' % (conf2ccScript, File(scriptInput).abspath, File(sourceFile).abspath)

# Generate source.cc file based on file.conf
conf2ccNode = env.Command(target = sourceFile,
                          source = scriptInput,
                          action = cmd)

libNode = env.Library(target = 'moduleA', source = sourceFile)
env.Depends(libNode, conf2ccNode)

moduleB / Sconscript

import os

Import('env')

sourceFiles = ['fileB.cc', 'source.cc']

# Get the source.cc file
externalSourceFile  = os.path.join('#moduleA', env['variantDir'], 'source.cc')
sourceTarget        = os.path.join('#moduleB', 'source.cc')

cmdNode = env.Command(target = sourceTarget,
                      source = externalSourceFile,
                      action = Copy('$TARGET', '$SOURCE'))

libNode = env.Library(target = 'moduleB', source = sourceFiles)
env.Depends(libNode, cmdNode)

Вот вывод при выполнении scons:

Любая помощь будет принята с благодарностью!

Брейди

notroot@ubuntu:~/projects/sconsTest/sconsTestHierDeps$ scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
/home/notroot/projects/sconsTest/sconsTestHierDeps/moduleA/conf2cc /home/notroot/projects/sconsTest/sconsTestHierDeps/file.conf /home/notroot/projects/sconsTest/sconsTestHierDeps/moduleA/linux/source.cc
g++ -o moduleA/linux/source.o -c moduleA/linux/source.cc
ar rc moduleA/linux/libmoduleA.a moduleA/linux/source.o
ranlib moduleA/linux/libmoduleA.a
g++ -o moduleB/linux/fileB.o -c moduleB/fileB.cc
scons: *** [moduleB/linux/source.o] Source `moduleB/source.cc' not found, needed by target `moduleB/linux/source.o'.
scons: building terminated because of errors.

Ответы [ 3 ]

0 голосов
/ 27 января 2012

Я предлагаю проблему в неправильной зависимости, какие вы используете и имена файлов.

Может быть проблема в option_dir и исходных файлах для moduleB, вы используете Command для генерации # / moduleB / source.cc, но в sourceFiles у вас есть 'source.cc'.

Итак, одним из способов помочь вам может быть правильный модуль B SConscript:

# Get the source.cc file
externalSourceFile  = os.path.join('#moduleA', env['variantDir'], 'source.cc')
sourceTarget        = os.path.join('#moduleB', 'source.cc')

sourceFiles = ['fileB.cc', sourceTarget]

cmdNode = env.Command(target = sourceTarget,
                      source = externalSourceFile,
                      action = Copy('$TARGET', '$SOURCE'))

libNode = env.Library(target = 'moduleB', source = sourceFiles)

И попробуйте использовать Command как исходный файл.вместо имени файла.Это выглядит более правильно.модуль A:

conf2ccNode = env.Command(target = sourceFile,
                          source = scriptInput,
                          action = cmd)
libNode = env.Library(target = 'moduleA', source = conf2ccNode)

модуль B:

cmdNode = env.Command(target = sourceTarget,
                      source = externalSourceFile,
                      action = Copy('$TARGET', '$SOURCE'))

libNode = env.Library(target = 'moduleB', source = ['fileB.cc', cmdNode])
0 голосов
/ 12 июня 2012

Мое решение:

def CreateLibrary(env, name, sources, shared=True):

    def GetObjectFile(sourceFileName):

        def GetFileNameWithoutExtension(path):
            return os.path.splitext(os.path.basename(path))[0]

        def IsFileNameExist(newFileName):
            return fileNames.count(newFileName) > 0

        sourceAbsPath = os.path.abspath(sourceFileName)
        fileNameWithoutExtension = GetFileNameWithoutExtension(sourceAbsPath)
        destFileName = fileNameWithoutExtension
        attemptNumber = 0
        while IsFileNameExist(destFileName):
            attemptNumber += 1
            destFileName = fileNameWithoutExtension + str(attemptNumber)
        fileNames.append(destFileName)
        destFilePath = os.path.join(compilationDirRoot, destFileName)
        if shared:
            return env.SharedObject(destFilePath, sourceAbsPath)
        else:
            return env.StaticObject(destFilePath, sourceAbsPath)

    objFiles = []
    fileNames = []
    compilationDirRoot = Dir('.').abspath
    for src in sources:
        if isinstance(src,str):
            objFiles.append(GetObjectFile(src))
        elif isinstance(src, SCons.Node.FS.File):
            objFiles.append(GetObjectFile(SCons.Node.FS.File.rstr(src)))
        else:
            for f in src:
                objFiles.append(GetObjectFile(str(f)))
    if shared:
        return env.SharedLibrary(name, objFiles, no_import_lib=True)
    else:
        return env.StaticLibrary(name, objFiles)

Пример использования:

theora = CreateLibrary(env, 'theora', sources)
0 голосов
/ 23 января 2012

Я нашел решение проблемы, но я не совсем понимаю, почему это работает.

Если я добавлю вызов env.Default () с нужными мне целями, то это сработает.Таким образом, файлы SConscript будут выглядеть следующим образом:

moduleA / Sconscript

import os

Import('env')

scriptInput   = '#file.conf'
sourceFile    = os.path.join('#moduleA', env['variantDir'],  'source.cc')
conf2ccScript = File('#moduleA/conf2cc').abspath

# The script needs abspaths for input and output, not the scons '#' prepended
# the script syntax is: script <inputFile> <outputFile>
cmd = '%s %s %s' % (conf2ccScript, File(scriptInput).abspath, File(sourceFile).abspath)

# Generate source.cc file based on file.conf
conf2ccNode = env.Command(target = sourceFile,
                          source = scriptInput,
                          action = cmd)

libNode = env.Library(target = 'moduleA', source = sourceFile)
env.Depends(libNode, conf2ccNode)
env.Default([conf2ccNode, libNode])

moduleB / Sconscript

import os

Import('env')

sourceFiles = ['fileB.cc', 'source.cc']

# Get the source.cc file
externalSourceFile  = os.path.join('#moduleA', env['variantDir'], 'source.cc')
sourceTarget        = os.path.join('#moduleB', 'source.cc')

cmdNode = env.Command(target = sourceTarget,
                      source = externalSourceFile,
                      action = Copy('$TARGET', '$SOURCE'))

libNode = env.Library(target = 'moduleB', source = sourceFiles)
env.Depends(libNode, cmdNode)
env.Default(cmdNode, libNode)

Так что возникает вопрос: если я неуказать цели по умолчанию (), и существует более одной цели, как scons узнает, какую из них построить?

Кроме того, я до сих пор не понимаю, почему scons не разрешает зависимость в moduleB / SConscript, которую libNode имеет в cmdNode.

...