简体   繁体   English

使用宏定义包含文件

[英]Using a macro to define an include file

To make a long story short, I'm working on some code that needs different header files based on various configuration options.长话短说,我正在编写一些代码,这些代码需要基于各种配置选项的不同头文件。 I could do something like this:我可以做这样的事情:

#if OPTION == A
#include "relative/path/to/file/a.hpp"
#elseif OPTION == B
#include "relative/path/to/file/b.hpp"
#elseif OPTION = ...
...
#endif

This would work, but it seems like a really ugly solution for what could potentially be more than a handful files.这会起作用,但对于可能不仅仅是少数文件的情况,这似乎是一个非常丑陋的解决方案。 I could also simply include all the various header files, but that, too, seems like a bit of an ugly solution, and it could pose problems in the future if files (for some horrible reason) start redefining the same objects.我也可以简单地包含所有各种头文件,但这似乎也有点丑陋的解决方案,如果文件(出于某种可怕的原因)开始重新定义相同的对象,它可能会在未来造成问题。 The idea I had was that something like the following would be nice, particularly in the context of how the rest of the code is written:我的想法是,像下面这样的东西会很好,特别是在其余代码是如何编写的上下文中:

#define QUOTE(str) #str
#define STRINGIFY(A,B) QUOTE(A##B)
...
#include STRINGIFY(relative/path/to/option/,OPTION)

The problem with this seems to be two-fold:这个问题似乎有两个方面:

  1. The OPTION definition doesn't expand properly inside STRINGIFY . OPTION定义没有在STRINGIFY内正确展开。
  2. If there are any forward slashes in the path name, STRINGIFY fails altogether, with g++ giving me an error along the lines of the following:如果路径名中有任何正斜杠,则STRINGIFY完全失败,g++ 给我一个错误,如下所示:

error: pasting "/" and "OPTION" does not give a valid preprocessing token错误:粘贴“/”和“OPTION”没有给出有效的预处理令牌

I can't seem to find any real information on why / is a bad character for the C++ preprocessor, just a few articles saying that you should just put "/" in and rely on automatic C++ string concatenation (which doesn't work in an #include statement).我似乎找不到任何关于为什么/是 C++ 预处理器的坏字符的真实信息,只有几篇文章说你应该把"/"放入并依赖自动 C++ 字符串连接(这在#include语句)。 I'm willing to consider design alternatives if I'm just trying to do something really dumb, but I'd also like to figure out why this isn't working.如果我只是想做一些非常愚蠢的事情,我愿意考虑设计替代方案,但我也想弄清楚为什么这不起作用。

EDIT: I should make the clarification that I'm working on a codebase originally designed by a group of scientists.编辑:我应该澄清一下,我正在研究最初由一组科学家设计的代码库。 Reasonable coding conventions and typical expectations for how a code gets used go completely out the window.合理的编码约定和对如何使用代码的典型期望完全被排除在外。 This code will probably be modified at least as many times as it gets used, often by people who have spent their entire careers writing Fortran 77 and think object-oriented programming is some new-fangled invention that just makes your code harder to understand.这段代码可能至少会被修改多次,通常由那些将整个职业生涯都用于编写 Fortran 77 并认为面向对象编程是一些新奇的发明,只会让你的代码更难理解的人修改。

When writing macros it is essential to look at the output after preprocessing.编写宏时,必须查看预处理后的输出。 With gcc thats the -E option.使用gcc就是-E选项。

To include different files I would rely on your build tools rather than macro voodoo.要包含不同的文件,我将依赖您的构建工具而不是宏 voodoo。 For example when the code is例如,当代码是

include option

Then gcc -E -option=\"foo.h\" yields然后gcc -E -option=\"foo.h\"产生

include "foo.h"

Note that I ommitted the # here, otherwise preprocessing would fail due to not finding "foo.h" .请注意,我在这里省略了# ,否则由于找不到"foo.h" ,预处理会失败。

I wanted to do something similar, searched around and found this post, and after trying few things I think I can help you.我想做类似的事情,四处搜索并找到了这篇文章,在尝试了一些事情之后,我想我可以帮助你。

So, your approach:所以,你的方法:

#define QUOTE(str) #str
#define STRINGIFY(A,B) QUOTE(A##B)
...
#include STRINGIFY(relative/path/to/option/,OPTION)

As I understand from https://gcc.gnu.org/onlinedocs/cpp/Concatenation.html doesn't work because when using ## to paste tokens, the result must be a valid token, where something like path/to/file.hpp is not a valid preprocessing token.据我了解https://gcc.gnu.org/onlinedocs/cpp/Concatenation.html不起作用,因为使用##粘贴令牌时,结果必须是有效令牌,其中类似于path/to/file.hpp不是有效的预处理令牌。

Now, I think that you only need to have a macro which holds the path plus the token to be replaced.现在,我认为您只需要一个包含路径和要替换的令牌的宏。 Well, you don't really need to add the relative path if you are using the -I flag.好吧,如果您使用-I标志,您实际上并不需要添加相对路径。 Your macro could look like #define myMacro relative/path/to/file/OPTION.hpp , then you just need to define OPTION and pass it to one macro so OPTION gets replaced with its value and then another macro to stringize.您的宏可能看起来像#define myMacro relative/path/to/file/OPTION.hpp ,然后您只需要定义OPTION并将其传递给一个宏,以便OPTION被其值替换,然后另一个宏被字符串化。 These two levels of macros are described herehttps://gcc.gnu.org/onlinedocs/cpp/Stringizing.html#Stringizing此处描述了这两个级别的宏https://gcc.gnu.org/onlinedocs/cpp/Stringizing.html#Stringizing

The following example will ilustrate both cases (with/without -I flag).以下示例将说明这两种情况(带/不带-I标志)。

Consider this directory structure:考虑这个目录结构:

.   
|-- a.c 
|-- headers
|   |-- A.hpp
|   `-- B.hpp
`-- makefile

Where ac:其中交流:

#define header OPTION.hpp
#define xstr(x) #x
#define str(x) xstr(x)
#include str(header)

makefile:生成文件:

PATH_OPTION ?= headers/A
OPTION ?= A

.PHONY: all 
all: a.c 
        cpp -D OPTION=${PATH_OPTION} $<
        cpp -I./headers -D OPTION=${OPTION} $<

A.hpp A.hpp

#warning Including A.hpp
1   

B.hpp B.hpp

#warning Including B.hpp
2   

With this, you can call make which by default will include headers/A.hpp and you should be able to see both approaches (with/without -I flag) working and printing to stdout the corresponding warning.有了这个,您可以调用make默认情况下将包含headers/A.hpp并且您应该能够看到两种方法(带/不带-I标志)工作并打印到标准输出相应的警告。

To include headers/B.hpp you would do make OPTION=B or make PATH_OPTION=headers/B depending on the approach you take.要包含headers/B.hpp ,您可以根据您采用的方法make OPTION=Bmake PATH_OPTION=headers/B

I also tried with g++ instead of cpp and it works as well.我也尝试使用g++而不是cpp ,它也可以。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM