From 1a7f4837c6a2a9472144891e5db8342526d6b8ab Mon Sep 17 00:00:00 2001 From: Emily Boudreaux Date: Wed, 3 Dec 2025 08:54:33 -0500 Subject: [PATCH] build(wasm): libconfig now builds and works in wasm --- build-config/yaml-cpp/meson.build | 30 +++++++++++++++++++++++--- cross/macos_arm64.ini | 19 +++++++++++++++++ cross/wasm.ini | 19 +++++++++++++++++ examples/config_example.yml | 4 ++++ examples/meson.build | 2 ++ examples/simple.cpp | 35 +++++++++++++++++++++++++++++++ examples/wasm.cpp | 19 +++++++++++++++++ meson.build | 13 +++++++++--- meson_options.txt | 4 +++- 9 files changed, 138 insertions(+), 7 deletions(-) create mode 100644 cross/macos_arm64.ini create mode 100644 cross/wasm.ini create mode 100644 examples/config_example.yml create mode 100644 examples/meson.build create mode 100644 examples/simple.cpp create mode 100644 examples/wasm.cpp diff --git a/build-config/yaml-cpp/meson.build b/build-config/yaml-cpp/meson.build index 3009725..82d1b20 100644 --- a/build-config/yaml-cpp/meson.build +++ b/build-config/yaml-cpp/meson.build @@ -2,17 +2,41 @@ cmake = import('cmake') yaml_cpp_cmake_options = cmake.subproject_options() yaml_cpp_cmake_options.add_cmake_defines({ - 'BUILD_SHARED_LIBS': 'ON', + 'BUILD_SHARED_LIBS': 'OFF', + 'BUILD_STATIC_LIBS': 'ON', 'YAML_CPP_BUILD_TESTS': 'OFF', 'CMAKE_CXX_FLAGS': '-Wno-shadow', 'CMAKE_C_FLAGS': '-Wno-shadow', 'CMAKE_INSTALL_LIBDIR': get_option('libdir'), 'CMAKE_INSTALL_INCLUDEDIR': get_option('includedir'), - 'CMAKE_POLICY_VERSION_MINIMUM': '3.5' + 'CMAKE_POLICY_VERSION_MINIMUM': '3.5', + 'CMAKE_POSITION_INDEPENDENT_CODE': 'ON' }) yaml_cpp_sp = cmake.subproject( 'yaml-cpp', options: yaml_cpp_cmake_options, ) -yaml_cpp_dep = yaml_cpp_sp.dependency('yaml-cpp') + + +yaml_cpp_tgt = yaml_cpp_sp.target('yaml-cpp') +yaml_cpp_inc = yaml_cpp_sp.include_directories('yaml-cpp') +empty_yaml_cpp_file = configure_file( + output: 'yaml_cpp_dummy_ar.cpp', + command: ['echo'], + capture: true + ) +libyaml_static = static_library( + 'yaml_cpp-static', + empty_yaml_cpp_file, + objects: [yaml_cpp_tgt.extract_all_objects(recursive: true)], + include_directories: yaml_cpp_inc, + pic: true, + install: false +) + + +yaml_cpp_dep = declare_dependency( + link_with: libyaml_static, + include_directories: yaml_cpp_inc, +) diff --git a/cross/macos_arm64.ini b/cross/macos_arm64.ini new file mode 100644 index 0000000..74dd72a --- /dev/null +++ b/cross/macos_arm64.ini @@ -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'] diff --git a/cross/wasm.ini b/cross/wasm.ini new file mode 100644 index 0000000..03fc49a --- /dev/null +++ b/cross/wasm.ini @@ -0,0 +1,19 @@ +[binaries] +cpp = 'em++' +ar = 'emar' +strip = 'emstrip' + +exec_wrapper = 'node' + +[built-in options] +cpp_args = ['-Dpkg_config=false', '-Dbuild_tests=false', '-Dbuild_examples=true', '-fwasm-exceptions', '-s', 'MEMORY64=1'] +cpp_link_args = ['-s', 'WASM=1', '-s', 'ALLOW_MEMORY_GROWTH=1', '-s', 'MEMORY64=1', '-fwasm-exceptions', '-s', 'EXPORTED_RUNTIME_METHODS=["FS", "callMain"]', '-s', 'INVOKE_RUN=0'] + +[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' diff --git a/examples/config_example.yml b/examples/config_example.yml new file mode 100644 index 0000000..d8bca95 --- /dev/null +++ b/examples/config_example.yml @@ -0,0 +1,4 @@ +men: ["John Smith", "Bill Jones"] +women: + - Karol Boudreaux + - Emily Boudreaux diff --git a/examples/meson.build b/examples/meson.build new file mode 100644 index 0000000..78c4537 --- /dev/null +++ b/examples/meson.build @@ -0,0 +1,2 @@ +executable('simple_config_test', 'simple.cpp', dependencies: [config_dep]) +executable('simple_config_wasm_test', 'wasm.cpp', dependencies: [config_dep]) diff --git a/examples/simple.cpp b/examples/simple.cpp new file mode 100644 index 0000000..e925d10 --- /dev/null +++ b/examples/simple.cpp @@ -0,0 +1,35 @@ +#include "fourdst/config/config.h" +#include +#include +#include +#include + +std::string get_validated_filename(int argc, char* argv[]) { + if (argc != 2) { + std::cout << "Usage: " << argv[0] << " " << std::endl; + exit(1); + } + + std::filesystem::path const file_path{ argv[1] }; + + if (not std::filesystem::exists(file_path) || not std::filesystem::is_regular_file(file_path)) { + std::cout << "Error: File does not exist or is not a regular file." << std::endl; + exit(1); + } + + return file_path.string(); +} + +int main(int argc, char* argv[]) { + fourdst::config::Config& config = fourdst::config::Config::getInstance(); + + std::string filename = get_validated_filename(argc, argv); + config.loadConfig(filename); + + auto men = config.get>("men", {}); + + for (const auto& name : men) { + std::cout << "men are " << name << std::endl; + } + +} diff --git a/examples/wasm.cpp b/examples/wasm.cpp new file mode 100644 index 0000000..ecff35e --- /dev/null +++ b/examples/wasm.cpp @@ -0,0 +1,19 @@ +#include "fourdst/config/config.h" +#include +#include +#include +#include + + +int main(int argc, char* argv[]) { + fourdst::config::Config& config = fourdst::config::Config::getInstance(); + + config.loadConfig("/input.yaml"); + + auto men = config.get>("men", {}); + + for (const auto& name : men) { + std::cout << "men are " << name << std::endl; + } + +} diff --git a/meson.build b/meson.build index 3816640..4f6ac74 100644 --- a/meson.build +++ b/meson.build @@ -18,7 +18,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # *********************************************************************** # -project('libconfig', 'cpp', version: 'v1.1.3', default_options: ['cpp_std=c++23'], meson_version: '>=1.5.0') +project('libconfig', 'cpp', version: 'v1.1.4', 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') @@ -26,9 +26,16 @@ add_project_arguments('-fvisibility=default', language: 'cpp') cpp = meson.get_compiler('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 libconfig...') pkg = import('pkgconfig') pkg.generate( diff --git a/meson_options.txt b/meson_options.txt index ad7b203..0fc180a 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1 +1,3 @@ -option('pkg-config', type: 'boolean', value: true, description: 'generate pkg-config file for libconfig (fourdst_config.pc)') +option('pkg_config', type: 'boolean', value: true, description: 'generate pkg-config file for libconfig (fourdst_config.pc)') +option('build_tests', type: 'boolean', value: true, description: 'Build unit and integration tests (uses gtest)') +option('build_examples', type: 'boolean', value: true, description: 'Build simple example programs')