1
2
3
4
5
6
7 import os, sys, re, string, optparse
8 import Utils, TaskGen, Runner, Configure, Task, Options
9 from Logs import debug, error, warn
10 from Utils import quote_whitespace
11 from TaskGen import taskgen, after, before, feature
12
13 from Configure import conftest
14 import ccroot
15 from libtool import read_la_file
16 from os.path import exists
19 """Special linker for MSVC with support for embedding manifests into DLL's
20 and executables compiled by Visual Studio 2005 or probably later. Without
21 the manifest file, the binaries are unusable.
22 See: http://msdn2.microsoft.com/en-us/library/ms235542(VS.80).aspx
23 Problems with this tool: it is always called whether MSVC creates manifests or not."""
24 e = task.env
25 linker = e['LINK']
26 srcf = e['LINK_SRC_F']
27 trgtf = e['LINK_TGT_F']
28 linkflags = e.get_flat('LINKFLAGS')
29 libdirs = e.get_flat('_LIBDIRFLAGS')
30 libs = e.get_flat('_LIBFLAGS')
31
32 subsystem=''
33 if task.subsystem:
34 subsystem='/subsystem:%s' % task.subsystem
35 outfile=task.outputs[0].bldpath(e)
36 manifest=outfile+'.manifest'
37
38 pdbnode=task.outputs[0].change_ext('.pdb')
39 pdbfile=pdbnode.bldpath(e)
40
41 objs=" ".join(['"%s"' % a.abspath(e) for a in task.inputs])
42
43 cmd="%s %s %s%s %s%s %s %s %s" % (linker,subsystem,srcf,objs,trgtf,outfile, linkflags, libdirs,libs)
44
45
46
47 ret=Runner.exec_command(cmd, shell=False)
48 if ret: return ret
49
50
51 if os.path.exists(pdbfile):
52 task.outputs.append(pdbnode)
53
54 if os.path.exists(manifest):
55 debug('msvc: manifesttool')
56 mtool = e['MT']
57 if not mtool:
58 return 0
59 mode=''
60
61
62 if task.type == 'program':
63 mode='1'
64 elif task.type == 'shlib':
65 mode='2'
66
67 debug('msvc: embedding manifest')
68 flags = e['MTFLAGS']
69 if flags:
70 flags=string.join(flags,' ')
71 else:
72 flags=''
73
74 cmd='%s %s -manifest "%s" -outputresource:"%s";#%s' % (mtool, flags,
75 manifest, outfile, mode)
76 ret=Runner.exec_command(cmd)
77 return ret
78
79
80 g_msvc_systemlibs = """
81 aclui activeds ad1 adptif adsiid advapi32 asycfilt authz bhsupp bits bufferoverflowu cabinet
82 cap certadm certidl ciuuid clusapi comctl32 comdlg32 comsupp comsuppd comsuppw comsuppwd comsvcs
83 credui crypt32 cryptnet cryptui d3d8thk daouuid dbgeng dbghelp dciman32 ddao35 ddao35d
84 ddao35u ddao35ud delayimp dhcpcsvc dhcpsapi dlcapi dnsapi dsprop dsuiext dtchelp
85 faultrep fcachdll fci fdi framedyd framedyn gdi32 gdiplus glauxglu32 gpedit gpmuuid
86 gtrts32w gtrtst32hlink htmlhelp httpapi icm32 icmui imagehlp imm32 iphlpapi iprop
87 kernel32 ksguid ksproxy ksuser libcmt libcmtd libcpmt libcpmtd loadperf lz32 mapi
88 mapi32 mgmtapi minidump mmc mobsync mpr mprapi mqoa mqrt msacm32 mscms mscoree
89 msdasc msimg32 msrating mstask msvcmrt msvcurt msvcurtd mswsock msxml2 mtx mtxdm
90 netapi32 nmapinmsupp npptools ntdsapi ntdsbcli ntmsapi ntquery odbc32 odbcbcp
91 odbccp32 oldnames ole32 oleacc oleaut32 oledb oledlgolepro32 opends60 opengl32
92 osptk parser pdh penter pgobootrun pgort powrprof psapi ptrustm ptrustmd ptrustu
93 ptrustud qosname rasapi32 rasdlg rassapi resutils riched20 rpcndr rpcns4 rpcrt4 rtm
94 rtutils runtmchk scarddlg scrnsave scrnsavw secur32 sensapi setupapi sfc shell32
95 shfolder shlwapi sisbkup snmpapi sporder srclient sti strsafe svcguid tapi32 thunk32
96 traffic unicows url urlmon user32 userenv usp10 uuid uxtheme vcomp vcompd vdmdbg
97 version vfw32 wbemuuid webpost wiaguid wininet winmm winscard winspool winstrm
98 wintrust wldap32 wmiutils wow32 ws2_32 wsnmp32 wsock32 wst wtsapi32 xaswitch xolehlp
99 """.split()
103 """
104 Win32/MSVC specific code to glean out information from libtool la files.
105 this function is not attached to the task_gen class
106 """
107 lt_names=[
108 'lib%s.la' % libname,
109 '%s.la' % libname,
110 ]
111
112 for path in self.libpaths:
113 for la in lt_names:
114 laf=os.path.join(path,la)
115 dll=None
116 if exists(laf):
117 ltdict=read_la_file(laf)
118 lt_libdir=None
119 if ltdict.has_key('libdir') and ltdict['libdir'] != '':
120 lt_libdir=ltdict['libdir']
121 if not is_static and ltdict.has_key('library_names') and ltdict['library_names'] != '':
122 dllnames=ltdict['library_names'].split()
123 dll=dllnames[0].lower()
124 dll=re.sub('\.dll$', '', dll)
125 return (lt_libdir, dll, False)
126 elif ltdict.has_key('old_library') and ltdict['old_library'] != '':
127 olib=ltdict['old_library']
128 if exists(os.path.join(path,olib)):
129 return (path, olib, True)
130 elif lt_libdir != '' and exists(os.path.join(lt_libdir,olib)):
131 return (lt_libdir, olib, True)
132 else:
133 return (None, olib, True)
134 else:
135 raise Utils.WafError('invalid libtool object file: %s' % laf)
136 return (None, None, None)
137
139 lib=libname.lower()
140 lib=re.sub('\.lib$','',lib)
141
142 if lib in g_msvc_systemlibs:
143 return lib+'.lib'
144
145 lib=re.sub('^lib','',lib)
146
147 if lib == 'm':
148 return None
149
150 (lt_path, lt_libname, lt_static) = find_lt_names_msvc(self, lib, is_static)
151
152 if lt_path != None and lt_libname != None:
153 if lt_static == True:
154
155 return os.path.join(lt_path,lt_libname)
156
157 if lt_path != None:
158 _libpaths=[lt_path] + self.libpaths
159 else:
160 _libpaths=self.libpaths
161
162 static_libs=[
163 '%ss.lib' % lib,
164 'lib%ss.lib' % lib,
165 '%s.lib' %lib,
166 'lib%s.lib' % lib,
167 ]
168
169 dynamic_libs=[
170 'lib%s.dll.lib' % lib,
171 'lib%s.dll.a' % lib,
172 '%s.dll.lib' % lib,
173 '%s.dll.a' % lib,
174 'lib%s_d.lib' % lib,
175 '%s_d.lib' % lib,
176 '%s.lib' %lib,
177 ]
178
179 libnames=static_libs
180 if not is_static:
181 libnames=dynamic_libs + static_libs
182
183 for path in _libpaths:
184 for libn in libnames:
185 if os.path.exists(os.path.join(path,libn)):
186 debug('msvc: lib found: %s' % os.path.join(path,libn))
187 return libn
188
189 return None
190
191 @taskgen
192 @feature('cc', 'cxx')
193 @after('apply_obj_vars_cc')
194 @after('apply_obj_vars_cxx')
195 -def apply_msvc_obj_vars(self):
196 env = self.env
197 app = env.append_unique
198
199 cpppath_st = env['CPPPATH_ST']
200 lib_st = env['LIB_ST']
201 staticlib_st = env['STATICLIB_ST']
202 libpath_st = env['LIBPATH_ST']
203 staticlibpath_st = env['STATICLIBPATH_ST']
204 self.libpaths = []
205
206 for i in env['RPATH']: app('LINKFLAGS', i)
207 for i in env['LIBPATH']:
208 app('LINKFLAGS', libpath_st % i)
209 if not self.libpaths.count(i):
210 self.libpaths.append(i)
211 for i in env['LIBPATH']:
212 app('LINKFLAGS', staticlibpath_st % i)
213 if not self.libpaths.count(i):
214 self.libpaths.append(i)
215
216
217 if not env['FULLSTATIC']:
218 if env['STATICLIB'] or env['LIB']:
219 app('LINKFLAGS', env['SHLIB_MARKER'])
220
221 if env['STATICLIB']:
222 app('LINKFLAGS', env['STATICLIB_MARKER'])
223 for i in env['STATICLIB']:
224 debug('msvc: libname: %s' % i)
225 libname = libname_msvc(self, i, True)
226 debug('msvc: libnamefixed: %s' % libname)
227 if libname != None:
228 app('LINKFLAGS', libname)
229
230 if self.env['LIB']:
231 for i in env['LIB']:
232 debug('msvc: libname: %s' % i)
233 libname = libname_msvc(self, i)
234 debug('msvc: libnamefixed: %s' % libname)
235 if libname != None:
236 app('LINKFLAGS', libname)
237
238 @taskgen
239 @feature('cc', 'cxx')
240 @after('apply_core')
241 @before('apply_obj_vars_cc')
242 @before('apply_obj_vars_cxx')
243 -def apply_link_msvc(self):
244
245
246
247 if self.type == 'objects':
248 self.out_nodes = []
249 app = self.out_nodes.append
250 for t in self.compiled_tasks: app(t.outputs[0])
251 return
252
253
254 link = getattr(self, 'link', None)
255 if not link:
256 if self.type == 'staticlib': link = 'msvc_ar_link_static'
257 elif 'cxx' in self.features: link = 'msvc_cxx_link'
258 else: link = 'msvc_cc_link'
259 linktask = self.create_task(link)
260
261 outputs = [t.outputs[0] for t in self.compiled_tasks]
262 linktask.set_inputs(outputs)
263 linktask.set_outputs(self.path.find_or_declare(ccroot.get_target_name(self)))
264
265 linktask.type = self.type
266 linktask.subsystem = getattr(self, 'subsystem', '')
267 self.link_task = linktask
268
269 @taskgen
270 @feature('cc', 'cxx')
271 @before('apply_core')
272 -def init_msvc(self):
273 "all methods (msvc and non-msvc) are to be executed, but we remove the ones we do not want"
274 if self.env['CC_NAME'] == 'msvc' or self.env['CXX_NAME'] == 'msvc':
275 self.meths.remove('apply_link')
276 else:
277 for x in ['apply_link_msvc', 'apply_msvc_obj_vars']:
278 self.meths.remove(x)
279 self.libpaths = getattr(self, 'libpaths', '')
280
281 static_link_str = '${STLIBLINK} ${LINK_SRC_F}${SRC} ${LINK_TGT_F}${TGT}'
282 Task.simple_task_type('msvc_ar_link_static', static_link_str, color='YELLOW', ext_in='.o')
283 Task.task_type_from_func('msvc_cc_link', vars=['LINK', 'LINK_SRC_F', 'LINK_TGT_F', 'LINKFLAGS', '_LIBDIRFLAGS', '_LIBFLAGS', 'MT', 'MTFLAGS'] , color='YELLOW', func=msvc_linker, ext_in='.o')
284 Task.task_type_from_func('msvc_cxx_link', vars=['LINK', 'LINK_SRC_F', 'LINK_TGT_F', 'LINKFLAGS', '_LIBDIRFLAGS', '_LIBFLAGS', 'MT', 'MTFLAGS'] , color='YELLOW', func=msvc_linker, ext_in='.o')
285
286 rc_str='${RC} ${RCFLAGS} /fo ${TGT} ${SRC}'
287 Task.simple_task_type('rc', rc_str, color='GREEN', before='cc cxx')
288
289 import winres
290
291 detect = '''
292 find_msvc
293 msvc_common_flags
294 cc_load_tools
295 cxx_load_tools
296 cc_add_flags
297 cxx_add_flags
298 '''
302
303 if sys.platform != 'win32':
304 conf.fatal('MSVC module only works under native Win32 Python! cygwin is not supported yet')
305
306 v = conf.env
307
308
309 cxx = None
310 if v['CXX']: cxx = v['CXX']
311 elif 'CXX' in os.environ: cxx = os.environ['CXX']
312 if not cxx: cxx = conf.find_program('CL', var='CXX')
313 if not cxx: conf.fatal('CL was not found (compiler)')
314
315
316 v['CXX'] = quote_whitespace(cxx)
317 v['CC'] = v['CXX']
318 v['CXX_NAME'] = 'msvc'
319 v['CC_NAME'] = 'msvc'
320
321
322 if not v['LINK_CXX']:
323 link = conf.find_program('LINK')
324 if link: v['LINK_CXX'] = link
325 else: conf.fatal('LINK was not found (linker)')
326 v['LINK'] = '\"%s\"' % link
327
328 if not v['LINK_CC']: v['LINK_CC'] = v['LINK_CXX']
329
330
331 if not v['STLIBLINK']:
332 stliblink = conf.find_program('LIB')
333 if not stliblink: return
334 v['STLIBLINK'] = '\"%s\"' % stliblink
335
336
337 manifesttool = conf.find_program('MT')
338 if manifesttool:
339 v['MT'] = quote_whitespace (manifesttool)
340 v['MTFLAGS']=['/NOLOGO']
341
342 conf.check_tool('winres')
343
344 if not conf.env['WINRC']:
345 warn('Resource compiler not found. Compiling resource file is disabled')
346
349 v = conf.env
350
351 v['CPPFLAGS'] = ['/W3', '/nologo', '/EHsc', '/errorReport:prompt']
352 v['CCDEFINES'] = ['WIN32']
353 v['CXXDEFINES'] = ['WIN32']
354
355 v['_CCINCFLAGS'] = []
356 v['_CCDEFFLAGS'] = []
357 v['_CXXINCFLAGS'] = []
358 v['_CXXDEFFLAGS'] = []
359
360 v['CC_SRC_F'] = ''
361 v['CC_TGT_F'] = '/c /Fo'
362 v['CXX_SRC_F'] = ''
363 v['CXX_TGT_F'] = '/c /Fo'
364
365 v['CPPPATH_ST'] = '/I%s'
366
367
368 v['CPPFLAGS_CONSOLE'] = ['/SUBSYSTEM:CONSOLE']
369 v['CPPFLAGS_NATIVE'] = ['/SUBSYSTEM:NATIVE']
370 v['CPPFLAGS_POSIX'] = ['/SUBSYSTEM:POSIX']
371 v['CPPFLAGS_WINDOWS'] = ['/SUBSYSTEM:WINDOWS']
372 v['CPPFLAGS_WINDOWSCE'] = ['/SUBSYSTEM:WINDOWSCE']
373
374
375 v['CPPFLAGS_CRT_MULTITHREADED'] = ['/MT']
376 v['CPPFLAGS_CRT_MULTITHREADED_DLL'] = ['/MD']
377 v['CPPDEFINES_CRT_MULTITHREADED'] = ['_MT']
378 v['CPPDEFINES_CRT_MULTITHREADED_DLL'] = ['_MT', '_DLL']
379
380 v['CPPFLAGS_CRT_MULTITHREADED_DBG'] = ['/MTd']
381 v['CPPFLAGS_CRT_MULTITHREADED_DLL_DBG'] = ['/MDd']
382 v['CPPDEFINES_CRT_MULTITHREADED_DBG'] = ['_DEBUG', '_MT']
383 v['CPPDEFINES_CRT_MULTITHREADED_DLL_DBG'] = ['_DEBUG', '_MT', '_DLL']
384