mirror of
https://github.com/wiiu-env/wut.git
synced 2024-12-05 03:04:16 +01:00
Add support for C++ std::thread.
Overwrites bits/gthr-default.h to implement gthreads.
This commit is contained in:
parent
a5a1bac28c
commit
a9829a3226
@ -5,3 +5,4 @@ add_subdirectory(libdefaultheap)
|
||||
add_subdirectory(libgfd)
|
||||
add_subdirectory(libwhb)
|
||||
add_subdirectory(wutnewlib)
|
||||
add_subdirectory(wutstdc++)
|
||||
|
17
libraries/wutstdc++/CMakeLists.txt
Normal file
17
libraries/wutstdc++/CMakeLists.txt
Normal file
@ -0,0 +1,17 @@
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
project(wutstdc++ CXX)
|
||||
|
||||
add_library(wutstdc++
|
||||
thread.cc)
|
||||
|
||||
target_compile_definitions(wutstdc++
|
||||
PRIVATE _GLIBCXX_HAS_GTHREADS)
|
||||
|
||||
target_include_directories(wutstdc++
|
||||
PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include" "${WUT_ROOT}/include")
|
||||
|
||||
install(TARGETS wutstdc++
|
||||
ARCHIVE DESTINATION "${CMAKE_INSTALL_PREFIX}/lib")
|
||||
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/"
|
||||
DESTINATION "${CMAKE_INSTALL_PREFIX}/include"
|
||||
FILES_MATCHING PATTERN "*.h*")
|
288
libraries/wutstdc++/include/bits/gthr-default.h
Normal file
288
libraries/wutstdc++/include/bits/gthr-default.h
Normal file
@ -0,0 +1,288 @@
|
||||
/* Threads compatibility routines for libgcc2 and libobjc. */
|
||||
/* Compile this one with gcc. */
|
||||
/* Copyright (C) 1997-2016 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
Under Section 7 of GPL version 3, you are granted additional
|
||||
permissions described in the GCC Runtime Library Exception, version
|
||||
3.1, as published by the Free Software Foundation.
|
||||
|
||||
You should have received a copy of the GNU General Public License and
|
||||
a copy of the GCC Runtime Library Exception along with this program;
|
||||
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef _GLIBCXX_GCC_GTHR_SINGLE_H
|
||||
#define _GLIBCXX_GCC_GTHR_SINGLE_H
|
||||
|
||||
#define __GTHREADS 1
|
||||
#define __GTHREADS_CXX0X 1
|
||||
|
||||
#include <coreinit/condition.h>
|
||||
#include <coreinit/thread.h>
|
||||
#include <coreinit/mutex.h>
|
||||
#include <coreinit/baseheap.h>
|
||||
#include <coreinit/expandedheap.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/errno.h>
|
||||
|
||||
#define _GTHREAD_USE_MUTEX_TIMEDLOCK 0
|
||||
|
||||
typedef OSThread *__gthread_t;
|
||||
typedef uint32_t __gthread_once_t;
|
||||
typedef OSMutex __gthread_mutex_t;
|
||||
typedef OSMutex __gthread_recursive_mutex_t;
|
||||
typedef OSCondition __gthread_cond_t;
|
||||
typedef struct timespec __gthread_time_t;
|
||||
|
||||
// Unimplemented
|
||||
typedef void *__gthread_key_t;
|
||||
|
||||
#define __GTHREAD_HAS_COND 1
|
||||
|
||||
#define __GTHREAD_ONCE_INIT { }
|
||||
#define __GTHREAD_MUTEX_INIT_FUNCTION __gthread_mutex_init_function
|
||||
#define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION __gthread_recursive_mutex_init_function
|
||||
#define __GTHREAD_COND_INIT_FUNCTION __gthread_cond_init_function
|
||||
#define __GTHREAD_TIME_INIT { 0, 0 }
|
||||
|
||||
#define __GTHREAD_STACK_SIZE (4096*1024)
|
||||
|
||||
static inline int
|
||||
__gthread_active_p (void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline void
|
||||
__gthread_thread_deallocator(OSThread *thread, void *stack)
|
||||
{
|
||||
MEMExpandedHeap *heap = (MEMExpandedHeap *)MEMGetBaseHeapHandle(MEM_BASE_HEAP_MEM2);
|
||||
MEMFreeToExpHeap(heap, thread);
|
||||
MEMFreeToExpHeap(heap, stack);
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_create (__gthread_t *__threadid, void *(*__func) (void*),
|
||||
void *__args)
|
||||
{
|
||||
MEMExpandedHeap *heap = (MEMExpandedHeap *)MEMGetBaseHeapHandle(MEM_BASE_HEAP_MEM2);
|
||||
OSThread *thread = (OSThread *)MEMAllocFromExpHeapEx(heap, sizeof(OSThread), 8);
|
||||
char *stack = (char *)MEMAllocFromExpHeapEx(heap, __GTHREAD_STACK_SIZE, 8);
|
||||
memset(thread, 0, sizeof(OSThread));
|
||||
|
||||
if (!OSCreateThread(thread,
|
||||
(OSThreadEntryPointFn)__func,
|
||||
(int)__args,
|
||||
NULL,
|
||||
stack + __GTHREAD_STACK_SIZE,
|
||||
__GTHREAD_STACK_SIZE,
|
||||
16,
|
||||
OS_THREAD_ATTRIB_AFFINITY_ANY)) {
|
||||
MEMFreeToExpHeap((MEMExpandedHeap*)MEMGetBaseHeapHandle(MEM_BASE_HEAP_MEM2), thread);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
*__threadid = thread;
|
||||
OSSetThreadDeallocator(thread, &__gthread_thread_deallocator);
|
||||
OSResumeThread(thread);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_join (__gthread_t __threadid, void **__value_ptr)
|
||||
{
|
||||
if (!OSJoinThread(__threadid, (int *)__value_ptr)) {
|
||||
return EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_detach (__gthread_t __threadid)
|
||||
{
|
||||
OSDetachThread(__threadid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_equal (__gthread_t __t1, __gthread_t __t2)
|
||||
{
|
||||
return __t1 == __t2;
|
||||
}
|
||||
|
||||
static inline __gthread_t
|
||||
__gthread_self (void)
|
||||
{
|
||||
return OSGetCurrentThread();
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_yield (void)
|
||||
{
|
||||
OSYieldThread();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_once (__gthread_once_t *__once, void (*__func) (void))
|
||||
{
|
||||
// TODO: Implement __gthread_once
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_key_create (__gthread_key_t *__key, void (*__dtor) (void *))
|
||||
{
|
||||
// TODO: Implement __gthread_key_create
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_key_delete (__gthread_key_t __key)
|
||||
{
|
||||
// TODO: Implement __gthread_key_delete
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline void *
|
||||
__gthread_getspecific (__gthread_key_t __key)
|
||||
{
|
||||
// TODO: Implement __gthread_getspecific
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_setspecific (__gthread_key_t __key, const void *__ptr)
|
||||
{
|
||||
// TODO: Implement __gthread_setspecific
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline void
|
||||
__gthread_mutex_init_function (__gthread_mutex_t *__mutex)
|
||||
{
|
||||
OSInitMutex(__mutex);
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_mutex_destroy (__gthread_mutex_t *__mutex)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_mutex_lock (__gthread_mutex_t *__mutex)
|
||||
{
|
||||
OSLockMutex(__mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_mutex_trylock (__gthread_mutex_t *__mutex)
|
||||
{
|
||||
if (!OSTryLockMutex(__mutex)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_mutex_unlock (__gthread_mutex_t *__mutex)
|
||||
{
|
||||
OSUnlockMutex(__mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *__mutex)
|
||||
{
|
||||
OSInitMutex(__mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *__mutex)
|
||||
{
|
||||
OSLockMutex(__mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *__mutex)
|
||||
{
|
||||
if (!OSTryLockMutex(__mutex)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *__mutex)
|
||||
{
|
||||
OSUnlockMutex(__mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_recursive_mutex_destroy (__gthread_recursive_mutex_t *__mutex)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
__gthread_cond_init_function (__gthread_cond_t *__cond)
|
||||
{
|
||||
OSInitCond(__cond);
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_cond_broadcast (__gthread_cond_t *__cond)
|
||||
{
|
||||
OSSignalCond(__cond);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_cond_signal (__gthread_cond_t *__cond)
|
||||
{
|
||||
OSSignalCond(__cond);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_cond_wait (__gthread_cond_t *__cond, __gthread_mutex_t *__mutex)
|
||||
{
|
||||
OSWaitCond(__cond, __mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_cond_wait_recursive (__gthread_cond_t *__cond,
|
||||
__gthread_recursive_mutex_t *__mutex)
|
||||
{
|
||||
OSWaitCond(__cond, __mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_cond_destroy (__gthread_cond_t* __cond)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* ! _GLIBCXX_GCC_GTHR_SINGLE_H */
|
218
libraries/wutstdc++/thread.cc
Normal file
218
libraries/wutstdc++/thread.cc
Normal file
@ -0,0 +1,218 @@
|
||||
// thread -*- C++ -*-
|
||||
|
||||
// Copyright (C) 2008-2018 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, or (at your option)
|
||||
// any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// Under Section 7 of GPL version 3, you are granted additional
|
||||
// permissions described in the GCC Runtime Library Exception, version
|
||||
// 3.1, as published by the Free Software Foundation.
|
||||
|
||||
// You should have received a copy of the GNU General Public License and
|
||||
// a copy of the GCC Runtime Library Exception along with this program;
|
||||
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
#define _GLIBCXX_THREAD_ABI_COMPAT 1
|
||||
#include <thread>
|
||||
#include <system_error>
|
||||
#include <cerrno>
|
||||
#include <bits/cxxabi_forced.h>
|
||||
|
||||
#if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1)
|
||||
|
||||
#if defined(_GLIBCXX_USE_GET_NPROCS)
|
||||
# include <sys/sysinfo.h>
|
||||
# define _GLIBCXX_NPROCS get_nprocs()
|
||||
#elif defined(_GLIBCXX_USE_PTHREADS_NUM_PROCESSORS_NP)
|
||||
# define _GLIBCXX_NPROCS pthread_num_processors_np()
|
||||
#elif defined(_GLIBCXX_USE_SYSCTL_HW_NCPU)
|
||||
# include <stddef.h>
|
||||
# include <sys/sysctl.h>
|
||||
static inline int get_nprocs()
|
||||
{
|
||||
int count;
|
||||
size_t size = sizeof(count);
|
||||
int mib[] = { CTL_HW, HW_NCPU };
|
||||
if (!sysctl(mib, 2, &count, &size, NULL, 0))
|
||||
return count;
|
||||
return 0;
|
||||
}
|
||||
# define _GLIBCXX_NPROCS get_nprocs()
|
||||
#elif defined(_GLIBCXX_USE_SC_NPROCESSORS_ONLN)
|
||||
# include <unistd.h>
|
||||
# define _GLIBCXX_NPROCS sysconf(_SC_NPROCESSORS_ONLN)
|
||||
#elif defined(_GLIBCXX_USE_SC_NPROC_ONLN)
|
||||
# include <unistd.h>
|
||||
# define _GLIBCXX_NPROCS sysconf(_SC_NPROC_ONLN)
|
||||
#else
|
||||
# define _GLIBCXX_NPROCS 0
|
||||
#endif
|
||||
|
||||
#ifndef _GLIBCXX_USE_NANOSLEEP
|
||||
# ifdef _GLIBCXX_HAVE_SLEEP
|
||||
# include <unistd.h>
|
||||
# elif defined(_GLIBCXX_HAVE_WIN32_SLEEP)
|
||||
# include <windows.h>
|
||||
# else
|
||||
# error "No sleep function known for this target"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
namespace std _GLIBCXX_VISIBILITY(default)
|
||||
{
|
||||
extern "C"
|
||||
{
|
||||
static void*
|
||||
execute_native_thread_routine(void* __p)
|
||||
{
|
||||
thread::_State_ptr __t{ static_cast<thread::_State*>(__p) };
|
||||
__t->_M_run();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if _GLIBCXX_THREAD_ABI_COMPAT
|
||||
static void*
|
||||
execute_native_thread_routine_compat(void* __p)
|
||||
{
|
||||
thread::_Impl_base* __t = static_cast<thread::_Impl_base*>(__p);
|
||||
thread::__shared_base_type __local;
|
||||
// Now that a new thread has been created we can transfer ownership of
|
||||
// the thread state to a local object, breaking the reference cycle
|
||||
// created in thread::_M_start_thread.
|
||||
__local.swap(__t->_M_this_ptr);
|
||||
__t->_M_run();
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
} // extern "C"
|
||||
|
||||
_GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
|
||||
thread::_State::~_State() = default;
|
||||
|
||||
void
|
||||
thread::join()
|
||||
{
|
||||
int __e = EINVAL;
|
||||
|
||||
if (_M_id != id())
|
||||
__e = __gthread_join(_M_id._M_thread, 0);
|
||||
|
||||
if (__e)
|
||||
__throw_system_error(__e);
|
||||
|
||||
_M_id = id();
|
||||
}
|
||||
|
||||
void
|
||||
thread::detach()
|
||||
{
|
||||
int __e = EINVAL;
|
||||
|
||||
if (_M_id != id())
|
||||
__e = __gthread_detach(_M_id._M_thread);
|
||||
|
||||
if (__e)
|
||||
__throw_system_error(__e);
|
||||
|
||||
_M_id = id();
|
||||
}
|
||||
|
||||
void
|
||||
thread::_M_start_thread(_State_ptr state, void (*)())
|
||||
{
|
||||
const int err = __gthread_create(&_M_id._M_thread,
|
||||
&execute_native_thread_routine,
|
||||
state.get());
|
||||
if (err)
|
||||
__throw_system_error(err);
|
||||
state.release();
|
||||
}
|
||||
|
||||
#if _GLIBCXX_THREAD_ABI_COMPAT
|
||||
void
|
||||
thread::_M_start_thread(__shared_base_type __b)
|
||||
{
|
||||
if (!__gthread_active_p())
|
||||
#if __cpp_exceptions
|
||||
throw system_error(make_error_code(errc::operation_not_permitted),
|
||||
"Enable multithreading to use std::thread");
|
||||
#else
|
||||
__throw_system_error(int(errc::operation_not_permitted));
|
||||
#endif
|
||||
|
||||
_M_start_thread(std::move(__b), nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
thread::_M_start_thread(__shared_base_type __b, void (*)())
|
||||
{
|
||||
auto ptr = __b.get();
|
||||
// Create a reference cycle that will be broken in the new thread.
|
||||
ptr->_M_this_ptr = std::move(__b);
|
||||
int __e = __gthread_create(&_M_id._M_thread,
|
||||
&execute_native_thread_routine_compat, ptr);
|
||||
if (__e)
|
||||
{
|
||||
ptr->_M_this_ptr.reset(); // break reference cycle, destroying *ptr.
|
||||
__throw_system_error(__e);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned int
|
||||
thread::hardware_concurrency() noexcept
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
void
|
||||
__sleep_for(chrono::seconds __s, chrono::nanoseconds __ns)
|
||||
{
|
||||
#ifdef _GLIBCXX_USE_NANOSLEEP
|
||||
__gthread_time_t __ts =
|
||||
{
|
||||
static_cast<std::time_t>(__s.count()),
|
||||
static_cast<long>(__ns.count())
|
||||
};
|
||||
while (::nanosleep(&__ts, &__ts) == -1 && errno == EINTR)
|
||||
{ }
|
||||
#elif defined(_GLIBCXX_HAVE_SLEEP)
|
||||
# ifdef _GLIBCXX_HAVE_USLEEP
|
||||
::sleep(__s.count());
|
||||
if (__ns.count() > 0)
|
||||
{
|
||||
long __us = __ns.count() / 1000;
|
||||
if (__us == 0)
|
||||
__us = 1;
|
||||
::usleep(__us);
|
||||
}
|
||||
# else
|
||||
::sleep(__s.count() + (__ns.count() >= 1000000));
|
||||
# endif
|
||||
#elif defined(_GLIBCXX_HAVE_WIN32_SLEEP)
|
||||
unsigned long ms = __ns.count() / 1000000;
|
||||
if (__ns.count() > 0 && ms == 0)
|
||||
ms = 1;
|
||||
::Sleep(chrono::milliseconds(__s).count() + ms);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
_GLIBCXX_END_NAMESPACE_VERSION
|
||||
} // namespace std
|
||||
|
||||
#endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1
|
19
samples/helloworld_std_thread/CMakeLists.txt
Normal file
19
samples/helloworld_std_thread/CMakeLists.txt
Normal file
@ -0,0 +1,19 @@
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
project(helloworld_std_thread CXX)
|
||||
include("${WUT_ROOT}/share/wut.cmake" REQUIRED)
|
||||
|
||||
add_executable(helloworld_std_thread
|
||||
main.cpp)
|
||||
|
||||
target_link_libraries(helloworld_std_thread
|
||||
whb
|
||||
defaultheap
|
||||
coreinit
|
||||
proc_ui
|
||||
sysapp)
|
||||
|
||||
wut_enable_stdcpp(helloworld_std_thread)
|
||||
wut_create_rpx(helloworld_std_thread.rpx helloworld_std_thread)
|
||||
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/helloworld_std_thread.rpx"
|
||||
DESTINATION "${CMAKE_INSTALL_PREFIX}")
|
45
samples/helloworld_std_thread/main.cpp
Normal file
45
samples/helloworld_std_thread/main.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
#include <coreinit/thread.h>
|
||||
#include <coreinit/time.h>
|
||||
#include <coreinit/systeminfo.h>
|
||||
|
||||
#include <whb/proc.h>
|
||||
#include <whb/log.h>
|
||||
#include <whb/log_console.h>
|
||||
|
||||
#include <thread>
|
||||
|
||||
int
|
||||
hello_thread()
|
||||
{
|
||||
OSCalendarTime tm;
|
||||
|
||||
WHBProcInit();
|
||||
WHBLogConsoleInit();
|
||||
WHBLogPrintf("Hello World from a std::thread!");
|
||||
|
||||
while(WHBProcIsRunning()) {
|
||||
OSTicksToCalendarTime(OSGetTime(), &tm);
|
||||
WHBLogPrintf("%02d/%02d/%04d %02d:%02d:%02d I'm still here.",
|
||||
tm.tm_mday, tm.tm_mon, tm.tm_year,
|
||||
tm.tm_hour, tm.tm_min, tm.tm_sec);
|
||||
|
||||
WHBLogConsoleDraw();
|
||||
OSSleepTicks(OSMilliseconds(1000));
|
||||
}
|
||||
|
||||
WHBLogPrintf("Exiting... good bye.");
|
||||
WHBLogConsoleDraw();
|
||||
OSSleepTicks(OSMilliseconds(1000));
|
||||
|
||||
WHBLogConsoleFree();
|
||||
WHBProcShutdown();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
std::thread t(hello_thread);
|
||||
t.join();
|
||||
return 0;
|
||||
}
|
@ -1,5 +1,16 @@
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
|
||||
macro(wut_enable_stdcpp target)
|
||||
target_link_libraries(${target}
|
||||
wutstdc++)
|
||||
|
||||
target_compile_definitions(${target}
|
||||
PRIVATE _GLIBCXX_HAS_GTHREADS)
|
||||
|
||||
set_target_properties(${target} PROPERTIES
|
||||
COMPILE_FLAGS "-std=c++17")
|
||||
endmacro(wut_enable_stdcpp)
|
||||
|
||||
macro(wut_create_rpx target source)
|
||||
target_link_libraries(${source}
|
||||
wutnewlib
|
||||
|
Loading…
Reference in New Issue
Block a user