MATLAB Speaks C++
Hi everyone! Today I'd like to introduce a guest blogger, Vivek Bhownani, who is the lead developer for an exciting new feature in R2019a that opens up easy access to C++ libraries without writing any C++ code. Take it away Vivek...
Is there a C++ library you use or would like to use in MATLAB? We hear requests all the time from users looking to call C++ libraries spanning subjects from Machine Learning to Game Development. OpenCV, Tensorflow, and LibXL are some examples.
Wrapping a C++ library for use from an external environment can be a very time consuming task, requiring a lot of development work. Our goal is to enable you to call C++ without writing any C++ code, potentially bringing days of work for wrapping a library down to a few hours.
For many years, MATLAB has provided the ability to call these libraries by wrapping them in C interfaces and using LOADLIBRARY. MATLAB has also provided the MEX interface which allows you to write a MATLAB wrapper file for calling out to C or C++ functionality. However, each option has its limitations, and neither provides a direct way to call C++ from MATLAB. This is why I’m excited about the new capabilities in R2019a that help you call C++ libraries from MATLAB. MATLAB now speaks C++!
Our User Personas: I want to reach out to two different types of users through this post. You are a publisher of a library if you're looking to make a certain C++ library available for calling in MATLAB. You are an end user if you're looking to simply call a library through its published interface.
Contents
You don't need to know C++ to call C++
We want to help publishers focus on building applications based on your C++ libraries. In fact, you don't even need to know much C++. Leave that to us.
SWIG is a tool which provides a way to publish wrapper interfaces for C++ libraries that can be used from environments including Python and Java. But users need to write special SWIG interface code, which they must learn and maintain. Unlike SWIG, MATLAB will attempt to generate an interface definition file for you. You can then edit this file in designated blocks to tailor the interface to your needs. You don’t need to learn a specific way to code.
As an end user, you may not need to even create the interface file - maybe someone will write one for you.
We encourage some of you to act as publishers and create these interface files for libraries you want to share with end users. You might be a developer who wrote the C++ library and want to reach a broader audience; or maybe your company provides drivers for hardware that could be used with MATLAB. Other publishers might simply want to share their work to help other users call a C++ library you’re calling. As a publisher, you will need a compatible C++ compiler. If you are an end user, you do not need a C++ compiler to call the library.
Let’s look at calling a C++ class I wrote
I created a couple of classes in C++ for a Car with Engine example:
class Engine { private: int fNumberOfCylinders; public: Engine(int numcylinders) : fNumberOfCylinders(numcylinders), isServiced(false) {} int getNumCylinders() const { return fNumberOfCylinders; } bool isServiced; }; class Car { private: Engine& fEngine; public: Car(Engine &engine): fEngine(engine) {} Engine& getEngine() { return fEngine; } };
Building the Interface
Since this library is just a header file, we can do a "direct" build using the following function:
clibgen.generateLibraryDefinition("auto.h");
build(defineauto);
Warning: Only header files specified; assuming this is a header-only library. If library files also need to be specified, use the 'Libraries' option. Warning: File 'manifest.json' not found. Using Microsoft Visual C++ 2015 compiler. Generated definition file 'C:\BlogPost\defineauto.mlx' and data file 'C:\BlogPost\autoData.xml' contain definitions for 9 constructs supported by MATLAB. Build using build(defineauto). Building interface file 'autoInterface.dll'. Interface file 'autoInterface.dll' built in folder 'C:\BlogPost\auto'. To use the library, add the interface file folder to the MATLAB path.
You can safely ignore the warning generated in this case. We issue a warning to remind users that we are assuming that this is a header-only library, and if that is not accurate, then the "Libraries" option should be used to provide the library. Don’t forget to add the generated folder 'auto' (which contains the generated interface) to the MATLAB path.
addpath('auto');
That's it, we're now ready to call this library from MATLAB
Let's first create a car with an engine
eng = clib.auto.Engine(4); car = clib.auto.Car(eng); car.getEngine.isServiced
ans = logical 0
Now let's service the engine, and check the car again:
eng.isServiced = true; car.getEngine.isServiced
ans = logical 1
MATLAB creates handles to represent C++ objects. As you see above, 'eng' points to the engine inside the car (the object returned by the 'getEngine' method in the 'car' class). However, it cannot be used to destroy the engine inside the car, i.e., the car continues to own its engine. Notice when we call delete on the engine.
delete(eng) eng
eng = handle to deleted Engine
car.getEngine % The car (with its engine) is still intact.
ans = Engine with properties: isServiced: 1
Let's now look at an encryption example
Here's a piece of C++ code that calls an encryption algorithm in the SpaceCrypto library to encrypt the string "hello world!" and then subsequently calls decryption to get the original string back.
#include <iostream> #include "cryptopp_wrapper.h" using namespace std; int main() { // Call Encryption cout<<"Space Wrapper TEST!"<<endl<<endl; SpaceCrypto::CryptBlowFish hello; hello.setPlainString("HelloWorld!"); hello.setKey("mySecUreKey!!"); std::string crypt; crypt = hello.Encrypt(); // Call Decryption cout<<"Plain Text: HelloWorld!"<<endl; cout<<"Crypt Text: "<<crypt<<endl; hello.reset(); hello.setEncString(crypt); hello.setInputMode(SpaceCrypto::HEX); hello.setKey("mySecUreKey!!"); hello.setOutputMode(SpaceCrypto::NORMAL); cout<<"Decry Text: "<<hello.Decrypt()<<endl; }
Building the Interface
Here we will need to do a little more work than the last example, but we still don’t need to write C++ Code. We have an alternative way to build the interface, which is a multi-step process - generate definition file, provide definitions, and then build.
Setup Environment
loc = 'cryptopp700'; dllLoc = fullfile(loc, 'x64\DLL_Output\Release'); path = getenv('PATH'); setenv('PATH', [dllLoc ';' path]);
Generate Definition
headerFiles = "cryptopp_wrapper.h"; includePath = loc; outputFolder = pwd; libraries = [fullfile(loc, "x64\DLL_Output\Release\cryptopp.lib"), ... fullfile(loc, "x64\DLL_Output\Release\cryptlib.lib")]; clibgen.generateLibraryDefinition(headerFiles, "IncludePath", includePath, ... 'Libraries', libraries, 'OutputFolder', outputFolder, 'PackageName', 'crypto', 'verbose', true);
Warning: Some C++ language constructs in the header file are not supported and not imported. Using Microsoft Visual C++ 2015 compiler. Generated definition file 'C:\BlogPost\definecrypto.mlx' and data file 'C:\BlogPost\cryptoData.xml' contain definitions for 20 constructs supported by MATLAB. 4 constructs require additional definition. To include these constructs in the interface, edit the definitions in 'C:\BlogPost\definecrypto.mlx'. Build using build(definecrypto).
The above step generates the definition file. This lists all the classes, functions, enums, etc. that we read in the header file.
The definition file...why do I need it?
Most of the workflow in building the C++ interface is automated. MATLAB reads the provided header files and generates an interface library that provides a way to call every function/class in the library. However, there are occasions when we cannot automatically call such functionality, and we need publishers to help specify "how to call" such functions ( Click here for an example.). Here's a snippet from the generated file:
Provide definitions for functions you want to call, if they are not fully defined. Use the C++ code (as shown above) to understand which functions need to be defined.
Now build the interface by calling:
build(definecrypto)
Building interface file 'cryptoInterface.dll'. Interface file 'cryptoInterface.dll' built in folder 'C:\BlogPost\crypto'. To use the library, add the interface file folder to the MATLAB path.
Please Note: You need a C++ compiler that is compatible with the compiler that the library was built with.
We are now ready to call the library in MATLAB. More importantly, we have an interface which publishers can share with end users, and they DO NOT need a compiler or need to know any C++ to call the library. Calling this C++ library in MATLAB is like calling any other piece of MATLAB code.
Import SpaceCrypto library
addpath('crypto') loc = 'cryptopp700'; dllLoc = fullfile(loc, 'x64\DLL_Output\Release'); path = getenv('PATH'); setenv('PATH', [dllLoc ';' path]); import clib.crypto.*
Encrypt original message
cryptObj = SpaceCrypto.CryptBlowFish; cryptObj.setPlainString("MATLAB Speaks C++!"); % Use MATLAB strings cryptObj.setKey("mySecUreKey!!"); encryptedMessage = cryptObj.Encrypt()
encryptedMessage = "3540541C31806EDD0FED2AD653A9B1EAD224D192AA281B26"
Decrypt and retrive original message
cryptObj = SpaceCrypto.CryptBlowFish; cryptObj.setEncString(encryptedMessage); cryptObj.setInputMode(SpaceCrypto.OUT_TYPE.HEX); % MATLAB enum for C++ enum cryptObj.setKey("mySecUreKey!!"); cryptObj.setOutputMode(SpaceCrypto.OUT_TYPE.NORMAL); originalMessage = cryptObj.Decrypt
originalMessage = "MATLAB Speaks C++!"
Try to interface to your own C++ library
Use the steps described above to wrap a C++ library you want to call in MATLAB. Read our documentation to learn more. In 19a we support a lot of C++ 98 constructs such as functions, classes, methods, template instantiations and typedefs. In future, we will be providing support for std::vector, smart pointers, wide strings, and more. We also plan to support automatic memory management for C++ objects in MATLAB. We are going to keep improving this feature, and I'd like to hear from you. Comment below and tell us how it went for you or what capabilities you think we should add to this next. We’re just getting started!
- Category:
- External Interfaces,
- Third Party Integration
Comments
To leave a comment, please click here to sign in to your MathWorks Account or create a new one.