|
Urbi SDK Remote for C++
2.7.5
|
00001 /* 00002 * Copyright (C) 2009-2011, Gostai S.A.S. 00003 * 00004 * This software is provided "as is" without warranty of any kind, 00005 * either expressed or implied, including but not limited to the 00006 * implied warranties of fitness for a particular purpose. 00007 * 00008 * See the LICENSE file for more information. 00009 */ 00010 00011 #include <libport/sys/stat.h> 00012 #include <libport/unistd.h> 00013 00014 #include <libport/cassert> 00015 #include <libport/cstring> 00016 #include <libport/cstdlib> 00017 #include <libport/cstdio> 00018 #include <iostream> 00019 00020 #include <libport/config.h> 00021 #include <libport/foreach.hh> 00022 #include <libport/sysexits.hh> 00023 00024 #include <urbi/urbi-root.hh> 00025 #ifdef STATIC_BUILD 00026 # include <urbi/umain.hh> 00027 #endif 00028 00029 #if defined WIN32 00030 # define APPLE_LINUX_WINDOWS(Apple, Linux, Windows) Windows 00031 #elif defined __APPLE__ 00032 # define APPLE_LINUX_WINDOWS(Apple, Linux, Windows) Apple 00033 #else 00034 # define APPLE_LINUX_WINDOWS(Apple, Linux, Windows) Linux 00035 #endif 00036 00037 static std::string 00038 mygetenv(const std::string& var, const std::string& val = ""); 00039 00040 /*------------. 00041 | Reporting. | 00042 `------------*/ 00043 00044 static bool 00045 debug() 00046 { 00047 static bool res = mygetenv("GD_LEVEL") == "DUMP"; 00048 return res; 00049 } 00050 00051 # define URBI_ROOT_ECHO(S) \ 00052 std::cerr << S << std::endl \ 00053 00054 # define URBI_ROOT_DEBUG(Self, S) \ 00055 do { \ 00056 if (debug()) \ 00057 URBI_ROOT_ECHO(Self << ": " << S); \ 00058 } while (0) 00059 00060 # define URBI_ROOT_FATAL(Self, N, S) \ 00061 do { \ 00062 URBI_ROOT_ECHO(Self << ": " << S); \ 00063 exit(N); \ 00064 } while (0) 00065 00066 00067 00068 /*----------. 00069 | Helpers. | 00070 `----------*/ 00071 00072 static std::string 00073 mygetenv(const std::string& var, const std::string& val) 00074 { 00075 const char* res = getenv(var.c_str()); 00076 return res ? std::string(res) : val; 00077 } 00078 00079 static std::string 00080 urbi_getenv(const std::string& logname, 00081 std::string var, 00082 const std::string& val = "") 00083 { 00084 var = "URBI_" + var; 00085 const char* res = getenv(var.c_str()); 00086 if (res) 00087 { 00088 URBI_ROOT_DEBUG(logname, "obeying to " << var << " = " << res); 00089 return res; 00090 } 00091 else 00092 return val; 00093 } 00094 00095 /*-----------------. 00096 | File constants. | 00097 `-----------------*/ 00098 00099 static const std::string libext = 00100 APPLE_LINUX_WINDOWS(".dylib", ".so", ".dll"); 00101 static const std::string separator = 00102 APPLE_LINUX_WINDOWS("/", "/", "\\"); 00103 static const std::string libdir = 00104 APPLE_LINUX_WINDOWS("lib", "lib", "bin"); 00105 00107 static 00108 std::string 00109 operator/(const std::string& lhs, const std::string& rhs) 00110 { 00111 return (lhs.empty() ? rhs 00112 : rhs.empty() ? lhs 00113 : lhs + separator + rhs); 00114 } 00115 00116 /*-------------------------------------. 00117 | Crapy dynamic portability routines. | 00118 `-------------------------------------*/ 00119 00120 #ifdef WIN32 00121 # define RTLD_LAZY 0 00122 # define RTLD_NOW 0 00123 # define RTLD_GLOBAL 0 00124 00125 static RTLD_HANDLE 00126 dlopen(const char* name, int) 00127 { 00128 RTLD_HANDLE res = LoadLibrary(name); 00129 if (res) 00130 { 00131 char buf[BUFSIZ]; 00132 GetModuleFileName(res, buf, sizeof buf - 1); 00133 buf[sizeof buf - 1] = 0; 00134 } 00135 return res; 00136 } 00137 00138 static void* 00139 dlsym(RTLD_HANDLE module, const char* name) 00140 { 00141 return static_cast<void*>(GetProcAddress(module, name)); 00142 } 00143 00144 static const char* 00145 dlerror(DWORD err = GetLastError()) 00146 { 00147 static char buf[1024]; 00148 00149 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 00150 0, err, 0, 00151 (LPTSTR)buf, sizeof buf, 00152 0); 00153 00154 return buf; 00155 } 00156 00157 #else 00158 # include <dlfcn.h> 00159 #endif 00160 00161 typedef std::vector<std::string> strings_type; 00162 static strings_type 00163 split(std::string lib) 00164 { 00165 strings_type res; 00166 size_t pos = lib.find(':'); 00167 00168 if ((pos = lib.find(':')) == lib.npos) 00169 { 00170 res.push_back(lib); 00171 return res; 00172 } 00173 00174 do 00175 { 00176 std::string s = lib.substr(0, pos); 00177 if (pos != lib.npos) 00178 { 00179 lib = lib.substr(pos + 1, lib.npos); 00180 pos = lib.find(':'); 00181 } 00182 else 00183 lib.clear(); 00184 00185 #ifdef WIN32 00186 // Colon could be used as a path separator under cygwin and as a volume 00187 // separator under windows. 00188 if (s[0] == '\\' && !res.empty()) 00189 { 00190 std::string& back = res.back(); 00191 size_t back_len = back.length(); 00192 00193 // In case we split "c:\foo" into "c" and "\foo", glue them 00194 // together again. 00195 if (back_len == 1) 00196 back += ':' + s; 00197 00198 // In case we split "bar;c:\foo" into "bar;c" and "\foo", split them 00199 // into "bar" and "c:\foo" 00200 else if (back_len >= 2 && back[back_len - 2] == ';') 00201 { 00202 s = std::string("") + back[back_len - 1] + ':' + s; 00203 back = back.substr(0, back_len - 2); 00204 res.push_back(s); 00205 } 00206 } 00207 else 00208 res.push_back(s); 00209 #else 00210 res.push_back(s); 00211 #endif 00212 00213 } while (!lib.empty()); 00214 00215 return res; 00216 } 00217 00219 static 00220 RTLD_HANDLE 00221 xdlopen(const std::string& program, 00222 const std::string& msg, 00223 std::string path, 00224 sysexit status = EX_FAIL, 00225 int flags = RTLD_LAZY | RTLD_GLOBAL) 00226 { 00227 path += libext; 00228 URBI_ROOT_DEBUG(program, "loading library: " << path << " (" << msg << ")"); 00229 if (RTLD_HANDLE res = dlopen(path.c_str(), flags)) 00230 return res; 00231 else 00232 URBI_ROOT_FATAL(program, status, 00233 "cannot open library: " << path << ": " << dlerror()); 00234 } 00235 00236 template <typename Res> 00237 static 00238 Res 00239 xdlsym(const std::string& program, 00240 const char* modname, RTLD_HANDLE module, 00241 const char* name) 00242 { 00243 URBI_ROOT_DEBUG(program, "loading symbol " << name << " from " << modname); 00244 // Reinterpret-cast fails with gcc3 arm. 00245 if (Res res = (Res)(dlsym(module, name))) 00246 return res; 00247 else 00248 URBI_ROOT_FATAL(program, 2, 00249 "cannot locate " << name << " symbol: " << dlerror()); 00250 } 00251 00252 00253 static 00254 std::string 00255 resolve_symlinks(const std::string& logname, const std::string& s) 00256 { 00257 #if defined WIN32 00258 return s; 00259 #else 00260 char path[BUFSIZ]; 00261 strncpy(path, s.c_str(), sizeof path - 1); 00262 path[sizeof path - 1] = 0; 00263 while (readlink(path, path, sizeof path) != -1) 00264 URBI_ROOT_DEBUG(logname, "unrolling symbolic link: " << path); 00265 return path; 00266 #endif 00267 } 00268 00274 static 00275 std::string 00276 find_program(const std::string& logname, 00277 std::string prog) 00278 { 00279 #ifdef WIN32 00280 size_t pos = prog.find_last_of("/\\"); 00281 { 00282 size_t dot = prog.find_last_of("."); 00283 if (dot == prog.npos || prog.substr(dot + 1) != "exe") 00284 prog += ".exe"; 00285 } 00286 #else 00287 size_t pos = prog.rfind('/'); 00288 #endif 00289 if (pos == std::string::npos) 00290 { 00291 struct stat stats; 00292 std::string dir, file; 00293 bool found = false; 00294 00295 #ifdef WIN32 00296 URBI_ROOT_DEBUG(logname, 00297 "check if invoked from the current directory"); 00298 00299 { 00300 char *dir_buf = getcwd(0, 0); 00301 std::string dir(dir_buf); 00302 free(dir_buf); 00303 file = dir / prog; 00304 } 00305 00306 found = stat(file.c_str(), &stats) == 0; 00307 if (!found) 00308 { 00309 URBI_ROOT_DEBUG(logname, "not found: " << file); 00310 #endif 00311 URBI_ROOT_DEBUG(logname, 00312 "check if invoked from the path"); 00313 strings_type path = split(mygetenv("PATH")); 00314 foreach (const std::string& dir_, path) 00315 { 00316 file = dir_ / prog; 00317 found = stat(file.c_str(), &stats) == 0; 00318 if (found) 00319 { 00320 dir = dir_; 00321 break; 00322 } 00323 URBI_ROOT_DEBUG(logname, "not found: " << file); 00324 } 00325 #ifdef WIN32 00326 } 00327 #endif 00328 00329 if (found) 00330 { 00331 URBI_ROOT_DEBUG(logname, "found: " << file); 00332 std::string res = dir / ".."; 00333 URBI_ROOT_DEBUG(logname, "root directory is: " << res); 00334 return res; 00335 } 00336 } 00337 else 00338 { 00339 std::string res = prog.substr(0, pos) / ".."; 00340 URBI_ROOT_DEBUG(logname, 00341 "invoked with a path, setting root to parent directory: " 00342 << res); 00343 return res; 00344 } 00345 return ""; 00346 } 00347 00348 /*-----------. 00349 | UrbiRoot. | 00350 `-----------*/ 00351 00352 UrbiRoot::UrbiRoot(const std::string& program, bool static_build) 00353 : program_(program) 00354 , root_() 00355 , handle_libjpeg_(0) 00356 , handle_libport_(0) 00357 , handle_libsched_(0) 00358 , handle_liburbi_(0) 00359 , handle_libuobject_(0) 00360 { 00361 // Find our directory. 00362 std::string uroot = urbi_getenv(program, "ROOT"); 00363 if (uroot.empty()) 00364 { 00365 URBI_ROOT_DEBUG(program_, "guessing Urbi root: invoked as: " << program_); 00366 // Handle the chained symlinks case. 00367 std::string argv0 = resolve_symlinks(program_, program); 00368 root_ = find_program(program_, argv0); 00369 } 00370 else 00371 { 00372 root_ = uroot; 00373 URBI_ROOT_DEBUG(program_, 00374 "URBI_ROOT is set, forcing root directory: " << root_); 00375 } 00376 00377 if (root_.empty()) 00378 URBI_ROOT_FATAL(program_, 3, 00379 "Unable to find Urbi SDK installation location. " 00380 "Please set URBI_ROOT."); 00381 00382 if (!static_build) 00383 { 00384 handle_libjpeg_ = library_load("jpeg4urbi"); 00385 handle_libport_ = library_load("port"); 00386 handle_libsched_ = library_load("sched"); 00387 #ifdef LIBPORT_ENABLE_SERIALIZATION 00388 handle_libserialize_ = library_load("serialize"); 00389 #endif 00390 handle_liburbi_ = library_load("urbi"); 00391 } 00392 } 00393 00394 RTLD_HANDLE 00395 UrbiRoot::library_load(const std::string& base, const std::string& env_suffix) 00396 { 00397 std::string envvar; 00398 if (env_suffix.empty()) 00399 envvar = "ROOT_LIB" + base; 00400 else 00401 envvar = "ROOT_LIB" + env_suffix; 00402 foreach (char& s, envvar) 00403 s = toupper(s); 00404 00405 return 00406 xdlopen(program_, 00407 base, 00408 urbi_getenv(program_, envvar, 00409 root() / libdir / "lib" + base + library_suffix())); 00410 } 00411 00412 const std::string& 00413 UrbiRoot::root() const 00414 { 00415 return root_; 00416 } 00417 00418 std::string 00419 UrbiRoot::core_path() const 00420 { 00421 return root() / LIBPORT_LIBDIRNAME / "gostai"; 00422 } 00423 00424 std::string 00425 UrbiRoot::doc_dir() const 00426 { 00427 return urbi_getenv(program_, "DOC", root() / "share" / "doc" / "urbi-sdk"); 00428 } 00429 00430 std::string 00431 UrbiRoot::share_dir() const 00432 { 00433 return urbi_getenv(program_, "SHARE", root() / "share" / "gostai"); 00434 } 00435 00436 std::vector<std::string> 00437 UrbiRoot::uobjects_path() const 00438 { 00439 std::vector<std::string> res; 00440 if (!library_suffix().empty()) 00441 res.push_back(core_path() / "uobjects" + library_suffix()); 00442 res.push_back(core_path() / "uobjects"); 00443 return res; 00444 } 00445 00446 std::string 00447 UrbiRoot::library_suffix() const 00448 { 00449 return LIBPORT_LIBSFX; 00450 } 00451 00452 void 00453 UrbiRoot::load_plugin() 00454 { 00455 handle_libuobject_ = 00456 xdlopen(program_, 00457 "plugin UObject implementation", 00458 urbi_getenv(program_, "ROOT_LIBPLUGIN", 00459 core_path() / "engine" / "libuobject"+library_suffix()), 00460 // This exit status is understood by the test suite. It 00461 // helps it skipping SDK Remote tests that cannot run 00462 // without Urbi SDK. 00463 EX_OSFILE); 00464 } 00465 00467 void 00468 UrbiRoot::load_remote() 00469 { 00470 handle_libuobject_ = 00471 xdlopen(program_, 00472 "remote UObject implementation", 00473 urbi_getenv(program_, "ROOT_LIBREMOTE", 00474 core_path() / "remote" / "libuobject"+library_suffix()), 00475 EX_OSFILE); 00476 } 00477 00478 void 00479 UrbiRoot::load_custom(const std::string& path_) 00480 { 00481 handle_libuobject_ = 00482 xdlopen(program_, 00483 "custom UObject implementation", 00484 path_ / "libuobject", 00485 EX_OSFILE); 00486 } 00487 00488 int 00489 UrbiRoot::urbi_launch(int argc, const char** argv) 00490 { 00491 urbi_launch_type f = 00492 xdlsym<urbi_launch_type>(program_, 00493 "liburbi-launch", handle_liburbi_, 00494 "urbi_launch"); 00495 return f(argc, argv, *this); 00496 } 00497 00498 int 00499 UrbiRoot::urbi_launch(int argc, char** argv) 00500 { 00501 return urbi_launch(argc, const_cast<const char**>(argv)); 00502 } 00503 00504 typedef int(*urbi_main_type)(const std::vector<std::string>& args, 00505 UrbiRoot& root, 00506 bool block, bool errors); 00507 int 00508 UrbiRoot::urbi_main(const std::vector<std::string>& args, 00509 bool block, bool errors) 00510 { 00511 #ifdef STATIC_BUILD 00512 return ::urbi_main_args(args, *this, block, errors); 00513 #else 00514 urbi_main_type f = 00515 xdlsym<urbi_main_type>(program_, 00516 "libuobject", handle_libuobject_, 00517 "urbi_main_args"); 00518 URBI_ROOT_DEBUG(program_, "command line: "); 00519 foreach (const std::string& arg, args) 00520 URBI_ROOT_DEBUG(program_, " " << arg); 00521 00522 return f(args, *this, block, errors); 00523 #endif 00524 }