Repository.mk | 1 static/CustomTarget_unoembind.mk | 10 static/Module_static.mk | 1 static/Package_unoembind.mk | 18 + static/README.wasm.md | 18 - static/source/embindmaker/embindmaker.cxx | 335 +++++++++++++++++++----------- 6 files changed, 260 insertions(+), 123 deletions(-)
New commits: commit cbae6e581ad62771122d35742bd304be44fb982c Author: Stephan Bergmann <stephan.bergm...@allotropia.de> AuthorDate: Thu Jan 25 16:59:49 2024 +0100 Commit: Stephan Bergmann <stephan.bergm...@allotropia.de> CommitDate: Thu Jan 25 18:31:42 2024 +0100 Let embindmaker also generate a .js file with more natural names (i.e., Module.unoembind_uno.com.sun.star... vs. Module.com$sun$star$..., and see the updated examples in static/README.wasm.md for further shortening that to just css...) Change-Id: I6dc079caa8c93a4042a6a8aa2d8fcc8f76bf80f3 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162580 Tested-by: Jenkins Reviewed-by: Stephan Bergmann <stephan.bergm...@allotropia.de> diff --git a/Repository.mk b/Repository.mk index 2eb8ae6936e8..f39f9dc656df 100644 --- a/Repository.mk +++ b/Repository.mk @@ -1036,6 +1036,7 @@ $(eval $(call gb_Helper_register_packages_for_install,ooo,\ ) \ resource_fonts \ cui \ + $(if $(filter EMSCRIPTEN,$(OS)),unoembind) \ )) $(eval $(call gb_Helper_register_packages_for_install,ooo_fonts,\ diff --git a/static/CustomTarget_unoembind.mk b/static/CustomTarget_unoembind.mk index 4bed6f585fa7..cccb36f1dce2 100644 --- a/static/CustomTarget_unoembind.mk +++ b/static/CustomTarget_unoembind.mk @@ -11,12 +11,16 @@ $(eval $(call gb_CustomTarget_CustomTarget,static/unoembind)) $(eval $(call gb_CustomTarget_register_targets,static/unoembind, \ bindings_uno.cxx \ + bindings_uno.js \ )) -$(call gb_CustomTarget_get_workdir,static/unoembind)/bindings_uno.cxx: \ +$(call gb_CustomTarget_get_workdir,static/unoembind)/bindings_uno.cxx \ +$(call gb_CustomTarget_get_workdir,static/unoembind)/bindings_uno.js: \ $(call gb_Executable_get_target_for_build,embindmaker) $(call gb_UnoApi_get_target,udkapi) \ $(call gb_UnoApi_get_target,offapi) - $(call gb_Executable_get_command,embindmaker) uno +$(call gb_UnoApi_get_target,udkapi) \ - +$(call gb_UnoApi_get_target,offapi) > $@ + $(call gb_Executable_get_command,embindmaker) uno \ + $(call gb_CustomTarget_get_workdir,static/unoembind)/bindings_uno.cxx \ + $(call gb_CustomTarget_get_workdir,static/unoembind)/bindings_uno.js \ + +$(call gb_UnoApi_get_target,udkapi) +$(call gb_UnoApi_get_target,offapi) # vim: set noet sw=4 ts=4: diff --git a/static/Module_static.mk b/static/Module_static.mk index 3b785c7ba4cb..c91441a6b924 100644 --- a/static/Module_static.mk +++ b/static/Module_static.mk @@ -19,6 +19,7 @@ ifeq (EMSCRIPTEN,$(OS)) $(eval $(call gb_Module_add_targets,static,\ CustomTarget_emscripten_fs_image \ CustomTarget_unoembind \ + Package_unoembind \ StaticLibrary_unoembind \ $(if $(ENABLE_QT5), \ CustomTarget_wasm-qt5-mandelbrot_moc \ diff --git a/static/Package_unoembind.mk b/static/Package_unoembind.mk new file mode 100644 index 000000000000..d1f82b970424 --- /dev/null +++ b/static/Package_unoembind.mk @@ -0,0 +1,18 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t; fill-column: 100 -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_Package_Package,unoembind,$(call gb_CustomTarget_get_workdir,static/unoembind))) + +$(eval $(call gb_Package_use_custom_target,unoembind,static/unoembind)) + +$(eval $(call gb_Package_add_files,unoembind,$(LIBO_BIN_FOLDER), \ + bindings_uno.js \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/static/README.wasm.md b/static/README.wasm.md index f39a79247d00..2bfecb404a7e 100644 --- a/static/README.wasm.md +++ b/static/README.wasm.md @@ -223,29 +223,33 @@ improvement! ;) Some usage examples through javascript of the current implementation: ```js // inserts a string at the start of the Writer document. +Module.init_unoembind_uno(); +let css = Module.unoembind_uno.com.sun.star; xModel = Module.getCurrentModelFromViewSh(); -xTextDocument = new Module.com$sun$star$text$XTextDocumentRef(xModel, Module.UnoReference_Query.UNO_QUERY); +xTextDocument = new css.text.XTextDocument(xModel, Module.UnoReference_Query.UNO_QUERY); xText = xTextDocument.getText(); -xSimpleText = new Module.com$sun$star$text$XSimpleTextRef(xText, Module.UnoReference_Query.UNO_QUERY); +xSimpleText = new css.text.XSimpleText(xText, Module.UnoReference_Query.UNO_QUERY); xTextCursor = xSimpleText.createTextCursor(); -xTextRange = new Module.com$sun$star$text$XTextRangeRef(xTextCursor, Module.UnoReference_Query.UNO_QUERY); +xTextRange = new css.text.XTextRange(xTextCursor, Module.UnoReference_Query.UNO_QUERY); xTextRange.setString(new Module.OUString("string here!")); xModel.delete(); xTextDocument.delete(); xText.delete(); xSimpleText.delete(); xTextCursor.delete(); xTextRange.delete(); ``` ```js // changes each paragraph of the Writer document to a random color. +Module.init_unoembind_uno(); +let css = Module.unoembind_uno.com.sun.star; xModel = Module.getCurrentModelFromViewSh(); -xTextDocument = new Module.com$sun$star$text$XTextDocumentRef(xModel, Module.UnoReference_Query.UNO_QUERY); +xTextDocument = new css.text.XTextDocument(xModel, Module.UnoReference_Query.UNO_QUERY); xText = xTextDocument.getText(); -xEnumAccess = new Module.com$sun$star$container$XEnumerationAccessRef(xText, Module.UnoReference_Query.UNO_QUERY); +xEnumAccess = new css.container.XEnumerationAccess(xText, Module.UnoReference_Query.UNO_QUERY); xParaEnumeration = xEnumAccess.createEnumeration(); while (xParaEnumeration.hasMoreElements()) { - xParagraph = new Module.com$sun$star$text$XTextRangeRef(); + xParagraph = new css.text.XTextRange(); xParagraph.set(xParaEnumeration.nextElement(), Module.UnoReference_Query.UNO_QUERY); if (xParagraph.is()) { - xParaProps = new Module.com$sun$star$beans$XPropertySetRef(xParagraph, Module.UnoReference_Query.UNO_QUERY); + xParaProps = new css.beans.XPropertySet(xParagraph, Module.UnoReference_Query.UNO_QUERY); xParaProps.setPropertyValue(new Module.OUString("CharColor"), new Module.Any(Math.floor(Math.random() * 0xFFFFFF), Module.UnoType.long)); } } diff --git a/static/source/embindmaker/embindmaker.cxx b/static/source/embindmaker/embindmaker.cxx index 184d635da5c0..ed326ce4ed99 100644 --- a/static/source/embindmaker/embindmaker.cxx +++ b/static/source/embindmaker/embindmaker.cxx @@ -11,7 +11,13 @@ #include <cassert> #include <cstdlib> +#include <fstream> +#include <ios> #include <iostream> +#include <map> +#include <memory> +#include <ostream> +#include <string> #include <string_view> #include <utility> #include <vector> @@ -20,9 +26,11 @@ #include <codemaker/typemanager.hxx> #include <osl/file.hxx> #include <osl/process.h> +#include <osl/thread.h> #include <rtl/process.h> #include <rtl/ref.hxx> #include <rtl/string.hxx> +#include <rtl/textcvt.h> #include <rtl/ustrbuf.hxx> #include <rtl/ustring.hxx> #include <sal/main.h> @@ -35,14 +43,32 @@ void badUsage() { std::cerr << "Usage: " - " embindmaker <prefix> <registries> " + " embindmaker <name> <cpp-ouptput> <js-output> <registries> " "where each <registry> is '+' (primary) or ':' (secondary), followed by: either a " "new- or legacy-format .rdb file, a single .idl file, or a root directory of an " - ".idl file tree. Embind code for all primary registries is written to stdout," - "with <prefix> used as part of the name passed to EMSCRIPTEN_BINDINGS. "; + ".idl file tree. For all primary registries, Embind code is written to " + "<cpp-output> and corresponding JavaScript scaffolding code is written to " + "<js-output>. The <name> is used as part of some of the identifiers in those " + "generated files. "; std::exit(EXIT_FAILURE); } +std::string getPathnameArgument(sal_uInt32 argument) +{ + OUString arg; + rtl_getAppCommandArg(argument, &arg.pData); + OString path; + auto const enc = osl_getThreadTextEncoding(); + if (!arg.convertToString(&path, enc, + RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR + | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)) + { + std::cerr << "Cannot convert \"" << arg << "\" to system encoding " << enc << " "; + std::exit(EXIT_FAILURE); + } + return std::string(path); +} + std::pair<OUString, bool> parseRegistryArgument(sal_uInt32 argument) { OUString arg; @@ -86,10 +112,17 @@ std::pair<OUString, bool> parseRegistryArgument(sal_uInt32 argument) return { abs, primary }; } +struct Module +{ + std::map<OUString, std::shared_ptr<Module>> modules; + std::vector<OUString> interfaces; +}; + void scan(rtl::Reference<unoidl::MapCursor> const& cursor, std::u16string_view prefix, - std::vector<OUString>& interfaces) + Module* module, std::vector<OUString>& interfaces) { assert(cursor.is()); + assert(module != nullptr); for (;;) { OUString id; @@ -102,10 +135,18 @@ void scan(rtl::Reference<unoidl::MapCursor> const& cursor, std::u16string_view p switch (ent->getSort()) { case unoidl::Entity::SORT_MODULE: + { + auto& sub = module->modules[id]; + if (!sub) + { + sub = std::make_shared<Module>(); + } scan(static_cast<unoidl::ModuleEntity*>(ent.get())->createCursor(), - Concat2View(name + "."), interfaces); + Concat2View(name + "."), sub.get(), interfaces); break; + } case unoidl::Entity::SORT_INTERFACE_TYPE: + module->interfaces.emplace_back(name); interfaces.emplace_back(name); break; default: @@ -118,16 +159,17 @@ OUString cppName(OUString const& name) { return "::" + name.replaceAll(u".", u": OUString jsName(OUString const& name) { return name.replace('.', '$'); } -void dumpAttributes(OUString const& name, rtl::Reference<unoidl::InterfaceTypeEntity> const& entity) +void dumpAttributes(std::ostream& out, OUString const& name, + rtl::Reference<unoidl::InterfaceTypeEntity> const& entity) { for (auto const& attr : entity->getDirectAttributes()) { - std::cout << " .function(\"get" << attr.name << "\", &" << cppName(name) << "::get" - << attr.name << ") "; + out << " .function(\"get" << attr.name << "\", &" << cppName(name) << "::get" + << attr.name << ") "; if (!attr.readOnly) { - std::cout << " .function(\"set" << attr.name << "\", &" << cppName(name) - << "::set" << attr.name << ") "; + out << " .function(\"set" << attr.name << "\", &" << cppName(name) << "::set" + << attr.name << ") "; } } } @@ -201,7 +243,8 @@ bool passByReference(rtl::Reference<TypeManager> const& manager, OUString const& } } -void dumpType(rtl::Reference<TypeManager> const& manager, std::u16string_view name, bool isConst) +void dumpType(std::ostream& out, rtl::Reference<TypeManager> const& manager, + std::u16string_view name, bool isConst) { sal_Int32 k; std::vector<OString> args; @@ -209,69 +252,69 @@ void dumpType(rtl::Reference<TypeManager> const& manager, std::u16string_view na b2u(codemaker::UnoType::decompose(u2b(resolveAllTypedefs(manager, name)), &k, &args))); if (isConst) { - std::cout << "const "; + out << "const "; } for (sal_Int32 i = 0; i != k; ++i) { - std::cout << "::css::uno::Sequence<"; + out << "::css::uno::Sequence<"; } switch (manager->getSort(n)) { case codemaker::UnoType::Sort::Void: - std::cout << "void"; + out << "void"; break; case codemaker::UnoType::Sort::Boolean: - std::cout << "::sal_Bool"; + out << "::sal_Bool"; break; case codemaker::UnoType::Sort::Byte: - std::cout << "::sal_Int8"; + out << "::sal_Int8"; break; case codemaker::UnoType::Sort::Short: - std::cout << "::sal_Int16"; + out << "::sal_Int16"; break; case codemaker::UnoType::Sort::UnsignedShort: - std::cout << "::sal_uInt16"; + out << "::sal_uInt16"; break; case codemaker::UnoType::Sort::Long: - std::cout << "::sal_Int32"; + out << "::sal_Int32"; break; case codemaker::UnoType::Sort::UnsignedLong: - std::cout << "::sal_uInt32"; + out << "::sal_uInt32"; break; case codemaker::UnoType::Sort::Hyper: - std::cout << "::sal_Int64"; + out << "::sal_Int64"; break; case codemaker::UnoType::Sort::UnsignedHyper: - std::cout << "::sal_uInt64"; + out << "::sal_uInt64"; break; case codemaker::UnoType::Sort::Float: - std::cout << "float"; + out << "float"; break; case codemaker::UnoType::Sort::Double: - std::cout << "double"; + out << "double"; break; case codemaker::UnoType::Sort::Char: - std::cout << "::sal_Unicode"; + out << "::sal_Unicode"; break; case codemaker::UnoType::Sort::String: - std::cout << "::rtl::OUString"; + out << "::rtl::OUString"; break; case codemaker::UnoType::Sort::Type: - std::cout << "::css::uno::Type"; + out << "::css::uno::Type"; break; case codemaker::UnoType::Sort::Any: - std::cout << "::css::uno::Any"; + out << "::css::uno::Any"; break; case codemaker::UnoType::Sort::Enum: case codemaker::UnoType::Sort::PlainStruct: case codemaker::UnoType::Sort::Exception: - std::cout << cppName(n); + out << cppName(n); break; case codemaker::UnoType::Sort::PolymorphicStructTemplate: - std::cout << cppName(n); + out << cppName(n); if (!args.empty()) { - std::cout << "<"; + out << "<"; bool first = true; for (auto const& arg : args) { @@ -281,17 +324,17 @@ void dumpType(rtl::Reference<TypeManager> const& manager, std::u16string_view na } else { - std::cout << ", "; + out << ", "; } - dumpType(manager, b2u(arg), false); + dumpType(out, manager, b2u(arg), false); } - std::cout << ">"; + out << ">"; } break; case codemaker::UnoType::Sort::Interface: - std::cout << "::css::uno::Reference<"; - std::cout << cppName(n); - std::cout << ">"; + out << "::css::uno::Reference<"; + out << cppName(n); + out << ">"; break; default: throw CannotDumpException(OUString::Concat("unexpected entity \"") + name @@ -299,11 +342,11 @@ void dumpType(rtl::Reference<TypeManager> const& manager, std::u16string_view na } for (sal_Int32 i = 0; i != k; ++i) { - std::cout << ">"; + out << ">"; } } -void dumpParameters(rtl::Reference<TypeManager> const& manager, +void dumpParameters(std::ostream& out, rtl::Reference<TypeManager> const& manager, unoidl::InterfaceTypeEntity::Method const& method, bool declarations) { bool first = true; @@ -315,7 +358,7 @@ void dumpParameters(rtl::Reference<TypeManager> const& manager, } else { - std::cout << ", "; + out << ", "; } bool isConst; bool isRef; @@ -332,58 +375,60 @@ void dumpParameters(rtl::Reference<TypeManager> const& manager, // For the embind wrapper, we define a pointer instead of a reference: if (declarations) { - dumpType(manager, param.type, isConst); - std::cout << " "; + dumpType(out, manager, param.type, isConst); + out << " "; } if (isRef) { - std::cout << "*"; + out << "*"; } if (declarations) { - std::cout << " "; + out << " "; } - std::cout << param.name; + out << param.name; } } -void dumpWrapper(rtl::Reference<TypeManager> const& manager, OUString const& interfaceName, - unoidl::InterfaceTypeEntity::Method const& method, bool forReference) +void dumpWrapper(std::ostream& out, rtl::Reference<TypeManager> const& manager, + OUString const& interfaceName, unoidl::InterfaceTypeEntity::Method const& method, + bool forReference) { - std::cout << " .function(\"" << method.name << "\", +[]("; + out << " .function(\"" << method.name << "\", +[]("; if (forReference) { - std::cout << "::com::sun::star::uno::Reference<"; + out << "::com::sun::star::uno::Reference<"; } - std::cout << cppName(interfaceName); + out << cppName(interfaceName); if (forReference) { - std::cout << ">"; + out << ">"; } - std::cout << " * the_self"; + out << " * the_self"; if (!method.parameters.empty()) { - std::cout << ", "; + out << ", "; } - dumpParameters(manager, method, true); - std::cout << ") { return the_self->"; + dumpParameters(out, manager, method, true); + out << ") { return the_self->"; if (forReference) { - std::cout << "get()->"; + out << "get()->"; } - std::cout << method.name << "("; - dumpParameters(manager, method, false); - std::cout << "); }, ::emscripten::allow_raw_pointers()) "; + out << method.name << "("; + dumpParameters(out, manager, method, false); + out << "); }, ::emscripten::allow_raw_pointers()) "; } -void dumpMethods(rtl::Reference<TypeManager> const& manager, OUString const& name, - rtl::Reference<unoidl::InterfaceTypeEntity> const& entity, bool forReference) +void dumpMethods(std::ostream& out, rtl::Reference<TypeManager> const& manager, + OUString const& name, rtl::Reference<unoidl::InterfaceTypeEntity> const& entity, + bool forReference) { for (auto const& meth : entity->getDirectMethods()) { if (forReference) { - dumpWrapper(manager, name, meth, true); + dumpWrapper(out, manager, name, meth, true); } else if (std::any_of( meth.parameters.begin(), meth.parameters.end(), [](auto const& parameter) { @@ -391,15 +436,45 @@ void dumpMethods(rtl::Reference<TypeManager> const& manager, OUString const& nam != unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN; })) { - dumpWrapper(manager, name, meth, false); + dumpWrapper(out, manager, name, meth, false); } else { - std::cout << " .function(\"" << meth.name << "\", &" << cppName(name) - << "::" << meth.name << ") "; + out << " .function(\"" << meth.name << "\", &" << cppName(name) + << "::" << meth.name << ") "; } } } + +void writeJsMap(std::ostream& out, Module const& module, std::string const& prefix) +{ + auto comma = false; + for (auto const& ifc : module.interfaces) + { + if (comma) + { + out << ", "; + } + out << prefix << "'" << ifc.copy(ifc.lastIndexOf('.') + 1) << "': Module." << jsName(ifc) + << "Ref"; + comma = true; + } + for (auto const & [ id, sub ] : module.modules) + { + if (comma) + { + out << ", "; + } + out << prefix << "'" << id << "': { "; + writeJsMap(out, *sub, prefix + " "); + out << prefix << "}"; + comma = true; + } + if (comma) + { + out << " "; + } +} } SAL_IMPLEMENT_MAIN() @@ -407,14 +482,16 @@ SAL_IMPLEMENT_MAIN() try { auto const args = rtl_getAppCommandArgCount(); - if (args == 0) + if (args < 3) { badUsage(); } - OUString prefix; - rtl_getAppCommandArg(0, &prefix.pData); + OUString name; + rtl_getAppCommandArg(0, &name.pData); + auto const cppPathname = getPathnameArgument(1); + auto const jsPathname = getPathnameArgument(2); rtl::Reference<TypeManager> mgr(new TypeManager); - for (sal_uInt32 i = 1; i != args; ++i) + for (sal_uInt32 i = 3; i != args; ++i) { auto const & [ uri, primary ] = parseRegistryArgument(i); try @@ -427,67 +504,99 @@ SAL_IMPLEMENT_MAIN() std::exit(EXIT_FAILURE); } } + auto const module = std::make_shared<Module>(); std::vector<OUString> interfaces; for (auto const& prov : mgr->getPrimaryProviders()) { - scan(prov->createRootCursor(), u"", interfaces); + scan(prov->createRootCursor(), u"", module.get(), interfaces); } - std::cout << "#include <emscripten/bind.h> " - "#include <com/sun/star/uno/Any.hxx> " - "#include <com/sun/star/uno/Reference.hxx> "; + std::ofstream cppOut(cppPathname, std::ios_base::out | std::ios_base::trunc); + if (!cppOut) + { + std::cerr << "Cannot open \"" << cppPathname << "\" for writing "; + std::exit(EXIT_FAILURE); + } + cppOut << "#include <emscripten/bind.h> " + "#include <com/sun/star/uno/Any.hxx> " + "#include <com/sun/star/uno/Reference.hxx> "; for (auto const& ifc : interfaces) { - std::cout << "#include <" << ifc.replace('.', '/') << ".hpp> "; + cppOut << "#include <" << ifc.replace('.', '/') << ".hpp> "; } - std::cout << " " - "// TODO: This is a temporary workaround that likely causes the Embind UNO " - "// bindings to leak memory. Reference counting and cloning mechanisms of " - "// Embind should be investigated to figure out what exactly we need here: " - "namespace emscripten::internal { "; + cppOut << " " + "// TODO: This is a temporary workaround that likely causes the Embind UNO " + "// bindings to leak memory. Reference counting and cloning mechanisms of " + "// Embind should be investigated to figure out what exactly we need here: " + "namespace emscripten::internal { "; for (auto const& ifc : interfaces) { - std::cout << " template<> void raw_destructor<" << cppName(ifc) << ">(" - << cppName(ifc) << " *) {} "; + cppOut << " template<> void raw_destructor<" << cppName(ifc) << ">(" << cppName(ifc) + << " *) {} "; } - std::cout << "} " - "EMSCRIPTEN_BINDINGS(uno_bindings_" - << prefix << ") { "; + cppOut << "} " + "EMSCRIPTEN_BINDINGS(unoembind_" + << name << ") { "; for (auto const& ifc : interfaces) { auto const ent = mgr->getManager()->findEntity(ifc); assert(ent.is()); assert(ent->getSort() == unoidl::Entity::SORT_INTERFACE_TYPE); rtl::Reference const ifcEnt(static_cast<unoidl::InterfaceTypeEntity*>(ent.get())); - std::cout << " ::emscripten::class_<" << cppName(ifc) << ">(\"" << jsName(ifc) - << "\") "; - dumpAttributes(ifc, ifcEnt); - dumpMethods(mgr, ifc, ifcEnt, false); - std::cout << " ; " - " ::emscripten::class_<::com::sun::star::uno::Reference<" - << cppName(ifc) - << ">, ::emscripten::base<::com::sun::star::uno::BaseReference>>(\"" - << jsName(ifc) - << "Ref\") " - " .constructor<>() " - " .constructor<::com::sun::star::uno::BaseReference, " - "::com::sun::star::uno::UnoReference_Query>() " - " .function(\"is\", &::com::sun::star::uno::Reference<" - << cppName(ifc) - << ">::is) " - " .function(\"get\", &::com::sun::star::uno::Reference<" - << cppName(ifc) - << ">::get, ::emscripten::allow_raw_pointers()) " - " .function(\"set\", " - "::emscripten::select_overload<bool(::com::sun::star::uno::Any const " - "&, " - "com::sun::star::uno::UnoReference_Query)>(&::com::sun::star::uno::" - "Reference<" - << cppName(ifc) << ">::set)) "; - dumpAttributes(ifc, ifcEnt); - dumpMethods(mgr, ifc, ifcEnt, true); - std::cout << " ; "; + cppOut << " ::emscripten::class_<" << cppName(ifc) << ">(\"" << jsName(ifc) + << "\") "; + dumpAttributes(cppOut, ifc, ifcEnt); + dumpMethods(cppOut, mgr, ifc, ifcEnt, false); + cppOut << " ; " + " ::emscripten::class_<::com::sun::star::uno::Reference<" + << cppName(ifc) + << ">, ::emscripten::base<::com::sun::star::uno::BaseReference>>(\"" + << jsName(ifc) + << "Ref\") " + " .constructor<>() " + " .constructor<::com::sun::star::uno::BaseReference, " + "::com::sun::star::uno::UnoReference_Query>() " + " .function(\"is\", &::com::sun::star::uno::Reference<" + << cppName(ifc) + << ">::is) " + " .function(\"get\", &::com::sun::star::uno::Reference<" + << cppName(ifc) + << ">::get, ::emscripten::allow_raw_pointers()) " + " .function(\"set\", " + "::emscripten::select_overload<bool(::com::sun::star::uno::Any const " + "&, " + "com::sun::star::uno::UnoReference_Query)>(&::com::sun::star::uno::" + "Reference<" + << cppName(ifc) << ">::set)) "; + dumpAttributes(cppOut, ifc, ifcEnt); + dumpMethods(cppOut, mgr, ifc, ifcEnt, true); + cppOut << " ; "; + } + cppOut << "} "; + cppOut.close(); + if (!cppOut) + { + std::cerr << "Failed to write \"" << cppPathname << "\" "; + std::exit(EXIT_FAILURE); + } + std::ofstream jsOut(jsPathname, std::ios_base::out | std::ios_base::trunc); + if (!jsOut) + { + std::cerr << "Cannot open \"" << jsPathname << "\" for writing "; + std::exit(EXIT_FAILURE); + } + jsOut << "Module.init_unoembind_" << name + << " = function() { " + " Module.unoembind_" + << name << " = { "; + writeJsMap(jsOut, *module, " "); + jsOut << " }; " + "}; "; + jsOut.close(); + if (!jsOut) + { + std::cerr << "Failed to write \"" << jsPathname << "\" "; + std::exit(EXIT_FAILURE); } - std::cout << "} "; return EXIT_SUCCESS; } catch (unoidl::FileFormatException const& e)