Auto link static libraries from header file - c++

I'm writing a library for in-house use and I want to automate the linking of static library (.lib) files so users don't have to know all the libraries they need. We use Visual Studio 2015 so I've knocked something up using pragma which seems to work but I'm getting a lot or warnings, which I presume are caused by what I'm doing.
Warning LNK4221 This object file does not define any previously
undefined public symbols, so it will not be used by any link operation
that consumes this library
I include this code in all the public facing interface header files and extend it to include internal and external libraries necessary.
#ifndef GFXK_LIBS_NET_IMPORT__
#define GFXK_LIBS_NET_IMPORT__
#ifdef _DEBUG
#ifdef WIN32
#pragma comment( lib, "gfxk_net_Debug_Win32-v140.lib" )
#else
#pragma comment( lib, "gfxk_net_Debug_x64-v140.lib" )
#endif
#else
#ifdef WIN32
#pragma comment( lib, "gfxk_net_Release_Win32-v140" )
#else
#pragma comment( lib, "gfxk_net_Release_x64-v140" )
#endif
#endif /*_DEBUG*/
#endif /*GFXK_LIBS_NET_IMPORT__*/
My question is how do I do this nicely so that I can remove this hack job. I'm looking for something similar to what Boost does with it's auto linking, I can't find out how to do this. I'm not too worried about cross platform as library targets only Windows at this time.

You can specify .libs path in your project settings Configuration Properties -> Linker -> Input -> Additional dependencies. You may specify different settings for different configurations and platforms. That would be a clearer way.
But the warning won't appear after you add functions to your .lib and use them in your project. Warning is just saying that this pragma-lib statement is pointless as no functions are really imported.

Related

Linking a library fails with LINK1181 on VS17

I am trying to use the ADTF streaming library in my project. When I am including the lib, I get the LNK1181 error. The library comes with the headers, the lib files and dll files.
I have added the path inside the C/C++ -> General -> Additional Include Directories.
In addition, I have added the library inside the Linker -> Input -> Additional Dependencies.
Here is also the error screenshot.
Update: I have changed the location of the dll and the libs to my project path and include it again. It does not complain now about the lib itself. Now I am getting an error LNK2001. I believe it is also a linker error.
And here where it all goes wrong!
Update 2: After I see the full log of the build. This appears, I think this means, the linker can't find my lib. Is that right?
The main application code is as this:
#include "pch.h"
#include <iostream>
#include "adtf_streaming.h"
using namespace adtfstreaming;
int main()
{
std::cout << "Hello World!\n";
IADTFFileReader *pFileReader = IADTFFileReader::Create();
}
and the header file which is trying to read/ import my lib is
#ifndef _ADTF_STREAMING_LIBRARY_DLL_
#define _ADTF_STREAMING_LIBRARY_DLL_
#ifdef WIN32
#ifdef STREAMINGLIB_EXPORTS
#pragma message ("Create ADTF Streaming Library ")
// export symbols
#define DOEXPORT __declspec( dllexport )
#else
#pragma message ("Use dynamic ADTF Streaming Library ")
#ifdef _DEBUG
#pragma comment( lib, "adtfstreamingD_290.lib" )
#else
#pragma comment( lib, "adtfstreaming_290.lib" )
#endif
#define DOEXPORT __declspec( dllimport )
#endif
#else
#ifdef STREAMINGLIB_EXPORTS
#define DOEXPORT __attribute__ ((visibility("default")))
#else
#pragma comment( lib, "adtfstreaming_290.lib" )
#define DOEXPORT __declspec( dllimport )
#endif
#endif
//standard includes
#include <stdlib.h>
#include <string.h>
//adtf base types and errors
#include "adtf_base_ref.h"
//streaming lib version
#include "adtf_streaming_version.h"
//adtf streaming lib package headers
#include "adtf_streaming_pkg.h"
#endif //_ADTF_STREAMING_LIBRARY_DLL_
You need to specify the Additional Library Directories, in Linker properties, to set the directory where you have the lib file. You don't need to include the libs in Additional Dependencies because you are doing it in the lib header file #pragma comment( lib, "adtfstreamingD_290.lib" ) when you compile your app in debug or #pragma comment( lib, "adtfstreaming_290.lib" ) when you compile in release. But you need to specify where are these libs in Additional Library Directories.
If you see the lib include file, you see that if STREAMINGLIB_EXPORTS macro is defined all functions with DOEXPORT modifier are exported functions #define DOEXPORT __declspec( dllexport ). But if this macro is not defined #define DOEXPORT __declspec( dllimport ), the same functions are imported functions. It is because the dll needs to specify that this functions are exported functions, so in the dll code someone has defined this macro. Because in your code you have not (and you must not do) define this macro, this functions are imported functions.
ADTF Streaming Library requires VS 2010 and is not compatible with other versions! So make sure to use it with v100 build tools. Or change to ADTF File Library a.k.a. IFHD, which is the v141 compatible successor and works with ADTF 2.x and ADTF 3.x as well. Note that the Lib comes completely open source licensed. See ADTF .dat trace file reader for some overview
I found the answer to the problem. Well, a combination of problems.
The library was built to support 0x86 machines only. I have built it again to support 0x64 and it worked.
P.S. It worked on Visual Studio 2017 too, unfortunately the documentation is poor and lacks information.

Linker can't find LIB file of the DLL imported

I've looked through full 14 pages list of similar problems but didn't find my case.
I have VS2017 c++ solution which has two projects DLL and EXE. EXE projects includes DLL header to import function from it.
The problem is that linker can't find dllproject.lib file. I tried to add it to Linker -> Input -> Additional Dependencies but didn't help because linker failed to find that lib file and it exists in the output folder.
Then I used
#pragma comment( lib, "C:\\FULL_PATH\\dllproject.lib")
And this time helped. But the problem is my local absolute path to the lib. I suppose I can somehow configure that in the project settings, but all my attempts failed.
In the DLL header file I have the block (was advised in other answers).
#ifdef MYDLL_EXPORTS
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endif
Please help.
Adding a library to your project is a two step process.
You add the library name to Linker/Input/Additional Dependencies and you add the library folder to Linker/General/Additional Library Directories.
Then of course you have the potential problem of your program failing to find your DLL, but that's another question.

C++ conditional link with preprocessor

I have a MSVC C++ project, I am conditionally compiling parts of the source code by passing specifing Preprocessor Defintions in the C++/Preprocessor section of the Project Properties.
What I would also like to do is conditionally link with libraries based on the preprocessor definitions, how do I achieve this?
For example in my project if CLSOPENLDV is defined I want to exclude:
nodetalk32_vcpp.obj
and include:
ldv32.lib
And when it isn't defined I want to do the opposite.
You probably need this:
#ifdef SOME_MACRO
#pragma comment( lib, "ldv32" )
#endif
This is Microsoft specific, it probably won't work with gcc, clang or other compilers.
For excluding nodetalk32_vcpp.obj the only thing you can do that comes into my mind is:
#ifndef SOME_MACRO
// content of nodetalk32_vcpp.cpp
#endif

Where is *.lib after generating *.dll with VC++?

I generated a *.dll with VC++. When I want to use it, a *.lib is required. But I cannot find it. How to get the *.lib? Thanks.
Unless you specify otherwise, the .lib will be generated in the same directory as the .DLL.
If you're getting a dll but not a lib, chances are pretty good that somehow or other you're not actually exporting anything from the dll. In such a case, the linker will create the dll, but won't automatically create a matching import library.
This really depends on your project settings.
Take a look at *.vcprojx
and search for similar pattern:
<link>
<ImportLibrary>.\Release/yourlibrary.lib</ImportLibrary>
</link>
Usually, Visual Studio puts the .lib right next to the .dll file.
YOur case sounds like it wouldn't generate a .lib at all. When building libraries as dll, if you want to link to that library in another project (as opposed to using dllopen and the likes), you have to specify which functions should be exported to a lib. For this, you have to prepend all classes or functions you want to export with a __declspec(dllexport) when building the library, and __declspec(dllimport) when linking it.
What you often find is some macro like this:
#ifdef WIN32
#ifdef MYLIB_EXPORTS
#define MYLIBAPI __declspec(dllexport)
#else
#define MYLIBAPI __declspec(dllimport)
#endif
#else
#define MYLIBAPI
#endif
Then, when building the lib, you define the MYLIB_EXPORTS preprocessor, so that it exports, while linking against it imports. Your own Code could then look like this
class MYLIBAPI MyClass
{
public:
void SomeFunction()
}
MYLIBAPI void SomeGlobalFunction();
Now, MyClass and SomeGLobalFunction are exported when building, and occur in the lib file.

Using #pragma detect_mismatch to ensure a DLL uses the correct statically linked library

I have a static S.lib that is used by my D.dll.
I'm trying to use #pragma detect_mismatch to make sure that both were compiled under the same release or debug settings.
I've followed Holger Grund's instructions here
http://boost.2283326.n4.nabble.com/Boost-and-Microsoft-s-SECURE-SCL-td3025203.html
dumpbin on S.lib shows:
Linker Directives
-----------------
/FAILIFMISMATCH:"COMPILED_DEBUG=1"
/INCLUDE:_dll_impl_interface_mismatch_check
/DEFAULTLIB:"MSVCRTD"
/DEFAULTLIB:"OLDNAMES"
I compile D.dll successfully, which should not happen.
dumpbin on D.dll's D.lib shows:
Linker Directives
-----------------
/FAILIFMISMATCH:"COMPILED_DEBUG=2"
/INCLUDE:_dll_impl_interface_mismatch_check
/DEFAULTLIB:"uuid.lib"
/DEFAULTLIB:"uuid.lib"
/FAILIFMISMATCH:"_MSC_VER=1600"
/FAILIFMISMATCH:"_ITERATOR_DEBUG_LEVEL=2"
/DEFAULTLIB:"msvcprtd"
/DEFAULTLIB:"MSVCRTD"
/DEFAULTLIB:"OLDNAMES"
Any help would be greatly appreciated.
EDIT:
I accidentally defined the symbol 'dll_impl_interface_mismatch_check' in BOTH my static library and my consuming DLL. This meant that the symbol was not looked for in the static library S.lib, and the mismatch directive was never found. I think.
I'm just guessing here - I'll have to experiment with this tonight.
Holger Grund's instructions are designed for objects that depend on the DLL. In your case the DLL depends on the static lib.
So, I'm guessing that you want the _dll_impl_interface_mismatch_check object to be added to the static lib rather than the DLL. So instead of:
extern "C" const char dll_impl_interface_mismatch_check=0;
cl /c /Zl foo.cpp
lib D.lib foo.obj
try:
extern "C" const char dll_impl_interface_mismatch_check=0;
cl /c /Zl foo.cpp
lib S.lib foo.obj
You have to build a string with the preprocessor that represents your build settings, and use that string with #pragma detect_mismatch.
E.g.
#if defined(_DEBUG)
#define FOO_DEBUG_PART "_debug"
#else
#define FOO_DEBUG_PART "_release"
#endif
#if defined(_MT)
#define FOO_CRT_PART1 "_MT"
#else
#define FOO_CRT_PART1 "_st"
#endif
#if defined(_DLL)
#define FOO_CRT_PART2 "_DLL"
#else
#define FOO_CRT_PART2 "_LIB"
#endif
// ...
#define FOO_BUILD_SETTINGS FOO_DEBUG_PART FOO_CRT_PART1 FOO_CRT_PART2 /* ... */
#pragma detect_mismatch("foo_build_settings", FOO_BUILD_SETTINGS)
The IMO better solution though is to use #pragma comment(lib) to link to your libraries, and then build a similar string and use it as part of the file name of the lib:
// build FOO_BUILD_SETTINGS like above
#pragma comment(lib, "mylib" FOO_BUILD_SETTINGS)
That way you cannot use the wrong library (unless you either change the code or the lib is created with the wrong file name ... or renamed afterwards). And of course, if you're as paranoid as I am, you can always do both :)