Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
dist/
node_modules/
occt-src/
**/.git
Expand Down
12 changes: 7 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
FROM emscripten/emsdk:3.1.14 AS base-image
FROM emscripten/emsdk:3.1.20
# FROM emscripten/emsdk:3.1.20 AS base-image

RUN \
apt update -y && \
Expand Down Expand Up @@ -54,16 +55,17 @@ WORKDIR /src/
ARG threading=single-threaded
ENV threading=$threading

FROM base-image AS test-image
# FROM base-image AS test-image

RUN \
mkdir /opencascade.js/build/ && \
mkdir /opencascade.js/dist/ && \
/opencascade.js/src/applyPatches.py

ENTRYPOINT ["/opencascade.js/src/buildFromYaml.py"]
VOLUME /opencascade.js/src
VOLUME /opencascade.js/build
VOLUME /src

FROM test-image AS custom-build-image
# FROM test-image AS custom-build-image

RUN \
/opencascade.js/src/generateBindings.py && \
Expand Down
10 changes: 10 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

version: "3.9"
services:
opencascade:
build: .
volumes:
- ./build:/opencascade.js/build
- ./src:/opencascade.js/src
- ./dist:/src

26 changes: 19 additions & 7 deletions src/bindings.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import clang.cindex
import re
import sys

from wasmGenerator.Common import SkipException, isAbstractClass, getMethodOverloadPostfix
from filter.filterClasses import filterClass
Expand Down Expand Up @@ -36,11 +37,10 @@ def shouldProcessClass(child: clang.cindex.Cursor, occtBasePath: str):
child.kind == clang.cindex.CursorKind.CLASS_DECL or
child.kind == clang.cindex.CursorKind.STRUCT_DECL
):
baseSpec = list(filter(lambda x: x.kind == clang.cindex.CursorKind.CXX_BASE_SPECIFIER and x.access_specifier == clang.cindex.AccessSpecifier.PUBLIC, child.get_children()))
if len(baseSpec) > 1:
print("cannot handle multiple base classes (" + child.spelling + ")")
return False

# baseSpec = list(filter(lambda x: x.kind == clang.cindex.CursorKind.CXX_BASE_SPECIFIER and x.access_specifier == clang.cindex.AccessSpecifier.PUBLIC, child.get_children()))
# if len(baseSpec) > 1:
# print("cannot handle multiple base classes (" + child.spelling + ")")
# return False
return True

return False
Expand Down Expand Up @@ -399,8 +399,10 @@ def generateInvocationArgs(x):
if method.access_specifier == clang.cindex.AccessSpecifier.PUBLIC and method.kind == clang.cindex.CursorKind.FIELD_DECL:
if method.type.kind == clang.cindex.TypeKind.CONSTANTARRAY:
print("Cannot handle array properties, skipping " + className + "::" + method.spelling)
sys.stdout.flush()
elif not method.type.get_pointee().kind == clang.cindex.TypeKind.INVALID:
print("Cannot handle pointer properties, skipping " + className + "::" + method.spelling)
sys.stdout.flush()
else:
output += f"{indent(2)}.property(\"{method.spelling}\", &{className}::{method.spelling})\n"
return output
Expand Down Expand Up @@ -462,15 +464,23 @@ def __init__(
def processClass(self, theClass, templateDecl = None, templateArgs = None):
output = ""
baseSpec = list(filter(lambda x: x.kind == clang.cindex.CursorKind.CXX_BASE_SPECIFIER and x.access_specifier == clang.cindex.AccessSpecifier.PUBLIC, theClass.get_children()))
name = getClassTypeName(theClass, templateDecl)
baseClassDefinition = ""
if len(baseSpec) > 0:
if any(x in baseSpec[0].type.spelling for x in [":", "<"]):
print("Unsupported character for base class \"" + baseSpec[0].type.spelling + "\" (" + theClass.spelling + ")")
sys.stdout.flush()
else:
baseClassDefinition = " extends " + baseSpec[0].type.spelling
if len(baseSpec) == 1:
baseClassDefinition = " extends " + baseSpec[0].type.spelling
else:
classes = ", ".join(map(lambda x: x.type.spelling, baseSpec))
baseClassDefinition = " extends __" + name
output += "class __" + name + " {}\n"
output += "interface __" + name + " extends " + classes + " {}\n"
output += "applyMixins(__" + name + ", [" + classes + "]);\n"
# self.addImportIfWeHaveTo(baseSpec[0].type.spelling)

name = getClassTypeName(theClass, templateDecl)
output += "export declare class " + name + baseClassDefinition + " {\n"
self.exports.append(name)

Expand Down Expand Up @@ -546,6 +556,7 @@ def getTypescriptDefFromResultType(self, res, templateDecl = None, templateArgs
resTypeName = resTypedefType
if resTypeName == "" or "(" in resTypeName or ":" in resTypeName or "<" in resTypeName:
print("could not generate proper types for type name '" + resTypeName + "', using 'any' instead.")
sys.stdout.flush()
resTypeName = "any"
return resTypeName

Expand All @@ -555,6 +566,7 @@ def getTypescriptDefFromArg(self, arg, suffix = "", templateDecl = None, templat
argTypeName = self.convertBuiltinTypes(argTypeName)
if argTypeName == "" or "(" in argTypeName or ":" in argTypeName:
print("could not generate proper types for type name '" + argTypeName + "', using 'any' instead.")
sys.stdout.flush()
argTypeName = "any"

argname = (arg.spelling if not arg.spelling == "" else ("a" + str(suffix)))
Expand Down
38 changes: 31 additions & 7 deletions src/buildFromYaml.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/python3

import os
import sys
import subprocess
import json
from itertools import chain
Expand Down Expand Up @@ -30,12 +31,14 @@
except Exception:
pass

generateCustomCodeBindings(buildConfig["additionalCppCode"])
compileCustomCodeBindings({
"threading": os.environ['threading'],
})
# generateCustomCodeBindings(buildConfig["additionalCppCode"])
# compileCustomCodeBindings({
# "threading": os.environ['threading'],
# })

def verifyBinding(binding) -> bool:
print("Verify Binding: " + binding["symbol"])
sys.stdout.flush()
for dirpath, dirnames, filenames in os.walk(libraryBasePath + "/bindings"):
for item in filenames:
if item.endswith(".cpp.o") and binding["symbol"] == item[:-6]:
Expand Down Expand Up @@ -101,6 +104,7 @@ def getAdditionalBindCodeO():
return None
additionalBindCodeO = getAdditionalBindCodeO()
print("Running build: " + build["name"])
sys.stdout.flush()
bindingsO = []
for dirpath, dirnames, filenames in os.walk(libraryBasePath + "/bindings"):
for item in filenames:
Expand All @@ -115,20 +119,23 @@ def getAdditionalBindCodeO():
continue
if item.endswith(".o"):
sourcesO.append(dirpath + "/" + item)
outFileName = os.getcwd() + "/" + build["name"]
subprocess.check_call([
"emcc", "-lembind", ("" if additionalBindCodeO is None else additionalBindCodeO),
*bindingsO, *sourcesO,
"-o", os.getcwd() + "/" + build["name"],
"-o", outFileName,
"-pthread" if os.environ["threading"] == "multi-threaded" else "",
*build["emccFlags"],
])
print("Build finished")
print("Build finished: " + outFileName)

runBuild(buildConfig["mainBuild"])
for extraBuild in buildConfig["extraBuilds"]:
runBuild(extraBuild)

if buildConfig["generateTypescriptDefinitions"]:
print("Generate Typescript Definitions")
sys.stdout.flush()
typescriptDefinitionOutput = ""
typescriptExports = []
for dts in typescriptDefinitions:
Expand Down Expand Up @@ -295,8 +302,25 @@ def getAdditionalBindCodeO():
"}\n\n" + \
"\nexport type OpenCascadeInstance = {FS: typeof FS} & {\n " + ";\n ".join(map(lambda x: x["export"] + ((": typeof " + x["export"]) if x["kind"] == "class" else (": " + x["export"])), typescriptExports)) + ";\n" + \
"};\n\n" + \
"\n\n" + \
"function applyMixins(derivedCtor: any, constructors: any[]) {\n" + \
" constructors.forEach((baseCtor) => {\n" + \
" Object.getOwnPropertyNames(baseCtor.prototype).forEach((name) => {\n" + \
" Object.defineProperty(\n" + \
" derivedCtor.prototype,\n" + \
" name,\n" + \
" Object.getOwnPropertyDescriptor(baseCtor.prototype, name) ||\n" + \
" Object.create(null)\n" + \
" );\n" + \
" });\n" + \
" });\n" + \
"}\n" + \
"\n\n" + \
"declare function init(): Promise<OpenCascadeInstance>;\n\n" + \
"export default init;\n"

typescriptDefinitionsFile = open(os.getcwd() + "/" + os.path.splitext(buildConfig["mainBuild"]["name"])[0] + ".d.ts", "w")
tsFilename = os.getcwd() + "/" + os.path.splitext(buildConfig["mainBuild"]["name"])[0] + ".d.ts"
typescriptDefinitionsFile = open(tsFilename, "w")
typescriptDefinitionsFile.write(typescriptDefinitionOutput)
print("Typescript: " + tsFilename)
sys.stdout.flush()
3 changes: 3 additions & 0 deletions src/compileBindings.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/python3

import os
import sys
from Common import ocIncludePaths, additionalIncludePaths
import subprocess
import multiprocessing
Expand All @@ -13,6 +14,7 @@
def buildOneFile(args, item):
if not os.path.exists(item + ".o"):
print("building " + item)
sys.stdout.flush()
command = [
"emcc",
"-flto",
Expand All @@ -36,6 +38,7 @@ def buildOneFile(args, item):
])
else:
print("file " + item + ".o already exists, skipping")
sys.stdout.flush()

def compileCustomCodeBindings(args):
filesToBuild = []
Expand Down
3 changes: 3 additions & 0 deletions src/compileSources.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/python3

import os
import sys
import subprocess
import multiprocessing

Expand Down Expand Up @@ -72,12 +73,14 @@ def buildObjectFiles(file, args):

if not os.path.exists(libraryBasePath + "/" + relativeFile + ".o"):
print("Building " + relativeFile)
sys.stdout.flush()
subprocess.check_call([
*command,
"-o", libraryBasePath + "/" + relativeFile + ".o",
])
else:
print(relativeFile + ".o already exists, skipping")
sys.stdout.flush()

allModules = {}
for dirpath, dirnames, filenames in os.walk(sourceBasePath):
Expand Down
4 changes: 4 additions & 0 deletions src/generateBindings.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from bindings import EmbindBindings, TypescriptBindings, shouldProcessClass
import clang.cindex
import os
import sys
import errno
from filter.filterTypedefs import filterTypedef
from filter.filterEnums import filterEnum
Expand Down Expand Up @@ -85,14 +86,17 @@ def processChildBatch(customCode, generator, buildType: str, extension: str, fil

if not os.path.exists(filename):
print("Processing " + child.spelling)
sys.stdout.flush()
try:
output = processFunction(tu, preamble, child, typedefGenerator(tu), templateTypedefGenerator(tu))
bindingsFile = open(filename, "w")
bindingsFile.write(output)
except SkipException as e:
print(str(e))
sys.stdout.flush()
else:
print("file " + child.spelling + ".cpp already exists, skipping")
sys.stdout.flush()

def split(a, n):
k, m = divmod(len(a), n)
Expand Down