Index: autoconf/configure.ac =================================================================== --- autoconf/configure.ac +++ autoconf/configure.ac @@ -1399,6 +1399,7 @@ if test "$llvm_cv_os_type" = "MingW" ; then AC_CHECK_LIB(imagehlp, main) AC_CHECK_LIB(psapi, main) + AC_CHECK_LIB(shell32, main) fi dnl dlopen() is required for plugin support. Index: cmake/config-ix.cmake =================================================================== --- cmake/config-ix.cmake +++ cmake/config-ix.cmake @@ -415,6 +415,7 @@ if( MINGW ) set(HAVE_LIBIMAGEHLP 1) set(HAVE_LIBPSAPI 1) + set(HAVE_LIBSHELL32 1) # TODO: Check existence of libraries. # include(CheckLibraryExists) # CHECK_LIBRARY_EXISTS(imagehlp ??? . HAVE_LIBIMAGEHLP) Index: cmake/modules/LLVM-Config.cmake =================================================================== --- cmake/modules/LLVM-Config.cmake +++ cmake/modules/LLVM-Config.cmake @@ -2,7 +2,7 @@ # Returns in `return_var' a list of system libraries used by LLVM. if( NOT MSVC ) if( MINGW ) - set(system_libs ${system_libs} imagehlp psapi) + set(system_libs ${system_libs} imagehlp psapi shell32) elseif( CMAKE_HOST_UNIX ) if( HAVE_LIBRT ) set(system_libs ${system_libs} rt) Index: cmake/modules/TableGen.cmake =================================================================== --- cmake/modules/TableGen.cmake +++ cmake/modules/TableGen.cmake @@ -128,7 +128,7 @@ endif() if( MINGW ) - target_link_libraries(${target} imagehlp psapi) + target_link_libraries(${target} imagehlp psapi shell32) if(CMAKE_SIZEOF_VOID_P MATCHES "8") set_target_properties(${target} PROPERTIES LINK_FLAGS -Wl,--stack,16777216) endif(CMAKE_SIZEOF_VOID_P MATCHES "8") Index: configure =================================================================== --- configure +++ configure @@ -12084,6 +12084,87 @@ fi + +{ echo "$as_me:$LINENO: checking for main in -lshell32" >&5 +echo $ECHO_N "checking for main in -lshell32... $ECHO_C" >&6; } +if test "${ac_cv_lib_shell32_main+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lshell32 $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + +int +main () +{ +return main (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_shell32_main=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_shell32_main=no +fi + +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_shell32_main" >&5 +echo "${ECHO_T}$ac_cv_lib_shell32_main" >&6; } +if test $ac_cv_lib_shell32_main = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBSHELL32 1 +_ACEOF + + LIBS="-lshell32 $LIBS" + +fi + fi { echo "$as_me:$LINENO: checking for library containing dlopen" >&5 Index: include/llvm/Config/config.h.cmake =================================================================== --- include/llvm/Config/config.h.cmake +++ include/llvm/Config/config.h.cmake @@ -203,6 +203,9 @@ /* Define to 1 if you have the `pthread' library (-lpthread). */ #cmakedefine HAVE_LIBPTHREAD ${HAVE_LIBPTHREAD} +/* Define to 1 if you have the `shell32' library (-lshell32). */ +#cmakedefine HAVE_LIBSHELL32 ${HAVE_LIBSHELL32} + /* Define to 1 if you have the `udis86' library (-ludis86). */ #undef HAVE_LIBUDIS86 Index: include/llvm/Config/config.h.in =================================================================== --- include/llvm/Config/config.h.in +++ include/llvm/Config/config.h.in @@ -217,6 +217,9 @@ /* Define to 1 if you have the `pthread' library (-lpthread). */ #undef HAVE_LIBPTHREAD +/* Define to 1 if you have the `shell32' library (-lshell32). */ +#undef HAVE_LIBSHELL32 + /* Define to 1 if you have the `udis86' library (-ludis86). */ #undef HAVE_LIBUDIS86 Index: include/llvm/Support/Process.h =================================================================== --- include/llvm/Support/Process.h +++ include/llvm/Support/Process.h @@ -25,7 +25,9 @@ #ifndef LLVM_SUPPORT_PROCESS_H #define LLVM_SUPPORT_PROCESS_H +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/OwningPtr.h" #include "llvm/Config/llvm-config.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/TimeValue.h" @@ -168,6 +170,13 @@ // string. \arg Name is assumed to be in UTF-8 encoding too. static Optional GetEnv(StringRef name); + /// This function, given arguments passed to main, returns arguments suitable + /// for program execution. + static Optional > + GetArgumentVector(ArrayRef OriginalMainArgs, + OwningArrayPtr &NewArgVectorPointers, + std::vector &NewArgVectorStrings); + /// This function determines if the standard input is connected directly /// to a user's input (keyboard probably), rather than coming from a file /// or pipe. Index: lib/Support/Unix/Process.inc =================================================================== --- lib/Support/Unix/Process.inc +++ lib/Support/Unix/Process.inc @@ -190,6 +190,12 @@ return std::string(Val); } +Optional > +Process::GetArgumentVector(ArrayRef OriginalArgVector, + OwningArrayPtr &, std::vector &) { + return OriginalArgVector; +} + bool Process::StandardInIsUserInput() { return FileDescriptorIsDisplayed(STDIN_FILENO); } Index: lib/Support/Windows/DynamicLibrary.inc =================================================================== --- lib/Support/Windows/DynamicLibrary.inc +++ lib/Support/Windows/DynamicLibrary.inc @@ -83,8 +83,15 @@ // This is mostly to ensure that the return value still shows up as "valid". return DynamicLibrary(&OpenedHandles); } + + SmallVector filenameUnicode; + if (error_code ec = windows::UTF8ToUTF16(filename, filenameUnicode)) { + SetLastError(ec.value()); + MakeErrMsg(errMsg, std::string(filename) + ": Can't convert to UTF-16: "); + return DynamicLibrary(); + } - HMODULE a_handle = LoadLibrary(filename); + HMODULE a_handle = LoadLibraryW(filenameUnicode.data()); if (a_handle == 0) { MakeErrMsg(errMsg, std::string(filename) + ": Can't open : "); Index: lib/Support/Windows/Path.inc =================================================================== --- lib/Support/Windows/Path.inc +++ lib/Support/Windows/Path.inc @@ -128,7 +128,7 @@ BYTE val = 0; if (!::CryptGenRandom(CryptoProvider, 1, &val)) return windows_error(::GetLastError()); - random_path_utf16.push_back("0123456789abcdef"[val & 15]); + random_path_utf16.push_back(L"0123456789abcdef"[val & 15]); } else random_path_utf16.push_back(*i); @@ -257,6 +257,8 @@ goto retry_cur_dir; } + // On success, GetCurrentDirectoryW returns the number of characters not + // including the null-terminator. cur_path.set_size(len); return UTF16ToUTF8(cur_path.begin(), cur_path.size(), result); } Index: lib/Support/Windows/Process.inc =================================================================== --- lib/Support/Windows/Process.inc +++ lib/Support/Windows/Process.inc @@ -16,13 +16,18 @@ #include #include #include +#include #ifdef __MINGW32__ #if (HAVE_LIBPSAPI != 1) #error "libpsapi.a should be present" #endif + #if (HAVE_LIBSHELL32 != 1) + #error "libshell32.a should be present" + #endif #else - #pragma comment(lib, "psapi.lib") +#pragma comment(lib, "psapi.lib") +#pragma comment(lib, "Shell32.lib") #endif //===----------------------------------------------------------------------===// @@ -170,6 +175,45 @@ return std::string(&Res[0]); } +Optional > +Process::GetArgumentVector(ArrayRef, + OwningArrayPtr &NewArgVectorPointers, + std::vector &NewArgVectorStrings) { + int NewArgCount; + error_code ec; + + wchar_t **UnicodeCommandLine = + CommandLineToArgvW(GetCommandLineW(), &NewArgCount); + if (!UnicodeCommandLine) + return None; + + SmallVector StringOffsets; + StringOffsets.reserve(NewArgCount); + + for (int i = 0; i < NewArgCount; ++i) { + SmallVector NewArgString; + ec = windows::UTF16ToUTF8(UnicodeCommandLine[i], + wcslen(UnicodeCommandLine[i]), NewArgString); + if (ec) + break; + + StringOffsets.push_back(NewArgVectorStrings.size()); + NewArgVectorStrings.insert(NewArgVectorStrings.end(), NewArgString.begin(), + NewArgString.end()); + NewArgVectorStrings.push_back(0); + } + LocalFree(UnicodeCommandLine); + if (ec) + return None; + + NewArgVectorPointers.reset(new char *[NewArgCount + 1]); + for (int i = 0; i < NewArgCount; ++i) + NewArgVectorPointers[i] = NewArgVectorStrings.data() + StringOffsets[i]; + NewArgVectorPointers[NewArgCount] = 0; + + return ArrayRef(NewArgVectorPointers.get(), NewArgCount); +} + bool Process::StandardInIsUserInput() { return FileDescriptorIsDisplayed(0); } Index: lib/Support/Windows/Program.inc =================================================================== --- lib/Support/Windows/Program.inc +++ lib/Support/Windows/Program.inc @@ -42,42 +42,41 @@ // At this point, the file name is valid and does not contain slashes. // Let Windows search for it. - std::string buffer; - buffer.resize(MAX_PATH); - char *dummy = NULL; - DWORD len = SearchPath(NULL, progName.c_str(), ".exe", MAX_PATH, - &buffer[0], &dummy); + SmallVector buffer; + SmallVector progNameUnicode; + wchar_t *dummy = NULL; + if (windows::UTF8ToUTF16(progName, progNameUnicode)) + return ""; + +retry_search_path: + DWORD len = SearchPathW(NULL, progNameUnicode.data(), L".exe", + buffer.capacity(), buffer.data(), &dummy); // See if it wasn't found. if (len == 0) return ""; - // See if we got the entire path. - if (len < MAX_PATH) - return buffer; - // Buffer was too small; grow and retry. - while (true) { - buffer.resize(len+1); - DWORD len2 = SearchPath(NULL, progName.c_str(), ".exe", len+1, &buffer[0], &dummy); - - // It is unlikely the search failed, but it's always possible some file - // was added or removed since the last search, so be paranoid... - if (len2 == 0) - return ""; - else if (len2 <= len) - return buffer; - - len = len2; + if (len > buffer.capacity()) { + buffer.reserve(len); + goto retry_search_path; } + + buffer.set_size(len); + SmallVector result; + if (windows::UTF16ToUTF8(buffer.begin(), buffer.size(), result)) + return ""; + + return std::string(result.data(), result.size()); } static HANDLE RedirectIO(const StringRef *path, int fd, std::string* ErrMsg) { HANDLE h; if (path == 0) { - DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd), - GetCurrentProcess(), &h, - 0, TRUE, DUPLICATE_SAME_ACCESS); + if (!DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd), + GetCurrentProcess(), &h, + 0, TRUE, DUPLICATE_SAME_ACCESS)) + return INVALID_HANDLE_VALUE; return h; } @@ -92,9 +91,13 @@ sa.lpSecurityDescriptor = 0; sa.bInheritHandle = TRUE; - h = CreateFile(fname.c_str(), fd ? GENERIC_WRITE : GENERIC_READ, - FILE_SHARE_READ, &sa, fd == 0 ? OPEN_EXISTING : CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, NULL); + SmallVector fnameUnicode; + if (windows::UTF8ToUTF16(fname, fnameUnicode)) + return INVALID_HANDLE_VALUE; + + h = CreateFileW(fnameUnicode.data(), fd ? GENERIC_WRITE : GENERIC_READ, + FILE_SHARE_READ, &sa, fd == 0 ? OPEN_EXISTING : CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL); if (h == INVALID_HANDLE_VALUE) { MakeErrMsg(ErrMsg, std::string(fname) + ": Can't open file for " + (fd ? "input: " : "output: ")); @@ -218,34 +221,29 @@ *p = 0; // The pointer to the environment block for the new process. - OwningArrayPtr envblock; + std::vector EnvBlock; if (envp) { // An environment block consists of a null-terminated block of // null-terminated strings. Convert the array of environment variables to // an environment block by concatenating them. - - // First, determine the length of the environment block. len = 0; - for (unsigned i = 0; envp[i]; i++) - len += strlen(envp[i]) + 1; - - // Now build the environment block. - envblock.reset(new char[len+1]); - p = envblock.get(); - - for (unsigned i = 0; envp[i]; i++) { - const char *ev = envp[i]; - size_t len = strlen(ev) + 1; - memcpy(p, ev, len); - p += len; - } + for (unsigned i = 0; envp[i]; ++i) { + SmallVector EnvString; + if (error_code ec = windows::UTF8ToUTF16(envp[i], EnvString)) { + SetLastError(ec.value()); + MakeErrMsg(ErrMsg, "Unable to convert environment variable to UTF-16"); + return false; + } - *p = 0; + EnvBlock.insert(EnvBlock.end(), EnvString.begin(), EnvString.end()); + EnvBlock.push_back(0); + } + EnvBlock.push_back(0); } // Create a child process. - STARTUPINFO si; + STARTUPINFOW si; memset(&si, 0, sizeof(si)); si.cb = sizeof(si); si.hStdInput = INVALID_HANDLE_VALUE; @@ -269,9 +267,14 @@ if (redirects[1] && redirects[2] && *(redirects[1]) == *(redirects[2])) { // If stdout and stderr should go to the same place, redirect stderr // to the handle already open for stdout. - DuplicateHandle(GetCurrentProcess(), si.hStdOutput, - GetCurrentProcess(), &si.hStdError, - 0, TRUE, DUPLICATE_SAME_ACCESS); + if (!DuplicateHandle(GetCurrentProcess(), si.hStdOutput, + GetCurrentProcess(), &si.hStdError, + 0, TRUE, DUPLICATE_SAME_ACCESS)) { + CloseHandle(si.hStdInput); + CloseHandle(si.hStdOutput); + MakeErrMsg(ErrMsg, "can't dup stderr to stdout"); + return false; + } } else { // Just redirect stderr si.hStdError = RedirectIO(redirects[2], 2, ErrMsg); @@ -289,9 +292,26 @@ fflush(stdout); fflush(stderr); - std::string ProgramStr = Program; - BOOL rc = CreateProcess(ProgramStr.c_str(), command.get(), NULL, NULL, TRUE, - 0, envblock.get(), NULL, &si, &pi); + + SmallVector ProgramUtf16; + if (error_code ec = windows::UTF8ToUTF16(Program, ProgramUtf16)) { + SetLastError(ec.value()); + MakeErrMsg(ErrMsg, + std::string("Unable to convert application name to UTF-16")); + return false; + } + + SmallVector CommandUtf16; + if (error_code ec = windows::UTF8ToUTF16(command.get(), CommandUtf16)) { + SetLastError(ec.value()); + MakeErrMsg(ErrMsg, + std::string("Unable to convert command-line to UTF-16")); + return false; + } + + BOOL rc = CreateProcessW(ProgramUtf16.data(), CommandUtf16.data(), 0, 0, TRUE, + CREATE_UNICODE_ENVIRONMENT, + EnvBlock.empty() ? 0 : EnvBlock.data(), 0, &si, &pi); DWORD err = GetLastError(); // Regardless of whether the process got created or not, we are done with @@ -304,7 +324,7 @@ if (!rc) { SetLastError(err); MakeErrMsg(ErrMsg, std::string("Couldn't execute program '") + - ProgramStr + "'"); + Program.str() + "'"); return false; } Index: lib/Support/Windows/Signals.inc =================================================================== --- lib/Support/Windows/Signals.inc +++ lib/Support/Windows/Signals.inc @@ -135,7 +135,7 @@ static fpSymFunctionTableAccess64 SymFunctionTableAccess64; static bool load64BitDebugHelp(void) { - HMODULE hLib = ::LoadLibrary("Dbghelp.dll"); + HMODULE hLib = ::LoadLibrary(TEXT("Dbghelp.dll")); if (hLib) { StackWalk64 = (fpStackWalk64) ::GetProcAddress(hLib, "StackWalk64"); Index: lib/Support/Windows/Windows.h =================================================================== --- lib/Support/Windows/Windows.h +++ lib/Support/Windows/Windows.h @@ -24,6 +24,8 @@ #define _WIN32_IE 0x0600 // MinGW at it again. #define WIN32_LEAN_AND_MEAN +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Config/config.h" // Get build system configuration settings @@ -31,7 +33,6 @@ #include "llvm/Support/system_error.h" #include #include -#include #include #include #include Index: projects/sample/autoconf/configure.ac =================================================================== --- projects/sample/autoconf/configure.ac +++ projects/sample/autoconf/configure.ac @@ -1087,6 +1087,7 @@ if test "$llvm_cv_os_type" = "MingW" ; then AC_CHECK_LIB(imagehlp, main) AC_CHECK_LIB(psapi, main) + AC_CHECK_LIB(shell32, main) fi dnl dlopen() is required for plugin support. Index: projects/sample/configure =================================================================== --- projects/sample/configure +++ projects/sample/configure @@ -12397,6 +12397,87 @@ fi + +{ echo "$as_me:$LINENO: checking for main in -lshell32" >&5 +echo $ECHO_N "checking for main in -lshell32... $ECHO_C" >&6; } +if test "${ac_cv_lib_shell32_main+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lshell32 $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + +int +main () +{ +return main (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_shell32_main=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_shell32_main=no +fi + +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_shell32_main" >&5 +echo "${ECHO_T}$ac_cv_lib_shell32_main" >&6; } +if test $ac_cv_lib_shell32_main = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBSHELL32 1 +_ACEOF + + LIBS="-lshell32 $LIBS" + +fi + fi { echo "$as_me:$LINENO: checking for library containing dlopen" >&5 Index: utils/FileCheck/CMakeLists.txt =================================================================== --- utils/FileCheck/CMakeLists.txt +++ utils/FileCheck/CMakeLists.txt @@ -4,7 +4,7 @@ target_link_libraries(FileCheck LLVMSupport) if( MINGW ) - target_link_libraries(FileCheck imagehlp psapi) + target_link_libraries(FileCheck imagehlp psapi shell32) endif( MINGW ) if( LLVM_ENABLE_THREADS AND HAVE_LIBPTHREAD ) target_link_libraries(FileCheck pthread) Index: utils/FileUpdate/CMakeLists.txt =================================================================== --- utils/FileUpdate/CMakeLists.txt +++ utils/FileUpdate/CMakeLists.txt @@ -4,7 +4,7 @@ target_link_libraries(FileUpdate LLVMSupport) if( MINGW ) - target_link_libraries(FileUpdate imagehlp psapi) + target_link_libraries(FileUpdate imagehlp psapi shell32) endif( MINGW ) if( LLVM_ENABLE_THREADS AND HAVE_LIBPTHREAD ) target_link_libraries(FileUpdate pthread) Index: utils/not/CMakeLists.txt =================================================================== --- utils/not/CMakeLists.txt +++ utils/not/CMakeLists.txt @@ -4,7 +4,7 @@ target_link_libraries(not LLVMSupport) if( MINGW ) - target_link_libraries(not imagehlp psapi) + target_link_libraries(not imagehlp psapi shell32) endif( MINGW ) if( LLVM_ENABLE_THREADS AND HAVE_LIBPTHREAD ) target_link_libraries(not pthread)