‎03-23-2010 09:07 PM
I have seen some posts on this, but none of them take it all the way from C code to configuring the shared library node...
My code is heavily based on this:
http://forums.ni.com/ni/board/message?board.id=170&thread.id=171056
Here are my files:
//reedll.h
#ifdef BUILD_DLL
// the dll exports
#define EXPORT __declspec(dllexport)
#else
// the exe imports
#define EXPORT __declspec(dllimport)
#endif
// function to be imported/exported
EXPORT void tstfunc(int A, int B, int C);
and:
//DLL_Test.c
#include "reedll.h"
EXPORT void tstfunc(int A, int B, int C)
{
C = A + B;
}
Its meant to be as bare bones as I can get it. No crazy pointers or anything.
I compile as follows usin MinGW:
g++ -c -DBUILD_DLL DLL_Test.c
g++ -shared -o tst.dll -Wl,--out-implib,libtstdll.a DLL_Test.o
And it appears to compile fine.
When I go to import the .dll into the shared library node the "Function Name" field is garbled and says "Z7tstfunciii" instead of "tstfunc". Needless to say the shared library function icon that results doesnt work
‎03-24-2010 08:47 AM - edited ‎03-24-2010 08:48 AM
You should tell the mingw compiler to not name mangle the symbols. Most likely you use a cpp file enxtension and then mingw as Visual C will invoke the cpp compiler instead of c which by default name mangles function names.
If you want or need to use cpp, you can also try to declare your exported symbols like this:
#ifdef __cplusplus
extern "C" {
#endif
EXPORT void tstfunc(int A, int B, int C);
/* all the other function prototypes you do not want to be mangled */
#ifdef __cplusplus
}
#endif
Not sure if __cplusplus is defined by mingw, if not you have to find how it indicates that C++ mode has been invoked.
‎08-06-2018 11:01 AM
Trying to do the same thing. Not sure if this was resolved. I think I have tried what is suggested here. When I try to load the DLL into Labview, it breaks the vi (or if I try to use a wire for the dll path, it gives an error 3). Normally I would think this is bit issue, and maybe it is. It's not super obvious to me. First, the file I am compiling is (test_dll.cpp)
#ifdef __cplusplus extern "C" { #endif __stdcall __declspec(dllexport) int hello ( void ) { return 10; }
#ifdef __cplusplus } #endif
I compile with
g++ -c -o obj/test_dll.o test_dll.cpp -I../include g++ -shared -o bin\test_dll.dll obj/test_dll.o -I../include
The DLL then shows up using the file command in mingw as
test_dll.dll: PE32+ executable for MS Windows (DLL) (console) Mono/.Net assembly
Supposedly PE32+ implies 64-bit.
When I call g++ -v
COLLECT_GCC=g++ COLLECT_LTO_WRAPPER=c:/octave/octave-4.4.0/bin/../libexec/gcc/x86_64-w64-mingw32/7.2.0/lto-wrapper.exe Target: x86_64-w64-mingw32 Configured with: /scratch/build/mxe-octave-w64-32-stable/tmp-native-gcc/gcc-7.2.0/configure --target=x86_64-w64-mingw32 --host=x86_64-w64-mingw32 --build=x86_64-pc-linux-gnu --prefix=/scratch/build/mxe-octave-w64-32-stable/usr/x86_64-w64-mingw32 --enable-languages=c,c++,fortran --disable-libsanitizer --enable-version-specific-runtime-libs --disable-nls --without-x --disable-win32-registry --with-native-system-header-dir=/scratch/build/mxe-octave-w64-32-stable/usr/x86_64-w64-mingw32/include --enable-threads=posix --disable-multilib --enable-64bit --disable-libgomp --with-cloog=/scratch/build/mxe-octave-w64-32-stable/usr/x86_64-w64-mingw32 --with-gmp=/scratch/build/mxe-octave-w64-32-stable/usr/x86_64-w64-mingw32 --with-isl=/scratch/build/mxe-octave-w64-32-stable/usr/x86_64-w64-mingw32 --with-mpc=/scratch/build/mxe-octave-w64-32-stable/usr/x86_64-w64-mingw32 --with-mpfr=/scratch/build/mxe-octave-w64-32-stable/usr/x86_64-w64-mingw32 Thread model: posix gcc version 7.2.0 (GCC)
So like x86_64 targets everywhere seem good, but maybe the mingw32 is not good? This version of mingw32 is setup to compile Octave which I'm trying to interface with Labview.
Essentially, the XY problem here is that I want to exchange data between Octave scripts we have and Labview software. One way to do that is to build the interpreter of Octave into a DLL, supply it parameters through the DLL interface from Labview, then load and call the script supplied with the parameters. A long time ago, someone built Octave into Visual C++, but I think the project has gone dormant. Currently, a MinGW version is available. However, I've never built DLLs from MinGW and I'm not sure what it takes to get them to be happy in Labview.
‎08-06-2018 01:12 PM - edited ‎08-06-2018 01:27 PM
You describe in detail what you have done and checked -> very good.
But you don't mention at all what does not work. What does not work? Do you get error messages and where? Do you use error handling? Have you tried to debug it in LabVIEW and/or C? What LabVIEW version? You created a 64-bit DLL but are you also using 64-bit LabVIEW for this?
Can you compile a mini test program in MingW that attempts to load this DLL with LoadLibrary() and GetProcAddress()? Do you have access to Visual C to compile this mini test program. It may work in the mingw executable but not in an executable created with anything else than mingw because it can not reference the mingw version of the Gnu C runtime library (it may not be properly installed on your computer). When you load the program in the mingw test executable the executable itself already loaded that library and the DLL may just link to it, but by non mingw application that does of course not work. Generally it is a mingw problem that you should try to resolve in the mingw community. Almost nobody who uses LabVIEW is likely to use mingw and even less so know anything useful about mingw.
Once you manage to load the DLL in another non-mingw application, be it Visual C or whatever, we can debug further with eventual LabVIEW problems, but I'm pretty sure that they will be gone too then. If the mingw community can't or doesn't want to support this use case at all, they could just as well remove the ability to create a DLL. It is basically useless to be able to create DLLs that can only get loaded by executables created by the same compiler.
‎08-06-2018 02:00 PM - edited ‎08-06-2018 02:02 PM
Thanks for responding. I tried right in the first paragraph to explain the issue, which I guess I failed to do.
Selecting the DLL and the function in the call library node breaks the VI because it can't load the library (or alternatively, if I wire the path to the call library node, I get an error 3). I am attempting to use 64-bit everything. Normally, I have experienced this when the bitness is wrong. I think it can also happen maybe when a DLL for some reason can't see other dependencies (i.e. DLLs it depends on). I don't think this thing has other dependencies but perhaps it does, even though the code is trivial and I don't explicitly build against anything fancy.
I'll try to get it running in VC++. I admit that the use case here is a bit weird: I'm using MinGW as it is packaged in Octave, because Octave is weird and needs lots of hand holding to compile on Windows. So it's possible it's weird because this build of gcc is weird for Octave. Hopefully that isn't the case. Thanks for your help so far.
‎08-06-2018 03:28 PM
It probably does have other dependencies namely at least the MinGW threading support library unless you compile the DLL for single threaded use.
You installed MingW however it might not have installed this necessary runtime libraries in a way that can be easily found by non MingW executables, which LabVIEW is not one.
‎08-06-2018 04:36 PM
I looked for bonus dependencies with dumpbin /dependency and it just showed some standard stuff. I called the function with GetProcAddress and it crashed. I removed the __stdcall and it worked. Then I brought it back into Labview and it worked also. I had tried this before and it didn't work. I'm not sure what changed. But this is a step forward. Thanks.
‎08-07-2018 02:44 AM
It looks like an improvement but be aware of one thing: Just because it does not crash anymore, does never mean that everything is right. You can have horrible configuration errors in the Call Library Node or outright memory bugs, and everything seems to be fine. That is until you change something seemingly unrelated and suddenly your machine crashes all the time.
Memory buffer overflow errors and other related bugs are a nasty breed to avoid. They can crash your program good, or they can hide for some time to hit you right in the final stage of your project. Even if they hide they do corrupt memory somehow somewhere, just not in a way that is fatal for your program. Instead you could end up having illogical results in other areas of your program. Basically if they destroy memory that is used as pure data somewhere else, wrong results could result, if they corrupt memory that is used/translated at some point to memory addresses, things get usually more frappant with real crashes and exceptions.
‎08-08-2018 02:43 AM - edited ‎08-08-2018 02:49 AM
And as far as __stdcall is concerned. You need of course to make sure to configure the Call Library Node accordingly. Just look in the original post in the picture where you can configure the calling convention for a function in the Call Library Node.
Most C compilers including Visual C default to __cdecl calling convention when nothing is specified. This can be overwritten in Visual C in the project settings (and with GCC based compilers with a command line option) but the caller has to use the same calling convention of course than what was used for compiling the function.
Accordingly when you create a test program to test the DLL loading with GetProcAddress() the function pointer has to be declared with the right calling convention too, or things go immediately into chaos as soon as your code comes to the point to try to call this pointer.
__stdcall and __cdecl are not decorations to a function declaration, they are essential and influence what code the C compiler will create to put the parameters on the stack and how they will be removed from the stack after the function returns. If the caller and callee don't agree on the same convention, immediate stack corruption is unavoidable and that causes a very quick process termination.