3 # Tom Wambold tom5760 gmail.com 2009
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.
12 If you have been lured into trying to use Go, you should stick to their Makefiles.
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
22 run_str
= '${GOC} ${GOCFLAGS} ${CPPPATH_ST:INCPATHS} -o ${TGT} ${SRC}'
24 class gopackage(stlink_task
):
25 run_str
= '${GOP} grc ${TGT} ${SRC}'
27 class goprogram(link_task
):
28 run_str
= '${GOL} ${GOLFLAGS} -o ${TGT} ${SRC}'
32 class cgopackage(stlink_task
):
39 src_dir
= self
.generator
.bld
.path
41 target
= self
.outputs
[0].change_ext('')
43 #print ("--> %s" % self.outputs)
44 #print ('++> %s' % self.outputs[1])
45 bld_dir
= self
.outputs
[1]
47 obj_dir
= bld_dir
.make_node('_obj')
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
,'_'))
57 #print ('++> %s' % (s.path_from(src_dir),))
59 try:os
.remove(b
.abspath())
61 os
.symlink(s
.abspath(), b
.abspath())
63 # if no support for symlinks, copy the file from src
66 #print("--|> [%s]" % b.abspath())
67 b
.sig
= Utils
.h_file(b
.abspath())
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")
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. ---
77 include $(GOROOT)/src/Make.inc
81 GCIMPORTS= %(gcimports)s
86 CGO_CFLAGS= %(cgo_cflags)s
88 CGO_LDFLAGS= %(cgo_ldflags)s
90 include $(GOROOT)/src/Make.pkg
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
])
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(
113 cwd
=bld_dir
.abspath(),
116 import waflib
.Logs
as msg
117 msg
.error('** error running [%s] (cgo-%s)' % (cmd
, target
))
118 msg
.error(fout_node
.read())
120 self
.generator
.bld
.read_stlib(
122 paths
=[obj_dir
.abspath(),],
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
))
129 install_dir
= '${LIBDIR}'
130 #print('===> %s (%s)' % (tgt.abspath(), install_dir))
131 self
.generator
.bld
.install_files(
134 relative_trick
=False,
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'))
149 @feature('gopackage', 'goprogram', 'cgopackage')
150 @before_method('process_source')
151 def go_compiler_is_foobar(self
):
152 if self
.env
.GONAME
== 'gcc':
154 self
.source
= self
.to_nodes(self
.source
)
157 for node
in self
.source
:
158 if node
.name
.endswith('.go'):
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:])
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
])
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))
181 tg
= self
.bld
.get_tgen_by_name(name
)
183 raise Utils
.WafError('no target of name %r necessary for %r in go uselib local' % (name
, self
))
185 #print ("-- tg[%s]: %s" % (self.name,name))
186 lnk_task
= getattr(tg
, 'link_task', None)
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()])
215 def set_def(var
, val
):
216 if not conf
.env
[var
]:
219 goarch
= os
.getenv('GOARCH')
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')
227 set_def('GO_PLATFORM', platform
.machine())
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')
240 if not (conf
.env
.GO_COMPILER
or conf
.env
.GO_LINKER
):
241 raise conf
.fatal('Unsupported platform ' + platform
.machine())
243 set_def('GO_PACK', 'gopack')
244 set_def('gopackage_PATTERN', '%s.a')
245 set_def('CPPPATH_ST', '-I%s')
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')
252 conf
.find_program('cgo', var
='CGO')
254 TaskGen
.feature('go')(process_use
)
255 TaskGen
.feature('go')(propagate_uselib_vars
)