jack2 codebase
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

258 lines
7.7KB

  1. #!/usr/bin/env python
  2. # encoding: utf-8
  3. # Tom Wambold tom5760 gmail.com 2009
  4. # Thomas Nagy 2010
  5. """
  6. Go as a language may look nice, but its toolchain is one of the worse a developer
  7. has ever seen. It keeps changing though, and I would like to believe that it will get
  8. better eventually, but the crude reality is that this tool and the examples are
  9. getting broken every few months.
  10. If you have been lured into trying to use Go, you should stick to their Makefiles.
  11. """
  12. import os, platform
  13. from waflib import Utils, Task, TaskGen
  14. from waflib.TaskGen import feature, extension, after_method, before_method
  15. from waflib.Tools.ccroot import link_task, stlink_task, propagate_uselib_vars, process_use
  16. class go(Task.Task):
  17. run_str = '${GOC} ${GOCFLAGS} ${CPPPATH_ST:INCPATHS} -o ${TGT} ${SRC}'
  18. class gopackage(stlink_task):
  19. run_str = '${GOP} grc ${TGT} ${SRC}'
  20. class goprogram(link_task):
  21. run_str = '${GOL} ${GOLFLAGS} -o ${TGT} ${SRC}'
  22. inst_to = '${BINDIR}'
  23. chmod = Utils.O755
  24. class cgopackage(stlink_task):
  25. color = 'YELLOW'
  26. inst_to = '${LIBDIR}'
  27. ext_in = ['.go']
  28. ext_out = ['.a']
  29. def run(self):
  30. src_dir = self.generator.bld.path
  31. source = self.inputs
  32. target = self.outputs[0].change_ext('')
  33. #print ("--> %s" % self.outputs)
  34. #print ('++> %s' % self.outputs[1])
  35. bld_dir = self.outputs[1]
  36. bld_dir.mkdir()
  37. obj_dir = bld_dir.make_node('_obj')
  38. obj_dir.mkdir()
  39. bld_srcs = []
  40. for s in source:
  41. # FIXME: it seems gomake/cgo stumbles on filenames like a/b/c.go
  42. # -> for the time being replace '/' with '_'...
  43. #b = bld_dir.make_node(s.path_from(src_dir))
  44. b = bld_dir.make_node(s.path_from(src_dir).replace(os.sep,'_'))
  45. b.parent.mkdir()
  46. #print ('++> %s' % (s.path_from(src_dir),))
  47. try:
  48. try:os.remove(b.abspath())
  49. except Exception:pass
  50. os.symlink(s.abspath(), b.abspath())
  51. except Exception:
  52. # if no support for symlinks, copy the file from src
  53. b.write(s.read())
  54. bld_srcs.append(b)
  55. #print("--|> [%s]" % b.abspath())
  56. b.sig = Utils.h_file(b.abspath())
  57. pass
  58. #self.set_inputs(bld_srcs)
  59. #self.generator.bld.raw_deps[self.uid()] = [self.signature()] + bld_srcs
  60. makefile_node = bld_dir.make_node("Makefile")
  61. makefile_tmpl = '''\
  62. # Copyright 2009 The Go Authors. All rights reserved.
  63. # Use of this source code is governed by a BSD-style
  64. # license that can be found in the LICENSE file. ---
  65. include $(GOROOT)/src/Make.inc
  66. TARG=%(target)s
  67. GCIMPORTS= %(gcimports)s
  68. CGOFILES=\\
  69. \t%(source)s
  70. CGO_CFLAGS= %(cgo_cflags)s
  71. CGO_LDFLAGS= %(cgo_ldflags)s
  72. include $(GOROOT)/src/Make.pkg
  73. %%: install %%.go
  74. $(GC) $*.go
  75. $(LD) -o $@ $*.$O
  76. ''' % {
  77. 'gcimports': ' '.join(l for l in self.env['GOCFLAGS']),
  78. 'cgo_cflags' : ' '.join(l for l in self.env['GOCFLAGS']),
  79. 'cgo_ldflags': ' '.join(l for l in self.env['GOLFLAGS']),
  80. 'target': target.path_from(obj_dir),
  81. 'source': ' '.join([b.path_from(bld_dir) for b in bld_srcs])
  82. }
  83. makefile_node.write(makefile_tmpl)
  84. #print ("::makefile: %s"%makefile_node.abspath())
  85. cmd = Utils.subst_vars('gomake ${GOMAKE_FLAGS}', self.env).strip()
  86. o = self.outputs[0].change_ext('.gomake.log')
  87. fout_node = bld_dir.find_or_declare(o.name)
  88. fout = open(fout_node.abspath(), 'w')
  89. rc = self.generator.bld.exec_command(
  90. cmd,
  91. stdout=fout,
  92. stderr=fout,
  93. cwd=bld_dir.abspath(),
  94. )
  95. if rc != 0:
  96. import waflib.Logs as msg
  97. msg.error('** error running [%s] (cgo-%s)' % (cmd, target))
  98. msg.error(fout_node.read())
  99. return rc
  100. self.generator.bld.read_stlib(
  101. target,
  102. paths=[obj_dir.abspath(),],
  103. )
  104. tgt = self.outputs[0]
  105. if tgt.parent != obj_dir:
  106. install_dir = os.path.join('${LIBDIR}',
  107. tgt.parent.path_from(obj_dir))
  108. else:
  109. install_dir = '${LIBDIR}'
  110. #print('===> %s (%s)' % (tgt.abspath(), install_dir))
  111. self.generator.bld.install_files(
  112. install_dir,
  113. tgt.abspath(),
  114. relative_trick=False,
  115. postpone=False,
  116. )
  117. return rc
  118. @extension('.go')
  119. def compile_go(self, node):
  120. #print('*'*80, self.name)
  121. if not ('cgopackage' in self.features):
  122. return self.create_compiled_task('go', node)
  123. #print ('compile_go-cgo...')
  124. bld_dir = node.parent.get_bld()
  125. obj_dir = bld_dir.make_node('_obj')
  126. target = obj_dir.make_node(node.change_ext('.a').name)
  127. return self.create_task('cgopackage', node, node.change_ext('.a'))
  128. @feature('gopackage', 'goprogram', 'cgopackage')
  129. @before_method('process_source')
  130. def go_compiler_is_foobar(self):
  131. if self.env.GONAME == 'gcc':
  132. return
  133. self.source = self.to_nodes(self.source)
  134. src = []
  135. go = []
  136. for node in self.source:
  137. if node.name.endswith('.go'):
  138. go.append(node)
  139. else:
  140. src.append(node)
  141. self.source = src
  142. if not ('cgopackage' in self.features):
  143. #print('--> [%s]... (%s)' % (go[0], getattr(self, 'target', 'N/A')))
  144. tsk = self.create_compiled_task('go', go[0])
  145. tsk.inputs.extend(go[1:])
  146. else:
  147. #print ('+++ [%s] +++' % self.target)
  148. bld_dir = self.path.get_bld().make_node('cgopackage--%s' % self.target.replace(os.sep,'_'))
  149. obj_dir = bld_dir.make_node('_obj')
  150. target = obj_dir.make_node(self.target+'.a')
  151. tsk = self.create_task('cgopackage', go, [target, bld_dir])
  152. self.link_task = tsk
  153. @feature('gopackage', 'goprogram', 'cgopackage')
  154. @after_method('process_source', 'apply_incpaths',)
  155. def go_local_libs(self):
  156. names = self.to_list(getattr(self, 'use', []))
  157. #print ('== go-local-libs == [%s] == use: %s' % (self.name, names))
  158. for name in names:
  159. tg = self.bld.get_tgen_by_name(name)
  160. if not tg:
  161. raise Utils.WafError('no target of name %r necessary for %r in go uselib local' % (name, self))
  162. tg.post()
  163. #print ("-- tg[%s]: %s" % (self.name,name))
  164. lnk_task = getattr(tg, 'link_task', None)
  165. if lnk_task:
  166. for tsk in self.tasks:
  167. if isinstance(tsk, (go, gopackage, cgopackage)):
  168. tsk.set_run_after(lnk_task)
  169. tsk.dep_nodes.extend(lnk_task.outputs)
  170. path = lnk_task.outputs[0].parent.abspath()
  171. if isinstance(lnk_task, (go, gopackage)):
  172. # handle hierarchical packages
  173. path = lnk_task.generator.path.get_bld().abspath()
  174. elif isinstance(lnk_task, (cgopackage,)):
  175. # handle hierarchical cgopackages
  176. cgo_obj_dir = lnk_task.outputs[1].find_or_declare('_obj')
  177. path = cgo_obj_dir.abspath()
  178. # recursively add parent GOCFLAGS...
  179. self.env.append_unique('GOCFLAGS',
  180. getattr(lnk_task.env, 'GOCFLAGS',[]))
  181. # ditto for GOLFLAGS...
  182. self.env.append_unique('GOLFLAGS',
  183. getattr(lnk_task.env, 'GOLFLAGS',[]))
  184. self.env.append_unique('GOCFLAGS', ['-I%s' % path])
  185. self.env.append_unique('GOLFLAGS', ['-L%s' % path])
  186. for n in getattr(tg, 'includes_nodes', []):
  187. self.env.append_unique('GOCFLAGS', ['-I%s' % n.abspath()])
  188. pass
  189. pass
  190. def configure(conf):
  191. def set_def(var, val):
  192. if not conf.env[var]:
  193. conf.env[var] = val
  194. goarch = os.getenv('GOARCH')
  195. if goarch == '386':
  196. set_def('GO_PLATFORM', 'i386')
  197. elif goarch == 'amd64':
  198. set_def('GO_PLATFORM', 'x86_64')
  199. elif goarch == 'arm':
  200. set_def('GO_PLATFORM', 'arm')
  201. else:
  202. set_def('GO_PLATFORM', platform.machine())
  203. if conf.env.GO_PLATFORM == 'x86_64':
  204. set_def('GO_COMPILER', '6g')
  205. set_def('GO_LINKER', '6l')
  206. elif conf.env.GO_PLATFORM in ('i386', 'i486', 'i586', 'i686'):
  207. set_def('GO_COMPILER', '8g')
  208. set_def('GO_LINKER', '8l')
  209. elif conf.env.GO_PLATFORM == 'arm':
  210. set_def('GO_COMPILER', '5g')
  211. set_def('GO_LINKER', '5l')
  212. set_def('GO_EXTENSION', '.5')
  213. if not (conf.env.GO_COMPILER or conf.env.GO_LINKER):
  214. raise conf.fatal('Unsupported platform ' + platform.machine())
  215. set_def('GO_PACK', 'gopack')
  216. set_def('gopackage_PATTERN', '%s.a')
  217. set_def('CPPPATH_ST', '-I%s')
  218. set_def('GOMAKE_FLAGS', ['--quiet'])
  219. conf.find_program(conf.env.GO_COMPILER, var='GOC')
  220. conf.find_program(conf.env.GO_LINKER, var='GOL')
  221. conf.find_program(conf.env.GO_PACK, var='GOP')
  222. conf.find_program('cgo', var='CGO')
  223. TaskGen.feature('go')(process_use)
  224. TaskGen.feature('go')(propagate_uselib_vars)