(root)/
Python-3.11.7/
Tools/
freeze/
checkextensions_win32.py
       1  """Extension management for Windows.
       2  
       3  Under Windows it is unlikely the .obj files are of use, as special compiler options
       4  are needed (primarily to toggle the behavior of "public" symbols.
       5  
       6  I don't consider it worth parsing the MSVC makefiles for compiler options.  Even if
       7  we get it just right, a specific freeze application may have specific compiler
       8  options anyway (eg, to enable or disable specific functionality)
       9  
      10  So my basic strategy is:
      11  
      12  * Have some Windows INI files which "describe" one or more extension modules.
      13    (Freeze comes with a default one for all known modules - but you can specify
      14    your own).
      15  * This description can include:
      16    - The MSVC .dsp file for the extension.  The .c source file names
      17      are extracted from there.
      18    - Specific compiler/linker options
      19    - Flag to indicate if Unicode compilation is expected.
      20  
      21  At the moment the name and location of this INI file is hardcoded,
      22  but an obvious enhancement would be to provide command line options.
      23  """
      24  
      25  import os, sys
      26  try:
      27      import win32api
      28  except ImportError:
      29      win32api = None # User has already been warned
      30  
      31  class ESC[4;38;5;81mCExtension:
      32      """An abstraction of an extension implemented in C/C++
      33      """
      34      def __init__(self, name, sourceFiles):
      35          self.name = name
      36          # A list of strings defining additional compiler options.
      37          self.sourceFiles = sourceFiles
      38          # A list of special compiler options to be applied to
      39          # all source modules in this extension.
      40          self.compilerOptions = []
      41          # A list of .lib files the final .EXE will need.
      42          self.linkerLibs = []
      43  
      44      def GetSourceFiles(self):
      45          return self.sourceFiles
      46  
      47      def AddCompilerOption(self, option):
      48          self.compilerOptions.append(option)
      49      def GetCompilerOptions(self):
      50          return self.compilerOptions
      51  
      52      def AddLinkerLib(self, lib):
      53          self.linkerLibs.append(lib)
      54      def GetLinkerLibs(self):
      55          return self.linkerLibs
      56  
      57  def checkextensions(unknown, extra_inis, prefix):
      58      # Create a table of frozen extensions
      59  
      60      defaultMapName = os.path.join( os.path.split(sys.argv[0])[0], "extensions_win32.ini")
      61      if not os.path.isfile(defaultMapName):
      62          sys.stderr.write("WARNING: %s can not be found - standard extensions may not be found\n" % defaultMapName)
      63      else:
      64          # must go on end, so other inis can override.
      65          extra_inis.append(defaultMapName)
      66  
      67      ret = []
      68      for mod in unknown:
      69          for ini in extra_inis:
      70  #                       print "Looking for", mod, "in", win32api.GetFullPathName(ini),"...",
      71              defn = get_extension_defn( mod, ini, prefix )
      72              if defn is not None:
      73  #                               print "Yay - found it!"
      74                  ret.append( defn )
      75                  break
      76  #                       print "Nope!"
      77          else: # For not broken!
      78              sys.stderr.write("No definition of module %s in any specified map file.\n" % (mod))
      79  
      80      return ret
      81  
      82  def get_extension_defn(moduleName, mapFileName, prefix):
      83      if win32api is None: return None
      84      os.environ['PYTHONPREFIX'] = prefix
      85      dsp = win32api.GetProfileVal(moduleName, "dsp", "", mapFileName)
      86      if dsp=="":
      87          return None
      88  
      89      # We allow environment variables in the file name
      90      dsp = win32api.ExpandEnvironmentStrings(dsp)
      91      # If the path to the .DSP file is not absolute, assume it is relative
      92      # to the description file.
      93      if not os.path.isabs(dsp):
      94          dsp = os.path.join( os.path.split(mapFileName)[0], dsp)
      95      # Parse it to extract the source files.
      96      sourceFiles = parse_dsp(dsp)
      97      if sourceFiles is None:
      98          return None
      99  
     100      module = CExtension(moduleName, sourceFiles)
     101      # Put the path to the DSP into the environment so entries can reference it.
     102      os.environ['dsp_path'] = os.path.split(dsp)[0]
     103      os.environ['ini_path'] = os.path.split(mapFileName)[0]
     104  
     105      cl_options = win32api.GetProfileVal(moduleName, "cl", "", mapFileName)
     106      if cl_options:
     107          module.AddCompilerOption(win32api.ExpandEnvironmentStrings(cl_options))
     108  
     109      exclude = win32api.GetProfileVal(moduleName, "exclude", "", mapFileName)
     110      exclude = exclude.split()
     111  
     112      if win32api.GetProfileVal(moduleName, "Unicode", 0, mapFileName):
     113          module.AddCompilerOption('/D UNICODE /D _UNICODE')
     114  
     115      libs = win32api.GetProfileVal(moduleName, "libs", "", mapFileName).split()
     116      for lib in libs:
     117          module.AddLinkerLib(win32api.ExpandEnvironmentStrings(lib))
     118  
     119      for exc in exclude:
     120          if exc in module.sourceFiles:
     121              module.sourceFiles.remove(exc)
     122  
     123      return module
     124  
     125  # Given an MSVC DSP file, locate C source files it uses
     126  # returns a list of source files.
     127  def parse_dsp(dsp):
     128  #       print "Processing", dsp
     129      # For now, only support
     130      ret = []
     131      dsp_path, dsp_name = os.path.split(dsp)
     132      try:
     133          with open(dsp, "r") as fp:
     134              lines = fp.readlines()
     135      except IOError as msg:
     136          sys.stderr.write("%s: %s\n" % (dsp, msg))
     137          return None
     138      for line in lines:
     139          fields = line.strip().split("=", 2)
     140          if fields[0]=="SOURCE":
     141              if os.path.splitext(fields[1])[1].lower() in ['.cpp', '.c']:
     142                  ret.append( win32api.GetFullPathName(os.path.join(dsp_path, fields[1] ) ) )
     143      return ret
     144  
     145  def write_extension_table(fname, modules):
     146      fp = open(fname, "w")
     147      try:
     148          fp.write (ext_src_header)
     149          # Write fn protos
     150          for module in modules:
     151              # bit of a hack for .pyd's as part of packages.
     152              name = module.name.split('.')[-1]
     153              fp.write('extern void init%s(void);\n' % (name) )
     154          # Write the table
     155          fp.write (ext_tab_header)
     156          for module in modules:
     157              name = module.name.split('.')[-1]
     158              fp.write('\t{"%s", init%s},\n' % (name, name) )
     159  
     160          fp.write (ext_tab_footer)
     161          fp.write(ext_src_footer)
     162      finally:
     163          fp.close()
     164  
     165  
     166  ext_src_header = """\
     167  #include "Python.h"
     168  """
     169  
     170  ext_tab_header = """\
     171  
     172  static struct _inittab extensions[] = {
     173  """
     174  
     175  ext_tab_footer = """\
     176          /* Sentinel */
     177          {0, 0}
     178  };
     179  """
     180  
     181  ext_src_footer = """\
     182  extern DL_IMPORT(int) PyImport_ExtendInittab(struct _inittab *newtab);
     183  
     184  int PyInitFrozenExtensions()
     185  {
     186          return PyImport_ExtendInittab(extensions);
     187  }
     188  
     189  """