07-10-2015 09:22 AM
Hello all,
I'm sure I've done this before but I just can't remember how.
I want to use a library that exists both in Windows and Linux for the two versions of my CVI project. For instance libusb (a system lib on Linux, a manual install on Windows).
If I add the libusb.lib file to the cvi project on Windows, it compiles and runs fine, but then upon compiling on Linux with "cvicc -lusb test.prj" I get gcc: /.../libusb-win32-bin-1.2.6.0/lib/msvc/libusb.lib: No such file or directory
If I remove the lib from the project, it compiles and runs fine on Linux but fails on Windows with error: Undefined symbol '_usb_claim_interface' referenced in "l:\test\cvibuild.test\Debug\test.obj"
So how can I include the lib file in the Windows build but exclude it from the Linux build ? Actually this should be the default as I don't see how a lib file could work on both.
Thanks
07-13-2015 11:20 AM - edited 07-13-2015 11:21 AM
If I understand your question correctly, this is typically done by using predefined OS compiler macros. Here are a couple of examples showing how to do this:
http://stackoverflow.com/questions/8666378/detect-windows-or-linux-in-c-c
Because there are typically multiple possible macros for the same OS, you will probably want to use logcal ORs to check all possible cases:
http://stackoverflow.com/questions/3213037/determine-if-linux-or-windows-in-c
Here is a pretty extensive list of predefined macros you can use to determine the possibilities:
Pre-defined Compiler Macros
http://sourceforge.net/p/predef/wiki/OperatingSystems/
Thanks,
07-15-2015 05:12 AM
Thank you for the answer, but since it's a linker issue I don't think you can solve it by using compiler defines.
I've created a workaround by calling a script that removes the section of the .prj file that contains the .lib, and then send the patched project to cvicc. Sees to work but not very clean. I would think cvicc intelligent enough to ignore Windows only libraries ! Maybe this should be a bug report.
07-16-2015 09:39 AM
You should be able to use #ifdef statements to conditionally load the library using the Win32 API call to LoadLibrary. Documentation on the function can be found below:
http://digital.ni.com/public.nsf/allkb/8AE57BDA995ACCB486256AEA0062B3C6
https://msdn.microsoft.com/en-us/library/windows/desktop/ms684175(v=vs.85).aspx
There is also an example of how to use the Windows SDK in CVI located in <CVI>\Samples\sdk
folder (where <CVI>
is the installation directory of CVI).
Using this along with the predefined compiler macro for your operating system should do exactly what you want.
The code would resemble:
#ifdef(WINDOWS_OS_MACRO1 | WINDOWS_OS_MACRO2)
LoadLibrary(windows_usblib)
#endif
Thanks
07-17-2015 09:06 AM
Hmmm, OK, so you can selectively load a DLL (I wanted a simple static lib, but okay), but then with CVI don't you have to link with a DLL import library, in other words, a static lib ? It kind of defeats the purpose...
Or do you use a DLL import source file ? And find a way to not compile it on the Linux side...
07-17-2015 09:55 AM - edited 07-17-2015 09:57 AM
Dynamically linking to a DLL via LoadLibrary+GetProcAddress does not require you to have a .lib file in the project: you simpy need a #include file that gives the definitions of the DLL functions.
Here is when preprocessor macros come in handy: you may enclose the calls to the windows version in some #ifdef _WINDOWS or #ifdef _NI_mswin_ clause.
The boring part of this is to create the #include file that typedefs all the functions you need in your program. Just as an example, these are the definition of functions used by a APPLICOM communications board:
BOOL _stdcall IO_Init (WORD wCard, short *status); BOOL _stdcall IO_Exit (WORD wCard, short *status);
Here is how you need to declare them to call them in the DLL:
typedef BOOL _stdcall (*INIT)(WORD, short *); INIT IO_Init, IO_Exit;
If the translation is correct, you can then call the function in your code as if they where statically linked, after getting their address:
// Getting function addresses
hinstLib = LoadLibrary ("AppIO");
IO_Init = (INIT) GetProcAddress (hinstLib, "IO_Init");
IO_Exit = (INIT) GetProcAddress (hinstLib, "IO_Exit");
// Calling the functions
IO_Init (board, &sts);
07-17-2015 10:19 AM
An alternative would be to just manage two projects - one for linux and one for windows. If you're not adding and removing items from your projects a lot, this is a simple and very manageable solution
07-20-2015 08:47 AM
You could use a custom build configuration to make the same project work for both Windows & Linux. In the custom build config mark the import libary as being excluded from the build (rt-click the lib in the project tree). When building on linux, use the -config=__NameOfConfig__ option to specify the custom config to cvicc.
I've written CAR 537857 to fix this in the next release of CVI for Linux.
Michael
NI
07-21-2015 06:41 AM
Thanks all. I've given kudoes to everyone because you all offer different working solutions. I'm going with the 'manage 2 projects' option, with a simple script to tronsform the Windows prj into a Linux one:
# Remove the Windows library from the MyProj.prj project file for the Linux compilation Section=$(grep -B1 '^File Type = "Library"' MyProj.prj | head -1 | tr -d "\[\][:cntrl:]") sed -e "/$Section/,+11 d" MyProj.prj > MyProjLinux.prj