I am trying to get Bloomberg's BDE library to compile in Visual Studio 2015. Because they re-implement the standard libraries typically provided by the compiler, there are header files that have names that exactly match the standard library names, such as stddef.h
. They optionally allow you to turn off the overriding of the standard library, and to facilitate this, the files they re-implemented will optionally just include the original compiler supplied version such as stddef.h
. They do this include through macros such as the following:
我正在尝试让Bloomberg的BDE库在Visual Studio 2015中编译。因为它们重新实现了编译器通常提供的标准库,所以有一些头文件的名称与标准库名称完全匹配,例如stddef.h。它们可以选择允许您关闭标准库的重写,并为其提供便利,它们重新实现的文件只包括原始的编译器提供的版本,如stddef.h。它们通过以下宏来实现这一点:
# if defined(BSLS_COMPILERFEATURES_SUPPORT_INCLUDE_NEXT)
# include_next <stddef.h>
# else
# include BSL_NATIVE_C_LIB_HEADER(stddef.h)
# endif
源
Where BSL_NATIVE_C_LIB_HEADER
expands to something like this:
其中BSL_NATIVE_C_LIB_HEADER扩展为如下内容:
#if defined(BSLS_PLATFORM_CMP_SUN) // Sun Compiler
# define BSL_NATIVE_C_LIB_HEADER(filename) <../include/filename>
#elif defined(BSLS_PLATFORM_CMP_CLANG) || defined(BSLS_PLATFORM_CMP_GNU)
// Clang and GCC use 'include_next'
#elif defined(BSLS_PLATFORM_CMP_HP) // HP Compiler
# define BSL_NATIVE_C_LIB_HEADER(filename) <../include_std/filename>
#else
// Most other compilers
# define BSL_NATIVE_C_LIB_HEADER(filename) <../include/filename>
#endif
源
The issue is that Visual Studio 2015 introduces some refactoring that moves some of the C Standard Library header files to a path like this: C:\Program Files (x86)\Windows Kits\10\Include\10.0.10150.0\ucrt
. This obviously means that <../include/filename>
will no longer find the moved files. The issue is that all files have not moved. For example, iso646.h
is still in C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include
and will be picked up by the include.
问题是,Visual Studio 2015中引入了一些重构移动一些C标准库的头文件路径:C:\Program Files (x86)\Windows包\ 10 \ \ 10.0.10150.0 \ ucrt。这显然意味着/include/filename>将不再找到移动的文件。问题是所有文件都没有移动。例如,iso646。h仍在C:\Program Files (x86)\Microsoft Visual Studio 14.0 \ VC \包括和将被包括。
So here's my question in a nutshell: Is there a way I can continue to support the BSL_NATIVE_C_LIB_HEADER
macro being used, while behind the scenes figuring out whether the import should be from ../ucrt/
or ../include
, based on the file name? I know I could create two separate macros, but I'd rather keep the interface the same if possible.
因此,我的问题很简单:是否有一种方法可以继续支持正在使用的BSL_NATIVE_C_LIB_HEADER宏,同时在幕后确定是否应该从……/ ucrt /或. ./包含,基于文件名?我知道我可以创建两个独立的宏,但是如果可能的话,我宁愿保持接口不变。
2 个解决方案
#1
1
Ideally, the BSL_NATIVE_C_LIB_HEADER()-like macros would continue to work, while behind the scenes there is a mechanism to override some them based on filename to point at a different directory. At first it seems impossible because the argument to the macros is a filename and may contain "." or "/". But with enough macro-foolery I think it can still be done without changing the build scripts or the filesystem.
理想情况下,类似BSL_NATIVE_C_LIB_HEADER()的宏将继续工作,而在幕后,有一种机制根据文件名覆盖一些宏,以指向另一个目录。一开始似乎不可能,因为宏的参数是文件名,可能包含“.”或“/”。但是,有了足够的宏观操作,我认为在不更改构建脚本或文件系统的情况下,仍然可以实现这一点。
BTW, I'm not sure what this says about the C preprocessor, but here goes...
顺便说一句,我不确定这说明了C预处理器的什么,但是……
The idea is to construct a series of macros that would be inserted into bsl_stdhdrs_incpaths.h in a MSVC 2015 specific block. There are several of these macros that do basically the same thing, so I have factored the solution so that each user macro like BSL_NATIVE_C_LIB_HEADER is implemented in terms of a common macro FINDER. The implementation macros have short names for readability, they should get some sort of prefix.
其思想是构造一系列宏,这些宏将插入到bsl_stdhdrs_incpaths中。h in a MSVC 2015 specific block。这些宏中有几个做了基本相同的事情,所以我重构了解决方案,这样每个用户宏(比如BSL_NATIVE_C_LIB_HEADER)都可以用公共宏查找器实现。实现宏具有可读性的简短名称,它们应该具有某种前缀。
Caveat: these examples have only been tested on GCC 4.8.4 and unstable, clang-3.5, and MSVC 2015.
注意:这些示例仅在GCC 4.8.4和不稳定、clang-3.5和MSVC 2015上进行了测试。
Simple Idea
简单的想法
The first clue is that even if the argument to BSL_NATIVE_C_LIB_HEADER(stddef.h)
contains odd characters, it is not a single token. It is the list {'stddef', '.', 'h'}.
第一个线索是,即使BSL_NATIVE_C_LIB_HEADER(stddef.h)的参数包含奇数字符,它也不是单个标记。它是列表{'stddef', '。”、“h”}。
So we could #define stddef to ../include/stddef and it would work because the '.' and 'h' get appended after expansion! But better, we can use ## to paste the first token into macro with a unique name, say SELECTOR_stddef
. This can then be #defined with a unique path based on each filename:
所以我们可以将stddef定义为。/include/stddef和它将工作,因为'。“和”h”在扩展后被追加!但是更好的是,我们可以使用## #将第一个标记粘贴到带有唯一名称的宏中,例如SELECTOR_stddef。然后可以根据每个文件名使用唯一的路径来定义这个值:
#define ANGLES(f) <f>
#define BSL_NATIVE_C_LIB_HEADER(file) ANGLES(SELECTOR_##file)
/* each can now have a different prefix */
#define SELECTOR_stddef ../ucrt/stddef
#define SELECTOR_stdarg ../include/stdarg
/* later on, down in the user code... */
#include BSL_NATIVE_C_LIB_HEADER(stddef.h) /* #include <../ucrt/stddef.h> */
#include BSL_NATIVE_C_LIB_HEADER(stdarg.h) /* #include <../include/stddef.h> */
So this is working great! The only problem is that every single file that is called must have a selector. If not, it will try to include some stupid filename that looks like #include <SELECTOR_stdio.h>
and it won't work that well. Some maintenance programmer will probably come around and "fix" it by adding a bunch of symlinks to SELECTOR_stdio.h in the /usr/include directory and it will just end badly for everyone.
这真是太棒了!唯一的问题是每个被调用的文件都必须有一个选择器。如果不是,它将尝试包含一些看起来像#include
What would be really nice is if there could be a default for most files. Most appear to have been shuffled into .../ucrt and only compiler specific ones are left in .../include. So it would be nice to just override the ones we want. But even in this first form, it may work just fine. It has the advantage of simplicity.
如果大多数文件都有默认值,那将会非常好。大多数似乎都被拖进了……/ucrt中只剩下特定于编译器的/include。所以最好重写一下我们想要的。但即使是在第一种情况下,它也可以正常工作。它具有简单性的优点。
A bunch of SO questions that helped with this:
有很多这样的问题
- Can macros be overloaded by number of arguments?
- 可以用参数的数量重载宏吗?
- Overloading Macro on Number of Arguments
- 在多个参数上重载宏
- MSVC doesn't expand __VA_ARGS__ correctly
- MSVC没有正确地展开__VA_ARGS__
- Optional Parameters with C++ Macros
- 带有c++宏的可选参数。
- C preprocessor macro specialisation based on an argument
- 基于参数的预处理器宏专门化
- Variadic macro trick
- 可变宏观技巧
- Is it possible to iterate over arguments in variadic macros?
- 是否可以在可变宏中迭代参数?
A More Complete Solution
一个更完整的解决方案
/* presumably within an #if MSVC 2015 conditional in bsl_stdhdrs_incpaths.h */
#define DELIMITER(a) a
/* same as DELIMITER, but named to distinguish the MSVC __VA_ARGS__ bug */
/* workaround is fine to leave in place for standard compilers */
#define MSVCFIXER(a) a
/* add the angle brackets and re-attach the "rest" tokens */
#define FORMATER(x1, x2, pre, rest, ...) <DELIMITER(pre)rest>
/* if __VA_ARGS__ only has one argument, shift so that pre is the default
* otherwise if __VA_ARGS__ has two, pre is the override */
#define SHIFTER(pre, rest, def, ...) MSVCFIXER(FORMATER(__VA_ARGS__, pre, rest, def))
/* expand the commas */
#define EXPANDER(...) MSVCFIXER(SHIFTER(__VA_ARGS__))
/* main implementation - pass both the selector override and default */
#define FINDER(file, defloc) \
EXPANDER(HEAD_LOC_OVERRIDE_##file, DELIMITER(defloc)file,,)
/* now implement the top level macros */
#define BSL_NATIVE_C_LIB_HEADER(file) FINDER(file, HEAD_LOC_DEFAULT_PREFIX)
#define BSL_NATIVE_SYS_TIME_HEADER(file) FINDER(file, HEAD_LOC_DEFAULT_PREFIX)
#define BSL_NATIVE_CISO646_HEADER(file) FINDER(file, /tmp/)
/* maybe define a common default prefix, or hard code it like iso646
* since most files appear to be in ucrt, make this the default
(file.h) will become <../ucrt/file.h> */
#define HEAD_LOC_DEFAULT_PREFIX ../ucrt/
/* override any other files NOTE: the commas
* (stdarg.h) will become <../include/stdarg.h>
* (stdint.h) will become <../include/stdint.h> */
#define HEAD_LOC_OVERRIDE_stdarg ../include/stdarg,
#define HEAD_LOC_OVERRIDE_stdint ../include/stdint,
/* and you can even override the name part too, or remove or add the .h
* (where.h) will become <../somewhere/when> (note: use two commas)
* (sys/*.h) will become <../include/sys/*.h>
* (cstdio) will become <windows.h> */
#define HEAD_LOC_OVERRIDE_where ../somewhere/when,,
#define HEAD_LOC_OVERRIDE_sys ../include/sys,
#define HEAD_LOC_OVERRIDE_cstdio windows.h,
/* later on, down in the user code... */
#include BSL_NATIVE_C_LIB_HEADER(stdarg.h) /* <../include/stdarg.h */
#include BSL_NATIVE_C_LIB_HEADER(stdio.h) /* <../ucrt/stdio.h */
#include BSL_NATIVE_C_LIB_HEADER(cstdio) /* <windows.h> */
#include BSL_NATIVE_C_LIB_HEADER(what.h) /* <../ucrt/what.h> */
#include BSL_NATIVE_C_LIB_HEADER(where.h) /* <../somewhere/when> */
#include BSL_NATIVE_CISO646_HEADER(iso646.h) /* </tmp/iso646.h> */
#2
0
You can create a separate directory ../VC14-include-compat
that contains dummy include files that redirect to the actual location of each standard include file.
您可以创建一个单独的目录。包含虚拟包含文件的VC14-include-compat包含重定向到每个标准包含文件的实际位置的文件。
A simpler hack is to patch your VC14 include directory to add the missing files and make them include from the new directory explicitly.
一个更简单的方法是对VC14 include目录进行补丁,以添加丢失的文件,并使它们从新目录显式包含。
Also, why not use the alternative method and include the bsl include files from the bsl/bsl+bslhdrs
directory instead of the bsl/bsl+stdhdrs
. You will need to modify your source files to include for example <bsl_c_stddef.h>
instead of <stddef.h>
, but that will make your project more portable.
另外,为什么不使用替代方法,并将bsl包括来自bsl/bsl+bslhdrs目录的文件,而不是bsl/bsl+stdhdr。您需要修改源文件,例如
The BDE library has 1.7 million lines of code, good luck trying to fix any other portability issues!
BDE库有170万行代码,祝您好运,可以解决任何其他可移植性问题!
#1
1
Ideally, the BSL_NATIVE_C_LIB_HEADER()-like macros would continue to work, while behind the scenes there is a mechanism to override some them based on filename to point at a different directory. At first it seems impossible because the argument to the macros is a filename and may contain "." or "/". But with enough macro-foolery I think it can still be done without changing the build scripts or the filesystem.
理想情况下,类似BSL_NATIVE_C_LIB_HEADER()的宏将继续工作,而在幕后,有一种机制根据文件名覆盖一些宏,以指向另一个目录。一开始似乎不可能,因为宏的参数是文件名,可能包含“.”或“/”。但是,有了足够的宏观操作,我认为在不更改构建脚本或文件系统的情况下,仍然可以实现这一点。
BTW, I'm not sure what this says about the C preprocessor, but here goes...
顺便说一句,我不确定这说明了C预处理器的什么,但是……
The idea is to construct a series of macros that would be inserted into bsl_stdhdrs_incpaths.h in a MSVC 2015 specific block. There are several of these macros that do basically the same thing, so I have factored the solution so that each user macro like BSL_NATIVE_C_LIB_HEADER is implemented in terms of a common macro FINDER. The implementation macros have short names for readability, they should get some sort of prefix.
其思想是构造一系列宏,这些宏将插入到bsl_stdhdrs_incpaths中。h in a MSVC 2015 specific block。这些宏中有几个做了基本相同的事情,所以我重构了解决方案,这样每个用户宏(比如BSL_NATIVE_C_LIB_HEADER)都可以用公共宏查找器实现。实现宏具有可读性的简短名称,它们应该具有某种前缀。
Caveat: these examples have only been tested on GCC 4.8.4 and unstable, clang-3.5, and MSVC 2015.
注意:这些示例仅在GCC 4.8.4和不稳定、clang-3.5和MSVC 2015上进行了测试。
Simple Idea
简单的想法
The first clue is that even if the argument to BSL_NATIVE_C_LIB_HEADER(stddef.h)
contains odd characters, it is not a single token. It is the list {'stddef', '.', 'h'}.
第一个线索是,即使BSL_NATIVE_C_LIB_HEADER(stddef.h)的参数包含奇数字符,它也不是单个标记。它是列表{'stddef', '。”、“h”}。
So we could #define stddef to ../include/stddef and it would work because the '.' and 'h' get appended after expansion! But better, we can use ## to paste the first token into macro with a unique name, say SELECTOR_stddef
. This can then be #defined with a unique path based on each filename:
所以我们可以将stddef定义为。/include/stddef和它将工作,因为'。“和”h”在扩展后被追加!但是更好的是,我们可以使用## #将第一个标记粘贴到带有唯一名称的宏中,例如SELECTOR_stddef。然后可以根据每个文件名使用唯一的路径来定义这个值:
#define ANGLES(f) <f>
#define BSL_NATIVE_C_LIB_HEADER(file) ANGLES(SELECTOR_##file)
/* each can now have a different prefix */
#define SELECTOR_stddef ../ucrt/stddef
#define SELECTOR_stdarg ../include/stdarg
/* later on, down in the user code... */
#include BSL_NATIVE_C_LIB_HEADER(stddef.h) /* #include <../ucrt/stddef.h> */
#include BSL_NATIVE_C_LIB_HEADER(stdarg.h) /* #include <../include/stddef.h> */
So this is working great! The only problem is that every single file that is called must have a selector. If not, it will try to include some stupid filename that looks like #include <SELECTOR_stdio.h>
and it won't work that well. Some maintenance programmer will probably come around and "fix" it by adding a bunch of symlinks to SELECTOR_stdio.h in the /usr/include directory and it will just end badly for everyone.
这真是太棒了!唯一的问题是每个被调用的文件都必须有一个选择器。如果不是,它将尝试包含一些看起来像#include
What would be really nice is if there could be a default for most files. Most appear to have been shuffled into .../ucrt and only compiler specific ones are left in .../include. So it would be nice to just override the ones we want. But even in this first form, it may work just fine. It has the advantage of simplicity.
如果大多数文件都有默认值,那将会非常好。大多数似乎都被拖进了……/ucrt中只剩下特定于编译器的/include。所以最好重写一下我们想要的。但即使是在第一种情况下,它也可以正常工作。它具有简单性的优点。
A bunch of SO questions that helped with this:
有很多这样的问题
- Can macros be overloaded by number of arguments?
- 可以用参数的数量重载宏吗?
- Overloading Macro on Number of Arguments
- 在多个参数上重载宏
- MSVC doesn't expand __VA_ARGS__ correctly
- MSVC没有正确地展开__VA_ARGS__
- Optional Parameters with C++ Macros
- 带有c++宏的可选参数。
- C preprocessor macro specialisation based on an argument
- 基于参数的预处理器宏专门化
- Variadic macro trick
- 可变宏观技巧
- Is it possible to iterate over arguments in variadic macros?
- 是否可以在可变宏中迭代参数?
A More Complete Solution
一个更完整的解决方案
/* presumably within an #if MSVC 2015 conditional in bsl_stdhdrs_incpaths.h */
#define DELIMITER(a) a
/* same as DELIMITER, but named to distinguish the MSVC __VA_ARGS__ bug */
/* workaround is fine to leave in place for standard compilers */
#define MSVCFIXER(a) a
/* add the angle brackets and re-attach the "rest" tokens */
#define FORMATER(x1, x2, pre, rest, ...) <DELIMITER(pre)rest>
/* if __VA_ARGS__ only has one argument, shift so that pre is the default
* otherwise if __VA_ARGS__ has two, pre is the override */
#define SHIFTER(pre, rest, def, ...) MSVCFIXER(FORMATER(__VA_ARGS__, pre, rest, def))
/* expand the commas */
#define EXPANDER(...) MSVCFIXER(SHIFTER(__VA_ARGS__))
/* main implementation - pass both the selector override and default */
#define FINDER(file, defloc) \
EXPANDER(HEAD_LOC_OVERRIDE_##file, DELIMITER(defloc)file,,)
/* now implement the top level macros */
#define BSL_NATIVE_C_LIB_HEADER(file) FINDER(file, HEAD_LOC_DEFAULT_PREFIX)
#define BSL_NATIVE_SYS_TIME_HEADER(file) FINDER(file, HEAD_LOC_DEFAULT_PREFIX)
#define BSL_NATIVE_CISO646_HEADER(file) FINDER(file, /tmp/)
/* maybe define a common default prefix, or hard code it like iso646
* since most files appear to be in ucrt, make this the default
(file.h) will become <../ucrt/file.h> */
#define HEAD_LOC_DEFAULT_PREFIX ../ucrt/
/* override any other files NOTE: the commas
* (stdarg.h) will become <../include/stdarg.h>
* (stdint.h) will become <../include/stdint.h> */
#define HEAD_LOC_OVERRIDE_stdarg ../include/stdarg,
#define HEAD_LOC_OVERRIDE_stdint ../include/stdint,
/* and you can even override the name part too, or remove or add the .h
* (where.h) will become <../somewhere/when> (note: use two commas)
* (sys/*.h) will become <../include/sys/*.h>
* (cstdio) will become <windows.h> */
#define HEAD_LOC_OVERRIDE_where ../somewhere/when,,
#define HEAD_LOC_OVERRIDE_sys ../include/sys,
#define HEAD_LOC_OVERRIDE_cstdio windows.h,
/* later on, down in the user code... */
#include BSL_NATIVE_C_LIB_HEADER(stdarg.h) /* <../include/stdarg.h */
#include BSL_NATIVE_C_LIB_HEADER(stdio.h) /* <../ucrt/stdio.h */
#include BSL_NATIVE_C_LIB_HEADER(cstdio) /* <windows.h> */
#include BSL_NATIVE_C_LIB_HEADER(what.h) /* <../ucrt/what.h> */
#include BSL_NATIVE_C_LIB_HEADER(where.h) /* <../somewhere/when> */
#include BSL_NATIVE_CISO646_HEADER(iso646.h) /* </tmp/iso646.h> */
#2
0
You can create a separate directory ../VC14-include-compat
that contains dummy include files that redirect to the actual location of each standard include file.
您可以创建一个单独的目录。包含虚拟包含文件的VC14-include-compat包含重定向到每个标准包含文件的实际位置的文件。
A simpler hack is to patch your VC14 include directory to add the missing files and make them include from the new directory explicitly.
一个更简单的方法是对VC14 include目录进行补丁,以添加丢失的文件,并使它们从新目录显式包含。
Also, why not use the alternative method and include the bsl include files from the bsl/bsl+bslhdrs
directory instead of the bsl/bsl+stdhdrs
. You will need to modify your source files to include for example <bsl_c_stddef.h>
instead of <stddef.h>
, but that will make your project more portable.
另外,为什么不使用替代方法,并将bsl包括来自bsl/bsl+bslhdrs目录的文件,而不是bsl/bsl+stdhdr。您需要修改源文件,例如
The BDE library has 1.7 million lines of code, good luck trying to fix any other portability issues!
BDE库有170万行代码,祝您好运,可以解决任何其他可移植性问题!