Merged revisions 1675-1736 via svnmerge from
[scons.git] / src / engine / SCons / Tool / mslink.py
1 """SCons.Tool.mslink
2
3 Tool-specific initialization for the Microsoft linker.
4
5 There normally shouldn't be any need to import this module directly.
6 It will usually be imported through the generic SCons.Tool.Tool()
7 selection method.
8
9 """
10
11 #
12 # __COPYRIGHT__
13 #
14 # Permission is hereby granted, free of charge, to any person obtaining
15 # a copy of this software and associated documentation files (the
16 # "Software"), to deal in the Software without restriction, including
17 # without limitation the rights to use, copy, modify, merge, publish,
18 # distribute, sublicense, and/or sell copies of the Software, and to
19 # permit persons to whom the Software is furnished to do so, subject to
20 # the following conditions:
21 #
22 # The above copyright notice and this permission notice shall be included
23 # in all copies or substantial portions of the Software.
24 #
25 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
26 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
27 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 #
33
34 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
35
36 import os.path
37
38 import SCons.Action
39 import SCons.Defaults
40 import SCons.Errors
41 import SCons.Platform.win32
42 import SCons.Tool
43 import SCons.Tool.msvc
44 import SCons.Tool.msvs
45 import SCons.Util
46
47 def pdbGenerator(env, target, source, for_signature):
48     if target and env.has_key('PDB') and env['PDB']:
49         return ['/PDB:%s'%target[0].File(env['PDB']).get_string(for_signature),
50                 '/DEBUG']
51     return None
52
53 def windowsShlinkTargets(target, source, env, for_signature):
54     listCmd = []
55     dll = env.FindIxes(target, 'SHLIBPREFIX', 'SHLIBSUFFIX')
56     if dll: listCmd.append("/out:%s"%dll.get_string(for_signature))
57
58     implib = env.FindIxes(target, 'LIBPREFIX', 'LIBSUFFIX')
59     if implib: listCmd.append("/implib:%s"%implib.get_string(for_signature))
60
61     return listCmd
62
63 def windowsShlinkSources(target, source, env, for_signature):
64     listCmd = []
65
66     deffile = env.FindIxes(source, "WINDOWSDEFPREFIX", "WINDOWSDEFSUFFIX")
67     for src in source:
68         if src == deffile:
69             # Treat this source as a .def file.
70             listCmd.append("/def:%s" % src.get_string(for_signature))
71         else:
72             # Just treat it as a generic source file.
73             listCmd.append(src)
74     return listCmd
75
76 def windowsLibEmitter(target, source, env):
77     SCons.Tool.msvc.validate_vars(env)
78
79     dll = env.FindIxes(target, "SHLIBPREFIX", "SHLIBSUFFIX")
80     no_import_lib = env.get('no_import_lib', 0)
81
82     if not dll:
83         raise SCons.Errors.UserError, "A shared library should have exactly one target with the suffix: %s" % env.subst("$SHLIBSUFFIX")
84
85     insert_def = env.subst("$WINDOWS_INSERT_DEF")
86     if not insert_def in ['', '0', 0] and \
87        not env.FindIxes(source, "WINDOWSDEFPREFIX", "WINDOWSDEFSUFFIX"):
88
89         # append a def file to the list of sources
90         source.append(env.ReplaceIxes(dll,
91                                       "SHLIBPREFIX", "SHLIBSUFFIX",
92                                       "WINDOWSDEFPREFIX", "WINDOWSDEFSUFFIX"))
93
94     version_num, suite = SCons.Tool.msvs.msvs_parse_version(env.get('MSVS_VERSION', '6.0'))
95     if version_num >= 8.0 and env.get('WINDOWS_INSERT_MANIFEST', 0):
96         # MSVC 8 automatically generates .manifest files that must be installed
97         target.append(env.ReplaceIxes(dll,
98                                       "SHLIBPREFIX", "SHLIBSUFFIX",
99                                       "WINDOWSSHLIBMANIFESTPREFIX", "WINDOWSSHLIBMANIFESTSUFFIX"))
100
101     if env.has_key('PDB') and env['PDB']:
102         target.append(env['PDB'])
103
104     if not no_import_lib and \
105        not env.FindIxes(target, "LIBPREFIX", "LIBSUFFIX"):
106         # Append an import library to the list of targets.
107         target.append(env.ReplaceIxes(dll,
108                                       "SHLIBPREFIX", "SHLIBSUFFIX",
109                                       "LIBPREFIX", "LIBSUFFIX"))
110         # and .exp file is created if there are exports from a DLL
111         target.append(env.ReplaceIxes(dll,
112                                       "SHLIBPREFIX", "SHLIBSUFFIX",
113                                       "WINDOWSEXPPREFIX", "WINDOWSEXPSUFFIX"))
114
115     return (target, source)
116
117 def prog_emitter(target, source, env):
118     SCons.Tool.msvc.validate_vars(env)
119
120     exe = env.FindIxes(target, "PROGPREFIX", "PROGSUFFIX")
121     if not exe:
122         raise SCons.Errors.UserError, "An executable should have exactly one target with the suffix: %s" % env.subst("$PROGSUFFIX")
123
124     version_num, suite = SCons.Tool.msvs.msvs_parse_version(env.get('MSVS_VERSION', '6.0'))
125     if version_num >= 8.0 and env.get('WINDOWS_INSERT_MANIFEST', 0):
126         # MSVC 8 automatically generates .manifest files that have to be installed
127         target.append(env.ReplaceIxes(exe,
128                                       "PROGPREFIX", "PROGSUFFIX",
129                                       "WINDOWSPROGMANIFESTPREFIX", "WINDOWSPROGMANIFESTSUFFIX"))
130
131     if env.has_key('PDB') and env['PDB']:
132         target.append(env['PDB'])
133
134     return (target,source)
135
136 def RegServerFunc(target, source, env):
137     if env.has_key('register') and env['register']:
138         ret = regServerAction([target[0]], [source[0]], env)
139         if ret:
140             raise SCons.Errors.UserError, "Unable to register %s" % target[0]
141         else:
142             print "Registered %s sucessfully" % target[0]
143         return ret
144     return 0
145
146 regServerAction = SCons.Action.Action("$REGSVRCOM", "$REGSVRCOMSTR")
147 regServerCheck = SCons.Action.Action(RegServerFunc, None)
148 shlibLinkAction = SCons.Action.Action('${TEMPFILE("$SHLINK $SHLINKFLAGS $_SHLINK_TARGETS $( $_LIBDIRFLAGS $) $_LIBFLAGS $_PDB $_SHLINK_SOURCES")}')
149 compositeLinkAction = shlibLinkAction + regServerCheck
150
151 def generate(env):
152     """Add Builders and construction variables for ar to an Environment."""
153     SCons.Tool.createSharedLibBuilder(env)
154     SCons.Tool.createProgBuilder(env)
155
156     env['SHLINK']      = '$LINK'
157     env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS /dll')
158     env['_SHLINK_TARGETS'] = windowsShlinkTargets
159     env['_SHLINK_SOURCES'] = windowsShlinkSources
160     env['SHLINKCOM']   =  compositeLinkAction
161     env.Append(SHLIBEMITTER = [windowsLibEmitter])
162     env['LINK']        = 'link'
163     env['LINKFLAGS']   = SCons.Util.CLVar('/nologo')
164     env['_PDB'] = pdbGenerator
165     env['LINKCOM'] = '${TEMPFILE("$LINK $LINKFLAGS /OUT:$TARGET.windows $( $_LIBDIRFLAGS $) $_LIBFLAGS $_PDB $SOURCES.windows")}'
166     env.Append(PROGEMITTER = [prog_emitter])
167     env['LIBDIRPREFIX']='/LIBPATH:'
168     env['LIBDIRSUFFIX']=''
169     env['LIBLINKPREFIX']=''
170     env['LIBLINKSUFFIX']='$LIBSUFFIX'
171
172     env['WIN32DEFPREFIX']        = ''
173     env['WIN32DEFSUFFIX']        = '.def'
174     env['WIN32_INSERT_DEF']      = 0
175     env['WINDOWSDEFPREFIX']      = '${WIN32DEFPREFIX}'
176     env['WINDOWSDEFSUFFIX']      = '${WIN32DEFSUFFIX}'
177     env['WINDOWS_INSERT_DEF']    = '${WIN32_INSERT_DEF}'
178
179     env['WIN32EXPPREFIX']        = ''
180     env['WIN32EXPSUFFIX']        = '.exp'
181     env['WINDOWSEXPPREFIX']      = '${WIN32EXPPREFIX}'
182     env['WINDOWSEXPSUFFIX']      = '${WIN32EXPSUFFIX}'
183
184     env['WINDOWSSHLIBMANIFESTPREFIX'] = ''
185     env['WINDOWSSHLIBMANIFESTSUFFIX'] = env['SHLIBSUFFIX'] + '.manifest'
186     env['WINDOWSPROGMANIFESTPREFIX']  = ''
187     env['WINDOWSPROGMANIFESTSUFFIX']  = env['PROGSUFFIX'] + '.manifest'
188
189     env['REGSVRACTION'] = regServerCheck
190     env['REGSVR'] = os.path.join(SCons.Platform.win32.get_system_root(),'System32','regsvr32')
191     env['REGSVRFLAGS'] = '/s '
192     env['REGSVRCOM'] = '$REGSVR $REGSVRFLAGS ${TARGET.windows}'
193
194     try:
195         version = SCons.Tool.msvs.get_default_visualstudio_version(env)
196
197         if env.has_key('MSVS_IGNORE_IDE_PATHS') and env['MSVS_IGNORE_IDE_PATHS']:
198             include_path, lib_path, exe_path = SCons.Tool.msvc.get_msvc_default_paths(env,version)
199         else:
200             include_path, lib_path, exe_path = SCons.Tool.msvc.get_msvc_paths(env,version)
201
202         # since other tools can set these, we just make sure that the
203         # relevant stuff from MSVS is in there somewhere.
204         env.PrependENVPath('INCLUDE', include_path)
205         env.PrependENVPath('LIB', lib_path)
206         env.PrependENVPath('PATH', exe_path)
207     except (SCons.Util.RegError, SCons.Errors.InternalError):
208         pass
209
210     # For most platforms, a loadable module is the same as a shared
211     # library.  Platforms which are different can override these, but
212     # setting them the same means that LoadableModule works everywhere.
213     SCons.Tool.createLoadableModuleBuilder(env)
214     env['LDMODULE'] = '$SHLINK'
215     env['LDMODULEPREFIX'] = '$SHLIBPREFIX'
216     env['LDMODULESUFFIX'] = '$SHLIBSUFFIX'
217     env['LDMODULEFLAGS'] = '$SHLINKFLAGS'
218     # We can't use '$SHLINKCOM' here because that will stringify the
219     # action list on expansion, and will then try to execute expanded
220     # strings, with the upshot that it would try to execute RegServerFunc
221     # as a command.
222     env['LDMODULECOM'] = compositeLinkAction
223
224 def exists(env):
225     platform = env.get('PLATFORM', '')
226     if SCons.Tool.msvs.is_msvs_installed():
227         # there's at least one version of MSVS installed.
228         return 1
229     elif platform in ('win32', 'cygwin'):
230         # Only explicitly search for a 'link' executable on Windows
231         # systems.  Some other systems (e.g. Ubuntu Linux) have an
232         # executable named 'link' and we don't want that to make SCons
233         # think Visual Studio is installed.
234         return env.Detect('link')
235     return None