source: orange/setup.py @ 9574:a2598a0f3798

Revision 9574:a2598a0f3798, 23.5 KB checked in by ales_erjavec, 2 years ago (diff)

Removed maintainer info from package description.

Line 
1#!usr/bin/env python
2
3import os, sys       
4import distutils.core
5from distutils.core import setup
6from distutils.core import Extension
7from distutils.command.build_ext import build_ext
8from distutils.command.install_lib import install_lib
9from distutils.msvccompiler import MSVCCompiler
10from distutils.unixccompiler import UnixCCompiler
11
12have_setuptools = getattr(distutils.core, "have_setuptools", False) # This is set in setupegg.py
13
14import re
15import glob
16
17from subprocess import check_call
18
19import types
20
21from distutils.dep_util import newer_group
22from distutils.file_util import copy_file
23from distutils import log
24
25from distutils.sysconfig import get_python_inc, get_config_var
26import numpy
27numpy_include_dir = numpy.get_include()
28python_include_dir = get_python_inc(plat_specific=1)
29
30include_dirs = [python_include_dir, numpy_include_dir, "source/include"]
31
32if sys.platform == "darwin":
33    extra_compile_args = "-fPIC -fpermissive -fno-common -w -DDARWIN".split()
34    extra_link_args = "-headerpad_max_install_names -undefined dynamic_lookup".split()
35elif sys.platform == "win32":
36    extra_compile_args = ["-EHsc"]
37    extra_link_args = []
38elif sys.platform.startswith("linux"):
39    extra_compile_args = "-fPIC -fpermissive -w -DLINUX".split()
40    extra_link_args = ["-Wl,-R$ORIGIN"]   
41else:
42    extra_compile_args = []
43    extra_link_args = []
44       
45class LibStatic(Extension):
46    pass
47
48class PyXtractExtension(Extension):
49    def __init__(self, *args, **kwargs):
50        for name, default in [("extra_pyxtract_cmds", []), ("lib_type", "dynamic")]:
51            setattr(self, name, kwargs.get(name, default))
52            if name in kwargs:   
53                del kwargs[name]
54           
55        Extension.__init__(self, *args, **kwargs)
56       
57class PyXtractSharedExtension(PyXtractExtension):
58    pass
59       
60class pyxtract_build_ext(build_ext):
61    def run_pyxtract(self, ext, dir):
62        original_dir = os.path.realpath(os.path.curdir)
63        log.info("running pyxtract for %s" % ext.name)
64        try:
65            os.chdir(dir)
66            ## we use the commands which are used for building under windows
67            pyxtract_cmds = [cmd.split() for cmd in getattr(ext, "extra_pyxtract_cmds", [])]
68            if os.path.exists("_pyxtract.bat"): 
69                pyxtract_cmds.extend([cmd.split()[1:] for cmd in open("_pyxtract.bat").read().strip().splitlines()])
70            for cmd in pyxtract_cmds:
71                log.info(" ".join([sys.executable] + cmd))
72                check_call([sys.executable] + cmd)
73            if pyxtract_cmds:
74                ext.include_dirs.append(os.path.join(dir, "ppp"))
75                ext.include_dirs.append(os.path.join(dir, "px"))
76
77        finally:
78            os.chdir(original_dir)
79       
80    def finalize_options(self):
81        build_ext.finalize_options(self)
82        # add the build_lib dir (for liborange_include)
83        if not self.inplace:
84            self.library_dirs.append(self.build_lib) 
85        else:
86            self.library_dirs.append("./orange")
87       
88    def build_extension(self, ext):
89        if isinstance(ext, LibStatic):
90            self.build_static(ext)
91        elif isinstance(ext, PyXtractExtension):
92            self.build_pyxtract(ext)
93        else:
94            build_ext.build_extension(self, ext)
95           
96        if isinstance(ext, PyXtractSharedExtension):
97            if isinstance(self.compiler, MSVCCompiler):
98                # Copy ${TEMP}/orange/orange.lib to ${BUILD}/orange.lib
99                ext_fullpath = self.get_ext_fullpath(ext.name)
100                lib = glob.glob(os.path.join(self.build_temp, "*", "*", ext.name + ".lib"))[0]
101                copy_file(lib, os.path.splitext(ext_fullpath)[0] + ".lib")
102                         
103                #self.get
104            else:
105                # Make lib{name}.so link to {name}.so
106                ext_path = self.get_ext_fullpath(ext.name)
107                ext_path, ext_filename = os.path.split(ext_path)
108                realpath = os.path.realpath(os.curdir)
109                try:
110                    os.chdir(ext_path)
111                    # Get the shared library name
112                    lib_filename = self.compiler.library_filename(ext.name, lib_type="shared")
113                    # Create the link
114                    copy_file(ext_filename, lib_filename, link="sym")
115                except OSError, ex:
116                    log.info("failed to create shared library for %s: %s" % (ext.name, str(ex)))
117                finally:
118                    os.chdir(realpath)
119           
120    def build_pyxtract(self, ext):
121        ## mostly copied from build_extension
122        sources = ext.sources
123        if sources is None or type(sources) not in (types.ListType, types.TupleType):
124            raise DistutilsSetupError, \
125                  ("in 'ext_modules' option (extension '%s'), " +
126                   "'sources' must be present and must be " +
127                   "a list of source filenames") % ext.name
128        sources = list(sources)
129       
130        ext_path = self.get_ext_fullpath(ext.name)
131#        output_dir, _ = os.path.split(ext_path)
132#        lib_filename = self.compiler.library_filename(ext.name, lib_type='static', output_dir=output_dir)
133       
134        depends = sources + ext.depends
135        if not (self.force or newer_group(depends, ext_path, 'newer')):
136            log.debug("skipping '%s' extension (up-to-date)", ext.name)
137            return
138        else:
139            log.info("building '%s' extension", ext.name)
140
141        # First, scan the sources for SWIG definition files (.i), run
142        # SWIG on 'em to create .c files, and modify the sources list
143        # accordingly.
144        sources = self.swig_sources(sources, ext)
145       
146        # Run pyxtract in dir this adds ppp and px dirs to include_dirs
147        dir = os.path.commonprefix([os.path.split(s)[0] for s in ext.sources])
148        self.run_pyxtract(ext, dir)
149
150        # Next, compile the source code to object files.
151
152        # XXX not honouring 'define_macros' or 'undef_macros' -- the
153        # CCompiler API needs to change to accommodate this, and I
154        # want to do one thing at a time!
155
156        # Two possible sources for extra compiler arguments:
157        #   - 'extra_compile_args' in Extension object
158        #   - CFLAGS environment variable (not particularly
159        #     elegant, but people seem to expect it and I
160        #     guess it's useful)
161        # The environment variable should take precedence, and
162        # any sensible compiler will give precedence to later
163        # command line args.  Hence we combine them in order:
164        extra_args = ext.extra_compile_args or []
165
166        macros = ext.define_macros[:]
167        for undef in ext.undef_macros:
168            macros.append((undef,))
169
170        objects = self.compiler.compile(sources,
171                                         output_dir=self.build_temp,
172                                         macros=macros,
173                                         include_dirs=ext.include_dirs,
174                                         debug=self.debug,
175                                         extra_postargs=extra_args,
176                                         depends=ext.depends)
177
178        # XXX -- this is a Vile HACK!
179        #
180        # The setup.py script for Python on Unix needs to be able to
181        # get this list so it can perform all the clean up needed to
182        # avoid keeping object files around when cleaning out a failed
183        # build of an extension module.  Since Distutils does not
184        # track dependencies, we have to get rid of intermediates to
185        # ensure all the intermediates will be properly re-built.
186        #
187        self._built_objects = objects[:]
188
189        # Now link the object files together into a "shared object" --
190        # of course, first we have to figure out all the other things
191        # that go into the mix.
192        if ext.extra_objects:
193            objects.extend(ext.extra_objects)
194        extra_args = ext.extra_link_args or []
195
196        # Detect target language, if not provided
197        language = ext.language or self.compiler.detect_language(sources)
198
199        self.compiler.link_shared_object(
200            objects, ext_path,
201            libraries=self.get_libraries(ext),
202            library_dirs=ext.library_dirs,
203            runtime_library_dirs=ext.runtime_library_dirs,
204            extra_postargs=extra_args,
205            export_symbols=self.get_export_symbols(ext),
206            debug=self.debug,
207            build_temp=self.build_temp,
208            target_lang=language)
209       
210       
211    def build_static(self, ext):
212        ## mostly copied from build_extension, changed
213        sources = ext.sources
214        if sources is None or type(sources) not in (types.ListType, types.TupleType):
215            raise DistutilsSetupError, \
216                  ("in 'ext_modules' option (extension '%s'), " +
217                   "'sources' must be present and must be " +
218                   "a list of source filenames") % ext.name
219        sources = list(sources)
220       
221        ext_path = self.get_ext_fullpath(ext.name)
222        output_dir, _ = os.path.split(ext_path)
223        if not os.path.exists(output_dir): #VSC fails if the dir does not exist
224            os.makedirs(output_dir)
225        lib_filename = self.compiler.library_filename(ext.name, lib_type='static', output_dir=output_dir)
226       
227        depends = sources + ext.depends
228        if not (self.force or newer_group(depends, lib_filename, 'newer')):
229            log.debug("skipping '%s' extension (up-to-date)", ext.name)
230            return
231        else:
232            log.info("building '%s' extension", ext.name)
233
234        # First, scan the sources for SWIG definition files (.i), run
235        # SWIG on 'em to create .c files, and modify the sources list
236        # accordingly.
237        sources = self.swig_sources(sources, ext)
238
239        # Next, compile the source code to object files.
240
241        # XXX not honouring 'define_macros' or 'undef_macros' -- the
242        # CCompiler API needs to change to accommodate this, and I
243        # want to do one thing at a time!
244
245        # Two possible sources for extra compiler arguments:
246        #   - 'extra_compile_args' in Extension object
247        #   - CFLAGS environment variable (not particularly
248        #     elegant, but people seem to expect it and I
249        #     guess it's useful)
250        # The environment variable should take precedence, and
251        # any sensible compiler will give precedence to later
252        # command line args.  Hence we combine them in order:
253        extra_args = ext.extra_compile_args or []
254
255        macros = ext.define_macros[:]
256        for undef in ext.undef_macros:
257            macros.append((undef,))
258
259        objects = self.compiler.compile(sources,
260                                         output_dir=self.build_temp,
261                                         macros=macros,
262                                         include_dirs=ext.include_dirs,
263                                         debug=self.debug,
264                                         extra_postargs=extra_args,
265                                         depends=ext.depends)
266
267        # XXX -- this is a Vile HACK!
268        #
269        # The setup.py script for Python on Unix needs to be able to
270        # get this list so it can perform all the clean up needed to
271        # avoid keeping object files around when cleaning out a failed
272        # build of an extension module.  Since Distutils does not
273        # track dependencies, we have to get rid of intermediates to
274        # ensure all the intermediates will be properly re-built.
275        #
276        self._built_objects = objects[:]
277
278        # Now link the object files together into a "shared object" --
279        # of course, first we have to figure out all the other things
280        # that go into the mix.
281        if ext.extra_objects:
282            objects.extend(ext.extra_objects)
283        extra_args = ext.extra_link_args or []
284
285        # Detect target language, if not provided
286        language = ext.language or self.compiler.detect_language(sources)
287       
288        #first remove old library (ar only appends the contents if archive already exists
289        try:
290            os.remove(lib_filename)
291        except OSError, ex:
292            log.debug("failed to remove obsolete static library %s: %s" %(ext.name, str(ex)))
293
294        self.compiler.create_static_lib(
295            objects, ext.name, output_dir,
296            debug=self.debug,
297            target_lang=language)
298       
299    if not hasattr(build_ext, "get_ext_fullpath"):
300        #On mac OS X python 2.6.1 distutils does not have this method
301        def get_ext_fullpath(self, ext_name):
302            """Returns the path of the filename for a given extension.
303           
304            The file is located in `build_lib` or directly in the package
305            (inplace option).
306            """
307            import string
308            # makes sure the extension name is only using dots
309            all_dots = string.maketrans('/' + os.sep, '..')
310            ext_name = ext_name.translate(all_dots)
311            fullname = self.get_ext_fullname(ext_name)
312            modpath = fullname.split('.')
313            filename = self.get_ext_filename(ext_name)
314            filename = os.path.split(filename)[-1]
315            if not self.inplace:
316                # no further work needed
317                # returning :
318                #   build_dir/package/path/filename
319                filename = os.path.join(*modpath[:-1] + [filename])
320                return os.path.join(self.build_lib, filename)
321            # the inplace option requires to find the package directory
322            # using the build_py command for that
323            package = '.'.join(modpath[0:-1])
324            build_py = self.get_finalized_command('build_py')
325            package_dir = os.path.abspath(build_py.get_package_dir(package))
326            # returning
327            #   package_dir/filename
328            return os.path.join(package_dir, filename)
329       
330       
331class my_install_lib(install_lib):
332    """ An command to install orange (preserves liborange.so -> orange.so symlink)
333    """
334    def run(self):
335        install_lib.run(self)
336       
337    def copy_tree(self, infile, outfile, preserve_mode=1, preserve_times=1, preserve_symlinks=1, level=1):
338        """ Run copy_tree with preserve_symlinks=1 as default
339        """ 
340        install_lib.copy_tree(self, infile, outfile, preserve_mode, preserve_times, preserve_symlinks, level)
341       
342    def install(self):
343        """ Copy build_dir to install_dir
344        """
345        # A Hack to unlink liborange.so -> orange.so if it already exists,
346        # because copy_tree fails to overwrite it
347        #
348        liborange = os.path.join(self.install_dir, "liborange.so")
349        if self.force and os.path.exists(liborange) and os.path.islink(liborange):
350            log.info("unlinking %s -> %s", liborange, os.path.join(self.install_dir, "orange.so"))
351            os.unlink(liborange)
352           
353        return install_lib.install(self)
354       
355           
356def get_source_files(path, ext="cpp", exclude=[]):
357    files = glob.glob(os.path.join(path, "*." + ext))
358    files = [file for file in files if os.path.basename(file) not in exclude]
359    return files
360
361include_ext = LibStatic("orange_include", get_source_files("source/include/"), include_dirs=include_dirs)
362
363
364if sys.platform == "win32": # ?? mingw/cygwin
365    libraries = ["orange_include"]
366else:
367    libraries = ["stdc++", "orange_include"]
368
369
370import ConfigParser
371config = ConfigParser.RawConfigParser()
372config.read("setup-site.cfg")
373
374orange_sources = get_source_files("source/orange/")
375orange_include_dirs = list(include_dirs)
376orange_libraries = list(libraries)
377
378if config.has_option("blas", "library"):
379    # Link external blas library
380    orange_libraries += [config.get("blas", "library")]
381else:
382    orange_sources += get_source_files("source/orange/blas/", "c")
383   
384if config.has_option("R", "library"):
385    # Link external R library (for linpack)
386    orange_libraries += [config.get("R", "library")]
387else:
388    orange_sources += get_source_files("source/orange/linpack/", "c")
389   
390if config.has_option("liblinear", "library"):
391    # Link external LIBLINEAR library
392    orange_libraries += [config.get("liblinear", "library")]
393else:
394    orange_sources += get_source_files("source/orange/liblinear/", "cpp")
395    orange_include_dirs += ["source/orange/liblinear"]
396   
397if config.has_option("libsvm", "library"):
398    # Link external LibSVM library
399    orange_libraries += [config.get("libsvm", "library")]
400else:
401    orange_sources += get_source_files("source/orange/libsvm/", "cpp")
402   
403
404orange_ext = PyXtractSharedExtension("orange", orange_sources,
405                                      include_dirs=orange_include_dirs,
406                                      extra_compile_args = extra_compile_args + ["-DORANGE_EXPORTS"],
407                                      extra_link_args = extra_link_args,
408                                      libraries=orange_libraries,
409                                      extra_pyxtract_cmds = ["../pyxtract/defvectors.py"],
410#                                      depends=["orange/ppp/lists"]
411                                      )
412
413if sys.platform == "darwin":
414    build_shared_cmd = get_config_var("BLDSHARED")
415    if "-bundle" in build_shared_cmd.split(): #dont link liborange.so with orangeom and orangene - MacOS X treats loadable modules and shared libraries different
416        shared_libs = libraries
417    else:
418        shared_libs = libraries + ["orange"]
419else:
420    shared_libs = libraries + ["orange"]
421   
422orangeom_sources = get_source_files("source/orangeom/", exclude=["lib_vectors.cpp"])
423orangeom_libraries = list(shared_libs)
424orangeom_include_dirs = list(include_dirs)
425
426if config.has_option("qhull", "library"):
427    # Link external qhull library
428    orangeom_libraries += [config.get("qhull", "library")]
429else:
430    orangeom_sources += get_source_files("source/orangeom/qhull/", "c")
431    orangeom_include_dirs += ["source/orangeom"]
432
433
434orangeom_ext = PyXtractExtension("orangeom", orangeom_sources,
435                                  include_dirs=orangeom_include_dirs + ["source/orange/"],
436                                  extra_compile_args = extra_compile_args + ["-DORANGEOM_EXPORTS"],
437                                  extra_link_args = extra_link_args,
438                                  libraries=orangeom_libraries,
439                                  )
440
441orangene_ext = PyXtractExtension("orangene", get_source_files("source/orangene/", exclude=["lib_vectors.cpp"]), 
442                                  include_dirs=include_dirs + ["source/orange/"], 
443                                  extra_compile_args = extra_compile_args + ["-DORANGENE_EXPORTS"],
444                                  extra_link_args = extra_link_args,
445                                  libraries=shared_libs,
446                                  )
447
448corn_ext = Extension("corn", get_source_files("source/corn/"), 
449                     include_dirs=include_dirs + ["source/orange/"], 
450                     extra_compile_args = extra_compile_args + ["-DCORN_EXPORTS"],
451                     extra_link_args = extra_link_args,
452                     libraries=libraries
453                     )
454
455statc_ext = Extension("statc", get_source_files("source/statc/"), 
456                      include_dirs=include_dirs + ["source/orange/"], 
457                      extra_compile_args = extra_compile_args + ["-DSTATC_EXPORTS"],
458                      extra_link_args = extra_link_args,
459                      libraries=libraries
460                      )
461
462import fnmatch
463matches = []
464os.chdir("orange")
465for root, dirnames, filenames in os.walk('Orange'): #Recursively find '__init__.py's
466  for filename in fnmatch.filter(filenames, '__init__.py'):
467      matches.append(os.path.join(root, filename))
468packages = [os.path.dirname(pkg).replace(os.path.sep, '.') for pkg in matches]
469os.chdir("..")
470
471if have_setuptools:
472    setuptools_args = {"zip_safe": False,
473                       "install_requires": ["numpy"],
474                       "extra_requires": ["networkx", "PyQt4", "PyQwt"]
475                       }
476else:
477    setuptools_args = {}
478
479setup(cmdclass={"build_ext": pyxtract_build_ext, "install_lib": my_install_lib},
480      name ="Orange",
481      version = "2.5a1",
482      description = "Orange data mining library for python.",
483      author = "Bioinformatics Laboratory, FRI UL",
484      author_email = "orange@fri.uni-lj.si",
485      url = "http://orange.biolab.si",
486      download_url = "http://orange.biolab.si/svn/orange/trunk",
487      packages = packages + ["",
488                             "OrangeCanvas",
489                             "OrangeWidgets", 
490                             "OrangeWidgets.Associate",
491                             "OrangeWidgets.Classify",
492                             "OrangeWidgets.Data",
493                             "OrangeWidgets.Evaluate",
494                             "OrangeWidgets.Prototypes",
495                             "OrangeWidgets.Regression",
496                             "OrangeWidgets.Unsupervised",
497                             "OrangeWidgets.Visualize",
498                             "OrangeWidgets.Visualize Qt",
499                             "OrangeWidgets.plot",
500                             "OrangeWidgets.plot.primitives",
501                             "doc",
502                             ],
503      package_dir = {"": "orange"},
504      package_data = {"OrangeCanvas": ["icons/*.png", "orngCanvas.pyw", "WidgetTabs.txt"],
505                      "OrangeWidgets": ["icons/*.png", "icons/backgrounds/*.png", "report/index.html"],
506                      "OrangeWidgets.Associate": ["icons/*.png"],
507                      "OrangeWidgets.Classify": ["icons/*.png"],
508                      "OrangeWidgets.Data": ["icons/*.png"],
509                      "OrangeWidgets.Evaluate": ["icons/*.png"],
510                      "OrangeWidgets.Prototypes": ["icons/*.png"],
511                      "OrangeWidgets.Regression": ["icons/*.png"],
512                      "OrangeWidgets.Unsupervised": ["icons/*.png"],
513                      "OrangeWidgets.Visualize": ["icons/*.png"],
514                      "OrangeWidgets.plot": ["*.gs", "*.vs"],
515                      "OrangeWidgets.plot.primitives": ["*.obj"],
516                      "doc": ["datasets/*.tab", ],
517                      "": ["orangerc.cfg"]
518                      },
519      ext_modules = [include_ext, orange_ext, orangeom_ext, orangene_ext, corn_ext, statc_ext],
520      extra_path=("orange", "orange"),
521      scripts = ["orange/orange-canvas"],
522      license = "GNU General Public License (GPL)",
523      keywords = ["data mining", "machine learning", "artificial intelligence"],
524      classifiers = ["Development Status :: 4 - Beta",
525                     "Programming Language :: Python",
526                     "License :: OSI Approved :: GNU General Public License (GPL)",
527                     "Operating System :: POSIX",
528                     "Operating System :: Microsoft :: Windows",
529                     "Topic :: Scientific/Engineering :: Artificial Intelligence",
530                     "Topic :: Scientific/Engineering :: Visualization",
531                     "Intended Audience :: Education",
532                     "Intended Audience :: Science/Research"
533                     ],
534      long_description="""\
535Orange data mining library
536==========================
537
538Orange is a scriptable environment for fast prototyping of new
539algorithms and testing schemes. It is a collection of Python packages
540that sit over the core library and implement some functionality for
541which execution time is not crucial and which is easier done in Python
542than in C++. This includes a variety of tasks such as attribute subset,
543bagging and boosting, and alike.
544
545Orange also includes a set of graphical widgets that use methods from
546core library and Orange modules. Through visual programming, widgets
547can be assembled together into an application by a visual programming
548tool called Orange Canvas.
549""",
550      **setuptools_args)
551     
552
Note: See TracBrowser for help on using the repository browser.