0

I am writing a very minimal C/C++ Qt-based application for Windows (only Windows -- not cross platform at all) that uses a VISA library (visa64.dll) to talk to some external hardware. That library, in turn, uses some other libraries: Screenshot from Dependency Walker/depends.exe

(screenshot from Dependency Walker a.k.a. depends.exe)

Originally I wrote it in Visual Studio and it worked great. Then I ported it to Qt Creator (using Qt5, w/ MSVC 2015 Visual C++ toolchain) and I got runtime errors. It knows where to find the external header files, so I think my INCLUDEPATH is right, and it builds fine so I think the LIBS variables in my .pro file are right, which is to say it can find the .lib files it needs. However, the first API I call from this external library (viOpenDefaultRM) returns the following error: VI_ERROR_LIBRARY_NFOUND. This happens whether I make a debug build or a release build, and whether or not I am running it with a debugger. As long as I run the program from within Qt Creator, it gets runtime errors.

Here is my .pro file:

TEMPLATE = app
CONFIG += console c++11
CONFIG -= app_bundle
CONFIG -= qt

SOURCES += main.cpp

INCLUDEPATH += $$PWD/'../../../../Program Files/IVI Foundation/VISA/Win64/Include'

LIBS += -L$$PWD/'../../../../Program Files/IVI Foundation/VISA/Win64/Lib_x64/msc/' -lvisa64

INCLUDEPATH += $$PWD/'../../../../Program Files/IVI Foundation/VISA/Win64/Include'
DEPENDPATH += $$PWD/'../../../../Program Files/IVI Foundation/VISA/Win64/Include'

The paths that end with /Include have header (.h) files (it's a C library), and the path that ends with /msc has a .lib file. The .lib files are not static libraries, they are the interface files for some corresponding DLLs. Those DLL files are in C:\System32. There are also 32-bit versions in C:\SysWOW64. They may also exist elsewhere but if they do I am not aware of it.

Now, if I run it from cmd.exe it works fine. That is, if I open a cmd.exe terminal window and navigate to my Qt project's build directory (c:\blah\blah\blah\obj\debug\) and run the executable from cmd.exe, I get no runtime errors. It can connect to the external hardware, talk to it, all good things are happening, much rejoicing.

I've done a decent amount of searching and researching about this problem, and I am somewhat cursed by the fact that most people have the opposite problem, which means that problem (the opposite one of mine) is what turns up in Google/DuckDuckGo/StackOverflow/forum.qt.io/doc.qt.io searches. That problem usually has to do with missing/misplaced Qt libraries. Here is an example. The answer to this question usually ends up with a link to a page on how to deploy Qt projects for Windows, e.g. this article.

Also I've read this article from Qt on how to add libraries to your project, and it didn't help me out, but I could be missing something and/or doing it wrong.

This might be something really dumb I'm missing and frankly I hope it is. Thanks*10^6.

23r0c001
  • 151
  • 1
  • 6
  • Are you trying to link statically? I suppose yes as this is to be a .lib. Have you tried specifying the extension of the library (e.g. visa64.lib)? And what is generating this VI_ERROR_LIBRARY_NFOUND error exactly? Because depending on how you are linking, you should see either a compile-time error stating that the library is missing, file not found or undefined symbol at runtime. Btw you have added twice your INCLUDEPATH to VISA, but that's not going to matter. – Adrien Leravat Aug 12 '20 at 02:57
  • I am trying to link dynamically, though I may be biffing it. But the .lib file is just all the symbols from the corresponding DLL in system32. I think the .lib file is like having a bunch of LoadLibraryA() calls for in this case visa64.dll, but the compiled code of the library is in visa64.dll. If I understand correctly. So I believe the .lib file has to be there for the project to compile, but at runtime the DLL is where the actual compiled code for the APIs is. VI_ERROR_LIBRARY_NFOUND means generally it can't find or load VISA or a library VISA needs. – 23r0c001 Aug 12 '20 at 03:05
  • Right, don't do Windows dev that often anymore! So what I means by "what is generating the error VI_..." is that I'm surprised this shows up like that, except if something looks for it and links to it at runtime plugin-like. Which would mean that you don't even need the `-lvisa64` in the first place. Could it be instead that `viopenDefaultRM()` fails because the right plugins/files are not in the path where its looking? Here you are trying to register it as a depend library in the linker with `-l` but to me it looks like the application starts fine, and then it tries to load `visa64` and fails – Adrien Leravat Aug 12 '20 at 03:17
  • 1
    ... And I would assume viopenDefaultRM() is looking for it in a specific location, and just not finding it there – Adrien Leravat Aug 12 '20 at 03:17
  • I think you are right that ```viOpenDefaultRM()``` fails b/c it can't find the right plugins/files, maybe DLLs, where it is looking. I think. I think the reason it can compile even with that call to ```viOpenDefaultRM()``` in my code is because of the ```-lvisa64``` flag which refers to visa64.lib. visa64.lib I think gives it the names of the APIs from a DLL (visa64.dll) that is elsewhere. So I'm guessing it either doesn't know where to find visa64.dll for some reason, or it's looking in the wrong place with a different version of visa64.dll that I'm unaware of first. – 23r0c001 Aug 12 '20 at 03:33
  • I keep saying "I think" b/c I only just got into this Windows DLL stuff this in depth more or less when I ran into this problem. But from what I've been reading of late, it seems like a .lib file *can* be a static lib, *or* it can be a linking file or something. Like an intermediary for the actual DLL, so you don't have to manually load all the symbols/APIs from the DLL file. Instead you link to the .lib file and that links @ compile time. Then at run time your program loads APIs from the DLL based on instructions in the .lib file. – 23r0c001 Aug 12 '20 at 03:37
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/219651/discussion-between-adrien-leravat-and-23r0c001). – Adrien Leravat Aug 12 '20 at 04:33

1 Answers1

0

TL;DR: The kit I was using to compile in Qt Creator had a different PATH set than my system PATH. To fix this, I did echo %PATH in cmd.exe and copied all the stuff that had to do with the drivers I'm trying to use into the PATH for the kit I'm using in Qt Creator. More details below.

I got this to work this morning. As suggested by @adrien-lerevat, when run from within Qt Creator, my executable couldn't find some DLLs it needed. The long and short of it is that I was defining a PATH in my kit (a "kit" in Qt is basically a compiler, a debugger, and some environment variables) that was different from, and not a superset of, my normal system path. I had inherited this kit for other purposes, you see, from other projects, and I didn't realize a PATH could be set in it, or that I was setting one. So to find the PATH I was setting for Qt Creator, I went to the Tools dropdown and selected Options..., then Build & Run, then Kits. Then click on the kit you are using to edit it. As such: enter image description here

enter image description here

That should give you a list of stuff, one thing of which is called Environment. That should have a Change... button you can press: enter image description here

which should open a new window with all your environment stuff: enter image description here

(screenshot is from after I fixed the problem)

This is where I found PATH, as well as some library and include paths that were worth knowing about. So now that I knew what my Qt Creator PATH was, I opened cmd.exe and typed the command echo %PATH% to find out what my system PATH was. I grabbed everything that had to do with these VISA drivers I'm using (basically anything with VISA and/or IVI Foundation in the path) and pasted them into my PATH in Qt Creator. This was the list of stuff I pasted in there to make it work:

C:\WINDOWS\system32;C:\Program Files\IVI Foundation\VISA\Win64\ktvisa;C:\Program Files\IVI Foundation\VISA\Win64\bin;C:\Program Files (x86)\IVI Foundation\VISA\WinNT\bin;C:\Program Files (x86)\IVI Foundation\VISA\WinNT\Bin\;C:\Program Files\IVI Foundation\VISA\Win64\Bin\;C:\Program Files (x86)\IVI Foundation\VISA\winnt\agvisa;C:\Program Files\Keysight\IO Libraries Suite\bin;C:\Program Files (x86)\Keysight\IO Libraries Suite\bin;C:\Program Files (x86)\IVI Foundation\VISA\WinNT\ktvisa;C:\Program Files (x86)\IVI Foundation\IVI\bin;C:\Program Files\IVI Foundation\IVI\bin;

I added c:\system32 because I know that's where visa64.dll is, which is at least one top-level DLL I know I need. Oddly enough, though, when I added just c:\system32 without all the VISA and IVI Foundation stuff, that didn't work. So, I don't know if everything I added to my Qt Creator path was necessary, as I've just come upon this solution, but once I pare down the list to find out what all I actually needed I will add that information here. Just in case anyone else ever comes across this problem or is curious. And for the sake of completeness I suppose. Okay thanks everyone ;)

23r0c001
  • 151
  • 1
  • 6