2015-01-22 7 views
22

Unten ist ein einfaches Programm, das Tests mit einer C++ 11 thread_local Variable vom Nicht-POD-Typ in einer gemeinsam genutzten Bibliothek.Warum verbietet Apple clang 11 C++ 11 thread_local, wenn 'offizielle' clang es unterstützt

Wenn ich Homebrew Klirren verwenden, das funktioniert gut:

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

Allerdings, wenn ich versuche, Apple-Clang zu verwenden, erhalte ich eine Fehlermeldung, dass es nicht unterstützt wird:

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

Kann irgendjemand irgendeinen Einblick geben, warum apples clang-Variante feigig ist, thread_local zu respektieren, trotz der Tatsache, dass der zugrundeliegende Compiler dies unterstützt und der generierte Code zu funktionieren scheint?

lib.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); 
} 

main.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) 
+1

@BrettHale Apples offizielle Veröffentlichung in XCode 6 basiert auf clang-3.5 und clang-3.5 unterstützt thread_local auf Darwin. Ich glaube, dass es früher in Releases als clang-3.5 getan hat. – acm

+1

Wahrscheinlich ein Fehler: http://StackOverflow.com/a/23850891/1392778 – Thomas

Antwort

36

UPDATE: Der in den Xcode 8 Beta und GM-Versionen enthaltene clang-Compiler unterstützt das Schlüsselwort C++ 11 thread_local. Diese Fähigkeit wurde in the WWDC 2016 video "What's New in LLVM", beginnend mit the 5:50 mark diskutiert. (external transcript)

Das in der Frage aufgelistete Beispielprogramm kompiliert und läuft mit Xcode 8 GM unter OS X 10.11.6 und produziert die beabsichtigte Ausgabe.

In Bezug auf iOS habe ich durch Experimente herausgefunden, dass thread_local für iOS 9 und höher unterstützt wird, aber nicht für iOS 8.4 oder früher.


Für Xcode 7.x und früher, hier ist eine Antwort ab 2014 von einem Apple-Ingenieure auf dem alten Developer Forum von Apple (nicht mehr zugänglich):

Wir unterstützen nicht die thread_local Implementierung von der Open-Source- Clang, weil wir glauben, dass wir eine leistungsfähigere Implementierung für unsere Plattformen mit verschiedenen Funktionen in der dynamischen Linker bereitstellen können. Solch eine Implementierung wäre ABI-inkompatibel mit der Implementierung im Open-Source-Clang, also werden wir thread_local nicht unterstützen, bis wir eine Implementierung bekommen, mit der wir für die vorhersehbare Zukunft leben können.

Ein nachfolgender Post bestätigt, dass thread_local in Xcode 6.3 noch nicht unterstützt wird.

+37

Sie möchten die ABI-Kompatibilität * für eine bestimmte Funktion * nicht aufheben, damit sie diese Funktion nicht bieten? Das ist mental. –

+8

Das ist wirklich bedauerlich. Das bedeutet, dass Sie thread_local in portable C++ 11 noch nicht verwenden können, auch wenn VC14 dies unterstützt. Wenn es irgendwelche Ingenieure von Apple gibt, die das lesen, hoffe ich wirklich, dass Sie planen, das bald zu reparieren. – acm

+0

@KonradRudolph, arbeiten sie in einer besseren Funktion, die mit der vorhandenen Implementierung ABI-inkompatibel wäre, so dass sie die vorhandene Implementierung nicht unterstützen. Wenn sie es unterstützten und es später wegen ihrer besseren Implementierung fallen ließen, würde ich wetten, dass Sie sich noch mehr darüber beschweren würden, wie sie sich entscheiden sollten und die schlechtere Option für immer unterstützen sollten. – hmijail

1

Nach http://clang.llvm.org/cxx_status.html:

thread_local Unterstützung erfordert derzeit die C++ Laufzeitbibliothek von g ++ - 4.8 oder höher

Ich glaube, dass die Homebrew-Version von Klirren eine andere C++ Laufzeit verwendet.

+4

Sowohl XCode und Homebrew Clang sind in der Lage, sowohl libstdC++ als auch libC++ zu verwenden. Da OS X nur ein GCC 4.1 vintage libstdC++ enthält, ist es ein Nicht-Starter für C++ 11. Also, ich benutze definitiv libC++. Dennoch beantwortet es nicht die Frage, warum das Homebrew-Clang mit libC++ thread_local verwenden kann, aber der XCode-Clam mit libC++ kann nicht. – acm

+1

Dies könnte besser als Kommentar anstelle einer Antwort geschrieben worden sein. Ich stelle mir vor @HowardHinnant kennt den wahren Grund. – sbooth

+1

„Glendower: ich Geister aus dem vasty tief nennen Hotspur: Warum, so kann ich das, oder kann so ein Mensch, Aber werden sie kommen, wenn Sie sie nennen?“ – acm

Verwandte Themen