Jump to content

Help? - lvlib's, dynamic calls, plugin architecture, namespacing, executable


Recommended Posts

I'm coming late to the party on the lvlib project library and am struggling a bit to figure out whether they can be the magic bullet to solve a particular problem of mine.

What I've done so far: I've got a plugin-like architecture which implements a small homebrew scripting language. Each implemented instruction is placed on disk according to a convention of "<base instruction path>\Instruction\Instruction.vi" and all supporting subvi's for "Instruction.vi" are found in or under it's folder. At run time, these vi's are found and enumerated as the set of available scripting instructions. Later, a text script will be parsed and its tokens are compared against these instructions to determine what code to call dynamically. This is how I handle all of what I call the "built-in" instruction set.

However, I then took a shortcut to ease version control and made sure that all these built-in instructions are contained inside the built executable. I still call them dynamically, but they reside inside the exe.

In addition to these built-in instructions, dynamic plugin instructions can also be defined and placed under a special <plugins> folder. Here one can place newly invented scripting instructions that are found and run by the executable without recompiling. All this stuff works such as it is.

What I'd like: I've always kinda wished I could *also* use the <plugins> folder as a way to REDEFINE an existing built-in instruction as a means for quick bug-fixing or feature-extension. However, the namespacing issue has prevented this since any attempt to load a plugin at "<plugins>\Instruction\Instruction.vi" will in fact load up the already-loaded "<base instruction path>\Instruction\Instruction.vi" since they ultimately both resolve as a simple "Instruction.vi"

LVLIB confusion: I've finally started tinkering with the lvlib project library in hopes of making such a scheme possible. The idea would be that all built-in instructions would be part of an lvlib and would have namespacing like "InstrLib:Instruction.vi" Then I could still load in a plugin that's namespaced as a simple "Instruction.vi" without conflict. (I can handle the parsing needed to determine that the newly loaded plugin should override the statically linked instruction.)

I've searched this site and ni's and have found some ways to use vi server and library references to help enumerate the library's contents. But when I look at the name properties of the "Callees[]", I find that they are not namespaced with the "InstrLib:" qualifier. I'm also beginning to question how an approach based on lvlibs would translate into a built executable. It looks like vi's from the lvlib and the lvlib itself would not be inside the executable but would be distributed as source files in a folder under the executable.

In short, my brief overview idea of the lvlib made me expect it to be part of a neat and straightforward solution. Right now, it appears that it's gonna be fairly convoluted. I'm starting to think I'm better off adopting a simple convention like, "All plugins will have filenames that start with 'PLUGIN_', and then I just text-parse my way through the problem.

Am I missing something? Is there a simpler way to build an executable which contains vi's that are namespaced in a lvlib and will be called dynamically?

-Kevin P

Link to comment

LVLIB confusion: I've finally started tinkering with the lvlib project library in hopes of making such a scheme possible. The idea would be that all built-in instructions would be part of an lvlib and would have namespacing like "InstrLib:Instruction.vi" Then I could still load in a plugin that's namespaced as a simple "Instruction.vi" without conflict. (I can handle the parsing needed to determine that the newly loaded plugin should override the statically linked instruction.)

In short, my brief overview idea of the lvlib made me expect it to be part of a neat and straightforward solution. Right now, it appears that it's gonna be fairly convoluted. I'm starting to think I'm better off adopting a simple convention like, "All plugins will have filenames that start with 'PLUGIN_', and then I just text-parse my way through the problem.

Am I missing something? Is there a simpler way to build an executable which contains vi's that are namespaced in a lvlib and will be called dynamically?

I think you have reached a practical limitation of the architecture you have chosen. Can you hack together something that will mostly work? Probably. If this project will be around for a while I strongly suggest restructuring it into something that will be more maintainable.

The easiest solution is to pull the core instruction set out of the executable and load them from a MyApp\Core subdirectory. This makes it much easier to deploy bug fixes or upgrades without rebuilding the whole application AND you don't have to write and maintain all the code to decide whether to load the default library or the library in the plugins folder.

Another option is to switch over to classes. You are proposing writing an instruction vi that will load various back-end processing vis depending on the run-time conditions. You want the interface to remain the same (so client scripts don't break) but you need to be able to change the implementation. Classes excel at this.

Link to comment

Another option is to switch over to classes. You are proposing writing an instruction vi that will load various back-end processing vis depending on the run-time conditions. You want the interface to remain the same (so client scripts don't break) but you need to be able to change the implementation. Classes excel at this.

I concur.

I have had success with LVClass Plugins e.g. supporting different file types after deployment.

Check out Tomi blog for a simple demo:

http://expressionflow.com/2008/06/02/extending-labview-built-applications-with-lvoop-plugins/

Link to comment

Thanks for the replies guys. It sounds like I may in fact need to distribute both the .lvlib (or .lvclass) file which I understand to be just an XML description and also distribute all the source files for the code that is part of the library (or class). To hide implementation details would then require me to password-protect the diagrams, right?

The easiest solution is to pull the core instruction set out of the executable and load them from a MyApp\Core subdirectory. This makes it much easier to deploy bug fixes or upgrades without rebuilding the whole application AND you don't have to write and maintain all the code to decide whether to load the default library or the library in the plugins folder.

I had been resisting this approach because of config management and version control considerations. It's much easier to verify the version of a single monolithic executable than to verify a whole folder hierarchy of code. But it sounds like it may be time to bite the bullet and use the approach you describe.

Another option is to switch over to classes. You are proposing writing an instruction vi that will load various back-end processing vis depending on the run-time conditions. You want the interface to remain the same (so client scripts don't break) but you need to be able to change the implementation. Classes excel at this.

I haven't played with LVOOP yet and have only dabbled a little bit many years ago in text language world. Rightly or wrongly I have this idea in my head that OOP is mostly useful when there's a need to create multiple object instances with unique state variables. In my current app I won't be doing that. Executing one of my homebrew script instructions simply uses VI server and call-by-reference to call a stateless *function*. To me, my app doesn't feel like the kind of thing that would obviously benefit from classes, at least not in the sense of overall architecture.

Given that, is there still an advantage to making this a class rather than an lvlib project library? Or if I first do it as a library where I won't be distracted or thrown off by the OOP terminology, should it be fairly straightforward to convert the library to a class in the future?

-Kevin P

Edited by Kevin P
Link to comment

Thanks for the replies guys. It sounds like I may in fact need to distribute both the .lvlib (or .lvclass) file which I understand to be just an XML description and also distribute all the source files for the code that is part of the library (or class).

Yep, you always want to deploy the .lvlib/.lvclass files with all the vis that are part of the library together. I typically keep all the vis associated with a library (and only vis associated with a library) in a single directory along with .lvlib/.lvclass file.

To hide implementation details would then require me to password-protect the diagrams, right?

Depends on exactly what you mean by "hiding implementation details." Hiding the block diagrams of each vi requires you to apply passwords to each vi. Not letting users see or use privately-scoped member vis requires password protecting the library file. If you are concerned about users stealing your instruction source code you might consider compiling your core instruction set into a dll and calling that from your main application's source code. I've never built a dll from Labview code but you should be able to strip the block diagrams out of all the vis making it impossible for users to steal your code.

I had been resisting this approach because of config management and version control considerations. It's much easier to verify the version of a single monolithic executable than to verify a whole folder hierarchy of code.

The path you were following would not have eliminated that requirement. To discover which instruction versions are being used you'd need to search the plug-in folder to find out what is on the user's system. You'll still have an executable for your scripting engine. The only difference is that you've pulled the core instructions out of the executable to make it easier to deploy fixes.

Rightly or wrongly I have this idea in my head that OOP is mostly useful when there's a need to create multiple object instances with unique state variables.

Well, that's one place where it's useful, but it's not the only place. Objects are also useful when you want to change the behavior of something based on run-time considerations. For example, I have a class for a spectrum analyzer that I use to issue commands to the instrument in my applications. However, I want to be able to test my applications when the instrument is not connected to the computer. To do this I simply create a child of the original spectrum analyzer class and override the Read and Write vis (which are called in each of the instrument command methods) with NoOps and replace the original spectrum analyzer BD constant with the child class constant. In two minutes I've implemented a dummy object that has a different behavior and allows me to test my system.

To me, my app doesn't feel like the kind of thing that would obviously benefit from classes, at least not in the sense of overall architecture.

I agree with you as far as the core instruction library is concerned. It doesn't sound like you're wanting to execute SqRt function A if the number is positive and SqRt function B is the number is negative but intead completely replacing SqRt function A with SqRt function B. For that you just need a way to replace the vi on disk, which is why I suggested pulling the core library out of the executable.

Given that, is there still an advantage to making this a class rather than an lvlib project library?

If I were doing it from scratch I'd probably use an OOP based solution that provides each plug-in function library with the ability to describe its capabilities to the main app. Since you've already got working code that extracts the tokens and looks up the commands in the plug-in folder I don't see any reason to change it yet. If it ain't broke, don't fix it.

Or if I first do it as a library where I won't be distracted or thrown off by the OOP terminology, should it be fairly straightforward to convert the library to a class in the future?

Can't say. It depends on your how well you've modularized and abstracted your application.

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.