summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephan Bergmann <stephan.bergmann@allotropia.de>2024-01-21 14:50:15 +0100
committerStephan Bergmann <stephan.bergmann@allotropia.de>2024-01-21 15:51:39 +0100
commitb2ade3e63e34556cad8157e25f8c75d29e79537d (patch)
tree3d268145cc15bedf0d1860c2285ba37c5d62969f
parentwriterfilter : use constexpr frozen unordered_set instead of std::unordered_set (diff)
downloadcore-b2ade3e63e34556cad8157e25f8c75d29e79537d.tar.gz
core-b2ade3e63e34556cad8157e25f8c75d29e79537d.zip
Extract embindmaker from cppumaker into its own tool
...that directly generates one large .cxx Change-Id: I046539b83f8fde5eda7168c93a8b819137399665 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162343 Tested-by: Jenkins Reviewed-by: Stephan Bergmann <stephan.bergmann@allotropia.de>
-rw-r--r--Repository.mk1
-rw-r--r--RepositoryModule_build.mk1
-rw-r--r--codemaker/source/cppumaker/cppuoptions.cxx18
-rw-r--r--codemaker/source/cppumaker/cpputype.cxx204
-rw-r--r--codemaker/source/cppumaker/cpputype.hxx3
-rw-r--r--codemaker/source/cppumaker/dumputils.cxx14
-rw-r--r--codemaker/source/cppumaker/dumputils.hxx3
-rw-r--r--configure.ac3
-rw-r--r--include/codemaker/typemanager.hxx5
-rw-r--r--solenv/gbuild/UnoApi.mk17
-rw-r--r--solenv/gbuild/UnoApiTarget.mk15
-rw-r--r--solenv/gbuild/extensions/pre_BuildTools.mk1
-rw-r--r--static/CustomTarget_unoembind.mk22
-rw-r--r--static/Executable_embindmaker.mk26
-rw-r--r--static/Module_static.mk8
-rw-r--r--static/StaticLibrary_unoembind.mk27
-rw-r--r--static/source/embindmaker/embindmaker.cxx510
17 files changed, 606 insertions, 272 deletions
diff --git a/Repository.mk b/Repository.mk
index 3e2e29098e66..2eb8ae6936e8 100644
--- a/Repository.mk
+++ b/Repository.mk
@@ -33,6 +33,7 @@ $(eval $(call gb_Helper_register_executables,NONE, \
concat-deps \
cpp \
cppunittester \
+ $(if $(or $(filter EMSCRIPTEN,$(BUILD_TYPE_FOR_HOST)),$(filter EMSCRIPTEN,$(OS))),embindmaker) \
gbuildtojson \
$(if $(filter MSC,$(COM)), \
gcc-wrapper \
diff --git a/RepositoryModule_build.mk b/RepositoryModule_build.mk
index 2059c1f2a5a9..3efcb3cad705 100644
--- a/RepositoryModule_build.mk
+++ b/RepositoryModule_build.mk
@@ -45,6 +45,7 @@ $(eval $(call gb_Module_add_moduledirs,cross_toolset,\
shell \
solenv \
soltools \
+ $(if $(filter EMSCRIPTEN,$(BUILD_TYPE_FOR_HOST)),static) \
stoc \
store \
tools \
diff --git a/codemaker/source/cppumaker/cppuoptions.cxx b/codemaker/source/cppumaker/cppuoptions.cxx
index 548b4d369a8e..d16c7dacecba 100644
--- a/codemaker/source/cppumaker/cppuoptions.cxx
+++ b/codemaker/source/cppumaker/cppuoptions.cxx
@@ -216,24 +216,6 @@ bool CppuOptions::initOptions(int ac, char* av[], bool bCmdFile)
m_options["-G"_ostr] = OString();
break;
- case 'W': // generate embind javascript bindings for LOWA
- if (av[i][2] != '\0')
- {
- OString tmp("'-W', please check"_ostr);
- if (i <= ac - 1)
- {
- tmp += OString::Concat(" your input '") + av[i] + "'";
- }
-
- throw IllegalArgument(tmp);
- }
-
- if (!isValid("-C"_ostr) && !isValid("-CS"_ostr) && !isValid("-L"_ostr))
- {
- throw IllegalArgument("'-W' requires '-C' or '-CS' or '-L' option"_ostr);
- }
- m_options["-W"_ostr] = OString();
- break;
case 'X': // support for eXtra type rdbs
{
if (av[i][2] == '\0')
diff --git a/codemaker/source/cppumaker/cpputype.cxx b/codemaker/source/cppumaker/cpputype.cxx
index 2b995e1d31ae..9ae5d689072e 100644
--- a/codemaker/source/cppumaker/cpputype.cxx
+++ b/codemaker/source/cppumaker/cpputype.cxx
@@ -159,7 +159,6 @@ OString getFileExtension(FileType eFileType)
default:
case FileType::HDL: return ".hdl"_ostr;
case FileType::HPP: return ".hpp"_ostr;
- case FileType::EMBIND_CXX: return "_embind.cxx"_ostr;
}
}
@@ -189,8 +188,6 @@ public:
virtual void dumpHppFile(FileStream& o, codemaker::cppumaker::Includes & includes) = 0;
- void dumpEmbindCppFile(FileStream& o);
-
OUString dumpHeaderDefine(FileStream& o, std::u16string_view extension) const;
void dumpGetCppuType(FileStream & out);
@@ -241,8 +238,6 @@ protected:
assert(false); // this cannot happen
}
- virtual void dumpEmbindDeclaration(FileStream &) {};
-
virtual void dumpFiles(OUString const & uri, CppuOptions const & options);
virtual void addLightGetCppuTypeIncludes(
@@ -324,8 +319,6 @@ void CppuType::dumpFiles(OUString const & uri, CppuOptions const & options)
{
dumpFile(uri, name_, FileType::HDL, options);
dumpFile(uri, name_, FileType::HPP, options);
- if(options.isValid("-W"_ostr))
- dumpFile(uri, name_, FileType::EMBIND_CXX, options);
}
void CppuType::addLightGetCppuTypeIncludes(
@@ -460,9 +453,6 @@ void CppuType::dumpFile(
case FileType::HDL:
dumpHdlFile(out, includes);
break;
- case FileType::EMBIND_CXX:
- dumpEmbindCppFile(out);
- break;
}
} catch (...) {
out.close();
@@ -608,13 +598,6 @@ void CppuType::dumpHFileContent(
out << " *);\n\n#endif\n";
}
-void CppuType::dumpEmbindCppFile(FileStream &out)
-{
- out << "#include <emscripten/bind.h>\n"
- "#include <" << name_.replace('.', '/') << ".hpp>\n";
- dumpEmbindDeclaration(out);
-}
-
void CppuType::dumpGetCppuType(FileStream & out)
{
if (name_ == "com.sun.star.uno.XInterface") {
@@ -1136,14 +1119,10 @@ public:
OUString const & name, rtl::Reference< TypeManager > const & typeMgr);
virtual void dumpDeclaration(FileStream& o) override;
- virtual void dumpEmbindDeclaration(FileStream& o) override;
void dumpHppFile(FileStream& o, codemaker::cppumaker::Includes & includes) override;
void dumpAttributes(FileStream& o) const;
- void dumpEmbindAttributeBindings(FileStream& o) const;
void dumpMethods(FileStream& o) const;
- void dumpEmbindMethodBindings(FileStream& o, bool bDumpForReference=false) const;
- void dumpEmbindWrapperFunc(FileStream& o, const unoidl::InterfaceTypeEntity::Method& method, bool bDumpForReference=false) const;
void dumpNormalGetCppuType(FileStream& o) override;
void dumpComprehensiveGetCppuType(FileStream& o) override;
void dumpCppuAttributeRefs(FileStream& o, sal_uInt32& index);
@@ -1214,53 +1193,6 @@ void InterfaceType::dumpDeclaration(FileStream & out)
out << "};\n\n";
}
-void InterfaceType::dumpEmbindDeclaration(FileStream & out)
-{
- // 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.
- out << "namespace emscripten { namespace internal { \n"
- "template<> void raw_destructor<" << codemaker::cpp::scopedCppName(u2b(name_))
- << ">(" << codemaker::cpp::scopedCppName(u2b(name_)) << "*){}\n"
- "}}\n";
-
- out << "EMSCRIPTEN_BINDINGS(uno_bindings_";
- codemaker::cppumaker::dumpTypeFullWithDecorator(out, name_, u"_");
- codemaker::cppumaker::dumpTypeIdentifier(out, name_);
- out << ") {\n";
-
- out << "\n::emscripten::class_<" << codemaker::cpp::scopedCppName(u2b(name_)) << ">(\"";
- codemaker::cppumaker::dumpTypeFullWithDecorator(out, name_, u"$");
- codemaker::cppumaker::dumpTypeIdentifier(out, name_);
- out << "\")\n";
-
- inc();
- // dump bindings for attributes and methods.
- dumpEmbindAttributeBindings(out);
- dumpEmbindMethodBindings(out);
- out << indent() << ";\n";
- dec();
-
- // dump reference bindings.
- out << "\n::emscripten::class_<::css::uno::Reference<" << codemaker::cpp::scopedCppName(u2b(name_)) << ">, ::emscripten::base<::css::uno::BaseReference>>(\"";
- codemaker::cppumaker::dumpTypeFullWithDecorator(out, name_, u"$");
- codemaker::cppumaker::dumpTypeIdentifier(out, name_);
- out << "Ref\")\n";
- inc();
- out << indent() << ".constructor<>()\n"
- << indent() << ".constructor<::css::uno::BaseReference, ::css::uno::UnoReference_Query>()\n"
- << indent() << ".function(\"is\", &::css::uno::Reference<" << codemaker::cpp::scopedCppName(u2b(name_)) << ">::is)\n"
- << indent() << ".function(\"get\", &::css::uno::Reference<" << codemaker::cpp::scopedCppName(u2b(name_)) << ">::get, ::emscripten::allow_raw_pointers())\n"
- << indent() << ".function(\"set\", ::emscripten::select_overload<bool(const ::css::uno::Any&, com::sun::star::uno::UnoReference_Query)>(&::css::uno::Reference<" << codemaker::cpp::scopedCppName(u2b(name_)) << ">::set))\n";
- dumpEmbindAttributeBindings(out);
- dumpEmbindMethodBindings(out, true);
- out << indent() << ";\n";
- dec();
-
- out << "}\n";
-}
-
-
void InterfaceType::dumpHppFile(
FileStream & out, codemaker::cppumaker::Includes & includes)
{
@@ -1312,31 +1244,6 @@ void InterfaceType::dumpAttributes(FileStream & out) const
}
}
-void InterfaceType::dumpEmbindAttributeBindings(FileStream& out) const
-{
- if (!entity_->getDirectAttributes().empty())
- {
- out << indent() << "// Bindings for attributes\n";
- }
- for (const unoidl::InterfaceTypeEntity::Attribute& attr : entity_->getDirectAttributes())
- {
- if (m_isDeprecated || isDeprecated(attr.annotations))
- continue;
-
- out << indent();
- out << ".function(\"";
- out << "get" << attr.name << "\", &" << codemaker::cpp::scopedCppName(u2b(name_)) << "::get"
- << attr.name << ")\n";
- if (!attr.readOnly)
- {
- out << indent();
- out << ".function(\"";
- out << "set" << attr.name << "\", &" << codemaker::cpp::scopedCppName(u2b(name_))
- << "::set" << attr.name << ")\n";
- }
- }
-}
-
void InterfaceType::dumpMethods(FileStream & out) const
{
if (!entity_->getDirectMethods().empty()) {
@@ -1377,115 +1284,6 @@ void InterfaceType::dumpMethods(FileStream & out) const
}
}
-void InterfaceType::dumpEmbindWrapperFunc(FileStream& out,
- const unoidl::InterfaceTypeEntity::Method& method,
- bool bDumpForReference) const
-{
- out << indent();
- out << ".function(\"" << method.name << "\", ";
- out << indent() << "+[](";
- if (bDumpForReference)
- out << "::css::uno::Reference<";
- out << codemaker::cpp::scopedCppName(u2b(name_));
- if (bDumpForReference)
- out << ">";
- out << "* self";
- if(!method.parameters.empty())
- out << ",";
-
- auto dumpParameters = [&](bool bDumpType)
- {
- // dumpParams with references as pointers
- if (!method.parameters.empty())
- {
- out << " ";
- for (std::vector<unoidl::InterfaceTypeEntity::Method::Parameter>::const_iterator
- parameter(method.parameters.begin());
- parameter != method.parameters.end();)
- {
- bool isConst;
- bool isRef;
- if (parameter->direction
- == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN)
- {
- isConst = passByReference(parameter->type);
- isRef = isConst;
- }
- else
- {
- isConst = false;
- isRef = true;
- }
- // for the embind wrapper, we define a pointer instead of a reference.
- if (bDumpType)
- dumpType(out, parameter->type, isConst, /*isRef=*/false);
- if (isRef)
- out << "*";
-
- out << " " << parameter->name;
- ++parameter;
- if (parameter != method.parameters.end())
- {
- out << ", ";
- }
- }
- out << " ";
- }
- };
- dumpParameters(/*bDumpType=*/true);
-
- if (bDumpForReference)
- {
- out << ") { return self->get()->" << method.name << "(";
- }
- else
- {
- out << ") { return self->" << method.name << "(";
- }
-
- dumpParameters(/*bDumpType=*/false);
- out << "); }, ::emscripten::allow_raw_pointers() )\n";
-}
-
-void InterfaceType::dumpEmbindMethodBindings(FileStream & out, bool bDumpForReference) const
-{
- if (!entity_->getDirectMethods().empty()) {
- out << indent() << "// Bindings for methods\n";
- }
- for (const unoidl::InterfaceTypeEntity::Method& method : entity_->getDirectMethods()) {
- if( m_isDeprecated || isDeprecated(method.annotations) )
- continue;
-
- // if dumping the method binding for a reference implementation
- // dump wrapper.
- if(bDumpForReference)
- {
- dumpEmbindWrapperFunc(out, method, true);
- continue;
- }
-
- bool bHasOutParams = std::any_of(
- method.parameters.begin(), method.parameters.end(),
- [](const auto& parameter) {
- return parameter.direction
- != unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN;
- });
-
- if (bHasOutParams)
- {
- dumpEmbindWrapperFunc(out, method, false);
- continue;
- }
-
- out << indent();
- out << ".function(\"" << method.name << "\", &"
- << codemaker::cpp::scopedCppName(u2b(name_))
- << "::" << method.name << ")\n";
- }
-}
-
-
-
void InterfaceType::dumpNormalGetCppuType(FileStream & out)
{
dumpGetCppuTypePreamble(out);
@@ -3748,8 +3546,6 @@ private:
virtual void dumpFiles(OUString const & uri, CppuOptions const & options) override {
dumpFile(uri, name_, FileType::HPP, options);
- if(options.isValid("-W"_ostr))
- dumpFile(uri, name_, FileType::EMBIND_CXX, options);
}
};
diff --git a/codemaker/source/cppumaker/cpputype.hxx b/codemaker/source/cppumaker/cpputype.hxx
index a6f8f9bfe8a3..c41cfa287646 100644
--- a/codemaker/source/cppumaker/cpputype.hxx
+++ b/codemaker/source/cppumaker/cpputype.hxx
@@ -32,8 +32,7 @@ namespace codemaker::cppumaker {
enum class FileType
{
HDL,
- HPP,
- EMBIND_CXX
+ HPP
};
}
diff --git a/codemaker/source/cppumaker/dumputils.cxx b/codemaker/source/cppumaker/dumputils.cxx
index 54867523b0d4..2a3e809e70f3 100644
--- a/codemaker/source/cppumaker/dumputils.cxx
+++ b/codemaker/source/cppumaker/dumputils.cxx
@@ -74,20 +74,6 @@ void dumpTypeIdentifier(FileStream & out, std::u16string_view entityName) {
out << entityName.substr(entityName.rfind('.') + 1);
}
-bool dumpTypeFullWithDecorator(FileStream& out, std::u16string_view entityName, std::u16string_view decorator)
-{
- bool bOutput = false;
- for (sal_Int32 i = 0; i >= 0;)
- {
- std::u16string_view id(o3tl::getToken(entityName, 0, '.', i));
- if (i >= 0)
- {
- out << id << decorator;
- bOutput = true;
- }
- }
- return bOutput;
-}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/codemaker/source/cppumaker/dumputils.hxx b/codemaker/source/cppumaker/dumputils.hxx
index c7021cba7408..24e5bae3bede 100644
--- a/codemaker/source/cppumaker/dumputils.hxx
+++ b/codemaker/source/cppumaker/dumputils.hxx
@@ -35,9 +35,6 @@ bool dumpNamespaceOpen(FileStream& out, std::u16string_view entityName, bool ful
bool dumpNamespaceClose(FileStream& out, std::u16string_view entityName, bool fullModuleType);
void dumpTypeIdentifier(FileStream& out, std::u16string_view entityName);
-
-bool dumpTypeFullWithDecorator(FileStream& out, std::u16string_view entityName,
- std::u16string_view decorator);
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/configure.ac b/configure.ac
index 78d9ec669c39..5e836e8c0ab4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1422,6 +1422,9 @@ if test "$_os" = "Emscripten"; then
if test $EMSCRIPTEN_ERROR -ne 0; then
AC_MSG_ERROR(["Please fix your EMSDK setup to build with Emscripten!"])
fi
+
+ dnl Some build-side things are conditional on "EMSCRIPTEN in BUILD_TYPE_FOR_HOST":
+ BUILD_TYPE="$BUILD_TYPE EMSCRIPTEN"
fi
AC_SUBST(EMSDK_FILE_PACKAGER)
diff --git a/include/codemaker/typemanager.hxx b/include/codemaker/typemanager.hxx
index 3e6f67fe4b3f..7e312f3f8094 100644
--- a/include/codemaker/typemanager.hxx
+++ b/include/codemaker/typemanager.hxx
@@ -43,8 +43,13 @@ class TypeManager final : public salhelper::SimpleReferenceObject {
public:
TypeManager();
+ rtl::Reference<unoidl::Manager> const & getManager() const { return manager_; }
+
void loadProvider(OUString const & uri, bool primary);
+ std::vector<rtl::Reference<unoidl::Provider>> const & getPrimaryProviders() const
+ { return primaryProviders_; }
+
bool foundAtPrimaryProvider(OUString const & name) const;
codemaker::UnoType::Sort getSort(
diff --git a/solenv/gbuild/UnoApi.mk b/solenv/gbuild/UnoApi.mk
index 9ed314703f33..f396642901fe 100644
--- a/solenv/gbuild/UnoApi.mk
+++ b/solenv/gbuild/UnoApi.mk
@@ -36,8 +36,6 @@ define gb_UnoApi_add_idlfiles
$(call gb_UnoApiTarget_add_idlfiles,$(1),$(2),$(3))
$(call gb_UnoApiHeadersTarget_add_headerfiles,$(1),$(2),$(addsuffix .hpp,$(3)))
$(call gb_UnoApiHeadersTarget_add_headerfiles,$(1),$(2),$(addsuffix .hdl,$(3)))
-$(if $(filter EMSCRIPTEN, $(OS)),\
- $(call gb_UnoApiHeadersTarget_add_embind,$(1),$(2),$(addsuffix _embind,$(3))))
endef
@@ -71,19 +69,4 @@ $(call gb_UnoApiTarget_set_reference_rdbfile,$(1),$(2))
endef
-ifeq ($(OS),EMSCRIPTEN)
-$(eval $(call gb_StaticLibrary_StaticLibrary,unoembind))
-$(eval $(call gb_StaticLibrary_set_include,unoembind,\
- $$(INCLUDE) \
-))
-$(eval $(call gb_StaticLibrary_use_api,unoembind,\
- offapi \
- udkapi \
-))
-$(eval $(call gb_StaticLibrary_add_exception_objects,unoembind,\
- static/source/unoembindhelpers/PrimaryBindings\
-))
-
-endif
-
# vim: set noet sw=4 ts=4:
diff --git a/solenv/gbuild/UnoApiTarget.mk b/solenv/gbuild/UnoApiTarget.mk
index e4f92eb2d985..6eacbc66a0ab 100644
--- a/solenv/gbuild/UnoApiTarget.mk
+++ b/solenv/gbuild/UnoApiTarget.mk
@@ -152,7 +152,7 @@ $(call gb_UnoApiHeadersTarget_get_real_comprehensive_target,%) : \
$(call gb_Output_announce,$*,$(true),HPC,3)
$(call gb_Trace_StartRange,$*,HPC)
$(call gb_UnoApiHeadersTarget__command,$@,$*,$(call gb_UnoApiHeadersTarget_get_comprehensive_dir,$*), \
- -C $(if $(filter EMSCRIPTEN, $(OS)), -W))
+ -C)
$(call gb_Trace_EndRange,$*,HPC)
$(call gb_UnoApiHeadersTarget_get_real_target,%) : \
@@ -237,19 +237,6 @@ define gb_UnoApiHeadersTarget_add_headerfiles
$(foreach hdr,$(3),$(call gb_UnoApiHeadersTarget_add_headerfile,$(1),$(2)/$(hdr)))
endef
-# call gb_UnoApiEmbindTarget_add_embind,unoapi,directory,headerfilenames
-define gb_UnoApiHeadersTarget_add_embind
-$(if $(filter offapi udkapi, $(1)),\
- $(foreach hdr,$(3),$(eval $(call gb_UnoApiEmbindTarget__add_embind,$(1),$(2),$(hdr)))))
-endef
-
-define gb_UnoApiEmbindTarget__add_embind
-$(eval $(call gb_StaticLibrary_add_generated_exception_objects,unoembind,\
- UnoApiHeadersTarget/$(1)/comprehensive/$(2)/$(3) \
-))
-
-endef
-
define gb_UnoApiHeadersTarget__use_api_for_target
$(call gb_UnoApiHeadersTarget_get_$(3),$(1)) : $(call gb_UnoApiTarget_get_target,$(2))
$(call gb_UnoApiHeadersTarget_get_$(3),$(1)) : UNOAPI_DEPS += -X$(call gb_UnoApiTarget_get_target,$(2))
diff --git a/solenv/gbuild/extensions/pre_BuildTools.mk b/solenv/gbuild/extensions/pre_BuildTools.mk
index c31c809b9993..2522a4e7680c 100644
--- a/solenv/gbuild/extensions/pre_BuildTools.mk
+++ b/solenv/gbuild/extensions/pre_BuildTools.mk
@@ -16,6 +16,7 @@ gb_BUILD_TOOLS_executables = \
climaker \
cpp \
cppumaker \
+ $(if $(filter EMSCRIPTEN,$(BUILD_TYPE_FOR_HOST)),embindmaker) \
gencoll_rule \
genconv_dict \
gendict \
diff --git a/static/CustomTarget_unoembind.mk b/static/CustomTarget_unoembind.mk
new file mode 100644
index 000000000000..4bed6f585fa7
--- /dev/null
+++ b/static/CustomTarget_unoembind.mk
@@ -0,0 +1,22 @@
+# -*- 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_CustomTarget_CustomTarget,static/unoembind))
+
+$(eval $(call gb_CustomTarget_register_targets,static/unoembind, \
+ bindings_uno.cxx \
+))
+
+$(call gb_CustomTarget_get_workdir,static/unoembind)/bindings_uno.cxx: \
+ $(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) > $@
+
+# vim: set noet sw=4 ts=4:
diff --git a/static/Executable_embindmaker.mk b/static/Executable_embindmaker.mk
new file mode 100644
index 000000000000..de160a15f3cb
--- /dev/null
+++ b/static/Executable_embindmaker.mk
@@ -0,0 +1,26 @@
+# -*- 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_Executable_Executable,embindmaker))
+
+$(eval $(call gb_Executable_add_exception_objects,embindmaker, \
+ static/source/embindmaker/embindmaker \
+))
+
+$(eval $(call gb_Executable_use_libraries,embindmaker, \
+ sal \
+ salhelper \
+ unoidl \
+))
+
+$(eval $(call gb_Executable_use_static_libraries,embindmaker, \
+ codemaker \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/static/Module_static.mk b/static/Module_static.mk
index cd37748e1396..3b785c7ba4cb 100644
--- a/static/Module_static.mk
+++ b/static/Module_static.mk
@@ -18,6 +18,8 @@ $(eval $(call gb_Module_add_targets,static,\
ifeq (EMSCRIPTEN,$(OS))
$(eval $(call gb_Module_add_targets,static,\
CustomTarget_emscripten_fs_image \
+ CustomTarget_unoembind \
+ StaticLibrary_unoembind \
$(if $(ENABLE_QT5), \
CustomTarget_wasm-qt5-mandelbrot_moc \
Executable_wasm-qt5-mandelbrot \
@@ -27,4 +29,10 @@ endif
endif
+ifneq ($(filter EMSCRIPTEN,$(BUILD_TYPE_FOR_HOST)),)
+$(eval $(call gb_Module_add_targets,static, \
+ Executable_embindmaker \
+))
+endif
+
# vim: set noet sw=4 ts=4:
diff --git a/static/StaticLibrary_unoembind.mk b/static/StaticLibrary_unoembind.mk
new file mode 100644
index 000000000000..e2a2bfacd892
--- /dev/null
+++ b/static/StaticLibrary_unoembind.mk
@@ -0,0 +1,27 @@
+# -*- 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_StaticLibrary_StaticLibrary,unoembind))
+
+$(eval $(call gb_StaticLibrary_add_exception_objects,unoembind, \
+ static/source/unoembindhelpers/PrimaryBindings \
+))
+
+$(eval $(call gb_StaticLibrary_add_generated_exception_objects,unoembind, \
+ CustomTarget/static/unoembind/bindings_uno \
+))
+
+$(eval $(call gb_StaticLibrary_use_api,unoembind,\
+ offapi \
+ udkapi \
+))
+
+$(call gb_StaticLibrary_get_target,unoembind): $(call gb_CustomTarget_get_target,static/unoembind)
+
+# vim: set noet sw=4 ts=4:
diff --git a/static/source/embindmaker/embindmaker.cxx b/static/source/embindmaker/embindmaker.cxx
new file mode 100644
index 000000000000..184d635da5c0
--- /dev/null
+++ b/static/source/embindmaker/embindmaker.cxx
@@ -0,0 +1,510 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 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/.
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+#include <cstdlib>
+#include <iostream>
+#include <string_view>
+#include <utility>
+#include <vector>
+
+#include <codemaker/global.hxx>
+#include <codemaker/typemanager.hxx>
+#include <osl/file.hxx>
+#include <osl/process.h>
+#include <rtl/process.h>
+#include <rtl/ref.hxx>
+#include <rtl/string.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/main.h>
+#include <sal/types.h>
+#include <unoidl/unoidl.hxx>
+
+namespace
+{
+void badUsage()
+{
+ std::cerr
+ << "Usage:\n\n"
+ " embindmaker <prefix> <registries>\n\n"
+ "where each <registry> is '+' (primary) or ':' (secondary), followed by: either a\n"
+ "new- or legacy-format .rdb file, a single .idl file, or a root directory of an\n"
+ ".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.\n";
+ std::exit(EXIT_FAILURE);
+}
+
+std::pair<OUString, bool> parseRegistryArgument(sal_uInt32 argument)
+{
+ OUString arg;
+ rtl_getAppCommandArg(argument, &arg.pData);
+ bool primary;
+ if (arg.startsWith(u"+", &arg))
+ {
+ primary = true;
+ }
+ else if (arg.startsWith(u":", &arg))
+ {
+ primary = false;
+ }
+ else
+ {
+ std::cerr << "Bad registry argument \"" << arg << "\"\n";
+ std::exit(EXIT_FAILURE);
+ }
+ OUString url;
+ auto const e1 = osl::FileBase::getFileURLFromSystemPath(arg, url);
+ if (e1 != osl::FileBase::E_None)
+ {
+ std::cerr << "Cannot convert \"" << arg << "\" to file URL, error code " << +e1 << "\n";
+ std::exit(EXIT_FAILURE);
+ }
+ OUString cwd;
+ auto const e2 = osl_getProcessWorkingDir(&cwd.pData);
+ if (e2 != osl_Process_E_None)
+ {
+ std::cerr << "Cannot obtain working directory, error code " << +e2 << "\n";
+ std::exit(EXIT_FAILURE);
+ }
+ OUString abs;
+ auto const e3 = osl::FileBase::getAbsoluteFileURL(cwd, url, abs);
+ if (e3 != osl::FileBase::E_None)
+ {
+ std::cerr << "Cannot make \"" << url << "\" into an absolute file URL, error code " << +e3
+ << "\n";
+ std::exit(EXIT_FAILURE);
+ }
+ return { abs, primary };
+}
+
+void scan(rtl::Reference<unoidl::MapCursor> const& cursor, std::u16string_view prefix,
+ std::vector<OUString>& interfaces)
+{
+ assert(cursor.is());
+ for (;;)
+ {
+ OUString id;
+ auto const ent = cursor->getNext(&id);
+ if (!ent.is())
+ {
+ break;
+ }
+ OUString name(prefix + id);
+ switch (ent->getSort())
+ {
+ case unoidl::Entity::SORT_MODULE:
+ scan(static_cast<unoidl::ModuleEntity*>(ent.get())->createCursor(),
+ Concat2View(name + "."), interfaces);
+ break;
+ case unoidl::Entity::SORT_INTERFACE_TYPE:
+ interfaces.emplace_back(name);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+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)
+{
+ for (auto const& attr : entity->getDirectAttributes())
+ {
+ std::cout << " .function(\"get" << attr.name << "\", &" << cppName(name) << "::get"
+ << attr.name << ")\n";
+ if (!attr.readOnly)
+ {
+ std::cout << " .function(\"set" << attr.name << "\", &" << cppName(name)
+ << "::set" << attr.name << ")\n";
+ }
+ }
+}
+
+OUString resolveOuterTypedefs(rtl::Reference<TypeManager> const& manager, OUString const& name)
+{
+ for (OUString n(name);;)
+ {
+ rtl::Reference<unoidl::Entity> ent;
+ if (manager->getSort(n, &ent) != codemaker::UnoType::Sort::Typedef)
+ {
+ return n;
+ }
+ n = dynamic_cast<unoidl::TypedefEntity&>(*ent).getType();
+ }
+}
+
+OUString resolveAllTypedefs(rtl::Reference<TypeManager> const& manager, std::u16string_view name)
+{
+ sal_Int32 k1;
+ OUString n(b2u(codemaker::UnoType::decompose(u2b(name), &k1)));
+ for (;;)
+ {
+ rtl::Reference<unoidl::Entity> ent;
+ if (manager->getSort(n, &ent) != codemaker::UnoType::Sort::Typedef)
+ {
+ break;
+ }
+ sal_Int32 k2;
+ n = b2u(codemaker::UnoType::decompose(
+ u2b(static_cast<unoidl::TypedefEntity*>(ent.get())->getType()), &k2));
+ k1 += k2; //TODO: overflow
+ }
+ OUStringBuffer b;
+ for (sal_Int32 i = 0; i != k1; ++i)
+ {
+ b.append("[]");
+ }
+ b.append(n);
+ return b.makeStringAndClear();
+}
+
+bool passByReference(rtl::Reference<TypeManager> const& manager, OUString const& name)
+{
+ switch (manager->getSort(resolveOuterTypedefs(manager, name)))
+ {
+ case codemaker::UnoType::Sort::Boolean:
+ case codemaker::UnoType::Sort::Byte:
+ case codemaker::UnoType::Sort::Short:
+ case codemaker::UnoType::Sort::UnsignedShort:
+ case codemaker::UnoType::Sort::Long:
+ case codemaker::UnoType::Sort::UnsignedLong:
+ case codemaker::UnoType::Sort::Hyper:
+ case codemaker::UnoType::Sort::UnsignedHyper:
+ case codemaker::UnoType::Sort::Float:
+ case codemaker::UnoType::Sort::Double:
+ case codemaker::UnoType::Sort::Char:
+ case codemaker::UnoType::Sort::Enum:
+ return false;
+ case codemaker::UnoType::Sort::String:
+ case codemaker::UnoType::Sort::Type:
+ case codemaker::UnoType::Sort::Any:
+ case codemaker::UnoType::Sort::Sequence:
+ case codemaker::UnoType::Sort::PlainStruct:
+ case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct:
+ case codemaker::UnoType::Sort::Interface:
+ return true;
+ default:
+ throw CannotDumpException("unexpected entity \"" + name
+ + "\" in call to passByReference");
+ }
+}
+
+void dumpType(rtl::Reference<TypeManager> const& manager, std::u16string_view name, bool isConst)
+{
+ sal_Int32 k;
+ std::vector<OString> args;
+ OUString n(
+ b2u(codemaker::UnoType::decompose(u2b(resolveAllTypedefs(manager, name)), &k, &args)));
+ if (isConst)
+ {
+ std::cout << "const ";
+ }
+ for (sal_Int32 i = 0; i != k; ++i)
+ {
+ std::cout << "::css::uno::Sequence<";
+ }
+ switch (manager->getSort(n))
+ {
+ case codemaker::UnoType::Sort::Void:
+ std::cout << "void";
+ break;
+ case codemaker::UnoType::Sort::Boolean:
+ std::cout << "::sal_Bool";
+ break;
+ case codemaker::UnoType::Sort::Byte:
+ std::cout << "::sal_Int8";
+ break;
+ case codemaker::UnoType::Sort::Short:
+ std::cout << "::sal_Int16";
+ break;
+ case codemaker::UnoType::Sort::UnsignedShort:
+ std::cout << "::sal_uInt16";
+ break;
+ case codemaker::UnoType::Sort::Long:
+ std::cout << "::sal_Int32";
+ break;
+ case codemaker::UnoType::Sort::UnsignedLong:
+ std::cout << "::sal_uInt32";
+ break;
+ case codemaker::UnoType::Sort::Hyper:
+ std::cout << "::sal_Int64";
+ break;
+ case codemaker::UnoType::Sort::UnsignedHyper:
+ std::cout << "::sal_uInt64";
+ break;
+ case codemaker::UnoType::Sort::Float:
+ std::cout << "float";
+ break;
+ case codemaker::UnoType::Sort::Double:
+ std::cout << "double";
+ break;
+ case codemaker::UnoType::Sort::Char:
+ std::cout << "::sal_Unicode";
+ break;
+ case codemaker::UnoType::Sort::String:
+ std::cout << "::rtl::OUString";
+ break;
+ case codemaker::UnoType::Sort::Type:
+ std::cout << "::css::uno::Type";
+ break;
+ case codemaker::UnoType::Sort::Any:
+ std::cout << "::css::uno::Any";
+ break;
+ case codemaker::UnoType::Sort::Enum:
+ case codemaker::UnoType::Sort::PlainStruct:
+ case codemaker::UnoType::Sort::Exception:
+ std::cout << cppName(n);
+ break;
+ case codemaker::UnoType::Sort::PolymorphicStructTemplate:
+ std::cout << cppName(n);
+ if (!args.empty())
+ {
+ std::cout << "<";
+ bool first = true;
+ for (auto const& arg : args)
+ {
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ std::cout << ", ";
+ }
+ dumpType(manager, b2u(arg), false);
+ }
+ std::cout << ">";
+ }
+ break;
+ case codemaker::UnoType::Sort::Interface:
+ std::cout << "::css::uno::Reference<";
+ std::cout << cppName(n);
+ std::cout << ">";
+ break;
+ default:
+ throw CannotDumpException(OUString::Concat("unexpected entity \"") + name
+ + "\" in call to dumpType");
+ }
+ for (sal_Int32 i = 0; i != k; ++i)
+ {
+ std::cout << ">";
+ }
+}
+
+void dumpParameters(rtl::Reference<TypeManager> const& manager,
+ unoidl::InterfaceTypeEntity::Method const& method, bool declarations)
+{
+ bool first = true;
+ for (auto const& param : method.parameters)
+ {
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ std::cout << ", ";
+ }
+ bool isConst;
+ bool isRef;
+ if (param.direction == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN)
+ {
+ isConst = passByReference(manager, param.type);
+ isRef = isConst;
+ }
+ else
+ {
+ isConst = false;
+ isRef = true;
+ }
+ // For the embind wrapper, we define a pointer instead of a reference:
+ if (declarations)
+ {
+ dumpType(manager, param.type, isConst);
+ std::cout << " ";
+ }
+ if (isRef)
+ {
+ std::cout << "*";
+ }
+ if (declarations)
+ {
+ std::cout << " ";
+ }
+ std::cout << param.name;
+ }
+}
+
+void dumpWrapper(rtl::Reference<TypeManager> const& manager, OUString const& interfaceName,
+ unoidl::InterfaceTypeEntity::Method const& method, bool forReference)
+{
+ std::cout << " .function(\"" << method.name << "\", +[](";
+ if (forReference)
+ {
+ std::cout << "::com::sun::star::uno::Reference<";
+ }
+ std::cout << cppName(interfaceName);
+ if (forReference)
+ {
+ std::cout << ">";
+ }
+ std::cout << " * the_self";
+ if (!method.parameters.empty())
+ {
+ std::cout << ", ";
+ }
+ dumpParameters(manager, method, true);
+ std::cout << ") { return the_self->";
+ if (forReference)
+ {
+ std::cout << "get()->";
+ }
+ std::cout << method.name << "(";
+ dumpParameters(manager, method, false);
+ std::cout << "); }, ::emscripten::allow_raw_pointers())\n";
+}
+
+void dumpMethods(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);
+ }
+ else if (std::any_of(
+ meth.parameters.begin(), meth.parameters.end(), [](auto const& parameter) {
+ return parameter.direction
+ != unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN;
+ }))
+ {
+ dumpWrapper(manager, name, meth, false);
+ }
+ else
+ {
+ std::cout << " .function(\"" << meth.name << "\", &" << cppName(name)
+ << "::" << meth.name << ")\n";
+ }
+ }
+}
+}
+
+SAL_IMPLEMENT_MAIN()
+{
+ try
+ {
+ auto const args = rtl_getAppCommandArgCount();
+ if (args == 0)
+ {
+ badUsage();
+ }
+ OUString prefix;
+ rtl_getAppCommandArg(0, &prefix.pData);
+ rtl::Reference<TypeManager> mgr(new TypeManager);
+ for (sal_uInt32 i = 1; i != args; ++i)
+ {
+ auto const & [ uri, primary ] = parseRegistryArgument(i);
+ try
+ {
+ mgr->loadProvider(uri, primary);
+ }
+ catch (unoidl::NoSuchFileException&)
+ {
+ std::cerr << "Input <" << uri << "> does not exist\n";
+ std::exit(EXIT_FAILURE);
+ }
+ }
+ std::vector<OUString> interfaces;
+ for (auto const& prov : mgr->getPrimaryProviders())
+ {
+ scan(prov->createRootCursor(), u"", interfaces);
+ }
+ std::cout << "#include <emscripten/bind.h>\n"
+ "#include <com/sun/star/uno/Any.hxx>\n"
+ "#include <com/sun/star/uno/Reference.hxx>\n";
+ for (auto const& ifc : interfaces)
+ {
+ std::cout << "#include <" << ifc.replace('.', '/') << ".hpp>\n";
+ }
+ std::cout << "\n"
+ "// TODO: This is a temporary workaround that likely causes the Embind UNO\n"
+ "// bindings to leak memory. Reference counting and cloning mechanisms of\n"
+ "// Embind should be investigated to figure out what exactly we need here:\n"
+ "namespace emscripten::internal {\n";
+ for (auto const& ifc : interfaces)
+ {
+ std::cout << " template<> void raw_destructor<" << cppName(ifc) << ">("
+ << cppName(ifc) << " *) {}\n";
+ }
+ std::cout << "}\n\n"
+ "EMSCRIPTEN_BINDINGS(uno_bindings_"
+ << prefix << ") {\n";
+ 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)
+ << "\")\n";
+ dumpAttributes(ifc, ifcEnt);
+ dumpMethods(mgr, ifc, ifcEnt, false);
+ std::cout << " ;\n"
+ " ::emscripten::class_<::com::sun::star::uno::Reference<"
+ << cppName(ifc)
+ << ">, ::emscripten::base<::com::sun::star::uno::BaseReference>>(\""
+ << jsName(ifc)
+ << "Ref\")\n"
+ " .constructor<>()\n"
+ " .constructor<::com::sun::star::uno::BaseReference, "
+ "::com::sun::star::uno::UnoReference_Query>()\n"
+ " .function(\"is\", &::com::sun::star::uno::Reference<"
+ << cppName(ifc)
+ << ">::is)\n"
+ " .function(\"get\", &::com::sun::star::uno::Reference<"
+ << cppName(ifc)
+ << ">::get, ::emscripten::allow_raw_pointers())\n"
+ " .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))\n";
+ dumpAttributes(ifc, ifcEnt);
+ dumpMethods(mgr, ifc, ifcEnt, true);
+ std::cout << " ;\n";
+ }
+ std::cout << "}\n";
+ return EXIT_SUCCESS;
+ }
+ catch (unoidl::FileFormatException const& e)
+ {
+ std::cerr << "Bad input <" << e.getUri() << ">: " << e.getDetail() << "\n";
+ std::exit(EXIT_FAILURE);
+ }
+ catch (CannotDumpException const& e)
+ {
+ std::cerr << "Failure: " << e.getMessage() << "\n";
+ std::exit(EXIT_FAILURE);
+ }
+ catch (std::exception const& e)
+ {
+ std::cerr << "Failure: " << e.what() << "\n";
+ std::exit(EXIT_FAILURE);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */