2012-01-19 53 views
1

Im新的scons和我有問題scons依賴 在一個層次結構與變體目錄建立。scons依賴問題的層次結構與變體dirs

林能再現一個包含所SConscript目錄下 2子目錄(moduleA和moduleB)爲減少環境問題如下:

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

下面是需要做什麼樣的流程:

  1. moduleA執行shell腳本:conf2cc,輸入:$ projRootDir/file.conf,輸出:moduleA/$ variantDir/source.cc
  2. moduleA編譯source.cc並創建moduleA/$ variantDir /李bmoduleA.a
  3. moduleB需要moduleA/$ variantDir/source.cc複製到moduleB/source.cc
  4. moduleB需要編寫moduleB/source.cc和moduleB/fileB.cc到其 庫libmoduleB.a

這是完全可能的,我在這裏做了幾件事情錯了。例如,我知道 林在moduleA司令部()不使用$ TARGET/$ SOURCE,但目的多數民衆贊成,因爲 腳本需要的絕對路徑名,並且scons的犯規刪除前面的「#」

問題我有的是moduleB(上面的步驟3)中的Command()構建器從不執行。

這裏是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:

任何幫助將不勝感激!

布雷迪

[email protected]:~/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. 

回答

0

我建議您使用錯誤的依賴項和文件名問題。

可能是module_dir和moduleB的源文件存在問題,您使用Command來生成#/ moduleB/source.cc,但在sourceFiles中有'source.cc'。

因此,辦法幫助你可能是正確的moduleB 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) 

,並嘗試使用命令狀源文件。代替文件名。這看起來更正確。 moduleA:

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

moduleB:

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

libNode = env.Library(target = 'moduleB', source = ['fileB.cc', cmdNode]) 
+0

好極了!這按預期工作。我喜歡SCons指出隱含的依賴關係,而不必使用Depends()函數顯式列出它們。非常感謝! – Brady

+0

但有一點需要注意:moduleB/source.cc的目標文件放在moduleB中,而不是在moduleB的variant_dir中,而fileB.o確實放在了variant_dir中。這是爲什麼?我怎樣才能將source.o放置在variant_dir中? – Brady

+0

我想通過指定moduleB source.cc文件,如下所示: 'sourceTarget = os.path.join('#moduleB',env ['variantDir'],'source.cc')'現在來源.cc和source.o文件放置在variant_dir中。 – Brady

0

我找到了一個解決問題的辦法,但我真的不明白爲什麼它的工作原理。

如果我添加一個調用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不解決libNode在cmdNode上具有的moduleB/SConscript中的依賴性。

0

我的解決辦法:使用

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)