From 32b3fa462b013897124ff718e0c27504d49b7998 Mon Sep 17 00:00:00 2001 From: Gabriel Terwesten Date: Thu, 3 Mar 2022 17:20:52 +0100 Subject: [PATCH 1/4] Port to emscripten (cherry picked from commit 9e3f4d7af598e582f59291cc2481a20fb335cd4a) # Conflicts: # C/tests/CMakeLists.txt # C/tests/c4DatabaseTest.cc # LiteCore/Support/Error.cc # LiteCore/Support/FilePath.cc # LiteCore/Support/LogDecoder.cc # LiteCore/Support/Logging.cc # LiteCore/Support/MultiLogDecoder.hh # LiteCore/Support/StringUtil.cc # LiteCore/Support/StringUtil.hh # LiteCore/Support/ThreadUtil.cc # LiteCore/tests/DataFileTest.cc # LiteCore/tests/SQLiteFunctionsTest.cc # REST/tests/RESTListenerTest.cc --- C/tests/CMakeLists.txt | 10 +- C/tests/c4DatabaseTest.cc | 4 + C/tests/cmake/platform_emscripten.cmake | 32 +++++ CMakeLists.txt | 7 ++ LiteCore/Storage/UnicodeCollator_JS.cc | 113 ++++++++++++++++++ LiteCore/Support/Error.cc | 2 +- LiteCore/Support/FilePath.cc | 29 ++++- LiteCore/Support/LogDecoder.cc | 2 +- LiteCore/Support/Logging.cc | 4 +- LiteCore/Support/MultiLogDecoder.hh | 7 +- LiteCore/Support/StringUtil.cc | 4 +- LiteCore/Support/StringUtil.hh | 2 +- LiteCore/Support/StringUtil_JS.cc | 29 +++++ LiteCore/Support/ThreadUtil.cc | 11 +- LiteCore/tests/CMakeLists.txt | 2 + LiteCore/tests/DataFileTest.cc | 31 +++-- LiteCore/tests/SQLiteFunctionsTest.cc | 8 +- .../tests/cmake/platform_emscripten.cmake | 21 ++++ Networking/BLIP/CMakeLists.txt | 2 + .../BLIP/cmake/platform_emscripten.cmake | 32 +++++ Networking/NetworkInterfaces.cc | 2 + REST/tests/RESTListenerTest.cc | 7 +- build_cmake/scripts/build_tests_emscripten.sh | 13 ++ cmake/platform_emscripten.cmake | 49 ++++++++ scripts/run_tests_with_nodejs.sh | 6 + vendor/fleece | 2 +- 26 files changed, 398 insertions(+), 33 deletions(-) create mode 100644 C/tests/cmake/platform_emscripten.cmake create mode 100644 LiteCore/Storage/UnicodeCollator_JS.cc create mode 100644 LiteCore/Support/StringUtil_JS.cc create mode 100644 LiteCore/tests/cmake/platform_emscripten.cmake create mode 100644 Networking/BLIP/cmake/platform_emscripten.cmake create mode 100755 build_cmake/scripts/build_tests_emscripten.sh create mode 100644 cmake/platform_emscripten.cmake create mode 100755 scripts/run_tests_with_nodejs.sh diff --git a/C/tests/CMakeLists.txt b/C/tests/CMakeLists.txt index 96401e86b..08c409764 100644 --- a/C/tests/CMakeLists.txt +++ b/C/tests/CMakeLists.txt @@ -36,6 +36,8 @@ elseif(APPLE) include("${CMAKE_CURRENT_LIST_DIR}/cmake/platform_apple.cmake") elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") include("${CMAKE_CURRENT_LIST_DIR}/cmake/platform_linux.cmake") +elseif(EMSCRIPTEN) + include("${CMAKE_CURRENT_LIST_DIR}/cmake/platform_emscripten.cmake") else() message(FATAL_ERROR "Unsupported platform ${CMAKE_SYSTEM_NAME}") endif() @@ -56,15 +58,10 @@ add_executable( # EE tests: c4DatabaseEncryptionTest.cc c4CertificateTest.cc - + ${TOP}LiteCore/tests/main.cpp ${TOP}Crypto/SecureRandomize.cc - ${TOP}LiteCore/Support/FilePath.cc - ${TOP}LiteCore/Support/LogDecoder.cc - ${TOP}LiteCore/Support/Logging_Stub.cc - ${TOP}LiteCore/Support/StringUtil.cc ${TOP}LiteCore/Support/TestsCommon.cc - ${TOP}LiteCore/Support/Error.cc ${TOP}vendor/fleece/ObjC/slice+CoreFoundation.cc ) @@ -112,6 +109,7 @@ target_include_directories( ${TOP}vendor/fleece/API ${TOP}vendor/fleece/Fleece/Support ${TOP}C + ${TOP}C/include ${TOP}Crypto ${TOP}Replicator ${TOP}Replicator/tests diff --git a/C/tests/c4DatabaseTest.cc b/C/tests/c4DatabaseTest.cc index 350e7b04f..f789df853 100644 --- a/C/tests/c4DatabaseTest.cc +++ b/C/tests/c4DatabaseTest.cc @@ -80,7 +80,11 @@ N_WAY_TEST_CASE_METHOD(C4DatabaseTest, "Database ErrorMessages", "[Database][Err assertMessage(SQLiteDomain, SQLITE_IOERR_ACCESS, "SQLite error 3338", "disk I/O error (3338)"); assertMessage(SQLiteDomain, SQLITE_IOERR, "SQLite error 10", "disk I/O error"); assertMessage(LiteCoreDomain, 15, "LiteCore CorruptData", "data is corrupted"); +#ifdef __EMSCRIPTEN__ + assertMessage(POSIXDomain, ENOENT, "POSIX error 44", "No such file or directory"); +#else assertMessage(POSIXDomain, ENOENT, "POSIX error 2", "No such file or directory"); +#endif assertMessage(LiteCoreDomain, kC4ErrorTransactionNotClosed, "LiteCore TransactionNotClosed", "transaction not closed"); assertMessage(SQLiteDomain, -1234, "SQLite error -1234", "unknown error (-1234)"); diff --git a/C/tests/cmake/platform_emscripten.cmake b/C/tests/cmake/platform_emscripten.cmake new file mode 100644 index 000000000..4d28c1bfe --- /dev/null +++ b/C/tests/cmake/platform_emscripten.cmake @@ -0,0 +1,32 @@ +function(setup_build) + target_sources( + C4Tests PRIVATE + ${TOP}Crypto/mbedUtils.cc + ${TOP}LiteCore/Unix/strlcat.c + ) + + target_link_libraries( + C4Tests PRIVATE + mbedcrypto + mbedx509 + ) + + target_link_options( + C4Tests PRIVATE + "-pthread" + "-fwasm-exceptions" + "-lembind" + "SHELL:-s EXIT_RUNTIME=1" + "SHELL:-s PTHREAD_POOL_SIZE=24" + "SHELL:-s ALLOW_MEMORY_GROWTH=1" + "SHELL:-s DEMANGLE_SUPPORT=1" + "SHELL:-s WASM_BIGINT=1" + "-lnodefs.js" + "-lnoderawfs.js" + ) + + target_include_directories( + C4Tests PRIVATE + ${TOP}LiteCore/Unix + ) +endfunction() diff --git a/CMakeLists.txt b/CMakeLists.txt index e2ad78687..0ef61e1ce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -141,6 +141,13 @@ elseif(ANDROID) elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") option(LITECORE_DYNAMIC_ICU "If enabled, search for ICU at runtime so as not to depend on a specific version" OFF) include("${PROJECT_SOURCE_DIR}/cmake/platform_linux_desktop.cmake") +elseif(EMSCRIPTEN) + # Emscripten does not actually support shared libraries and instead + # just builds a static library for compatibility with existing + # build setups. We just set this property to suppress a CMake warning. + set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS TRUE) + + include("${PROJECT_SOURCE_DIR}/cmake/platform_emscripten.cmake") else() message(FATAL_ERROR "Unable to determine a supported platform from ${CMAKE_SYSTEM_NAME}") endif(MSVC) diff --git a/LiteCore/Storage/UnicodeCollator_JS.cc b/LiteCore/Storage/UnicodeCollator_JS.cc new file mode 100644 index 000000000..163eda549 --- /dev/null +++ b/LiteCore/Storage/UnicodeCollator_JS.cc @@ -0,0 +1,113 @@ +// +// UnicodeCollator_JS.cc +// +// Copyright 2017-Present Couchbase, Inc. +// +// Use of this software is governed by the Business Source License included +// in the file licenses/BSL-Couchbase.txt. As of the Change Date specified +// in that file, in accordance with the Business Source License, use of this +// software will be governed by the Apache License, Version 2.0, included in +// the file licenses/APL2.txt. +// + +// This is an UnicodeCollaction implementation based on the JS Intl.Collator API. +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Collator + +#include "UnicodeCollator.hh" +#include "Error.hh" +#include "emscripten/val.h" +#include "SQLiteCpp/Exception.h" +#include + +namespace litecore { + + using namespace std; + using namespace emscripten; + + class JSCollationContext : public CollationContext { + public: + val collator = val::undefined(); + + JSCollationContext(const Collation &collation) + : CollationContext(collation) { + auto locale = val::undefined(); + auto options = val::object(); + + if (collation.localeName) { + locale = val(collation.localeName.asString()); + } + + if (collation.diacriticSensitive) { + if (collation.caseSensitive) { + options.set("sensitivity", "variant"); + } else { + options.set("sensitivity", "accent"); + } + } + else { + if (collation.caseSensitive) { + options.set("sensitivity", "case"); + } else { + options.set("sensitivity", "base"); + } + } + + collator = val::global("Intl")["Collator"].new_(locale, options); + } + }; + + unique_ptr CollationContext::create(const Collation &coll) { + return make_unique(coll); + } + + static inline int compareStringsUnicode(int len1, const void *chars1, + int len2, const void *chars2, + const JSCollationContext &ctx) { + return ctx.collator.call("compare", string((const char *)chars1, len1), + string((const char *)chars2, len2)); + } + + static int collateUnicodeCallback(void *context, + int len1, const void *chars1, + int len2, const void *chars2) { + auto &coll = *(JSCollationContext *)context; + if (coll.canCompareASCII) { + int result = CompareASCII(len1, (const uint8_t *)chars1, + len2, (const uint8_t *)chars2, coll.caseSensitive); + if (result != kCompareASCIIGaveUp) + return result; + } + return compareStringsUnicode(len1, chars1, len2, chars2, coll); + } + + int CompareUTF8(slice str1, slice str2, const Collation &coll) { + return CompareUTF8(str1, str2, JSCollationContext(coll)); + } + + int CompareUTF8(slice str1, slice str2, const CollationContext &ctx) { + return collateUnicodeCallback((void *)&ctx, (int)str1.size, str1.buf, + (int)str2.size, str2.buf); + } + + int LikeUTF8(slice str1, slice str2, const Collation &coll) { + return LikeUTF8(str1, str2, JSCollationContext(coll)); + } + + bool ContainsUTF8(slice str, slice substr, const CollationContext &ctx) { + return ContainsUTF8_Slow(str, substr, ctx); + } + + unique_ptr RegisterSQLiteUnicodeCollation(sqlite3 *dbHandle, + const Collation &coll) { + unique_ptr context(new JSCollationContext(coll)); + int rc = sqlite3_create_collation(dbHandle, + coll.sqliteName().c_str(), + SQLITE_UTF8, + (void *)context.get(), + collateUnicodeCallback); + if (rc != SQLITE_OK) + throw SQLite::Exception(dbHandle, rc); + return context; + } + +} diff --git a/LiteCore/Support/Error.cc b/LiteCore/Support/Error.cc index 071481398..3fbb8daa0 100644 --- a/LiteCore/Support/Error.cc +++ b/LiteCore/Support/Error.cc @@ -37,7 +37,7 @@ # include #endif -#if defined(__clang__) && !defined(__ANDROID__) // For logBacktrace: +#if defined(__clang__) && !defined(__ANDROID__) && !defined(__EMSCRIPTEN__) // For logBacktrace: # include // Not available in Windows? # include #endif diff --git a/LiteCore/Support/FilePath.cc b/LiteCore/Support/FilePath.cc index 8353dd357..a4481ee7e 100644 --- a/LiteCore/Support/FilePath.cc +++ b/LiteCore/Support/FilePath.cc @@ -50,7 +50,7 @@ using namespace std; using namespace fleece; using namespace litecore; -#ifdef __linux__ +#if defined(__linux__) || defined(__EMSCRIPTEN__) static int copyfile(const char* from, const char* to) { int read_fd, write_fd; off_t offset = 0; @@ -73,7 +73,31 @@ static int copyfile(const char* from, const char* to) { return write_fd; } - size_t expected = stat_buf.st_size; + #ifdef __EMSCRIPTEN__ + static const size_t kBufSize = 1024; + uint8_t buf[kBufSize]; + while (offset < stat_buf.st_size) { + auto bytes_left_to_read = (size_t)(stat_buf.st_size - offset); + auto max_bytes_to_read = std::min(bytes_left_to_read, kBufSize); + ssize_t bytes_read; + if ((bytes_read = read(read_fd, &buf, max_bytes_to_read)) < 0) { + int e = errno; + close(read_fd); + close(write_fd); + errno = e; + return -1; + } + offset = offset + bytes_read; + if (write(write_fd, &buf, bytes_read) < 0) { + int e = errno; + close(read_fd); + close(write_fd); + errno = e; + return -1; + } + } + #else + size_t expected = stat_buf.st_size; ssize_t bytes = 0; while ( bytes < expected ) { expected -= bytes; @@ -98,6 +122,7 @@ static int copyfile(const char* from, const char* to) { return -1; } } +#endif if ( close(read_fd) < 0 ) { int e = errno; diff --git a/LiteCore/Support/LogDecoder.cc b/LiteCore/Support/LogDecoder.cc index 9eac8f8c9..142663ae7 100644 --- a/LiteCore/Support/LogDecoder.cc +++ b/LiteCore/Support/LogDecoder.cc @@ -46,7 +46,7 @@ namespace litecore { auto now = time_point_cast(system_clock::now()); auto count = now.time_since_epoch().count(); - time_t secs = (time_t)count / 1000000; + time_t secs = (time_t)(count / 1000000); unsigned microsecs = count % 1000000; return {secs, microsecs}; } diff --git a/LiteCore/Support/Logging.cc b/LiteCore/Support/Logging.cc index 38be15c6e..403bdd704 100644 --- a/LiteCore/Support/Logging.cc +++ b/LiteCore/Support/Logging.cc @@ -29,7 +29,7 @@ # include #endif -#if ( defined(__linux__) || defined(__APPLE__) ) && !defined(__ANDROID__) +#if (defined(__linux__) || defined(__APPLE__) || defined(__EMSCRIPTEN__)) && !defined(__ANDROID__) # include #endif @@ -625,7 +625,7 @@ namespace litecore { static std::string classNameOf(const Logging* obj) { const char* name = typeid(*obj).name(); -#if ( defined(__linux__) || defined(__APPLE__) ) && !defined(__ANDROID__) +#if (defined(__linux__) || defined(__APPLE__) || defined(__EMSCRIPTEN__)) && !defined(__ANDROID__) // Get the name of my class, unmangle it, and remove namespaces: size_t unmangledLen; int status; diff --git a/LiteCore/Support/MultiLogDecoder.hh b/LiteCore/Support/MultiLogDecoder.hh index eb2365a34..53bcc16f1 100644 --- a/LiteCore/Support/MultiLogDecoder.hh +++ b/LiteCore/Support/MultiLogDecoder.hh @@ -14,6 +14,7 @@ #include "LogDecoder.hh" #include #include +#include #include #include #include @@ -27,8 +28,10 @@ namespace litecore { class MultiLogDecoder : public LogIterator { public: MultiLogDecoder() { - _startTime = {UINT_MAX, 0}; - for ( unsigned i = 0; i <= kMaxLevel; i++ ) _startTimeByLevel[i] = {UINT_MAX, 0}; + auto max_time_t = std::numeric_limits::max(); + _startTime = {max_time_t, 0}; + for (unsigned i = 0; i <= kMaxLevel; i++) + _startTimeByLevel[i] = {max_time_t, 0}; } /// Adds a log iterator. Must be called before calling \ref next(). diff --git a/LiteCore/Support/StringUtil.cc b/LiteCore/Support/StringUtil.cc index 93358cfda..f06303a48 100644 --- a/LiteCore/Support/StringUtil.cc +++ b/LiteCore/Support/StringUtil.cc @@ -36,7 +36,7 @@ namespace litecore { using namespace fleece; -#if defined(__ANDROID__) || defined(__GLIBC__) || defined(_MSC_VER) +#if defined(__ANDROID__) || defined(__GLIBC__) || defined(_MSC_VER) || defined(__EMSCRIPTEN__) // digittoint is a BSD function, not available on Android, Linux, etc. int digittoint(char ch) { int d = ch - '0'; @@ -264,7 +264,7 @@ namespace litecore { } -#if !__APPLE__ && !defined(_MSC_VER) && !LITECORE_USES_ICU +#if !__APPLE__ && !defined(_MSC_VER) && !LITECORE_USES_ICU && !defined(__EMSCRIPTEN__) // Stub implementation for when case conversion is unavailable alloc_slice UTF8ChangeCase(slice str, bool toUppercase) { diff --git a/LiteCore/Support/StringUtil.hh b/LiteCore/Support/StringUtil.hh index 3b9dc2351..ccf17b1e2 100644 --- a/LiteCore/Support/StringUtil.hh +++ b/LiteCore/Support/StringUtil.hh @@ -27,7 +27,7 @@ namespace litecore { using namespace fleece; -#if defined(__ANDROID__) || defined(__GLIBC__) || defined(_MSC_VER) +#if defined(__ANDROID__) || defined(__GLIBC__) || defined(_MSC_VER) || defined(__EMSCRIPTEN__) // Converts a decimal or hex digit to its integer equivalent (0..15), or 0 if not a digit. // (This function is part of in BSD and Apple OSs.) int digittoint(char ch); diff --git a/LiteCore/Support/StringUtil_JS.cc b/LiteCore/Support/StringUtil_JS.cc new file mode 100644 index 000000000..b691ba23b --- /dev/null +++ b/LiteCore/Support/StringUtil_JS.cc @@ -0,0 +1,29 @@ +// +// StringUtil_JS.cc +// +// Copyright 2017-Present Couchbase, Inc. +// +// Use of this software is governed by the Business Source License included +// in the file licenses/BSL-Couchbase.txt. As of the Change Date specified +// in that file, in accordance with the Business Source License, use of this +// software will be governed by the Apache License, Version 2.0, included in +// the file licenses/APL2.txt. +// + +#include "StringUtil.hh" +#include "emscripten/val.h" + +namespace litecore { + using namespace fleece; + + alloc_slice UTF8ChangeCase(slice str, bool toUppercase) { + auto strVal = emscripten::val(str.asString()); + std::string resultStr; + if (toUppercase){ + resultStr = strVal.call("toUpperCase"); + } else { + resultStr = strVal.call("toLowerCase"); + } + return alloc_slice(resultStr); + } +} \ No newline at end of file diff --git a/LiteCore/Support/ThreadUtil.cc b/LiteCore/Support/ThreadUtil.cc index ff87d0220..255738b19 100644 --- a/LiteCore/Support/ThreadUtil.cc +++ b/LiteCore/Support/ThreadUtil.cc @@ -36,13 +36,18 @@ # ifndef HAVE_PTHREAD_GETNAME_NP # include # endif +#ifdef __EMSCRIPTEN__ +# include +#endif namespace litecore { void SetThreadName(const char* name) { # ifdef __APPLE__ pthread_setname_np(name); -# else +#elif defined(__EMSCRIPTEN__) + emscripten_set_thread_name(pthread_self(), name); +#else pthread_setname_np(pthread_self(), name); # endif } @@ -70,7 +75,9 @@ namespace litecore { tid = syscall(SYS_gettid); # elif defined(HAVE_NR_GETTID) tid = syscall(__NR_gettid); -# endif +#elif defined(__EMSCRIPTEN__) + tid = gettid(); +#endif s << "(" << tid << ")"; return s.str(); diff --git a/LiteCore/tests/CMakeLists.txt b/LiteCore/tests/CMakeLists.txt index f77859423..2cd2f61be 100644 --- a/LiteCore/tests/CMakeLists.txt +++ b/LiteCore/tests/CMakeLists.txt @@ -38,6 +38,8 @@ elseif(APPLE) include("${CMAKE_CURRENT_LIST_DIR}/cmake/platform_apple.cmake") elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") include("${CMAKE_CURRENT_LIST_DIR}/cmake/platform_linux.cmake") +elseif(EMSCRIPTEN) + include("${CMAKE_CURRENT_LIST_DIR}/cmake/platform_emscripten.cmake") else() message(FATAL_ERROR "Unsupported platform ${CMAKE_SYSTEM_NAME}") endif() diff --git a/LiteCore/tests/DataFileTest.cc b/LiteCore/tests/DataFileTest.cc index b81cad8fc..aaf88bcc1 100644 --- a/LiteCore/tests/DataFileTest.cc +++ b/LiteCore/tests/DataFileTest.cc @@ -20,6 +20,9 @@ #ifndef _MSC_VER # include #endif +#ifdef __EMSCRIPTEN__ +#include +#endif #include "LiteCoreTest.hh" #include @@ -645,19 +648,30 @@ N_WAY_TEST_CASE_METHOD(DataFileTestFixture, "DataFile Compact", "[DataFile]") { } TEST_CASE("CanonicalPath") { +#ifdef __EMSCRIPTEN__ + auto isMacOs = (bool)EM_ASM_INT({ + if (typeof require === 'undefined') return false; + const process = require('process'); + return process.platform === 'darwin'; + }); +#endif + #ifdef _MSC_VER const char* startPath = "C:\\folder\\..\\subfolder\\"; string endPath = "C:\\subfolder\\"; #else auto tmpPath = TestFixture::sTempDir.path(); auto startPath = tmpPath + "folder/"; - ::mkdir(startPath.c_str(), 777); + ::mkdir(startPath.c_str(), 0777); startPath += "../subfolder/"; auto endPath = tmpPath + "subfolder"; - ::mkdir(endPath.c_str(), 777); -# if __APPLE__ && !TARGET_OS_IPHONE - endPath = "/private" + endPath; -# endif + ::mkdir(endPath.c_str(), 0777); +#if __APPLE__ && !TARGET_OS_IPHONE || defined(__EMSCRIPTEN__) +#ifdef __EMSCRIPTEN__ + if (isMacOs) +#endif + endPath = "/private" + endPath; +#endif #endif FilePath path(startPath); @@ -668,9 +682,12 @@ TEST_CASE("CanonicalPath") { endPath = startPath; #else startPath = tmpPath + u8"日本語"; - ::mkdir(startPath.c_str(), 777); + ::mkdir(startPath.c_str(), 0777); endPath = startPath; -# if __APPLE__ && !TARGET_OS_IPHONE +#if __APPLE__ && !TARGET_OS_IPHONE || defined(__EMSCRIPTEN__) +#ifdef __EMSCRIPTEN__ + if (isMacOs) +#endif endPath = "/private" + endPath; # endif #endif diff --git a/LiteCore/tests/SQLiteFunctionsTest.cc b/LiteCore/tests/SQLiteFunctionsTest.cc index b869d04e8..85e835c93 100644 --- a/LiteCore/tests/SQLiteFunctionsTest.cc +++ b/LiteCore/tests/SQLiteFunctionsTest.cc @@ -328,7 +328,7 @@ TEST_CASE("Unicode string functions", "[Query]") { CHECK(UTF8ChangeCase("E"_sl, true) == "E"_sl); CHECK(UTF8ChangeCase("-"_sl, true) == "-"_sl); CHECK(UTF8ChangeCase("Z•rGMai2"_sl, true) == "Z•RGMAI2"_sl); -#if __APPLE__ || defined(_MSC_VER) || LITECORE_USES_ICU +#if __APPLE__ || defined(_MSC_VER) || LITECORE_USES_ICU || defined(__EMSCRIPTEN__) CHECK(UTF8ChangeCase("Zérgmåī2"_sl, true) == "ZÉRGMÅĪ2"_sl); #endif CHECK(UTF8ChangeCase("😀"_sl, true) == "😀"_sl); @@ -338,7 +338,7 @@ TEST_CASE("Unicode string functions", "[Query]") { CHECK(UTF8ChangeCase("e"_sl, false) == "e"_sl); CHECK(UTF8ChangeCase("-"_sl, false) == "-"_sl); CHECK(UTF8ChangeCase("Z•rGMai2"_sl, false) == "z•rgmai2"_sl); -#if __APPLE__ || defined(_MSC_VER) || LITECORE_USES_ICU +#if __APPLE__ || defined(_MSC_VER)|| LITECORE_USES_ICU || defined(__EMSCRIPTEN__) CHECK(UTF8ChangeCase("zÉRGMÅĪ2"_sl, false) == "zérgmåī2"_sl); #endif CHECK(UTF8ChangeCase("😀"_sl, false) == "😀"_sl); @@ -362,7 +362,7 @@ N_WAY_TEST_CASE_METHOD(SQLiteFunctionsTest, "N1QL string functions", "[Query]") CHECK(query("SELECT N1QL_lower('cAFES17•')") == (vector{"cafes17•"})); CHECK(query("SELECT N1QL_upper('cafes17')") == (vector{"CAFES17"})); -#if __APPLE__ || defined(_MSC_VER) || LITECORE_USES_ICU +#if __APPLE__ || defined(_MSC_VER)|| LITECORE_USES_ICU || defined(__EMSCRIPTEN__) CHECK(query("SELECT N1QL_lower('cAFÉS17•')") == (vector{"cafés17•"})); CHECK(query("SELECT N1QL_upper('cafés17')") == (vector{"CAFÉS17"})); #endif @@ -385,7 +385,7 @@ N_WAY_TEST_CASE_METHOD(SQLiteFunctionsTest, "SQLite fl_blob", "[Query]") { #pragma mark - COLLATION: -#if __APPLE__ || defined(_MSC_VER) || LITECORE_USES_ICU +#if __APPLE__ || defined(_MSC_VER) || LITECORE_USES_ICU || defined(__EMSCRIPTEN__) TEST_CASE("Unicode collation", "[Query][Collation]") { struct { slice a; diff --git a/LiteCore/tests/cmake/platform_emscripten.cmake b/LiteCore/tests/cmake/platform_emscripten.cmake new file mode 100644 index 000000000..76d3c8634 --- /dev/null +++ b/LiteCore/tests/cmake/platform_emscripten.cmake @@ -0,0 +1,21 @@ +function(setup_build) + target_include_directories( + CppTests PRIVATE + ${TOP}vendor/mbedtls/include + ${TOP}LiteCore/Unix + ) + + target_link_options( + CppTests PRIVATE + "-pthread" + "-fwasm-exceptions" + "-lembind" + "SHELL:-s EXIT_RUNTIME=1" + "SHELL:-s PTHREAD_POOL_SIZE=24" + "SHELL:-s ALLOW_MEMORY_GROWTH=1" + "SHELL:-s DEMANGLE_SUPPORT=1" + "SHELL:-s WASM_BIGINT=1" + "-lnodefs.js" + "-lnoderawfs.js" + ) +endfunction() diff --git a/Networking/BLIP/CMakeLists.txt b/Networking/BLIP/CMakeLists.txt index ad75ed613..6ff1ab1de 100644 --- a/Networking/BLIP/CMakeLists.txt +++ b/Networking/BLIP/CMakeLists.txt @@ -42,6 +42,8 @@ elseif(ANDROID) include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/platform_android.cmake") elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/platform_linux.cmake") +elseif(EMSCRIPTEN) + include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/platform_emscripten.cmake") else() message(FATAL_ERROR "Unsupported platform ${CMAKE_SYSTEM_NAME}!") endif() diff --git a/Networking/BLIP/cmake/platform_emscripten.cmake b/Networking/BLIP/cmake/platform_emscripten.cmake new file mode 100644 index 000000000..d95f73fad --- /dev/null +++ b/Networking/BLIP/cmake/platform_emscripten.cmake @@ -0,0 +1,32 @@ +include("${CMAKE_CURRENT_LIST_DIR}/platform_base.cmake") + +function(set_source_files) + set(oneValueArgs RESULT) + cmake_parse_arguments(EMSCRIPTEN_SSS "" "${oneValueArgs}" "" ${ARGN}) + if(NOT DEFINED EMSCRIPTEN_SSS_RESULT) + message(FATAL_ERROR "set_source_files needs to be called with RESULT") + endif() + + set_source_files_base(RESULT BASE_SRC_FILES) + set( + ${EMSCRIPTEN_SSS_RESULT} + ${BASE_SRC_FILES} + ${SUPPORT_LOCATION}/ThreadedMailbox.cc + PARENT_SCOPE + ) +endfunction() + +function(setup_build) + add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/../../vendor/zlib" "vendor/zlib") + target_include_directories( + BLIPStatic PRIVATE + "${CMAKE_CURRENT_LIST_DIR}/../../vendor/zlib" + "${CMAKE_CURRENT_BINARY_DIR}/vendor/zlib" + ${LITECORE_LOCATION}/LiteCore/Unix + ) + + target_link_libraries( + BLIPStatic INTERFACE + zlibstatic + ) +endfunction() diff --git a/Networking/NetworkInterfaces.cc b/Networking/NetworkInterfaces.cc index de0b94ae9..fad276642 100644 --- a/Networking/NetworkInterfaces.cc +++ b/Networking/NetworkInterfaces.cc @@ -100,6 +100,8 @@ namespace litecore::net { const auto firstBytePair = addr6().__u6_addr.__u6_addr16[0]; #elif defined(__ANDROID__) const auto firstBytePair = addr6().in6_u.u6_addr16[0]; +#elif defined(__EMSCRIPTEN__) + const auto firstBytePair = addr6().__in6_union.__s6_addr16[0]; #else const auto firstBytePair = addr6().__in6_u.__u6_addr16[0]; #endif diff --git a/REST/tests/RESTListenerTest.cc b/REST/tests/RESTListenerTest.cc index 47075aa4a..1a6cd7081 100644 --- a/REST/tests/RESTListenerTest.cc +++ b/REST/tests/RESTListenerTest.cc @@ -10,6 +10,9 @@ // the file licenses/APL2.txt. // +// TODO: Port RESTListener to emscripten +#ifndef __EMSCRIPTEN__ + #include "c4Test.hh" #include "Error.hh" #include "c4Collection.h" @@ -862,6 +865,6 @@ TEST_CASE_METHOD(C4RESTTest, "REST HTTP Replicate Oneshot, Auth", "[REST][Listen CHECK(r->status() == HTTPStatus::OK); } -# endif // COUCHBASE_ENTERPRISE +#endif // COUCHBASE_ENTERPRISE -#endif +#endif // __EMSCRIPTEN__ diff --git a/build_cmake/scripts/build_tests_emscripten.sh b/build_cmake/scripts/build_tests_emscripten.sh new file mode 100755 index 000000000..8784e68e4 --- /dev/null +++ b/build_cmake/scripts/build_tests_emscripten.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +set -e + +rm -rf build +mkdir -p build +cd build + +emcmake cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo .. + +core_count=`getconf _NPROCESSORS_ONLN` +emmake make C4Tests -j `expr $core_count + 1` +emmake make CppTests -j `expr $core_count + 1` diff --git a/cmake/platform_emscripten.cmake b/cmake/platform_emscripten.cmake new file mode 100644 index 000000000..6d23a20f6 --- /dev/null +++ b/cmake/platform_emscripten.cmake @@ -0,0 +1,49 @@ +include("${CMAKE_CURRENT_LIST_DIR}/platform_unix.cmake") + +macro(check_threading) + message(STATUS "No threading checks needed for Emscripten") +endmacro() + +function(setup_globals) + setup_globals_unix() + + set(EMSCRIPTEN_COMPILE_FLAGS "-pthread -fwasm-exceptions") + + set(LITECORE_C_FLAGS ${EMSCRIPTEN_COMPILE_FLAGS} CACHE INTERNAL "") + set(LITECORE_CXX_FLAGS ${EMSCRIPTEN_COMPILE_FLAGS} CACHE INTERNAL "") +endfunction() + +function(set_litecore_source) + set(oneValueArgs RESULT) + cmake_parse_arguments(EMSCRIPTEN_SSS "" ${oneValueArgs} "" ${ARGN}) + if(NOT DEFINED EMSCRIPTEN_SSS_RESULT) + message(FATAL_ERROR set_source_files_base needs to be called with RESULT) + endif() + + set_litecore_source_base(RESULT BASE_LITECORE_FILES) + set( + ${EMSCRIPTEN_SSS_RESULT} + ${BASE_LITECORE_FILES} + LiteCore/Storage/UnicodeCollator_JS.cc + LiteCore/Support/StringUtil_JS.cc + PARENT_SCOPE + ) +endfunction() + +function(setup_litecore_build) + setup_litecore_build_unix() + + target_include_directories( + LiteCoreStatic PRIVATE + LiteCore/Unix + ) + + target_link_libraries( + LiteCoreStatic INTERFACE + zlibstatic + ) +endfunction() + +function(setup_rest_build) + setup_rest_build_unix() +endfunction() diff --git a/scripts/run_tests_with_nodejs.sh b/scripts/run_tests_with_nodejs.sh new file mode 100755 index 000000000..c71a885ca --- /dev/null +++ b/scripts/run_tests_with_nodejs.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +set -e + +node --experimental-wasm-eh build/C/tests/C4Tests.js -r list +node --experimental-wasm-eh build/LiteCore/tests/CppTests.js -r list diff --git a/vendor/fleece b/vendor/fleece index 0610a53af..58eacd72a 160000 --- a/vendor/fleece +++ b/vendor/fleece @@ -1 +1 @@ -Subproject commit 0610a53af09b05ae9841cdc01cc339b157adbce0 +Subproject commit 58eacd72a97fe8794899536bcc1ec61de44f1579 From 105e4cb6e2269ea2d92a3f4293a612d61d2d93c1 Mon Sep 17 00:00:00 2001 From: Jens Alfke Date: Thu, 13 Jun 2024 14:29:12 -0700 Subject: [PATCH 2/4] clang-tidy --- LiteCore/Storage/UnicodeCollator_JS.cc | 68 ++++++++++---------------- LiteCore/Support/Error.cc | 4 +- LiteCore/Support/FilePath.cc | 20 ++++---- LiteCore/Support/LogDecoder.cc | 2 +- LiteCore/Support/Logging.cc | 4 +- LiteCore/Support/MultiLogDecoder.hh | 5 +- LiteCore/Support/StringUtil_JS.cc | 6 +-- LiteCore/Support/ThreadUtil.cc | 14 +++--- LiteCore/tests/DataFileTest.cc | 30 ++++++------ LiteCore/tests/SQLiteFunctionsTest.cc | 4 +- REST/tests/RESTListenerTest.cc | 12 ++--- 11 files changed, 76 insertions(+), 93 deletions(-) diff --git a/LiteCore/Storage/UnicodeCollator_JS.cc b/LiteCore/Storage/UnicodeCollator_JS.cc index 163eda549..e7c2a5929 100644 --- a/LiteCore/Storage/UnicodeCollator_JS.cc +++ b/LiteCore/Storage/UnicodeCollator_JS.cc @@ -25,27 +25,23 @@ namespace litecore { using namespace emscripten; class JSCollationContext : public CollationContext { - public: + public: val collator = val::undefined(); - JSCollationContext(const Collation &collation) - : CollationContext(collation) { - auto locale = val::undefined(); + JSCollationContext(const Collation& collation) : CollationContext(collation) { + auto locale = val::undefined(); auto options = val::object(); - if (collation.localeName) { - locale = val(collation.localeName.asString()); - } + if ( collation.localeName ) { locale = val(collation.localeName.asString()); } - if (collation.diacriticSensitive) { - if (collation.caseSensitive) { + if ( collation.diacriticSensitive ) { + if ( collation.caseSensitive ) { options.set("sensitivity", "variant"); } else { options.set("sensitivity", "accent"); } - } - else { - if (collation.caseSensitive) { + } else { + if ( collation.caseSensitive ) { options.set("sensitivity", "case"); } else { options.set("sensitivity", "base"); @@ -56,58 +52,46 @@ namespace litecore { } }; - unique_ptr CollationContext::create(const Collation &coll) { + unique_ptr CollationContext::create(const Collation& coll) { return make_unique(coll); } - static inline int compareStringsUnicode(int len1, const void *chars1, - int len2, const void *chars2, - const JSCollationContext &ctx) { - return ctx.collator.call("compare", string((const char *)chars1, len1), - string((const char *)chars2, len2)); + static inline int compareStringsUnicode(int len1, const void* chars1, int len2, const void* chars2, + const JSCollationContext& ctx) { + return ctx.collator.call("compare", string((const char*)chars1, len1), string((const char*)chars2, len2)); } - static int collateUnicodeCallback(void *context, - int len1, const void *chars1, - int len2, const void *chars2) { - auto &coll = *(JSCollationContext *)context; - if (coll.canCompareASCII) { - int result = CompareASCII(len1, (const uint8_t *)chars1, - len2, (const uint8_t *)chars2, coll.caseSensitive); - if (result != kCompareASCIIGaveUp) - return result; + static int collateUnicodeCallback(void* context, int len1, const void* chars1, int len2, const void* chars2) { + auto& coll = *(JSCollationContext*)context; + if ( coll.canCompareASCII ) { + int result = CompareASCII(len1, (const uint8_t*)chars1, len2, (const uint8_t*)chars2, coll.caseSensitive); + if ( result != kCompareASCIIGaveUp ) return result; } return compareStringsUnicode(len1, chars1, len2, chars2, coll); } - int CompareUTF8(slice str1, slice str2, const Collation &coll) { + int CompareUTF8(slice str1, slice str2, const Collation& coll) { return CompareUTF8(str1, str2, JSCollationContext(coll)); } - int CompareUTF8(slice str1, slice str2, const CollationContext &ctx) { - return collateUnicodeCallback((void *)&ctx, (int)str1.size, str1.buf, - (int)str2.size, str2.buf); + int CompareUTF8(slice str1, slice str2, const CollationContext& ctx) { + return collateUnicodeCallback((void*)&ctx, (int)str1.size, str1.buf, (int)str2.size, str2.buf); } - int LikeUTF8(slice str1, slice str2, const Collation &coll) { + int LikeUTF8(slice str1, slice str2, const Collation& coll) { return LikeUTF8(str1, str2, JSCollationContext(coll)); } - bool ContainsUTF8(slice str, slice substr, const CollationContext &ctx) { + bool ContainsUTF8(slice str, slice substr, const CollationContext& ctx) { return ContainsUTF8_Slow(str, substr, ctx); } - unique_ptr RegisterSQLiteUnicodeCollation(sqlite3 *dbHandle, - const Collation &coll) { + unique_ptr RegisterSQLiteUnicodeCollation(sqlite3* dbHandle, const Collation& coll) { unique_ptr context(new JSCollationContext(coll)); - int rc = sqlite3_create_collation(dbHandle, - coll.sqliteName().c_str(), - SQLITE_UTF8, - (void *)context.get(), + int rc = sqlite3_create_collation(dbHandle, coll.sqliteName().c_str(), SQLITE_UTF8, (void*)context.get(), collateUnicodeCallback); - if (rc != SQLITE_OK) - throw SQLite::Exception(dbHandle, rc); + if ( rc != SQLITE_OK ) throw SQLite::Exception(dbHandle, rc); return context; } -} +} // namespace litecore diff --git a/LiteCore/Support/Error.cc b/LiteCore/Support/Error.cc index 3fbb8daa0..125474959 100644 --- a/LiteCore/Support/Error.cc +++ b/LiteCore/Support/Error.cc @@ -37,8 +37,8 @@ # include #endif -#if defined(__clang__) && !defined(__ANDROID__) && !defined(__EMSCRIPTEN__) // For logBacktrace: -# include // Not available in Windows? +#if defined(__clang__) && !defined(__ANDROID__) && !defined(__EMSCRIPTEN__) // For logBacktrace: +# include // Not available in Windows? # include #endif diff --git a/LiteCore/Support/FilePath.cc b/LiteCore/Support/FilePath.cc index a4481ee7e..72d3cda3f 100644 --- a/LiteCore/Support/FilePath.cc +++ b/LiteCore/Support/FilePath.cc @@ -73,14 +73,14 @@ static int copyfile(const char* from, const char* to) { return write_fd; } - #ifdef __EMSCRIPTEN__ +# ifdef __EMSCRIPTEN__ static const size_t kBufSize = 1024; - uint8_t buf[kBufSize]; - while (offset < stat_buf.st_size) { - auto bytes_left_to_read = (size_t)(stat_buf.st_size - offset); - auto max_bytes_to_read = std::min(bytes_left_to_read, kBufSize); + uint8_t buf[kBufSize]; + while ( offset < stat_buf.st_size ) { + auto bytes_left_to_read = (size_t)(stat_buf.st_size - offset); + auto max_bytes_to_read = std::min(bytes_left_to_read, kBufSize); ssize_t bytes_read; - if ((bytes_read = read(read_fd, &buf, max_bytes_to_read)) < 0) { + if ( (bytes_read = read(read_fd, &buf, max_bytes_to_read)) < 0 ) { int e = errno; close(read_fd); close(write_fd); @@ -88,7 +88,7 @@ static int copyfile(const char* from, const char* to) { return -1; } offset = offset + bytes_read; - if (write(write_fd, &buf, bytes_read) < 0) { + if ( write(write_fd, &buf, bytes_read) < 0 ) { int e = errno; close(read_fd); close(write_fd); @@ -96,8 +96,8 @@ static int copyfile(const char* from, const char* to) { return -1; } } - #else - size_t expected = stat_buf.st_size; +# else + size_t expected = stat_buf.st_size; ssize_t bytes = 0; while ( bytes < expected ) { expected -= bytes; @@ -122,7 +122,7 @@ static int copyfile(const char* from, const char* to) { return -1; } } -#endif +# endif if ( close(read_fd) < 0 ) { int e = errno; diff --git a/LiteCore/Support/LogDecoder.cc b/LiteCore/Support/LogDecoder.cc index 142663ae7..0c8f1daa4 100644 --- a/LiteCore/Support/LogDecoder.cc +++ b/LiteCore/Support/LogDecoder.cc @@ -46,7 +46,7 @@ namespace litecore { auto now = time_point_cast(system_clock::now()); auto count = now.time_since_epoch().count(); - time_t secs = (time_t)(count / 1000000); + time_t secs = (time_t)(count / 1000000); unsigned microsecs = count % 1000000; return {secs, microsecs}; } diff --git a/LiteCore/Support/Logging.cc b/LiteCore/Support/Logging.cc index 403bdd704..8e246c9e1 100644 --- a/LiteCore/Support/Logging.cc +++ b/LiteCore/Support/Logging.cc @@ -29,7 +29,7 @@ # include #endif -#if (defined(__linux__) || defined(__APPLE__) || defined(__EMSCRIPTEN__)) && !defined(__ANDROID__) +#if ( defined(__linux__) || defined(__APPLE__) || defined(__EMSCRIPTEN__) ) && !defined(__ANDROID__) # include #endif @@ -625,7 +625,7 @@ namespace litecore { static std::string classNameOf(const Logging* obj) { const char* name = typeid(*obj).name(); -#if (defined(__linux__) || defined(__APPLE__) || defined(__EMSCRIPTEN__)) && !defined(__ANDROID__) +#if ( defined(__linux__) || defined(__APPLE__) || defined(__EMSCRIPTEN__) ) && !defined(__ANDROID__) // Get the name of my class, unmangle it, and remove namespaces: size_t unmangledLen; int status; diff --git a/LiteCore/Support/MultiLogDecoder.hh b/LiteCore/Support/MultiLogDecoder.hh index 53bcc16f1..db45cec43 100644 --- a/LiteCore/Support/MultiLogDecoder.hh +++ b/LiteCore/Support/MultiLogDecoder.hh @@ -29,9 +29,8 @@ namespace litecore { public: MultiLogDecoder() { auto max_time_t = std::numeric_limits::max(); - _startTime = {max_time_t, 0}; - for (unsigned i = 0; i <= kMaxLevel; i++) - _startTimeByLevel[i] = {max_time_t, 0}; + _startTime = {max_time_t, 0}; + for ( unsigned i = 0; i <= kMaxLevel; i++ ) _startTimeByLevel[i] = {max_time_t, 0}; } /// Adds a log iterator. Must be called before calling \ref next(). diff --git a/LiteCore/Support/StringUtil_JS.cc b/LiteCore/Support/StringUtil_JS.cc index b691ba23b..710082cde 100644 --- a/LiteCore/Support/StringUtil_JS.cc +++ b/LiteCore/Support/StringUtil_JS.cc @@ -17,13 +17,13 @@ namespace litecore { using namespace fleece; alloc_slice UTF8ChangeCase(slice str, bool toUppercase) { - auto strVal = emscripten::val(str.asString()); + auto strVal = emscripten::val(str.asString()); std::string resultStr; - if (toUppercase){ + if ( toUppercase ) { resultStr = strVal.call("toUpperCase"); } else { resultStr = strVal.call("toLowerCase"); } return alloc_slice(resultStr); } -} \ No newline at end of file +} // namespace litecore \ No newline at end of file diff --git a/LiteCore/Support/ThreadUtil.cc b/LiteCore/Support/ThreadUtil.cc index 255738b19..fdd206313 100644 --- a/LiteCore/Support/ThreadUtil.cc +++ b/LiteCore/Support/ThreadUtil.cc @@ -36,18 +36,18 @@ # ifndef HAVE_PTHREAD_GETNAME_NP # include # endif -#ifdef __EMSCRIPTEN__ -# include -#endif +# ifdef __EMSCRIPTEN__ +# include +# endif namespace litecore { void SetThreadName(const char* name) { # ifdef __APPLE__ pthread_setname_np(name); -#elif defined(__EMSCRIPTEN__) +# elif defined(__EMSCRIPTEN__) emscripten_set_thread_name(pthread_self(), name); -#else +# else pthread_setname_np(pthread_self(), name); # endif } @@ -75,9 +75,9 @@ namespace litecore { tid = syscall(SYS_gettid); # elif defined(HAVE_NR_GETTID) tid = syscall(__NR_gettid); -#elif defined(__EMSCRIPTEN__) +# elif defined(__EMSCRIPTEN__) tid = gettid(); -#endif +# endif s << "(" << tid << ")"; return s.str(); diff --git a/LiteCore/tests/DataFileTest.cc b/LiteCore/tests/DataFileTest.cc index aaf88bcc1..684664cae 100644 --- a/LiteCore/tests/DataFileTest.cc +++ b/LiteCore/tests/DataFileTest.cc @@ -21,7 +21,7 @@ # include #endif #ifdef __EMSCRIPTEN__ -#include +# include #endif #include "LiteCoreTest.hh" @@ -650,9 +650,9 @@ N_WAY_TEST_CASE_METHOD(DataFileTestFixture, "DataFile Compact", "[DataFile]") { TEST_CASE("CanonicalPath") { #ifdef __EMSCRIPTEN__ auto isMacOs = (bool)EM_ASM_INT({ - if (typeof require === 'undefined') return false; - const process = require('process'); - return process.platform === 'darwin'; + if ( typeof require == = 'undefined' ) return false; + const process = require('process'); + return process.platform == = 'darwin'; }); #endif @@ -666,12 +666,12 @@ TEST_CASE("CanonicalPath") { startPath += "../subfolder/"; auto endPath = tmpPath + "subfolder"; ::mkdir(endPath.c_str(), 0777); -#if __APPLE__ && !TARGET_OS_IPHONE || defined(__EMSCRIPTEN__) -#ifdef __EMSCRIPTEN__ - if (isMacOs) -#endif - endPath = "/private" + endPath; -#endif +# if __APPLE__ && !TARGET_OS_IPHONE || defined(__EMSCRIPTEN__) +# ifdef __EMSCRIPTEN__ + if ( isMacOs ) +# endif + endPath = "/private" + endPath; +# endif #endif FilePath path(startPath); @@ -684,11 +684,11 @@ TEST_CASE("CanonicalPath") { startPath = tmpPath + u8"日本語"; ::mkdir(startPath.c_str(), 0777); endPath = startPath; -#if __APPLE__ && !TARGET_OS_IPHONE || defined(__EMSCRIPTEN__) -#ifdef __EMSCRIPTEN__ - if (isMacOs) -#endif - endPath = "/private" + endPath; +# if __APPLE__ && !TARGET_OS_IPHONE || defined(__EMSCRIPTEN__) +# ifdef __EMSCRIPTEN__ + if ( isMacOs ) +# endif + endPath = "/private" + endPath; # endif #endif diff --git a/LiteCore/tests/SQLiteFunctionsTest.cc b/LiteCore/tests/SQLiteFunctionsTest.cc index 85e835c93..77f0aff56 100644 --- a/LiteCore/tests/SQLiteFunctionsTest.cc +++ b/LiteCore/tests/SQLiteFunctionsTest.cc @@ -338,7 +338,7 @@ TEST_CASE("Unicode string functions", "[Query]") { CHECK(UTF8ChangeCase("e"_sl, false) == "e"_sl); CHECK(UTF8ChangeCase("-"_sl, false) == "-"_sl); CHECK(UTF8ChangeCase("Z•rGMai2"_sl, false) == "z•rgmai2"_sl); -#if __APPLE__ || defined(_MSC_VER)|| LITECORE_USES_ICU || defined(__EMSCRIPTEN__) +#if __APPLE__ || defined(_MSC_VER) || LITECORE_USES_ICU || defined(__EMSCRIPTEN__) CHECK(UTF8ChangeCase("zÉRGMÅĪ2"_sl, false) == "zérgmåī2"_sl); #endif CHECK(UTF8ChangeCase("😀"_sl, false) == "😀"_sl); @@ -362,7 +362,7 @@ N_WAY_TEST_CASE_METHOD(SQLiteFunctionsTest, "N1QL string functions", "[Query]") CHECK(query("SELECT N1QL_lower('cAFES17•')") == (vector{"cafes17•"})); CHECK(query("SELECT N1QL_upper('cafes17')") == (vector{"CAFES17"})); -#if __APPLE__ || defined(_MSC_VER)|| LITECORE_USES_ICU || defined(__EMSCRIPTEN__) +#if __APPLE__ || defined(_MSC_VER) || LITECORE_USES_ICU || defined(__EMSCRIPTEN__) CHECK(query("SELECT N1QL_lower('cAFÉS17•')") == (vector{"cafés17•"})); CHECK(query("SELECT N1QL_upper('cafés17')") == (vector{"CAFÉS17"})); #endif diff --git a/REST/tests/RESTListenerTest.cc b/REST/tests/RESTListenerTest.cc index 1a6cd7081..dab67827e 100644 --- a/REST/tests/RESTListenerTest.cc +++ b/REST/tests/RESTListenerTest.cc @@ -10,9 +10,6 @@ // the file licenses/APL2.txt. // -// TODO: Port RESTListener to emscripten -#ifndef __EMSCRIPTEN__ - #include "c4Test.hh" #include "Error.hh" #include "c4Collection.h" @@ -33,11 +30,14 @@ using namespace litecore::REST; using namespace std; -#if !defined(_WIN32) || defined(_WIN64) +#if ( !defined(_WIN32) || defined(_WIN64) ) && !defined(__EMSCRIPTEN__) // These tests often hang in 32-bit Windows but let's cheekily ignore it since // this not part of Couchbase Lite directly anyway, but used in the cblite CLI // which is 64-bit only on Windows. +// TODO: Port RESTListener to emscripten + + static string to_str(FLSlice s) { return {(char*)s.buf, s.size}; } static string to_str(Value v) { return to_str(v.asString()); } @@ -865,6 +865,6 @@ TEST_CASE_METHOD(C4RESTTest, "REST HTTP Replicate Oneshot, Auth", "[REST][Listen CHECK(r->status() == HTTPStatus::OK); } -#endif // COUCHBASE_ENTERPRISE +# endif // COUCHBASE_ENTERPRISE -#endif // __EMSCRIPTEN__ +#endif // _WIN32, _Win64, __EMSCRIPTEN__ From 1d7d87fb4016a01e7d390a16fa6f7ff13b14d302 Mon Sep 17 00:00:00 2001 From: Jens Alfke Date: Fri, 14 Jun 2024 09:33:20 -0700 Subject: [PATCH 3/4] Got tests to run w/emscripten! (3 failures) CppTests: test cases: 499 | 496 passed | 3 failed assertions: 682799 | 682794 passed | 5 failed failed tests: >>> Query Functions >>> RealClockSource >>> Continuous Fast Push C4Tests: All tests passed (791941 assertions in 155 test cases) --- C/tests/CMakeLists.txt | 16 ++- C/tests/c4PerfTest.cc | 2 + C/tests/cmake/platform_emscripten.cmake | 10 +- CMakeLists.txt | 116 +++++++++--------- LiteCore/Storage/UnicodeCollator_JS.cc | 1 + LiteCore/Support/ThreadUtil.cc | 8 +- LiteCore/tests/CMakeLists.txt | 32 +++-- LiteCore/tests/DataFileTest.cc | 6 +- LiteCore/tests/LiteCoreTest.hh | 2 +- .../tests/cmake/platform_emscripten.cmake | 7 +- .../BLIP/cmake/platform_emscripten.cmake | 4 +- Replicator/tests/CookieStoreTest.cc | 1 + build_cmake/scripts/build_wasm_EE.sh | 19 +++ cmake/platform_emscripten.cmake | 12 +- cmake/platform_unix.cmake | 14 ++- 15 files changed, 163 insertions(+), 87 deletions(-) create mode 100755 build_cmake/scripts/build_wasm_EE.sh diff --git a/C/tests/CMakeLists.txt b/C/tests/CMakeLists.txt index 08c409764..e6953fad9 100644 --- a/C/tests/CMakeLists.txt +++ b/C/tests/CMakeLists.txt @@ -60,11 +60,25 @@ add_executable( c4CertificateTest.cc ${TOP}LiteCore/tests/main.cpp - ${TOP}Crypto/SecureRandomize.cc ${TOP}LiteCore/Support/TestsCommon.cc ${TOP}vendor/fleece/ObjC/slice+CoreFoundation.cc ) +if (NOT EMSCRIPTEN) + # These files contain internal functionality that isn't exported from the LiteCore shared lib. + # But C4Tests use these, so we have to compile them into its binary. + # This doesn't apply to Emscripten, bc WASM doesn't have shared libs; all linking is static. + target_sources( + C4Tests PRIVATE + ${TOP}Crypto/SecureRandomize.cc + ${TOP}LiteCore/Support/Error.cc + ${TOP}LiteCore/Support/FilePath.cc + ${TOP}LiteCore/Support/LogDecoder.cc + ${TOP}LiteCore/Support/Logging_Stub.cc + ${TOP}LiteCore/Support/StringUtil.cc + ) +endif() + get_directory_property(this_targets DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} BUILDSYSTEM_TARGETS) set(LITECORE_TARGETS ${LITECORE_TARGETS} ${this_targets} PARENT_SCOPE) setup_build() diff --git a/C/tests/c4PerfTest.cc b/C/tests/c4PerfTest.cc index 05124436c..d1d519475 100644 --- a/C/tests/c4PerfTest.cc +++ b/C/tests/c4PerfTest.cc @@ -175,6 +175,8 @@ class PerfTest : public C4Test { input += "_helium_macos"; #elif defined(__linux__) input += "_helium_linux"; +#elif defined(__EMSCRIPTEN__) + input += "_helium_emscripten"; #else # error "Unknown platform" #endif diff --git a/C/tests/cmake/platform_emscripten.cmake b/C/tests/cmake/platform_emscripten.cmake index 4d28c1bfe..cdf303ba4 100644 --- a/C/tests/cmake/platform_emscripten.cmake +++ b/C/tests/cmake/platform_emscripten.cmake @@ -1,14 +1,17 @@ function(setup_build) target_sources( C4Tests PRIVATE - ${TOP}Crypto/mbedUtils.cc ${TOP}LiteCore/Unix/strlcat.c ) target_link_libraries( C4Tests PRIVATE - mbedcrypto - mbedx509 + ) + + target_compile_options( + C4Tests PRIVATE + "-pthread" + "-fwasm-exceptions" ) target_link_options( @@ -19,7 +22,6 @@ function(setup_build) "SHELL:-s EXIT_RUNTIME=1" "SHELL:-s PTHREAD_POOL_SIZE=24" "SHELL:-s ALLOW_MEMORY_GROWTH=1" - "SHELL:-s DEMANGLE_SUPPORT=1" "SHELL:-s WASM_BIGINT=1" "-lnodefs.js" "-lnoderawfs.js" diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ef61e1ce..7f3d0540e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -127,7 +127,14 @@ if(BUILD_ENTERPRISE) ) endif() -if(MSVC) +if(EMSCRIPTEN) + # Emscripten does not actually support shared libraries and instead + # just builds a static library for compatibility with existing + # build setups. We just set this property to suppress a CMake warning. + set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS TRUE) + + include("${PROJECT_SOURCE_DIR}/cmake/platform_emscripten.cmake") +elseif(MSVC) add_definitions(-DWIN32_LEAN_AND_MEAN -D_WIN32_WINNT=0x0A00) if(WINDOWS_STORE) message(FATAL_ERROR "UWP no longer supported") @@ -141,13 +148,6 @@ elseif(ANDROID) elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") option(LITECORE_DYNAMIC_ICU "If enabled, search for ICU at runtime so as not to depend on a specific version" OFF) include("${PROJECT_SOURCE_DIR}/cmake/platform_linux_desktop.cmake") -elseif(EMSCRIPTEN) - # Emscripten does not actually support shared libraries and instead - # just builds a static library for compatibility with existing - # build setups. We just set this property to suppress a CMake warning. - set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS TRUE) - - include("${PROJECT_SOURCE_DIR}/cmake/platform_emscripten.cmake") else() message(FATAL_ERROR "Unable to determine a supported platform from ${CMAKE_SYSTEM_NAME}") endif(MSVC) @@ -340,60 +340,62 @@ install(FILES ${FLEECE_HEADERS} DESTINATION include/fleece) ### Support Libraries (Add functionality, but add nothing to official API) -add_subdirectory(REST EXCLUDE_FROM_ALL) - -set( - LC_WEBSOCKET_SRC - Networking/HTTP/HTTPTypes.cc - Networking/HTTP/HTTPLogic.cc - Networking/NetworkInterfaces.cc - Networking/Poller.cc - Networking/TCPSocket.cc - Networking/TLSContext.cc - Networking/WebSockets/BuiltInWebSocket.cc - vendor/sockpp/src/acceptor.cpp - vendor/sockpp/src/connector.cpp - vendor/sockpp/src/datagram_socket.cpp - vendor/sockpp/src/exception.cpp - vendor/sockpp/src/inet_address.cpp - vendor/sockpp/src/inet6_address.cpp - vendor/sockpp/src/mbedtls_context.cpp - vendor/sockpp/src/socket.cpp - vendor/sockpp/src/stream_socket.cpp -) +if (NOT EMSCRIPTEN) + add_subdirectory(REST EXCLUDE_FROM_ALL) -add_library(LiteCoreWebSocket STATIC EXCLUDE_FROM_ALL ${LC_WEBSOCKET_SRC}) -target_include_directories( - LiteCoreWebSocket PRIVATE - C - C/include - C/Cpp_include - Crypto - LiteCore/Support - Networking - Networking/BLIP/ - Networking/HTTP - Networking/WebSockets - Replicator - REST - vendor/fleece/Fleece/Support - vendor/fleece/API - vendor/sockpp/include - vendor/mbedtls/include - vendor/mbedtls/crypto/include -) + set( + LC_WEBSOCKET_SRC + Networking/HTTP/HTTPTypes.cc + Networking/HTTP/HTTPLogic.cc + Networking/NetworkInterfaces.cc + Networking/Poller.cc + Networking/TCPSocket.cc + Networking/TLSContext.cc + Networking/WebSockets/BuiltInWebSocket.cc + vendor/sockpp/src/acceptor.cpp + vendor/sockpp/src/connector.cpp + vendor/sockpp/src/datagram_socket.cpp + vendor/sockpp/src/exception.cpp + vendor/sockpp/src/inet_address.cpp + vendor/sockpp/src/inet6_address.cpp + vendor/sockpp/src/mbedtls_context.cpp + vendor/sockpp/src/socket.cpp + vendor/sockpp/src/stream_socket.cpp + ) -target_link_libraries( - LiteCoreWebSocket PUBLIC - LiteCoreObjects -) + add_library(LiteCoreWebSocket STATIC EXCLUDE_FROM_ALL ${LC_WEBSOCKET_SRC}) + target_include_directories( + LiteCoreWebSocket PRIVATE + C + C/include + C/Cpp_include + Crypto + LiteCore/Support + Networking + Networking/BLIP/ + Networking/HTTP + Networking/WebSockets + Replicator + REST + vendor/fleece/Fleece/Support + vendor/fleece/API + vendor/sockpp/include + vendor/mbedtls/include + vendor/mbedtls/crypto/include + ) -if(LITECORE_PERF_TESTING_MODE) - target_compile_definitions( + target_link_libraries( LiteCoreWebSocket PUBLIC - LITECORE_PERF_TESTING_MODE + LiteCoreObjects ) -endif() + + if(LITECORE_PERF_TESTING_MODE) + target_compile_definitions( + LiteCoreWebSocket PUBLIC + LITECORE_PERF_TESTING_MODE + ) + endif() +endif() # NOT EMSCRIPTEN ### TESTS: diff --git a/LiteCore/Storage/UnicodeCollator_JS.cc b/LiteCore/Storage/UnicodeCollator_JS.cc index e7c2a5929..87d817fc3 100644 --- a/LiteCore/Storage/UnicodeCollator_JS.cc +++ b/LiteCore/Storage/UnicodeCollator_JS.cc @@ -23,6 +23,7 @@ namespace litecore { using namespace std; using namespace emscripten; + using namespace fleece; class JSCollationContext : public CollationContext { public: diff --git a/LiteCore/Support/ThreadUtil.cc b/LiteCore/Support/ThreadUtil.cc index fdd206313..4809aabd7 100644 --- a/LiteCore/Support/ThreadUtil.cc +++ b/LiteCore/Support/ThreadUtil.cc @@ -33,11 +33,10 @@ # ifndef HAVE_PTHREAD_THREADID_NP # include # endif -# ifndef HAVE_PTHREAD_GETNAME_NP -# include -# endif # ifdef __EMSCRIPTEN__ # include +# elif !defined(HAVE_PTHREAD_GETNAME_NP) +# include # endif namespace litecore { @@ -55,10 +54,11 @@ namespace litecore { std::string GetThreadName() { std::string retVal; std::stringstream s; - char name[256]; # if defined(HAVE_PTHREAD_GETNAME_NP) + char name[256]; if ( pthread_getname_np(pthread_self(), name, 255) == 0 && name[0] != 0 ) { s << name << " "; } # elif defined(HAVE_PRCTL) + char name[256]; if ( prctl(PR_GET_NAME, name, 0, 0, 0) == 0 ) { s << name << " "; } # else s << " "; diff --git a/LiteCore/tests/CMakeLists.txt b/LiteCore/tests/CMakeLists.txt index 2cd2f61be..4ff8773da 100644 --- a/LiteCore/tests/CMakeLists.txt +++ b/LiteCore/tests/CMakeLists.txt @@ -71,9 +71,6 @@ add_executable( UpgraderTest.cc VectorQueryTest.cc VersionVectorTest.cc - ${TOP}REST/tests/RESTListenerTest.cc - ${TOP}REST/tests/RESTClientTest.cc - ${TOP}REST/tests/SyncListenerTest.cc ${TOP}vendor/fleece/Tests/API_ValueTests.cc ${TOP}vendor/fleece/Tests/DeltaTests.cc ${TOP}vendor/fleece/Tests/EncoderTests.cc @@ -89,13 +86,8 @@ add_executable( ${TOP}Replicator/tests/DBAccessTestWrapper.cc ${TOP}Replicator/tests/PropertyEncryptionTests.cc ${TOP}Replicator/tests/ReplicatorLoopbackTest.cc - ${TOP}Replicator/tests/ReplicatorAPITest.cc - ${TOP}Replicator/tests/ReplicatorSGTest.cc ${TOP}Replicator/tests/ReplicatorCollectionTest.cc - ${TOP}Replicator/tests/ReplicatorCollectionSGTest.cc - ${TOP}Replicator/tests/ReplicatorSG30Test.cc ${TOP}Replicator/tests/ReplicatorVVUpgradeTest.cc - ${TOP}Replicator/tests/SG.cc ${TOP}Replicator/tests/SGTestUser.cc ${TOP}Replicator/tests/ReplParams.cc ${TOP}C/tests/c4Test.cc @@ -105,6 +97,20 @@ add_executable( main.cpp ) +if (NOT EMSCRIPTEN) + target_sources( + CppTests PRIVATE + ${TOP}REST/tests/RESTListenerTest.cc + ${TOP}REST/tests/RESTClientTest.cc + ${TOP}REST/tests/SyncListenerTest.cc + ${TOP}Replicator/tests/ReplicatorAPITest.cc + ${TOP}Replicator/tests/ReplicatorSGTest.cc + ${TOP}Replicator/tests/ReplicatorCollectionSGTest.cc + ${TOP}Replicator/tests/ReplicatorSG30Test.cc + ${TOP}Replicator/tests/SG.cc + ) +endif() + get_directory_property(this_targets DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} BUILDSYSTEM_TARGETS) set(LITECORE_TARGETS ${LITECORE_TARGETS} ${this_targets} PARENT_SCOPE) setup_build() @@ -159,6 +165,12 @@ target_link_libraries( LiteCoreUnitTesting FleeceObjects BLIPObjects - LiteCoreREST_Static - LiteCoreWebSocket ) + +if (NOT EMSCRIPTEN) + target_link_libraries( + CppTests PRIVATE + LiteCoreREST_Static + LiteCoreWebSocket + ) +endif() diff --git a/LiteCore/tests/DataFileTest.cc b/LiteCore/tests/DataFileTest.cc index 684664cae..9c23961af 100644 --- a/LiteCore/tests/DataFileTest.cc +++ b/LiteCore/tests/DataFileTest.cc @@ -649,11 +649,13 @@ N_WAY_TEST_CASE_METHOD(DataFileTestFixture, "DataFile Compact", "[DataFile]") { TEST_CASE("CanonicalPath") { #ifdef __EMSCRIPTEN__ + // clang-format off auto isMacOs = (bool)EM_ASM_INT({ - if ( typeof require == = 'undefined' ) return false; + if ( typeof require === 'undefined' ) return false; const process = require('process'); - return process.platform == = 'darwin'; + return process.platform === 'darwin'; }); + // clang-format on #endif #ifdef _MSC_VER diff --git a/LiteCore/tests/LiteCoreTest.hh b/LiteCore/tests/LiteCoreTest.hh index 3df7faff8..7525c87ca 100644 --- a/LiteCore/tests/LiteCoreTest.hh +++ b/LiteCore/tests/LiteCoreTest.hh @@ -51,7 +51,7 @@ std::string stringWithFormat(const char* format, ...) __printflike(1, 2); */ template static std::string randomDigitString() { - static_assert(1 < numDigits <= 64); + static_assert(1 < numDigits && numDigits <= 64); static_assert(numDigits % 2 == 0); auto appendEightDigits = [](std::stringstream& sstr) { auto now = std::chrono::high_resolution_clock::now(); diff --git a/LiteCore/tests/cmake/platform_emscripten.cmake b/LiteCore/tests/cmake/platform_emscripten.cmake index 76d3c8634..247234663 100644 --- a/LiteCore/tests/cmake/platform_emscripten.cmake +++ b/LiteCore/tests/cmake/platform_emscripten.cmake @@ -5,6 +5,12 @@ function(setup_build) ${TOP}LiteCore/Unix ) + target_compile_options( + CppTests PRIVATE + "-pthread" + "-fwasm-exceptions" + ) + target_link_options( CppTests PRIVATE "-pthread" @@ -13,7 +19,6 @@ function(setup_build) "SHELL:-s EXIT_RUNTIME=1" "SHELL:-s PTHREAD_POOL_SIZE=24" "SHELL:-s ALLOW_MEMORY_GROWTH=1" - "SHELL:-s DEMANGLE_SUPPORT=1" "SHELL:-s WASM_BIGINT=1" "-lnodefs.js" "-lnoderawfs.js" diff --git a/Networking/BLIP/cmake/platform_emscripten.cmake b/Networking/BLIP/cmake/platform_emscripten.cmake index d95f73fad..0e17ba464 100644 --- a/Networking/BLIP/cmake/platform_emscripten.cmake +++ b/Networking/BLIP/cmake/platform_emscripten.cmake @@ -19,14 +19,14 @@ endfunction() function(setup_build) add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/../../vendor/zlib" "vendor/zlib") target_include_directories( - BLIPStatic PRIVATE + BLIPObjects PRIVATE "${CMAKE_CURRENT_LIST_DIR}/../../vendor/zlib" "${CMAKE_CURRENT_BINARY_DIR}/vendor/zlib" ${LITECORE_LOCATION}/LiteCore/Unix ) target_link_libraries( - BLIPStatic INTERFACE + BLIPObjects INTERFACE zlibstatic ) endfunction() diff --git a/Replicator/tests/CookieStoreTest.cc b/Replicator/tests/CookieStoreTest.cc index f5c06042c..b2739cba6 100644 --- a/Replicator/tests/CookieStoreTest.cc +++ b/Replicator/tests/CookieStoreTest.cc @@ -184,6 +184,7 @@ TEST_CASE("Cookie Parser Failure", "[cookies]") { "name=value; Max-Age=", }; for ( const auto& badCookie : badCookies ) { + ExpectingExceptions x; INFO("Checking " << badCookie); Cookie c(badCookie, "example.com", "/"); CHECK(!c); diff --git a/build_cmake/scripts/build_wasm_EE.sh b/build_cmake/scripts/build_wasm_EE.sh new file mode 100755 index 000000000..564d85c56 --- /dev/null +++ b/build_cmake/scripts/build_wasm_EE.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +# Copyright 2020-Present Couchbase, Inc. +# +# Use of this software is governed by the Business Source License included in +# the file licenses/BSL-Couchbase.txt. As of the Change Date specified in that +# file, in accordance with the Business Source License, use of this software +# will be governed by the Apache License, Version 2.0, included in the file +# licenses/APL2.txt. + +set -e + +SCRIPT_DIR=`dirname $0` +cd $SCRIPT_DIR/.. +mkdir -p wasm_EE +cd wasm_EE + +emcmake cmake -DBUILD_ENTERPRISE=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo ../.. +emmake make -j diff --git a/cmake/platform_emscripten.cmake b/cmake/platform_emscripten.cmake index 6d23a20f6..b1d4d1e21 100644 --- a/cmake/platform_emscripten.cmake +++ b/cmake/platform_emscripten.cmake @@ -8,9 +8,6 @@ function(setup_globals) setup_globals_unix() set(EMSCRIPTEN_COMPILE_FLAGS "-pthread -fwasm-exceptions") - - set(LITECORE_C_FLAGS ${EMSCRIPTEN_COMPILE_FLAGS} CACHE INTERNAL "") - set(LITECORE_CXX_FLAGS ${EMSCRIPTEN_COMPILE_FLAGS} CACHE INTERNAL "") endfunction() function(set_litecore_source) @@ -38,6 +35,15 @@ function(setup_litecore_build) LiteCore/Unix ) + foreach(platform LiteCoreObjects LiteCoreUnitTesting BLIPObjects CouchbaseSqlite3 SQLite3_UnicodeSN) + target_compile_options( + ${platform} PRIVATE + #${EMSCRIPTEN_COMPILE_FLAGS} + "-pthread" + "-fwasm-exceptions" + ) + endforeach() + target_link_libraries( LiteCoreStatic INTERFACE zlibstatic diff --git a/cmake/platform_unix.cmake b/cmake/platform_unix.cmake index 6bcfc0e6a..9df1ac732 100644 --- a/cmake/platform_unix.cmake +++ b/cmake/platform_unix.cmake @@ -79,24 +79,34 @@ function(setup_litecore_build_unix) target_compile_options(${liteCoreVariant} PRIVATE ${LITECORE_WARNINGS} -Wformat=2 - -fstack-protector -D_FORTIFY_SOURCE=2 $<$:-Wno-psabi;-Wno-odr> $<$:${LITECORE_CXX_WARNINGS}> $<$:${LITECORE_C_WARNINGS}> ) + if (NOT EMSCRIPTEN) + target_compile_options(${liteCoreVariant} PRIVATE + -fstack-protector + ) + endif() endforeach() target_compile_options(BLIPObjects PRIVATE ${LITECORE_WARNINGS} -Wformat=2 - -fstack-protector -D_FORTIFY_SOURCE=2 $<$:-Wno-psabi;-Wno-odr> $<$:${LITECORE_CXX_WARNINGS}> $<$:${LITECORE_C_WARNINGS}> ) + if (NOT EMSCRIPTEN) + target_compile_options(BLIPObjects PRIVATE + -fstack-protector + ) + endif() + + set(CMAKE_EXTRA_INCLUDE_FILES "sys/socket.h") check_type_size(socklen_t SOCKLEN_T) if(${HAVE_SOCKLEN_T}) From 0c5efc709a4037ab991d6cd9eb2064643188d5dc Mon Sep 17 00:00:00 2001 From: Jens Alfke Date: Fri, 14 Jun 2024 14:29:13 -0700 Subject: [PATCH 4/4] Tweaked Emscripten build flags to make WASM smaller - Defined the compile/link flags as variables and reuse them - Enabled LTO - Forced -Os, since build type MinSizeRel doesn't seem to do anything - Changed build type to Release, since the debug symbols add ~50MB to the .wasm files --- C/tests/cmake/platform_emscripten.cmake | 7 ++----- CMakeLists.txt | 2 +- LiteCore/tests/cmake/platform_emscripten.cmake | 7 ++----- Xcode/LiteCore.xcodeproj/project.pbxproj | 8 ++++++++ build_cmake/scripts/build_wasm_EE.sh | 2 +- cmake/platform_emscripten.cmake | 13 +++++++++---- vendor/fleece | 2 +- 7 files changed, 24 insertions(+), 17 deletions(-) diff --git a/C/tests/cmake/platform_emscripten.cmake b/C/tests/cmake/platform_emscripten.cmake index cdf303ba4..71048adab 100644 --- a/C/tests/cmake/platform_emscripten.cmake +++ b/C/tests/cmake/platform_emscripten.cmake @@ -10,15 +10,12 @@ function(setup_build) target_compile_options( C4Tests PRIVATE - "-pthread" - "-fwasm-exceptions" + ${EMSCRIPTEN_COMPILE_FLAGS} ) target_link_options( C4Tests PRIVATE - "-pthread" - "-fwasm-exceptions" - "-lembind" + ${EMSCRIPTEN_LINK_FLAGS} "SHELL:-s EXIT_RUNTIME=1" "SHELL:-s PTHREAD_POOL_SIZE=24" "SHELL:-s ALLOW_MEMORY_GROWTH=1" diff --git a/CMakeLists.txt b/CMakeLists.txt index 7f3d0540e..842714593 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -150,7 +150,7 @@ elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") include("${PROJECT_SOURCE_DIR}/cmake/platform_linux_desktop.cmake") else() message(FATAL_ERROR "Unable to determine a supported platform from ${CMAKE_SYSTEM_NAME}") -endif(MSVC) +endif() check_threading() setup_globals() diff --git a/LiteCore/tests/cmake/platform_emscripten.cmake b/LiteCore/tests/cmake/platform_emscripten.cmake index 247234663..d7825dd91 100644 --- a/LiteCore/tests/cmake/platform_emscripten.cmake +++ b/LiteCore/tests/cmake/platform_emscripten.cmake @@ -7,15 +7,12 @@ function(setup_build) target_compile_options( CppTests PRIVATE - "-pthread" - "-fwasm-exceptions" + ${EMSCRIPTEN_COMPILE_FLAGS} ) target_link_options( CppTests PRIVATE - "-pthread" - "-fwasm-exceptions" - "-lembind" + ${EMSCRIPTEN_LINK_FLAGS} "SHELL:-s EXIT_RUNTIME=1" "SHELL:-s PTHREAD_POOL_SIZE=24" "SHELL:-s ALLOW_MEMORY_GROWTH=1" diff --git a/Xcode/LiteCore.xcodeproj/project.pbxproj b/Xcode/LiteCore.xcodeproj/project.pbxproj index 8ae6aaf99..0fda1f47b 100644 --- a/Xcode/LiteCore.xcodeproj/project.pbxproj +++ b/Xcode/LiteCore.xcodeproj/project.pbxproj @@ -1179,6 +1179,10 @@ 275FF6661E42A90C005F90DD /* QueryParserTables.hh */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = QueryParserTables.hh; sourceTree = ""; }; 275FF6D11E4947E1005F90DD /* c4BaseTest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = c4BaseTest.cc; sourceTree = ""; }; 2760FBC826210AA0000F34C5 /* CollectionImpl.hh */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = CollectionImpl.hh; sourceTree = ""; }; + 27614AA12C1CDCCB0065FBB5 /* cmake */ = {isa = PBXFileReference; lastKnownFileType = folder; name = cmake; path = ../cmake; sourceTree = ""; }; + 27614AA52C1CDCEA0065FBB5 /* cmake */ = {isa = PBXFileReference; lastKnownFileType = folder; path = cmake; sourceTree = ""; }; + 27614AA62C1CDD110065FBB5 /* cmake */ = {isa = PBXFileReference; lastKnownFileType = folder; path = cmake; sourceTree = ""; }; + 27614AA72C1CDDB00065FBB5 /* cmake */ = {isa = PBXFileReference; lastKnownFileType = folder; path = cmake; sourceTree = ""; }; 2761F3EE1EE9CC58006D4BB8 /* CookieStore.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CookieStore.cc; sourceTree = ""; }; 2761F3EF1EE9CC58006D4BB8 /* CookieStore.hh */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = CookieStore.hh; sourceTree = ""; }; 2761F3F61EEA00C3006D4BB8 /* CookieStoreTest.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CookieStoreTest.cc; sourceTree = ""; }; @@ -1915,6 +1919,7 @@ 2708FE591CF4D0450022F721 /* LiteCoreTest.hh */, 274D040A1BA75E1C00FF7C35 /* main.cpp */, 2750735A1F4B5ECC003D2CCE /* CMakeLists.txt */, + 27614AA72C1CDDB00065FBB5 /* cmake */, 2719253B23970F4E0053DDA6 /* replacedb */, ); name = "C++ Tests"; @@ -2101,6 +2106,7 @@ children = ( 2744B329241854F2005A194D /* README.md */, 2744B30C241854F2005A194D /* CMakeLists.txt */, + 27614AA62C1CDD110065FBB5 /* cmake */, 2744B317241854F2005A194D /* BLIPConnection.hh */, 2744B319241854F2005A194D /* BLIP.hh */, 2744B31C241854F2005A194D /* MessageBuilder.hh */, @@ -2234,6 +2240,7 @@ 2783DF981D27436700F84E6E /* c4ThreadingTest.cc */, 2700BB612170117F00797537 /* EE */, 275073591F4B5E66003D2CCE /* CMakeLists.txt */, + 27614AA52C1CDCEA0065FBB5 /* cmake */, 2719253323970C7F0053DDA6 /* data */, ); path = tests; @@ -2260,6 +2267,7 @@ children = ( 273AD3CF18F4B23A007D8C23 /* README.md */, 275073581F4B5E13003D2CCE /* CMakeLists.txt */, + 27614AA12C1CDCCB0065FBB5 /* cmake */, 2757DE551B9FC34E002EE261 /* API */, 2745B7CA26825F970012A17A /* docs */, 27E4871019217187007D8940 /* LiteCore */, diff --git a/build_cmake/scripts/build_wasm_EE.sh b/build_cmake/scripts/build_wasm_EE.sh index 564d85c56..8eadeeb9b 100755 --- a/build_cmake/scripts/build_wasm_EE.sh +++ b/build_cmake/scripts/build_wasm_EE.sh @@ -15,5 +15,5 @@ cd $SCRIPT_DIR/.. mkdir -p wasm_EE cd wasm_EE -emcmake cmake -DBUILD_ENTERPRISE=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo ../.. +emcmake cmake -DBUILD_ENTERPRISE=ON -DCMAKE_BUILD_TYPE=Release ../.. emmake make -j diff --git a/cmake/platform_emscripten.cmake b/cmake/platform_emscripten.cmake index b1d4d1e21..fe7a61eae 100644 --- a/cmake/platform_emscripten.cmake +++ b/cmake/platform_emscripten.cmake @@ -4,10 +4,16 @@ macro(check_threading) message(STATUS "No threading checks needed for Emscripten") endmacro() +set(EMSCRIPTEN_COMPILE_FLAGS "-pthread" "-fwasm-exceptions" "-Os") +set(EMSCRIPTEN_LINK_FLAGS "-pthread" "-fwasm-exceptions" "-lembind") + function(setup_globals) setup_globals_unix() - set(EMSCRIPTEN_COMPILE_FLAGS "-pthread -fwasm-exceptions") + #if(NOT DISABLE_LTO_BUILD) + set(EMSCRIPTEN_COMPILE_FLAGS ${EMSCRIPTEN_COMPILE_FLAGS} "-flto" PARENT_SCOPE) + set(EMSCRIPTEN_LINK_FLAGS ${EMSCRIPTEN_LINK_FLAGS} "-flto" PARENT_SCOPE) + #endif() endfunction() function(set_litecore_source) @@ -35,12 +41,11 @@ function(setup_litecore_build) LiteCore/Unix ) + message(STATUS "Emscripten flags are ${EMSCRIPTEN_COMPILE_FLAGS}") foreach(platform LiteCoreObjects LiteCoreUnitTesting BLIPObjects CouchbaseSqlite3 SQLite3_UnicodeSN) target_compile_options( ${platform} PRIVATE - #${EMSCRIPTEN_COMPILE_FLAGS} - "-pthread" - "-fwasm-exceptions" + ${EMSCRIPTEN_COMPILE_FLAGS} ) endforeach() diff --git a/vendor/fleece b/vendor/fleece index 58eacd72a..de2fdb29e 160000 --- a/vendor/fleece +++ b/vendor/fleece @@ -1 +1 @@ -Subproject commit 58eacd72a97fe8794899536bcc1ec61de44f1579 +Subproject commit de2fdb29e419458367ee821ebc8096e0d6c74c7f