【问题标题】:Is it possible to read a file at compile time?是否可以在编译时读取文件?
【发布时间】:2014-11-27 11:27:40
【问题描述】:

我想知道在 C++11/14 中是否可以在编译时实际读取文件。例如下面的代码只有在可以成功读取文件的情况下才会编译。

constexpr std::string shader_source = load("~/foo.glsl");

你认为这可能吗?

我知道在构建我的应用程序时,我可以使用一些自定义工具来做到这一点。

【问题讨论】:

  • 这取决于你通过 load 断奶的内容。我知道的唯一解决方案是#include,这意味着编译器必须能够理解文件的内容。
  • 您可能想要的是一个外部变量声明,它将由链接器与实际数据相匹配。将它与将任意二进制资源嵌入到目标文件中的工具相结合,并使用您选择的导出符号,您就可以了。 (我可以建议这样一个工具,但你没有提到你正在使用什么工具链,并且 ELF、CV、PE、a.out 对象文件格式的工具是不同的)请注意,将资源转换为 C/C++ 代码为用十六进制字面量初始化的常量数组可能会非常非常慢,所以直接进入目标文件。
  • 我不敢相信您的load 函数是constexpr。所以完整的表达式不能是 constexpr。我不知道外部文件内容如何成为 constexpr 字符串。唯一的方法是使用一个简单的加载文件并生成c/c++代码的工具。
  • 鉴于 C++ 没有提供执行此操作的方法,假设特定的编译器/链接器,您会得到答案 - 您可能希望指定实际的操作系统/可移植性需求。
  • 是的,c++源文件可以读取

标签: c++ c++11 c++14


【解决方案1】:

基于 teivaz 的想法,我想知道通常的“扩展后字符串化”技巧是否可行:

#define STRINGIZE(...) #__VA_ARGS__
#define EXPAND_AND_STRINGIZE(...) STRINGIZE(__VA_ARGS__)

constexpr std::string shader_source = EXPAND_AND_STRINGIZE(
#include "~/.foo.glsl"
);


不过,我还是会选择传统的extern const char[] 声明,由链接器解析为内容。文章"Embedding a File in an Executable, aka Hello World, Version 5967"有一个例子:

# objcopy --input binary \
          --output elf32-i386 \
          --binary-architecture i386 data.txt data.o

当然,您应该更改--output--binary-architecture 命令以匹配您的平台。目标文件中的文件名以符号名称结尾,因此您可以像这样使用它:

#include <stdio.h>

/* here "data" comes from the filename data.o */
extern "C" char _binary_data_txt_start;
extern "C" char _binary_data_txt_end;

main()
{
    char*  p = &_binary_data_txt_start;

    while ( p != &_binary_data_txt_end ) putchar(*p++);
}

【讨论】:

  • 但正如 interjay 指出的那样,这可能会因 GLSL 中的逗号而中断。
  • 我已经检查过了。 shader_source 将包含#include "~/.foo.glsl"
  • @teivaz:即使是两层宏调用?
  • @teivaz:这根本不是解决方案,因为它不再是有效的 GLSL 代码。尤其是 GLSL 的 OTOH,您可以玩一些 #ifndef 技巧,因为我相信它支持 C 预处理器。
  • 由于 C++11 16.3/11,划掉的部分无法工作:“如果参数列表中有预处理标记序列,否则将充当预处理指令,则行为未定义。”
【解决方案2】:
#define STR(x) #x

const char* a =
{ 
#include "foo.glsl" 
};

并且 foo.glsl 应该将其内容包含在 字符串( ... )

更新。这将正确处理逗号

#define STRINGIFY(...) #__VA_ARGS__
#define STR(...) STRINGIFY(__VA_ARGS__)

【讨论】:

  • 预处理器声明,如#include 必须是该行的第一个非空格:(
  • 但请参阅 stackoverflow.com/a/5566624/103167 。可以在括号和#include 之间放置换行符,只要数据格式能够容忍字符串中出现的那些额外换行符(GLSL 是可以容忍的)。
  • 嗯,您的编辑修复了预处理器调用但破坏了字符串化。
  • @NeilKirk:可能是因为它应该是裸露的 GLSL 源代码,以便与着色器调试器兼容。
  • 如果文件包含逗号,STR 宏的使用将不起作用。我认为它也会改变文件中的空格。
【解决方案3】:

我做过类似的事情。看看这是否会给你想要的。

在程序中添加一个命令行选项来检查输入文件的存在和有效性。
如果文件不存在或无效,该选项应该以错误代码退出程序。

在您的 make 文件中,添加对程序的调用(使用该命令行选项),作为最后的构建步骤。

现在,当您构建程序时,如果正确的文件不可用或无效,您将收到错误消息。

【讨论】:

  • 他想避免外部程序。
猜你喜欢
  • 2016-10-10
  • 1970-01-01
  • 2012-09-04
  • 2014-04-19
  • 1970-01-01
  • 2023-03-25
  • 2013-06-23
  • 1970-01-01
  • 2011-07-14
相关资源
最近更新 更多