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

OpenCASCADE 7.4.0 #845

Draft
wants to merge 12 commits into
base: master
Choose a base branch
from
Draft

OpenCASCADE 7.4.0 #845

wants to merge 12 commits into from

Conversation

lvh
Copy link

@lvh lvh commented Feb 21, 2020

As #844, but as a draft this time.

@lvh
Copy link
Author

lvh commented Feb 21, 2020

As you can tell from the diff, OpenCASCADE is massive. FWIW: it looks like CI is running even though this is a draft?

@saudet
Copy link
Member

saudet commented Feb 21, 2020

Hum, this is annoying. Why did they start doing that? Anyway, one thing that works for sure is temporarily deleting the .appveyor.yml and .travis.yml files.

@lvh lvh closed this Feb 21, 2020
@lvh
Copy link
Author

lvh commented Feb 21, 2020

Closing it for now since maybe that will stop triggering the builds.

Got this error:

[ERROR] Failed to execute goal org.moditect:moditect-maven-plugin:1.0.0.Beta2:add-module-info (add-module-infos) on project opencascade: Execution add-module-infos of goal org.moditect:moditect-maven-plugin:1.0.0.Beta2:add-module-info failed: Couldn't parse /home/lvh/src/javacpp/javacpp-presets/opencascade/src/main/java9/module-info.java -> [Help 1]

I know how to fix this, but I was following the Create New Pretests documentation and it said:

Although not crucial, the calls to moditect-maven-plugin create for us module-info.class files that are required by the JPMS, in which case we need to create an additional src/main/java9/module-info.java file such as the following:

Should that be updated, or did I hit a special case where it turned out to be crucial?

@lvh
Copy link
Author

lvh commented Feb 21, 2020

Currently failing here:

[ERROR] Failed to execute goal org.moditect:moditect-maven-plugin:1.0.0.Beta2:add-module-info (add-module-infos) on project opencascade: Execution add-module-infos of goal org.moditect:moditect-maven-plugin:1.0.0.Beta2:add-module-info failed: Couldn't copy JAR file: /home/lvh/src/javacpp/javacpp-presets/opencascade/target/opencascade-linux-x86_64.jar -> [Help 1]

Looking at that target directory, there's a jar, but it doesn't have -linux-x86_64 in it. I assume this is the opencascade pom.xml that's broken. I'll try to figure out what the platform property is called exactly tomorrow :)

@saudet
Copy link
Member

saudet commented Feb 21, 2020

That just means the JAR file doesn't exist. Make sure to try to build it locally first. It's much easier to debug that way.

@saudet
Copy link
Member

saudet commented Feb 21, 2020

If you don't mind about JPMS, yes, we can erase all that, that's not a problem. It's not going to help you create the missing JAR file though.

@lvh
Copy link
Author

lvh commented Feb 21, 2020

Yep, I'm working locally. I took the clean out of the mvn command from the sample instructions because OpenCASCADE takes forever to compile even on my beefy desktop. Here's a more complete backtrace:

[INFO] --- maven-resources-plugin:3.1.0:testResources (default-testResources) @ opencascade ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/lvh/src/javacpp/javacpp-presets/opencascade/src/test/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.8.0:testCompile (default-testCompile) @ opencascade ---
[INFO] No sources to compile
[INFO] 
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ opencascade ---
[INFO] No tests to run.
[INFO] 
[INFO] --- maven-jar-plugin:3.1.0:jar (default-jar) @ opencascade ---
[INFO] Building jar: /home/lvh/src/javacpp/javacpp-presets/opencascade/target/opencascade.jar
[INFO] 
[INFO] --- maven-jar-plugin:3.1.0:jar (javacpp-linux-x86_64) @ opencascade ---
[INFO] Skipping packaging of the jar
[INFO] 
[INFO] --- moditect-maven-plugin:1.0.0.Beta2:add-module-info (add-module-infos) @ opencascade ---
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] 
[INFO] JavaCPP Presets 1.5.3-SNAPSHOT ..................... SUCCESS [  0.567 s]
[INFO] JavaCPP Presets for OpenCASCADE 7.4.0-1.5.3-SNAPSHOT FAILURE [05:22 min]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  05:24 min
[INFO] Finished at: 2020-02-20T22:44:48-06:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.moditect:moditect-maven-plugin:1.0.0.Beta2:add-module-info (add-module-infos) on project opencascade: Execution add-module-infos of goal org.moditect:moditect-maven-plugin:1.0.0.Beta2:add-module-info failed: Couldn't copy JAR file: /home/lvh/src/javacpp/javacpp-presets/opencascade/target/opencascade-linux-x86_64.jar -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/PluginExecutionException
[ERROR] 
[ERROR] After correcting the problems, you can resume the build with the command
[ERROR]   mvn <args> -rf :opencascade

-- note: opencascade.jar does exist, but opencascade-linux-x86_64.jar does not. Were you expecting to see both? Here are the contents:

jar -tf opencascade.jar       
META-INF/MANIFEST.MF
META-INF/
META-INF/maven/
META-INF/maven/org.bytedeco/
META-INF/maven/org.bytedeco/opencascade/
META-INF/maven/org.bytedeco/opencascade/pom.xml
META-INF/maven/org.bytedeco/opencascade/pom.properties
META-INF/versions/
META-INF/versions/9/
META-INF/versions/9/module-info.class

@lvh
Copy link
Author

lvh commented Feb 21, 2020

mvn compile --projects .,opencascade completes successfully but produces the same jar. mvn compile install --projects .,opencascade fails as above. I'm working off the currently pushed commit (just added module-info.java since you last saw it--as you pointed out that shouldn't make a difference, but it did make me double-check git status so I'm pretty sure we're looking at the same thing now :-))

@lvh
Copy link
Author

lvh commented Feb 21, 2020

.... except apparently we're not looking at the same thing, because closed draft PRs don't see new commits being pushed to the source branch apparently? I swear I felt like I understood GitHub 5 years ago and now I do not.

@lvh lvh reopened this Feb 21, 2020
@lvh
Copy link
Author

lvh commented Feb 21, 2020

Reopening it made the extra commit show up, but also re-triggered CI.

@lvh
Copy link
Author

lvh commented Feb 21, 2020

Let's see if closing it again makes Jenkins stop doing work.

@lvh lvh closed this Feb 21, 2020
@lvh
Copy link
Author

lvh commented Feb 21, 2020

Woo, that did it! Sorry for the e-mail notification spam -- see above for where I'm stuck at.

@saudet
Copy link
Member

saudet commented Feb 21, 2020

Woo, that did it! Sorry for the e-mail notification spam -- see above for where I'm stuck at.

Like I said, just delete .appveyor.yml and .travis.yml for now.

As for why it's not producing a JAR file, you'll need to have some content or it will keep skipping creating one as shown in your log above:

[INFO] --- maven-jar-plugin:3.1.0:jar (javacpp-linux-x86_64) @ opencascade ---
[INFO] Skipping packaging of the jar

@lvh lvh reopened this Feb 21, 2020
@lvh
Copy link
Author

lvh commented Feb 21, 2020

I've temporarily deleted those two files, disabling CI.

What's supposed to be in that jar? Just the .so's, or .so's + the generated InfoMapper class file? I'd expect the latter, and it to not be empty because of that. Do I edit the toplevel pom.xml, the module pom.xml, or the platform pom.xml? I assume it's the module pom.xml, but the Create New Presets wiki page doesn't seem to suggest I put anything in there beyond what's already in this PR.

* limitations under the License.
*/

package org.bytedeco.ale.presets;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll need to place your class in this package here:

[INFO] --- javacpp:1.5.3-SNAPSHOT:parse (javacpp-parser) @ opencascade ---
[WARNING] No classes found in package org.bytedeco.opencascade.presets
[INFO] Detected platform "linux-x86_64"
[INFO] Building for platform "linux-x86_64"

@lvh
Copy link
Author

lvh commented Mar 7, 2020

Progress! Thanks for pointing out that error. I've fixed that and got further.

Current error:

[ERROR] Failed to execute JavaCPP Builder: /home/lvh/src/javacpp/javacpp-presets/opencascade/cppbuild/linux-x86_64/include/opencascade/Standard_Persistent.hxx:27:Could not parse declaration at ','
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] 
[INFO] JavaCPP Presets 1.5.3-SNAPSHOT ..................... SUCCESS [  0.660 s]
[INFO] JavaCPP Presets for OpenCASCADE 7.4.0-1.5.3-SNAPSHOT FAILURE [ 42.322 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  43.668 s
[INFO] Finished at: 2020-03-06T20:35:30-06:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.bytedeco:javacpp:1.5.3-SNAPSHOT:parse (javacpp-parser) on project opencascade: Failed to execute JavaCPP Builder: /home/lvh/src/javacpp/javacpp-presets/opencascade/cppbuild/linux-x86_64/include/opencascade/Standard_Persistent.hxx:27:Could not parse declaration at ',' -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException
[ERROR] 
[ERROR] After correcting the problems, you can resume the build with the command
[ERROR]   mvn <args> -rf :opencascade

Here's the header file that breaks:

// Copyright (c) 1998-1999 Matra Datavision
// Copyright (c) 1999-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.

#ifndef _Standard_Persistent_HeaderFile
#define _Standard_Persistent_HeaderFile

#include <Standard_Type.hxx>

//! Root of "persistent" classes, a legacy support of
//! object oriented databases, now outdated.
class Standard_Persistent : public Standard_Transient
{
public:
  DEFINE_STANDARD_ALLOC
  
  Standard_Persistent() : _typenum(0), _refnum(0) {}

  DEFINE_STANDARD_RTTIEXT(Standard_Persistent,Standard_Transient)
  Standard_Integer& TypeNum() { return _typenum; }

private:
  Standard_Integer _typenum;
  Standard_Integer _refnum;

  friend class Storage_Schema;
};

#endif // _Standard_Persistent_HeaderFile

I'll try taking that out and moving on but I figured that would be useful information already :) Thank you for your help so far!

@lvh
Copy link
Author

lvh commented Mar 7, 2020

Thanks! That documentation is extremely well written: it quickly got me to exactly the two cases I've needed to cover so far.

Is there a way to continue on error so that I get all of the failures in one go instead of having to do a full mvn compile install --projects .,opencascade each time? The compilation step takes a while so this makes iterating slow.

@saudet
Copy link
Member

saudet commented Mar 7, 2020

We can skip some steps like "mvn -Djavacpp.cppbuild.skip ..." to speed things up, but the parser isn't that great, no.

@lvh
Copy link
Author

lvh commented Mar 7, 2020

OK, new place I'm stuck:

[ERROR] Failed to execute JavaCPP Builder: .../NCollection_BaseList.hxx:44:
Unexpected token 'Iterator'

Relevant section of the header file:

#ifndef NCollection_BaseList_HeaderFile
#define NCollection_BaseList_HeaderFile

#include <Standard_NoSuchObject.hxx>
#include <NCollection_DefineAlloc.hxx>
#include <NCollection_ListNode.hxx>

typedef void (* NCollection_DelListNode) 
     (NCollection_ListNode*, Handle(NCollection_BaseAllocator)& theAl);

// ********************************************************** BaseList class
class NCollection_BaseList
{
public:
  //! Memory allocation
  DEFINE_STANDARD_ALLOC
  DEFINE_NCOLLECTION_ALLOC

public:
  class Iterator                  // 💥 line 44 where the error happens
  {
  public:
    // ******** Empty constructor
    Iterator  (void) :
      myCurrent (NULL),
      myPrevious(NULL) {}
    // ******** Constructor with initialisation

I assumed the error was the (previously undefined) DEFINE_NCOLLECTION_ALLOC. I added that to the list of annotations (see commit cf1d3ef), but the parser still fails.

I'll continue reading that document and define more things from the headers included by that header to try and make progress in the mean while :)

@lvh
Copy link
Author

lvh commented Mar 7, 2020

Are includes literally "included" in-line? E.g. if I see a failure on line 44 and I start scanning for the stuff in front of it, is it possible the problem is actually in an included file? I ask because after walking the recursively included headers, I'm seeing two new custom macros DEFINE_STANDARD_RTTIEXT and DEFINE_STANDARD_HANDLE and I have no idea what they do yet (but I'll get there :-))

@saudet
Copy link
Member

saudet commented Mar 8, 2020

No, they are not actually included as explained in this section:
https://github.com/bytedeco/javacpp/wiki/Mapping-Recipes#including-multiple-header-files

@lvh
Copy link
Author

lvh commented Mar 8, 2020

Hm, OK: would you expect to see that Unexpected token 'Iterator' style problem if the inclusion order is wrong?

Given the huge number of header files I'm likely to do an actual topological sort with an ad-hoc parser rather than a manual one :-)

@saudet
Copy link
Member

saudet commented Mar 8, 2020

Listing the header files isn't what takes most of the time. If you feel that even this small task is going to take long, you should probably consider helping out with this first: bytedeco/javacpp#51

@lvh
Copy link
Author

lvh commented Mar 8, 2020

I'm just trying to make a little progress at a time. Since I've never done this before, it's hard to know which parts will be tricky. It makes sense that normally that part would be easy, but this thing has thousands of header files!

Should I interpret your comment to mean seeing [ERROR] Failed to execute JavaCPP Builder: .../NCollection_BaseList.hxx:44: Unexpected token 'Iterator' as a consequence of headers being included in the wrong order makes sense to you?

@saudet
Copy link
Member

saudet commented Mar 9, 2020

Yes, we need to start by including the header files that contain those macros first.

@mmaenz
Copy link

mmaenz commented Mar 17, 2020

Always compiling is a pain in the ass and takes about 40min. If build once, I did a shortcut to speed-up:

  1. created permanent directory under javacpp-presets/opencascade/<occ_dir>
  2. mv $PLATFORM/bin, include, lib, share out to <occ_dir>
  3. cppbuild.sh: comment out download section and cd'ing to opencascade-$OPENCASCADE_VERSION
  4. comment out everything on your platform and write cp -r ../../occ/* .

This way the result gets copied everytime and there is no need to recompile.

One thought on .../NCollection_BaseList.hxx:44: Unexpected token 'Iterator'.
Nested classes have changed since c++11 https://en.cppreference.com/w/cpp/language/nested_types. May the parser could have problems with that or clang isn't forced to use c++11?

I did a small test with helloworld-2.0 and exactly this nested class combination and it worked.
NCollection_BaseList uses on public: for Memory allocation and public: for the Iterator class. When commenting out the second public: it works till other problems occur.

Might worth to give it a try?

@mmaenz
Copy link

mmaenz commented Mar 17, 2020

Update on that.
Saudet is right, when all NCollection_Define* header are put in the beginning of @platform(include={..}) it works.

@mmaenz
Copy link

mmaenz commented Mar 18, 2020

Ok,

I broke the whole library into frameworks. Started with framework Foundation as this is the base for everything else. I included this in opencascade.java via inherit and moved everything foundation related to presets/frameworks/Foundation.java.

Foundation has 2 Toolkits. TKernel and TKMath which have several modules. If I get it working I'm thinking about a more granular structure...

Everything works fine, except when compiling. cmake installed opencascade headers into include/opencascade as usual but clang can't find them:
clang++ -I/Users/mmaenz/Projects/java-occ-cpp/javacpp-presets/opencascade/cppbuild/macosx-x86_64/include -I...
and fails with:
error: 'Standard_Transient.hxx' file not found with <angled> include; use "quotes" instead #include <Standard_Transient.hxx>.

Is there a way to tell the compiler the exact directory for the required includes? My current solution would be to tell cmake to output to include instead of include/opencascade.

BTW I'm on macOS.

@saudet
Copy link
Member

saudet commented Mar 19, 2020

When the files are in a "opencascade" subdirectory of the "include" directory, including "opencascade/Standard_Transient.hxx" instead of just "Standard_Transient.hxx" should work.

@mmaenz
Copy link

mmaenz commented Mar 19, 2020

Sorry my quoted error message is confusing. Here is a whole error:
In file included from /Users/mmaenz/Projects/java-occ-cpp/javacpp-presets/opencascade/target/native/org/bytedeco/opencascade/macosx-x86_64/jniopencascade.cpp:97: /Users/mmaenz/Projects/java-occ-cpp/javacpp-presets/opencascade/cppbuild/macosx-x86_64/include/opencascade/NCollection_DefineAlloc.hxx:19:10: error: 'NCollection_BaseAllocator.hxx' file not found with <angled> include; use "quotes" instead #include <NCollection_BaseAllocator.hxx>

I can't change NCollection_DefineAlloc.hxx or I have to change 10.000+ header files. Used opencascade with c++ installed with macports before and it required additional -I<..>/include/opencascade.

Using -DINSTALL_DIR_INCLUDE=include does the trick by now.

I had to exclude several headers from Foundation @Property include as they are throwing errors when compiling and they don't hold any neccessary data structures for me, just internal library stuff that doesn't need to be accessible.

Everything compiles fine now but the resulting opencascade-macosx-x86_64.jar is very tiny. I thought all .dylib libraries are included (shaded jar?)? How to I achieve this?

Here is my branch:
https://github.com/mmaenz/javacpp-presets/tree/feature/opencascade-7.4.0/working-foundation

@saudet
Copy link
Member

saudet commented Mar 19, 2020

It sounds like we need to add more include directories. Those can be added to the list here:
https://github.com/bytedeco/javacpp-presets/blob/master/pom.xml#L189

@lvh
Copy link
Author

lvh commented Mar 19, 2020

Sorry, I've been meaning to add an update to this.

I wrote a dinky little tool that takes an include/ directory, reads the headers, tries to build an internal dependency graph, heuristically removes cycles by breaking them so that headers with fewer dependencies move towards the top of the topsort, then does a topsort. It needs a little bit of plumbing to be usable from stdout, but it's mostly there: https://github.com/lvh/includegraph/blob/master/src/io/lvh/includegraph.clj.

I expect that it won't be super useful generally, but at the same time I won't be the last person to bind a library with more than a few header files, so I'll put it out there regardless.

Re: OpenCASCADE itself: a big problem I've ran into is the Handle concept. They're basically OpenCASCADE's custom smart pointers. You can find more details here: tpaviot/pythonocc-core#214 -- but the bottom line is that, if I understand correctly, pythonocc spent a bunch of effort (Thomas Paviot has forgotten more about OpenCASCADE than I will ever know) and ended up mostly punting on the problem and accepts that references will leak.

As a consequence I don't think I can land this by myself, so I'm very happy to see @mmaenz step in :)

@lvh
Copy link
Author

lvh commented Mar 19, 2020

Heads up, I was mistaken about how memory management works, they since then have come up with a better scheme, see tpaviot/pythonocc-core#220.

@mmaenz
Copy link

mmaenz commented Mar 20, 2020

SWIG was my first try to use occ with java and I modified tpaviot's generator wrapper. It is a python script which parses most of occ's headers and groups them into modules. It then generates the .i files required for SWIG. I was really disappointed about SWIG because it produces a flat java package and strange exceptions and after a long while i switched to javacpp. I emailed tpaviot for help but no response.

At least I used his python script to sort all headers by framework -> toolkit -> Module. His script produces nice collections of related headers like NCollection_module.hxx with all relevant headers inside.

Sadly (I'm not sure all at) I read somewhere that javacpp can't follow #include directives so I'm going to modify his script to output (as text to copy) all relevant headers for each module.
I will post the structure for further reference if needed.

The Handle is quite tricky. As far as I understand the sources, there is a base class handle which is a generic template (Standard_Handle.hxx) and 2 abstract classes Standard_Transient(.hxx) and Standard_Persistent(.hxx).

I'm not sure but I wouldn't care about internal memory management of occ. It's kept in the library and not on the java side. We need these 3 as classes in Java for use?
Please correct me if I'm wrong!

@saudet
Copy link
Member

saudet commented Mar 20, 2020

I'm not sure but I wouldn't care about internal memory management of occ. It's kept in the library and not on the java side. We need these 3 as classes in Java for use?
Please correct me if I'm wrong!

If they are part of the public API, yes, but if they are not meant to be called by end users, no.

@mmaenz
Copy link

mmaenz commented Mar 20, 2020

In my fork is a structure directory with information about the library and relevant header files sorted by modules.

I got reply from Agostino de Marco who had build jCAE in the past and worked with Thomas Paviot. He said he once bought the swig interface files from OpenCascade and ported them to 7.3.0. He said it was a pain and took real effort. However he is willing to contribute again. The newer versions of swig files are really pricy.

@lvh If you need an urgent running occ in java, I managed to get it done with opencascade 7.3.0
image

They didn't port the whole library, only the most needed headers to get most of the things working. I'm going to do the same now for javacpp and, if needed, more specific things on demand.

May it be possible to move the discussion out of the PR? If it get's closed, a lot of information will get lost?

@saudet
Copy link
Member

saudet commented Mar 21, 2020

They didn't port the whole library, only the most needed headers to get most of the things working. I'm going to do the same now for javacpp and, if needed, more specific things on demand.

Yes, that's how it should be done.

May it be possible to move the discussion out of the PR? If it get's closed, a lot of information will get lost?

This thread won't get deleted when the PR is closed. If you get something up and running and you open another PR, we can just reference this thread "for more information".

@saudet
Copy link
Member

saudet commented Mar 25, 2020

BTW, if Open CASCADE has a C API, even if it's limited, that's usually straightforward to map, so it could provide a good initial step and we would get something minimally usable right away.

@lvh
Copy link
Author

lvh commented Mar 25, 2020

Unfortunately they don't :-( I'll start by figuring out how to do this with pythonocc so at least I know what subset of APIs I need and how they're supposed to work. But this is a side project, so nobody should hold their breath :)

@agodemar
Copy link

agodemar commented Jun 4, 2020

I got reply from Agostino de Marco who had build jCAE in the past [...]. He said he once bought the swig interface files from OpenCascade and ported them to 7.3.0. He said it was a pain and took real effort. However he is willing to contribute again.

Hello, I confirm I'd like to help out with this preset. I just have to figure out how to start off working with javacpp.

@saudet
Copy link
Member

saudet commented Jun 4, 2020

@agodemar Please start here: https://github.com/bytedeco/javacpp/wiki/Mapping-Recipes

@agodemar
Copy link

agodemar commented Jun 6, 2020

@lvh @mmaenz @saudet
Regarding OCCT, to avoid compilation of OpenCASCADE in the CI workflow, you might want to consider this repo: occ-for-csg. It provides OpenCascade and required dependencies for OCC-CSG. The release area contains static builds for Linux, macOS and Windows (june 2020, v7.4.0).

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

Successfully merging this pull request may close these issues.

None yet

4 participants