build(wasm): liblogging now builds for wasm

Further, due to limitations of file system access on wasm, liblogging now outputs all logs to the console syncronously
This commit is contained in:
2025-12-03 10:46:29 -05:00
parent 03bbaf1a9e
commit 888d44cec1
12 changed files with 185 additions and 27 deletions

View File

@@ -1,15 +1,23 @@
cmake = import('cmake')
quill_cmake_options = cmake.subproject_options()
quill_cmake_options.add_cmake_defines({
'BUILD_SHARED_LIBS': 'ON',
'CMAKE_SKIP_INSTALL_RULES': 'ON'
'BUILD_STATIC_LIBS': 'ON',
'BUILD_SHARED_LIBS': 'OFF',
'CMAKE_SKIP_INSTALL_RULES': 'ON',
'CMAKE_POSITION_INDEPENDENT_CODE': 'ON'
})
quill_sp = cmake.subproject(
'quill',
options: quill_cmake_options,
)
quill_dep = quill_sp.dependency('quill')
message('Registering quill headers (' + meson.global_source_root() + '/subprojects/quill/include/quill) for installation...')
quill_headers = meson.global_source_root() + '/subprojects/quill/include/quill'
install_subdir(quill_headers, install_dir: get_option('includedir'))
message('Done registering quill headers for installation!')
if get_option('default_library') != 'static'
message('Registering quill headers for installation...')
# Note: verify this path matches your source structure
quill_headers = meson.global_source_root() + '/subprojects/quill/include/quill'
install_subdir(quill_headers, install_dir: get_option('includedir'))
endif

19
cross/macos_arm64.ini Normal file
View File

@@ -0,0 +1,19 @@
[binaries]
c = 'arm64-apple-darwin25-clang'
cpp = 'arm64-apple-darwin25-clang++'
ar = 'arm64-apple-darwin25-ar'
strip = 'arm64-apple-darwin25-strip'
pkg-config = 'pkg-config'
ranlib = '/usr/bin/true'
[host_machine]
system = 'darwin'
cpu_family = 'aarch64'
cpu = 'arm64'
endian = 'little'
[built-in options]
c_args = ['-mmacosx-version-min=15.0']
cpp_args = ['-mmacos-version-min=15.0']
c_link_args = ['-mmacosx-version-min=15.0']
cpp_link_args = ['-mmacos-version-min=15.0']

23
cross/wasm.ini Normal file
View File

@@ -0,0 +1,23 @@
[binaries]
c = 'emcc'
cpp = 'em++'
ar = 'emar'
strip = 'emstrip'
exec_wrapper = 'node'
[built-in options]
c_args = ['-Dpkg_config=false', '-Dbuild_tests=false', '-Dbuild_examples=true', '-s', 'MEMORY64=1', '-pthread', '-DQUILL_NO_THREAD_NAME_SUPPORT', '-DQUILL_IMMEDIATE_FLUSH']
cpp_args = ['-Dpkg_config=false', '-Dbuild_tests=false', '-Dbuild_examples=true', '-fwasm-exceptions', '-s', 'MEMORY64=1', '-pthread', '-DQUILL_NO_THREAD_NAME_SUPPORT', '-DQUILL_IMMEDIATE_FLUSH']
c_link_args = ['-s', 'WASM=1', '-s', 'ALLOW_MEMORY_GROWTH=1', '-s', 'MEMORY64=1', '-fwasm-exceptions', '-pthread', '-s', 'EXPORTED_RUNTIME_METHODS=["FS", "callMain"]']
cpp_link_args = ['-s', 'WASM=1', '-s', 'ALLOW_MEMORY_GROWTH=1', '-s', 'MEMORY64=1', '-fwasm-exceptions', '-pthread', '-s', 'EXPORTED_RUNTIME_METHODS=["FS", "callMain"]']
[host_machine]
system = 'emscripten'
cpu_family = 'wasm64'
cpu = 'wasm64'
endian = 'little'
[properties]
cmake_toolchain_file = '/home/tboudreaux/Programming/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake'

1
examples/meson.build Normal file
View File

@@ -0,0 +1 @@
executable('simple_logging_test', 'simple.cpp', dependencies: [logging_dep])

16
examples/simple.cpp Normal file
View File

@@ -0,0 +1,16 @@
#include <string>
#include <iostream>
#include "quill/LogMacros.h"
#include "fourdst/logging/logging.h"
int main() {
auto& logManager = fourdst::logging::LogManager::getInstance();
quill::Logger* logger = logManager.newFileLogger("test.log", "logger");
std::cout << "Logging...\n";
LOG_INFO(logger, "This is an info message: {}", 42);
std::cout << "Done Logging\n";
}

View File

@@ -18,15 +18,24 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# *********************************************************************** #
project('liblogging', 'cpp', version: 'v1.1.0', default_options: ['cpp_std=c++23'], meson_version: '>=1.5.0')
project('liblogging', 'cpp', version: 'v1.1.1', default_options: ['cpp_std=c++23'], meson_version: '>=1.5.0')
# Add default visibility for all C++ targets
add_project_arguments('-fvisibility=default', language: 'cpp')
subdir('build-config')
subdir('src')
subdir('tests')
if get_option('pkg-config')
if get_option('build_tests')
subdir('tests')
endif
if get_option('build_examples')
subdir('examples')
endif
if get_option('pkg_config')
message('Generating pkg-config file for liblogging...')
pkg = import('pkgconfig')
pkg.generate(

View File

@@ -1 +1,3 @@
option('pkg-config', type: 'boolean', value: true, description: 'generate pkg-config file for liblogging (fourdst_liblogging.pc)')
option('pkg_config', type: 'boolean', value: true, description: 'generate pkg-config file for liblogging (fourdst_liblogging.pc)')
option('build_tests', type: 'boolean', value: true, description: 'generate unit tests (uses gtest)')
option('build_examples', type: 'boolean', value: true, description: 'generate example programs')

View File

@@ -24,7 +24,6 @@
#include <string>
#include <map>
#include <vector>
#include <utility>
#include "quill/Logger.h"

View File

@@ -22,17 +22,17 @@
#include "quill/Frontend.h"
#include "quill/Logger.h"
#include "quill/sinks/ConsoleSink.h"
#include "quill/sinks/FileSink.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include <stdexcept>
#include <stdexcept>
#include <string>
#include <iostream>
#include <chrono>
#include <cmath>
#include <vector>
#include <utility>
#include <filesystem>
#if defined(__EMSCRIPTEN__)
#include <ranges>
#endif
#include "fourdst/logging/logging.h"
@@ -41,28 +41,43 @@ namespace fourdst::logging {
LogManager::LogManager() {
quill::Backend::start();
auto CLILogger = quill::Frontend::create_or_get_logger(
"root",
quill::Frontend::create_or_get_sink<quill::ConsoleSink>("sink_id_1"));
newFileLogger("fourdst.log", "log");
loggerMap.emplace("stdout", CLILogger);
}
#if defined(__EMSCRIPTEN__)
LogManager::~LogManager() {
for (const auto& logger : loggerMap | std::views::values) {
logger->flush_log();
}
quill::Backend::stop();
}
#else
LogManager::~LogManager() = default;
#endif
quill::Logger* LogManager::getLogger(const std::string& loggerName) {
auto it = loggerMap.find(loggerName); // Find *once*
auto it = loggerMap.find(loggerName);
if (it == loggerMap.end()) {
throw std::runtime_error("Cannot find logger " + loggerName);
}
return it->second; // Return the raw pointer from the shared_ptr
return it->second;
}
std::vector<std::string> LogManager::getLoggerNames() {
std::vector<std::string> loggerNames;
loggerNames.reserve(loggerMap.size());
for (const auto& pair : loggerMap) { // Use range-based for loop and const auto&
for (const auto& pair : loggerMap) {
loggerNames.push_back(pair.first);
}
return loggerNames;
@@ -72,13 +87,21 @@ std::vector<quill::Logger*> LogManager::getLoggers() {
std::vector<quill::Logger*> loggers;
loggers.reserve(loggerMap.size());
for (const auto& pair : loggerMap) {
loggers.push_back(pair.second); // Get the raw pointer
loggers.push_back(pair.second);
}
return loggers;
}
quill::Logger* LogManager::newFileLogger(const std::string& filename,
const std::string& loggerName) {
const std::string& loggerName) {
#if defined(__EMSCRIPTEN__)
auto proxy_sink = quill::Frontend::create_or_get_sink<quill::ConsoleSink>("sink_id_1");
quill::Logger* rawLogger = quill::Frontend::create_or_get_logger(loggerName, std::move(proxy_sink));
loggerMap.emplace(loggerName, rawLogger);
return rawLogger;
#else
auto file_sink = quill::Frontend::create_or_get_sink<quill::FileSink>(
filename,
[]() {
@@ -87,12 +110,13 @@ quill::Logger* LogManager::newFileLogger(const std::string& filename,
return cfg;
}(),
quill::FileEventNotifier{});
// Get the raw pointer.
quill::Logger* rawLogger = quill::Frontend::create_or_get_logger(loggerName, std::move(file_sink));
// Create a shared_ptr from the raw pointer.
loggerMap.emplace(loggerName, rawLogger);
return rawLogger;
#endif
}
} // namespace Probe
}

View File

@@ -0,0 +1,20 @@
--- quill/include/quill/core/Rdtsc.h.orig 2025-12-03 09:43:26.530875697 -0500
+++ quill/include/quill/core/Rdtsc.h 2025-12-03 09:42:49.852913743 -0500
@@ -16,7 +16,7 @@
#elif defined(__ARM_ARCH)
#include <chrono>
#include <cstdint>
-#elif (defined(_M_ARM) || defined(_M_ARM64))
+#elif (defined(_M_ARM) || defined(_M_ARM64) || defined(__wasm__))
#include <chrono>
#include <cstdint>
#elif (defined(__PPC64__))
@@ -72,7 +72,7 @@
// soft failover
return static_cast<uint64_t>(std::chrono::system_clock::now().time_since_epoch().count());
}
-#elif (defined(_M_ARM) || defined(_M_ARM64) || defined(__PPC64__))
+#elif (defined(_M_ARM) || defined(_M_ARM64) || defined(__PPC64__) || defined(__wasm__))
QUILL_NODISCARD QUILL_ATTRIBUTE_HOT inline uint64_t rdtsc() noexcept
{
// soft failover

View File

@@ -0,0 +1,36 @@
--- quill/inlcude/quill/backend/BackendUtilities.h.orig 2025-12-03 10:02:26.861779737 -0500
+++ quill/include/quill/backend/BackendUtilities.h 2025-12-03 10:09:04.509482559 -0500
@@ -35,7 +35,7 @@
#elif defined(__CYGWIN__)
#include <sched.h>
#include <unistd.h>
-#elif defined(__linux__)
+#elif (defined(__linux__) || defined(__EMSCRIPTEN__))
#include <pthread.h>
#include <sched.h>
#include <unistd.h>
@@ -84,6 +84,8 @@
thread_port_t mach_thread = pthread_mach_thread_np(pthread_self());
thread_policy_set(mach_thread, THREAD_AFFINITY_POLICY, (thread_policy_t)&policy, 1);
+#elif defined(__EMSCRIPTEN__)
+ (void)cpu_id;
#else
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
@@ -102,7 +104,7 @@
/***/
QUILL_ATTRIBUTE_COLD inline void set_thread_name(char const* name)
{
-#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) || defined(QUILL_NO_THREAD_NAME_SUPPORT)
+#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) || defined(QUILL_NO_THREAD_NAME_SUPPORT) || defined(__EMSCRIPTEN__)
// Disabled on MINGW / Cygwin.
(void)name;
#elif defined(_WIN32)
@@ -154,4 +156,4 @@
}
} // namespace detail
-QUILL_END_NAMESPACE
\ No newline at end of file
+QUILL_END_NAMESPACE

View File

@@ -1,5 +1,6 @@
[wrap-git]
url = https://github.com/odygrd/quill
revision = v8.1.1
diff_files = quill/add_wasm_rdtsc_fallback_support.patch, quill/enable_pthread_header_emscripted.patch
[cmake]
[cmake]