Home | History | Annotate | Download | only in distutils
      1 """distutils.core
      2 
      3 The only module that needs to be imported to use the Distutils; provides
      4 the 'setup' function (which is to be called from the setup script).  Also
      5 indirectly provides the Distribution and Command classes, although they are
      6 really defined in distutils.dist and distutils.cmd.
      7 """
      8 
      9 __revision__ = "$Id$"
     10 
     11 import sys
     12 import os
     13 
     14 from distutils.debug import DEBUG
     15 from distutils.errors import (DistutilsSetupError, DistutilsArgError,
     16                               DistutilsError, CCompilerError)
     17 from distutils.util import grok_environment_error
     18 
     19 # Mainly import these so setup scripts can "from distutils.core import" them.
     20 from distutils.dist import Distribution
     21 from distutils.cmd import Command
     22 from distutils.config import PyPIRCCommand
     23 from distutils.extension import Extension
     24 
     25 # This is a barebones help message generated displayed when the user
     26 # runs the setup script with no arguments at all.  More useful help
     27 # is generated with various --help options: global help, list commands,
     28 # and per-command help.
     29 USAGE = """\
     30 usage: %(script)s [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]
     31    or: %(script)s --help [cmd1 cmd2 ...]
     32    or: %(script)s --help-commands
     33    or: %(script)s cmd --help
     34 """
     35 
     36 def gen_usage(script_name):
     37     script = os.path.basename(script_name)
     38     return USAGE % {'script': script}
     39 
     40 
     41 # Some mild magic to control the behaviour of 'setup()' from 'run_setup()'.
     42 _setup_stop_after = None
     43 _setup_distribution = None
     44 
     45 # Legal keyword arguments for the setup() function
     46 setup_keywords = ('distclass', 'script_name', 'script_args', 'options',
     47                   'name', 'version', 'author', 'author_email',
     48                   'maintainer', 'maintainer_email', 'url', 'license',
     49                   'description', 'long_description', 'keywords',
     50                   'platforms', 'classifiers', 'download_url',
     51                   'requires', 'provides', 'obsoletes',
     52                   )
     53 
     54 # Legal keyword arguments for the Extension constructor
     55 extension_keywords = ('name', 'sources', 'include_dirs',
     56                       'define_macros', 'undef_macros',
     57                       'library_dirs', 'libraries', 'runtime_library_dirs',
     58                       'extra_objects', 'extra_compile_args', 'extra_link_args',
     59                       'swig_opts', 'export_symbols', 'depends', 'language')
     60 
     61 def setup(**attrs):
     62     """The gateway to the Distutils: do everything your setup script needs
     63     to do, in a highly flexible and user-driven way.  Briefly: create a
     64     Distribution instance; find and parse config files; parse the command
     65     line; run each Distutils command found there, customized by the options
     66     supplied to 'setup()' (as keyword arguments), in config files, and on
     67     the command line.
     68 
     69     The Distribution instance might be an instance of a class supplied via
     70     the 'distclass' keyword argument to 'setup'; if no such class is
     71     supplied, then the Distribution class (in dist.py) is instantiated.
     72     All other arguments to 'setup' (except for 'cmdclass') are used to set
     73     attributes of the Distribution instance.
     74 
     75     The 'cmdclass' argument, if supplied, is a dictionary mapping command
     76     names to command classes.  Each command encountered on the command line
     77     will be turned into a command class, which is in turn instantiated; any
     78     class found in 'cmdclass' is used in place of the default, which is
     79     (for command 'foo_bar') class 'foo_bar' in module
     80     'distutils.command.foo_bar'.  The command class must provide a
     81     'user_options' attribute which is a list of option specifiers for
     82     'distutils.fancy_getopt'.  Any command-line options between the current
     83     and the next command are used to set attributes of the current command
     84     object.
     85 
     86     When the entire command-line has been successfully parsed, calls the
     87     'run()' method on each command object in turn.  This method will be
     88     driven entirely by the Distribution object (which each command object
     89     has a reference to, thanks to its constructor), and the
     90     command-specific options that became attributes of each command
     91     object.
     92     """
     93 
     94     global _setup_stop_after, _setup_distribution
     95 
     96     # Determine the distribution class -- either caller-supplied or
     97     # our Distribution (see below).
     98     klass = attrs.get('distclass')
     99     if klass:
    100         del attrs['distclass']
    101     else:
    102         klass = Distribution
    103 
    104     if 'script_name' not in attrs:
    105         attrs['script_name'] = os.path.basename(sys.argv[0])
    106     if 'script_args' not in attrs:
    107         attrs['script_args'] = sys.argv[1:]
    108 
    109     # Create the Distribution instance, using the remaining arguments
    110     # (ie. everything except distclass) to initialize it
    111     try:
    112         _setup_distribution = dist = klass(attrs)
    113     except DistutilsSetupError, msg:
    114         if 'name' in attrs:
    115             raise SystemExit, "error in %s setup command: %s" % \
    116                   (attrs['name'], msg)
    117         else:
    118             raise SystemExit, "error in setup command: %s" % msg
    119 
    120     if _setup_stop_after == "init":
    121         return dist
    122 
    123     # Find and parse the config file(s): they will override options from
    124     # the setup script, but be overridden by the command line.
    125     dist.parse_config_files()
    126 
    127     if DEBUG:
    128         print "options (after parsing config files):"
    129         dist.dump_option_dicts()
    130 
    131     if _setup_stop_after == "config":
    132         return dist
    133 
    134     # Parse the command line and override config files; any
    135     # command-line errors are the end user's fault, so turn them into
    136     # SystemExit to suppress tracebacks.
    137     try:
    138         ok = dist.parse_command_line()
    139     except DistutilsArgError, msg:
    140         raise SystemExit, gen_usage(dist.script_name) + "\nerror: %s" % msg
    141 
    142     if DEBUG:
    143         print "options (after parsing command line):"
    144         dist.dump_option_dicts()
    145 
    146     if _setup_stop_after == "commandline":
    147         return dist
    148 
    149     # And finally, run all the commands found on the command line.
    150     if ok:
    151         try:
    152             dist.run_commands()
    153         except KeyboardInterrupt:
    154             raise SystemExit, "interrupted"
    155         except (IOError, os.error), exc:
    156             error = grok_environment_error(exc)
    157 
    158             if DEBUG:
    159                 sys.stderr.write(error + "\n")
    160                 raise
    161             else:
    162                 raise SystemExit, error
    163 
    164         except (DistutilsError,
    165                 CCompilerError), msg:
    166             if DEBUG:
    167                 raise
    168             else:
    169                 raise SystemExit, "error: " + str(msg)
    170 
    171     return dist
    172 
    173 
    174 def run_setup(script_name, script_args=None, stop_after="run"):
    175     """Run a setup script in a somewhat controlled environment, and
    176     return the Distribution instance that drives things.  This is useful
    177     if you need to find out the distribution meta-data (passed as
    178     keyword args from 'script' to 'setup()', or the contents of the
    179     config files or command-line.
    180 
    181     'script_name' is a file that will be run with 'execfile()';
    182     'sys.argv[0]' will be replaced with 'script' for the duration of the
    183     call.  'script_args' is a list of strings; if supplied,
    184     'sys.argv[1:]' will be replaced by 'script_args' for the duration of
    185     the call.
    186 
    187     'stop_after' tells 'setup()' when to stop processing; possible
    188     values:
    189       init
    190         stop after the Distribution instance has been created and
    191         populated with the keyword arguments to 'setup()'
    192       config
    193         stop after config files have been parsed (and their data
    194         stored in the Distribution instance)
    195       commandline
    196         stop after the command-line ('sys.argv[1:]' or 'script_args')
    197         have been parsed (and the data stored in the Distribution)
    198       run [default]
    199         stop after all commands have been run (the same as if 'setup()'
    200         had been called in the usual way
    201 
    202     Returns the Distribution instance, which provides all information
    203     used to drive the Distutils.
    204     """
    205     if stop_after not in ('init', 'config', 'commandline', 'run'):
    206         raise ValueError, "invalid value for 'stop_after': %r" % (stop_after,)
    207 
    208     global _setup_stop_after, _setup_distribution
    209     _setup_stop_after = stop_after
    210 
    211     save_argv = sys.argv
    212     g = {'__file__': script_name}
    213     l = {}
    214     try:
    215         try:
    216             sys.argv[0] = script_name
    217             if script_args is not None:
    218                 sys.argv[1:] = script_args
    219             f = open(script_name)
    220             try:
    221                 exec f.read() in g, l
    222             finally:
    223                 f.close()
    224         finally:
    225             sys.argv = save_argv
    226             _setup_stop_after = None
    227     except SystemExit:
    228         # Hmm, should we do something if exiting with a non-zero code
    229         # (ie. error)?
    230         pass
    231     except:
    232         raise
    233 
    234     if _setup_distribution is None:
    235         raise RuntimeError, \
    236               ("'distutils.core.setup()' was never called -- "
    237                "perhaps '%s' is not a Distutils setup script?") % \
    238               script_name
    239 
    240     # I wonder if the setup script's namespace -- g and l -- would be of
    241     # any interest to callers?
    242     return _setup_distribution
    243