Integrating C Code with LabVIEW on NI Linux Real-Time Targets

Updated Jun 15, 2021



  • LabVIEW

Operating System

  • LabVIEW Real-Time (NI Linux Real-Time)

Programming Language

  • C

This document discusses how to use the Call Library Function Node to call into a shared library from LabVIEW on a target running the NI Linux Real-Time distribution. It also explains how to interactively debug the shared library code when it is called from LabVIEW using the debug server running on the remote target.

NI recognizes that it is important to consider opportunities for code reuse whenever moving forward with a new project or platform. The Call Library Function Node is a LabVIEW VI which allows for code reuse that calls a DLL or shared library function directly inside your LabVIEW code. NI Linux Real-Time installs the GNU debug server on NI embedded hardware so that you can debug C and C++ shared libraries called by your LabVIEW Real-Time application.


1. Compiling your shared library

In order to call external code from within LabVIEW on the NI Linux Real-Time operating system, the code must be compiled into a shared object file, or .so file. This is the general equivalent to a .dll in the Windows environment.  NI provides C & C++ Development Tools for NI Linux Real-Time, Eclipse Edition 2017-2018 which includes the Eclipse IDE and GNU C cross-compilers for Linux. This setup can be used to perform the compilation.


The following set of instructions uses the Eclipse IDE to compile and debug the C shared library.

  1. To set up Eclipse with the appropriate GCC C cross-compiler for your embedded system follow the instructions in Getting Started with C/C++ Development Tools for NI Linux Real-Time, Eclipse Edition.
  2. Choose the “Shared Library” project type and use the “Cross GCC” Compiler.


Figure 1. Select Shared Library in the Eclipse New Project setup wizard


2. Programming in LabVIEW Real-Time

  1. Make sure the LabVIEW Real-Time Module is installed.
  2. To create a blank LabVIEW project, open LabVIEW and select File»Create Project…»Blank Project»Finish.
  3. Add a real-time device to the project by right-clicking on Project: <Project Name> and selecting New»Targets and Devices.

    Figure 2. Add a new embedded device to your LabVIEW project.
  4. If your embedded system is connected and running, select Existing target or device and find the device in the expandable list for your embedded system type (example: Real-Time CompactRIO). Otherwise, select New target or device and expand the appropriate list to select your embedded system type (example: cRIO-9068).
  5. To create a VI that will run on your embedded system, right-click on the embedded system in the project and select New»VI. For more detailed information about setting up a real-time project and general programming practices for real-time, check out this developer’s guide.
  6. Before the C shared library can be accessed from LabVIEW on the NI Linux Real-Time embedded system, the .so file will have to be present on the device. Place the file within the /usr/local/lib directory on the embedded system so that it will be automatically loaded into memory upon startup. You can use WebDAV to transfer files to your real-time embedded system. This can be done securely within the Eclipse environment as follows:
    1. Within Eclipse, select Window»Open Perspective»Other… and select Remote System Explorer.

      Figure 3. Setup the Remote System Explorer in Eclipse to access the file system on your embedded system.
    2. On the Remote Systems tab, select New»Connection and choose SSH Only.
    3. Type in the IP address of your embedded system for Host name and Connection name and click Finish.
      Figure 4. Establish an SSH connection to your embedded system using the IP address.
    4. Expand Sftp Files and a popup will appear to request a User ID and Password. By default, the user id will be admin and the password will be blank.
      Figure 5. The default User ID is 'admin' and the password is blank.
    5. Once you have logged in, expand the files under your embedded system to find /usr/local/lib. Now, expand the files under your local computer to find your .so file. Drag it from the host computer to /usr/local/lib to transfer it to the embedded system.
  7. Restart the embedded system by pressing the reset button on the device or clicking Restart in MAX to load a shared object file.
  8. Right-click on the block diagram to bring up the Functions palette and select the Call Library Function Node from Connectivity»Libraries & Executables. Double-click on the node to bring up the Call Library Function dialog box:
    Figure 6. Find the Call Library Function Node in the Functions Pallette to add it to your VI.
  9. Type the name of your library in “Library name or path” box with an asterisk as the file extension. Depending on what operating system the code is running on, LabVIEW will replace the asterisk with the appropriate extension. Note that if you are developing within the Windows environment, LabVIEW will be unable to populate the Function name drop down based on a .so file. You will need to manually type in the Function name that you want to call.
    Figure 7. Configure the Call Library Function Node with the name and path of the shared library, the function name and parameters.
    Optionally, you can build your code into a .dll file as well. This DLL will have no functionality on the real-time embedded system, but pointing to this file during development will allow the Function name dialog box to populate. Also, on  the development computer, the .dll file (along with a .h file) gives you the option to use the Import Shared Library Wizard to automatically create VI wrappers for your code as described in this document. However, you would have to go back into the wrappers and remove the dll extension from the file and replace with an asterisk as shown in the picture above.
  10. Configure the Parameters, Callbacks, and Error Checking tabs as you would on any operating system as described in this document. Note that configuring these options requires a solid understanding or documentation of the functions being called.
    Figure 8. An example LabVIEW Real-Time VI that passes two user-defined, double precision values to a shared library function called 'addDouble' and shows the 'Result' on the front panel.
  11. You can now press the run arrow at the top of the block diagram to deploy and run the code on your device. For a final application, we recommend that you build your code into an executable as described in this document.


3. Debugging

The GDB debug server on the cRIO-906x, cRIO-903x, and sbRIO-9651 allows developers to debug shared library code called by a LabVIEW VI. This can be done within the Eclipse environment or using the command line and an SSH Client. Both options will be discussed here.

For some debugging steps, GDB must have access to the .so files and other information from target directories. Therefore, before you start debugging, the /usr  and /usr/lib directory (or the directory contains your .so files) must be copied over to the host computer. See Step 6 under Programming in LabVIEW Real-Time above for information about how to transfer files between the host and the embedded system in Eclipse. For the rest of this document, the folder on the host you have copied these files into will be referred to as <RootFileSystemDir>.


Debugging within Eclipse

Refer to Getting Started with C/C++ Development Tools for NI Linux Real-Time, Eclipse Edition for basic information on using the Eclipse environment to communicate with your NI Linux Real-Time embedded system as well as information on general debugging within Eclipse.

  1. Ensure that you have configured your remote system in Eclipse so that it appears and is accessible from the Remote System Explorer perspective.
    Figure 9. Remote System Explorer in Eclipse, connected to a remote embedded system, specified by its IP address.
  2. Under the Project Explorer, right-click on your project and select Properties. In the left-hand menu, select C/C++ Build. Within the Builder Settings tab, change the Builder type  to Internal builder as shown below:
    Figure 10. To configure Eclipse Build Settings, right-click on your project in the Project Explorer and select Properties.
  3. Select Run»Debug Configurations to bring up the Debug Configurations dialog box and select your debug configuration under C/C++ Remote Application. If it is not there, double-click on C/C++ Remote Application to create one.
    Figure 11. Create and configure your Debug Configuration.
  4. Make the following changes on the Main tab:
    1. At the bottom of the menu, make sure that it reads Standard Remote Create Process Launcher. If not, click Select other… and select Standard Remote Create Process Launcher.
    2. Change Connection to point to your embedded system.
    3. Change the Remote Absolute File Path for C/C++ Application to the Linux-style path that points to your shared library (.so file) on your embedded system.
    4. Add the following command to Commands to execute before application:        
      gdbserver: NNNN –attach $(pidof lvrt)   (where NNNN is an available TCP port on the embedded system)

      Figure 12. Set the Connection, Project, C/C++ Application, Remote Absolute File Path and Commands to execute for the Debug Configuration.
  5. Switch over the Debugger tab and change the following settings in the Main tab:
    1. Browse to the correct path for the GDB debugger.
      • For ARM processors (cRIO-906x, sbRIO-9651), the path for the .exe is <Eclipse>\14.0\arm\sysroots\i686-nilrtsdk-mingw32\usr\bin\armv7a-vfp-neon-nilrt-linux-gnueabi\arm-nilrt-linux-gnueabi-gdb.exe
      • For x64 processors (cRIO-903x), the path for the .exe is <Eclipse>\14.0\x64\sysroots\i686-nilrtsdk-mingw32\usr\bin\x86_64-nilrt-linux\x86_64-nilrt-linux-gdb.exe
    2. Browse to the path of the .gdbinit file in your project. If it does not exist, create a text file within your project directory and save it as .gdbinit. The contents of the file should be:
      set breakpoint pending on
      set sysroot <RootFileSystemDir>

      Figure 13. The .gdbinit file contains GDB commands to automatically execute during GDB startup.
    3. Uncheck Stop on startup at: main
      Figure 14. Uncheck 'Stop on startup at: main' in the Debugger tab.
  6. Switch to the Gdbserver Settings tab and ensure that the Port number matches the number (NNNN) chosen in step 4.
    Figure 15. Verify the Gdbserver Settings.
  7. Click Apply and then Debug.
  8. You will get a warning asking if you want to open the Debug perspective. Click Yes.
  9. In the bottom, right-hand corner of Eclipse, press Display Selected Console and choose the option with the gdb.exe extension. Click Pin Console preserve this console view.
  10. Place breakpoints as desired in your source code.
  11. Now when LabVIEW calls the code containing the breakpoints, execution will be suspended and LabVIEW on the host will disconnect from the embedded system.
    Figure 16. LabVIEW will pop-up a message when a breakpoin is hit in the shared library.
  12. When execution is suspended, you should be able to type commands into the gdb console or debug using the buttons in the Eclipse environment (Step Over, set breakpoints, etc.). To discover what commands are available, type “help”.

Debugging using the Command Line and an SSH Client:

  1. Open the command line on the local host and navigate to the location of the GDB debugger on your computer.
    • For ARM processors (cRIO-906x, sbRIO-9651), the location is <Eclipse>\14.0\arm\sysroots\i686-nilrtsdk-mingw32\usr\bin\armv7a-vfp-neon-nilrt-linux-gnueabi
    • For x64 processors (cRIO-903x), the location is <Eclipse>\14.0\x64\sysroots\i686-nilrtsdk-mingw32\usr\bin\x86_64-nilrt-linux\
  2. Execute the GDB debugger by typing the name of your debugger.
    • For ARM processors (cRIO-906x, sbRIO-9651), the debugger name is arm-nilrt-linux-gnueabi-gdb.exe
    • For x64 processors (cRIO-903x), the debugger name is x86_64-nilrt-linux-gdb.exe
  3. Enter the following commands:
    Set breakpoint pending on
    File C:/path to the sharedObject from Eclipse Project/
    Set sysroot <RootFileSystemDir>
  4. Add breakpoints to your code by typing “b” and then the line number where you would like the breakpoint. (If you don’t add breakpoints, the GDB debugger will not have a reason to suspend execution so that you can debug).
    Figure 17. Set breakpoints in the code via the command line.
  5. Open an SSH Client (such as PuTTY) and type in the following shell command: gdbserver:NNNN –attach ‘pidof lvrt’ (where NNNN is an available TCP port on the embedded system)
  6. Move back to the command line window and type the following command: Target remote <Target Name>:NNNN (Make sure that NNNN matches the TCP port defined in step 5)
    Figure 18. Connect to the GDB server to start debugging.
  7. Run the code that calls the shared library. Execution will suspend, LabVIEW on the host will disconnect from the embedded system, and you should have control of the debugger. Once you have control, you can type commands into the console to set breakpoints, step through the code, etc. Type help to learn more about the debug options.
  8. When you are finished debugging, make sure the the GDB debugger is not in continue mode and type detach. The gdbserver process running on the embedded system will terminate and allow the lvrt process on the embedded system to continue running.