File:  [CENS] / python / pyGiNaC / setup3.py
Revision 1.9: download - view: text, annotated - select for diffs - revision graph
Thu May 31 17:57:45 2001 UTC (16 years, 5 months ago) by pearu
Branches: MAIN
CVS tags: HEAD
*** empty log message ***

#!/usr/bin/env python
#
#   Setup file for building/installing PyGiNaC
#
# Requirements:
#   Python 2.0 or higher (http://www.python.org/)
#   GiNaC 0.8.1 or higher (http://www.ginac.de/)
#     For GiNaC, you'll need CLN 1.1 (http://clisp.cons.org/~haible/packages-cln.html)
#       Optional, but recommended, CLN can use GMP 3.1.1 (http://www.swox.com/gmp/)
#   Boost 1.21.1 or higher (http://www.boost.org/)
#  
# Usage:
#   > python setup.py doc install  # this will generate ginac.doc, builds _ginac
#                                  # and installs the package.
#   > python setup.py test -v      # this will generate and run doctests.
#
# In Python `import ginac'. Module `ginac' extension classes exposing
# almost all GiNaC classes to Python.
# See GiNaC documentation (http://www.ginac.de/tutorial/) for usage.
#
# Notes:
# 1. Compilation of PyGiNaC requires more than 160MB memory (with gcc -O2
#   on Intel Linux). However, if you don't need all the GiNaC classes
#   to be exposed to Python, you can edit the list `wrap_input' below
#   to indicate your needs, this will decrease also the memory consumption
#   during the compilation. You don't need to worry about class dependencies
#   they are solved automatically. After you edit `wrap_input', run
#  > python setup.py reinstall
#
# Pearu Peterson <pearu@cens.ioc.ee>
# 30 March 2001
# 23 April 2001

__credits__ = """\
GiNaC group (www.ginac.de), for the GiNaC library.
Boost.Python group (www.boost.org), for BPL that considerably
simplified in exposing GiNaC C++ classes to Python.
"""

import sys,os,string,time

__today__ = time.asctime(time.localtime())
__author__ = 'Pearu Peterson <pearu@cens.ioc.ee>'

#++++++++++++++ Require Python 2.x +++++++++++++

if eval(sys.version[0])<2:
    print "You'll need Python 2.0 or higher to build PyGiNaC"
    sys.exit()

#++++++++++++++ Rebuild ++++++++++++++++++++++++
rebuild = 0
gendoc = 0
gentest = 0
disable_opt = 0 # set 0 for final compilation

if 'test' in sys.argv:
    i = sys.argv.index('test')
    gentest = 1
    if len(sys.argv)>i+1 and sys.argv[i+1]=='-v':
        gentest = 2
        del sys.argv[i+1]
    del sys.argv[i]
if 'doc' in sys.argv:
    del sys.argv[sys.argv.index('doc')]
    gendoc = 1

if 'rebuild' in sys.argv:
    sys.argv[sys.argv.index('rebuild')] = 'build'
    rebuild = 1
if 'reinstall' in sys.argv:
    sys.argv[sys.argv.index('reinstall')] = 'install'
    rebuild = 1

wrap_input = ['symbol','numeric','constant','relational',
              'lst','idx','varidx','power','add','mul',
              'ncmul','pseries','matrix','function','inifcns',
              'function','flags','exvector',
              'indexed','color','clifford','tensor']

wrap_input = ['symbol','numeric','constant','relational',
              'lst','power','add','mul',
              'ncmul','pseries','matrix','function','inifcns',
              'function',
              'flags','exvector']

#wrap_input += ['indexed','color','clifford','tensor']

#wrap_input = ['function','inifcns']
#wrap_input = ['add','mul','power','lst','pseries','relational','matrix','numeric','constant','symbol','varidx']
#wrap_input = ['symbol','function']
#wrap_input = ['symbol','tensor']
#wrap_input = ['symbol','add','mul','lst','numeric','power']

wrap_input = ['ex','symbol','numeric','lst','add','mul','power',
              'inifcns','function','relational','seq',
              'constant','matrix','pseries','ncmul']

#++++++++++++++++ Parameters ++++++++++++++++
#nof_lst_params = 10   # max 15 for ginac, max 10 for boost.python, min 1
#nof_ncmul_params = 6  # max 6
nof_function_params = 12 # max 12 for ginac (depends also on the code in function_py.cpp)
#++++++++++++++++++++ boost +++++++++++++++++++++

boost_dir = '/usr/local/share/boost'

if not os.path.isdir(boost_dir):
    print 'boost_dir=%s must be existing directory.'%(`boost_dir`)
    print 'Get Boost from http://www.boost.org/ and fix its path in setup.py'
    sys.exit()

bpl_dir = os.path.join(boost_dir,'libs','python','src')
bpl_src = map(lambda f:os.path.join(bpl_dir,f),
              ['classes.cpp','conversions.cpp','extension_class.cpp',
               'functions.cpp','init_function.cpp','module_builder.cpp',
               'objects.cpp','types.cpp'])

#++++++++++++++++++++++++++++++++++++++++++++++++
from distutils.core import setup, Extension

#+++HACK: replace linker gcc with g++ +++++++++++
from distutils import sysconfig
save_init_posix = sysconfig._init_posix
def my_init_posix():
    save_init_posix()
    g = sysconfig._config_vars
    if g['LDSHARED'][:3]=='gcc':
        print 'my_init_posix: changing LDSHARED =',`g['LDSHARED']`,
        g['LDSHARED'] = 'g++'+g['LDSHARED'][3:]
        print 'to',`g['LDSHARED']`
    if disable_opt and g['OPT'][:6]=='-g -O2':
        print 'my_init_posix: changing OPT =',`g['OPT']`,
        g['OPT'] = '-g'+g['OPT'][6:]
        print 'to',`g['OPT']`
sysconfig._init_posix = my_init_posix

#+++++++++++++++++ PyGiNaC version ++++++++++++++

wrapper_dir = 'wrappers3'
lib_dir = 'lib3'

major_version = 0
minor_version = 5
try: execfile(os.path.join('tools','get_revision.py'))
except: revision_version = 0
version='%d.%d.%d'%(major_version,minor_version,revision_version)

#++++++++++++++++ ginac._ginac +++++++++++++++++++++

ginac_cpp = os.path.join('src','_ginac.cpp')


ex_src = [
    os.path.join(wrapper_dir,'ginac_enhancements.cpp'),
    os.path.join(wrapper_dir,'ex_py.cpp'),
    os.path.join(wrapper_dir,'python_repr.cpp'),
    os.path.join(wrapper_dir,'python_str.cpp'),
    os.path.join(wrapper_dir,'python_csrc.cpp'),
    os.path.join(wrapper_dir,'pyfunc.cpp'),
    os.path.join(wrapper_dir,'slice.c'),
    ]

if gentest or gendoc:
    import re
    dt_match = re.compile(r'\s*/[*]DT(?P<text>.*?)[*]/',re.M|re.S)
    mdt_match = re.compile(r'\s*/[*]M_DT(?P<text>.*?)[*]/',re.M|re.S)
    fdt_match = re.compile(r'\s*/[*]F_DT(?P<text>.*?)[*]/',re.M|re.S)
    todo_match = re.compile(r'\s*/[*]\s*TODO(?P<text>.*?)[*]/',re.M|re.S)
    fon = os.path.join(lib_dir,'doc','__init__.py')
    fo = open(fon,'w')
    ftodo = open('TODO_py.txt','w')
    
    fo.write('#!/usr/bin/env python\n')
    fo.write('"""PyGiNaC class documentation."""\n')
    fo.write('__version__ = '+`version`+'\n')
    fo.write('__date__ = '+`__today__`+'\n')
    fo.write('__author__ = '+`__author__`+'\n')
    fo.write('__credits__ = '+`__credits__`+'\n')
    fo.write('''\
# This file (ginac/doc/.__init__.py) is auto-generated with
# a command "cd pyGiNaC && ./setup.py test"
# Website: http://cens.ioc.ee/projects/pyginac/\n''')
    fo.write('''\
if __name__ == "__main__":
    import sys,os
    from distutils import util
    sys.path.insert(0,os.path.abspath(os.path.join("build","lib.%s-%s" % (util.get_platform(),sys.version[0:3]))))\n''')
    ex_methods = []
    i = 0
    for s in wrap_input:
        i += 1
        f = s + '_py.cpp'
        fn = os.path.join(wrapper_dir,f)
        if not os.path.isfile(fn): continue
        m = dt_match.findall(open(fn,'r').read())
        if m:
            fo.write('\nclass test_%.2i_%s:\n    """\n'%(i,s))
            fo.write(''.join(m))
            fo.write('\n"""\n')
        m = mdt_match.findall(open(fn,'r').read())
        if m:
            for l in m:
                p,d=l.split('\n',1)
                ex_methods.append('''\n    def %s:\n        """%s"""\n'''%(p.strip(),d.strip()))
        m = todo_match.findall(open(fn,'r').read())
        if m:
            ftodo.write('In %s:\n'%fn)
            ftodo.write('\n'.join(map(lambda s:'\t'+s.strip(),m))+'\n')
        m = fdt_match.findall(open(fn,'r').read())
        if m:
            for l in m:
                p,d=l.split('\n',1)
                fo.write('''def %s:\n    """%s"""\n'''%(p.strip(),d.strip()))
    fo.write('''\
class ex:
%s
if __name__ == "__main__":
    import doctest
    import __init__
    tt = __init__
    doctest.testmod(tt)\n'''%('\n'.join(ex_methods)))
    fo.close()
    ftodo.close()
    if gentest==2:
        os.system('%s %s -v'%(sys.executable,fon))
    elif gentest==1:
        os.system('%s %s'%(sys.executable,fon))
    if gendoc:
        #os.system('cd doc && pydoc -w ginac.html ginac')
        os.system('cd doc && pydoc -w ginac.doc.html ginac.doc')
if len(sys.argv)==1:
    print "PyGiNaC Version",version
    sys.exit()

if rebuild:
    print 'Creating file',os.path.join(wrapper_dir,'ex_py_subs.cpp')
    f=open(os.path.join(wrapper_dir,'ex_py_subs.cpp'),'w')
    for n in wrap_input:
        ff = n + '_py.cpp'
        fn = os.path.join(wrapper_dir,ff)
        if n=='ex': continue
        if not os.path.isfile(fn):
            print 'File does not exist:',fn,'    Skipping.'
            continue
        f.write('#include "%s"\n'%ff)
    f.write('#undef PYGINAC_DEFS\n#undef PYGINAC_EX_PROTOS\n#undef PYGINAC_PROTOS\n')
    f.close()
    os.system('touch wrappers3/ex_py.cpp')
    print 'Creating file',os.path.join(wrapper_dir,'function_py_subs.cpp')
    f=open(os.path.join(wrapper_dir,'function_py_subs.cpp'),'w')
    protos,impl = [],[]
    for k in ['eval','evalf']:
        for i in range(nof_function_params+1):
            a1 = ['const GiNaC::ex & a'+`j` for j in range(i)]+['const GiNaC::ex & ser']
            a2 = ['args.set_item(%s,a%s);'%(j,j) for j in range(i)]
            impl.append('PYGINAC_CB_FUNC(%s,%s,(%s),%s,%s)\n'%(k,i,', '.join(a1),i,' '.join(a2)))
            protos.append('PYGINAC_CB_FUNC_PROTO(%s,%s,(%s));\n'%(k,i,', '.join(a1)))
    if 1:
        k = 'derivative'
        for i in range(nof_function_params+1):
            a1 = ['const GiNaC::ex & a'+`j` for j in range(i)]
            a1 += ['const GiNaC::ex & ser','unsigned n']
            a2 = ['args.set_item(%s,a%s);'%(j,j) for j in range(i)]
            a2 += ['args.set_item(%s,n);'%i]
            impl.append('PYGINAC_CB_FUNC(%s,%s,(%s),%s,%s)\n'%(k,i,', '.join(a1),i+1,' '.join(a2)))
            protos.append('PYGINAC_CB_FUNC_PROTO(%s,%s,(%s));\n'%(k,i,', '.join(a1)))
    if 1:
        k = 'series'
        for i in range(nof_function_params+1):
            a1 = ['const GiNaC::ex & a'+`j` for j in range(i)]
            a1 += ['const GiNaC::ex & ser']
            a1 += ['const GiNaC::relational & rel']
            a1 += ['int order']
            a1 += ['unsigned opt']
            a2 = ['args.set_item(%s,a%s);'%(j,j) for j in range(i)]
            a2+= ['args.set_item(%s,rel);'%i]
            a2+= ['args.set_item(%s,order);'%(i+1)]
            a2+= ['args.set_item(%s,opt);'%(i+2)]
            impl.append('PYGINAC_CB_FUNC(%s,%s,(%s),%s,%s)\n'%(k,i,', '.join(a1),i+3,' '.join(a2)))
            protos.append('PYGINAC_CB_FUNC_PROTO(%s,%s,(%s));\n'%(k,i,', '.join(a1)))
    f.write('#ifdef PYGINAC_PROTOS\n')
    f.write('\n'.join(protos))
    f.write('#else\n')
    f.write('\n'.join(impl))
    f.write('#endif\n')
    f.close() 
           
ginac_ext = Extension('ginac._ginac',
                      sources=ex_src+bpl_src,
                      include_dirs=[boost_dir,wrapper_dir],
                      libraries=['ginac','cln'],
                      library_dirs=[],
                      )

#++++++++++++++++++++ setup +++++++++++++++++++++

setup (name = "PyGiNaC",
       version = version,
       description = "PyGiNaC --- the wrapper of C++ library GiNaC to Python",
       author = "Pearu Peterson",
       author_email = "pearu@cens.ioc.ee",
       maintainer = "Pearu Peterson",
       maintainer_email = "pearu@cens.ioc.ee",
       licence = "LGPL",
       long_description= """
GiNaC is an open framework for symbolic computation within the C++
programming language (http://www.ginac.de/).
PyGiNaC is a Python extension package that implements a complete
and transparent interface to the GiNaC library.
""",
       url = "http://cens.ioc.ee/projects/pyginac/",
       ext_modules = [ ginac_ext ],
       packages = ['ginac','ginac.doc'],
       package_dir = {'ginac': lib_dir,
                      'ginac.doc':os.path.join(lib_dir,'doc') },
       )

print "PyGiNaC Version",version

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>