12d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner/* Copyright (C) 2011 The Android Open Source Project
22d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner**
32d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner** This software is licensed under the terms of the GNU General Public
42d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner** License version 2, as published by the Free Software Foundation, and
52d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner** may be copied, distributed, and modified under those terms.
62d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner**
72d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner** This program is distributed in the hope that it will be useful,
82d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner** but WITHOUT ANY WARRANTY; without even the implied warranty of
92d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
102d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner** GNU General Public License for more details.
112d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner*/
122d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner
132d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner/* This is the source code to the tiny "emulator" launcher program
142d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner * that is in charge of starting the target-specific emulator binary
152d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner * for a given AVD, i.e. either 'emulator-arm' or 'emulator-x86'
162d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner *
172d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner * This program will be replaced in the future by what is currently
182d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner * known as 'emulator-ui', but is a good placeholder until this
192d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner * migration is completed.
202d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner */
212d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner
222d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner#include <errno.h>
232d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner#include <stdio.h>
242d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner#include <stdlib.h>
252d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner#include <string.h>
262d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner#include <unistd.h>
277891dd35fa2439a70f43ab8572778a398365bf24David 'Digit' Turner#include <android/utils/compiler.h>
28ee57375c96822790cc7f837b4fdf64a9c1d69b3aDavid 'Digit' Turner#include <android/utils/host_bitness.h>
292d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner#include <android/utils/panic.h>
302d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner#include <android/utils/path.h>
312d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner#include <android/utils/bufprint.h>
3260d0a1536e4e75cee039c09da65a2e994be2e106David 'Digit' Turner#include <android/utils/win32_cmdline_quote.h>
332d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner#include <android/avd/util.h>
342d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner
352d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner/* Required by android/utils/debug.h */
362d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turnerint android_verbose;
372d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner
382d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner
392d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner#define DEBUG 1
402d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner
412d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner#if DEBUG
422d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner#  define D(...)  do { if (android_verbose) printf("emulator:" __VA_ARGS__); } while (0)
432d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner#else
442d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner#  define D(...)  do{}while(0)
452d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner#endif
462d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner
47bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner/* The extension used by dynamic libraries on the host platform */
48bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner#ifdef _WIN32
49bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner#  define DLL_EXTENSION  ".dll"
50bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner#elif defined(__APPLE__)
51bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner#  define DLL_EXTENSION  ".dylib"
52bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner#else
53bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner#  define DLL_EXTENSION  ".so"
54bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner#endif
55bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner
569554550a3ecf2987af84d98d4b683757c74d8b93David 'Digit' Turner// Name of GPU emulation main library for (32-bit and 64-bit versions)
579554550a3ecf2987af84d98d4b683757c74d8b93David 'Digit' Turner#define GLES_EMULATION_LIB    "libOpenglRender" DLL_EXTENSION
589554550a3ecf2987af84d98d4b683757c74d8b93David 'Digit' Turner#define GLES_EMULATION_LIB64  "lib64OpenglRender" DLL_EXTENSION
59bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner
602d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner/* Forward declarations */
61ddd4ef7f7c8d07e95dc88ca897634f537666d5f3Andrew Hsiehstatic char* getTargetEmulatorPath(const char* progName, const char* avdArch, const int force_32bit);
62bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turnerstatic char* getSharedLibraryPath(const char* progName, const char* libName);
63bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turnerstatic void  prependSharedLibraryPath(const char* prefix);
642d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner
657891dd35fa2439a70f43ab8572778a398365bf24David 'Digit' Turner/* The execv() definition in older mingw is slightly bogus.
66add001c9d30ef442e87ee18ec59342929401bd49David Turner * It takes a second argument of type 'const char* const*'
67add001c9d30ef442e87ee18ec59342929401bd49David Turner * while POSIX mandates char** instead.
68add001c9d30ef442e87ee18ec59342929401bd49David Turner *
69add001c9d30ef442e87ee18ec59342929401bd49David Turner * To avoid compiler warnings, define the safe_execv macro
70add001c9d30ef442e87ee18ec59342929401bd49David Turner * to perform an explicit cast with mingw.
71add001c9d30ef442e87ee18ec59342929401bd49David Turner */
727891dd35fa2439a70f43ab8572778a398365bf24David 'Digit' Turner#if defined(_WIN32) && !ANDROID_GCC_PREREQ(4,4)
73add001c9d30ef442e87ee18ec59342929401bd49David Turner#  define safe_execv(_filepath,_argv)  execv((_filepath),(const char* const*)(_argv))
74add001c9d30ef442e87ee18ec59342929401bd49David Turner#else
75add001c9d30ef442e87ee18ec59342929401bd49David Turner#  define safe_execv(_filepath,_argv)  execv((_filepath),(_argv))
76add001c9d30ef442e87ee18ec59342929401bd49David Turner#endif
77add001c9d30ef442e87ee18ec59342929401bd49David Turner
782d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner/* Main routine */
792d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turnerint main(int argc, char** argv)
802d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner{
812d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner    const char* avdName = NULL;
822d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner    char*       avdArch = NULL;
832d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner    char*       emulatorPath;
84ddd4ef7f7c8d07e95dc88ca897634f537666d5f3Andrew Hsieh    int         force_32bit = 0;
852d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner
862d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner    /* Define ANDROID_EMULATOR_DEBUG to 1 in your environment if you want to
872d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner     * see the debug messages from this launcher program.
882d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner     */
892d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner    const char* debug = getenv("ANDROID_EMULATOR_DEBUG");
902d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner
912d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner    if (debug != NULL && *debug && *debug != '0')
922d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner        android_verbose = 1;
932d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner
94ddd4ef7f7c8d07e95dc88ca897634f537666d5f3Andrew Hsieh    /* Parse command-line and look for
95ddd4ef7f7c8d07e95dc88ca897634f537666d5f3Andrew Hsieh     * 1) an avd name either in the form or '-avd <name>' or '@<name>'
96ddd4ef7f7c8d07e95dc88ca897634f537666d5f3Andrew Hsieh     * 2) '-force-32bit' which always use 32-bit emulator on 64-bit platforms
9701174a2daca341a893afa33988dd6129418f9dcfDavid 'Digit' Turner     * 3) '-verbose', or '-debug-all' or '-debug all' to enable verbose mode.
982d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner     */
992d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner    int  nn;
1002d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner    for (nn = 1; nn < argc; nn++) {
1012d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner        const char* opt = argv[nn];
1022d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner
1032d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner        if (!strcmp(opt,"-qemu"))
1042d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner            break;
1052d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner
10601174a2daca341a893afa33988dd6129418f9dcfDavid 'Digit' Turner        if (!strcmp(opt,"-verbose") || !strcmp(opt,"-debug-all")) {
10701174a2daca341a893afa33988dd6129418f9dcfDavid 'Digit' Turner            android_verbose = 1;
10801174a2daca341a893afa33988dd6129418f9dcfDavid 'Digit' Turner        }
10901174a2daca341a893afa33988dd6129418f9dcfDavid 'Digit' Turner
11001174a2daca341a893afa33988dd6129418f9dcfDavid 'Digit' Turner        if (!strcmp(opt,"-debug") && nn + 1 < argc &&
11101174a2daca341a893afa33988dd6129418f9dcfDavid 'Digit' Turner            !strcmp(argv[nn + 1], "all")) {
11201174a2daca341a893afa33988dd6129418f9dcfDavid 'Digit' Turner            android_verbose = 1;
11301174a2daca341a893afa33988dd6129418f9dcfDavid 'Digit' Turner        }
11401174a2daca341a893afa33988dd6129418f9dcfDavid 'Digit' Turner
115ddd4ef7f7c8d07e95dc88ca897634f537666d5f3Andrew Hsieh        if (!strcmp(opt,"-force-32bit")) {
116ddd4ef7f7c8d07e95dc88ca897634f537666d5f3Andrew Hsieh            force_32bit = 1;
117ddd4ef7f7c8d07e95dc88ca897634f537666d5f3Andrew Hsieh            continue;
1182d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner        }
119ddd4ef7f7c8d07e95dc88ca897634f537666d5f3Andrew Hsieh
120ddd4ef7f7c8d07e95dc88ca897634f537666d5f3Andrew Hsieh        if (!avdName) {
121ddd4ef7f7c8d07e95dc88ca897634f537666d5f3Andrew Hsieh            if (!strcmp(opt,"-avd") && nn+1 < argc) {
122ddd4ef7f7c8d07e95dc88ca897634f537666d5f3Andrew Hsieh                avdName = argv[nn+1];
123ddd4ef7f7c8d07e95dc88ca897634f537666d5f3Andrew Hsieh            }
124ddd4ef7f7c8d07e95dc88ca897634f537666d5f3Andrew Hsieh            else if (opt[0] == '@' && opt[1] != '\0') {
125ddd4ef7f7c8d07e95dc88ca897634f537666d5f3Andrew Hsieh                avdName = opt+1;
126ddd4ef7f7c8d07e95dc88ca897634f537666d5f3Andrew Hsieh            }
1272d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner        }
1282d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner    }
1292d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner
1302d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner    /* If there is an AVD name, we're going to extract its target architecture
1312d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner     * by looking at its config.ini
1322d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner     */
1332d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner    if (avdName != NULL) {
1342d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner        D("Found AVD name '%s'\n", avdName);
1352d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner        avdArch = path_getAvdTargetArch(avdName);
1362d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner        D("Found AVD target architecture: %s\n", avdArch);
1372d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner    } else {
1382d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner        /* Otherwise, using the ANDROID_PRODUCT_OUT directory */
1392d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner        const char* androidOut = getenv("ANDROID_PRODUCT_OUT");
1402d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner
1415ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner        if (androidOut != NULL) {
1422d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner            D("Found ANDROID_PRODUCT_OUT: %s\n", androidOut);
1432d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner            avdArch = path_getBuildTargetArch(androidOut);
144c005246ed03de874fdc432073ba8e5e8ebfed922David 'Digit' Turner            D("Found build target architecture: %s\n",
1455ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner              avdArch ? avdArch : "<NULL>");
1462d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner        }
1472d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner    }
1482d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner
1492d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner    if (avdArch == NULL) {
1502d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner        avdArch = "arm";
1512d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner        D("Can't determine target AVD architecture: defaulting to %s\n", avdArch);
1522d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner    }
1532d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner
1542d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner    /* Find the architecture-specific program in the same directory */
155ddd4ef7f7c8d07e95dc88ca897634f537666d5f3Andrew Hsieh    emulatorPath = getTargetEmulatorPath(argv[0], avdArch, force_32bit);
1562d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner    D("Found target-specific emulator binary: %s\n", emulatorPath);
1572d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner
1582d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner    /* Replace it in our command-line */
1592d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner    argv[0] = emulatorPath;
1602d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner
161bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner    /* We need to find the location of the GLES emulation shared libraries
162bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner     * and modify either LD_LIBRARY_PATH or PATH accordingly
163bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner     */
164bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner    {
165bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner        char*  sharedLibPath = getSharedLibraryPath(emulatorPath, GLES_EMULATION_LIB);
166bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner
1679554550a3ecf2987af84d98d4b683757c74d8b93David 'Digit' Turner        if (!sharedLibPath) {
1689554550a3ecf2987af84d98d4b683757c74d8b93David 'Digit' Turner            // Sometimes, only the 64-bit libraries are available, for example
1699554550a3ecf2987af84d98d4b683757c74d8b93David 'Digit' Turner            // when storing binaries under $AOSP/prebuilts/android-emulator/<system>/
1709554550a3ecf2987af84d98d4b683757c74d8b93David 'Digit' Turner            sharedLibPath = getSharedLibraryPath(emulatorPath, GLES_EMULATION_LIB64);
1719554550a3ecf2987af84d98d4b683757c74d8b93David 'Digit' Turner        }
1729554550a3ecf2987af84d98d4b683757c74d8b93David 'Digit' Turner
173bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner        if (sharedLibPath != NULL) {
174bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner            D("Found OpenGLES emulation libraries in %s\n", sharedLibPath);
175bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner            prependSharedLibraryPath(sharedLibPath);
176bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner        } else {
177bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner            D("Could not find OpenGLES emulation host libraries!\n");
178bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner        }
179bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner    }
180bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner
18160d0a1536e4e75cee039c09da65a2e994be2e106David 'Digit' Turner#ifdef _WIN32
18260d0a1536e4e75cee039c09da65a2e994be2e106David 'Digit' Turner    // Take care of quoting all parameters before sending them to execv().
18360d0a1536e4e75cee039c09da65a2e994be2e106David 'Digit' Turner    // See the "Eveyone quotes command line arguments the wrong way" on
18460d0a1536e4e75cee039c09da65a2e994be2e106David 'Digit' Turner    // MSDN.
18560d0a1536e4e75cee039c09da65a2e994be2e106David 'Digit' Turner    int n;
18660d0a1536e4e75cee039c09da65a2e994be2e106David 'Digit' Turner    for (n = 0; n < argc; ++n) {
18760d0a1536e4e75cee039c09da65a2e994be2e106David 'Digit' Turner        // Technically, this leaks the quoted strings, but we don't care
18860d0a1536e4e75cee039c09da65a2e994be2e106David 'Digit' Turner        // since this process will terminate after the execv() anyway.
18960d0a1536e4e75cee039c09da65a2e994be2e106David 'Digit' Turner        argv[n] = win32_cmdline_quote(argv[n]);
19060d0a1536e4e75cee039c09da65a2e994be2e106David 'Digit' Turner        D("Quoted param: [%s]\n", argv[n]);
19160d0a1536e4e75cee039c09da65a2e994be2e106David 'Digit' Turner    }
19260d0a1536e4e75cee039c09da65a2e994be2e106David 'Digit' Turner#endif
19360d0a1536e4e75cee039c09da65a2e994be2e106David 'Digit' Turner
19460d0a1536e4e75cee039c09da65a2e994be2e106David 'Digit' Turner    // Launch it with the same set of options !
19560d0a1536e4e75cee039c09da65a2e994be2e106David 'Digit' Turner    // Note that on Windows, the first argument must _not_ be quoted or
19660d0a1536e4e75cee039c09da65a2e994be2e106David 'Digit' Turner    // Windows will fail to find the program.
197add001c9d30ef442e87ee18ec59342929401bd49David Turner    safe_execv(emulatorPath, argv);
1982d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner
1992d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner    /* We could not launch the program ! */
2002d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner    fprintf(stderr, "Could not launch '%s': %s\n", emulatorPath, strerror(errno));
2012d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner    return errno;
2022d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner}
2032d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner
2040cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner/* Probe the filesystem to check if an emulator executable named like
2050cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner * <progDir>/<prefix><arch> exists.
2060cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner *
2070cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner * |progDir| is an optional program directory. If NULL, the executable
2080cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner * will be searched in the current directory.
2090cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner * |archSuffix| is an architecture-specific suffix, like "arm", or 'x86"
2100cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner * If |search_for_64bit_emulator| is true, lookup for 64-bit emulator first,
2110cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner * then the 32-bit version.
2120cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner * If |try_current_path|, try to look into the current path if no
2130cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner * executable was found under |progDir|.
2140cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner * On success, returns the path of the executable (string must be freed by
2150cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner * the caller). On failure, return NULL.
2162d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner */
2172d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turnerstatic char*
2180cadcd089dafa412543773c695e10936c9d796a4David 'Digit' TurnerprobeTargetEmulatorPath(const char* progDir,
2190cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner                        const char* archSuffix,
2200cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner                        bool search_for_64bit_emulator,
2210cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner                        bool try_current_path)
2222d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner{
2230cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    char path[PATH_MAX], *pathEnd = path + sizeof(path), *p;
2240cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner
2250cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    static const char kEmulatorPrefix[] = "emulator-";
2260cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    static const char kEmulator64Prefix[] = "emulator64-";
2272d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner#ifdef _WIN32
2280cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    const char kExeExtension[] = ".exe";
2292d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner#else
2300cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    const char kExeExtension[] = "";
2312d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner#endif
2322d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner
2330cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    // First search for the 64-bit emulator binary.
234ddd4ef7f7c8d07e95dc88ca897634f537666d5f3Andrew Hsieh    if (search_for_64bit_emulator) {
2350cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner        p = path;
2360cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner        if (progDir) {
2370cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner            p = bufprint(p, pathEnd, "%s/", progDir);
238c7389bd69e570a2c8432b37399aff1976b021f0fAndrew Hsieh        }
2390cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner        p = bufprint(p, pathEnd, "%s%s%s", kEmulator64Prefix,
2400cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner                        archSuffix, kExeExtension);
2410cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner        D("Probing program: %s\n", path);
2420cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner        if (p < pathEnd && path_exists(path)) {
243c7389bd69e570a2c8432b37399aff1976b021f0fAndrew Hsieh            return strdup(path);
244c7389bd69e570a2c8432b37399aff1976b021f0fAndrew Hsieh        }
245c7389bd69e570a2c8432b37399aff1976b021f0fAndrew Hsieh    }
246c7389bd69e570a2c8432b37399aff1976b021f0fAndrew Hsieh
2470cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    // Then for the 32-bit one.
2480cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    p = path;
2490cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    if (progDir) {
2500cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner        p = bufprint(p, pathEnd, "%s/", progDir);
2512d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner    }
2520cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    p = bufprint(p, pathEnd, "%s%s%s", kEmulatorPrefix,
2530cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner                    archSuffix, kExeExtension);
2540cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    D("Probing program: %s\n", path);
2550cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    if (p < pathEnd && path_exists(path)) {
256c7389bd69e570a2c8432b37399aff1976b021f0fAndrew Hsieh        return strdup(path);
2572d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner    }
2582d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner
2590cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    // Not found, try in the current path then
2600cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    if (try_current_path) {
2610cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner        char* result;
2620cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner
263ddd4ef7f7c8d07e95dc88ca897634f537666d5f3Andrew Hsieh        if (search_for_64bit_emulator) {
2640cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner            p = bufprint(path, pathEnd, "%s%s%s", kEmulator64Prefix,
2650cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner                          archSuffix, kExeExtension);
2660cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner            if (p < pathEnd) {
2670cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner                D("Probing path for: %s\n", path);
2680cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner                result = path_search_exec(path);
2690cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner                if (result) {
2700cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner                    return result;
2710cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner                }
2720cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner            }
273c7389bd69e570a2c8432b37399aff1976b021f0fAndrew Hsieh        }
274c7389bd69e570a2c8432b37399aff1976b021f0fAndrew Hsieh
2750cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner        p = bufprint(path, pathEnd, "%s%s%s", kEmulatorPrefix,
2760cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner                      archSuffix, kExeExtension);
277c7389bd69e570a2c8432b37399aff1976b021f0fAndrew Hsieh        if (p < pathEnd) {
2780cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner            D("Probing path for: %s\n", path);
2790cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner            result = path_search_exec(path);
2800cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner            if (result) {
2810cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner                return result;
2820cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner            }
2830cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner        }
2840cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    }
2850cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner
2860cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    return NULL;
2870cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner}
2880cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner
2890cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turnerstatic char*
2900cadcd089dafa412543773c695e10936c9d796a4David 'Digit' TurnergetTargetEmulatorPath(const char* progName,
2910cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner                      const char* avdArch,
2920cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner                      const int force_32bit)
2930cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner{
2940cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    char*  progDir;
2950cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    char*  result;
2960cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner#ifdef _WIN32
2970cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    /* TODO: currently amd64-mingw32msvc-gcc doesn't work which prevents
2980cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner             generating 64-bit binaries for Windows */
2990cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    bool search_for_64bit_emulator = false;
3000cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner#else
3010cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    bool search_for_64bit_emulator =
3020cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner            !force_32bit && android_getHostBitness() == 64;
3030cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner#endif
3040cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner
3050cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    /* Only search in current path if there is no directory separator
3060cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner     * in |progName|. */
3070cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner#ifdef _WIN32
3080cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    bool try_current_path =
3090cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner            (!strchr(progName, '/') && !strchr(progName, '\\'));
3100cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner#else
3110cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    bool try_current_path = !strchr(progName, '/');
3120cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner#endif
3130cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner
3140cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    /* Get program's directory name in progDir */
3150cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    path_split(progName, &progDir, NULL);
3160cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner
3170cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    const char* emulatorSuffix;
3180cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner
3190cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    // Special case: for x86_64, first try to find emulator-x86_64 before
3200cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    // looking for emulator-x86.
3210cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    if (!strcmp(avdArch, "x86_64")) {
3220cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner        emulatorSuffix = "x86_64";
3230cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner
3240cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner        D("Looking for emulator backend for %s CPU\n", avdArch);
3250cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner
3260cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner        result = probeTargetEmulatorPath(progDir,
3270cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner                                         emulatorSuffix,
3280cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner                                         search_for_64bit_emulator,
3297654e7efee943bdbaf167170a087388c54681366David 'Digit' Turner                                         try_current_path);
3307654e7efee943bdbaf167170a087388c54681366David 'Digit' Turner        if (result) {
3317654e7efee943bdbaf167170a087388c54681366David 'Digit' Turner            return result;
3327654e7efee943bdbaf167170a087388c54681366David 'Digit' Turner        }
3337654e7efee943bdbaf167170a087388c54681366David 'Digit' Turner    }
3347654e7efee943bdbaf167170a087388c54681366David 'Digit' Turner
3357654e7efee943bdbaf167170a087388c54681366David 'Digit' Turner    // Special case: for arm64, first try to find emulator-arm64 before
3367654e7efee943bdbaf167170a087388c54681366David 'Digit' Turner    // looking for emulator-arm.
3377654e7efee943bdbaf167170a087388c54681366David 'Digit' Turner    if (!strcmp(avdArch, "arm64")) {
3387654e7efee943bdbaf167170a087388c54681366David 'Digit' Turner        emulatorSuffix = "arm64";
3397654e7efee943bdbaf167170a087388c54681366David 'Digit' Turner
3407654e7efee943bdbaf167170a087388c54681366David 'Digit' Turner        D("Looking for emulator backend for %s CPU\n", avdArch);
3417654e7efee943bdbaf167170a087388c54681366David 'Digit' Turner
3427654e7efee943bdbaf167170a087388c54681366David 'Digit' Turner        result = probeTargetEmulatorPath(progDir,
3437654e7efee943bdbaf167170a087388c54681366David 'Digit' Turner                                         emulatorSuffix,
3447654e7efee943bdbaf167170a087388c54681366David 'Digit' Turner                                         search_for_64bit_emulator,
3450cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner                                         try_current_path);
3460cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner        if (result) {
3470cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner            return result;
3482d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner        }
3492d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner    }
3502d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner
3510cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    // Now for the regular case.
3520cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    emulatorSuffix = emulator_getBackendSuffix(avdArch);
3530cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    if (!emulatorSuffix) {
3540cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner        APANIC("This emulator cannot emulate %s CPUs!\n", avdArch);
3550cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    }
3560cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    D("Looking for emulator-%s to emulate '%s' CPU\n", emulatorSuffix,
3570cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner      avdArch);
3580cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner
3590cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    result = probeTargetEmulatorPath(progDir,
3600cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner                                     emulatorSuffix,
3610cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner                                     search_for_64bit_emulator,
3620cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner                                     try_current_path);
3630cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    if (result) {
3640cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner        return result;
3650cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    }
3660cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner
3672d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner    /* Otherwise, the program is missing */
3680cadcd089dafa412543773c695e10936c9d796a4David 'Digit' Turner    APANIC("Missing emulator engine program for '%s' CPUS.\n", avdArch);
3692d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner    return NULL;
3702d238fd9871687b1557f15b8878a6cf3e9634b57David 'Digit' Turner}
371add001c9d30ef442e87ee18ec59342929401bd49David Turner
372bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner/* return 1 iff <path>/<filename> exists */
373bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turnerstatic int
374bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' TurnerprobePathForFile(const char* path, const char* filename)
375bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner{
376bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner    char  temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
377bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner    p = bufprint(temp, end, "%s/%s", path, filename);
378bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner    D("Probing for: %s\n", temp);
379bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner    return (p < end && path_exists(temp));
380bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner}
381bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner
382bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner/* Find the directory containing a given shared library required by the
383bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner * emulator (for GLES emulation). We will probe several directories
384bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner * that correspond to various use-cases.
385bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner *
386bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner * Caller must free() result string. NULL if not found.
387bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner */
388bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner
389bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turnerstatic char*
390bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' TurnergetSharedLibraryPath(const char* progName, const char* libName)
391bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner{
392bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner    char* progDir;
393bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner    char* result = NULL;
394bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner    char  temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
395bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner
396bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner    /* Get program's directory name */
397bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner    path_split(progName, &progDir, NULL);
398bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner
399bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner    /* First, try to probe the program's directory itself, this corresponds
400bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner     * to the standalone build with ./android-configure.sh where the script
401bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner     * will copy the host shared library under external/qemu/objs where
402bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner     * the binaries are located.
403bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner     */
404bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner    if (probePathForFile(progDir, libName)) {
405bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner        return progDir;
406bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner    }
407bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner
408bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner    /* Try under $progDir/lib/, this should correspond to the SDK installation
409bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner     * where the binary is under tools/, and the libraries under tools/lib/
410bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner     */
411bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner    {
412bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner        p = bufprint(temp, end, "%s/lib", progDir);
413bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner        if (p < end && probePathForFile(temp, libName)) {
414bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner            result = strdup(temp);
415bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner            goto EXIT;
416bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner        }
417bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner    }
418bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner
419bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner    /* try in $progDir/../lib, this corresponds to the platform build
420c7389bd69e570a2c8432b37399aff1976b021f0fAndrew Hsieh     * where the emulator binary is under out/host/<system>/bin and
421bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner     * the libraries are under out/host/<system>/lib
422bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner     */
423bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner    {
424bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner        char* parentDir = path_parent(progDir, 1);
425bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner
426bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner        if (parentDir == NULL) {
427bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner            parentDir = strdup(".");
428bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner        }
429bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner        p = bufprint(temp, end, "%s/lib", parentDir);
430bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner        free(parentDir);
431bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner        if (p < end && probePathForFile(temp, libName)) {
432bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner            result = strdup(temp);
433bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner            goto EXIT;
434bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner        }
435bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner    }
436bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner
437bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner    /* Nothing found! */
438bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' TurnerEXIT:
439bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner    free(progDir);
440bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner    return result;
441bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner}
442bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner
443bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner/* Prepend the path in 'prefix' to either LD_LIBRARY_PATH or PATH to
444bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner * ensure that the shared libraries inside the path will be available
445bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner * through dlopen() to the emulator program being launched.
446bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner */
447bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turnerstatic void
448bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' TurnerprependSharedLibraryPath(const char* prefix)
449bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner{
4505ed60d1e0865d948f3e7bba38c98bcfbb58fc24bJesse Hall    size_t len = 0;
4515ed60d1e0865d948f3e7bba38c98bcfbb58fc24bJesse Hall    char *temp = NULL;
4525ed60d1e0865d948f3e7bba38c98bcfbb58fc24bJesse Hall    const char* path = NULL;
4535ed60d1e0865d948f3e7bba38c98bcfbb58fc24bJesse Hall
454bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner#ifdef _WIN32
4555ed60d1e0865d948f3e7bba38c98bcfbb58fc24bJesse Hall    path = getenv("PATH");
4565ed60d1e0865d948f3e7bba38c98bcfbb58fc24bJesse Hall#else
4575ed60d1e0865d948f3e7bba38c98bcfbb58fc24bJesse Hall    path = getenv("LD_LIBRARY_PATH");
4585ed60d1e0865d948f3e7bba38c98bcfbb58fc24bJesse Hall#endif
4595ed60d1e0865d948f3e7bba38c98bcfbb58fc24bJesse Hall
4605ed60d1e0865d948f3e7bba38c98bcfbb58fc24bJesse Hall    /* Will need up to 7 extra characters: "PATH=", ';' or ':', and '\0' */
4615ed60d1e0865d948f3e7bba38c98bcfbb58fc24bJesse Hall    len = 7 + strlen(prefix) + (path ? strlen(path) : 0);
4625ed60d1e0865d948f3e7bba38c98bcfbb58fc24bJesse Hall    temp = malloc(len);
4635ed60d1e0865d948f3e7bba38c98bcfbb58fc24bJesse Hall    if (!temp)
4645ed60d1e0865d948f3e7bba38c98bcfbb58fc24bJesse Hall        return;
4655ed60d1e0865d948f3e7bba38c98bcfbb58fc24bJesse Hall
4665ed60d1e0865d948f3e7bba38c98bcfbb58fc24bJesse Hall    if (path && path[0] != '\0') {
4675ed60d1e0865d948f3e7bba38c98bcfbb58fc24bJesse Hall#ifdef _WIN32
4685ed60d1e0865d948f3e7bba38c98bcfbb58fc24bJesse Hall        bufprint(temp, temp + len, "PATH=%s;%s", prefix, path);
4695ed60d1e0865d948f3e7bba38c98bcfbb58fc24bJesse Hall#else
4705ed60d1e0865d948f3e7bba38c98bcfbb58fc24bJesse Hall        bufprint(temp, temp + len, "%s:%s", prefix, path);
4715ed60d1e0865d948f3e7bba38c98bcfbb58fc24bJesse Hall#endif
472bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner    } else {
4735ed60d1e0865d948f3e7bba38c98bcfbb58fc24bJesse Hall#ifdef _WIN32
4745ed60d1e0865d948f3e7bba38c98bcfbb58fc24bJesse Hall        bufprint(temp, temp + len, "PATH=%s", prefix);
4755ed60d1e0865d948f3e7bba38c98bcfbb58fc24bJesse Hall#else
4765ed60d1e0865d948f3e7bba38c98bcfbb58fc24bJesse Hall        strcpy(temp, prefix);
4775ed60d1e0865d948f3e7bba38c98bcfbb58fc24bJesse Hall#endif
478bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner    }
4795ed60d1e0865d948f3e7bba38c98bcfbb58fc24bJesse Hall
4805ed60d1e0865d948f3e7bba38c98bcfbb58fc24bJesse Hall#ifdef _WIN32
481bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner    D("Setting %s\n", temp);
482dca64d13258f05ec3385403a99eff7da4773ce24David 'Digit' Turner    putenv(strdup(temp));
483bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner#else
4845ed60d1e0865d948f3e7bba38c98bcfbb58fc24bJesse Hall    D("Setting LD_LIBRARY_PATH=%s\n", temp);
4855ed60d1e0865d948f3e7bba38c98bcfbb58fc24bJesse Hall    setenv("LD_LIBRARY_PATH", temp, 1);
486bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner#endif
487bfcfa46044116a54ebe11ee2881142fd38a87939David 'Digit' Turner}
488