Finding current executable's path without /proc/self/exe

前端 未结 13 1025
有刺的猬
有刺的猬 2020-11-22 01:06

It seems to me that Linux has it easy with /proc/self/exe. But I\'d like to know if there is a convenient way to find the current application\'s directory in C/C++ with cros

13条回答
  •  醉梦人生
    2020-11-22 01:35

    Making this work reliably across platforms requires using #ifdef statements.

    The below code finds the executable's path in Windows, Linux, MacOS, Solaris or FreeBSD (although FreeBSD is untested). It uses boost>=1.55.0 to simplify the code but it's easy enough to remove if you want. Just use defines like _MSC_VER and __linux as the OS and compiler require.

    #include 
    #include 
    
    #if (BOOST_OS_WINDOWS)
    #  include 
    #elif (BOOST_OS_SOLARIS)
    #  include 
    #  include 
    #elif (BOOST_OS_LINUX)
    #  include 
    #  include 
    #elif (BOOST_OS_MACOS)
    #  include 
    #elif (BOOST_OS_BSD_FREE)
    #  include 
    #  include 
    #endif
    
    /*
     * Returns the full path to the currently running executable,
     * or an empty string in case of failure.
     */
    std::string getExecutablePath() {
    #if (BOOST_OS_WINDOWS)
        char *exePath;
        if (_get_pgmptr(&exePath) != 0)
            exePath = "";
    #elif (BOOST_OS_SOLARIS)
        char exePath[PATH_MAX];
        if (realpath(getexecname(), exePath) == NULL)
            exePath[0] = '\0';
    #elif (BOOST_OS_LINUX)
        char exePath[PATH_MAX];
        ssize_t len = ::readlink("/proc/self/exe", exePath, sizeof(exePath));
        if (len == -1 || len == sizeof(exePath))
            len = 0;
        exePath[len] = '\0';
    #elif (BOOST_OS_MACOS)
        char exePath[PATH_MAX];
        uint32_t len = sizeof(exePath);
        if (_NSGetExecutablePath(exePath, &len) != 0) {
            exePath[0] = '\0'; // buffer too small (!)
        } else {
            // resolve symlinks, ., .. if possible
            char *canonicalPath = realpath(exePath, NULL);
            if (canonicalPath != NULL) {
                strncpy(exePath,canonicalPath,len);
                free(canonicalPath);
            }
        }
    #elif (BOOST_OS_BSD_FREE)
        char exePath[2048];
        int mib[4];  mib[0] = CTL_KERN;  mib[1] = KERN_PROC;  mib[2] = KERN_PROC_PATHNAME;  mib[3] = -1;
        size_t len = sizeof(exePath);
        if (sysctl(mib, 4, exePath, &len, NULL, 0) != 0)
            exePath[0] = '\0';
    #endif
        return std::string(exePath);
    }
    

    The above version returns full paths including the executable name. If instead you want the path without the executable name, #include boost/filesystem.hpp> and change the return statement to:

    return strlen(exePath)>0 ? boost::filesystem::path(exePath).remove_filename().make_preferred().string() : std::string();
    

提交回复
热议问题