#!/usr/bin/env python
#
# Setup script for the Python bindings to NEST (PyNEST)
#
# This file is part of NEST.
#
# Copyright (C) 2004 The NEST Initiative
#
# NEST is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# NEST is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with NEST. If not, see <http://www.gnu.org/licenses/>.
#
# Author: Jochen Martin Eppler
# Date: 05/04/2007
#
# Rewritten to make use of Python's distutils package, 01/31/08
# Sven Schrader, Jochen Martin Eppler
#
import sys, os
from string import split
from sys import exit
import distutils.sysconfig as sysc
cxx = '@CXX@'
sources = ['@PKGSRCDIR@/pynest/pynestkernel.cpp',
'@PKGSRCDIR@/pynest/pydatum.cpp',
'@PKGSRCDIR@/pynest/datumtopythonconverter.cpp',
'@PKGSRCDIR@/pynest/pynestpycsa.cpp']
# -fpermissive needed for ndarrayobject.h
# to compile due to comma terminated enumerations
pre_cxxflags = '@AM_CXXFLAGS@ @PYNEST_CXXFLAGS@'
pre_includes = [
'@PKGSRCDIR@/libnestutil',
'@PKGSRCDIR@/librandom',
'@PKGSRCDIR@/sli',
'@PKGSRCDIR@/nestkernel',
'@PKGBUILDDIR@/libnestutil',
'@PKGBUILDDIR@/nest',
'@MUSIC_INCLUDE@',
'@MPI_INCLUDE@',
'@GSL_CFLAGS@',
'@INCLTDL@']
pre_ldflags = [
'-L@PKGBUILDDIR@/nestkernel/.libs',
'-L@PKGBUILDDIR@/librandom/.libs',
'-L@PKGBUILDDIR@/sli/.libs',
'@LINKED_USER_MODULES@',
'@LINKED_MODULES@',
'-lnest',
'-lrandom',
'-lsli',
'@KOMP_LIBS@',
'@SLI_LIBS@',
'@GSL_LIBS@',
'@MUSIC_LIBS@',
'@MPI_LIBS@',
'-lpthread',
'@LIBLTDL@',
'@LIBADD_DL@']
include_dirs = []
library_dirs = []
libraries = []
define_macros = []
setup_flags = []
extra_objects = []
cxxflags = []
extra_link_args = ['@OPENMP_CXXFLAGS@']
runtime_library_dirs = []
for incs in pre_includes :
for inc in incs.split(' '):
if len(inc) > 1:
if '-i' in inc.lower():
include_dirs.append(inc.replace('-I', '').replace('-i',''))
else:
include_dirs.append(inc)
for libs in pre_ldflags :
for lib in libs.split(' '):
if len(lib) > 1:
if lib[1] == 'L' :
library_dirs.append(lib.replace('-L', ''))
if lib[1] == 'l' :
libraries.append(lib.replace('-l', ''))
# read the libtool .la file and extract name and path
if lib.endswith('.la'):
filename=lib.replace('$(top_builddir)','@PKGBUILDDIR@')
try:
fp = open(filename, 'r')
dlname=''
libdir=''
line = fp.readline()
while line:
# dlname: library name
if len(line) > 7 and line.startswith('dlname=') and dlname=='':
dlname = line[8:-2]
# old_library: library name (static module)
if len(line) > 12 and line.startswith('old_library=') and dlname=='':
dlname = line[13:-2]
# ...and its directory
if len(line) > 7 and line.startswith('libdir='):
libdir = line[8:-2]
line = fp.readline()
fp.close()
# hard-code library path to avoid setting environment
if libdir:
runtime_library_dirs += [libdir]
# full location of the object file
if dlname:
extra_objects += [ os.path.dirname(filename) + '/.libs/' + dlname ]
except:
print 'Could not parse file', filename
for flag in pre_cxxflags.strip().split(' '):
if len(flag) > 1:
cxxflags += [flag]
if 'build' in sys.argv :
setup_flags += ['--build-base=@PKGBUILDDIR@/pynest/build']
# look for numpy libs and change flags/macros accordingly
# this dependency cannot be detected by distutils automatically
# HAVE_NUMPY must be set both in build and install mode
try:
import numpy
if 'arrayobject.h' in os.listdir(numpy.__path__[0]+ '/core/include/numpy'):
include_dirs += [ numpy.__path__[0] + '/core/include']
define_macros += [('HAVE_NUMPY', None)]
else:
print '*** No numpy headers installed ***'
except ImportError:
print '*** No numpy package installed ***'
if 'clean' in sys.argv :
# 'make clean' does not work properly; python bug 510186
print '*** running clean, ignore warnings about nonexistent directories ***'
sys.argv = sys.argv + setup_flags
# Change the compiler and linker:
# replace first argumemnt with compiler-variable 'cxx'
vars = sysc.get_config_vars()
for key in ['CC','LDSHARED', 'CXX', 'LINKCC']:
value = vars[key].split()
value[0] = cxx
vars[key] = ' '.join(value)
# the following compiler options are not accepted by newer g++ versions
for opt in ["-Wstrict-prototypes", "-Wno-long-double", "-no-cpp-precomp"]:
vars["CFLAGS"]=sysc.get_config_var("CFLAGS").replace(opt, "")
# from here, it's distutils' way
from distutils.core import setup, Extension
# an empty string is also interpreted as a library to link against.
if extra_link_args == ['']:
extra_link_args = []
extdict = {'include_dirs' : include_dirs,
'libraries' : libraries,
'library_dirs' : library_dirs,
'sources' : sources,
'extra_compile_args' : cxxflags,
'extra_link_args' : extra_link_args,
'define_macros' : define_macros,
'extra_objects' : extra_objects}
# set linker-path correctly when using mpicc.
# distutils sets wrong parameters there. See Python bugs #445902, #1254718
if runtime_library_dirs != [] :
if 'mpi' in cxx.lower() or cxx.lower()[-3:] in ('gcc', 'g++') :
extdict['extra_link_args'] += ['-Wl,-rpath,' + dir for dir in runtime_library_dirs]
else :
extdict['runtime_library_dirs'] = runtime_library_dirs
setup(name = 'PyNEST',
version = '@SLI_VERSION@',
description = 'PyNEST provides Python bindings for NEST',
author = 'The NEST Initiative',
url = 'http://www.nest-initiative.org',
packages = ['nest', 'nest.tests'],
package_dir = {'nest': '@PKGSRCDIR@/pynest/nest'},
package_data = {'nest': ['pynest-init.sli']},
ext_modules = [Extension('nest.pynestkernel', **extdict)])