2012-01-19 2 views
1

scons 종속성에 문제가 있으며 변형 디렉터리가있는 계층 구조 빌드에서 에 문제가 있습니다.변형 된 디렉터리가있는 계층 적 빌드에서 scons 종속성 문제

임 2 SConscript 디렉토리 아래에 하위 디렉토리 (moduleA 및 moduleB) 등으로 구성되어 감소 된 환경에서 문제를 재현 할 수는 다음과 같습니다 여기

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

가해야할 일들의 흐름입니다 : conf2cc 입력 : $ projRootDir/file.conf 출력 : moduleA/$ variantDir/source.cc
  • moduleA가 source.cc를 컴파일하고 생성 moduleA/$ variantDir/리

    1. moduleA 쉘 스크립트를 실행 bmoduleA.a
    2. moduleB은/source.cc
    3. moduleB가 라이브러리에 moduleB/source.cc 및 moduleB/fileB.cc을 컴파일 할 필요가
    4. libmoduleB.a
    5. moduleB에 moduleA/$ variantDir가/source.cc을 복사 할 필요가

    여기에서 몇 가지 일을 잘못하고 있다는 전적으로 가능합니다. 예를 들어, 나는 는 moduleA 명령()에서 $ TARGET/$ 소스를 사용하지 않는 임 알고 있지만 목적에 그게 전부는 스크립트는 절대 경로 이름을 필요로하기 때문에, 그리고 SCons는이 선도 '#의'

    문제를 제거 나던 모듈 B에서 Command() 빌더 (위의 3 단계)가 실행되지 않습니다.

    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) 
    

    출력 할 때이다 : 여기

    는 SConstruct 및 SConscript 파일들이다 나는 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

    내가 잘못 당신이 무엇을 사용 종속 및 파일 이름에 문제를 제시한다.

    이 moduleB에 대한 variant_dir 및 소스 파일에 문제가있을 수 있습니다, 당신은 #/moduleB/source.cc를 생성하는 명령을 사용할 수 있지만 소스 파일에 당신은 '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) 
    

    그리고 소스 파일과 같은 명령을 사용하려고합니다. 대신 filename. 더 정확한 것 같습니다. 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에 있고 variantBody에 대한 variant_dir에는 없습니다. 반면에 fileB.o는 실제로 variant_dir에 있습니다. 왜 그런가요? 어떻게하면 source.o를 variant_dir에 넣을 수 있습니까? 다음 – Brady

    +0

    는 I는 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는이 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)