在静态库中嵌入资源 - C / C ++

时间:2016-03-19 07:00:39

标签: c resources static-libraries archive

我正在学习如何使用终端创建库。是否有可能(我怀疑它可能不是)将资源(如图像,文本,API密钥等)放入静态链接的存档文件中,就像在NSBundle中一样?我如何参考这些资源?

2 个答案:

答案 0 :(得分:0)

您要做的是从二进制blob创建一个目标文件,以便能够链接到它。它需要是一个包含符号表的目标文件,该符号表至少包含一个符号(可能是blob的开头),因为你想要在程序的其余部分处理二进制数据的句柄

因为目标文件完全依赖于系统(有时甚至是编译器),所以没有直接实际执行此操作的可移植方法。例如,Linux曾经有过至少两种不同的目标文件格式。

最容易可移植(也许,甚至最简单)的方法:使用知道如何为开发环境构建目标文件的工具: C编译器。

编写自己的转换器,从二进制数据中创建C代码,如

const unsigned char blob[] = {0x0,0x22,.....};

然后编译并链接。不应该太难做,而是10分钟的工作。其他一切都完全不便携。

在可以使用GNU objcopy 的平台上,这可能是另一种做事方式。 (指定'binary'作为输入文件格式,将目标文件格式指定为输出目标。还需要使用“--add-symbol”添加blob的起始符号。)但我自己从未这样做过。

答案 1 :(得分:0)

在POSIX系统上,你有一个非常标准的shell sh,四个非常有用的shell实用程序叫做rmprintfodsed

假设您希望使用包含二进制文件foo.c内容的const unsigned char blob[]数组创建文件foo.bar

export LANG=C LC_ALL=C
rm -f foo.c
printf 'const unsigned char blob[] = {\n' > foo.c
od -A n -t x1 foo.bar | sed -e 's| *\([0-9A-Fa-f][0-9A-Fa-f]\)| 0x\1U,|g; s|^|   |' >> foo.c
printf '};\n' >> foo.c

第一行将语言环境设置为C。这可以确保实用程序使用我们期望的格式,而不是某些本地化的变体。

第二行删除可能存在的foo.c。 (如果您将输出直接输出到现有文件而没有附加,则有些shell会抱怨。)如果文件尚不存在,-f会安排任何投诉。

第三行和第五行附加数组定义并关闭foo.c文件。

第四行使用od实用程序将foo.bar的内容输出为十六进制字节。我们使用sed添加0x并将U,附加到每个十六进制字节以使其漂亮且漂亮的C,然后我们在该行前面添加另外三个空格(使其缩进四个空格)。

如果您不喜欢这种方法,您可以随时编写自己的实用程序来完成此操作。例如:     #包括     #包括     #包括     #include

#ifndef  DEFAULT_VARNAME
#define  DEFAULT_VARNAME "blob"
#endif

#ifndef  DEFAULT_STORAGE
#define  DEFAULT_STORAGE "const"
#endif

#ifndef  DEFAULT_ATTRIBUTES
#define  DEFAULT_ATTRIBUTES ""
#endif

#ifndef  DEFAULT_INDENT
#define  DEFAULT_INDENT "    "
#endif

#ifndef  DEFAULT_COLUMNS
#define  DEFAULT_COLUMNS 16
#endif

int usage(const char *argv0)
{
    fprintf(stderr, "\n");
    fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv0);
    fprintf(stderr, "       %s [ OPTIONS ] file [ [ OPTIONS ] file .. ]\n", argv0);
    fprintf(stderr, "\n");
    fprintf(stderr, "Options:\n");
    fprintf(stderr, "       -n %-10s Variable name\n", "'" DEFAULT_VARNAME "'");
    fprintf(stderr, "       -s %-10s Storage type\n", "'" DEFAULT_STORAGE "'");
    fprintf(stderr, "       -a %-10s Attributes\n", "'" DEFAULT_ATTRIBUTES "'");
    fprintf(stderr, "       -i %-10s Indentation\n", "'" DEFAULT_INDENT "'");
    fprintf(stderr, "       -c %-10d Bytes per line\n", (int)DEFAULT_COLUMNS);
    fprintf(stderr, "\n");
    fprintf(stderr, "This program will output the contents of the specified file(s)\n");
    fprintf(stderr, "as C source code.\n");
    fprintf(stderr, "\n");
    return EXIT_SUCCESS;
}


int main(int argc, char *argv[])
{
    const char *storage = DEFAULT_STORAGE;
    const char *varname = DEFAULT_VARNAME;
    const char *attributes = DEFAULT_ATTRIBUTES;
    const char *indent = DEFAULT_INDENT;
    size_t      columns = DEFAULT_COLUMNS;

    FILE   *in;
    size_t  bytes;
    int     ch, arg;
    char    dummy;

    if (argc < 2)
        return usage(argv[0]);

    arg = 1;
    while (arg < argc) {

        if (argv[arg][0] == '-') {
            if (argv[arg][1] == 'n') {
                if (argv[arg][2] != '\0') {
                    varname = argv[arg] + 2;
                    arg++;
                    continue;
                } else
                if (arg + 1 < argc) {
                    varname = argv[arg + 1];
                    arg += 2;
                    continue;
                }
            } else
            if (argv[arg][1] == 's') {
                if (argv[arg][2] != '\0') {
                    storage = argv[arg] + 2;
                    arg++;
                    continue;
                } else
                if (arg + 1 < argc) {
                    storage = argv[arg + 1];
                    arg += 2;
                    continue;
                }
            } else
            if (argv[arg][1] == 'a') {
                if (argv[arg][2] != '\0') {
                    attributes = argv[arg] + 2;
                    arg++;
                    continue;
                } else
                if (arg + 1 < argc) {
                    attributes = argv[arg + 1];
                    arg += 2;
                    continue;
                }
            } else
            if (argv[arg][1] == 'i') {
                if (argv[arg][2] != '\0') {
                    indent = argv[arg] + 2;
                    arg++;
                    continue;
                } else
                if (arg + 1 < argc) {
                    indent = argv[arg + 1];
                    arg += 2;
                    continue;
                }
            } else
            if (argv[arg][1] == 'c') {
                if (argv[arg][2] != '\0') {
                    if (sscanf(argv[arg] + 2, " %zu %c", &columns, &dummy) != 1 || columns < 1) {
                        fprintf(stderr, "%s: Invalid number of bytes per line.\n", argv[arg] + 2);
                        return EXIT_FAILURE;
                    }
                    arg++;
                    continue;
                } else
                if (arg + 1 < argc) {
                    if (sscanf(argv[arg+1], " %zu %c", &columns, &dummy) != 1 || columns < 1) {
                        fprintf(stderr, "%s: Invalid number of bytes per line.\n", argv[arg + 1]);
                        return EXIT_FAILURE;
                    }
                    arg += 2;
                    continue;
                }
            } else
            if (!strcmp(argv[arg], "-h") || !strcmp(argv[arg], "--help"))
                return usage(argv[0]);
        }

        in = fopen(argv[arg], "r");
        if (!in) {
            fprintf(stderr, "%s: %s.\n", argv[arg], strerror(errno));
            return EXIT_FAILURE;
        }

        printf("%s unsigned char %s[] %s= {", storage, varname, attributes);

        bytes = 0;
        while ((ch = getc(in)) != EOF)
            if (bytes++ % columns)
                printf(", %3u", (unsigned int)ch);
            else
                printf("\n%s%3u", indent, (unsigned int)ch);

        printf("\n}; /* %zu bytes */\n\n", bytes);

        if (ferror(in)) {
            fclose(in);
            fprintf(stderr, "%s: Read error.\n", argv[arg]);
            return EXIT_FAILURE;
        }
        if (fclose(in)) {
            fprintf(stderr, "%s: Delayed read error.\n", argv[arg]);
            return EXIT_FAILURE;
        }

        if (fflush(stdout) || ferror(stdout)) {
            fprintf(stderr, "Error writing to standard output.\n");
            return EXIT_FAILURE;
        }

        arg++;
    }

    return EXIT_SUCCESS;
}

上述代码中唯一的POSIX-ism是使用%zu来扫描和打印size_t