setup.py.in 9.49 KB
#############################################################################
# Disutils setup file for gammalib Python extension module                  #
# ------------------------------------------------------------------------- #
# Copyright (C) 2011-2014 Juergen Knoedlseder                               #
# ------------------------------------------------------------------------- #
#                                                                           #
#  This program 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 3 of the License, or        #
#  (at your option) any later version.                                      #
#                                                                           #
#  This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.    #
#                                                                           #
#############################################################################

from distutils.core import setup, Extension
from distutils import sysconfig
import glob
import os
import sys
import re

# Define package name
pkg_name = 'gammalib'

# Define core modules
core_modules = ['app', 'base', 'fits', 'linalg', 'model', 'numerics', \
                'obs', 'opt', 'sky', 'support', 'test', 'xml', 'xspec', \
                'vo']

# Detect execution mode
is_build = True
if (len(sys.argv) >= 2):
	if (sys.argv[1] == 'install'):
		is_build = False
if is_build:
	sys.stdout.write("Python extension module building:\n")
else:
	sys.stdout.write("Python extension module installation:\n")

# Darwin MacPorts kluge: Remove -L/opt/local/lib path from LDSHARED as this
# overrides the GammaLib settings. Otherwise, MacPorts libraries would be
# used instead of the libraries selected by GammaLib
if sys.platform.lower().startswith("darwin"):
	
	# Get configuration variables
	cvars = sysconfig.get_config_vars()
	
	# Extract LDSHARED
	ldshared_old = cvars.get('LDSHARED')
	ldshared_new = ''
	ldshared_rm  = ''
	for option in ldshared_old.split(' '):
		if option.lstrip().find('-L/opt/local/lib') != 0:
			ldshared_new += option + ' '
		else:
			ldshared_rm += option + ' '
	if (len(ldshared_rm) > 0):
		sys.stdout.write("Removed following option(s) from LDSHARED: "+ldshared_rm+"\n")	
	# Set LDSHARED
	cvars['LDSHARED'] = ldshared_new

# Set default include directories, install files, library paths and libraries
include_dirs         = ['@top_srcdir@/include']
install_files        = glob.glob('@top_srcdir@/pyext/*.i')
library_dirs         = ['../src/.libs']
runtime_library_dirs = ['../src/.libs']
libraries            = ['gamma']

# Add install directory to runtime library path
if os.path.exists('@prefix@/lib'):
	runtime_library_dirs.append('@prefix@/lib')

# Add cfitsio library only if available
if '@WITH_CFITSIO_TRUE@' != '#':
	sys.stdout.write("Link cfitsio into Python bindings.\n")
	libraries.append('cfitsio')

# Add readline library only if available
if '@WITH_READLINE_TRUE@' != '#':
	sys.stdout.write("Link readline into Python bindings.\n")
	libraries.append('readline')
	libraries.append('ncurses')

# Add extra libraries
extra_libs = ('@PYTHON_EXTRA_LIBS@').split(',')
for extra_lib in extra_libs:
	if len(extra_lib) > 0:
		libraries.append(extra_lib)

# Get extra library paths (for cfitsio, readline, ncurses)
extra_lib_paths = ('@LDFLAGS@').split(' ')
for extra_lib_path in extra_lib_paths:
	if extra_lib_path.lstrip().find('-L') == 0:
		dir = extra_lib_path.lstrip().lstrip('-L')
		if len(dir) > 0:
			library_dirs.append(dir)
			runtime_library_dirs.append(dir)

# Get extra include directories
extra_inc_paths = ('@CPPFLAGS@').split(' ')
for extra_inc_path in extra_inc_paths:
	if extra_inc_path.lstrip().find('-I') == 0:
		dir = extra_inc_path.lstrip().lstrip('-I')
		if len(dir) > 0:
			include_dirs.append(dir)

# Add definitions for instrument specific modules
inst_modules = []
if '@WITH_INST_MWL_TRUE@' != '#':
	sys.stdout.write("Include multi-wavelength interface in gammalib Python bindings.\n")
	inst_modules.append('mwl')
if '@WITH_INST_CTA_TRUE@' != '#':
	sys.stdout.write("Include CTA instrument interface in gammalib Python bindings.\n")
	inst_modules.append('cta')
if '@WITH_INST_LAT_TRUE@' != '#':
	sys.stdout.write("Include Fermi/LAT instrument interface in gammalib Python bindings.\n")
	inst_modules.append('lat')
if '@WITH_INST_COM_TRUE@' != '#':
	sys.stdout.write("Include COMPTEL instrument interface in gammalib Python bindings.\n")
	inst_modules.append('com')

# Set extension definition for core modules
all_modules = []
ext_modules = []
py_modules  = []

# Optionally enable OpenMP
if '@OPENMP_TRUE@' != '#':
	extra_compile_args = ['@OPENMP_CXXFLAGS@']
	extra_link_args    = ['@OPENMP_CXXFLAGS@']
else:
	extra_compile_args = []
	extra_link_args    = []

# Loop over all core modules
for module in core_modules:
	
	# Define module
	ext_module = Extension('_'+module, [pkg_name+'/'+module+'_wrap.cpp'], \
	                       include_dirs=include_dirs, \
                           libraries=libraries,
                           library_dirs=library_dirs,
                           runtime_library_dirs=runtime_library_dirs,
                           extra_compile_args=extra_compile_args,
                           extra_link_args=extra_link_args)
	all_modules.append(module)
	ext_modules.append(ext_module)
	py_modules.append(pkg_name+'.'+module)

# Set extension definition for instrument dependent modules
for module in inst_modules:

	# Define paths
	pyext_path   = '@top_srcdir@/inst/'+module+'/pyext'
	include_path = '@top_srcdir@/inst/'+module+'/include'
	
	# Set include directories for module
	include_inst_dirs = include_dirs
	include_inst_dirs.append(include_path)
	
	# Add SWIG files to install_files
	install_files.extend(glob.glob(pyext_path+'/*.i'))
	
	# Define module
	ext_module = Extension('_'+module, [pkg_name+'/'+module+'_wrap.cpp'], \
                           include_dirs=include_dirs, \
                           libraries=libraries,
                           library_dirs=library_dirs,
                           runtime_library_dirs=runtime_library_dirs,
                           extra_compile_args=extra_compile_args,
                           extra_link_args=extra_link_args)
	all_modules.append(module)
	ext_modules.append(ext_module)
	py_modules.append(pkg_name+'.'+module)

# Build list of class names
classes = []
casts   = []
for module in all_modules:

	# Set file names
	filename = pkg_name+"/"+module+".py"
	infile  = open(filename, 'r')

	# Loop over all lines of input file
	for line in infile:

		# Search class names
		if line.find("class G") != -1:
			pos  = line.find("(")
			name = line[6:pos]
			classes.append(name)

		# Search casts
		elif line.find("def cast_") != -1:
			pos     = line.find("(")
			name    = line[4:pos]
			casts.append(name)

	# Close file
	infile.close()

# Sort
classes.sort()
casts.sort()

# Build names string
names   = ""
n_names = 0
for name in classes:
	if n_names > 0:
		names += ", "
	names   += "'"+name+"'"
	n_names += 1
for name in casts:
	if n_names > 0:
		names += ", "
	names   += "'"+name+"'"
	n_names += 1

# Create gammalib/__init__.py file
file = open(pkg_name+'/__init__.py', 'w')
file.write('# This file is created automatically by setup.py\n')
file.write('# Please do not modify, unless you exactly know what you do.\n')
file.write('__all__ = [')
file.write(names)
file.write(']\n')
for module in all_modules:
	file.write('from gammalib.'+module+' import *\n')

# Remove useless and annoying `*_swigregister` entries from the namespace
# see https://cta-redmine.irap.omp.eu/issues/832
file.write("""
bad_entries = [entry for entry in list(locals())
               if entry.endswith('_swigregister')]
for entry in bad_entries:
    del locals()[entry]
del gammalib.gammalib
""")
file.close()

# Set data files to install.
data_files=[('@prefix@/share/gammalib/swig', install_files)]

# Setup
setup(name='@PACKAGE_NAME@',
      version='@PACKAGE_VERSION@',
      description='gammalib Python bindings',
      author='Juergen Knoedlseder',
      author_email='@PACKAGE_BUGREPORT@',
      maintainer='Juergen Knoedlseder',
      maintainer_email='@PACKAGE_BUGREPORT@',
      url='http://gammalib.sourceforge.net/',
      packages=[pkg_name],
      ext_package=pkg_name,
      ext_modules=ext_modules,
      py_modules=py_modules,
      data_files=data_files,
      license="GNU GPL v3",
      long_description="Versatile toolbox for the analysis of astronomical gamma-ray data",
      platforms=["Linux", "Solaris", "Mac OS-X", "Unix", "BSD"],
	  )

# Post-processing. A symbolic link is created to the directory containing the
# shared wrapper libraries so that we can add this directory to the PYTHONPATH
# for testing.
if is_build:
	try:
		os.chdir('build')
		os.remove('gammalib')
		sys.stdout.write("Removed symbolic link build/gammalib.\n")
	except:
		pass
	try:
		path = glob.glob('lib.*/gammalib')
		os.symlink(path[0], 'gammalib')
		sys.stdout.write("Created symbolic link build/gammalib.\n")
	except:
		sys.stdout.write("WARNING: Failed to create symbolic link build/gammalib.\n")