source: PyFMI/branches/PyFMI-2.5.x/setup.py @ 13737

Last change on this file since 13737 was 13737, checked in by Christian Andersson, 8 weeks ago

Updated version number. Related to ticket:5854

File size: 12.8 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4# Copyright (C) 2014 Modelon AB
5#
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU Lesser General Public License as published by
8# the Free Software Foundation, version 3 of the License.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU Lesser General Public License for more details.
14#
15# You should have received a copy of the GNU Lesser General Public License
16# along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18#from distutils.core import setup, Extension
19#from distutils.ccompiler import new_compiler
20
21
22import distutils
23import os as O
24import sys as S
25import shutil
26import numpy as N
27import ctypes.util
28import sys
29
30#If prefix is set, we want to allow installation in a directory that is not on PYTHONPATH
31#and this is only possible with distutils, not setuptools
32if str(sys.argv[1:]).find("--prefix") == -1:
33    from setuptools import setup 
34else:
35    from distutils.core import setup
36
37try:
38    from Cython.Distutils import build_ext
39    from Cython.Build import cythonize
40except ImportError:
41    raise Exception("Please upgrade to a newer Cython version, >= 0.15.")
42
43
44NAME = "PyFMI"
45AUTHOR = "Modelon AB"
46AUTHOR_EMAIL = ""
47VERSION = "2.5.5"
48LICENSE = "LGPL"
49URL = "https://jmodelica.org/pyfmi"
50DOWNLOAD_URL = "https://jmodelica.org/pyfmi/installation.html"
51DESCRIPTION = "A package for working with dynamic models compliant with the Functional Mock-Up Interface standard."
52PLATFORMS = ["Linux", "Windows", "MacOS X"]
53CLASSIFIERS = [ 'Programming Language :: Python',
54                'Operating System :: MacOS :: MacOS X',
55                'Operating System :: Microsoft :: Windows',
56                'Operating System :: Unix']
57
58LONG_DESCRIPTION = """
59PyFMI is a package for loading and interacting with Functional Mock-Up
60Units (FMUs), which are compiled dynamic models compliant with the
61Functional Mock-Up Interface (FMI), see
62https://www.fmi-standard.org/ for more information. PyFMI
63is based on FMI Library, see http://www.jmodelica.org/FMILibrary .
64
65FMI is a standard that enables tool independent exchange of dynamic
66models on binary format. Several industrial simulation platforms
67supports export of FMUs, including, Dymola, JModelica.org, OpenModelica
68and SimulationX, see https://www.fmi-standard.org/tools
69for a complete list. PyFMI offers a Python interface for interacting
70with FMUs and enables for example loading of FMU models, setting of
71model parameters and evaluation of model equations.
72
73PyFMI is available as a stand-alone package or as part of the
74JModelica.org distribution. Using PyFMI together with the Python
75simulation package `Assimulo <http://pypi.python.org/pypi/Assimulo>`_ adds industrial grade simulation
76capabilities of FMUs to Python.
77
78Requirements:
79-------------
80- `FMI Library (at least 2.0.1) <http://www.jmodelica.org/FMILibrary>`_
81- `Numpy (recommended 1.6.2) <http://pypi.python.org/pypi/numpy>`_
82- `Scipy (recommended 0.10.1) <http://pypi.python.org/pypi/scipy>`_
83- `lxml (at least 2.3) <http://pypi.python.org/pypi/lxml>`_
84- `Assimulo (at least 3.0) <http://pypi.python.org/pypi/Assimulo>`_
85- `Cython (at least 0.18) <http://cython.org/>`_
86- Python-headers (usually included on Windows, python-dev on Ubuntu)
87
88Optional
89---------
90- `wxPython <http://pypi.python.org/pypi/wxPython>`_ For the Plot GUI.
91- `matplotlib <http://pypi.python.org/pypi/matplotlib>`_ For the Plot GUI.
92
93Source Installation:
94----------------------
95
96python setup.py install --fmil-home=/path/to/FMI_Library/
97
98"""
99
100copy_args=sys.argv[1:]
101
102if O.getenv("FMIL_HOME"): #Check for if there exists and environment variable that specifies FMIL
103    incdirs = O.path.join(O.getenv("FMIL_HOME"),'include')
104    libdirs = O.path.join(O.getenv("FMIL_HOME"),'lib')
105else:
106    incdirs = ""
107    libdirs = ""
108   
109static = False
110debug_flag = False
111fmilib_shared = ""
112copy_gcc_lib = False
113gcc_lib = None
114force_32bit = False
115no_msvcr = False
116python3_flag = True if S.hexversion > 0x03000000 else False
117with_openmp = False
118
119static_link_gcc = "-static-libgcc"
120flag_32bit = "-m32"
121extra_c_flags = ""
122
123# Fix path sep
124for x in sys.argv[1:]:
125    if not x.find('--prefix'):
126        copy_args[copy_args.index(x)] = x.replace('/',O.sep)
127    if not x.find('--fmil-home'):
128        incdirs = O.path.join(x[12:],'include')
129        libdirs = O.path.join(x[12:],'lib')
130        copy_args.remove(x)
131    if not x.find('--copy-libgcc'):
132        if x[14:].upper() == "TRUE":
133            copy_gcc_lib = True
134        copy_args.remove(x)
135    if not x.find('--static'):
136        static = x[9:]
137        if x[9:].upper() == "TRUE":
138            static = True
139        else:
140            static = False
141        copy_args.remove(x)
142    if not x.find('--force-32bit'):
143        if x[14:].upper() == "TRUE":
144            force_32bit = True
145        copy_args.remove(x)
146    if not x.find('--no-msvcr'):
147        if x[11:].upper() == "TRUE":
148            no_msvcr = True
149        copy_args.remove(x)
150    if not x.find('--extra-c-flags'):
151        extra_c_flags = x[16:]
152        copy_args.remove(x)
153    if not x.find('--with-openmp'):
154        with_openmp = True
155        copy_args.remove(x)
156    if not x.find('--version'):
157        VERSION = x[10:]
158        copy_args.remove(x)
159    if not x.find('--debug'):
160        if x[8:].upper() == "TRUE":
161            debug_flag = True
162        else:
163            debug_flag = False
164        copy_args.remove(x)
165   
166
167if not incdirs:
168    raise Exception("FMI Library cannot be found. Please specify its location, either using the flag to the setup script '--fmil-home' or specify it using the environment variable FMIL_HOME.")
169
170#Check to see if FMILIB_SHARED exists and if so copy it
171if 0 != sys.argv[1].find("clean"): #Dont check if we are cleaning!
172    if sys.platform.startswith("win"):
173        try:
174            files = O.listdir(O.path.join(libdirs))
175        except:
176            raise Exception("The FMI Library binary cannot be found at path: "+str(O.path.join(libdirs)))
177        for file in files:
178            if "fmilib_shared" in file and not file.endswith("a"):
179                shutil.copy2(O.path.join(libdirs,file),O.path.join(".","src","pyfmi"))
180                fmilib_shared = O.path.join(".","src","pyfmi",file)
181                break
182        else:
183            raise Exception("Could not find FMILibrary at: %s"%libdirs)
184           
185        if copy_gcc_lib:
186            path_gcc_lib = ctypes.util.find_library("libgcc_s_dw2-1.dll")
187            if path_gcc_lib != None:
188                shutil.copy2(path_gcc_lib,O.path.join(".","src","pyfmi"))
189                gcc_lib = O.path.join(".","src","pyfmi","libgcc_s_dw2-1.dll")
190
191if no_msvcr:
192    # prevent the MSVCR* being added to the DLLs passed to the linker
193    def msvc_runtime_library_mod(): 
194        return None
195   
196    import numpy.distutils
197    numpy.distutils.misc_util.msvc_runtime_library = msvc_runtime_library_mod
198
199def check_extensions():
200    ext_list = []
201    extra_link_flags = []
202   
203    if static:
204        extra_link_flags.append(static_link_gcc)
205
206    if force_32bit:
207        extra_link_flags.append(flag_32bit)
208
209    #COMMON PYX
210    """
211    ext_list = cythonize(["src"+O.path.sep+"common"+O.path.sep+"core.pyx"],
212                    include_path=[".","src","src"+O.sep+"common"],
213                    include_dirs=[N.get_include()],pyrex_gdb=debug)
214   
215    ext_list[-1].include_dirs = [N.get_include(), "src","src"+O.sep+"common", incdirs]
216       
217    if debug:
218        ext_list[-1].extra_compile_args = ["-g", "-fno-strict-aliasing", "-ggdb"]
219        ext_list[-1].extra_link_args = extra_link_flags
220    else:
221        ext_list[-1].extra_compile_args = ["-O2", "-fno-strict-aliasing"]
222        ext_list[-1].extra_link_args = extra_link_flags
223    """
224   
225    #FMI PYX
226    ext_list += cythonize(["src"+O.path.sep+"pyfmi"+O.path.sep+"fmi.pyx"], 
227                    include_path=[".","src","src"+O.sep+"pyfmi"])
228   
229    #FMI UTIL
230    ext_list += cythonize(["src"+O.path.sep+"pyfmi"+O.path.sep+"fmi_util.pyx"], 
231                    include_path=[".","src","src"+O.sep+"pyfmi"])
232   
233    #FMI Extended PYX
234    ext_list += cythonize(["src"+O.path.sep+"pyfmi"+O.path.sep+"fmi_extended.pyx"], 
235                    include_path=[".","src","src"+O.sep+"pyfmi"])
236                   
237    #FMI Coupled PYX
238    ext_list += cythonize(["src"+O.path.sep+"pyfmi"+O.path.sep+"fmi_coupled.pyx"], 
239                    include_path=[".","src","src"+O.sep+"pyfmi"])
240                   
241    #MASTER PYX
242    compile_time_env = {'WITH_OPENMP': with_openmp}
243    ext_list += cythonize(["src"+O.path.sep+"pyfmi"+O.path.sep+"master.pyx"], 
244                    include_path=[".","src","src"+O.sep+"pyfmi"], compile_time_env=compile_time_env)
245   
246    for i in range(len(ext_list)):
247       
248        ext_list[i].include_dirs = [N.get_include(), "src","src"+O.sep+"pyfmi", incdirs]
249        ext_list[i].library_dirs = [libdirs]
250        ext_list[i].language = "c"
251        ext_list[i].libraries = ["fmilib_shared"] if sys.platform.startswith("win") else ["fmilib"] #If windows shared, else static
252       
253        if debug_flag:
254            ext_list[i].extra_compile_args = ["-g", "-fno-strict-aliasing", "-ggdb"]
255        else:
256            ext_list[i].extra_compile_args = ["-O2", "-fno-strict-aliasing"]
257       
258        if force_32bit:
259            ext_list[i].extra_compile_args.append(flag_32bit)
260           
261        if extra_c_flags:
262            flags = extra_c_flags.split(' ')
263            for f in flags:
264                ext_list[i].extra_compile_args.append(f)
265       
266        ext_list[i].extra_link_args = extra_link_flags
267       
268        if with_openmp:
269            ext_list[i].extra_link_args.append("-fopenmp")
270            ext_list[i].extra_compile_args.append("-fopenmp")
271       
272        if python3_flag:
273            ext_list[i].cython_directives = {"language_level": 3}
274
275    return ext_list
276
277ext_list = check_extensions()
278
279try:
280    from subprocess import Popen, PIPE
281    _p = Popen(["svnversion", "."], stdout=PIPE)
282    revision = _p.communicate()[0].decode('ascii')
283except:
284    revision = "unknown"
285version_txt = 'src'+O.path.sep+'pyfmi'+O.path.sep+'version.txt'
286
287#If a revision is found, always write it!
288if revision != "unknown" and revision!="":
289    with open(version_txt, 'w') as f:
290        f.write(VERSION+'\n')
291        f.write("r"+revision)
292else:# If it does not, check if the file exists and if not, create the file!
293    if not O.path.isfile(version_txt):
294        with open(version_txt, 'w') as f:
295            f.write(VERSION+'\n')
296            f.write("unknown")
297           
298try:
299    shutil.copy2('LICENSE', 'src'+O.path.sep+'pyfmi'+O.path.sep+'LICENSE')
300    shutil.copy2('CHANGELOG', 'src'+O.path.sep+'pyfmi'+O.path.sep+'CHANGELOG')
301except:
302    pass
303
304from numpy.distutils.core import setup
305setup(name=NAME,
306      version=VERSION,
307      license=LICENSE,
308      description=DESCRIPTION,
309      long_description=LONG_DESCRIPTION,
310      author=AUTHOR,
311      author_email=AUTHOR_EMAIL,
312      url=URL,
313      download_url=DOWNLOAD_URL,
314      platforms=PLATFORMS,
315      classifiers=CLASSIFIERS,
316      ext_modules = ext_list,
317      package_dir = {'pyfmi':'src'+O.path.sep+'pyfmi','pyfmi.common':'src'+O.path.sep+'common', 'pyfmi.tests':'tests'},
318      packages=['pyfmi','pyfmi.simulation','pyfmi.examples','pyfmi.common','pyfmi.common.plotting', 'pyfmi.tests'],
319      package_data = {'pyfmi':['examples'+O.path.sep+'files'+O.path.sep+'FMUs'+O.path.sep+'ME1.0'+O.path.sep+'*',
320                               'examples'+O.path.sep+'files'+O.path.sep+'FMUs'+O.path.sep+'CS1.0'+O.path.sep+'*',
321                               'examples'+O.path.sep+'files'+O.path.sep+'FMUs'+O.path.sep+'ME2.0'+O.path.sep+'*',
322                               'examples'+O.path.sep+'files'+O.path.sep+'FMUs'+O.path.sep+'CS2.0'+O.path.sep+'*',
323                               'tests'+O.path.sep+'files'+O.path.sep+'FMUs'+O.path.sep+'XML'+O.path.sep+'ME1.0'+O.path.sep+'*',
324                               'tests'+O.path.sep+'files'+O.path.sep+'FMUs'+O.path.sep+'XML'+O.path.sep+'CS1.0'+O.path.sep+'*',
325                               'tests'+O.path.sep+'files'+O.path.sep+'FMUs'+O.path.sep+'XML'+O.path.sep+'ME2.0'+O.path.sep+'*',
326                               'tests'+O.path.sep+'files'+O.path.sep+'FMUs'+O.path.sep+'XML'+O.path.sep+'CS2.0'+O.path.sep+'*',
327                               'tests'+O.path.sep+'files'+O.path.sep+'Results'+O.path.sep+'*',
328                               'version.txt', 'LICENSE', 'CHANGELOG',
329                               'util'+O.path.sep+'*']+(['*fmilib_shared*'] if sys.platform.startswith("win") else [])+(['libgcc_s_dw2-1.dll'] if copy_gcc_lib else [])},
330      script_args=copy_args
331      )
332
333
334#Dont forget to delete fmilib_shared
335if 0 != sys.argv[1].find("clean"): #Dont check if we are cleaning!
336    if sys.platform.startswith("win"):
337        if O.path.exists(fmilib_shared):
338            O.remove(fmilib_shared)
339        if gcc_lib and O.path.exists(gcc_lib):
340            O.remove(gcc_lib)
Note: See TracBrowser for help on using the repository browser.