我在项目中大量使用c ++ 0x/c ++ 11特性,特别是代码块和共享指针.当我将操作系统升级到10.8 Mountain Lion(编辑:从10.7开始)时,我被迫升级Xcode.在升级Xcode时,我失去了编译我的c ++项目以便在10.6系统上部署的能力,因为我收到以下错误.
clang: error: invalid deployment target for -stdlib=libc++ (requires Mac OS X 10.7 or later)
苹果似乎试图通过不允许开发者支持Snow Leopard来强迫人们进行升级.这让我很生气.Arrrggg!
我能做什么?
编辑:经过几次来回评论后,应该明确10.6不附带系统libc ++库.因此,仅仅为10.6部署构建libc ++项目是不够的.您还需要在您的10.6发行版中包含libc ++二进制文件,或者静态链接到它们.所以让我们继续我已经在做的那个前提.
更新1:此问题最初打算用于Xcode 4.5.2(问题提出时的最新版本).我已经升级到Xcode 4.6.3并更新了问题和答案以反映这一点.
更新2:我已经升级到Xcode 5.0.2.以下所选答案中列出的技术仍可按预期工作.
更新3:我已经升级到Xcode 5.1.下面的答案中列出的技术尚不适用于此版本!
更新4:我已经升级到Xcode 6.0.1.以下所选答案中列出的技术似乎再次起作用.
更新5:我已经升级到Xcode 7.1.1.下面选定答案中列出的技术似乎再次起作用,但有一个重要的警告.您必须禁用Bitcoding用于AppThinning因为开源LLVM版本不支持它(也不应该).因此,您需要在开源和Apple LLVM clang之间切换,以便为10.6和tvOS/watchOS进行编译(因为这些操作系统需要Bitcoding).
直观地说,从C++规范来看,它看起来好像istream::putback( c )应该总是安排输入缓冲区,以便下一次调用istream::peek()应该读取字符c.这不正确吗?我问,因为随Xcode 4.6发布的最新版本的libc ++似乎并未在所有情况下强制执行此行为 - 特别是当最后一个字符位于EOF时.如果您使用unget()而不是,也是如此putback( c ).
libc ++的行为是正确的,还是我对如何putback()/unget()正确行事的直觉?
考虑这个示例代码,它与libstdc ++一起使用但不与libc ++一起使用(断言失败).
#include <sstream>
#include <cassert>
int main(int argc, const char * argv[])
{
std::istringstream in( "[Test]" );
while( in )
{
int c = in.get();
if( c == ']' )
{
in.putback( c );
assert( in.peek() == c ); // Fails with libc++. Succeeds with libstdc++.
break;
}
}
return 0;
}
Run Code Online (Sandbox Code Playgroud) 我注意到很多boost和libc ++/libstdc ++在代码中明确地为SFINAE提供了一个默认值零
// libc++ http://llvm.org/svn/llvm-project/libcxx/trunk/include/memory
namespace __has_pointer_type_imp
{
template <class _Up> static __two __test(...);
template <class _Up> static char __test(typename _Up::pointer* = 0);
}
template <class _Tp>
struct __has_pointer_type
: public integral_constant<bool, sizeof(__has_pointer_type_imp::__test<_Tp>(0)) == 1>
{
};
Run Code Online (Sandbox Code Playgroud)
然而,当我们明确地用0调用它时,为什么会出现这种情况让我感到困惑.我记得听到某个地方它是一个优化(在实例化模板时加速编译器)但我不完全理解它是如何工作的.我查看了标准,它有一个部分简要描述了与模板参数推导相关的default-arguments会发生什么.
14.8.2
在模板参数推导过程中的某些点,有必要采用一个使用模板参数的函数类型,并用相应的模板参数替换这些模板参数.当任何显式指定的模板参数被替换为函数类型时,这在模板参数推导的开始处完成,并且当替换从默认参数推导或获得的任何模板参数时,再次在模板参数推断的结尾处完成.
最后一点听起来与我的问题有关
并且在模板参数推断结束时再次替换从默认参数推导或获得的任何模板参数.
然而,如果必须做更多工作,这听起来与优化相反.有没有人有任何理由为什么0必须在那里,它没有它工作,但libc ++中的每个SFINAE例子至少似乎明确地把0放在那里,即使他们从不调用没有参数的函数.
我希望在一些现有的c ++项目中使用一些c ++ 11特性,所以我开始在一些项目中更改Clang中的编译标志,并且我一直在遇到关于C++ 11处理转换操作符(或者转换)的特定问题运算符)我没想到会看到并且不明白为什么现在这被认为是一个错误,因为它是有效的C++代码而不是c ++ 11
我把它归结为这个简单的例子:
#include <iostream>
#include <vector>
class SerializableFormat
{
public:
size_t i;
};
class A
{
public:
size_t x, y;
A(size_t n) : x(n), y(1) { }
operator const SerializableFormat() const
{
SerializableFormat result;
result.i = x;
if (y)
{
result.i /= y;
}
return result;
}
};
int main(int argc, const char * argv[])
{
std::vector<SerializableFormat> v;
for(size_t i = 0; i < 20; i++)
{
v.push_back(A(i));
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
-std=c++98 …经过大量努力,让clang和libc ++编译,运行,与NetBeans集成,甚至交叉编译到32位机器,我想我已经弄明白了!所以我去使用libstdc ++没有的一些功能(将我的开发环境颠倒过来的全部原因),并发现......我实际上无法做到这一点.
安装了libc ++,它可以运行,编译后的程序(当它工作时)确实需要它.但是,编译器仍然试图通过搞乱命名空间来抓住每个机会使用libstdc ++版本.std::__1::map,std::__1::basic_string等等.现在,我从这个问题中知道为什么会发生这种情况,以及为什么libc ++会这样做.我只需要知道如何删除它,因为它完全不适用 - 我真的,确实想要使用libc ++版本,我的代码中没有任何内容需要两种类型共存.
我已经尝试从包含路径中取出libstdc ++文件夹,并且失败了,这使得它们完全无法访问.没运气.我没有使用任何附加库,只使用内置的Linux/POSIX头文件(errno,socket,syslog,fcntl).
编辑:错误消息:
CoreCache.cpp:61:12: error: no member named 'emplace' in 'std::__1::map<std::__1::basic_string<char>, CacheEntry, std::__1::less<std::__1::basic_string<char> >, std::__1::allocator<std::__1::pair<const std::__1::basic_string<char>, CacheEntry> > >'
Run Code Online (Sandbox Code Playgroud)
libstdc ++地图没有emplace().libc中++版本呢.
从命令行调用以下似乎有效:
clang++ -o stachecache -I /usr/local/lib/clang/3.1/include/ -I /usr/include/c++/v1/ -std=c++0x -stdlib=libc++ ./*.cpp
Run Code Online (Sandbox Code Playgroud)
NetBeans中的调用不会:
clang++ -stdlib=libc++ -O3 -c -O3 -Werror -MMD -MP -MF build/Release/clang-Linux-x86/CoreCache.o.d -o build/Release/clang-Linux-x86/CoreCache.o CoreCache.cpp
Run Code Online (Sandbox Code Playgroud) 我尽可能地缩小了它,这似乎是一个错误......
#include <algorithm>
#include <vector>
int main(int argc, char *argv[])
{
// Crashes
std::vector<uint8_t> bs{1, 0, 0};
std::search_n(bs.begin(), bs.end(), 3, 1);
// Does not crash
std::vector<uint8_t> bs{1, 0};
std::search_n(bs.begin(), bs.end(), 2, 1);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我明白了
Segmentation fault: 11
Run Code Online (Sandbox Code Playgroud)
我希望我没有错误地使用std :: search_n :)
目前使用LLDB似乎无法单步执行STL实现.
版本信息:
$clang --version
Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn)
Target: x86_64-apple-darwin12.3.0
Thread model: posix
Run Code Online (Sandbox Code Playgroud)
证据;)
13:06:47 ~/bug$ cat bug.cc
#include <algorithm>
#include <vector>
int main(int argc, char *argv[])
{
std::vector<uint8_t> bs{1, 0, 0}; …Run Code Online (Sandbox Code Playgroud) 现在Mac OS X上可以存在多个C++标准库,现在看起来非常混乱.根据/sf/answers/592045961/,混合libstdc ++和libc ++将导致链接错误,这会捕获这样的危险情况并且是一件好事.
另一方面,还有两种情况需要更多调查,我在github gist(https://gist.github.com/manphiz/7195515)中为此创建了一些测试用例.它确认混合链接到libstdc ++(来自系统或vanilla GNU GCC)和libc ++(系统)的动态库将导致链接错误.但是,如果一个动态库链接到系统libstdc ++,而另一个动态库链接到vanilla GNU GCC libstdc ++,然后将它们链接到二进制文件也可以工作,对于我的简单测试用例,它甚至可以在运行时工作.
$ make -f Makefile.system_gnu
g++-4.8 -g -Wall -fPIC -o main.o -c main.cc
g++-4.8 -g -Wall -fPIC -o test_a.o -c test_a.cc
g++-4.8 -dynamiclib -o libtest_a.dylib test_a.o
clang++ -g -Wall -fPIC "-stdlib=libstdc++" -o test_b.o -c test_b.cc
clang++ -dynamiclib "-stdlib=libstdc++" -o libtest_b.dylib test_b.o
g++-4.8 -o test main.o -L. -ltest_a -ltest_b
$ ./test
main_test_a_test_b
Run Code Online (Sandbox Code Playgroud)
所以这里需要建议:
is_copy_constructible的libc ++实现是这样的:
template <class _Tp>
struct _LIBCPP_TYPE_VIS_ONLY is_copy_constructible
: public is_constructible<_Tp, const typename add_lvalue_reference<_Tp>::type>
{};
Run Code Online (Sandbox Code Playgroud)
is_copy_constructible的C++规范很简单:
std::is_copy_constructible specification: std::is_constructible<T, const T&>::value is true.
Run Code Online (Sandbox Code Playgroud)
但是,上面的实现不是实现T&const而不是const T&?将const应用于add_lvalue_reference应该没有任何效果,并且至少有一个编译器(EDG)以警告的形式识别它.
演示问题的示例程序:
#include <type_traits>
struct ProofTest
{
ProofTest(){}
ProofTest(const ProofTest&) = delete; // is_copy_constructible should use this.
ProofTest(ProofTest&){ } // But instead it's using this.
};
void Proof()
{
static_assert(std::is_copy_constructible<ProofTest>::value == false, "is_copy_constructible bug");
}
Run Code Online (Sandbox Code Playgroud)
在libstdc ++下,上面的代码编译正常,但在libc ++下,static_assert会触发.
以下是正确的修复方法吗?:
template <class _Tp>
struct _LIBCPP_TYPE_VIS_ONLY is_copy_constructible
: public is_constructible<_Tp, typename add_lvalue_reference<typename std::add_const<_Tp>::type>::type>
{};
Run Code Online (Sandbox Code Playgroud)
这也会影响其他一些libc ++类型的特征.
我在Ubuntu 14.04.1上安装了clang ++ 3.5,g ++ 4.9.1,libc ++和Qt Creator.
我通常使用clang ++作为编译器.但最近我发现的libstdc ++从G ++作为C++标准库.据我所知,后者目前尚未完全支持C++ 14的创新.
用clang ++编译项目时如何用libc ++替换libstd ++?
我已经做了什么(.pro-file):
QMAKE_CXXFLAGS_CXX11 = -std=gnu++1y
CONFIG *= c++11
QMAKE_CXXFLAGS += -stdlib=libc++
LIBS += -stdlib=libc++
Run Code Online (Sandbox Code Playgroud)
但是Qt Creator编辑器仍然使用libstdc ++来DEPENDPATH浏览包含的文件.如何解决这种不良行为?也许我应该在mkspec文件中修复一些东西?
我有一个小代码如下:
int main() {
double d;
const char* str = "26.50";
std::from_chars(str, str + strlen(str), d);
std::cout << d;
}
Run Code Online (Sandbox Code Playgroud)
此代码在 libstdc++ 中按预期工作,但在 libc++ 12.0.0 中失败并出现以下错误:
int main() {
double d;
const char* str = "26.50";
std::from_chars(str, str + strlen(str), d);
std::cout << d;
}
Run Code Online (Sandbox Code Playgroud)
这是 libc++ 的错误吗?或者我错过了什么?我应该说,如果我将数据类型从 更改为 ,这段代码就可以double工作int。