Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

interfaces #1

Closed
Johnly1986 opened this issue Jul 17, 2020 · 11 comments
Closed

interfaces #1

Johnly1986 opened this issue Jul 17, 2020 · 11 comments

Comments

@Johnly1986
Copy link

Can all interfaces of OCC be supported. If I change it opencascade.idl , do you need to make other changes?

@donalffons
Copy link
Owner

donalffons commented Jul 17, 2020

My assumption is that most parts of OCC can be supported. That's especially true for everything that is "just" algorithmic - those parts should convert very easily into JavaScript + WASM. However, there are certain parts of OpenCascade (especially in the Visualization module), which rely on some kind of graphics output. I haven't used those interfaces - but I would assume those to be more difficult to expose to JavaScript (although Emscripten supports WebGL output, so this might actually work).

Generally speaking, there are certain limitations in Emscripten. However, generally my experience has been that most things just run out of the box, as Emscripten does a great job of "polyfilling" interfaces that do not exist on the web. A good example would be the file system API, which let you "simulate" a file system in JavaScript, so that C++ functions that rely on file loading and saving can work as usual.

There is one major annoyance at the moment though: JavaScript + the IDL syntax does not allow overloading of methods based on argument+return value types, Overloading in JavaScript only works when methods have different numbers of arguments. I.e. this would be an invalid IDL definition:

interface SomeClass {
    void test(long value);
    void test(double value);
};

However, it is possible to write the same kind of interface as valid C++ code. There are a couple of spots in the OpenCascade library, where this type of overloading is used. Therefore, these functions cannot be directly exposed to JavaScript without renaming them. The better long term solution would be to use Emscripten's Embind system instead of the IDL system. That's on my to-do list, but will take a while until implemented.

To expose additional interfaces, it should be enough to change the opencascade.idl and potentially add missing include files here. Sometimes I use this file to define Handle-types, as that macro / template stuff doesn't work well with the IDL syntax. Then run python2 make.py && python2 make.py wasm and it will generate the build files.

@Johnly1986
Copy link
Author

This is a very exciting project. There are only some small shortcomings, such as the wasm file is too large, the trouble of redefinition of functions, the referenced data structure, and so on;

@Johnly1986
Copy link
Author

Can you tell me how to distinguish between pointers and references in this system, and when to use "new".

@donalffons
Copy link
Owner

Yeah, true... The WASM build is really quite large at 30MB (~30 seconds on a 3G network, ~3 seconds on 4G, ~2 seconds on my 100Mbit connection at home). However, if you're building your own version of the library, you can delete all unused interfaces and methods from the IDL file. This will allow Emscripten to perform dead-code-elimination, which reduces the size of the library. I have recently been working on a STEP/IGES/STL/OBJ file viewer (which does a couple of other things like volume calculation and shape healing for IGES files), where the WASM build came down to around 20MB. For super simple applications, I managed to get down to around ~13MB.

Can you tell me how to distinguish between pointers and references in this system

JavaScript passes all variables by value as shallow copies. When an OCCT method expects an argument to be passed as a pointer or reference, you indicate that with the [Ref] flag in the IDL file. When passing references or pointers to variables of the JavaScript type number, string or boolean, those values will of course also be passed by value (another limitation). If a C++ function returns an object by value, this is indicated with the [Value] flag in the IDL file (which has some caveats). More information is available in the Emscripten documentation.

and when to use "new"

You need to use new in your JavaScript code, whenever you want to instantiate a new object (unlike C++ JavaScript doesn't differentiate between heap and stack - any object must be create with new).

@Johnly1986
Copy link
Author

With regard to "new", why are all the return values marked with ref created with new. These objects have no new in the original C + + example.

I reported some errors when compiling the project with emscripten. Can you help me analyze it.

=====================================================

File " make.py ", line 285, in

build()

File " make.py ", line 243, in build

'-DBUILD_ MODULE_ ApplicationFramework=OFF'

File "D:\Program Files\Emscripten\emscripten\1.35.0\tools\ shared.py ", line 1141, in configure

process = Popen(args, stdout=None if EM_ BUILD_ VERBOSE_ LEVEL >= 2 else stdout, stderr=None if EM_ BUILD_ VERBOSE_ LEVEL >= 1 else stderr, env=env)

File "C:\Python27\lib\ subprocess.py ", line 394, in __ init__

errread, errwrite)

File "C:\Python27\lib\ subprocess.py ", line 644, in _ execute_ child

startupinfo)

Windowserror: [error 193]% 1 is not a valid Win32

@Johnly1986
Copy link
Author

With regard to "new", why are all the return values marked with ref created with new. These objects have no new in the original C + + example.

I reported some errors when compiling the project with emscripten. Can you help me analyze it.

=====================================================

File " make.py ", line 285, in

build()

File " make.py ", line 243, in build

'-DBUILD_ MODULE_ ApplicationFramework=OFF'

File "D:\Program Files\Emscripten\emscripten\1.35.0\tools\ shared.py ", line 1141, in configure

process = Popen(args, stdout=None if EM_ BUILD_ VERBOSE_ LEVEL >= 2 else stdout, stderr=None if EM_ BUILD_ VERBOSE_ LEVEL >= 1 else stderr, env=env)

File "C:\Python27\lib\ subprocess.py ", line 394, in __ init__

errread, errwrite)

File "C:\Python27\lib\ subprocess.py ", line 644, in _ execute_ child

startupinfo)

Windowserror: [error 193]% 1 is not a valid Win32

process = Popen(args, shell=True, stdout=None if EM_BUILD_VERBOSE_LEVEL >= 2 else stdout, stderr=None if EM_BUILD_VERBOSE_LEVEL >= 1 else stderr, env=env)
This may be an emscripten bug. It cannot be compiled normally without "shell = true" in win10 operating system

@Johnly1986
Copy link
Author

When I use the "python make.py wasm" command, an exception occurred again. The exception content is

======================================================================
Traceback (most recent call last):

File "D:\Program Files\Emscripten\emscripten\1.35.0\emcc", line 960, in

assert not shared.Settings.ALLOW_ MEMORY_ GROWTH, 'memory growth is not supported with WASM=1'

AssertionError: memory growth is not supported with WASM=1

Traceback (most recent call last):

File " make.py ", line 287, in

build()

File " make.py ", line 266, in build

emscripten.Building.emcc ('-DNOTHING_ WAKA_ WAKA', emcc_ args + ['glue.o'] + opencascade_ libs + myincludes[:len(myincludes)-2] + ['--js-transform', 'python %s' % os.path.join ('..', ' bundle.py ')], temp)

File "D:\Program Files\Emscripten\emscripten\1.35.0\tools\ shared.py ", line 1550, in emcc

assert os.path.exists (output_ filename), 'emcc could not create output file: ' + output_ filename

AssertionError: emcc could not create output file: .\js\ opencascade.wasm.js

========================================================================

I think these problems may be due to different operating systems or versions of emscripten. In order for more people to use it, maybe you need to make this information public.

@donalffons
Copy link
Owner

process = Popen(args, shell=True, stdout=None if EM_BUILD_VERBOSE_LEVEL >= 2 else stdout, stderr=None if EM_BUILD_VERBOSE_LEVEL >= 1 else stderr, env=env)
This may be an emscripten bug. It cannot be compiled normally without "shell = true" in win10 operating system

Awesome, thanks for sharing that. I will add that into the script then. Glad that you're making progress.

I think these problems may be due to different operating systems or versions of emscripten. In order for more people to use it, maybe you need to make this information public.

I'm using Manjaro Linux to build this. I haven't tried any other operating systems. However, I think I will create a simple Dockerfile, so that you can more easily build the application under any host operating system by creating a Docker container with a correctly configured build operating system.

@Johnly1986
Copy link
Author

process = Popen(args, shell=True, stdout=None if EM_BUILD_VERBOSE_LEVEL >= 2 else stdout, stderr=None if EM_BUILD_VERBOSE_LEVEL >= 1 else stderr, env=env)
This may be an emscripten bug. It cannot be compiled normally without "shell = true" in win10 operating system

Awesome, thanks for sharing that. I will add that into the script then. Glad that you're making progress.

I think these problems may be due to different operating systems or versions of emscripten. In order for more people to use it, maybe you need to make this information public.

I'm using Manjaro Linux to build this. I haven't tried any other operating systems. However, I think I will create a simple Dockerfile, so that you can more easily build the application under any host operating system by creating a Docker container with a correctly configured build operating system.

Can you share a docker for me? Now my head will split. Although the compiler passes, the file does not seem to load normally.

@donalffons
Copy link
Owner

donalffons commented Jul 23, 2020

Hi, I just made a few commits to the master branch which make this project work with Docker. It would be great, if you could try this and let me know if this works on your end.

Before starting, you probably want to install Docker for windows.
You probably also want to delete the opencascade.js/build directory, if it exists and use git pull to make sure you have all the latest changes on your disk.

Then you have to open up a command prompt in the directory of opencascade.js. Under linux, I execute the build as follows

docker build -t opencascade .
docker run -it -v "$(pwd)/build":"/opencascade/build" -v "$(pwd)/dist":"/opencascade/dist" opencascade

You have to run both commands, whenever you make changes to any file and want to build the library again. The first command will build a container, which is based on an Ubuntu linux and configures it for running the build. The second command runs the build. It creates two directories, which will be shared with your host system: build and dist. build contains temporary build files (so that you don't have to recompile the entire library, each time you make a small change). dist contains the final WASM + JS builds.
Under linux, I use $(pwd) to tell docker to use the current directory in the path for the shared folders (print working directory). I guess under windows, you should probably use something like the following:

docker build -t opencascade .
docker run -it -v "%cd%/build":"/opencascade/build" -v "%cd%/dist":"/opencascade/dist" opencascade

Not sure if this is the correct syntax though. Would be great if you could let me know if this works for you!

PS: When you run those commands for the first time, it will probably take very long to run (on my machine, its around an hour). For successive builds, it will run much faster.

@donalffons
Copy link
Owner

There are now instructions on how to build with Docker in the readme.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants