Panda3D
|
00001 // Filename: mayapath.cxx 00002 // Created by: drose (07Apr08) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 // This program works as a stub to launch maya2egg, egg2maya, and 00016 // similar programs that invoke OpenMaya and require certain 00017 // environment variables to be set first. 00018 00019 // It used to duplicate code in mayaWrapper.cxx, but now the 00020 // functionality for these two separate programs are unified here. 00021 00022 // If MAYAVERSION is defined at the time this is compiled, then that 00023 // particular version of Maya is insisted upon, and the desired Maya 00024 // location is found in the Registry; otherwise, we require that 00025 // $MAYA_LOCATION be set at runtime and points to the desired Maya 00026 // installation. 00027 00028 // If MAYAVERSION is defined and $MAYA_LOCATION is also set, then we 00029 // check that definition of $MAYA_LOCATION is reasonable, which we 00030 // define as pointing to the same version of OpenMaya.dll. If so, 00031 // then we use the runtime $MAYA_LOCATION, allowing the user to 00032 // (slightly) override the runtime Maya directory. If $MAYA_LOCATION 00033 // is set but points to a different version of OpenMaya.dll, we ignore 00034 // it altogether and replace it with our registry data, which allows 00035 // the user to have MAYA_LOCATION pointing to a different version of 00036 // Maya without interfering with this program. 00037 00038 #include "dtoolbase.h" 00039 #include "filename.h" 00040 #include "globPattern.h" 00041 #include "dSearchPath.h" 00042 #include "executionEnvironment.h" 00043 #include "hashVal.h" 00044 #include <stdlib.h> 00045 00046 #if defined(_WIN32) 00047 #define WIN32_LEAN_AND_MEAN 00048 #include <windows.h> 00049 #endif 00050 00051 #define QUOTESTR(x) #x 00052 #define TOSTRING(x) QUOTESTR(x) 00053 00054 #ifdef IS_OSX 00055 static const Filename openmaya_filename = "MacOS/libOpenMaya.dylib"; 00056 #else 00057 static const Filename openmaya_filename = "bin/OpenMaya.so"; 00058 #endif // IS_OSX 00059 00060 // Searches for python26.zip or whatever version it is. 00061 static Filename 00062 find_pyzip(const Filename &maya_location) { 00063 // This is where python26.zip appears on Windows. Should it be in 00064 // other locations on other platforms? 00065 Filename dirname(maya_location, "bin"); 00066 00067 vector_string results; 00068 GlobPattern glob("python*.zip"); 00069 if (glob.match_files(results, dirname) != 0) { 00070 return Filename(dirname, results[0]); 00071 } 00072 00073 return Filename(); 00074 } 00075 00076 struct { char *ver, *key; } maya_versions[] = { 00077 { "MAYA6", "6.0" }, 00078 { "MAYA65", "6.5" }, 00079 { "MAYA7", "7.0" }, 00080 { "MAYA8", "8.0" }, 00081 { "MAYA85", "8.5" }, 00082 { "MAYA2008", "2008" }, 00083 { "MAYA2009", "2009" }, 00084 { "MAYA2010", "2010" }, 00085 { "MAYA2011", "2011"}, 00086 { "MAYA2012", "2012"}, 00087 { 0, 0 }, 00088 }; 00089 00090 static char * 00091 get_version_number(const char *ver) { 00092 for (int i=0; maya_versions[i].ver != 0; i++) { 00093 if (strcmp(maya_versions[i].ver, ver)==0) { 00094 return maya_versions[i].key; 00095 } 00096 } 00097 return 0; 00098 } 00099 00100 #if defined(_WIN32) 00101 static void 00102 get_maya_location(const char *ver, string &loc) { 00103 char fullkey[1024]; 00104 const char *developer; 00105 LONG res; 00106 00107 for (int dev=0; dev<3; dev++) { 00108 switch (dev) { 00109 case 0: developer="Alias|Wavefront"; break; 00110 case 1: developer="Alias"; break; 00111 case 2: developer="Autodesk"; break; 00112 } 00113 sprintf(fullkey, "SOFTWARE\\%s\\Maya\\%s\\Setup\\InstallPath", developer, ver); 00114 for (int hive=0; hive<2; hive++) { 00115 HKEY hkey; 00116 res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, fullkey, 0, KEY_READ | (hive ? 256:0), &hkey); 00117 if (res == ERROR_SUCCESS) { 00118 DWORD dtype; 00119 DWORD size = 4096; 00120 char result[4096 + 1]; 00121 res = RegQueryValueEx(hkey, "MAYA_INSTALL_LOCATION", NULL, &dtype, (LPBYTE)result, &size); 00122 if ((res == ERROR_SUCCESS)&&(dtype == REG_SZ)) { 00123 result[size] = 0; 00124 loc = result; 00125 } 00126 RegCloseKey(hkey); 00127 } 00128 } 00129 } 00130 } 00131 00132 #elif defined(__APPLE__) 00133 static void 00134 get_maya_location(const char *ver, string &loc) { 00135 char mpath[64]; 00136 sprintf(mpath, "/Applications/Autodesk/maya%s/Maya.app/Contents", ver); 00137 struct stat st; 00138 if(stat(mpath, &st) == 0) { 00139 loc = mpath; 00140 } 00141 } 00142 00143 #else // _WIN32 00144 static void 00145 get_maya_location(const char *ver, string &loc) { 00146 char mpath[64]; 00147 #if __WORDSIZE == 64 00148 sprintf(mpath, "/usr/autodesk/maya%s-x64", ver); 00149 #else 00150 sprintf(mpath, "/usr/autodesk/maya%s", ver); 00151 #endif 00152 struct stat st; 00153 if(stat(mpath, &st) == 0) { 00154 loc = mpath; 00155 } else { 00156 #if __WORDSIZE == 64 00157 sprintf(mpath, "/usr/aw/maya%s-x64", ver); 00158 #else 00159 sprintf(mpath, "/usr/aw/maya%s", ver); 00160 #endif 00161 if(stat(mpath, &st) == 0) { 00162 loc = mpath; 00163 } 00164 } 00165 } 00166 00167 #endif // _WIN32 00168 00169 00170 int 00171 main(int argc, char *argv[]) { 00172 // First, get the command line and append _bin, so we will actually 00173 // run maya2egg_bin.exe, egg2maya_bin.exe, etc. 00174 Filename command = Filename::from_os_specific(argv[0]); 00175 if (!command.is_fully_qualified()) { 00176 DSearchPath path; 00177 path.append_path(ExecutionEnvironment::get_environment_variable("PATH")); 00178 #ifdef _WIN32 00179 command.set_extension("exe"); 00180 #endif 00181 command.resolve_filename(path); 00182 } 00183 00184 #ifdef _WIN32 00185 if (command.get_extension() == "exe") { 00186 command.set_extension(""); 00187 } 00188 #endif 00189 00190 command = command.get_fullpath() + string("_bin"); 00191 #ifdef _WIN32 00192 command.set_extension("exe"); 00193 #endif 00194 string os_command = command.to_os_specific(); 00195 00196 // First start with $PANDA_MAYA_LOCATION. If it is set, it 00197 // overrides everything else. 00198 Filename maya_location = Filename::expand_from("$PANDA_MAYA_LOCATION"); 00199 if (!maya_location.empty()) { 00200 // Reset maya_location to its full long name, because Maya 00201 // requires this. 00202 maya_location.make_canonical(); 00203 maya_location = Filename::from_os_specific(maya_location.to_os_long_name()); 00204 00205 } else { 00206 // $PANDA_MAYA_LOCATION wasn't set, so check the normal locations. 00207 // First, we get the standard location, as a point of reference. 00208 Filename standard_maya_location; 00209 #ifdef MAYAVERSION 00210 const char *key = get_version_number(TOSTRING(MAYAVERSION)); 00211 if (key == NULL) { 00212 cerr << "Unknown Maya version: " << TOSTRING(MAYAVERSION) << "\n"; 00213 } else { 00214 string loc; 00215 get_maya_location(key, loc); 00216 if (loc.empty()) { 00217 cerr << "Cannot locate " << TOSTRING(MAYAVERSION) << ": it does not appear to be installed.\n"; 00218 } else { 00219 standard_maya_location = Filename::from_os_specific(loc); 00220 } 00221 } 00222 if (!standard_maya_location.empty()) { 00223 // Reset standard_maya_location to its full long name, so we can 00224 // compare reliably to the given version. 00225 standard_maya_location.make_canonical(); 00226 standard_maya_location = Filename::from_os_specific(standard_maya_location.to_os_long_name()); 00227 } 00228 #endif // MAYAVERSION 00229 00230 // Now check if $MAYA_LOCATION is set. If it is, and it's 00231 // consistent with the standard location, we respect it. 00232 maya_location = Filename::expand_from("$MAYA_LOCATION"); 00233 if (!maya_location.empty()) { 00234 // Reset maya_location to its full long name, so we can compare 00235 // it reliably to the standard location; and also because Maya 00236 // requires this. 00237 maya_location.make_canonical(); 00238 maya_location = Filename::from_os_specific(maya_location.to_os_long_name()); 00239 } 00240 00241 if (maya_location.empty()) { 00242 // If it is not set, we use the standard version instead. 00243 maya_location = standard_maya_location; 00244 00245 } else if (maya_location != standard_maya_location) { 00246 // If it *is* set, we verify that OpenMaya.dll matches the 00247 // standard version. 00248 Filename openmaya_given = Filename::dso_filename(Filename(maya_location, openmaya_filename)); 00249 Filename openmaya_standard = Filename::dso_filename(Filename(standard_maya_location, openmaya_filename)); 00250 00251 if (openmaya_given != openmaya_standard) { 00252 #ifdef HAVE_OPENSSL 00253 // If we have OpenSSL, we can use it to check the md5 hashes of 00254 // the DLL. 00255 HashVal hash_given, hash_standard; 00256 if (!hash_standard.hash_file(openmaya_standard)) { 00257 // Couldn't read the standard file, so use the given one. 00258 00259 } else { 00260 if (!hash_given.hash_file(openmaya_given)) { 00261 // Couldn't even read the given file; use the standard one 00262 // instead. 00263 maya_location = standard_maya_location; 00264 00265 } else { 00266 if (hash_standard != hash_given) { 00267 // No match; it must be the wrong version. 00268 cerr << "$MAYA_LOCATION points to wrong version; using standard location instead.\n"; 00269 maya_location = standard_maya_location; 00270 } else { 00271 // The hash matches; keep the given MAYA_LOCATION setting. 00272 } 00273 } 00274 } 00275 #else // HAVE_OPENSSL 00276 // Without OpenSSL, just check the DLL filesize only. 00277 off_t size_given, size_standard; 00278 size_standard = openmaya_standard.get_file_size(); 00279 if (size_standard == 0) { 00280 // Couldn't read the standard file, so use the given one. 00281 00282 } else { 00283 size_given = openmaya_given.get_file_size(); 00284 if (size_given == 0) { 00285 // Couldn't even read the given file; use the standard one 00286 // instead. 00287 maya_location = standard_maya_location; 00288 00289 } else { 00290 if (size_standard != size_given) { 00291 // No match; it must be the wrong version. 00292 cerr << "$MAYA_LOCATION points to wrong version; using standard location instead.\n"; 00293 maya_location = standard_maya_location; 00294 00295 } else { 00296 // The size matches; keep the given MAYA_LOCATION setting. 00297 } 00298 } 00299 } 00300 00301 #endif // HAVE_OPENSSL 00302 } 00303 } 00304 } 00305 00306 if (maya_location.empty()) { 00307 cerr << "$MAYA_LOCATION is not set!\n"; 00308 exit(1); 00309 } 00310 00311 cerr << "MAYA_LOCATION: " << maya_location.to_os_specific() << endl; 00312 if (!maya_location.is_directory()) { 00313 cerr << "The directory referred to by $MAYA_LOCATION does not exist!\n"; 00314 exit(1); 00315 } 00316 00317 // Look for OpenMaya.dll as a sanity check. 00318 Filename openmaya = Filename::dso_filename(Filename(maya_location, openmaya_filename)); 00319 if (!openmaya.is_regular_file()) { 00320 cerr << "Could not find $MAYA_LOCATION/" << Filename::dso_filename(openmaya_filename).to_os_specific() << "!\n"; 00321 exit(1); 00322 } 00323 00324 // Re-set MAYA_LOCATION to its properly sanitized form. 00325 { 00326 string putenv_str = "MAYA_LOCATION=" + maya_location.to_os_specific(); 00327 char *putenv_cstr = strdup(putenv_str.c_str()); 00328 putenv(putenv_cstr); 00329 } 00330 00331 #ifdef WIN32 00332 string sep = ";"; 00333 #else 00334 string sep = ":"; 00335 #endif 00336 00337 // Now set PYTHONHOME & PYTHONPATH. Maya2008 requires this to be 00338 // set and pointing within $MAYA_LOCATION, or it might get itself 00339 // confused with another Python installation (e.g. Panda's). 00340 Filename python = Filename(maya_location, "Python"); 00341 if (python.is_directory()) { 00342 { 00343 string putenv_str = "PYTHONHOME=" + python.to_os_specific(); 00344 char *putenv_cstr = strdup(putenv_str.c_str()); 00345 putenv(putenv_cstr); 00346 } 00347 { 00348 string putenv_str = "PYTHONPATH=" + python.to_os_specific(); 00349 00350 Filename pyzip = find_pyzip(maya_location); 00351 if (!pyzip.empty() && pyzip.exists()) { 00352 putenv_str += sep; 00353 putenv_str += pyzip.to_os_specific(); 00354 } 00355 00356 Filename site_packages(python, "lib/site-packages"); 00357 if (site_packages.is_directory()) { 00358 putenv_str += sep; 00359 putenv_str += site_packages.to_os_specific(); 00360 } 00361 00362 char *putenv_cstr = strdup(putenv_str.c_str()); 00363 putenv(putenv_cstr); 00364 } 00365 } 00366 00367 // Also put the Maya bin directory on the PATH. 00368 Filename bin = Filename(maya_location, "bin"); 00369 if (bin.is_directory()) { 00370 char *path = getenv("PATH"); 00371 if (path == NULL) { 00372 path = ""; 00373 } 00374 string putenv_str = "PATH=" + bin.to_os_specific() + sep + path; 00375 char *putenv_cstr = strdup(putenv_str.c_str()); 00376 putenv(putenv_cstr); 00377 } 00378 00379 #ifdef IS_OSX 00380 // And on DYLD_LIBRARY_PATH. 00381 if (bin.is_directory()) { 00382 char *path = getenv("DYLD_LIBRARY_PATH"); 00383 if (path == NULL) { 00384 path = ""; 00385 } 00386 string sep = ":"; 00387 string putenv_str = "DYLD_LIBRARY_PATH=" + bin.to_os_specific() + sep + path; 00388 char *putenv_cstr = strdup(putenv_str.c_str()); 00389 putenv(putenv_cstr); 00390 } 00391 00392 #elif !defined(_WIN32) 00393 // Linux (or other non-Windows OS) gets it added to LD_LIBRARY_PATH. 00394 if (bin.is_directory()) { 00395 char *path = getenv("LD_LIBRARY_PATH"); 00396 if (path == NULL) { 00397 path = ""; 00398 } 00399 string sep = ":"; 00400 string putenv_str = "LD_LIBRARY_PATH=" + bin.to_os_specific() + sep + path; 00401 char *putenv_cstr = strdup(putenv_str.c_str()); 00402 putenv(putenv_cstr); 00403 } 00404 00405 #endif // IS_OSX 00406 00407 // When this is set, Panda3D will try not to use any functions from the 00408 // CPython API. This is necessary because Maya links with its own copy 00409 // of Python, which may be incompatible with ours. 00410 putenv("PANDA_INCOMPATIBLE_PYTHON=1"); 00411 00412 // Now that we have set up the environment variables properly, chain 00413 // to the actual maya2egg_bin (or whichever) executable. 00414 00415 #ifdef _WIN32 00416 // Windows case. 00417 char *command_line = strdup(GetCommandLine()); 00418 STARTUPINFO startup_info; 00419 PROCESS_INFORMATION process_info; 00420 GetStartupInfo(&startup_info); 00421 BOOL result = CreateProcess(os_command.c_str(), 00422 command_line, 00423 NULL, NULL, true, 0, 00424 NULL, NULL, 00425 &startup_info, 00426 &process_info); 00427 if (result) { 00428 WaitForSingleObject(process_info.hProcess, INFINITE); 00429 DWORD exit_code = 0; 00430 00431 if (GetExitCodeProcess(process_info.hProcess, &exit_code)) { 00432 if (exit_code != 0) { 00433 cerr << "Program exited with status " << exit_code << "\n"; 00434 } 00435 } 00436 00437 CloseHandle(process_info.hProcess); 00438 CloseHandle(process_info.hThread); 00439 exit(exit_code); 00440 } 00441 cerr << "Couldn't execute " << command << ": " << GetLastError() << "\n"; 00442 00443 #else 00444 // Unix case. 00445 execvp(os_command.c_str(), argv); 00446 #endif 00447 00448 // Couldn't execute for some reason. 00449 return 1; 00450 }