wscript 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. #! /usr/bin/env python
  2. # encoding: utf-8
  3. # Thomas Nagy, 2010 (ita)
  4. VERSION='0.0.1'
  5. APPNAME='cpp_gen'
  6. top = '.'
  7. out = 'build'
  8. def options(opt):
  9. opt.load('compiler_cxx')
  10. def configure(conf):
  11. conf.load('compiler_cxx')
  12. conf.check(header_name='stdio.h', features='cxx cxxprogram', mandatory=False)
  13. def build(bld):
  14. bld.program(source='main.cpp a.cpp', target='app')
  15. #--------
  16. import os
  17. from waflib import Task, TaskGen, Utils
  18. from waflib.Tools import cxx
  19. @TaskGen.extension('.cpp')
  20. def more_tasks_at_once(self, node):
  21. task1 = self.create_task('prog1', node, [])
  22. task2 = self.create_compiled_task('cxx', node)
  23. def cmpnodes(a, b):
  24. return cmp(a.abspath(), b.abspath())
  25. class prog1(Task.Task):
  26. before = ['cxxprogram', 'cxxshlib', 'cxxstlib']
  27. def uid(self):
  28. """
  29. the unique id of this task should only depend on the file inputs
  30. """
  31. m = Utils.md5()
  32. up = m.update
  33. up(self.__class__.__name__.encode())
  34. for x in self.inputs:
  35. up(x.abspath().encode())
  36. return m.digest()
  37. def runnable_status(self):
  38. """
  39. since it is called after the build has started,
  40. any task added must be passed through 'more_tasks'
  41. """
  42. for x in self.run_after:
  43. if not x.hasrun:
  44. return Task.ASK_LATER
  45. # so this is a bit special, the goal here is to set the output nodes
  46. # and to create the c++ tasks before the normal processing is done
  47. sig = self.signature()
  48. for x in self.generator.bld.raw_deps.get(sig, []):
  49. self.outputs.append(self.generator.bld.srcnode.find_node(x))
  50. if not self.outputs:
  51. self.read_outputs_from_cache()
  52. if self.outputs:
  53. self.create_cxx_task()
  54. ret = Task.Task.runnable_status(self)
  55. return ret
  56. def create_cxx_task(self):
  57. """
  58. create a task dynamically during the build
  59. notice the use of 'more_tasks'
  60. """
  61. tsk = cxx.cxx_hook(self.generator, self.outputs[0])
  62. tsk.set_run_after(self) # the build has started, so the order must be set manually
  63. self.more_tasks = [tsk] # add tasks dynamically during the build
  64. self.generator.link_task.inputs.append(tsk.outputs[0]) # add another input for the link task
  65. try:
  66. self.generator.link_task.inputs.sort(cmp=cmpnodes) # eliminate the random order (more tasks like this)
  67. except:
  68. self.generator.link_task.inputs.sort(key=lambda x: x.abspath()) # python3
  69. self.generator.link_task.set_run_after(tsk) # do not forget to set the build order there too
  70. def run(self):
  71. """
  72. actual execution
  73. this code should not be executed if the files are retrieved from the cache
  74. """
  75. if self.inputs[0].name == 'a.cpp':
  76. # simulate the creation of an interface file
  77. out = self.inputs[0].parent.get_bld().make_node('a.ser.cpp')
  78. out.write('\n\n')
  79. # read the file system
  80. # remember that nodes cannot be created concurrently
  81. # so you might to crate a lock if several tasks want the same nodes
  82. inp = self.inputs[0]
  83. node = inp.parent.get_bld().find_node(inp.name.replace('.cpp', '.ser.cpp'))
  84. if node:
  85. self.outputs = [node]
  86. h_node = inp.parent.find_node(inp.name.replace('.cpp', '.ser.h'))
  87. if h_node:
  88. self.outputs.append(h_node)
  89. # if there are outputs, create a new c++ task
  90. if self.outputs:
  91. self.create_cxx_task()
  92. # access the scanner data
  93. self.generator.bld.raw_deps[self.signature()] = [x.path_from(self.generator.bld.srcnode) for x in self.outputs]
  94. def read_outputs_from_cache(self):
  95. """
  96. set the outputs from the results found in the cache
  97. we assume that the files are created in the same folder as the inputs
  98. if it is not like this, the nodes should be restored by another system, for example
  99. by storing them in a separate file during run()
  100. """
  101. env = self.env
  102. sig = self.signature()
  103. ssig = Utils.to_hex(sig)
  104. # first try to access the cache folder for the task
  105. dname = os.path.join(self.generator.bld.cache_global, ssig)
  106. try:
  107. t1 = os.stat(dname).st_mtime
  108. except OSError:
  109. return None
  110. try:
  111. lst = os.listdir(dname)
  112. except:
  113. return
  114. for x in lst:
  115. self.outputs.append(self.inputs[0].parent.find_or_declare(x))
  116. # not a fresh build and the cache is removed -> remember the files in the scanner data
  117. self.generator.bld.raw_deps[self.signature()] = [x.path_from(self.generator.bld.srcnode) for x in self.outputs]