动态#include基于宏定义

时间:2014-01-08 13:24:10

标签: c++ macros makefile

我正在编写一个C ++应用程序,我想让开发人员在编译时选择用于特定问题的算法。这两种算法都是作为实现通用接口的C ++类实现的,并且是相互替代的替代品。它们都有.h和.cpp文件,并且驻留在子目录中(我们称之为impl/)。

在我的Makefile中,我有类似的内容:

...
IMPL = default
...
binary: ... impl/$(IMPL).o
...
impl/%.o: impl/%.cpp impl-interface.h impl/%.h
...
%o: %.cpp ...
    $(CXX) $(CXXFLAGS) -DIMPL=$(IMPL) -c -o $@ $*.cpp

我们的想法是用户应该可以输入make binary IMPL=thatimpl

在任何想要使用用户选择的算法的文件中,我都会这样做:

IImpl o = new IMPL();

但是,这要求我包含所选实现的头文件。不幸的是,C ++要求#include后跟"string"<libfile>。您也可以使用建议的here宏,但它要求宏的参数是文字字符串。如果我使用:

#define QUOTEME(M)       #M
#define INCLUDE_FILE(M)  QUOTEME(impl/##M##.h)
#include INCLUDE_FILE(IMPL)

编译器将尝试包含文字字符串impl/IMPL.h,而不是将IMPL扩展为传递给make然后传递给编译器的任何内容。

关于如何实现这一目标的任何指示都非常受欢迎!

3 个答案:

答案 0 :(得分:6)

由于预处理器的工作方式,您只需添加一个额外的间接层。这应该做:

#define QUOTEME(x) QUOTEME_1(x)
#define QUOTEME_1(x) #x
#define INCLUDE_FILE(x) QUOTEME(impl/x.h)

#include INCLUDE_FILE(IMPL)

Live example

答案 1 :(得分:0)

我看到树的方法来解决你的问题:

  • 使用#ifdef在我看来更清洁:

如下:

#if !defined(IMPL_CHOICE)
# define  IMPL_1 // default to 1, or
//#error "You have to define IMPL_CHOICE"
#endif

#if IMPL_CHOICE == 1

# include "impl1.h"
// other stuff

#elif IMPL_CHOICE == 2

# include "impl1.h"
// other stuff

//elif IMPL_CHOICE == 3 // And so on

#else
# error "invalid IMPL_CHOICE"
#endif
  • 另一种方法是在makefile中添加正确的-I include指令

假设名称相同但位于不同的目录

假设树结构

src/common/*.{cpp,h}
   /implementation_1/header.h
   /implementation_2/header.h
   /implementation_3/header.h

所以你的普通包含目录只是“src /”

所以你的#include看起来像是

#include "implementation_1/header.h"

现在,如果你还添加(条件)“src / implementation_1 /”,它就会变成

#include "header.h"

或者使用-include(对于gcc),就像你对pch(预编译的头文件)所做的那样。

  • 或者在makefile过程中动态创建标题...

答案 2 :(得分:0)

您还可以使用Boost预处理器,尤其是BOOST_PP_STRINGIZE宏:

#include <boost/preprocessor/stringize.hpp>

#define INCLUDE_FILE(X) BOOST_PP_STRINGIZE(impl/X.h)

// expands to: #include "impl/IMPL.h" where IMPL is given by the developer
#include INCLUDE_FILE(IMPL)

直播示例here

(参见我对Generate include file name in a macro的回答)