On Windows, how to use classes in C++ DLL library from Julia?

question
windows

#1

I do work on Windows as it’s the standard platform for our company. A simulation software vendor provided a C++ DLL library that was built with Visual Studio. I cannot access the source code, nor can the vendor custom-build things for me. However, I do have the C++ header files that contain the definition of exposed classes and functions. Under Visual Studio, I was able to use them from either a C++ application or C# .NET application (through C++/CLI).

It’ll be so great if I can use this simulation library from Julia. With my limited C++ knowledge, though, I was not able to figure out how. There are several C++ compatibility libraries Cxx.jl, CxxWrap.jl, Cpp.jl, Clang.jl, but they seem to be Linux-centric to me, and may require MinGW or other non-Visual Stuido compilers/builders on Windows, which I am reluctant to try since the DLL I have is built with Visual Studio.

In addition, I will need to be able to new objects of classes and update class member variables’ values in run-time. The data types involved include integers, enums, doubles, strings (char arrays to be exact), 1-and-2-dimensional double arrays, and pointers or array of pointers to objects (all their classes are defined in the available header files). So it is maybe insufficient for me only to be able to call C++ functions…

Anybody here has any experience or suggestion regarding how this can be done? Many thanks!


#2

Can you write a C-API wrapper that has different functions for the various operations you want to do, compile and link that to the library, then ccall into the wrapper?


#3

CxxWrap supports using Visual Studio, and in fact does so by default on Windows for now, see:

This in fact automates what @tkelman suggests. Also, there are caveats when not using the same compiler as Julia even when going through ccall, discussed here for instance:


#4

Hi tkelman, thanks for replying.

It is theoretically possible but fairly difficult to wrap everything into top level function calls… The model is a hierarchical structure - the top layer object contains subcomponents that are also objects of custom classes. For one simulation run, there will be many different results and different ways to examine these results. I am constantly experimenting with different models and examining different results so such variations should be done at high level in Julia, not in the C++ wrapper, otherwise I should just write the whole numerical “experiments” in C++ then.


#5

Hi barche, I didn’t realize that! I just added CxxWrap.jl on my Windows based Julia 0.5 and it was built successfully (in contrast to Cxx.jl which won’t build). I’ll try it out first. Thanks!


#6

Today I was able to install CxxWrap.jl and re-create the CppHello example using Visual Studio 2015 on Windows. It took me a while to figure out the necessary compiler/linker options to make it work. I am not sure how many out there could be in similar situations as mine (mainly working with Visual Studio on Windows and not terribly familiar with C++), but here’s a step-by-step guide, based upon the CxxWrap.jl github README.md and examples, for myself to remember and for whoever may find it helpful:

First, in order to install CxxWrap,

  • Make sure the system has Visual Studio 2015 (aka Visual Studio 14) installed (community edition ISO download link can be found here), and Visual C++ has been installed.
    Note 1: By default installing Visual Studio only gives you C# and VB. User must select Visual C++ to be installed.
    Note 2: Visual Studio 2015 is required; 2013 or 2017 would not work.

  • Make sure CMake has been installed (download link), and its bin folder is included in the environmental variable PATH. For example, if the installation path is C:\CMake, then C:\CMake\bin should be included in PATH - the installer would add it automatically.

  • Create an environmental variable BUILD_ON_WINDOWS with the value 1.

  • In Julia console, type:
    Pkg.add("CxxWrap")
    Because BUILD_ON_WINDOWS = 1, the package will try to build the binary on Windows instead of downloading the binary from server. The build process will use CMake which in turn uses Visual C++ compiler.

Now it’s time to create the Visual Studio project to build CppHello.dll. The following steps assume JuliaPro 0.5.1 has been installed to C:\JuliaPro.

  • In Visual Studio 2015, New Project, Installed | Templates | Other Languages | Visual C++ | Win32 | Win32 Project. Type in the name “CppHello” and choose Location of the project.

  • In the Win32 Application Wizard, click Next, then select Application Type as DLL; in Additional options uncheck Security Development Lifecycle (SDL) checks. Then click Finish.

  • Choose the active configuration as Release; choose x86 or x64 to match the CPU and the Julia version installed.

  • Right click on the project name in the Solution Explorer, and choose Properties. Make the following changes (modify directory names as needed to match the actual Julia installation path):

C/C++ | General | Additional Include Directories: insert “C:\JuliaPro\Julia-0.5.1\include\julia;C:\JuliaPro\pkgs-0.5.1.1\v0.5\CxxWrap\deps\usr\include;”

C/C++ | Preprocessor | Preprocessor Definitions: insert “JULIA_ENABLE_THREADING;” before “%(PreprocessorDefinitions)”

Linker | Input | Additional Dependencies: insert “C:\JuliaPro\pkgs-0.5.1.1\v0.5\CxxWrap\deps\usr\lib\cxx_wrap.lib;C:\JuliaPro\Julia-0.5.1\lib\libjulia.dll.a;” before “%(AdditionalIncludeDirectories)”

Click OK to exit the CppHello Property Pages.

  • In Solution Explorer, under Source Files, double click “CppHello.cpp” to open it. Append the following code at the end and save:
#include <cxx_wrap.hpp>

std::string greet()
{
  return "hello, world";
}

JULIA_CPP_MODULE_BEGIN(registry)
  cxx_wrap::Module& hello = registry.create_module("CppHello");
  hello.method("greet", &greet);
JULIA_CPP_MODULE_END
  • Build the CppHello project.

  • Locate the resulted CppHello.dll file under the Release folder. For a 64-bit build, it would be the project folder\x64\Release.
    For testing, let’s assume we copy the DLL file to C:\temp\CppHello.dll

  • Time for the rubber to hit the road! In the Julia console, try the following - the output should match what’s shown below.

julia> using CxxWrap

julia> wrap_modules("C:\\temp\\CppHello.dll")

julia> CppHello.greet()
"hello, world

#7

Have you tried Visual Studio 2017 or are you just assuming it won’t work based on the CxxWrap readme which just says to use the latest VS and mentions VS 2015 specifically?


#8

I started the build with Visual Studio 2013 and 2017 installed but without 2015. The build didn’t work. The error message as well as the installation .jl script indicated CMake was looking for Visual Studio 2015 specifically. So I installed 2015 and the build worked.


#9

That’s likely due to the relative release schedules of visual studio and cmake. Some future version of cmake will probably change the default search order they use.


#10

Nice tutorial, feel free to open a pull request to integrate it into the readme! Note that it is not necessary to create the Visual Studio project by hand: CMake creates a .sln file in the deps/build directory of the package, and that can be opened using Visual Studio to edit the source files and so on. The drawback is that this file gets overwritten if you add a new C++ source file for example.

Regarding the Visual Studio version, this is indeed hard-coded into the build.jl, because at the time I wrote it VS2015 was the only version capable of compiling the C++11 code. Presumably VS2017 would also work, so I should look into making both work (made an issue to track this).


#11

Thanks! I have created the pull request at GitHub. Really appreciate your nice library.