Calling MATLAB from C++ errors: unresolved external symbol
Asked Answered
C

2

8

I encounter several errors when calling my MATLAB function from C++. The main idea is: firstly compile a MATLAB function and generate DLL file, and then include .h and .lib files in C++. Finally, write .cpp to test and call the function. Here's my detailed steps and please tell me where I'm wrong.

(Using MATLAB 2012b and Visual C++ 2008, Windows 7 64-bit)

In MATLAB:

  1. mbuild -setup and mex -setup to set Visual Microsoft Visual C++ 2008 SP1 as the compiler.
  2. Create MyAdd.m in folder C:\Users\WangYudong\Documents\MATLAB\MyAdd_M and the function is like:

    function [c] = MyAdd(a, b)
    c = a + b;
    
  3. mcc -W cpplib:libMyAdd -T link:lib MyAdd to compile MyAdd.m and generate several files including libMyAdd.dll, libMyAdd.h, libMyAdd.lib and other files.

In C++

  1. Select VC++ DirectoriesInclude files to add E:\MATLAB\R2012b\extern\include.

  2. Select VC++ DirectoriesLibrary files to add E:\MATLAB\R2012b\extern\lib\win64\microsoft and C:\Users\WangYudong\Documents\MATLAB\MyAdd_M.

  3. Select LinkerInputAdditional Dependencies to add new entries:

    mclmcr.lib
    mclmcrrt.lib
    libmx.lib
    libmat.lib
    libMyAdd.lib
    
  4. Create a new MyAdd_test.cpp and put libMyAdd.dll, libMyAdd.h and libMyAdd.lib in the same folder. Add libMyAdd.h in Header Files, libMyAdd.h and libMyAdd.lib in Resource Files.

Code of MyAdd_test.cpp is like:

#include "mclmcr.h"
#include "matrix.h"
#include "mclcppclass.h"
#include "libMyAdd.h"

int main() {   
    double a = 6;
    double b = 9;
    double c;
    // initialize lib
    if( !libMyAddInitialize()) {
        std::cout << "Could not initialize libMyAdd!" << std::endl;
        return -1;
    }

    // allocate space
    mwArray mwA(1, 1, mxDOUBLE_CLASS);
    mwArray mwB(1, 1, mxDOUBLE_CLASS);
    mwArray mwC(1, 1, mxDOUBLE_CLASS);  
    // set data
    mwA.SetData(&a, 1);
    mwB.SetData(&b, 1);
    // use function: MyAdd
    MyAdd(1, mwC, mwA, mwB);
    // get data
    c = mwC.Get(1, 1);
    printf("c is %f\n", c); 

    // terminate the lib
    libMyAddTerminate();   
    // terminate MCR
    mclTerminateApplication();
    return 0;
}  

At last, the result is

Compiling...
MyAdd_test.cpp
Linking...
MyAdd_test.obj : error LNK2019: unresolved external symbol _mclTerminateApplication_proxy referenced in function _main
MyAdd_test.obj : error LNK2019: unresolved external symbol _libMyAddTerminate referenced in function _main
MyAdd_test.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) void __cdecl MyAdd(int,class mwArray &,class mwArray const &,class mwArray const &)" (__imp_?MyAdd@@YAXHAAVmwArray@@ABV1@1@Z) referenced in function _main
MyAdd_test.obj : error LNK2019: unresolved external symbol _libMyAddInitialize referenced in function _main
MyAdd_test.obj : error LNK2019: unresolved external symbol _mclGetMatrix referenced in function "public: __thiscall mwArray::mwArray(unsigned int,unsigned int,enum mxClassID,enum mxComplexity)" (??0mwArray@@QAE@IIW4mxClassID@@W4mxComplexity@@@Z)
MyAdd_test.obj : error LNK2019: unresolved external symbol _mclcppGetLastError referenced in function "public: static void __cdecl mwException::raise_error(void)" (?raise_error@mwException@@SAXXZ)
MyAdd_test.obj : error LNK2019: unresolved external symbol _mclcppCreateError referenced in function "public: __thiscall mwException::mwException(void)" (??0mwException@@QAE@XZ)
MyAdd_test.obj : error LNK2019: unresolved external symbol _ref_count_obj_addref referenced in function "public: __thiscall mwException::mwException(class mwException const &)" (??0mwException@@QAE@ABV0@@Z)
MyAdd_test.obj : error LNK2019: unresolved external symbol _ref_count_obj_release referenced in function "public: virtual __thiscall mwException::~mwException(void)" (??1mwException@@UAE@XZ)
MyAdd_test.obj : error LNK2019: unresolved external symbol _error_info_get_message referenced in function "public: virtual char const * __thiscall mwException::what(void)const " (?what@mwException@@UBEPBDXZ)
MyAdd_test.obj : error LNK2019: unresolved external symbol _array_ref_getV_int referenced in function "public: class mwArray __cdecl mwArray::GetPromoted(unsigned int,...)" (?GetPromoted@mwArray@@QAA?AV1@IZZ)
MyAdd_test.obj : error LNK2019: unresolved external symbol _array_ref_set_numeric_mxDouble referenced in function "public: void __thiscall mwArray::SetData(double *,unsigned int)" (?SetData@mwArray@@QAEXPANI@Z)
MyAdd_test.obj : error LNK2019: unresolved external symbol _array_ref_get_numeric_mxDouble referenced in function "public: __thiscall mwArray::operator double(void)const " (??BmwArray@@QBENXZ)
C:\Users\WangYudong\Documents\Visual Studio 2008\Projects\MyAdd_C\Debug\MyAdd_C.exe : fatal error LNK1120: 13 unresolved externals

Actually, the work above is my test to call a custom MATLAB function from C++. My following work is to convert a MATLAB program to C++, which contains image processing functions like imread, edge, strel, etc. I've tried MATLAB Coder, but it can't convert MATLAB functions. So I try the method above. Is it an efficient way to convert those functions or should I implement them using OpenCV?

Cherianne answered 15/6, 2013 at 5:51 Comment(4)
Are you compiling all your libraries for 64-bit?Coggins
When you edit the VS library configuration, make sure you edit it for every config (Debug,Release,32,64bit). You should start "debugging" this problem by seeing the actual command that is run: #824354Pal
@WangYudong: your problem is linking. Why not use mbuild to build the test program: mbuild MyAdd_test.cpp libMyAdd.lib. It knows how to invoke the VC++ compiler/linker with the correct flags. If you add a verbose -v option, you'll be able to see the actual callsTrotter
btw I think you forgot to initialize the MCR first in your code: mclInitializeApplicationTrotter
T
6

Before you start, make sure you have a supported compiler installed. That would be Visual C++ and possibly Windows SDK if you are using VS Express edition on a 64-bit Windows. Next you need to configure MATLAB by running these steps at least once:

>> mex -setup
>> mbuild -setup

Now given the following simple function:

MyAdd.m

function c = MyAdd(a,b)
    c = a + b;
end

We want to build a C++ shared library using the MATLAB Compiler mcc:

>> mcc -N -W cpplib:libMyAdd -T link:lib MyAdd.m -v

This will produce a couple of files including a header file, a DLL, and an import library:

libMyAdd.h
libMyAdd.dll
libMyAdd.lib

Next we create a C++ program to test the above library:

MyAdd_test.cpp

#include "libMyAdd.h"

int main()
{
    // initialize MCR and lib
    if (!mclInitializeApplication(NULL,0))  {
        std::cerr << "could not initialize the application" << std::endl;
        return -1;
    }
    if(!libMyAddInitialize()) {
        std::cerr << "Could not initialize the library" << std::endl;
        return -1;
    }

    try {
        // create input
        double a[] = {1.0, 2.0, 3.0, 4.0};
        double b[] = {5.0, 6.0, 7.0, 8.0};
        mwArray in1(2, 2, mxDOUBLE_CLASS, mxREAL);
        mwArray in2(2, 2, mxDOUBLE_CLASS, mxREAL);
        in1.SetData(a, 4);
        in2.SetData(b, 4);

        // call function
        mwArray out;
        MyAdd(1, out, in1, in2);

        // show result
        std::cout << "in1 + in2 = " << std::endl;
        std::cout << out << std::endl;

        double c[4];
        out.GetData(c, 4);
        for(int i=0; i<4; i++) {
            std::cout << c[i] << " " << std::endl;
        }

    } catch (const mwException& e) {
        std::cerr << e.what() << std::endl;
        return -2;
    } catch (...) {
        std::cerr << "Unexpected error thrown" << std::endl;
        return -3;
    } 

    // cleanup
    libMyAddTerminate();   
    mclTerminateApplication();

    return 0;
}

We could compile this program right from inside MATLAB using:

>> mbuild MyAdd_test.cpp libMyAdd.lib -v
>> !MyAdd_test

We could also compile it ourselves using Visual Studio. We start by creating a native console application, then set the project settings as follows:

  • From the menu, select "Project > Properties" and apply the settings to "All configurations" (both debug and release targets)
  • Under C/C++ properties, set the "Additional Include Directories" by adding both the directory containing the generated header file libMyAdd.h, in addition to the directory containing MATLAB's header files:

    $matlabroot\extern\include
    
  • Similarly under "Linker", set the "Additional Library Directories". That would be the same directory as before containing libMyAdd.lib, as well as in my case:

    $matlabroot\extern\lib\win32\microsoft
    

    Then go to "Linker > Input" and add the following inside "Additional Dependencies":

    libMyAdd.lib
    mclmcrrt.lib
    
  • Finally under "Debugging > Environment", you might want to extend the PATH environment variable to include the directory containing the generated libMyAdd.dll file. That way you can directly hit F5 to compile run the program directly from inside VS. This will be something like:

    PATH=%PATH%;C:\path\to\output\folder
    

If you do this kind of thing often, you could create a property sheet once, which could then be reused in other VC++ projects. See this answer for an example.

Trotter answered 16/6, 2013 at 1:7 Comment(1)
An important note: if you want to compile and use your generated DLL you MUST configure Matlab to use the Visual Studio C++ compiler through mex and mbuild setup, otherwise you got linking errors in visual studio, even if you configure it as explained in this answerNalda
L
1

I compiled C++ library in Matlab using one of the commands below, with Matlab configured to use MinGW.

mcc -W cpplib:fooLIb FooFunc.m
mcc -B cpplib:fooLIb FooFunc.m

Than I tried to use this library with Visual Studio project and got one unresolved external symbol. Solution was to configure Matlab to use Visual Studio compiler. To see default compiler run commands below (both are important). Click on the provided link to set default compiler.

mex -setup cpp
mbuild -setup cpp

It is worth noting that C library compiled with MinGW works fine even in Visual Studio C++ project.

Leitmotif answered 3/9 at 12:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.