LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

How to run a shared object file built from C++ object-oriented source code on Call Library Function Node?

I am trying to run a shared object (so) file on sbRIO 9627 which has a 32-bit Linux environment. The file was built from C code but the C code uses C++ open-source code by using an interface. Actually, the open-source code is the COIN IPOPT project which was written in C++:

 

(https://projects.coin-or.org/Ipopt/browser/stable/3.10/Ipopt/doc/documentation.pdf?format=raw). 

 

I am testing by running the example hs071_c.c in the COIN project. Here is the link for c code:

https://github.com/pemryan/Ipopt/tree/master/Ipopt/examples/hs071_c

and here is its C interface:

https://github.com/coin-or/Ipopt/blob/master/src/Interfaces/IpStdCInterface.cpp

 

Here was what I did for the test:

1. I set up Eclipse 2017 32 bit:

     a. Write an additional header file named hs071_c.h and made some changes.

     b. Include necessary paths.

2. The Eclipse generated a shared library without any errors.

 

However, when I deployed the so file to the NI sbRIO controller, I had the following message:

 

Undefined symbol: AddIpoptNumOption.

 

I read the following thread but it is not clear to me:

https://forums.ni.com/t5/LabVIEW/Calling-a-C-object-in-a-DLL-from-LabVIEW/td-p/1054694

 

My question is: Is there any way to run a so file on LabVIEW, 32-bit arm Linux. The so file is compiled from C code but the C code uses C++ object-oriented code? 

 

I appreciate any help.

-Peter

 

0 Kudos
Message 1 of 25
(3,832 Views)

The Call Library Node only can interface to global exported functions, not C++ objects.

 

One of the reasons is that the ABI for C++ is compiler specific, and LabVIEW could never start to guess which compiler was used for a specific external library. The other and just as important fact is that a Call Library Node with that feature would require a configuration interface where the current options look peanuts in comparison. Considering that most people already struggle with the (much more simple) configuration it now has, there is not much merit in spending the (not very small) time and energy for such a feature.

 

Interfacing C++ code always means that you will need to write a wrapper shared library that translates the object methods into global exported functions.

 

Over on the LabVIEW WIKI you can find an example of how you would have to create such a wrapper in C. All the exported functions need to be declared as extern "C" if you try to compile the wrapper in C++ mode. The example uses some Windows specific includes and defines but the principle is exactly the same for Linux, except that you need to remove those Windowismes and adjust for your Unix environment.

 

It would appear that your IpStdCInterface.cpp/ IpStdCInterface.h files define a C interface to the library. Are you sure this file is really added to the shared library that you did compile? You can do an objdump -TC <file name> on the command line of your sbRIO device. readelf -Ws <file name> gives you a similar list of exports. nm -gD <file name> is yet another possible option.

If the symbols don't show up in this list, they simply aren't present at all in the library and you need to check your linker stage to properly include the according object file for your c/cpp source file.

If the symbols appear in the output of this command, you'll have to dig deeper into the attributes of those symbols. Not all symbols are effectively exported to be accessible through the dlopen() and dlsym() calls that LabVIEW uses when you try to access a shared library in the Call Library Node. That can depend on compilation settings which can make that symbols are by default hidden, unless a specific attribute is set in the function declaration to change that. See https://gcc.gnu.org/wiki/Visibility 

Rolf Kalbermatter
My Blog
Message 2 of 25
(3,781 Views)

Hi Rolk,

 

Thank you for your reply. I did include IpStdCInterface.cpp/ IpStdCInterface.h during the compilation. In IpStdCInterface.h, extern "C" is used. As your comments, I run objdump -TC. And it gave me the following result: 

Peter_HP_0-1588294239065.png

 

As you can see, there are some symbols marked as *UND*. For example, on the line 4 in the above image, it seems that class object still remains (Ipopt::IpoptApplication::). 

 

Do you have any other comments?

I appreciate your help.

-P

 

 

 

0 Kudos
Message 3 of 25
(3,755 Views)

@Peter_HP wrote:

As you can see, there are some symbols marked as *UND*. For example, on the line 4 in the above image, it seems that class object still remains (Ipopt::IpoptApplication::). 


*UND* means the symbol is referenced form the dll, but not defined.

 

It doesn't have a value (00000000 isn't valid).

 

It seems to me the dll needs work...

0 Kudos
Message 4 of 25
(3,735 Views)

Almost all the symbols in that table you show come from other shared libraries such as glibc, glibcxx and similar. They will be resolved by the elf loader when the shared library is loaded and the according pointer references will be updated to be non-zero and point to those external library entry points.

 

Even the actual C++ symbols for the library seem not present in the shared lib. So did you just create a shared library from the IpStdCInterface.cpp file only? Do the according symbols like CreateIpoptProblem(), FreeIpoptProblem() even appear in that list?

 

Depending on if you want to do a custom build of this library or leave the original library as is I would think you need to either include all the files including the IpStdCInterface.cpp into the project, or create a separate project just for a wrapper shared library that only includes IpStdCInterface.cpp and possible support files.

In the second case you will have to make sure that both shared libraries are installed onto the target.

Rolf Kalbermatter
My Blog
Message 5 of 25
(3,718 Views)

Hi Rolf,

Thank you for your reply.

 

My purpose is to create a shared library to implement main() in hs071_c.c. I included IpStdCInterface.cpp. The below files are set up  for compiling:

                hs071_c.c (link: https://github.com/coin-or/Ipopt/blob/master/examples/hs071_c/hs071_c.c)

                hs071_c.h (I created and just declaring functions in hs071_c.c)

                IpStdCInterface.cpp (link: https://github.com/coin-or/Ipopt/blob/master/src/Interfaces/IpStdCInterface.cpp)

                IpStdCInterface.h (link: https://github.com/coin-or/Ipopt/blob/master/src/Interfaces/IpStdCInterface.h)

Other files are added as Includes. I am using C/C++ 32-bit Eclipse provided by NI.

yes, those symbols (CreateIpoptProblem(), FreeIpoptProblem()) appear on the list.

 

Do you think the setup is correct as I just wanted to run the main() in hs071_c.c (again the link: https://github.com/coin-or/Ipopt/blob/master/examples/hs071_c/hs071_c.c)?

Bests,

-P

                

0 Kudos
Message 6 of 25
(3,707 Views)

No, no, no!

 

The hs071_c.c should never be part of a shared library. That is the main function for an executable and just doesn't make sense. You want to either compile the original shared library and make sure the IpStdCInterface.cpp is added too to the build, or create a separate shared library project. I'm sorry to say that you will for sure need to learn quite a bit more about C compiling and shared libraries before you can hope to make this work beyond a lucky shot that just somehow works by accident and will fall apart as soon as you blink with your eye.

The Call Library Node is the interface to C functions. Without a good understanding of C and its programming, trying to use that interface is just going to get you into trouble. You will basically want to replicate the functionality in the hs071_c.c file all in LabVIEW by calling the functions in IpStdCInterface.cpp through the Call Library Node. Nothing more and nothing less!

Rolf Kalbermatter
My Blog
Message 7 of 25
(3,702 Views)

Thank you for the prompt reply. The comment is constructive indeed.

 

It should be good if you can give me some more comments on the approaches as I still want to try to solve my problems. It is somewhat off the topic but I appreciate your comments.

    

     Approach 1: I am a bit familiar with MATLAB. I used MATLAB script and solved my problems. MATLAB uses a MEX file created from the open-source (https://www.mathworks.com/matlabcentral/fileexchange/53040-ebertolazzi-mexipopt). But when it came to the phase of NI sbRIO deployment, it seems 2017 MathScript Node for sbRIO 32-Linux does not have facilities to read MEX or SO files; lib_call and similar are not supported for the target. 

Do you think it is possible to create an interface with MATLAB to use IPOPT and deploy in a 32-bit Linux Arm NI RIO? If it is, could you please tell me a direction or how to implement it?

 

    Approach 2: I carefully read your comments in the last reply. However, replicating functionalities of IpStdCInterface.cpp in LabVIEW is not an easy task as my problem is a bit complex. Do you think it is possible to create some C or C++ functions to implement functions in IpStdCInterface.cpp, and then it in Call Library Node? If it is, could you please tell me a direction or how to implement it?

 

I appreciate your time!

Bests,

-P

 

 

0 Kudos
Message 8 of 25
(3,681 Views)

I don't know Matlab on that level. The Mathscript node supports basic Matlab functions but it is not Matlab for obvious reason. As long as you want to use mathematical functions you can get quite far but Mathscript does not implement a full Matlab environment. As such the approach to include your library in a mex script is only going to multiply the number of problems you will have to deal with. Simply not useful.

 

You do not replicate the IpStdCInterface functions in LabVIEW. You create VIs to call them! You replicate the functionality of the hs071_c.c file in LabVIEW or something else, whatever is needed to solve your problem. hs071_c.c is simply an example that shows you how to use your library from a C program through the IpStdCInterface functions. Since a Call Library Node can only call standard C functions, it's the closest of a sample you can get about what you will need to do in LabVIEW. You will need to fully understand what is done in hs071_c.c to have any hope to get this working in LabVIEW and you will need to be able to create a shared library that contains the functions of IpStdCInterface.

 

You do not need to write extra code to implement the functions in IpStdCInterface as the IpStdCInterface already implements these functions! It is already that code! You simply want to create a shared library that exports the functions of IpStdCInterface and call those functions through Call Library Nodes.

Rolf Kalbermatter
My Blog
Message 9 of 25
(3,660 Views)

I am sorry for the confusion that I used the file names incorrectly. Instead of hs071_c.c, I wrote IpStdCInterface. What I meant was functionalities in hs071_c.c.

 

Do you think it is possible to write a function in C or C++ to implement the functionalities of hs071_c.c and I can call that function in LabVIEW? Something like writing an extra function for IpStdCInterface. That function will become a part of the shared library created from IpStdCInterface?

 

I appreciate your time!

Bests.

-P

0 Kudos
Message 10 of 25
(3,649 Views)