以下は、共有ライブラリで非PODタイプのC++ 11 thread_local変数を使用してテストする簡単なプログラムです。
私が自作のクランを使用する場合、これはうまくいきます:
> /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を尊重することを拒否する理由について洞察を提供できますか?
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)
Xcode 8以降に含まれているclangコンパイラは、C++ 11 thread_local
キーワードをサポートしています。 WWDC 2016ビデオ「What's New in LLVM」 で説明されているように、この機能はXcode 8ベータに追加され、 5:50マーク から始まります。 ( 外部筆記録 )
質問にリストされているサンプルプログラムは、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以前の場合、古いApple開発者フォーラム(アクセス不可)のAppleエンジニアからの2014年の回答は次のとおりです。
ダイナミックリンカーのさまざまな機能を使用して、プラットフォームに高性能の実装を提供できると考えているため、オープンソースのClangからのthread_local実装はサポートしていません。そのような実装はオープンソースのClangの実装とABI非互換であるため、近い将来に対応できる実装が得られるまで、thread_localはサポートされません。
その後の投稿で、Xcode 6.3ではthread_local
はまだサポートされていません。
によると http://clang.llvm.org/cxx_status.html :
thread_localサポートには現在、g ++-4.8以降のC++ランタイムライブラリが必要です
自作バージョンのclangは別のC++ランタイムを使用していると思います。