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