二进制文件的相对路径

Relative paths from binary file

我有以下文件夹结构:

bin/ <-binary-file is in here
include/
src/
data/
Makefile

在我的代码中,我使用数据的相对路径。所以“../data/xml/xmlFile.xml”。如果我从 bin/ 文件夹中执行二进制文件,这很好:

brandonto@computer:~/PATH-TO-PROJECT/bin$ ./binary-file 
argv[0] = ./binary-file
dirname(argv[0]) = .

但是如果我从主文件夹(或不是 bin/ 文件夹的任何其他文件夹)执行二进制文件:

brandonto@computer:~/PATH-TO-PROJECT$ bin/binary-file 
argv[0] = bin/binary-file
dirname(argv[0]) = bin

找不到 xml 文件,因为“../data”现在会从主文件夹(或执行程序时所在的任何文件夹)上升到一个目录。

我怎样才能使二进制文件可以从我系统上的任何目录执行?

为了让问题更清楚一点:

brandonto@brandonto-Aspire-S3-391:~/cpp-workspace/sdl-projects/sdl-space-shooter/bin$ ~/cpp-workspace/sdl-projects/sdl-space-shooter/bin/SpaceShooter 
argv[0] = /home/brandonto/cpp-workspace/sdl-projects/sdl-space-shooter/bin/SpaceShooter
dirname(argv[0]) = /home/brandonto/cpp-workspace/sdl-projects/sdl-space-shooter/bin

brandonto@brandonto-Aspire-S3-391:~/cpp-workspace/sdl-projects/sdl-space-shooter/bin$ cd ..
brandonto@brandonto-Aspire-S3-391:~/cpp-workspace/sdl-projects/sdl-space-shooter$ ~/cpp-workspace/sdl-projects/sdl-space-shooter/bin/SpaceShooter 
argv[0] = /home/brandonto/cpp-workspace/sdl-projects/sdl-space-shooter/bin/SpaceShooter
dirname(argv[0]) = /home/brandonto/cpp-workspace/sdl-projects/sdl-space-shooter/bin
Unable to load image ../data/graphics/background/darkPurple.png! SDL_image Error: Couldn't open ../data/graphics/background/darkPurple.png
Unable to load image ../data/graphics/sprites/meteorBrown_big1.png! SDL_image Error: Couldn't open ../data/graphics/sprites/meteorBrown_big1.png

在这里,我从 bin/ 文件夹中执行一次二进制文件,然后从主文件夹中执行一次。二进制文件 运行 在 bin/ 文件夹中很好,但无法从主文件夹中找到 .png 文件的相对路径。

我相信您可以使用 getpid 命令找到您的进程 ID (pid),并以类似于 this question 的方式执行提取目录的功能 Ubuntu。

我会让数据以某种方式(有组织地)与可执行文件所在的 bin 目录相关联。

然后,当运行例程时,如果提供了完整路径(通过检查arg[0]注明),则可以找到数据目录。如果提供了相对路径,则依次搜索搜索路径,直到找到可执行文件,然后就可以找到数据目录。

不需要 pid。 (我认为这就是 Python 找到它的方式,或者至少它过去是如何找到它的方式。)

你可能问错了问题:构建系统与程序执行无关。

但是,如果您要寻找答案,如何让我的程序正确使用相对于程序安装定位的数据,那么这里就是答案。

当您的程序 main 被执行时,它会获取二进制路径作为第一个参数(索引 0)。该路径可以是相对路径或绝对路径,但无论如何它都可以让您找到 base 目录。

这些也是有用的链接:

  • How do I find the location of the executable in C?
  • Finding current executable's path without /proc/self/exe

在这里你可以如何使用第一个参数:

#include <linux/limits.h>
#include <stdio.h>
#include <string.h>
#include <libgen.h>

int main(int argc, char *argv[])
{
  char datadir[PATH_MAX];
  strncpy(datadir, argv[0], sizeof(datadir));
  dirname(datadir);
  strncat(datadir, "/../data", sizeof(datadir));

  printf("Data dir: %s\n", datadir);

  return 0;
}

我一般都是通过程序设置来解决这个问题。在过去的美好时光里,我会将这些设置放在可执行文件附带的 .ini 文件中。一些设置可以在程序中配置,所有设置都可以使用文本编辑器进行编辑。如果文件丢失或任何设置丢失,它们将默认创建。

对于程序数据的位置,我会使用它的完整绝对路径名。例如它可能是

Datapath = D:\os50k

然后程序会根据需要将各个文件名附加到路径中。

这些天在 Windows 系统注册表用于此目的。但是,您的问题被标记为 Linux,它将设置存储在各个地方,包括程序目录。

This question, and this question 更全面地描述过程。

如果您的路径可以在构建时确定(即您的项目永远不需要安装到另一个目录),您可以通过构建系统将路径作为预处理器定义注入。这是 CMake 的示例:

file(TO_CMAKE_PATH "${PROJECT_BINARY_DIR}/resources" RESOURCE_DIR) # Normalize Windows/Linux paths
add_custom_command(
    TARGET my_target POST_BUILD
    COMMAND ${CMAKE_COMMAND} ARGS -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/resources ${RESOURCE_DIR}
)
target_compile_definitions(my_target PUBLIC RESOURCE_DIR=${RESOURCE_DIR})

.

#define VAL(x) #x
#define STR(x) VAL(x)
const char* my_resource = STR(RESOURCE_DIR) "/my_resource.abc";