windows和ubuntu下c++编译的库文件获取运行时自身所在路径的异同
很多时候我们需要使用自己编写的库文件,而这些库文件可能也依赖于某些文件,需要在运行时加载。
在主程序调用库文件时,主程序所在路径才是当前的工作路径,所以很多时候库文件加载需要的文件放在主程序所在路径下,这样默认才能加载成功。
但有时为了便于区分,我们会把库文件放在单独的目录下,而其所依赖的文件仍然放在主程序目录下,这样会显得不便。
若把依赖文件放在库文件同目录下,那么在库文件编写时,必须确定主程序和库文件的目录关系才能找到这些文件,显然因为库文件是要复用的,在不同的主程序中使用很可能是不同的,
因此固定这种关系是不方便的。那么有没有办法来解决这个问题呢?关键是要能够在运行时调用库文件时能够获取库文件所在的路径。
1. 基本思路
如果能够在程序运行时确定被加载的库文件的绝对路径,并且把其所依赖的文件放到库文件同目录下,那么我们便可以利用这个路径来为库文件中的函数指定依赖的路径,从而能够准确的找到所依赖的文件。
要确定库文件加载时自身所在的路径,依赖于系统的支持,所以不同的系统下是不同的。
所以我们讨论一下windows下和ubuntu下程序运行时确定库文件自身所在路径方法的不同。
2. windows下程序运行时确定库文件自身路径
windows下程序运行时获取程序获取执行程序和调用的dll文件的路径,使用下面这两个头文件:
#include <dir.h>
#include <Windows.h>
确定主程序的路径的函数为:
char curpwd[100];
getcwd(curpwd, 100);
string filedir(curpwd);//获取当前执行程序的路径
确定调用的dll的路径函数为:
HMODULE GetCurrentModule(BOOL bRef) // = FALSE,参数用false
{
HMODULE hModule = NULL;
if (GetModuleHandleEx(bRef ? GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS : (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
| GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT), (LPCSTR)GetCurrentModule, &hModule))
{
return hModule;
}
return NULL;
}
//获取程序、模块所在路径
string GetProgramDir()
{
char exeFullPath[MAX_PATH]; // Full path
string strPath = "";
GetModuleFileName(GetCurrentModule(false),exeFullPath,MAX_PATH);
strPath=(string)exeFullPath; // Get full path of the file
int pos = strPath.find_last_of('\\', strPath.length());
return strPath.substr(0, pos); // Return the directory without the file name
}
string filename;
filedir=GetProgramDir();//获取当前so所在的路径
具体解释可以参考后面的参考文献。
3. ubuntu下程序运行时确定库文件自身路径
ubuntu下与windows下的方法存在不同,首先是依赖的头文件不同为:
#include "unistd.h"
#include <dlfcn.h>
获取主程序路径的函数相同:
char curpwd[100];
getcwd(curpwd, 100);
string filedir(curpwd);//获取当前执行程序的路径
库文件路径的获取函数则存在不同:
//
//for linux
//
static void empty_dladdr()
{
//
}
string GetProgramDir()
{
Dl_info dl_info;
dladdr((void*)empty_dladdr, &dl_info);
string strPath = (string)dl_info.dli_fname;
int pathlen=strPath.length()-14; //#here 14 is the length of /libwinrate.so
return strPath.substr(0,pathlen);
}
string filename;
filedir=GetProgramDir();//获取当前so所在的路径
printf("dllpwd: %s...\n",filedir.c_str());
//windows
//filename=filedir+"\\HandRanks.dat";
//linux
filename=filedir+"/HandRanks.dat";
需要注意的是windows下和ubuntu下分割路径的符号是不同的。
具体解释可以参考后面的参考文献。
4. 两个系统下的差异
差异项 | windows | ubuntu |
---|---|---|
头文件依赖 | dir.h | unistd.h |
头文件依赖 | windows.h | dlfcn.h |
依赖函数 | GetModuleFileName | dl_info |
小结
本文根据前人的知识比较了一下windows下和ubuntu下程序运行时获取库文件自身路径的异同,算是一个梳理性总结,为不同系统下的程序迁移提供帮助。
参考文献:
- https://www.cnblogs.com/findumars/p/5936702.html
- https://blog.csdn.net/jiangqin115/article/details/45312773
- https://quantum6.blog.csdn.net/article/details/105795550?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1.pc_relevant_paycolumn_v3&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1.pc_relevant_paycolumn_v3&utm_relevant_index=2
- https://blog.csdn.net/buknow/article/details/89407519?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1.pc_relevant_aa&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1.pc_relevant_aa&utm_relevant_index=1
- https://stackoverflow.com/questions/1681060/library-path-when-dynamically-loaded