Community Documents

cancel
Showing results for 
Search instead for 
Did you mean: 

Debugging Symptoms - Build Namespacing - Missing VIs in Compiled Executable or PPL Code Appears to not Run

Debugging Symptoms Introduction

Welcome to my first posting as a Technical Support Engineer at NI! I'll be starting off a series of documents showcasing symptoms you might run into in the world of developing LabVIEW applications, the situation(s) that cause them, and how to fix them. These writeups will include a bit of a narrative describing some techniques the developer may have heard about that could lead them down the path they're stuck on and provide context to how they arrived at their destination. Eventually I'll be recording demo videos walking through the demos but we'll see how long it takes me to get around to those; I have a habit of taking on too many projects at once!

 

Prerequisites

The code for the demos are made in LabVIEW 2020.

 

To ensure PPLs are built in the correct order MGI's Solution Explorer (download page opens in a new tab) is used. This tool is now included in LabVIEW starting with 2020 so no separate download is needed! The Solution Explorer (LVSLN) is a tool that allows coordinating build specs contained in several projects, as well as running specific VIs as build actions, and differentiating between debug builds and release builds. It should be considered a mandatory tool when working with PPLs! The MGI Solution Explorer download page lists it as an evaluation but it's the full, free tool.

 

You can find the LVSLN tool in the... tools menu of the project explorer:

lvsln-menu.png

 

Symptom Overview

There are two situations we'll be discussing that are caused by the same mechanism of LabVIEW builds:

  • Loading source VIs in an executable and they can't find common / vi.lib VIs
  • Building PPLs and it appears as if code using shared VIs (Functional Globals) never runs

 

Loading source VIs in an executable and they can't find common / vi.lib VIs

SourceVIMain.png

 

The developer has created an application that utilizes the Open VI Ref function so they can update their deployed application by replacing a handful of VIs on disk and don't have to recompile their whole application. When they run their application directly in LabVIEW everything works well and the VIs opened by path are able to successfully load and run. However once they compile the application and run the executable they start seeing the search dialog show up for common VIs, such as the Simple Error Handler, not being found. This initially manifests as error 1003 when trying to open and launch the processing source VI from disk:

SourceVIError.png

 

 

This can be extremely frustrating as opening the VI shows a solid run arrow without any errors reported. After spending some time crawling the internet for answers they run across some documents suggesting they should add the Simple Error Handler VI to the "Always included" list of their application build spec. The problem persists which is even more confusing due to the fact that the Simple Error Handler is used elsewhere in their application and works just fine. In fact, the Simple Error Handler in the main app is what's producing the error window shown above; it's definitely working!

 

Now we'll discuss another symptom related to VI namespacing issues and will help with explaining the situation later on.

 

Building PPLs and it appears as if code using shared VIs (Functional Globals) never runs

A developer is starting down the path of using PPLs in their applications as they are interested in reducing compile times when their team only updates individual components of the application. Eventually they'll be moving to a plugin architecture that can load the functionality they need at run-time in the application. Their application consists of a couple of different modules implemented as PPLs, the executable that uses those PPLs, and some common code that handles the abstraction but isn't a PPL. The abstraction code has a Functional Global that maintains a list of the dynamic features that have been registered so that the application knows what VIs it can programmatically open references to and run. The executable has a few features built in that use this mechanism and the two libraries in this application also use this mechanism.


Here's the block diagram of the main VI that performs all the feature registration and displays a dialog confirm which features have been registered.

main.png

 

 

Both of the plugins use the same registration VIs as the top level application, an inspection confirmed there was no cross-linking.

plugina.png

 

 


Here's the result of running the app. No Plugin A and no Plugin B showing up!

run.png

 

 

 

 

As shown above, once they build the full application, the two plugin modules never get listed in the dialog box! Suddenly there's a lot of confusion and insinuations of the run-time engine skipping VIs or the app builder somehow not including the PPLs. Everything appears to run correctly, no errors are generated. Then they also test the functionality in LabVIEW instead of the built executable and they still see the same thing! They step through the code after running a handful of times and confirm no errors and all VIs do in fact run. Things get weird when they step into the registration FG though:

reg-a.png

 


The FG has different values in it than when it's called by the main application! Plugin B's calls to the registration FG show the same thing: a list of Plugin B. Surely PPLs are just broken and now they'll have to redesign their whole architecture! However if you look at the title bar of the block diagram window above you'll get a hint as to what has happened.

 

Explanation

When the app builder generates compiled outputs (EXEs and PPLs) it makes sure that the code will always be able to run. The Run-Time Engine (RTE) doesn't know about vi.lib, instr.lib, user.lib, or even your source project. This means that the app builder has to build copies of source VIs it knows about into the PPL or EXE. Looking closely at the last screenshot you'll see that the Plugin A PPL (plugin-a.lvlibp) has it's own version of the Registration FG.vi! Step through Plugin B's code and you'll see it has a "plugin-b.lvlibp:Registration FG.vi" title similar to Plugin A's. The Registration FG used by the main application has just "Registration FG.vi" in its titlebar.

 

What's happening here is Namespacing and if you use classes or project libraries even without compiling them to PPLs you've seen namespacing. Whenever a VI is moved into a class or a library, the container becomes part of the VI's name. This can also be seen when using context help on a subVI:

 

lib-class.pngThis screenshot of the context help window also shows that namespacing can have multiple levels such as a class inside a library or libraries inside of libraries. This namespacing is what allows VIs with the same file name to exist in different libraries and classes in the same project. When looking at the string value of a VI name, such as from the VI Name property node, the clear indicator that it is namespaced is that it contains a colon ':' in it to separate the namespace(s) and the VI filename.

 

Something that might surprise people working on a plugin architecture, with or without PPLs) is that the same thing happens for VIs that get built into an executable! I know this confounded me in the past when I've made a dynamically loaded source plugin (VIs on disk not compiled into a PPL) complaining about not being able to find the Simple Error Handler.vi even after I added it to the exe build spec to always be included. The VI name of the error handler that was built into the exe effectively becomes "MyApp.exe:Simple Error Handler.vi" so my source plugin's code looking for "Simple Error Handler.vi" couldn't find a match in memory. This will also be the same situation for the mathematics VIs, signal processing libraries, statistics, etc.

 

The Fix(es)

Solving namespacing issues can take two routes: using PPLs or not using PPLs. Okay, let's be more specific... In general, if you want to be able to dynamically load code to run with the run-time engine (this can include running code in TestStand with the run-time adapter!) you should be building your functionality into a PPL. If you do not need the dynamic loading capability you should probably move away from using PPLs.

 

In the first example, building the processing plugin into a PPL and loading the VI from the PPL in the main application. Running this build step to generate the PPL means that the Process.vi file will always have access to the error handler VIs and the Linear Fit VI since they get built into the PPL. The other nice thing about this is that only two changes need to be made to implement this!

  1. Adding the Process.vi to a project library that gets built into a PPL:
    SourceVIPPL.png

     

  2. Modify the path for the VI to open to include the PPL file as if it were a sub folder:

SourceVIFix.png

 

 

Nothing else in the main application had to change. All the same loading and execution code was able to be used as-is. Now when the functionality needs to be updated the PPL can be rebuilt to the proper location and the executable can run the updated code without being recompiled itself. For a bonus: if the plugin PPL doesn't use classes and references are managed properly you can even update and run the new functionality without restarting the executable! In fact, the fixed example manages this and you can give it a shot yourself: run the executable once and click the process button to see the result then edit the Process.vi source to perform a different function and build the PPL all while the executable continues to run. Of course there are a handful of caveats to this approach that are outside the scope of this document.

 

Now let's move on to the plugin registration example.


As one possible solution, since this example isn't very big and doesn't use dynamic loading, you could stop using PPLs and revert the code used by the application back to the calling code from the source libraries instead of the built PPLs. This way the app builder will be able to "fix" the VI calls to use the version that's built into the executable. The problem with using the PPLs is that they're already built and can't be changed so they can't be told to look for the name that would be available in the EXE.

 

The second solution would be the route to follow if you know why you're using PPLs and need to stick with them. This involves putting Registration FG.vi & Registration FG Action.ctl into their own library and building that to a PPL. Since PPLs don't get rebuilt into dependent PPLs and executables, the dependent code stays referencing the PPL directly and as long as the run-time can find and load the PPL it will run successfully. The general rule here is that any dependencies of PPLs should also be built into PPLs as well.

Contributors