gpt4 book ai didi

c++ - 当路径中存在同名文件时,跨平台方式包含系统头文件?

转载 作者:可可西里 更新时间:2023-11-01 17:59:16 28 4
gpt4 key购买 nike

我正在尝试获取 Bloomberg's BDE library在 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

Source

在哪里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

Source

问题是 Visual Studio 2015 introduces some refactoring将 C 标准库头文件的 一些 移动到如下路径:C:\Program Files (x86)\Windows Kits\10\Include\10.0.10150.0\ucrt .这显然意味着 <../include/filename>将不再找到移动的文件。问题是所有文件都没有移动。例如,iso646.h还在C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include并且会被 include 拾取。

所以我的问题简而言之:有没有办法让我继续支持 BSL_NATIVE_C_LIB_HEADER正在使用宏,同时在幕后确定导入是否应该来自 ../ucrt/../include , 基于文件名?我知道我可以创建两个单独的宏,但我宁愿尽可能保持界面相同。

最佳答案

理想情况下,类似于 BSL_NATIVE_C_LIB_HEADER() 的宏将继续工作,而在幕后有一种机制可以根据文件名覆盖某些宏以指向不同的目录。起初这似乎是不可能的,因为宏的参数是一个文件名并且可能包含“.”。或者 ”/”。但是如果有足够多的宏操作,我认为它仍然可以在不更改构建脚本或文件系统的情况下完成。

顺便说一句,我不确定这对 C 预处理器有何影响,但这里...

想法是构建一系列宏,这些宏将插入到 MSVC 2015 特定 block 中的 bsl_stdhdrs_incpaths.h 中。这些宏中有几个基本上做同样的事情,所以我已经分解了解决方案,以便每个用户宏(如 BSL_NATIVE_C_LIB_HEADER)都根据通用宏 FINDER 实现。实现宏的名称很短,便于阅读,它们应该有某种前缀。

警告:这些示例仅在 GCC 4.8.4 和不稳定、clang-3.5 和 MSVC 2015 上进行了测试。

简单的想法

第一个线索是即使参数BSL_NATIVE_C_LIB_HEADER(stddef.h)包含奇怪的字符,它不是一个单一的 token 。它是列表 {'stddef', '.', 'h'}。

所以我们可以将 stddef#define 到 ../include/stddef 并且它会起作用,因为 '.'并且'h'在扩展后被追加!但更好的是,我们可以使用 ## 将第一个标记粘贴到具有唯一名称的宏中,比如 SELECTOR_stddef .然后可以使用基于每个文件名的唯一路径#defined:

#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> */

所以这很好用!唯一的问题是每个被调用的文件都必须有一个选择器。如果不是,它将尝试包含一些看起来像 #include <SELECTOR_stdio.h> 的愚蠢文件名。它不会那么好用。一些维护程序员可能会通过向/usr/include 目录中的 SELECTOR_stdio.h 添加一堆符号链接(symbolic link)来“修复”它,这对每个人来说都会很糟糕。

真正 最好的是,如果大多数文件都可以有一个默认值。大多数似乎已被改组到 .../ucrt 中,只有编译器特定的留在 .../include 中。所以最好只覆盖我们想要的那些。但即使是第一种形式,它也可能工作得很好。它的优点是简单。

一堆对此有帮助的 SO 问题:

更完整的解决方案

/* 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> */

关于c++ - 当路径中存在同名文件时,跨平台方式包含系统头文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33793984/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com