Skip to main content
 首页 » 编程设计

xcode之为什么当 'official' clang 支持 C++11 thread_local 时,Apple clang 不允许它

2024年12月31日8luoye11

下面是一个简单的程序,它使用共享库中的非 POD 类型的 C++11 thread_local 变量进行测试。

如果我使用自制的 clang ,这很好用:

> /usr/local/Cellar/llvm/3.5.0_2/bin/clang --version                                           
clang version 3.5.0 (tags/RELEASE_350/final) 
Target: x86_64-apple-darwin14.0.0 
Thread model: posix 
 
> cmake .. -G Ninja -DCMAKE_C_COMPILER=/usr/local/Cellar/llvm/3.5.0_2/bin/clang -DCMAKE_CXX_COMPILER=/usr/local/Cellar/llvm/3.5.0_2/bin/clang++ 
-- The C compiler identification is Clang 3.5.0 
-- The CXX compiler identification is Clang 3.5.0 
-- Check for working C compiler using: Ninja 
-- Check for working C compiler using: Ninja -- works 
-- Detecting C compiler ABI info 
-- Detecting C compiler ABI info - done 
-- Check for working CXX compiler using: Ninja 
-- Check for working CXX compiler using: Ninja -- works 
-- Detecting CXX compiler ABI info 
-- Detecting CXX compiler ABI info - done 
-- Configuring done 
-- Generating done 
> ninja all 
...                                                                                       
 
>  ./main                                                                                        
XXX LifeCycle::LifeCycle 0x7fedc0c04b90 
X before: -17 
XXX LifeCycle::LifeCycle 0x7fedc0c04c10 
X before in thread: -17 
X after in thread: 2 
XXX LifeCycle::~LifeCycle 0x7fedc0c04c10 
X after: 1 
XXX LifeCycle::~LifeCycle 0x7fedc0c04b90 

但是,如果我尝试使用 Apple Clang,我会收到一条错误消息,指出它不受支持:
> /usr/bin/clang --version 
Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn) 
Target: x86_64-apple-darwin14.0.0 
Thread model: posix 
> cmake .. -G Ninja -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++ 
-- The C compiler identification is AppleClang 6.0.0.6000056 
-- The CXX compiler identification is AppleClang 6.0.0.6000056 
-- Check for working C compiler using: Ninja 
-- Check for working C compiler using: Ninja -- works 
-- Detecting C compiler ABI info 
-- Detecting C compiler ABI info - done 
-- Check for working CXX compiler using: Ninja 
-- Check for working CXX compiler using: Ninja -- works 
-- Detecting CXX compiler ABI info 
-- Detecting CXX compiler ABI info - done 
-- Configuring done 
-- Generating done 
-- Build files have been written to: 
 
> ninja all 
[1/4] Building CXX object CMakeFiles/lib.dir/lib.cpp.o 
FAILED: /usr/bin/clang++   -Dlib_EXPORTS -Wall -std=c++11 -mmacosx-version-min=10.7 -stdlib=libc++ -fPIC -MMD -MT CMakeFiles/lib.dir/lib.cpp.o -MF CMakeFiles/lib.dir/lib.cpp.o.d -o CMakeFiles/lib.dir/lib.cpp.o -c ../lib.cpp 
../lib.cpp:23:5: error: thread-local storage is unsupported for the current target 
    thread_local LifeCycle lc; 
    ^ 
1 error generated. 
ninja: build stopped: subcommand failed. 

任何人都可以提供任何见解,尽管底层编译器支持它,并且生成的代码似乎可以工作,但为什么 Apple 的 clang 变体懦弱地拒绝尊重 thread_local?

库.h:
#pragma once 
 
int doit(int) __attribute__((__visibility__("default"))); 

lib.cpp:
#include "lib.h" 
 
#include <thread> 
#include <cstdlib> 
#include <cstdio> 
 
namespace { 
 
    class LifeCycle { 
    public: 
        LifeCycle() 
            : x(-17) { 
            printf("XXX LifeCycle::LifeCycle %p\n", this); 
        } 
 
        ~LifeCycle() { 
            printf("XXX LifeCycle::~LifeCycle %p\n", this); 
        } 
 
        int x; 
    }; 
 
    thread_local LifeCycle lc; 
} // namespace 
 
int doit(int arg) { 
    printf("X before: %d\n", lc.x); 
    lc.x = arg; 
    std::thread xwriter([arg]() { 
            if (lc.x == arg) 
                abort(); 
            printf("X before in thread: %d\n", lc.x); 
            lc.x = arg + 1; 
            printf("X after in thread: %d\n", lc.x); 
        }); 
    xwriter.join(); 
    printf("X after: %d\n", lc.x); 
    return (lc.x == arg ? EXIT_SUCCESS : EXIT_FAILURE); 
} 

主.cpp:
#include "lib.h" 
 
int main(int argc, char* argv[]) { 
    return doit(argc); 
} 

CMakeLists.txt:
cmake_minimum_required(VERSION 3.1) 
 
set(CMAKE_CXX_FLAGS "-Wall -std=c++11 -mmacosx-version-min=10.7 -stdlib=libc++") 
 
add_library(lib SHARED lib.cpp) 
add_executable(main main.cpp) 
target_link_libraries(main lib) 

请您参考如下方法:

Xcode 8 及更高版本中包含的 clang 编译器支持 C++11 thread_local关键词。此功能已添加到 Xcode 8 beta 中,如 the WWDC 2016 video "What's New in LLVM" 中所述。 , 从 the 5:50 mark 开始. ( external transcript )

问题中列出的示例程序在 OS X 10.11.6 下使用 Xcode 8 GM 编译和运行,并产生预期的输出。它随后在 macOS 10.13.4 下的 Xcode 9.3 和 macOS 10.14.4 下的 Xcode 10.2.1 进行了重新测试,并继续按预期运行。

关于iOS,我通过实验发现thread_local支持 iOS 9 及更高版本,但不支持 iOS 8.4 或更早版本。

对于 Xcode 7.x 及更早版本,以下是 2014 年 Apple 工程师在旧 Apple Developer Forum(不再可访问)上的回答:

We don't support the thread_local implementation from the open-source Clang because we believe we can provide a higher-performance implementation for our platforms using various features in the dynamic linker. Such an implementation would be ABI-incompatible with the implementation in the open-source Clang, so we won't support thread_local until we get an implementation we can live with for the foreseeable future.



随后的帖子证实 thread_local Xcode 6.3 中仍然不支持。