首页 > 解决方案 > C++:无法读取 macOS 包中的资源文件

问题描述

背景:

我正在编写一个“Hello Rectangle”OpenGL 应用程序。我希望它是独立.app的,而不仅仅是“UNIX 可执行文件”。代码从 Terminal.app 运行良好。

我没有使用 Xcode;我的磁盘空间非常紧张,而且我没有做 iOS 开发。相反,我使用的是 brewed 工具链,包括gcc-8,glfwglew.

我根据这个SO 问题构建了我的发布目录,如下所示:

Contents
├── Frameworks
│   ├── libGLEW.2.1.dylib
│   ├── libgcc_s.1.dylib
│   ├── libglfw.3.dylib
│   └── libstdc++.6.dylib
├── MacOS
│   ├── hello-rect    <- the actual binary
│   └── launcher.sh   <- entry wrapper for working dir as the above link suggests
├── Resources
│   ├── rect.frag
│   └── rect.vert
└── Info.plist

我还在二进制文件中修改了对 dylibs 的引用。但它不会运行。

经过几个小时的谷歌搜索,这个SO 答案和这个SO问题以及其他几个问题让我确信我应该使用.CoreFoundationResources

问题:

我尝试了以下代码(从上面的链接粘贴并稍作修改),但它得到了段错误:

const char* textFileReadCF(const char *&filename){
  // Get a reference to the main bundle
  CFBundleRef mainBundle = CFBundleGetMainBundle();

  // Get a reference to the file's URL
  CFStringRef filenameHandle = CFStringRef(filename);

  // ------ segfault 11 here ------
  CFURLRef fileURL = CFBundleCopyResourceURL(mainBundle, filenameHandle, NULL, NULL);

  // Convert the URL reference into a string reference
  CFStringRef filePath = CFURLCopyFileSystemPath(fileURL, kCFURLPOSIXPathStyle);

  // Get the system encoding method
  CFStringEncoding encodingMethod = CFStringGetSystemEncoding();

  // Convert the string reference into a C string
  const char *path = CFStringGetCStringPtr(filePath, encodingMethod);
  
  // the real read function, read in file and returns all as a big char* arr
  return textFileRead(path);
}

// this runs fine before packing and I didn't change, 
// just for the sake of completeness
const char *textFileRead(const char *filename){
  std::ifstream shaderFile(filename);
  std::ostringstream shaderBuffer;
  shaderBuffer << shaderFile.rdbuf();
  std::string shaderBufferStr = shaderBuffer.str();
  // Warning: safe only until shaderBufferStr is destroyed or modified
  char * ret = new char[shaderBufferStr.size()];
  std::strcpy(ret, shaderBufferStr.c_str());
  return ret;
}

textFileReadCF将用"rect.vert"and调用两次"rect.vert"(不是字面意思,而是const char*持有它们)。

我不知道为什么会出现段错误。我确保有一个mainBundle通过assert(省略),据我所知这filenameHandle是有效的,但除此之外我不知道去哪里找。

标签: macosopenglcore-foundation

解决方案


原来我不需要CoreFoundation。我只是需要GLFW

在早期版本中,我的发布目录如下所示:

Contents
├── Frameworks
│   ├── libGLEW.2.1.dylib
│   ├── libgcc_s.1.dylib
│   ├── libglfw.3.dylib
│   └── libstdc++.6.dylib
├── MacOS
│   ├── hello-rect    <- the actual binary
│   ├── launcher.sh   <- entry wrapper for working dir as the above link suggests
│   ├── rect.frag
│   └── rect.vert
└── Info.plist

因为未捆绑的版本显然看起来无处可去cwd。我什至不知道有Resources。当时我的代码也没有运行;我的谷歌跟踪让我相信这CoreFoundation是解决方案。直到我检查了文档,CoreFoundation我才知道应该有Resources. 当所有的点都连接在一起时,我只是偶然遇到了这个SO question 。

显然我的版本GLFW也表现得像链接状态:(直接来自源)

// 切换到我们的应用程序包的资源目录,如果存在的话

因此,使捆绑包开箱即用所需要做的就是,像讨论的那样构造发布目录,然后直接textFileRead使用"rect.vert"and调用"rect.vert",我们都准备好了。


推荐阅读