From 5e0dbf5f64456101a5e1398647a304d85801769a Mon Sep 17 00:00:00 2001 From: Lewis Baker Date: Tue, 18 Jul 2017 08:13:41 +0930 Subject: [PATCH 01/14] Experimental support for building with Clang under Linux. Skip building file I/O files as these are currently Windows only. --- .gitmodules | 2 +- config.cake | 62 +++++++++++++++++++++++++++++++++++++++++++++++++ lib/build.cake | 18 +++++++------- test/build.cake | 8 +++++-- tools/cake | 2 +- 5 files changed, 79 insertions(+), 13 deletions(-) diff --git a/.gitmodules b/.gitmodules index 61907af1..452d37a1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "cake"] path = tools/cake url = https://github.com/lewissbaker/cake.git - branch = master \ No newline at end of file + branch = clang diff --git a/config.cake b/config.cake index 97b9bbb3..34dfc409 100644 --- a/config.cake +++ b/config.cake @@ -145,3 +145,65 @@ if cake.system.isWindows() or cake.system.isCygwin(): except CompilerNotFoundError, e: print str(e) + +elif cake.system.isLinux(): + + from cake.library.compilers.clang import ClangCompiler + + clangVariant = baseVariant.clone(compiler='clang', + platform='linux', + architecture='x64') + + compiler = ClangCompiler( + configuration=configuration, + clangExe='/usr/bin/clang-5.0', + llvmArExe='/usr/bin/llvm-ar-5.0', + binPaths=['/usr/bin']) + + compiler.addCppFlag('-std=c++1z') + compiler.addCppFlag('-fcoroutines-ts') + compiler.addCppFlag('-m64') + + # Set this to the install-prefix of where libc++-5.0 is installed. + libCxxInstallPrefix = None # '/path/to/install' + + if libCxxInstallPrefix: + compiler.addCppFlag('-nostdinc++') + compiler.addIncludePath(cake.path.join( + libCxxInstallPrefix, 'include', 'c++', 'v1')) + compiler.addLibraryPath(cake.path.join( + libCxxInstallPrefix, 'lib')) + else: + compiler.addCppFlag('-stdlib=libc++') + + compiler.addLibrary('c++') + compiler.addLibrary('c++abi') + compiler.addLibrary('c') + compiler.addLibrary('pthread') + + #compiler.addProgramFlag('-Wl,--trace') + #compiler.addProgramFlag('-Wl,-v') + + clangVariant.tools['compiler'] = compiler + + env = clangVariant.tools["env"] + env["COMPILER"] = "clang" + env["COMPILER_VERSION"] = "5.0" + env["PLATFORM"] = "linux" + env["ARCHITECTURE"] = "x64" + + clangDebugVariant = clangVariant.clone(release='debug') + clangDebugVariant.tools["env"]["RELEASE"] = 'debug' + + # TODO: Configure debug-specific settings here + compiler = clangDebugVariant.tools["compiler"] + + configuration.addVariant(clangDebugVariant) + + clangOptimisedVariant = clangVariant.clone(release='optimised') + clangOptimisedVariant.tools["env"]["RELEASE"] = 'optimised' + + # TODO: Configure optimised-specific settings here + compiler = clangOptimisedVariant.tools["compiler"] + + configuration.addVariant(clangOptimisedVariant) diff --git a/lib/build.cake b/lib/build.cake index 83480d63..102932c7 100644 --- a/lib/build.cake +++ b/lib/build.cake @@ -50,15 +50,6 @@ sources = script.cwd([ 'cancellation_token.cpp', 'cancellation_source.cpp', 'cancellation_registration.cpp', - 'io_service.cpp', - 'file.cpp', - 'readable_file.cpp', - 'writable_file.cpp', - 'read_only_file.cpp', - 'write_only_file.cpp', - 'read_write_file.cpp', - 'file_read_operation.cpp', - 'file_write_operation.cpp', ]) extras = script.cwd([ @@ -72,6 +63,15 @@ if variant.platform == "windows": ])) sources.extend(script.cwd([ 'win32.cpp', + 'io_service.cpp', + 'file.cpp', + 'readable_file.cpp', + 'writable_file.cpp', + 'read_only_file.cpp', + 'write_only_file.cpp', + 'read_write_file.cpp', + 'file_read_operation.cpp', + 'file_write_operation.cpp', ])) buildDir = env.expand('${CPPCORO_BUILD}') diff --git a/test/build.cake b/test/build.cake index 6e39b3eb..45c6241b 100644 --- a/test/build.cake +++ b/test/build.cake @@ -27,10 +27,14 @@ sources = script.cwd([ 'shared_lazy_task_tests.cpp', 'shared_task_tests.cpp', 'task_tests.cpp', - 'io_service_tests.cpp', - 'file_tests.cpp', ]) +if variant.platform == 'windows': + sources += script.cwd([ + 'io_service_tests.cpp', + 'file_tests.cpp', + ]) + extras = script.cwd([ 'build.cake', ]) diff --git a/tools/cake b/tools/cake index ccb64fd8..e63b4cb5 160000 --- a/tools/cake +++ b/tools/cake @@ -1 +1 @@ -Subproject commit ccb64fd82ea829cdda5f2053edccc70346c5125a +Subproject commit e63b4cb5dd0936c776e10f0d43e4f5855516acbd From 5734b5c2e9ce3e4ba7face9baac0f84cb2c6b6bd Mon Sep 17 00:00:00 2001 From: Lewis Baker Date: Tue, 18 Jul 2017 08:14:56 +0930 Subject: [PATCH 02/14] Add a helper script for running cake under Linux. --- init.sh | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 init.sh diff --git a/init.sh b/init.sh new file mode 100644 index 00000000..a01914bf --- /dev/null +++ b/init.sh @@ -0,0 +1,7 @@ + +export CAKE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/tools/cake/src/run.py" + +function cake() +{ + python2.7 "$CAKE" "$@" +} From e0ac2abe5508f1248a51e21fa896b8ff3880edc6 Mon Sep 17 00:00:00 2001 From: wind85 Date: Tue, 18 Jul 2017 05:00:07 +0200 Subject: [PATCH 03/14] fixed missing include --- test/generator_tests.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/test/generator_tests.cpp b/test/generator_tests.cpp index 9377bd47..9efa82a6 100644 --- a/test/generator_tests.cpp +++ b/test/generator_tests.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include From e5bf85c5e91de9bbf3b4113affa70c9902b1c4a9 Mon Sep 17 00:00:00 2001 From: Lewis Baker Date: Tue, 18 Jul 2017 22:03:27 +0930 Subject: [PATCH 04/14] Fix bug in recursive_generator when building under Clang. The promise_type::get_return_object() method was returning a reference to the promise object, expecting that reference to be passed to the constructor of recursive_generator. However, under Clang the result of get_return_object() is assigned to an 'auto' variable, which ends up taking a copy of the promise object on the stack and passing that copy into the recursive_generator constructor. Modified get_return_object() to return the already-constructed recursive_generator object. --- include/cppcoro/recursive_generator.hpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/include/cppcoro/recursive_generator.hpp b/include/cppcoro/recursive_generator.hpp index 9f76dcbf..30160eb6 100644 --- a/include/cppcoro/recursive_generator.hpp +++ b/include/cppcoro/recursive_generator.hpp @@ -28,9 +28,12 @@ namespace cppcoro , m_parentOrLeaf(this) {} - promise_type& get_return_object() noexcept + promise_type(const promise_type&) = delete; + promise_type(promise_type&&) = delete; + + auto get_return_object() noexcept { - return *this; + return recursive_generator{ *this }; } std::experimental::suspend_always initial_suspend() noexcept From 49ec4915b0ed3ae8111c113d165681971a85563a Mon Sep 17 00:00:00 2001 From: Lewis Baker Date: Tue, 18 Jul 2017 22:21:34 +0930 Subject: [PATCH 05/14] Add workarounds for broken 'co_return ;' in Clang. --- include/cppcoro/shared_lazy_task.hpp | 3 ++- include/cppcoro/shared_task.hpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/cppcoro/shared_lazy_task.hpp b/include/cppcoro/shared_lazy_task.hpp index a29ae3bc..7e6c9a57 100644 --- a/include/cppcoro/shared_lazy_task.hpp +++ b/include/cppcoro/shared_lazy_task.hpp @@ -5,6 +5,7 @@ #ifndef CPPCORO_SHARED_LAZY_TASK_HPP_INCLUDED #define CPPCORO_SHARED_LAZY_TASK_HPP_INCLUDED +#include #include #include @@ -512,7 +513,7 @@ namespace cppcoro co_return co_await std::move(t); } -#if defined(_MSC_VER) && _MSC_FULL_VER <= 191025019 +#if defined(_MSC_VER) && _MSC_FULL_VER <= 191025019 || CPPCORO_COMPILER_CLANG // HACK: Workaround for broken MSVC that doesn't execute in 'co_return ;'. inline shared_lazy_task make_shared_task(lazy_task t) { diff --git a/include/cppcoro/shared_task.hpp b/include/cppcoro/shared_task.hpp index 085f681e..b2996b4b 100644 --- a/include/cppcoro/shared_task.hpp +++ b/include/cppcoro/shared_task.hpp @@ -5,6 +5,7 @@ #ifndef CPPCORO_SHARED_TASK_HPP_INCLUDED #define CPPCORO_SHARED_TASK_HPP_INCLUDED +#include #include #include @@ -475,7 +476,7 @@ namespace cppcoro co_return co_await std::move(t); } -#if defined(_MSC_VER) && _MSC_FULL_VER <= 191025019 +#if defined(_MSC_VER) && _MSC_FULL_VER <= 191025019 || CPPCORO_COMPILER_CLANG // HACK: Work around bug in MSVC handling of 'co_return ' for void-returning expression. // It doesn't actually evaluate before calling .return_void(). inline shared_task make_shared_task(task t) From 9dc84262f76f68aa1eacbe8f7bacab82c0c3ba7c Mon Sep 17 00:00:00 2001 From: Lewis Baker Date: Tue, 18 Jul 2017 22:22:17 +0930 Subject: [PATCH 06/14] Add some missing #includes needed by Clang under optimised builds. --- test/lazy_task_tests.cpp | 1 + test/shared_task_tests.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/test/lazy_task_tests.cpp b/test/lazy_task_tests.cpp index 559203f7..f7cf9910 100644 --- a/test/lazy_task_tests.cpp +++ b/test/lazy_task_tests.cpp @@ -9,6 +9,7 @@ #include "counted.hpp" +#include #include #include diff --git a/test/shared_task_tests.cpp b/test/shared_task_tests.cpp index 3706af5f..0d157b81 100644 --- a/test/shared_task_tests.cpp +++ b/test/shared_task_tests.cpp @@ -9,6 +9,7 @@ #include "counted.hpp" +#include #include #include "doctest/doctest.h" From 7db28481ac2544324ff6588bd056dc17c879a71e Mon Sep 17 00:00:00 2001 From: Lewis Baker Date: Tue, 18 Jul 2017 22:26:30 +0930 Subject: [PATCH 07/14] Add debug/optimised flags for Clang build variants. debug: -O0 -g optimised: -O2 -g -flto --- config.cake | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/config.cake b/config.cake index 34dfc409..13f4d29a 100644 --- a/config.cake +++ b/config.cake @@ -195,15 +195,22 @@ elif cake.system.isLinux(): clangDebugVariant = clangVariant.clone(release='debug') clangDebugVariant.tools["env"]["RELEASE"] = 'debug' - # TODO: Configure debug-specific settings here + # Configure debug-specific settings here compiler = clangDebugVariant.tools["compiler"] + compiler.addCppFlag('-O0') + compiler.addCppFlag('-g') configuration.addVariant(clangDebugVariant) clangOptimisedVariant = clangVariant.clone(release='optimised') clangOptimisedVariant.tools["env"]["RELEASE"] = 'optimised' - # TODO: Configure optimised-specific settings here + # Configure optimised-specific settings here compiler = clangOptimisedVariant.tools["compiler"] + compiler.addCppFlag('-O2') + compiler.addCppFlag('-g') + compiler.addCppFlag('-flto') + compiler.addProgramFlag('-flto') + compiler.addModuleFlag('-flto') configuration.addVariant(clangOptimisedVariant) From f0040af1515c16159d470f69c4965db730e0bb14 Mon Sep 17 00:00:00 2001 From: Lewis Baker Date: Fri, 28 Jul 2017 23:16:03 +0930 Subject: [PATCH 08/14] Fix compilation of async_auto_reset_event tests under clang/linux. - Disable the test that requires io_service when not on Windows. - Add missing #include. --- test/async_auto_reset_event_tests.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test/async_auto_reset_event_tests.cpp b/test/async_auto_reset_event_tests.cpp index 365cd177..62326039 100644 --- a/test/async_auto_reset_event_tests.cpp +++ b/test/async_auto_reset_event_tests.cpp @@ -5,12 +5,17 @@ #include +#include #include -#include #include +#if CPPCORO_OS_WINNT +# include +#endif + #include #include +#include #include "doctest/doctest.h" @@ -65,6 +70,7 @@ TEST_CASE("multiple waiters") CHECK(t2.is_ready()); } +#if CPPCORO_OS_WINNT TEST_CASE("multi-threaded") { cppcoro::io_service ioService; @@ -140,5 +146,6 @@ TEST_CASE("multi-threaded") joinOnExit2.call_now(); joinOnExit3.call_now(); } +#endif TEST_SUITE_END(); From 4f4dbd5f0a631b5588d9897e986a1dc3065eeff6 Mon Sep 17 00:00:00 2001 From: Lewis Baker Date: Wed, 2 Aug 2017 21:28:56 +0930 Subject: [PATCH 09/14] Update config.cake to not be specific to clang-5.0 It now supports being built with clang 6.0. --- config.cake | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/config.cake b/config.cake index 3b1fba45..3d61240f 100644 --- a/config.cake +++ b/config.cake @@ -158,17 +158,26 @@ elif cake.system.isLinux(): platform='linux', architecture='x64') + # If you have built your own version of Clang, you can modify + # this variable to point to the CMAKE_INSTALL_PREFIX for + # where you have installed your clang/libcxx build. + clangInstallPrefix = '/usr' + + clangBinPath = cake.path.join(clangInstallPrefix, 'bin') + compiler = ClangCompiler( configuration=configuration, - clangExe='/usr/bin/clang-5.0', - llvmArExe='/usr/bin/llvm-ar-5.0', - binPaths=['/usr/bin']) + clangExe=cake.path.join(clangBinPath, 'clang'), + llvmArExe=cake.path.join(clangBinPath, 'llvm-ar'), + binPaths=[clangBinPath]) compiler.addCppFlag('-std=c++1z') compiler.addCppFlag('-fcoroutines-ts') compiler.addCppFlag('-m64') - # Set this to the install-prefix of where libc++-5.0 is installed. + # Set this to the install-prefix of where libc++ is installed. + # You only need to set this if it is not installed at the same + # location as clang. libCxxInstallPrefix = None # '/path/to/install' if libCxxInstallPrefix: From dbfa380acccaaa85bad79c620408ac2dbb2042c5 Mon Sep 17 00:00:00 2001 From: Lewis Baker Date: Wed, 2 Aug 2017 21:29:17 +0930 Subject: [PATCH 10/14] Fix whitespace. --- config.cake | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/config.cake b/config.cake index 3d61240f..1b559818 100644 --- a/config.cake +++ b/config.cake @@ -193,10 +193,10 @@ elif cake.system.isLinux(): compiler.addLibrary('c++abi') compiler.addLibrary('c') compiler.addLibrary('pthread') - + #compiler.addProgramFlag('-Wl,--trace') #compiler.addProgramFlag('-Wl,-v') - + clangVariant.tools['compiler'] = compiler env = clangVariant.tools["env"] @@ -207,12 +207,12 @@ elif cake.system.isLinux(): clangDebugVariant = clangVariant.clone(release='debug') clangDebugVariant.tools["env"]["RELEASE"] = 'debug' - + # Configure debug-specific settings here compiler = clangDebugVariant.tools["compiler"] compiler.addCppFlag('-O0') compiler.addCppFlag('-g') - + configuration.addVariant(clangDebugVariant) clangOptimisedVariant = clangVariant.clone(release='optimised') @@ -225,5 +225,5 @@ elif cake.system.isLinux(): compiler.addCppFlag('-flto') compiler.addProgramFlag('-flto') compiler.addModuleFlag('-flto') - + configuration.addVariant(clangOptimisedVariant) From 7513d9cf0c5fca803ab5805caacf66b04c48a510 Mon Sep 17 00:00:00 2001 From: Lewis Baker Date: Wed, 2 Aug 2017 21:30:17 +0930 Subject: [PATCH 11/14] Remove hack workaround for `co_return ` under clang. This bug has been fixed in clang-6.0. --- include/cppcoro/shared_lazy_task.hpp | 2 +- include/cppcoro/shared_task.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/cppcoro/shared_lazy_task.hpp b/include/cppcoro/shared_lazy_task.hpp index 7e6c9a57..710a73e0 100644 --- a/include/cppcoro/shared_lazy_task.hpp +++ b/include/cppcoro/shared_lazy_task.hpp @@ -513,7 +513,7 @@ namespace cppcoro co_return co_await std::move(t); } -#if defined(_MSC_VER) && _MSC_FULL_VER <= 191025019 || CPPCORO_COMPILER_CLANG +#if defined(_MSC_VER) && _MSC_FULL_VER <= 191025019 // HACK: Workaround for broken MSVC that doesn't execute in 'co_return ;'. inline shared_lazy_task make_shared_task(lazy_task t) { diff --git a/include/cppcoro/shared_task.hpp b/include/cppcoro/shared_task.hpp index b2996b4b..240753c9 100644 --- a/include/cppcoro/shared_task.hpp +++ b/include/cppcoro/shared_task.hpp @@ -476,7 +476,7 @@ namespace cppcoro co_return co_await std::move(t); } -#if defined(_MSC_VER) && _MSC_FULL_VER <= 191025019 || CPPCORO_COMPILER_CLANG +#if defined(_MSC_VER) && _MSC_FULL_VER <= 191025019 // HACK: Work around bug in MSVC handling of 'co_return ' for void-returning expression. // It doesn't actually evaluate before calling .return_void(). inline shared_task make_shared_task(task t) From 83ab6399ecba784f56f60177447849e01286d915 Mon Sep 17 00:00:00 2001 From: Lewis Baker Date: Thu, 3 Aug 2017 00:12:47 +0930 Subject: [PATCH 12/14] Suppress some Clang warnings about unused return values. Cast result to (void) where we are intentionally ignoring the return value. --- include/cppcoro/async_generator.hpp | 2 +- test/async_generator_tests.cpp | 4 ++-- test/lazy_task_tests.cpp | 2 +- test/shared_lazy_task_tests.cpp | 2 +- test/when_all_ready_tests.cpp | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/cppcoro/async_generator.hpp b/include/cppcoro/async_generator.hpp index 7ea00db3..1fc1bd27 100644 --- a/include/cppcoro/async_generator.hpp +++ b/include/cppcoro/async_generator.hpp @@ -671,7 +671,7 @@ namespace cppcoro while (it != itEnd) { co_yield std::invoke(func, *it); - co_await ++it; + (void)co_await ++it; } } } diff --git a/test/async_generator_tests.cpp b/test/async_generator_tests.cpp index 0b05666b..8d485e2a 100644 --- a/test/async_generator_tests.cpp +++ b/test/async_generator_tests.cpp @@ -182,10 +182,10 @@ TEST_CASE("async producer with async consumer" { auto it = co_await producer.begin(); CHECK(*it == 1u); - co_await ++it; + (void)co_await ++it; CHECK(*it == 2u); co_await c1; - co_await ++it; + (void)co_await ++it; CHECK(it == producer.end()); }(); diff --git a/test/lazy_task_tests.cpp b/test/lazy_task_tests.cpp index f7cf9910..20bb9a6e 100644 --- a/test/lazy_task_tests.cpp +++ b/test/lazy_task_tests.cpp @@ -113,7 +113,7 @@ TEST_CASE("lazy_task destructor destroys result") [](cppcoro::lazy_task& t) -> cppcoro::task<> { - co_await t; + co_await t.when_ready(); CHECK(t.is_ready()); CHECK(counted::active_count() == 1); }(t); diff --git a/test/shared_lazy_task_tests.cpp b/test/shared_lazy_task_tests.cpp index 421dcc0a..6af00656 100644 --- a/test/shared_lazy_task_tests.cpp +++ b/test/shared_lazy_task_tests.cpp @@ -73,7 +73,7 @@ TEST_CASE("result is destroyed when last reference is destroyed" [](cppcoro::shared_lazy_task t) -> cppcoro::task<> { - co_await t; + co_await t.when_ready(); }(t); CHECK(counted::active_count() == 1); diff --git a/test/when_all_ready_tests.cpp b/test/when_all_ready_tests.cpp index 9655f011..6966ca85 100644 --- a/test/when_all_ready_tests.cpp +++ b/test/when_all_ready_tests.cpp @@ -38,7 +38,7 @@ TEST_CASE("when_all_ready() with no args") { auto run = []() -> cppcoro::task<> { - co_await cppcoro::when_all_ready(); + (void)co_await cppcoro::when_all_ready(); }; CHECK(run().is_ready()); } @@ -366,7 +366,7 @@ TEST_CASE("when_all_ready() doesn't rethrow exceptions") { auto[t0, t1] = co_await cppcoro::when_all_ready(makeTask(true), makeTask(false)); - CHECK_THROWS_AS(co_await t0, const std::exception&); + CHECK_THROWS_AS((void)co_await t0, const std::exception&); CHECK(co_await t1 == 123); } catch (...) From 75e9a18c06f8218c664d088456d495c633f8bc16 Mon Sep 17 00:00:00 2001 From: Lewis Baker Date: Sun, 6 Aug 2017 14:55:11 +0930 Subject: [PATCH 13/14] Move libc++ path customisation point nearer to clang's. --- config.cake | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/config.cake b/config.cake index 1b559818..f1d8baa2 100644 --- a/config.cake +++ b/config.cake @@ -163,6 +163,11 @@ elif cake.system.isLinux(): # where you have installed your clang/libcxx build. clangInstallPrefix = '/usr' + # Set this to the install-prefix of where libc++ is installed. + # You only need to set this if it is not installed at the same + # location as clangInstallPrefix. + libCxxInstallPrefix = None # '/path/to/install' + clangBinPath = cake.path.join(clangInstallPrefix, 'bin') compiler = ClangCompiler( @@ -175,11 +180,6 @@ elif cake.system.isLinux(): compiler.addCppFlag('-fcoroutines-ts') compiler.addCppFlag('-m64') - # Set this to the install-prefix of where libc++ is installed. - # You only need to set this if it is not installed at the same - # location as clang. - libCxxInstallPrefix = None # '/path/to/install' - if libCxxInstallPrefix: compiler.addCppFlag('-nostdinc++') compiler.addIncludePath(cake.path.join( From e0260d427880c77110b45dc66ca9f24436085267 Mon Sep 17 00:00:00 2001 From: Lewis Baker Date: Sun, 6 Aug 2017 16:29:36 +0930 Subject: [PATCH 14/14] Add documentation to README about building under Linux. --- README.md | 224 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 216 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index f2dd061b..d808d22d 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,12 @@ proposal. It has been open-sourced in the hope that others will find it useful and that the C++ community can provide feedback on it and ways to improve it. +It requires a compiler that supports the coroutines TS: +- Windows + Visual Studio 2017 +- Linux + Clang 5.0/6.0 + libc++ + +The Linux version is functional except for the `io_context` and file I/O related classes which have not yet been implemented for Linux (see issue [#15](https://github.com/lewissbaker/cppcoro/issues/15) for more info). + # Class Details ## `task` @@ -1458,19 +1464,26 @@ Given a type, `S`, that implements the `DelayedScheduler` and an instance, `s` o # Building +The cppcoro library supports building under Windows with Visual Studio 2017 and Linux with Clang 5.0+. + This library makes use of the [Cake build system](https://github.com/lewissbaker/cake) (no, not the [C# one](http://cakebuild.net/)). +The cake build system is checked out automatically as a git submodule so you don't need to download or install it separately. + +## Building on Windows + This library currently requires Visual Studio 2017 or later and the Windows 10 SDK. Support for Clang ([#3](https://github.com/lewissbaker/cppcoro/issues/3)) and Linux ([#15](https://github.com/lewissbaker/cppcoro/issues/15)) is planned. -## Prerequisites +### Prerequisites The Cake build-system is implemented in Python and requires Python 2.7 to be installed. Ensure Python 2.7 interpreter is in your PATH and available as 'python'. -Ensure Visual Studio 2017 is installed (preferably the latest update). +Ensure Visual Studio 2017 Update 2 or later is installed. +Note that there are some known issues with coroutines in Update 2 that have been fixed in the latest Update 3 preview. You can also use an experimental version of the Visual Studio compiler by downloading a NuGet package from https://vcppdogfooding.azurewebsites.net/ and unzipping the .nuget file to a directory. Just update the `config.cake` file to point at the unzipped location by modifying and uncommenting the following line: @@ -1481,13 +1494,13 @@ nugetPath = None # r'C:\Path\To\VisualCppTools.14.0.25224-Pre' Ensure that you have the Windows 10 SDK installed. It will use the latest Windows 10 SDK and Universal C Runtime version by default. -## Cloning the repository +### Cloning the repository The cppcoro repository makes use of git submodules to pull in the source for the Cake build system. This means you need to pass the `--recursive` flag to the `git clone` command. eg. ``` -c:\Code> git clone --recursive https://github.com/lewissbaker/cppcoro +c:\Code> git clone --recursive https://github.com/lewissbaker/cppcoro.git ``` If you have already cloned cppcoro, then you should update the submodules after pulling changes. @@ -1495,7 +1508,7 @@ If you have already cloned cppcoro, then you should update the submodules after c:\Code\cppcoro> git submodule update --init --recursive ``` -## Building from the command-line +### Building from the command-line To build from the command-line just run 'cake.bat' in the workspace root. @@ -1510,6 +1523,7 @@ Compiling test\main.cpp Compiling test\main.cpp Compiling test\main.cpp Compiling test\main.cpp +... Linking build\windows_x86_msvc14.10_debug\test\run.exe Linking build\windows_x64_msvc14.10_optimised\test\run.exe Linking build\windows_x86_msvc14.10_optimised\test\run.exe @@ -1522,7 +1536,7 @@ Build succeeded. Build took 0:00:02.419. ``` -By default this will build all projects with all build variants and execute the unit-tests. +By default, running `cake` with no arguments will build all projects with all build variants and execute the unit-tests. You can narrow what is built by passing additional command-line arguments. eg. ``` @@ -1535,9 +1549,9 @@ Build took 0:00:00.321. You can run `cake --help` to list available command-line options. -## Building Visual Studio project files +### Building Visual Studio project files -To develop from within Visual Studio you can build .vcproj/.sln files by running `cake -p`. +To develop from within Visual Studio you can build .vcproj/.sln files by running `cake.bat -p`. eg. ``` @@ -1556,3 +1570,197 @@ Build took 0:00:00.247. ``` When you build these projects from within Visual Studio it will call out to cake to perform the compilation. + +## Building on Linux + +The cppcoro project can also be built under Linux using Clang + libc++ 5.0 or later. + +Building cppcoro has been tested under Ubuntu 17.04. + +### Prerequisities + +Ensure you have the following packages installed: +* Python 2.7 +* Clang >= 5.0 +* LLD >= 5.0 +* libc++ >= 5.0 + + +### Building cppcoro + +This is assuming you have Clang and libc++ built and installed. + +If you don't have Clang configured yet, see the following sections +for details on setting up Clang for building with cppcoro. + +Checkout cppcoro and its submodules: +``` +git clone --recursive https://github.com/lewissbaker/cppcoro.git cppcoro +``` + +Run `init.sh` to setup the `cake` bash function: +``` +cd cppcoro +source init.sh +``` + +Then you can run `cake` from the workspace root to build cppcoro and run tests: +``` +$ cake +``` + +You can specify additional command-line arguments to customise the build: +* `--help` will print out help for command-line arguments +* `--debug=run` will show the build command-lines being run +* `release=debug` or `release=optimised` will limit the build variant to + either debug or optimised (by default it will build both). +* `lib/build.cake` will just build the cppcoro library and not the tests. +* `test/build.cake@task_tests.cpp` will just compile a particular source file + +For example: +``` +$ cake --debug=run release=debug lib/build.cake +``` + +### Customising location of Clang + +If your clang compiler is not located at `/usr/bin/clang` then you need to +modify the `config.cake` file to tell cake where to find clang. + +Edit the following line in `config.cake`: +```python + # If you have built your own version of Clang, you can modify + # this variable to point to the CMAKE_INSTALL_PREFIX for + # where you have installed your clang/libcxx build. + clangInstallPrefix = '/usr' +``` + +If you have `libc++` installed in a different location then you can +customise its location by modifying the following line in `config.cake`. +```python + # Set this to the install-prefix of where libc++ is installed. + # You only need to set this if it is not installed at the same + # location as clangInstallPrefix. + libCxxInstallPrefix = None # '/path/to/install' +``` + +If the install location has multiple versions of Clang installed and +the one you want to use is not `/bin/clang` then you +can explicitly specify which one to use by modifying the `config.cake` +file to specify the name of the clang binaries: +```python + compiler = ClangCompiler( + configuration=configuration, + clangExe=cake.path.join(clangBinPath, 'clang-6.0'), + llvmArExe=cake.path.join(clangBinPath, 'llvm-ar-6.0'), + binPaths=[clangBinPath]) +``` + +### Using a snapshot build of Clang + +If your Linux distribution does not have a version of Clang 5.0 or later +available, you can install a snapshot build from the LLVM project. + +Follow instructions at http://apt.llvm.org/ to setup your package manager +to support pulling from the LLVM package manager. + +For example, for Ubuntu 17.04 Zesty: + +Edit `/etc/apt/sources.list` and add the following lines: +``` +deb http://apt.llvm.org/zesty/ llvm-toolchain-zesty main +deb-src http://apt.llvm.org/zesty/ llvm-toolchain-zesty main +``` + +Install the PGP key for those packages: +``` +$ wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - +``` + +Install Clang and LLD: +``` +$ sudo apt-get install clang-6.0 lld-6.0 +``` + +The LLVM snapshot builds do not include libc++ versions so you'll need to build that yourself. +See below. + +### Building your own Clang + +You can also use the bleeding-edge Clang version by building Clang from source yourself. + +See instructions here: + +To do this you will need to install the following pre-requisites: +``` +$ sudo apt-get install git cmake ninja-build clang lld +``` + +Note that we are using your distribution's version of clang to build +clang from source. GCC could also be used here instead. + + +Checkout LLVM + Clang + LLD + libc++ repositories: +``` +mkdir llvm +cd llvm +git clone --depth=1 https://github.com/llvm-mirror/llvm.git llvm +git clone --depth=1 https://github.com/llvm-mirror/clang.git llvm/tools/clang +git clone --depth=1 https://github.com/llvm-mirror/lld.git llvm/tools/lld +git clone --depth=1 https://github.com/llvm-mirror/libcxx.git llvm/projects/libcxx +ln -s llvm/tools/clang clang +ln -s llvm/tools/lld lld +ln -s llvm/projects/libcxx libcxx +``` + +Configure and build Clang: +``` +mkdir clang-build +cd clang-build +cmake -GNinja \ + -DCMAKE_CXX_COMPILER=/usr/bin/clang++ \ + -DCMAKE_C_COMPILER=/usr/bin/clang \ + -DCMAKE_BUILD_TYPE=MinSizeRel \ + -DCMAKE_INSTALL_PREFIX="/path/to/clang/install" + -DCMAKE_BUILD_WITH_INSTALL_RPATH="yes" \ + -DLLVM_TARGETS_TO_BUILD=X86 \ + -DLLVM_ENABLE_PROJECTS="lld;clang" \ + ../llvm +ninja install-clang \ + install-clang-headers \ + install-llvm-ar \ + install-lld +``` + +### Building libc++ + +The cppcoro project requires libc++ as it contains the `` +header required to use C++ coroutines under Clang. + +Checkout `libc++` + `llvm`: +``` +mkdir llmv +cd llvm +git clone --depth=1 https://github.com/llvm-mirror/llvm.git llvm +git clone --depth=1 https://github.com/llvm-mirror/libcxx.git llvm/projects/libcxx +ln -s llvm/projects/libcxx libcxx +``` + +Build `libc++`: +``` +mkdir libcxx-build +cd libcxx-build +cmake -GNinja \ + -DCMAKE_CXX_COMPILER="/path/to/clang/install/bin/clang++" \ + -DCMAKE_C_COMPILER="/path/to/clang/install/bin/clang" \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX="/path/to/clang/install" + -DLLVM_PATH="../llvm" \ + -DLIBCXX_CXX_ABI=libstdc++ \ + -DLIBCXX_CXX_ABI_INCLUDE_PATHS="/usr/include/c++/6.3.0/;/usr/include/x86_64-linux-gnu/c++/6.3.0/" \ + ../libcxx +ninja cxx +ninja install +``` + +This will build and install libc++ into the same install directory where you have clang installed.