2015-09-07 77 views
4

我的waf項目有兩個依賴項,使用CMake構建。 我想要做的,是繼在WAF git倉庫發現dynamic_build3例如,創建一個工具,它派生CMake和編譯成功後,執行安裝到WAF的輸出子目錄:將Waf目標鏈接到由外部構建系統生成的庫(CMake)

@extension('.txt') 
def spawn_cmake(self, node): 
    if node.name == 'CMakeLists.txt': 
     self.cmake_task = self.create_task('CMake', node) 
     self.cmake_task.name = self.target 


@feature('cmake') 
@after_method('process_source') 
def update_outputs(self): 
    self.cmake_task.add_target() 


class CMake(Task.Task): 
    color = 'PINK' 

    def keyword(self): 
     return 'CMake' 

    def run(self): 
     lists_file = self.generator.source[0] 
     bld_dir = self.generator.bld.bldnode.make_node(self.name) 
     bld_dir.mkdir() 

     # process args and append install prefix 
     try: 
      cmake_args = self.generator.cmake_args 
     except AttributeError: 
      cmake_args = [] 
     cmake_args.append(
      '-DCMAKE_INSTALL_PREFIX={}'.format(bld_dir.abspath())) 

     # execute CMake 
     cmd = '{cmake} {args} {project_dir}'.format(
      cmake=self.env.get_flat('CMAKE'), 
      args=' '.join(cmake_args), 
      project_dir=lists_file.parent.abspath()) 
     try: 
      self.generator.bld.cmd_and_log(
       cmd, cwd=bld_dir.abspath(), quiet=Context.BOTH) 
     except WafError as err: 
      return err.stderr 

     # execute make install 
     try: 
      self.generator.bld.cmd_and_log(
       'make install', cwd=bld_dir.abspath(), quiet=Context.BOTH) 
     except WafError as err: 
      return err.stderr 

     try: 
      os.stat(self.outputs[0].abspath()) 
     except: 
      return 'library {} does not exist'.format(self.outputs[0]) 

     # store the signature of the generated library to avoid re-running the 
     # task without need 
     self.generator.bld.raw_deps[self.uid()] = [self.signature()] + self.outputs 

    def add_target(self): 
     # override the outputs with the library file name 
     name = self.name 
     bld_dir = self.generator.bld.bldnode.make_node(name) 
     lib_file = bld_dir.find_or_declare('lib/{}'.format(
      (
       self.env.cshlib_PATTERN 
       if self.generator.lib_type == 'shared' else self.env.cstlib_PATTERN 
      ) % name)) 
     self.set_outputs(lib_file) 

    def runnable_status(self): 
     ret = super(CMake, self).runnable_status() 
     try: 
      lst = self.generator.bld.raw_deps[self.uid()] 
      if lst[0] != self.signature(): 
       raise Exception 
      os.stat(lst[1].abspath()) 
      return Task.SKIP_ME 
     except: 
      return Task.RUN_ME 
     return ret 

我會喜歡產卵的工具,然後通過調用bld.read_shlib() WAF的目標鏈接到安裝的庫,這是我執行使用「假庫」機制:

def build(bld): 
    bld.post_mode = Build.POST_LAZY 
    # build 3rd-party CMake dependencies first 
    for lists_file in bld.env.CMAKE_LISTS: 
     if 'Chipmunk2D' in lists_file: 
      bld(
       source=lists_file, 
       features='cmake', 
       target='chipmunk', 
       lib_type='shared', 
       cmake_args=[ 
        '-DBUILD_DEMOS=OFF', 
        '-DINSTALL_DEMOS=OFF', 
        '-DBUILD_SHARED=ON', 
        '-DBUILD_STATIC=OFF', 
        '-DINSTALL_STATIC=OFF', 
        '-Wno-dev', 
       ]) 
    bld.add_group() 

    # after this, specifying `use=['chipmunk']` in the target does the job 
    out_dir = bld.bldnode.make_node('chipmunk') 
    bld.read_shlib(
     'chipmunk', 
     paths=[out_dir.make_node('lib')], 
     export_includes=[out_dir.make_node('include')]) 

我覺得這是* 非常難看 *因爲:

  1. 在最終目標的鏈接階段的花栗鼠庫需要ONLY,沒有理由阻止整個構建(通過使用Build.POST_LAZY模式和bld.add_group()),但疏通它使read_shlib()失敗。想象一下,如果在此之前還有某種git clone任務...
  2. build()命令中調用read_shlib()命令意味着調用者知道工具如何以及在何處安裝文件。我希望工具本身執行read_shlib()的調用(如有必要)。但我失敗在run()runnable_status()這樣做,作爲建議書WAF節第11.4.2約Custom tasks,看來我必須以某種方式incapsulate調用read_shlib()ANOTHER任務,並把它裏面的無證more_tasks屬性。

而且有問題:

  1. 我怎樣才能incapsulate的read_shlib()呼叫任務,由CMake的任務被催生?
  2. 是否可以讓任務以非阻塞方式並行進行其他任務(假設項目中有2個或3個這些CMake依賴關係,這些依賴關係將由遠程回購提供git)?

回答

0

那麼實際上你已經完成了大部分工作:)

read_shlib只創建一個假的任務假裝打造一個已經存在的庫。在你的情況下,你真的建立的庫,所以你真的不需要read_shlib。假設你設置了正確的參數,你可以在你的cmake任務生成器的某個地方使用use

關鍵字use識別所使用的任務發電機的一些參數:

  • export_includes
  • export_defines

它還管理庫和任務的命令,如果使用任務發電機具有link_task

所以,你只需要正確設置export_includesexport_defines在cmake的任務發電機,再加上設置一個link_task屬性,它引用您的cmake_task屬性。你也必須正確地設置你的cmake_task輸出才能正常工作,即列表的第一個輸出必須是lib節點(你在add_target中做的事情似乎沒問題)。喜歡的東西:

@feature('cmake') 
@after_method('update_outputs') 
def export_for_use(self): 
    self.link_task = self.cmake_task 
    out_dir = self.bld.bldnode.make_node(self.target) 
    self.export_includes = out_dir.make_node('include') 

做的這,你可以簡單的在你的主WScript的寫:

def build(bld): 
    for lists_file in bld.env.CMAKE_LISTS: 
     if 'Chipmunk2D' in lists_file: 
      bld(
       source=lists_file, 
       features='cmake', 
       target='chipmunk', 
       lib_type='shared', 
       cmake_args=[ 
        '-DBUILD_DEMOS=OFF', 
        '-DINSTALL_DEMOS=OFF', 
        '-DBUILD_SHARED=ON', 
        '-DBUILD_STATIC=OFF', 
        '-DINSTALL_STATIC=OFF', 
        '-Wno-dev', 
       ]) 

    bld.program(source="main.cpp", use="chipmunk") 

當然你也可以簡化/因式分解的代碼。我認爲add_target不應該在任務中,它主要管理任務生成器屬性。