如何在编译时检查“#define VERSION 3.1.4”的值?
我将编译时检查添加到我公司的C ++项目中,以确保所有开发机器和构建服务器上的第三方库都是最新的。 对于例如版本3.1.4,大多数库定义如下所示:
#define VERSION_MAJOR 3
#define VERSION_MINOR 1
#define VERSION_BUILD 4
这很好,并且易于使用static_assert
或预处理器指令进行检查。
现在我正在查看定义单个宏的第三方库:
#define VERSION 3.1.4
我如何在编译时验证这种宏的价值?
在C ++ 11中,我可以使用constexpr
字符串比较函数,并对宏进行字符串化以检查它:
constexpr bool static_equal(const char * a, const char * b)
{
return (*a == *b) && (*a == ' ' || static_equal(a + 1, b + 1));
}
// stringification functions
#define str(x) #x
#define xstr(x) str(x)
static_assert(static_equal(xstr(VERSION), "3.1.4"), "incorrect version of libwhatever");
但是我们在Windows机器上使用Visual Studio 2013,所以我只能使用它支持的C ++ 11的子集。 不幸的是, constexpr
不支持。
这是我现在正在做的事情:
#define str(x) #x
#define xstr(x) str(x)
#include xstr(libwhatever.version.is.VERSION.should.be.3.1.4)
除此之外,我libwhatever.version.is.3.1.4.should.be.3.1.4
向项目添加了一个名为libwhatever.version.is.3.1.4.should.be.3.1.4
的空文件。 因此,如果版本正确,预处理器将成功包含此文件。 否则,它将会以“无法打开”libwhatever.version.is.2.7.2.should.be.3.1.4',没有这样的文件或目录“而失败。 如果通过一些有意义的信息来构建这个构建体系,那最终还是很重要的。
当然这种方法不是很灵活, 例如我无法检查最小版本或一系列版本。 但对我来说,能够检查确切的值就足够了。
这似乎与Visual C ++和g ++一起工作。 不过,我不确定行为是否完全按照标准定义好。
你不能在预处理器中,但你可以滥用类型特征!
VS 2013似乎支持可变模板。 尝试使用宏CSTRING
在https://stackoverflow.com/a/15912824/2097780(你应该能够使用const
替换constexpr
并让代码仍然有效)并执行如下操作:
#define STRT(x) decltype(CSTRING(x))
static_assert(std::is_same<STRT(VERSION), STRT("3.1.4")>::value, "incorrect version of libwhatever");
编辑:这是行不通的。 但是,如果你的编译器编译没有错误:
extern const char data[] = "abc";
template <char C> struct x {
static const char c = C;
};
char buf[(int)x<"ABC123"[0]>::c];
int main() { return (int)buf; }
然后你可以试试这个:
#include <type_traits>
#define VERSION 1.2.3
#define STR2(x) #x
#define STR(x) STR2(x)
template <char...> struct ststring;
// https://stackoverflow.com/a/15860416/2097780
#define MACRO_GET_1(str, i)
(sizeof(str) > (i) ? str[(i)] : 0)
#define MACRO_GET_4(str, i)
MACRO_GET_1(str, i+0),
MACRO_GET_1(str, i+1),
MACRO_GET_1(str, i+2),
MACRO_GET_1(str, i+3)
#define MACRO_GET_16(str, i)
MACRO_GET_4(str, i+0),
MACRO_GET_4(str, i+4),
MACRO_GET_4(str, i+8),
MACRO_GET_4(str, i+12)
#define MACRO_GET_64(str, i)
MACRO_GET_16(str, i+0),
MACRO_GET_16(str, i+16),
MACRO_GET_16(str, i+32),
MACRO_GET_16(str, i+48)
#define MACRO_GET_STR(str) MACRO_GET_64(str, 0), 0
static_assert(std::is_same<ststring<MACRO_GET_STR(STR(VERSION))>,
ststring<MACRO_GET_STR("1.2.3")>>::value,
"invalid library version");
如果你右键点击你的项目 - >属性 - >生成事件 - >预生成事件你会看到一个选项,说“命令行”。 你可以在这里打电话给另一个程序。
您可以使用C ++或任何您喜欢的语言编写另一个程序来检查您的文件(或任何数量的文件)“#define VERSION 3.1.4”。 您可以放弃构建并在该程序中添加任何您需要的警告。
这里是一个教程:https://dillieodigital.wordpress.com/2012/11/27/quick-tip-aborting-builds-in-visual-studio-based-on-file-contents/
相关阅读:https://msdn.microsoft.com/en-us/library/e85wte0k.aspx
我尝试了很久的预处理器命令,并且我找不到只使用预处理器命令的方法。
链接地址: http://www.djcxy.com/p/85837.html上一篇: How to check a value like "#define VERSION 3.1.4" at compile time?