diff options
Diffstat (limited to 'doc/DISTUTILS.rst.txt')
-rw-r--r-- | doc/DISTUTILS.rst.txt | 489 |
1 files changed, 489 insertions, 0 deletions
diff --git a/doc/DISTUTILS.rst.txt b/doc/DISTUTILS.rst.txt new file mode 100644 index 000000000..b86274447 --- /dev/null +++ b/doc/DISTUTILS.rst.txt @@ -0,0 +1,489 @@ +.. -*- rest -*- + +NumPy Distutils - Users Guide +============================= + +.. contents:: + +SciPy structure +''''''''''''''' + +Currently SciPy project consists of two packages: + +- NumPy (previously called SciPy core) --- it provides packages like: + + + numpy.distutils - extension to Python distutils + + numpy.f2py - a tool to bind Fortran/C codes to Python + + numpy.core - future replacement of Numeric and numarray packages + + numpy.lib - extra utility functions + + numpy.testing - numpy-style tools for unit testing + + etc + +- SciPy --- a collection of scientific tools for Python. + +The aim of this document is to describe how to add new tools to SciPy. + + +Requirements for SciPy packages +''''''''''''''''''''''''''''''' + +SciPy consists of Python packages, called SciPy packages, that are +available to Python users via the ``scipy`` namespace. Each SciPy package +may contain other SciPy packages. And so on. Therefore, the SciPy +directory tree is a tree of packages with arbitrary depth and width. +Any SciPy package may depend on NumPy packages but the dependence on other +SciPy packages should be kept minimal or zero. + +A SciPy package contains, in addition to its sources, the following +files and directories: + + + ``setup.py`` --- building script + + ``info.py`` --- contains documentation and import flags + + ``__init__.py`` --- package initializer + + ``tests/`` --- directory of unittests + +Their contents are described below. + +The ``setup.py`` file +''''''''''''''''''''' + +In order to add a Python package to SciPy, its build script (``setup.py``) +must meet certain requirements. The most important requirement is that the +package define a ``configuration(parent_package='',top_path=None)`` function +which returns a dictionary suitable for passing to +``numpy.distutils.core.setup(..)``. To simplify the construction of +this dictionary, ``numpy.distutils.misc_util`` provides the +``Configuration`` class, described below. + +SciPy pure Python package example +--------------------------------- + +Below is an example of a minimal ``setup.py`` file for a pure SciPy package:: + + #!/usr/bin/env python + def configuration(parent_package='',top_path=None): + from numpy.distutils.misc_util import Configuration + config = Configuration('mypackage',parent_package,top_path) + return config + + if __name__ == "__main__": + from numpy.distutils.core import setup + #setup(**configuration(top_path='').todict()) + setup(configuration=configuration) + +The arguments of the ``configuration`` function specifiy the name of +parent SciPy package (``parent_package``) and the directory location +of the main ``setup.py`` script (``top_path``). These arguments, +along with the name of the current package, should be passed to the +``Configuration`` constructor. + +The ``Configuration`` constructor has a fourth optional argument, +``package_path``, that can be used when package files are located in +a different location than the directory of the ``setup.py`` file. + +Remaining ``Configuration`` arguments are all keyword arguments that will +be used to initialize attributes of ``Configuration`` +instance. Usually, these keywords are the same as the ones that +``setup(..)`` function would expect, for example, ``packages``, +``ext_modules``, ``data_files``, ``include_dirs``, ``libraries``, +``headers``, ``scripts``, ``package_dir``, etc. However, the direct +specification of these keywords is not recommended as the content of +these keyword arguments will not be processed or checked for the +consistency of SciPy building system. + +Finally, ``Configuration`` has ``.todict()`` method that returns all +the configuration data as a dictionary suitable for passing on to the +``setup(..)`` function. + +``Configuration`` instance attributes +------------------------------------- + +In addition to attributes that can be specified via keyword arguments +to ``Configuration`` constructor, ``Configuration`` instance (let us +denote as ``config``) has the following attributes that can be useful +in writing setup scripts: + ++ ``config.name`` - full name of the current package. The names of parent + packages can be extracted as ``config.name.split('.')``. + ++ ``config.local_path`` - path to the location of current ``setup.py`` file. + ++ ``config.top_path`` - path to the location of main ``setup.py`` file. + +``Configuration`` instance methods +---------------------------------- + ++ ``config.todict()`` --- returns configuration dictionary suitable for + passing to ``numpy.distutils.core.setup(..)`` function. + ++ ``config.paths(*paths) --- applies ``glob.glob(..)`` to items of + ``paths`` if necessary. Fixes ``paths`` item that is relative to + ``config.local_path``. + ++ ``config.get_subpackage(subpackage_name,subpackage_path=None)`` --- + returns a list of subpackage configurations. Subpackage is looked in the + current directory under the name ``subpackage_name`` but the path + can be specified also via optional ``subpackage_path`` argument. + If ``subpackage_name`` is specified as ``None`` then the subpackage + name will be taken the basename of ``subpackage_path``. + Any ``*`` used for subpackage names are expanded as wildcards. + ++ ``config.add_subpackage(subpackage_name,subpackage_path=None)`` --- + add SciPy subpackage configuration to the current one. The meaning + and usage of arguments is explained above, see + ``config.get_subpackage()`` method. + ++ ``config.add_data_files(*files)`` --- prepend ``files`` to ``data_files`` + list. If ``files`` item is a tuple then its first element defines + the suffix of where data files are copied relative to package installation + directory and the second element specifies the path to data + files. By default data files are copied under package installation + directory. For example, + + :: + + config.add_data_files('foo.dat', + ('fun',['gun.dat','nun/pun.dat','/tmp/sun.dat']), + 'bar/car.dat'. + '/full/path/to/can.dat', + ) + + will install data files to the following locations + + :: + + <installation path of config.name package>/ + foo.dat + fun/ + gun.dat + pun.dat + sun.dat + bar/ + car.dat + can.dat + + Path to data files can be a function taking no arguments and + returning path(s) to data files -- this is a useful when data files + are generated while building the package. (XXX: explain the step + when this function are called exactly) + ++ ``config.add_data_dir(data_path)`` --- add directory ``data_path`` + recursively to ``data_files``. The whole directory tree starting at + ``data_path`` will be copied under package installation directory. + If ``data_path`` is a tuple then its first element defines + the suffix of where data files are copied relative to package installation + directory and the second element specifies the path to data directory. + By default, data directory are copied under package installation + directory under the basename of ``data_path``. For example, + + :: + + config.add_data_dir('fun') # fun/ contains foo.dat bar/car.dat + config.add_data_dir(('sun','fun')) + config.add_data_dir(('gun','/full/path/to/fun')) + + will install data files to the following locations + + :: + + <installation path of config.name package>/ + fun/ + foo.dat + bar/ + car.dat + sun/ + foo.dat + bar/ + car.dat + gun/ + foo.dat + bar/ + car.dat + ++ ``config.add_include_dirs(*paths)`` --- prepend ``paths`` to + ``include_dirs`` list. This list will be visible to all extension + modules of the current package. + ++ ``config.add_headers(*files)`` --- prepend ``files`` to ``headers`` + list. By default, headers will be installed under + ``<prefix>/include/pythonX.X/<config.name.replace('.','/')>/`` + directory. If ``files`` item is a tuple then it's first argument + specifies the installation suffix relative to + ``<prefix>/include/pythonX.X/`` path. This is a Python distutils + method; its use is discouraged for NumPy and SciPy in favour of + ``config.add_data_files(*files)``. + ++ ``config.add_scripts(*files)`` --- prepend ``files`` to ``scripts`` + list. Scripts will be installed under ``<prefix>/bin/`` directory. + ++ ``config.add_extension(name,sources,*kw)`` --- create and add an + ``Extension`` instance to ``ext_modules`` list. The first argument + ``name`` defines the name of the extension module that will be + installed under ``config.name`` package. The second argument is + a list of sources. ``add_extension`` method takes also keyword + arguments that are passed on to the ``Extension`` constructor. + The list of allowed keywords is the following: ``include_dirs``, + ``define_macros``, ``undef_macros``, ``library_dirs``, ``libraries``, + ``runtime_library_dirs``, ``extra_objects``, ``extra_compile_args``, + ``extra_link_args``, ``export_symbols``, ``swig_opts``, ``depends``, + ``language``, ``f2py_options``, ``module_dirs``, ``extra_info``. + + Note that ``config.paths`` method is applied to all lists that + may contain paths. ``extra_info`` is a dictionary or a list + of dictionaries that content will be appended to keyword arguments. + The list ``depends`` contains paths to files or directories + that the sources of the extension module depend on. If any path + in the ``depends`` list is newer than the extension module, then + the module will be rebuilt. + + The list of sources may contain functions ('source generators') + with a pattern ``def <funcname>(ext, build_dir): return + <source(s) or None>``. If ``funcname`` returns ``None``, no sources + are generated. And if the ``Extension`` instance has no sources + after processing all source generators, no extension module will + be built. This is the recommended way to conditionally define + extension modules. Source generator functions are called by the + ``build_src`` command of ``numpy.distutils``. + + For example, here is a typical source generator function:: + + def generate_source(ext,build_dir): + import os + from distutils.dep_util import newer + target = os.path.join(build_dir,'somesource.c') + if newer(target,__file__): + # create target file + return target + + The first argument contains the Extension instance that can be + useful to access its attributes like ``depends``, ``sources``, + etc. lists and modify them during the building process. + The second argument gives a path to a build directory that must + be used when creating files to a disk. + ++ ``config.add_library(name, sources, **build_info)`` --- add + a library to ``libraries`` list. Allowed keywords arguments + are ``depends``, ``macros``, ``include_dirs``, + ``extra_compiler_args``, ``f2py_options``. See ``.add_extension()`` + method for more information on arguments. + ++ ``config.have_f77c()`` --- return True if Fortran 77 compiler is + available (read: a simple Fortran 77 code compiled succesfully). + ++ ``config.have_f90c()`` --- return True if Fortran 90 compiler is + available (read: a simple Fortran 90 code compiled succesfully). + ++ ``config.get_version()`` --- return version string of the current package, + ``None`` if version information could not be detected. This methods + scans files ``__version__.py``, ``<packagename>_version.py``, + ``version.py``, ``__svn_version__.py`` for string variables + ``version``, ``__version__``, ``<packagename>_version``. + ++ ``config.make_svn_version_py()`` --- appends a data function to + ``data_files`` list that will generate ``__svn_version__.py`` file + to the current package directory. The file will be removed from + the source directory when Python exits. + ++ ``config.get_build_temp_dir()`` --- return a path to a temporary + directory. This is the place where one should build temporary + files. + ++ ``config.get_distribution()`` --- return distutils ``Distribution`` + instance. + ++ ``config.get_config_cmd()`` --- returns ``numpy.distutils`` config + command instance. + ++ ``config.get_info(*names)`` --- + +Template files +-------------- + +XXX: Describe how files with extensions ``.f.src``, ``.pyf.src``, +``.c.src``, etc. are pre-processed by the ``build_src`` command. + +Useful functions in ``numpy.distutils.misc_util`` +------------------------------------------------- + ++ ``get_numpy_include_dirs()`` --- return a list of NumPy base + include directories. NumPy base include directories contain + header files such as ``numpy/arrayobject.h``, ``numpy/funcobject.h`` + etc. For installed NumPy the returned list has length 1 + but when building NumPy the list may contain more directories, + for example, a path to ``config.h`` file that + ``numpy/base/setup.py`` file generates and is used by ``numpy`` + header files. + ++ ``append_path(prefix,path)`` --- smart append ``path`` to ``prefix``. + ++ ``gpaths(paths, local_path='')`` --- apply glob to paths and prepend + ``local_path`` if needed. + ++ ``njoin(*path)`` --- join pathname components + convert ``/``-separated path + to ``os.sep``-separated path and resolve ``..``, ``.`` from paths. + Ex. ``njoin('a',['b','./c'],'..','g') -> os.path.join('a','b','g')``. + ++ ``minrelpath(path)`` --- resolves dots in ``path``. + ++ ``rel_path(path, parent_path)`` --- return ``path`` relative to ``parent_path``. + ++ ``def get_cmd(cmdname,_cache={})`` --- returns ``numpy.distutils`` + command instance. + ++ ``all_strings(lst)`` + ++ ``has_f_sources(sources)`` + ++ ``has_cxx_sources(sources)`` + ++ ``filter_sources(sources)`` --- return ``c_sources, cxx_sources, + f_sources, fmodule_sources`` + ++ ``get_dependencies(sources)`` + ++ ``is_local_src_dir(directory)`` + ++ ``get_ext_source_files(ext)`` + ++ ``get_script_files(scripts)`` + ++ ``get_lib_source_files(lib)`` + ++ ``get_data_files(data)`` + ++ ``dot_join(*args)`` --- join non-zero arguments with a dot. + ++ ``get_frame(level=0)`` --- return frame object from call stack with given level. + ++ ``cyg2win32(path)`` + ++ ``mingw32()`` --- return ``True`` when using mingw32 environment. + ++ ``terminal_has_colors()``, ``red_text(s)``, ``green_text(s)``, + ``yellow_text(s)``, ``blue_text(s)``, ``cyan_text(s)`` + ++ ``get_path(mod_name,parent_path=None)`` --- return path of a module + relative to parent_path when given. Handles also ``__main__`` and + ``__builtin__`` modules. + ++ ``allpath(name)`` --- replaces ``/`` with ``os.sep`` in ``name``. + ++ ``cxx_ext_match``, ``fortran_ext_match``, ``f90_ext_match``, + ``f90_module_name_match`` + +``numpy.distutils.system_info`` module +-------------------------------------- + ++ ``get_info(name,notfound_action=0)`` ++ ``combine_paths(*args,**kws)`` ++ ``show_all()`` + +``numpy.distutils.cpuinfo`` module +---------------------------------- + ++ ``cpuinfo`` + +``numpy.distutils.log`` module +------------------------------ + ++ ``set_verbosity(v)`` + + +``numpy.distutils.exec_command`` module +--------------------------------------- + ++ ``get_pythonexe()`` ++ ``find_executable(exe, path=None)`` ++ ``exec_command( command, execute_in='', use_shell=None, use_tee=None, **env )`` + +The ``info.py`` file +'''''''''''''''''''' + +SciPy package import hooks assume that each package contains a +``info.py`` file. This file contains overall documentation about the package +and variables defining the order of package imports, dependency +relations between packages, etc. + +On import, the following information will be looked for in ``info.py``: + +__doc__ + The documentation string of the package. + +__doc_title__ + The title of the package. If not defined then the first non-empty + line of ``__doc__`` will be used. + +__all__ + List of symbols that package exports. Optional. + +global_symbols + List of names that should be imported to numpy name space. To import + all symbols to ``numpy`` namespace, define ``global_symbols=['*']``. + +depends + List of names that the package depends on. Prefix ``numpy.`` + will be automatically added to package names. For example, + use ``testing`` to indicate dependence on ``numpy.testing`` + package. Default value is ``[]``. + +postpone_import + Boolean variable indicating that importing the package should be + postponed until the first attempt of its usage. Default value is ``False``. + Depreciated. + +The ``__init__.py`` file +'''''''''''''''''''''''' + +To speed up the import time and minimize memory usage, numpy +uses ``ppimport`` hooks to transparently postpone importing large modules, +which might not be used during the SciPy session. In order to +have access to the documentation of all SciPy packages, including +postponed packages, the docstring from ``info.py`` is imported +into ``__init__.py``. + +The header of a typical ``__init__.py`` is:: + + # + # Package ... - ... + # + + from info import __doc__ + ... + + from numpy.testing import Tester + test = Tester().test + bench = Tester().bench + +Extra features in NumPy Distutils +''''''''''''''''''''''''''''''''' + +Specifing config_fc options for libraries in setup.py script +------------------------------------------------------------ + +It is possible to specify config_fc options in setup.py scripts. +For example, using + + config.add_library('library', + sources=[...], + config_fc={'noopt':(__file__,1)}) + +will compile the ``library`` sources without optimization flags. + +It's recommended to specify only those config_fc options in such a way +that are compiler independent. + +Getting extra Fortran 77 compiler options from source +----------------------------------------------------- + +Some old Fortran codes need special compiler options in order to +work correctly. In order to specify compiler options per source +file, ``numpy.distutils`` Fortran compiler looks for the following +pattern:: + + CF77FLAGS(<fcompiler type>) = <fcompiler f77flags> + +in the first 20 lines of the source and use the ``f77flags`` for +specified type of the fcompiler (the first character ``C`` is optional). + +TODO: This feature can be easily extended for Fortran 90 codes as +well. Let us know if you would need such a feature. |