请考虑以下内容,其中我们在不同的转换单元中有两个文件范围的对象,这是通过初始化顺序fiasco的未定义行为的常规设置:
a.hpp:
struct thing {
public:
thing(int value);
~thing();
int value() const;
static int count();
private:
int _value;
};
Run Code Online (Sandbox Code Playgroud)
a.cpp:
#include "a.hpp"
#include <atomic>
namespace {
std::atomic<int> things;
}
thing::thing(int value) : _value(value) {
++things;
}
thing::~thing() {
--things;
}
int thing::value() const {
return _value;
}
int thing::count() {
return things.load();
}
Run Code Online (Sandbox Code Playgroud)
b.cpp:
#include <iostream>
#include "a.hpp"
namespace {
thing static_thing(42);
}
void foo() {
std::cout << static_thing.value() << ' ' << thing::count() << '\n';
} …Run Code Online (Sandbox Code Playgroud) 代码库有一个COMPILER_BARRIER定义为的宏__asm__ volatile("" ::: "memory").宏的目的是防止编译器跨屏障重新排序读取和写入.请注意,这显然是编译器障碍,而不是处理器级别的内存障碍.
因此,这是相当便携的,因为AssemblerTemplate中没有实际的汇编指令,只有volatile和memoryclobber.因此,只要编译器遵循GCC扩展Asm语法,它就可以正常工作.尽管如此,我很好奇如果可能的话,在C++ 11 atomics API中表达它的正确方法是什么.
以下似乎可能是正确的想法:atomic_signal_fence(memory_order_acq_rel);.
我的理由是:
<atomic>API中,仅需要atomic_signal_fence并且atomic_thread_fence不需要用于操作的存储器地址.atomic_thread_fence 影响内存排序,我们不需要编译器障碍.memoryExtended Asm版本中的clobber不区分读取和写入,因此看起来我们需要获取和释放语义,因此memory_order_acq_rel似乎至少需要.memory_order_seq_cst 似乎没必要,因为我们不需要跨线程的总顺序 - 我们只对当前线程中的指令排序感兴趣.是否有可能__asm__ volatile("" ::: "memory")用C++ 11 atomics API 表达完全可移植的等价物?如果是这样,是否atomic_signal_fence使用正确的API?如果是这样,这里适当/需要什么内存顺序参数?
或者,我在这里的杂草中,有一个更好的方法来解决这个问题吗?
我想明白为什么内联函数的libc ++可见性宏使用__forceinline或__attribute__((__always_inline__))作为与内联函数关联的属性的一部分.
有关背景,请参阅
如果这些内联函数将被标记为__visibility__("hidden")无论如何,为什么还需要强制编译器内联它们?
我已经考虑了一下,我有一些假设,但似乎没有一个对我完全满意:
hidden属性不足够吗?同样,在构建库时是否只需要强制内联函数?消费者不应该在意.visibility("hidden")吗?我问这个是因为我正在构建一个C++库,我希望有一天能够标准化ABI,我正在使用libc ++作为指导.到目前为止,它运作良好,但这个问题引起了一些人头疼.
特别是,我们有报道称用户抱怨MSVC拒绝遵守该__forceinline属性,从而导致警告.我们提出的解决方案是__forceinline在构建库时将模拟扩展到INLINE_VISIBILITY仅包括(或GCC等效),假设上面的第一个解释.
但是,由于我们并不完全相信我们理解强制内联函数背后的原因,__forceinline或者__attribute__((__always_inline__))首先,我们对采用这种解决方案有点犹豫不决.
任何人都可以提供一个明确的答案,为什么libc ++需要强制内联其内联函数,即使它们已被装饰为具有隐藏的可见性?
我正在使用NDK为Android构建armv8a SDK,我想在启用LTO的情况下构建.我添加-flto到C++工具链的编译和链接标志,一切顺利,直到我试图在模拟器中运行,此时发出如下错误:
WARNING: linker: /data/lib/libservice.so: unused DT entry: type 0x6ffffef6 arg 0x8e30
和
WARNING: linker: /data/lib/libservice.so: unused DT entry: type 0x6ffffef7 arg 0x2fb50
一些研究让我得到了这个答案,这个答案让我能够挖出符号名称,0x6ffffef6并且0x6ffffef6它们分别恰好TLSDESC_PLT和TLSDESC_GOT动态链接器和PLT/GOT以及TLS有关.精细.
将非LTO构建与LTO构建进行比较,这些标志肯定只适用于LTO构建:
$ readelf -a /lto/lib/libservice.so | grep TLS
L (link order), O (extra OS processing required), G (group), T (TLS),
TLS 0x000000000001ed70 0x000000000002ed70 0x000000000002ed70
0x000000006ffffef6 (TLSDESC_PLT) 0x8e30
0x000000006ffffef7 (TLSDESC_GOT) 0x2fb50
00000002ffd8 000000000407 R_AARCH64_TLSDESC 0
00000002ffe8 000000000407 R_AARCH64_TLSDESC 8
579: 0000000000000008 8 TLS …
在构建C++ DLL或共享库时,__attribute__((__visibility__("default")))或__declspec(dllexport)经常通过宏附加到应该为库的使用者提供的具体符号(类,函数等)时,其他符号默认为具有内部可见性.
但是应该如何处理内联函数或模板?
似乎对于内联函数,答案应该是不需要注释.如果定义内联函数的标题的使用者实际内联函数,则不需要符号.如果消费者发出了一个外线定义,那仍然可以.唯一的缺点是DLL内部和每个消费库内部的内联函数的定义可能不同.所以,如果你期望可靠地比较内联函数的地址,你可能会遇到麻烦,但无论如何这看起来都很粗略.
鉴于该论点,似乎因为模板主体通常对于消费TU完全可见,所以应用相同的逻辑.
我觉得这里可能存在一些关于'extern模板'和显式实例化的细微之处.
有没有人对可见性属性如何遵循内联函数和模板有具体的指导?
显然,与XCode捆绑在一起的clang不尊重上游__clang_major__和__clang_minor__值,而是报告某种面向XCode用户的版本.
以下是clang的各种MacPorts安装的参考值.他们似乎尊重上游版本标识符.在Linux上测试时,我得到类似的值.
? prohibit-clang-3.2 /opt/local/bin/clang++-mp-3.2 -dM -E -x c /dev/null |
grep __clang_m
#define __clang_major__ 3
#define __clang_minor__ 2
? prohibit-clang-3.2 /opt/local/bin/clang++-mp-3.3 -dM -E -x c /dev/null |
grep __clang_m
#define __clang_major__ 3
#define __clang_minor__ 3
? prohibit-clang-3.2 /opt/local/bin/clang++-mp-3.4 -dM -E -x c /dev/null |
grep __clang_m
#define __clang_major__ 3
#define __clang_minor__ 4
Run Code Online (Sandbox Code Playgroud)
但是,出于某种原因,Apple提供了clang has __clang_major__和__clang_minor__跟踪XCode版本的版本,而不是基本的clang版本:
? prohibit-clang-3.2
/Applications/Xcode-4.6.3.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++
-dM -E -x c /dev/null | grep __clang_m
#define __clang_major__ 4
#define __clang_minor__ 2 …Run Code Online (Sandbox Code Playgroud) 在C++ 11中,我的理解是默认情况下析构函数是隐式的noexcept(true),除了:
如果我有一个C明确标记了析构函数的类noexcept(false)(可能是因为它因某些奇怪的原因而抛出,我知道你不应该这样做,以及为什么)那么派生自C或包含类型成员的任何类的析构函数C也成了noexcept(false).
然而,其中包含了一个类std::shared_ptr<C>显然并不自动拥有它的析构函数切换到noexcept(false),并且同样适用于含有std::weak_ptr<C>,std::unique_ptr<C>等等.
这是一个完整的例子:
#include <type_traits>
#include <memory>
struct Normal {
~Normal() {
}
};
struct ThrowsInDtor {
~ThrowsInDtor() noexcept(false) {
throw 42;
}
};
template<typename T>
struct Wrapper {
T t;
};
template<typename T>
struct UniquePtrWrapper {
std::unique_ptr<T> t;
};
template<typename T>
struct SharedPtrWrapper {
std::shared_ptr<T> t;
};
static_assert(std::is_nothrow_destructible<Normal>::value, "A"); // OK
static_assert(!std::is_nothrow_destructible<ThrowsInDtor>::value, "B"); // OK
static_assert(std::is_nothrow_destructible<Wrapper<Normal>>::value, "C"); …Run Code Online (Sandbox Code Playgroud) 根据此演示文稿,如果复制构造函数或复制赋值运算符是"用户声明的",则不会生成隐式移动操作.请问delete荷兰国际集团的拷贝构造函数或拷贝赋值运算符计数为"用户声明"?
struct NoCopy {
NoCopy(NoCopy&) = delete;
NoCopy& operator=(const NoCopy&) = delete;
};
Run Code Online (Sandbox Code Playgroud)
是否会为NoCopy类生成隐式移动操作?或者删除相关的复制操作是否计为"用户声明",从而禁止隐式移动生成?
如果可能的话,我更愿意参考标准的相关部分.
我想并排安装XCode,并使用DEVELOPER_DIR环境变量在它们之间进行选择.这样做的目的是使用结果xcrun -f --sdk macosx clang来确定适当的C编译器,然后在脚本或构建系统中使用它.
CC=$(DEVELOPER_DIR=<something> xcrun -f --sdk macosx clang)
我的问题是DEVELOPER_DIR,在使用找到的工具时是否需要保持设置xcrun,或者是否可以在执行期间设置它xcrun,如上所述,然后在默认环境中使用返回的工具,而不进行DEVELOPER_DIR设置.
换句话说,虽然xcrun显然确实取决于价值DEVELOPER_DIR,但工具本身也依赖于它吗?两者之间有什么有意义的区别:
DEVELOPER_DIR=<whatever> command CC=$(xcrun -f --sdk macosx clang)command CC=$(DEVELOPER_DIR=<whatever> xcrun -f --sdk macosx clang)第二个是正确的吗?还是只有第一个?
如果有人提出并回答了这个问题,我深表歉意。将其重定向到可以回答这个问题的规范资源将是非常不错的。
我最近收到了一个请求,要求提供我为iOS维护的项目的构建,这不是我熟悉的平台。特别是,我不是应用程序开发人员,从未向App Store提交过应用程序,等等。该项目提供了标准的C ++ 11 SDK:某些标头和某些库,已安装为autoconf样式$PREFIX/include和$PREFIX/lib目录。要满足请求,就需要提供针对iOS的预构建二进制文件和标头。出于本文的目的,假设我可以限制为更新的iOS,例如iOS 10.2+。
对于非IOS开发人员而言,此SDK的典型交付方式传统上是作为标头和一组动态链接的库。该项目是围绕动态链接设计的,因此对于许多用户来说效果很好。
但是,我的搜索导致关于是否完全可以在iOS上以这种方式使用动态库以及如果打算提供以iOS为目标的SDK时正确的传递机制/格式是什么的信息相互矛盾。
我有几个问题:
第一个问题:完全有可能提供一个包含动态库(dylib)的SDK,以便应用程序开发人员可以针对该SDK构建其应用程序,并将dylib与他们的应用程序打包在一起,从而产生一些可以包含在应用程序中的东西商店。
第二个问题:如果以上问题的答案为“是”,是否有具体限制?我已经看到一些信息,表明只有当动态库形成框架(框架捆绑包?)时,才有可能。有人知道我可能会以此模型发布的任何开源SDK吗?
第三个问题:如果我要交付静态SDK,我相信作为SDK开发人员,代码签名对我来说不是问题,因为应用程序开发人员使用自己的密钥对最终生成的工件进行签名,并且由于它们也在签名,因此可以正常工作他们从静态库中获取的任何位。在我看来,如果有可能交付动态SDK,那么对工件进行代码签名的负担就会转移到我身上。我有正确的吗?是否可以交付其中不同部分具有不同签名密钥的应用程序(例如,如果我签名SDK dylib,并且应用程序开发人员签署了他们的应用程序位,情况就是这样)?
第四个问题:将SDK作为dylib交付会对希望为其构建应用程序的人们的可用性产生不利影响吗?如果是这样,怎么办?
请注意,我并不是在问是否可以使用dlopen一个库,还是下载动态代码并使用它等等。我的理解是,出于相当明显的原因,那是禁止的。这里的用例旨在使开发的应用程序具有引用SDK dylib的显式加载命令。同样,我也不想绕过Apple的任何限制:我只是想得到一个答案,让我知道什至尝试将这个SDK作为一组dylib交付是否有意义,或者是否应该重定向我的致力于生成静态版本的SDK。
c++ ×8
c++11 ×4
clang ×2
dll ×2
xcode ×2
abi ×1
android ×1
android-ndk ×1
arm ×1
atomicity ×1
barrier ×1
code-signing ×1
destructor ×1
dylib ×1
elf ×1
ios ×1
libc++ ×1
linker ×1
macos ×1
move ×1
noexcept ×1
portability ×1
static ×1
visibility ×1
xcrun ×1