PageRenderTime 306ms CodeModel.GetById 141ms app.highlight 73ms RepoModel.GetById 88ms app.codeStats 0ms

/Lib/distutils/mwerkscompiler.py

http://unladen-swallow.googlecode.com/
Python | 248 lines | 192 code | 12 blank | 44 comment | 31 complexity | 1c499c66930c349383474c8e59c868bf MD5 | raw file
  1"""distutils.mwerkscompiler
  2
  3Contains MWerksCompiler, an implementation of the abstract CCompiler class
  4for MetroWerks CodeWarrior on the Macintosh. Needs work to support CW on
  5Windows."""
  6
  7# This module should be kept compatible with Python 2.1.
  8
  9__revision__ = "$Id: mwerkscompiler.py 55881 2007-06-11 05:28:45Z neal.norwitz $"
 10
 11import sys, os, string
 12from types import *
 13from distutils.errors import \
 14     DistutilsExecError, DistutilsPlatformError, \
 15     CompileError, LibError, LinkError
 16from distutils.ccompiler import \
 17     CCompiler, gen_preprocess_options, gen_lib_options
 18import distutils.util
 19import distutils.dir_util
 20from distutils import log
 21
 22class MWerksCompiler (CCompiler) :
 23    """Concrete class that implements an interface to MetroWerks CodeWarrior,
 24       as defined by the CCompiler abstract class."""
 25
 26    compiler_type = 'mwerks'
 27
 28    # Just set this so CCompiler's constructor doesn't barf.  We currently
 29    # don't use the 'set_executables()' bureaucracy provided by CCompiler,
 30    # as it really isn't necessary for this sort of single-compiler class.
 31    # Would be nice to have a consistent interface with UnixCCompiler,
 32    # though, so it's worth thinking about.
 33    executables = {}
 34
 35    # Private class data (need to distinguish C from C++ source for compiler)
 36    _c_extensions = ['.c']
 37    _cpp_extensions = ['.cc', '.cpp', '.cxx']
 38    _rc_extensions = ['.r']
 39    _exp_extension = '.exp'
 40
 41    # Needed for the filename generation methods provided by the
 42    # base class, CCompiler.
 43    src_extensions = (_c_extensions + _cpp_extensions +
 44                      _rc_extensions)
 45    res_extension = '.rsrc'
 46    obj_extension = '.obj' # Not used, really
 47    static_lib_extension = '.lib'
 48    shared_lib_extension = '.slb'
 49    static_lib_format = shared_lib_format = '%s%s'
 50    exe_extension = ''
 51
 52
 53    def __init__ (self,
 54                  verbose=0,
 55                  dry_run=0,
 56                  force=0):
 57
 58        CCompiler.__init__ (self, verbose, dry_run, force)
 59
 60
 61    def compile (self,
 62                 sources,
 63                 output_dir=None,
 64                 macros=None,
 65                 include_dirs=None,
 66                 debug=0,
 67                 extra_preargs=None,
 68                 extra_postargs=None,
 69                 depends=None):
 70        (output_dir, macros, include_dirs) = \
 71           self._fix_compile_args (output_dir, macros, include_dirs)
 72        self.__sources = sources
 73        self.__macros = macros
 74        self.__include_dirs = include_dirs
 75        # Don't need extra_preargs and extra_postargs for CW
 76        return []
 77
 78    def link (self,
 79              target_desc,
 80              objects,
 81              output_filename,
 82              output_dir=None,
 83              libraries=None,
 84              library_dirs=None,
 85              runtime_library_dirs=None,
 86              export_symbols=None,
 87              debug=0,
 88              extra_preargs=None,
 89              extra_postargs=None,
 90              build_temp=None,
 91              target_lang=None):
 92        # First fixup.
 93        (objects, output_dir) = self._fix_object_args (objects, output_dir)
 94        (libraries, library_dirs, runtime_library_dirs) = \
 95            self._fix_lib_args (libraries, library_dirs, runtime_library_dirs)
 96
 97        # First examine a couple of options for things that aren't implemented yet
 98        if not target_desc in (self.SHARED_LIBRARY, self.SHARED_OBJECT):
 99            raise DistutilsPlatformError, 'Can only make SHARED_LIBRARY or SHARED_OBJECT targets on the Mac'
100        if runtime_library_dirs:
101            raise DistutilsPlatformError, 'Runtime library dirs not implemented yet'
102        if extra_preargs or extra_postargs:
103            raise DistutilsPlatformError, 'Runtime library dirs not implemented yet'
104        if len(export_symbols) != 1:
105            raise DistutilsPlatformError, 'Need exactly one export symbol'
106        # Next there are various things for which we need absolute pathnames.
107        # This is because we (usually) create the project in a subdirectory of
108        # where we are now, and keeping the paths relative is too much work right
109        # now.
110        sources = map(self._filename_to_abs, self.__sources)
111        include_dirs = map(self._filename_to_abs, self.__include_dirs)
112        if objects:
113            objects = map(self._filename_to_abs, objects)
114        else:
115            objects = []
116        if build_temp:
117            build_temp = self._filename_to_abs(build_temp)
118        else:
119            build_temp = os.curdir()
120        if output_dir:
121            output_filename = os.path.join(output_dir, output_filename)
122        # The output filename needs special handling: splitting it into dir and
123        # filename part. Actually I'm not sure this is really needed, but it
124        # can't hurt.
125        output_filename = self._filename_to_abs(output_filename)
126        output_dir, output_filename = os.path.split(output_filename)
127        # Now we need the short names of a couple of things for putting them
128        # into the project.
129        if output_filename[-8:] == '.ppc.slb':
130            basename = output_filename[:-8]
131        elif output_filename[-11:] == '.carbon.slb':
132            basename = output_filename[:-11]
133        else:
134            basename = os.path.strip(output_filename)[0]
135        projectname = basename + '.mcp'
136        targetname = basename
137        xmlname = basename + '.xml'
138        exportname = basename + '.mcp.exp'
139        prefixname = 'mwerks_%s_config.h'%basename
140        # Create the directories we need
141        distutils.dir_util.mkpath(build_temp, dry_run=self.dry_run)
142        distutils.dir_util.mkpath(output_dir, dry_run=self.dry_run)
143        # And on to filling in the parameters for the project builder
144        settings = {}
145        settings['mac_exportname'] = exportname
146        settings['mac_outputdir'] = output_dir
147        settings['mac_dllname'] = output_filename
148        settings['mac_targetname'] = targetname
149        settings['sysprefix'] = sys.prefix
150        settings['mac_sysprefixtype'] = 'Absolute'
151        sourcefilenames = []
152        sourcefiledirs = []
153        for filename in sources + objects:
154            dirname, filename = os.path.split(filename)
155            sourcefilenames.append(filename)
156            if not dirname in sourcefiledirs:
157                sourcefiledirs.append(dirname)
158        settings['sources'] = sourcefilenames
159        settings['libraries'] = libraries
160        settings['extrasearchdirs'] = sourcefiledirs + include_dirs + library_dirs
161        if self.dry_run:
162            print 'CALLING LINKER IN', os.getcwd()
163            for key, value in settings.items():
164                print '%20.20s %s'%(key, value)
165            return
166        # Build the export file
167        exportfilename = os.path.join(build_temp, exportname)
168        log.debug("\tCreate export file %s", exportfilename)
169        fp = open(exportfilename, 'w')
170        fp.write('%s\n'%export_symbols[0])
171        fp.close()
172        # Generate the prefix file, if needed, and put it in the settings
173        if self.__macros:
174            prefixfilename = os.path.join(os.getcwd(), os.path.join(build_temp, prefixname))
175            fp = open(prefixfilename, 'w')
176            fp.write('#include "mwerks_shcarbon_config.h"\n')
177            for name, value in self.__macros:
178                if value is None:
179                    fp.write('#define %s\n'%name)
180                else:
181                    fp.write('#define %s %s\n'%(name, value))
182            fp.close()
183            settings['prefixname'] = prefixname
184
185        # Build the XML file. We need the full pathname (only lateron, really)
186        # because we pass this pathname to CodeWarrior in an AppleEvent, and CW
187        # doesn't have a clue about our working directory.
188        xmlfilename = os.path.join(os.getcwd(), os.path.join(build_temp, xmlname))
189        log.debug("\tCreate XML file %s", xmlfilename)
190        import mkcwproject
191        xmlbuilder = mkcwproject.cwxmlgen.ProjectBuilder(settings)
192        xmlbuilder.generate()
193        xmldata = settings['tmp_projectxmldata']
194        fp = open(xmlfilename, 'w')
195        fp.write(xmldata)
196        fp.close()
197        # Generate the project. Again a full pathname.
198        projectfilename = os.path.join(os.getcwd(), os.path.join(build_temp, projectname))
199        log.debug('\tCreate project file %s', projectfilename)
200        mkcwproject.makeproject(xmlfilename, projectfilename)
201        # And build it
202        log.debug('\tBuild project')
203        mkcwproject.buildproject(projectfilename)
204
205    def _filename_to_abs(self, filename):
206        # Some filenames seem to be unix-like. Convert to Mac names.
207##        if '/' in filename and ':' in filename:
208##           raise DistutilsPlatformError, 'Filename may be Unix or Mac style: %s'%filename
209##        if '/' in filename:
210##           filename = macurl2path(filename)
211        filename = distutils.util.convert_path(filename)
212        if not os.path.isabs(filename):
213            curdir = os.getcwd()
214            filename = os.path.join(curdir, filename)
215        # Finally remove .. components
216        components = string.split(filename, ':')
217        for i in range(1, len(components)):
218            if components[i] == '..':
219                components[i] = ''
220        return string.join(components, ':')
221
222    def library_dir_option (self, dir):
223        """Return the compiler option to add 'dir' to the list of
224        directories searched for libraries.
225        """
226        return # XXXX Not correct...
227
228    def runtime_library_dir_option (self, dir):
229        """Return the compiler option to add 'dir' to the list of
230        directories searched for runtime libraries.
231        """
232        # Nothing needed or Mwerks/Mac.
233        return
234
235    def library_option (self, lib):
236        """Return the compiler option to add 'dir' to the list of libraries
237        linked into the shared library or executable.
238        """
239        return
240
241    def find_library_file (self, dirs, lib, debug=0):
242        """Search the specified list of directories for a static or shared
243        library file 'lib' and return the full path to that file.  If
244        'debug' true, look for a debugging version (if that makes sense on
245        the current platform).  Return None if 'lib' wasn't found in any of
246        the specified directories.
247        """
248        return 0