.NET programmers are well aware of the References section of a .NET project using which we specify the dependencies. Things are pretty straight forward in the managed world and with an IDE like Visual Studio it can't be easier. You are using a type from a particular assembly, then just add that assembly to the references of the project. The rest is taken care of by the IDE and framework. When we move to the native/unmanaged world, we get slightly more powers with of course increased responsibility.
Any external symbol that we are using must be approved by two tools/stages: The compiler and the linker. The compiler can be tackled by having the appropriate header file (.h file) which just has the declaration and no definition/implementation. Using this is simple. #include the header file in whichever source file you are using the symbol. But just make sure that the compiler knows where to find that header file, that is maintain an includes directory and tell the compiler about that directory.
The linker is a less tamed beast or rather a more difficult a beast to tame. One simple reason being that since it handles the object code, its error messages cannot be traced back to a line in the source code. Another reason being that we have two versions of library: Static and Dynamic.
Now to use this we will have to provide each of these libs, containing the symbols that we use, as input to the linker. On the VS IDE, we have to list all the required libs in the project settings and also specify the the library containing the libs. I say this is not as simple as the references thing .NET because, to change anything you will have to visit the Project Settings page. And if you are developing without an IDE, your compiler invocation command line will be really really long. (though you can shorten it with some gmake variables and system variables). But apart from these geeky build methods there is yet another simple way to tell the linker which all .lib files it has to look into for symbols when linking the current code and thats where this #pragma directive comes into picture.
#pragma comment(lib, "requiredLibrary.lib") --- This line of code will make the linker look for the library file requiredLibrary.lib. Isn't that cool? Don't you get a feeling that you, kind of, tamed the linker using your C/C++ code?
All you need to do is to put this line of code in one of your code files and the compiler will know what to do. When this code is encountered, the compiler adds a "search directive" to the object file (.obj file) that it generates. When the linker reads that search record it will know what lib file it has to look for to find any external symbol that is present in the current object file that it is linking.
So, suppose you are providing a library and you want to enforce this above method on anyone who consumes your lib, you can provide a header file that they must include to use your symbols. And in that header file you can specify this above pre-processor directive. This way all your anyone who is using your lib will implicitly tell the linker which lib file to look for.
This #pragma comment on a broader sense is used to inject extra information to the object code generated by the compiler. This information can be used by the linker. Here is the msdn article on what all this #pragma comment can do: This page.
Any external symbol that we are using must be approved by two tools/stages: The compiler and the linker. The compiler can be tackled by having the appropriate header file (.h file) which just has the declaration and no definition/implementation. Using this is simple. #include the header file in whichever source file you are using the symbol. But just make sure that the compiler knows where to find that header file, that is maintain an includes directory and tell the compiler about that directory.
The linker is a less tamed beast or rather a more difficult a beast to tame. One simple reason being that since it handles the object code, its error messages cannot be traced back to a line in the source code. Another reason being that we have two versions of library: Static and Dynamic.
Now to use this we will have to provide each of these libs, containing the symbols that we use, as input to the linker. On the VS IDE, we have to list all the required libs in the project settings and also specify the the library containing the libs. I say this is not as simple as the references thing .NET because, to change anything you will have to visit the Project Settings page. And if you are developing without an IDE, your compiler invocation command line will be really really long. (though you can shorten it with some gmake variables and system variables). But apart from these geeky build methods there is yet another simple way to tell the linker which all .lib files it has to look into for symbols when linking the current code and thats where this #pragma directive comes into picture.
#pragma comment(lib, "requiredLibrary.lib") --- This line of code will make the linker look for the library file requiredLibrary.lib. Isn't that cool? Don't you get a feeling that you, kind of, tamed the linker using your C/C++ code?
All you need to do is to put this line of code in one of your code files and the compiler will know what to do. When this code is encountered, the compiler adds a "search directive" to the object file (.obj file) that it generates. When the linker reads that search record it will know what lib file it has to look for to find any external symbol that is present in the current object file that it is linking.
So, suppose you are providing a library and you want to enforce this above method on anyone who consumes your lib, you can provide a header file that they must include to use your symbols. And in that header file you can specify this above pre-processor directive. This way all your anyone who is using your lib will implicitly tell the linker which lib file to look for.
This #pragma comment on a broader sense is used to inject extra information to the object code generated by the compiler. This information can be used by the linker. Here is the msdn article on what all this #pragma comment can do: This page.
Hey Brahmana remember me??
ReplyDeleteI was just searching for that pragma and yours was the hit!!
Hi JAB,
ReplyDeleteGood to know my blog post helped you.
And I am sorry but I could not recognize you and neither could I see your profile. A little more info would be helpful. :)
Regards,
Brahmana (Srirang)
#pragma comment(lib, "libfilename") has a couple problems:
ReplyDelete1) It is VC++ only, or at best heavily compiler/linker dependent as you are specifying the linker file name based on how you expect it for your compiler. Move to another compiler and that may no longer hold true - e.g. libFileName.a versus fileName.lib.
2) You lose all ability to change which libs you are linking against based on your build. For example, you might want to have one set of libs for debug and another set for release. This is more easily handled via the project linker options.
TemporalBeing,
ReplyDeleteAgree with you on the 1st point. This is totally MSVC specific. Though, admittedly it is a pretty cool feature.
But as I mention at the end of my post, this feature suits library developers very well. And as a library developer you know which compiler and platform you support. So you can do this selectively with a #ifdef. The logic is applicable for different environments -- debug, release, test, etc. #ifdef again works.
This is just one additional measure to make sure users of your library will not get those weird looking long linker error messages because they forgot to include your library in the necessary libraries list for their project. The moment they include your header file, your library is also linked (sort of).
I realize I'm way late with this response, but I just thought I'd point out that you can also use this functionality with the __pragma keyword, allowing it to be used from a preprocessor macro:
ReplyDelete#define XSTR2(X) #X
#define XSTR(X) XSTR2(X)
#define REDIRECT_EXPORT(DLL,NAME) \
__pragma(comment(linker, "/export:" XSTR(NAME) "=" DLL "." XSTR(NAME)))
#define IMPORT_LIB(BASENAME) \
__pragma(comment(lib, XSTR(BASENAME) COMMON_SUFFIX ".lib"))