summaryrefslogtreecommitdiff
path: root/codemaker
diff options
context:
space:
mode:
authorSarper Akdemir <sarper.akdemir.extern@allotropia.de>2023-08-07 14:41:32 +0300
committerSarper Akdemir <sarper.akdemir.extern@allotropia.de>2023-09-18 19:59:57 +0200
commit841f898574affb526a516224d7c3db9b137ea62b (patch)
treeb26718c1a063f47b2a75eb939b4fd0d55f90f79f /codemaker
parent971425f9b7613183a565e9b4ec5792b3f67bb133 (diff)
JavaScript uno bindings for WASM with Embind - first cut
A rough implementation of uno bindings for LOWA using embind. Adds new parameter '-W' to cppumaker to generate _embind.cxx files alongside .hdl & .hpp. For usage examples see static/README.wasm.md Change-Id: Iee5d05e37bfba8e101c08212b15c05f7f2fa6c33 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/156273 Tested-by: Jenkins Reviewed-by: Sarper Akdemir <sarper.akdemir.extern@allotropia.de>
Diffstat (limited to 'codemaker')
-rw-r--r--codemaker/source/cppumaker/cppuoptions.cxx18
-rw-r--r--codemaker/source/cppumaker/cpputype.cxx250
-rw-r--r--codemaker/source/cppumaker/cpputype.hxx9
-rw-r--r--codemaker/source/cppumaker/dumputils.cxx14
-rw-r--r--codemaker/source/cppumaker/dumputils.hxx3
-rw-r--r--codemaker/source/cppumaker/includes.cxx19
-rw-r--r--codemaker/source/cppumaker/includes.hxx5
7 files changed, 295 insertions, 23 deletions
diff --git a/codemaker/source/cppumaker/cppuoptions.cxx b/codemaker/source/cppumaker/cppuoptions.cxx
index 0a2ad962381a..f4ccf69b1ae7 100644
--- a/codemaker/source/cppumaker/cppuoptions.cxx
+++ b/codemaker/source/cppumaker/cppuoptions.cxx
@@ -216,6 +216,24 @@ bool CppuOptions::initOptions(int ac, char* av[], bool bCmdFile)
m_options["-G"] = OString();
break;
+ case 'W': // generate embind javascript bindings for LOWA
+ if (av[i][2] != '\0')
+ {
+ OString tmp("'-W', please check");
+ if (i <= ac - 1)
+ {
+ tmp += OString::Concat(" your input '") + av[i] + "'";
+ }
+
+ throw IllegalArgument(tmp);
+ }
+
+ if (!isValid("-C") && !isValid("-CS") && !isValid("-L"))
+ {
+ throw IllegalArgument("'-W' requires '-C' or '-CS' or '-L' option");
+ }
+ m_options["-W"] = 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 bb8e3ed7d33c..cb3422de16d0 100644
--- a/codemaker/source/cppumaker/cpputype.cxx
+++ b/codemaker/source/cppumaker/cpputype.cxx
@@ -53,6 +53,8 @@
namespace
{
+using FileType = codemaker::cppumaker::FileType;
+
bool isBootstrapType(OUString const & name)
{
static char const * const names[] = {
@@ -150,6 +152,17 @@ bool isBootstrapType(OUString const & name)
return std::any_of(std::begin(names), std::end(names), pred);
}
+OString getFileExtension(FileType eFileType)
+{
+ switch(eFileType)
+ {
+ default:
+ case FileType::HDL: return ".hdl";
+ case FileType::HPP: return ".hpp";
+ case FileType::EMBIND_CXX: return "_embind.cxx";
+ }
+}
+
class CppuType
{
public:
@@ -163,7 +176,7 @@ public:
void dump(CppuOptions const & options);
void dumpFile(
- std::u16string_view uri, std::u16string_view name, bool hpp,
+ std::u16string_view uri, std::u16string_view name, FileType eFileType,
CppuOptions const & options);
void dumpDependedTypes(
@@ -176,6 +189,8 @@ public:
virtual void dumpHppFile(FileStream& o, codemaker::cppumaker::Includes & includes) = 0;
+ virtual void dumpEmbindCppFile(FileStream& o);
+
OUString dumpHeaderDefine(FileStream& o, std::u16string_view extension) const;
void dumpGetCppuType(FileStream & out);
@@ -226,6 +241,8 @@ protected:
assert(false); // this cannot happen
}
+ virtual void dumpEmbindDeclaration(FileStream &) {};
+
virtual void dumpFiles(OUString const & uri, CppuOptions const & options);
virtual void addLightGetCppuTypeIncludes(
@@ -305,8 +322,10 @@ const
void CppuType::dumpFiles(OUString const & uri, CppuOptions const & options)
{
- dumpFile(uri, name_, false, options);
- dumpFile(uri, name_, true, options);
+ dumpFile(uri, name_, FileType::HDL, options);
+ dumpFile(uri, name_, FileType::HPP, options);
+ if(options.isValid("-W"))
+ dumpFile(uri, name_, FileType::EMBIND_CXX, options);
}
void CppuType::addLightGetCppuTypeIncludes(
@@ -411,12 +430,12 @@ void CppuType::dump(CppuOptions const & options)
}
void CppuType::dumpFile(
- std::u16string_view uri, std::u16string_view name, bool hpp,
+ std::u16string_view uri, std::u16string_view name, FileType eFileType,
CppuOptions const & options)
{
OUString fileUri(
b2u(createFileNameFromType(
- u2b(uri), u2b(name), hpp ? ".hpp" : ".hdl")));
+ u2b(uri), u2b(name), getFileExtension(eFileType))));
if (fileUri.isEmpty()) {
throw CannotDumpException(OUString::Concat("empty target URI for entity ") + name);
}
@@ -430,13 +449,20 @@ void CppuType::dumpFile(
if(!out.isValid()) {
throw CannotDumpException("cannot open " + tmpUri + " for writing");
}
- codemaker::cppumaker::Includes includes(m_typeMgr, m_dependencies, hpp);
+ codemaker::cppumaker::Includes includes(m_typeMgr, m_dependencies, eFileType);
try {
- if (hpp) {
- addGetCppuTypeIncludes(includes);
- dumpHppFile(out, includes);
- } else {
- dumpHdlFile(out, includes);
+ switch(eFileType)
+ {
+ case FileType::HPP:
+ addGetCppuTypeIncludes(includes);
+ dumpHppFile(out, includes);
+ break;
+ case FileType::HDL:
+ dumpHdlFile(out, includes);
+ break;
+ case FileType::EMBIND_CXX:
+ dumpEmbindCppFile(out);
+ break;
}
} catch (...) {
out.close();
@@ -582,6 +608,16 @@ void CppuType::dumpHFileContent(
out << " *);\n\n#endif\n";
}
+void CppuType::dumpEmbindCppFile(FileStream &out)
+{
+ out << "#ifdef EMSCRIPTEN\n";
+ out << "#include <emscripten/bind.h>\n"
+ "#include <" << name_.replace('.', '/') << ".hpp>\n";
+ out << "using namespace emscripten;\n\n";
+ dumpEmbindDeclaration(out);
+ out << "#endif\n";
+}
+
void CppuType::dumpGetCppuType(FileStream & out)
{
if (name_ == "com.sun.star.uno.XInterface") {
@@ -1103,10 +1139,14 @@ 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);
@@ -1168,15 +1208,65 @@ void InterfaceType::dumpDeclaration(FileStream & out)
<< ("static inline ::css::uno::Type const & SAL_CALL"
" static_type(void * = 0);\n\n");
dec();
+#ifdef EMSCRIPTEN
+ out << "#ifndef EMSCRIPTEN\n";
+#endif
out << "protected:\n";
inc();
out << indent() << "~" << id_
<< ("() SAL_NOEXCEPT {} // avoid warnings about virtual members and"
" non-virtual dtor\n");
+#ifdef EMSCRIPTEN
+ out << "#endif\n";
+#endif
dec();
out << "};\n\n";
}
+void InterfaceType::dumpEmbindDeclaration(FileStream & out)
+{
+ 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 << "\nclass_<" << 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 << "\nclass_<::css::uno::Reference<" << codemaker::cpp::scopedCppName(u2b(name_)) << ">, 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, 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)
{
@@ -1228,6 +1318,31 @@ 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()) {
@@ -1268,6 +1383,115 @@ 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 << "); }, 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);
@@ -3515,7 +3739,9 @@ private:
}
virtual void dumpFiles(OUString const & uri, CppuOptions const & options) override {
- dumpFile(uri, name_, true, options);
+ dumpFile(uri, name_, FileType::HPP, options);
+ if(options.isValid("-W"))
+ dumpFile(uri, name_, FileType::EMBIND_CXX, options);
}
};
diff --git a/codemaker/source/cppumaker/cpputype.hxx b/codemaker/source/cppumaker/cpputype.hxx
index 40fc94f26c29..a6f8f9bfe8a3 100644
--- a/codemaker/source/cppumaker/cpputype.hxx
+++ b/codemaker/source/cppumaker/cpputype.hxx
@@ -28,6 +28,15 @@ namespace rtl { class OUString; }
class CppuOptions;
class TypeManager;
+namespace codemaker::cppumaker {
+enum class FileType
+{
+ HDL,
+ HPP,
+ EMBIND_CXX
+};
+}
+
void produce(
OUString const & name, rtl::Reference< TypeManager > const & manager,
codemaker::GeneratedTypeSet & generated, CppuOptions const & options);
diff --git a/codemaker/source/cppumaker/dumputils.cxx b/codemaker/source/cppumaker/dumputils.cxx
index 2a3e809e70f3..54867523b0d4 100644
--- a/codemaker/source/cppumaker/dumputils.cxx
+++ b/codemaker/source/cppumaker/dumputils.cxx
@@ -74,6 +74,20 @@ 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 24e5bae3bede..c7021cba7408 100644
--- a/codemaker/source/cppumaker/dumputils.hxx
+++ b/codemaker/source/cppumaker/dumputils.hxx
@@ -35,6 +35,9 @@ 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/codemaker/source/cppumaker/includes.cxx b/codemaker/source/cppumaker/includes.cxx
index 9dacdf268265..05f768bbc505 100644
--- a/codemaker/source/cppumaker/includes.cxx
+++ b/codemaker/source/cppumaker/includes.cxx
@@ -20,6 +20,7 @@
#include "includes.hxx"
+#include "cpputype.hxx"
#include "dependencies.hxx"
#include "dumputils.hxx"
@@ -40,8 +41,8 @@ using codemaker::cppumaker::Includes;
Includes::Includes(
rtl::Reference< TypeManager > manager,
- codemaker::cppumaker::Dependencies const & dependencies, bool hpp):
- m_manager(std::move(manager)), m_map(dependencies.getMap()), m_hpp(hpp),
+ codemaker::cppumaker::Dependencies const & dependencies, FileType eFileType):
+ m_manager(std::move(manager)), m_map(dependencies.getMap()), m_filetype(eFileType),
m_includeCassert(false),
m_includeAny(dependencies.hasAnyDependency()), m_includeReference(false),
m_includeSequence(dependencies.hasSequenceDependency()),
@@ -136,7 +137,7 @@ void dumpEmptyLineBeforeFirst(FileStream & out, bool * first) {
void Includes::dump(
FileStream & out, OUString const * companionHdl, bool exceptions)
{
- OSL_ASSERT(companionHdl == nullptr || m_hpp);
+ OSL_ASSERT(companionHdl == nullptr || m_filetype == FileType::HPP);
if (!m_includeReference) {
for (const auto& pair : m_map)
{
@@ -159,12 +160,12 @@ void Includes::dump(
{
if (exceptions || pair.second != Dependencies::KIND_EXCEPTION) {
dumpEmptyLineBeforeFirst(out, &first);
- if (m_hpp || pair.second == Dependencies::KIND_BASE
+ if ((m_filetype == FileType::HPP) || pair.second == Dependencies::KIND_BASE
|| !isInterfaceType(u2b(pair.first)))
{
// If we know our name, then avoid including ourselves.
if (!companionHdl || *companionHdl != pair.first) {
- dumpInclude(out, u2b(pair.first), m_hpp);
+ dumpInclude(out, u2b(pair.first), (m_filetype == FileType::HPP));
}
} else {
bool ns = dumpNamespaceOpen(out, pair.first, false);
@@ -185,22 +186,22 @@ void Includes::dump(
static char const * hxxExtension[2] = { "h", "hxx" };
if (m_includeAny) {
dumpEmptyLineBeforeFirst(out, &first);
- out << "#include \"com/sun/star/uno/Any." << hxxExtension[m_hpp]
+ out << "#include \"com/sun/star/uno/Any." << hxxExtension[(m_filetype == FileType::HPP)]
<< "\"\n";
}
if (m_includeReference) {
dumpEmptyLineBeforeFirst(out, &first);
- out << "#include \"com/sun/star/uno/Reference." << hxxExtension[m_hpp]
+ out << "#include \"com/sun/star/uno/Reference." << hxxExtension[(m_filetype == FileType::HPP)]
<< "\"\n";
}
if (m_includeSequence) {
dumpEmptyLineBeforeFirst(out, &first);
- out << "#include \"com/sun/star/uno/Sequence." << hxxExtension[m_hpp]
+ out << "#include \"com/sun/star/uno/Sequence." << hxxExtension[(m_filetype == FileType::HPP)]
<< "\"\n";
}
if (m_includeType) {
dumpEmptyLineBeforeFirst(out, &first);
- out << "#include \"com/sun/star/uno/Type." << hxxExtension[m_hpp]
+ out << "#include \"com/sun/star/uno/Type." << hxxExtension[(m_filetype == FileType::HPP)]
<< "\"\n";
}
if (m_includeCppuMacrosHxx) {
diff --git a/codemaker/source/cppumaker/includes.hxx b/codemaker/source/cppumaker/includes.hxx
index 8cd830b4a731..dcdcb5836f7e 100644
--- a/codemaker/source/cppumaker/includes.hxx
+++ b/codemaker/source/cppumaker/includes.hxx
@@ -29,12 +29,13 @@ class FileStream;
class TypeManager;
namespace codemaker::cppumaker {
+enum class FileType;
class Includes {
public:
Includes(
rtl::Reference< TypeManager > manager,
- Dependencies const & dependencies, bool hpp);
+ Dependencies const & dependencies, FileType eFileType);
~Includes();
@@ -73,7 +74,7 @@ private:
rtl::Reference< TypeManager > m_manager;
Dependencies::Map m_map;
- bool m_hpp;
+ FileType m_filetype;
bool m_includeCassert;
bool m_includeAny;
bool m_includeReference;