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.

267 lines
10 KiB

6 years ago
  1. """SCons.Platform
  2. SCons platform selection.
  3. This looks for modules that define a callable object that can modify a
  4. construction environment as appropriate for a given platform.
  5. Note that we take a more simplistic view of "platform" than Python does.
  6. We're looking for a single string that determines a set of
  7. tool-independent variables with which to initialize a construction
  8. environment. Consequently, we'll examine both sys.platform and os.name
  9. (and anything else that might come in to play) in order to return some
  10. specification which is unique enough for our purposes.
  11. Note that because this subsystem just *selects* a callable that can
  12. modify a construction environment, it's possible for people to define
  13. their own "platform specification" in an arbitrary callable function.
  14. No one needs to use or tie in to this subsystem in order to roll
  15. their own platform definition.
  16. """
  17. #
  18. # Copyright (c) 2001 - 2017 The SCons Foundation
  19. #
  20. # Permission is hereby granted, free of charge, to any person obtaining
  21. # a copy of this software and associated documentation files (the
  22. # "Software"), to deal in the Software without restriction, including
  23. # without limitation the rights to use, copy, modify, merge, publish,
  24. # distribute, sublicense, and/or sell copies of the Software, and to
  25. # permit persons to whom the Software is furnished to do so, subject to
  26. # the following conditions:
  27. #
  28. # The above copyright notice and this permission notice shall be included
  29. # in all copies or substantial portions of the Software.
  30. #
  31. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
  32. # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  33. # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  34. # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  35. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  36. # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  37. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  38. #
  39. from __future__ import print_function
  40. __revision__ = "src/engine/SCons/Platform/__init__.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
  41. import SCons.compat
  42. import imp
  43. import os
  44. import sys
  45. import tempfile
  46. import SCons.Errors
  47. import SCons.Subst
  48. import SCons.Tool
  49. def platform_default():
  50. """Return the platform string for our execution environment.
  51. The returned value should map to one of the SCons/Platform/*.py
  52. files. Since we're architecture independent, though, we don't
  53. care about the machine architecture.
  54. """
  55. osname = os.name
  56. if osname == 'java':
  57. osname = os._osType
  58. if osname == 'posix':
  59. if sys.platform == 'cygwin':
  60. return 'cygwin'
  61. elif sys.platform.find('irix') != -1:
  62. return 'irix'
  63. elif sys.platform.find('sunos') != -1:
  64. return 'sunos'
  65. elif sys.platform.find('hp-ux') != -1:
  66. return 'hpux'
  67. elif sys.platform.find('aix') != -1:
  68. return 'aix'
  69. elif sys.platform.find('darwin') != -1:
  70. return 'darwin'
  71. else:
  72. return 'posix'
  73. elif os.name == 'os2':
  74. return 'os2'
  75. else:
  76. return sys.platform
  77. def platform_module(name = platform_default()):
  78. """Return the imported module for the platform.
  79. This looks for a module name that matches the specified argument.
  80. If the name is unspecified, we fetch the appropriate default for
  81. our execution environment.
  82. """
  83. full_name = 'SCons.Platform.' + name
  84. if full_name not in sys.modules:
  85. if os.name == 'java':
  86. eval(full_name)
  87. else:
  88. try:
  89. file, path, desc = imp.find_module(name,
  90. sys.modules['SCons.Platform'].__path__)
  91. try:
  92. mod = imp.load_module(full_name, file, path, desc)
  93. finally:
  94. if file:
  95. file.close()
  96. except ImportError:
  97. try:
  98. import zipimport
  99. importer = zipimport.zipimporter( sys.modules['SCons.Platform'].__path__[0] )
  100. mod = importer.load_module(full_name)
  101. except ImportError:
  102. raise SCons.Errors.UserError("No platform named '%s'" % name)
  103. setattr(SCons.Platform, name, mod)
  104. return sys.modules[full_name]
  105. def DefaultToolList(platform, env):
  106. """Select a default tool list for the specified platform.
  107. """
  108. return SCons.Tool.tool_list(platform, env)
  109. class PlatformSpec(object):
  110. def __init__(self, name, generate):
  111. self.name = name
  112. self.generate = generate
  113. def __call__(self, *args, **kw):
  114. return self.generate(*args, **kw)
  115. def __str__(self):
  116. return self.name
  117. class TempFileMunge(object):
  118. """A callable class. You can set an Environment variable to this,
  119. then call it with a string argument, then it will perform temporary
  120. file substitution on it. This is used to circumvent the long command
  121. line limitation.
  122. Example usage:
  123. env["TEMPFILE"] = TempFileMunge
  124. env["LINKCOM"] = "${TEMPFILE('$LINK $TARGET $SOURCES','$LINKCOMSTR')}"
  125. By default, the name of the temporary file used begins with a
  126. prefix of '@'. This may be configred for other tool chains by
  127. setting '$TEMPFILEPREFIX'.
  128. env["TEMPFILEPREFIX"] = '-@' # diab compiler
  129. env["TEMPFILEPREFIX"] = '-via' # arm tool chain
  130. """
  131. def __init__(self, cmd, cmdstr = None):
  132. self.cmd = cmd
  133. self.cmdstr = cmdstr
  134. def __call__(self, target, source, env, for_signature):
  135. if for_signature:
  136. # If we're being called for signature calculation, it's
  137. # because we're being called by the string expansion in
  138. # Subst.py, which has the logic to strip any $( $) that
  139. # may be in the command line we squirreled away. So we
  140. # just return the raw command line and let the upper
  141. # string substitution layers do their thing.
  142. return self.cmd
  143. # Now we're actually being called because someone is actually
  144. # going to try to execute the command, so we have to do our
  145. # own expansion.
  146. cmd = env.subst_list(self.cmd, SCons.Subst.SUBST_CMD, target, source)[0]
  147. try:
  148. maxline = int(env.subst('$MAXLINELENGTH'))
  149. except ValueError:
  150. maxline = 2048
  151. length = 0
  152. for c in cmd:
  153. length += len(c)
  154. length += len(cmd) - 1
  155. if length <= maxline:
  156. return self.cmd
  157. # Check if we already created the temporary file for this target
  158. # It should have been previously done by Action.strfunction() call
  159. node = target[0] if SCons.Util.is_List(target) else target
  160. cmdlist = getattr(node.attributes, 'tempfile_cmdlist', None) \
  161. if node is not None else None
  162. if cmdlist is not None :
  163. return cmdlist
  164. # We do a normpath because mktemp() has what appears to be
  165. # a bug in Windows that will use a forward slash as a path
  166. # delimiter. Windows's link mistakes that for a command line
  167. # switch and barfs.
  168. #
  169. # We use the .lnk suffix for the benefit of the Phar Lap
  170. # linkloc linker, which likes to append an .lnk suffix if
  171. # none is given.
  172. (fd, tmp) = tempfile.mkstemp('.lnk', text=True)
  173. native_tmp = SCons.Util.get_native_path(os.path.normpath(tmp))
  174. if env.get('SHELL',None) == 'sh':
  175. # The sh shell will try to escape the backslashes in the
  176. # path, so unescape them.
  177. native_tmp = native_tmp.replace('\\', r'\\\\')
  178. # In Cygwin, we want to use rm to delete the temporary
  179. # file, because del does not exist in the sh shell.
  180. rm = env.Detect('rm') or 'del'
  181. else:
  182. # Don't use 'rm' if the shell is not sh, because rm won't
  183. # work with the Windows shells (cmd.exe or command.com) or
  184. # Windows path names.
  185. rm = 'del'
  186. prefix = env.subst('$TEMPFILEPREFIX')
  187. if not prefix:
  188. prefix = '@'
  189. args = list(map(SCons.Subst.quote_spaces, cmd[1:]))
  190. os.write(fd, bytearray(" ".join(args) + "\n",'utf-8'))
  191. os.close(fd)
  192. # XXX Using the SCons.Action.print_actions value directly
  193. # like this is bogus, but expedient. This class should
  194. # really be rewritten as an Action that defines the
  195. # __call__() and strfunction() methods and lets the
  196. # normal action-execution logic handle whether or not to
  197. # print/execute the action. The problem, though, is all
  198. # of that is decided before we execute this method as
  199. # part of expanding the $TEMPFILE construction variable.
  200. # Consequently, refactoring this will have to wait until
  201. # we get more flexible with allowing Actions to exist
  202. # independently and get strung together arbitrarily like
  203. # Ant tasks. In the meantime, it's going to be more
  204. # user-friendly to not let obsession with architectural
  205. # purity get in the way of just being helpful, so we'll
  206. # reach into SCons.Action directly.
  207. if SCons.Action.print_actions:
  208. cmdstr = env.subst(self.cmdstr, SCons.Subst.SUBST_RAW, target,
  209. source) if self.cmdstr is not None else ''
  210. # Print our message only if XXXCOMSTR returns an empty string
  211. if len(cmdstr) == 0 :
  212. print("Using tempfile "+native_tmp+" for command line:\n"+
  213. str(cmd[0]) + " " + " ".join(args))
  214. # Store the temporary file command list into the target Node.attributes
  215. # to avoid creating two temporary files one for print and one for execute.
  216. cmdlist = [ cmd[0], prefix + native_tmp + '\n' + rm, native_tmp ]
  217. if node is not None:
  218. try :
  219. setattr(node.attributes, 'tempfile_cmdlist', cmdlist)
  220. except AttributeError:
  221. pass
  222. return cmdlist
  223. def Platform(name = platform_default()):
  224. """Select a canned Platform specification.
  225. """
  226. module = platform_module(name)
  227. spec = PlatformSpec(name, module.generate)
  228. return spec
  229. # Local Variables:
  230. # tab-width:4
  231. # indent-tabs-mode:nil
  232. # End:
  233. # vim: set expandtab tabstop=4 shiftwidth=4: