root/MGET/Trunk/PythonPackage/src/GeoEco/Matlab.py
| Revision 294, 10.0 kB (checked in by jjr8, 1 year ago) |
|---|
| Line | |
|---|---|
| 1 | # Matlab.py - Provides methods for initializing the Matlab Component |
| 2 | # Runtime (MCR). These methods are only intended for use within the |
| 3 | # GeoEco Python package and should not be invoked by external callers. |
| 4 | # |
| 5 | # Copyright (C) 2008 Jason J. Roberts |
| 6 | # |
| 7 | # This program is free software; you can redistribute it and/or |
| 8 | # modify it under the terms of the GNU General Public License |
| 9 | # as published by the Free Software Foundation; either version 2 |
| 10 | # of the License, or (at your option) any later version. |
| 11 | # |
| 12 | # This program is distributed in the hope that it will be useful, |
| 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 15 | # GNU General Public License (available in the file LICENSE.TXT) |
| 16 | # for more details. |
| 17 | # |
| 18 | # You should have received a copy of the GNU General Public License |
| 19 | # along with this program; if not, write to the Free Software |
| 20 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| 21 | |
| 22 | import os |
| 23 | import os.path |
| 24 | import string |
| 25 | import sys |
| 26 | |
| 27 | from GeoEco.Dependencies import Dependency, SoftwareNotInstalledError, UnsupportedPlatformError |
| 28 | from GeoEco.DynamicDocString import DynamicDocString |
| 29 | from GeoEco.Internationalization import _ |
| 30 | from GeoEco.Logging import Logger |
| 31 | |
| 32 | |
| 33 | class MatlabDependency(Dependency): |
| 34 | __doc__ = DynamicDocString() |
| 35 | |
| 36 | def GetResultCacheKey(self): |
| 37 | return u'MatlabDependency' |
| 38 | |
| 39 | def Initialize(self): |
| 40 | |
| 41 | # Return successfully if we have already been initalized. |
| 42 | |
| 43 | if MatlabDependency._Initialized: |
| 44 | return |
| 45 | |
| 46 | # Fail if we are not running on Windows. Currently we only |
| 47 | # support Matlab on Windows. |
| 48 | |
| 49 | if sys.platform.lower() != u'win32': |
| 50 | Logger.RaiseException(UnsupportedPlatformError(_(u'This tool can only execute on a computer running the Microsoft Windows operating system. Python reports that this computer is running the \"%s\" operating system.') % platform.system())) |
| 51 | |
| 52 | else: |
| 53 | |
| 54 | # Look in the system path for the libraries MCLMCRRT77.DLL |
| 55 | # and MCLMCR.DLL. |
| 56 | |
| 57 | Logger.Debug(_(u'Checking software dependency: MATLAB 2007b or MATLAB Component Runtime (MCR) 7.7.')) |
| 58 | |
| 59 | found = False |
| 60 | dir1 = None |
| 61 | dir2 = None |
| 62 | |
| 63 | for i, p in enumerate(map(string.strip, os.environ['PATH'].split(os.path.pathsep))): |
| 64 | if len(p) > 0 and os.path.isfile(os.path.join(p, 'MCLMCRRT77.DLL')): |
| 65 | dir1 = p |
| 66 | if os.path.isfile(os.path.join(dir1, 'MCLMCR.DLL')): # Seems to be true if MATLAB is installed |
| 67 | dir2 = dir1 |
| 68 | found = True |
| 69 | break |
| 70 | elif os.path.isfile(os.path.join(os.path.dirname(os.path.dirname(dir1)), 'bin', 'win32', 'MCLMCR.DLL')): # Seems to be true if MCR is installed |
| 71 | dir2 = os.path.join(os.path.dirname(os.path.dirname(dir1)), 'bin', 'win32') |
| 72 | found = True |
| 73 | break |
| 74 | |
| 75 | # If we don't find the libraries in the path, try the |
| 76 | # default MATLAB 2007b and MCR 7.7 installation |
| 77 | # directories. |
| 78 | |
| 79 | if not found: |
| 80 | dir1 = os.path.join(os.environ['ProgramFiles'], 'MATLAB', 'R2007b', 'bin', 'win32') |
| 81 | dir2 = dir1 |
| 82 | if os.path.isfile(os.path.join(dir1, 'MCLMCRRT77.DLL')) and os.path.isfile(os.path.join(dir2, 'MCLMCR.DLL')): |
| 83 | found = True |
| 84 | else: |
| 85 | dir1 = os.path.join(os.environ['ProgramFiles'], 'MATLAB', 'MATLAB Component Runtime', 'v77', 'runtime', 'win32') |
| 86 | dir2 = os.path.join(os.environ['ProgramFiles'], 'MATLAB', 'MATLAB Component Runtime', 'v77', 'bin', 'win32') |
| 87 | if os.path.isfile(os.path.join(dir1, 'MCLMCRRT77.DLL')) and os.path.isfile(os.path.join(dir2, 'MCLMCR.DLL')): |
| 88 | found = True |
| 89 | |
| 90 | # If we found the directories containing the libraries, |
| 91 | # move them to the front of the system path, so that if |
| 92 | # multiple copies of MATLAB or the MCR are installed, |
| 93 | # these are the ones that are probed first when DLLs are |
| 94 | # loaded. |
| 95 | |
| 96 | if found: |
| 97 | newPaths = map(string.strip, os.environ['PATH'].split(os.path.pathsep)) |
| 98 | while i < len(newPaths): |
| 99 | if newPaths[i] == dir1 or newPaths[i] == dir2: |
| 100 | del newPaths[i] |
| 101 | else: |
| 102 | i += 1 |
| 103 | |
| 104 | if dir1 == dir2: |
| 105 | Logger.Debug(_(u'Found required MATLAB libraries %(dir1)s\\MCLMCRRT77.DLL and %(dir2)s\\MCLMCR.DLL. MATLAB 2007b appears to be installed.') % {u'dir1': dir1, u'dir2': dir2}) |
| 106 | os.environ['PATH'] = dir1 + os.path.pathsep + os.path.pathsep.join(newPaths) |
| 107 | else: |
| 108 | Logger.Debug(_(u'Found required MATLAB libraries %(dir1)s\\MCLMCRRT77.DLL and %(dir2)s\\MCLMCR.DLL. MATLAB Component Runtime (MCR) 7.7 appears to be installed.') % {u'dir1': dir1, u'dir2': dir2}) |
| 109 | os.environ['PATH'] = dir1 + os.path.pathsep + dir2 + os.path.pathsep + os.path.pathsep.join(newPaths) |
| 110 | |
| 111 | Logger.Debug(_('Set environment variable PATH=%s') % os.environ['PATH']) |
| 112 | |
| 113 | # Fail if we did not fnd the library. |
| 114 | |
| 115 | else: |
| 116 | Logger.RaiseException(SoftwareNotInstalledError(_(u'This tool requires either MATLAB 2007b or the MATLAB Component Runtime (MCR) 7.7, but neither appear to be installed. You can download a free copy of the MCR 7.7 from http://code.env.duke.edu/projects/mget/wiki/MCR. Please install it and try again. If you believe you already have one of these programs installed, and it is the proper version, verify that the program\'s binary directory is in the system PATH variable. Please see the MATLAB documentation for more information.'))) |
| 117 | |
| 118 | # If this is ArcGIS 9.3 or later, explicitly load |
| 119 | # xerces-c_2_7.dll from the MATLAB directory. |
| 120 | # |
| 121 | # xerces-c_2_7.dll is an open-source XML parser that is |
| 122 | # used by both ArcGIS 9.3 and MATLAB 2007b. Both products |
| 123 | # compile this DLL but they versions they produce are not |
| 124 | # compatible with each other (perhaps they used different |
| 125 | # compilers or compiler options). Because they used the |
| 126 | # same file name, when one product calls Win32 LoadLibrary |
| 127 | # on that name, there is a chance it will load the other |
| 128 | # product's DLL. Or, if the first product has already |
| 129 | # loaded its DLL into the process, the second product will |
| 130 | # be given a handle to that DLL instead of its own DLL. As |
| 131 | # a result, when it calls GetProcAddress (or whatever) to |
| 132 | # get the address of a function it wants to call, that |
| 133 | # function will not be there and the Win32 error "The |
| 134 | # specified procedure could not be found" will occur. |
| 135 | # |
| 136 | # The proper way to prevent this name collision problem is |
| 137 | # for either ESRI or MathWorks or both to compile the DLL |
| 138 | # using an ArcGIS- or MATLAB-specific name, rather than |
| 139 | # both using the default name, xerces-c_2_7.dll. Neither |
| 140 | # of them seem to be aware of the incompatibility problem |
| 141 | # they're creating. |
| 142 | # |
| 143 | # Fortunately it looks like ArcGIS only loads the DLL when |
| 144 | # it is needed for specific scenarios. I am not sure what |
| 145 | # those scenarios are, but they seem to be rare. But |
| 146 | # MATLAB loads it right away when you initialize the MCR. |
| 147 | # Our strategy, therefore, is to ensure that the MATLAB |
| 148 | # version of the DLL will be loaded. According to the |
| 149 | # rules of Win32 LoadLibrary, we should have already done |
| 150 | # this by moving the MATLAB paths to the front of the |
| 151 | # system PATH variable. But this does not seem to work and |
| 152 | # I can't figure out why. Somehow it is still being loaded |
| 153 | # from C:\Program Files\ArcGIS\Bin whenever the MCR is |
| 154 | # initialized. |
| 155 | # |
| 156 | # To deal with this, we explicitly load it here from the |
| 157 | # MATLAB directory. Then, when the MCR initializes, |
| 158 | # LoadLibrary detects that the DLL is already in memory |
| 159 | # and uses that copy. |
| 160 | # |
| 161 | # Note that if ArcGIS ever DOES need to use the DLL, when |
| 162 | # it calls LoadLibrary it will get the MATLAB version. |
| 163 | # This could cause it to fail in an unexpected way. Sadly, |
| 164 | # there is no way around this. Because of this |
| 165 | # possibility, all GeoEco tools that use MATLAB should be |
| 166 | # run as out-of-process geoprocessing tools under Arc 9.3 |
| 167 | # and later versions, so that the MATLAB DLL is not loaded |
| 168 | # into ArcGIS processes such as ArcCatalog.exe or |
| 169 | # ArcMap.exe. |
| 170 | |
| 171 | from GeoEco.ArcGIS import GeoprocessorManager |
| 172 | if GeoprocessorManager.GetArcGISMajorVersion() >= 9 and GeoprocessorManager.GetArcGISMinorVersion() >= 3: |
| 173 | import win32api |
| 174 | Logger.Debug(_('Explicitly loading %s so the MATLAB MCR will use it rather than ArcGIS\'s version of it, which is not compatible.') % os.path.join(dir2, 'xerces-c_2_7.dll')) |
| 175 | MatlabDependency._XercesDLLHandle = win32api.LoadLibrary(os.path.join(dir2, 'xerces-c_2_7.dll')) |
| 176 | |
| 177 | # Set our flag indicating that initialization was successful. |
| 178 | |
| 179 | MatlabDependency._Initialized = True |
| 180 | |
| 181 | _Initialized = False |
| 182 | _XercesDLLHandle = None |
| 183 | |
| 184 | |
| 185 | ############################################################################### |
| 186 | # Names exported by this module |
| 187 | ############################################################################### |
| 188 | |
| 189 | __all__ = ['MatlabDependency'] |
Note: See TracBrowser for help on using the browser.
