file(GLOB modules "${MODULES}/*.prx") if(NOT modules) message(FATAL_ERROR "no modules in ${MODULES}") endif() set(explicit "__cxa_thread_atexit_nid_postfix|__cxa_thread_atexit_impl_nid_postfix|LibcInternalExtCxaThreadAtexit_nid_postfix") set(failures "") foreach(module IN LISTS modules) get_filename_component(name "${module}" NAME) execute_process(COMMAND "${NM}" --defined-only "${module}" OUTPUT_VARIABLE symbols RESULT_VARIABLE result ERROR_QUIET) if(NOT result EQUAL 0 OR symbols STREQUAL "") list(APPEND failures "${name}: no symbol table to inspect") continue() endif() if(NOT symbols MATCHES " T __mingw_cxa_thread_atexit\n") continue() endif() execute_process(COMMAND "${OBJDUMP}" -d --no-show-raw-insn "${module}" OUTPUT_VARIABLE code RESULT_VARIABLE result ERROR_QUIET) if(NOT result EQUAL 0) list(APPEND failures "${name}: cannot disassemble") continue() endif() string(REGEX MATCHALL "\n[0-9a-f]+ <[^>\n]+>:|(call|jmp)[^\n]*<__cxa_thread_atexit>" lines "${code}") set(function "") foreach(line IN LISTS lines) if(line MATCHES "^\n[0-9a-f]+ <([^>\n]+)>:$") set(function "${CMAKE_MATCH_1}") elseif(NOT function MATCHES "^(${explicit})$") list(APPEND failures "${name}: ${function} registers a thread_local destructor") endif() endforeach() endforeach() if(failures) list(REMOVE_DUPLICATES failures) list(JOIN failures "\n " text) message(FATAL_ERROR "On Windows a thread_local destructor in a module runs after emulated TLS freed the object; keep such objects in HostThreadLocal:\n ${text}") endif() list(LENGTH modules count) message(STATUS "${count} modules register no thread_local destructors")