什么聪明的解决方案在静态库中包含资源?

时间:2011-08-04 17:27:12

标签: objective-c ios opengl-es static-libraries

我有一个静态库Xcode 4项目,其中包含一个自制的渲染引擎,我在多个应用程序中重用了这个引擎。该引擎使用OpenGL ES 2.0,并通过扩展,使用着色器。随着着色器变得更加复杂,我不再将它们作为NSStrings存储在源文件中,现在将它们存储为具有.vert和.frag扩展名的独立文本文件。

这适用于在自己的源中包含渲染引擎的应用程序;着色器只是添加到应用程序的“复制包资源”构建阶段,并在运行时加载到NSStrings并编译,链接等。

如果加载这些着色器的渲染引擎位于静态库项目中,则此策略根本不起作用;没有可以复制资源的包。我目前不得不让静态lib渲染引擎的每个客户端项目都在他们自己的“Copy Bundle Resources”构建阶段包含他们自己的着色器副本。这是一个巨大的痛苦,并且首先打破了将渲染引擎变成静态库的大部分便利。

我想这是“静态库中的资源”这个更一般问题的特定实例。我能想到的最佳解决方案是将着色器文件的内容复制到头文件中的字符串中,然后将其包含在呈现引擎的源代码中。我甚至可以通过一些“运行脚本”构建阶段魔术自动将.frag转换为.h,但不幸的是它很复杂。

我有什么遗漏吗?

3 个答案:

答案 0 :(得分:3)

为了后代的利益,我将分享我最终使用的解决方案。在较高的层次上,解决方案是将有问题的资源编译到应用程序二进制文件中,从而避免了将其复制到捆绑资源的需要。

我决定将任何文件数据编译到二进制文件中的通用且可靠的方法是将文件内容存储在头文件中的静态字节数组中。假设已经创建了一个头文件并将其添加到静态lib目标中,我创建了以下bash脚本来读取文件,并将其内容写为具有C语法的十六进制文字的字节数组。然后我在“运行脚本”构建阶段中运行脚本,然后编译源代码和复制标题构建阶段:

#!/bin/bash
# Hexify.sh reads an input file, and hexdumps its contents to an output
# file in C-compliant syntax. The final argument is the name of the array.

infile=$1
outfile=$2
arrayName=$3

fileSize=$(stat -f "%z" $infile)
fileHexString=$(hexdump -ve '1/1 "0x%.2x, "' $infile)

prefix=$arrayName
suffix="Size"
variableName=$arrayName$suffix
nullTermination="0x00"

echo "//" > $headerFile
echo "//  This file was automatically generated by a build script." >> $headerFile
echo "//  Do not modify; the contents of this file will be overwritten on each build." >> $headerFile
echo "//" >> $headerFile
echo "" >> $headerFile;
echo "#ifndef some_arbitrary_include_guard" >> $headerFile
echo "#define some_arbitrary_include_guard" >> $headerFile
echo "" >> $headerFile
echo "static const int $variableName = $((fileSize+1));" >> $outfile
echo "static const char $arrayName[$variableName] = {" >> $outfile
echo -e "\t$fileHexString$nullTermination" >> $outfile
echo "};" >> $outfile
echo "#endif" >> $headerFile

因此,例如,如果我有一个资源文件example.txt:

Hello this
is a file

我要运行./Hexify.sh example.txt myHeader.h exampleArray,标题看起来像这样:

//
//  This file was automatically generated by a build script.
//  Do not modify; the contents of this file will be overwritten on each build.
//

#ifndef some_arbitrary_include_guard
#define some_arbitrary_include_guard

static const int exampleArraySize = 21;
static const char exampleArray[exampleArraySize] = {
    0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x74, 0x68, 0x69, 0x73, 0x0a,
    0x69, 0x73, 0x20, 0x61, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x00
};
#endif

现在,在任何时候我都会从主包中加载所述资源,我可以改为引用该头文件中的字节数组。请注意,我的脚本版本添加了一个空终止字节,这使得数据适合创建字符串对象。这可能不适用于所有情况。

作为最后一个附录,如果bash脚本让任何真正的bash程序员畏缩,我道歉;我几乎不知道我在用bash做什么。

答案 1 :(得分:2)

我觉得你的痛苦伙伴,静态图书馆和资源不能很好地融合在一起。我认为最简单的方法是你已经提到的那个:编写一个脚本来读取着色器,正确地转义它们并用C兼容代码包装它们。

我不是专家,但也许您可以在连接时将着色器数据添加到Mach-O可执行文件的某些部分?但这最终归结为与上述相同的解决方案,唯一的缺点就是你留下了丑陋的工作部分。

我会使用一些shell脚本来寻找字符串常量。根据我的经验,PHP非常擅长做这种工作。当然还有bash脚本,但我不太擅长。

答案 2 :(得分:1)

您可以尝试创建一个框架,它似乎符合您的需求。有关如何在此页面上为iOS创建此类框架的示例:

http://db-in.com/blog/2011/07/universal-framework-iphone-ios-2-0/

编写指南的人实际上使用这种技术来分发his own iOS 3D engine project

编辑链接到较新版本的指南。