I create a set of C++ DLLs and their import libraries in VisualStudio (2013). So far, these were all generated at the same time by linker. My DLLs use symbols from other libraries, which are included as additional dependencies in properties/link edition.
Sometimes, the DLL generation fails because of missing importation libraries, which is fine to me, but in such case there's no generated .lib file either. I would like to generate the import libs (of my DLLs) even if the DLLs cannot be done, in order to allow other projects to rely on the symbols I shall export before I'm able to provide the whole stuff.
I found a workaround through a pre-link event command line, with:
LIB /DEF:(...)\myLib.def /OUT:(...)\myLib.lib $(IntDir)*.obj
This generates exactly what I need, when I do have a .def file.
The problem is, I most often don't have such a .def file but rely on __declspec(dllexport) instructions instead, and in such case I didn't find a way to get a correct result.
I tried:
LIB /OUT:(...)\myLib.lib $(IntDir)*.obj (#1)
This creates a (static ?) lib file, not an import library, not what I need.
LIB /DEF /OUT:(...)\myLib.lib $(IntDir)*.obj (#2)
This fails on error 1104 because of missing (other) import libraries.
What's more puzzling to me is, the command line (#2) fails on libraries that should be here (they are found by the linker, actually). I'm wondering whether I am supposed to provide the complete LINK command line arguments to the LIB command, in which case it would be a no-go.
I'm not much of a specialist of the compilation/link tools, I fear, I'm probably doing pretty wrong stuff...
Does anyone know of a simple way to fulfill my need without using a .def file ? Is there an option in the linker to ask for import library creation from the declared __declspec(dllexport) symbols and generate it even when the DLL cannot link ?
This fails on error 1104 because of missing (other) import libraries.
Edit: oh, I get it. .obj files have /DEFAULTLIB: inside them and lib complains. Use /NODEFAULTLIB
hasunresolved.c:
#pragma comment(lib, "missinglib.lib")
void missingfunc();
__declspec(dllexport)
void dllfunc() {
missingfunc();
}
usedll.c
__declspec(dllimport)
void dllfunc();
int main() {
dllfunc();
return 0;
}
in VS command prompt:
cl -c hasunresolved.c
lib /def /OUT:test.lib hasunresolved.obj
rem this prints: LIB : fatal error LNK1104: cannot open file 'missinglib.lib'
lib /NODEFAULTLIB /def /OUT:test.lib hasunresolved.obj
cl usedll.c test.lib
dumpbin /IMPORTS:test.dll usedll.exe
output:
Dump of file usedll.exe
test.dll
0 dllfunc
Related
I've got 2 C++ project in the same Visual Studio solution: Engine, a library; and Test, that uses the Engine library
Engine compiles correctly on Windows and produces a lib and a dll. The lib is correctly given to the linker of Test as well
In Test, I try to import a module from Engine, but the compiler fails with error C2230
Here are code excerpts from the 2 projects:
Engine > hal.ixx
export module hal;
#ifdef TEST_ENGINE_EXPORTS
#define TEST_ENGINE_API __declspec(dllexport)
#else
#define TEST_ENGINE_API __declspec(dllimport)
#endif
import <string>;
export extern TEST_ENGINE_API void prepareMain();
export extern TEST_ENGINE_API int init();
//...
Test > main.cpp
#include <cstddef>
#include <stdio.h>
import hal; //fails here: error C2230 could not find module 'hal'
int main(int argc, char const* argv[])
{
prepareMain();
// some other stuff...
}
I'm using Visual Studio 2022 (v. 17.4.0), and for the 2 projects, I compile with std::c++latest, /permissive- and /experimental:module. I've also added the Engine header's folder as Additional include directory for the Test project.
I've tried to remove the module altogether and including headers files in Test and functions are correctly called
I already read this question (How to import a c++ module from another library?) that has the same problem that me, and the article linked in one comment (VS2019 Modules), but I fail to see how it can solve my problem
EDIT
So, I ran a couple of tests, and basically, it seems to stem from the fact that my library is a dll project
I tried making a new solution with 2 projects
The library one is a WindowsStaticLib project. Compiler options are : /std:c++latest, /std:c17, /permissive-, /experimental:module, and /sdl and /W3 (last 2 where there by default, I let them as they were). I deactivated precompiled headers since it seemed to interfere with modules (compliling amodule unit with /exportHeader as it is recommended here when module import standard header was causing VS to start looking for pch.h in header)
For the actual project using the library; library project is added as a reference, compiler options are the same as the library project, lib headers directory is added to VC++ directories > External include directories, lib folder to Library directories, and .lib file added as an Additional dependancy
Everything works.
Module is correctly found and imported, and functions can be called from the actual project.
As a side note, I should add that I didn't need to specify my module functions as extern for them to be usable in the other project main.cpp. I thought I should have done it but apparently not.
Now I tried to do the same thing but with a DLL project for the library. New solution with 2 project, with the exact same configuration as it was for the previous solution.
Error C2230 when I try to import my module in the actual project main.cpp.
Does anyone know something about this ?
Is it normal behaviour that I just didn't know ?
I try to make simple dll project in Visual Studio 2013 like in http://www.itcsolutions.eu/2009/12/10/how-to-create-a-dll-dynamic-link-library-in-c-as-visual-studio-2008-project/
But when i try to build solution it falls with an error:
error LNK1104: can not open file "D:\prj\dlltest1\Debug\dlltest1.lib" D:\prj\dlltest1\ConsoleApplication1\LINK ConsoleApplication1
But dlltest1 is dll-project. Why there is an .lib file?
Updated: The reason why no libs are generated because you have no symbols exported. I just checked your code.
You should have a *.h file define exported symbols like this.
#ifdef WIN32PROJECT1_EXPORTS
#define WIN32PROJECT1_API __declspec(dllexport)
#else
#define WIN32PROJECT1_API __declspec(dllimport)
#endif WIN32PROJECT1_API int fnWin32Project1(void);
When you created a DLL project, it has some exported symbols other project can use. These symbols' name and offset are stored in *.lib file. *.lib file is created with *.dll files, both of them are put in the output directory.
In the link stage of you ConsoleApplication, the linker try to find the symbols from all your referenced libs (defined in project property) and store these symbols' offset and source dll in output exe file.
You can change the libs settings in Property->Linker
Wikipedia says:
DLL compilation will produce both DLL and LIB files. The LIB file is used to link against a DLL at compile-time; it is not necessary for run-time linking.
The code within your application determines whether compile-time or run-time linking is required:
If you access your DLL functions like
__declspec(dllimport) someFunction(int firstArg, int secondArg)
then your compiler will require both the .dll and the .lib file for linking to the shared library, but during execution, only the .dll will be required.
If you however make use of the DLL functions LoadLibrary, GetProcAddress and FreeLibrary, the .lib will not be required for linking.
I am working on a project using c++/windows forms (visual studio 2010), we have 4 projects:
1 project containing GUI windows forms {managed code} and this is the exe project
other 3 projects {non-managed code} and all are static libraries.
in the 4 projects we don`t use precompilied headers stdafx.h , and common language runtime support is the Pure MSIL Common Language Runtime Support (/clr:pure).
every project include the other 3 projects as additional include directories , and link library dependencies set to yes.
We have:
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
This warning appeared for the 3 static libraries projects in the same object files (.NETFramework,Version=v4.0.AssemblyAttributes.obj).
We want to eliminate it, but after some search, most topics speak about the precompiled headers to be a reason while we don not use it.
Any new ideas about why this warning exist and how to eliminate it?
Disclaimer: This solution is indeed terrible, and this code should not be added to production build! It is only useful to "hide" the warning.
A better solution would be to remove the file in question from the compilation, as it is anyway useless.
Original post:
I had a the problem with this warning originating from several dependencies, and I found that it was caused by some translation unit being empty, i.e. empty source files.
These files actually had a content but it was deactivated for visual studio so I just added at the beginning:
__declspec( dllexport ) void getRidOfLNK4221(){}
And now my project compiles without any warning :)
Hope it helps, even if this is a late answer!
I had a c++ static library with an empty module in it, linking which in non-optimized mode gave me that LNK4221 warning. (in Visual Studio)
I went to Librarian->All Options, and added "/ignore:4221" to Additional Options.
So, the warning has disappeared.
You get this warning because you use only template classes in cpp file.
To get rid of it, insert one simple function with no template.
See this:
https://learn.microsoft.com/en-us/cpp/error-messages/tool-errors/linker-tools-warning-lnk4221
In summary, the file exports nothing, so linker does not link, as it thinks it's a waste of effort
This was kind of just my particular problem but if your .cpp doesn't define any new functions or has empty bodies for constructor functions, you will get this warning. I used an initialization list for my constructor so the body was empty.
https://devblogs.microsoft.com/cppblog/linker-warning-lnk4221-and-some-tips-to-avoid-it/
In ” Visual Studio 2008 Command Prompt”, enter the following commands (Note: We use command line here to specify the order of .obj files; Visual Studio 2008 will supply linker with .obj files in alphabetical order)
cl /c a.cpp b.cpp
link /lib /out:test.lib a.obj b.obj
And LNK4221 will be thrown for a.obj as the following.
a.obj : warning LNK4221: no public symbols found; archive member will be inaccessible
For the above case, atlbase.h (shipped with Visual Studio) contains some definitions of symbols, which will be included in both a.obj and b.obj. Additionally, there is a function, func1, defined in b.obj. Linker will process OBJ files in Last In First Out manner, so when it is processing a.obj, it cannot find any new public symbols in it because b.obj provide all the public symbols that a.obj has, LNK4221 will be thrown. If command line 2 is replaced with following
link /lib /out:test.lib b.obj a.obj
Now the warning is gone!
I'm trying to create a .lib file to go with an external .dll so we can compile our code against it (VS2010). In this external library functions are declared using __stdcall, they don't specify __declspec(dllimport). Example:
extern "C"
{
int __stdcall exampleFunction(int firstArgument);
}
I've tried the following:
Create .lib from .def
Creating a .def file as follows:
EXPORTS
method_1
method_1#16 #1 ; ordinal from dumpbin
...
Then creating the .lib from this
lib /MACHINE:x86 /def:my_def_file.def OUT:my_library.lib
The code links ok but throws a "Privileged Instruction" exception when first invoking a method from the dll.
Create .lib from .obj
As detailed in this kb another possibility is to create a set of stub functions, compile them into a .obj file and create the .lib from that. I am however unable to even get the example on the kb page to work, e.g.
// my_library.cpp
extern "C" __declspec(dllexport) void _stdcall Function(void) {}
When I run the required commands on this file:
CL /c /Ob0 my_library.cpp
lib /def:my_library.obj /MACHINE:x86
Then opening my_library.obj does show the string "_Function#0", as expected but my_library.lib shows no trace of this. Furthermore I get some funky warning messages when running the lib command:
hasp_api.obj : warning LNK4017: L☺♥ statement not supported for the target platform; gnored
hasp_api.obj : warning LNK4017: ► statement not supported for the target platform; ignored
I'm all for peace and love but I'm kinda stuck and its driving me crazy, any help with either of the methods above would be appreciated!
I use NetBeans, Windows and Cygwin with G++ compiler.
I'm examining Windows Sockets 2. I do everything that is written in MS manual. I have a code (mostly from this manual):
#include <winsock2.h>
#include <ws2tcpip.h>
#include <cstdlib>
#include <iostream>
#pragma comment(lib, "Ws2_32.lib")
int main() {
WSADATA wsaData;
int iResult;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed: %d\n", iResult);
return 1;
}
else cout << "Initialization OK.";
return 0;
}
And I have a problem when I try to run the project:
undefined reference to `_WSAStartup#8'
I understand that Ws2_32.lib is missing. This is because I do not have Windows SDK installed. But before installing it I want to try out tools that Cygwin offers. It has all the w32api header files, I have them in:
C:\cygwin\usr\include\w32api
And it has some w32api almost .lib files in the directory:
C:\cygwin\lib\w32api
But all these lib files are different, they have .a extension and a little bit different name, like:
libws2_32.a // in Cygwin
vs.
ws2_32.lib // in Windows
When I use Cygwin terminal to create an .exe file, everything works fine. The commands I input are:
cd C:\\c++\\myProgram // go to the dir
g++ myProgram.cpp -lws2_32 // compile using -l option to link libws2_32.a
And after it I get a.exe file. I run it and it works:
./a.exe // Initialization OK.
But as I said I use NetBeans. And if I try to run the project from NB ([F6] button) I always have this error undefined reference to '_WSAStartup#8'.
I've tried already everything I could find on NB forums. I've tried to link libws2_32.a to my project this way. I go to:
File -> Project Properties -> Linker -> Libraries
And there are three options:
Add Library...
Add Library File...
Add Option...
I've tried them all. I've tried to link both just Add Library... and Add Library File.... I've also tried to add such an option in the Add Option... button:
Add Option... -> Other option -> // and I input here "-lws2_32"
But whatever I do I can't run the project from NB, I get error undefined reference to '_WSAStartup#8'.
So it seems that it is not a problem (error) in the code. It seems that the problem is with NB, with its possibility to link libraries. Or I do wrong steps to attach them to the project.
So my questions are:
1) What do I do wrong? How may I run the project right from NB? I didn't try to install Windows SDK, I want to try with Cygwin tools as it has such kind of tools.
2) What is the difference between Windows .lib files and Cygwin .a files? Is it better to install Windows SDK and just forget about those .a files? Everything I could find so far about them on Cygwin site is this:
The import library is a regular UNIX-like .a library, but it only
contains the tiny bit of information needed to tell the OS how your
program interacts with ("imports") the dll. This information is linked
into your .exe. This is also generated by dlltool.
3) Is it possible to use #pragma comment(lib, "libws2_32.a") to link .a files? I've tried but didn't get success results.
1) What do I do wrong? How may I run the project right from NB? I didn't try to install Windows SDK, I want to try with Cygwin tools as it has such kind of tools.
Try this: http://forums.netbeans.org/ptopic44959.html
2) What is the difference between Windows .lib files and Cygwin .a files? Is it better to install Windows SDK and just forget about those .a files?
Both of these files in this particular case are called "import libraries". Import libraries are basically a file containing a list of valid functions, so that when you link your exe, the linker knows that those functions will exist in some particular DLL. So when you link to wsock32.lib or ws2_32.lib, the linker now knows that these functions will exist in wsock32.dll and ws2_32.dll. Thus, it will not complain. Now, the .lib import library format is Microsoft's format. GCC/unix/linux/mingw/cygwin etc. have a different format, and the extension for that format is .a. Now, cygwin/mingw etc. provide a ws2_32.a so that when using cygwin/mingw/gcc, the linker can read the import library in the correct format. cygwin/mingw/gcc will simply not understand the .lib. Microsoft provides the .lib files in their SDK, but I am not sure how this will help in this case. (Though the SDK is definitely useful, because it provides lots of header files and DLLs for other useful things you might need, but the import libraries are useless, because gcc/mingw/cygwin will not understand them; unless you use a converter tool, like the one mentioned in your duplicate question).
3) Is it possible to use #pragma comment(lib, "libws2_32.a") to link .a files? I've tried but didn't get success results.
No, the #pragma linking comments are an MSVC specific (ugly IMO) extension. Use the linker options in the menus.
eclipse, Cygwin
propeties -> C/C++ Build -> Settings -> Cygwin C Linker
Command line pattern
add to -lws2_32
ex)${COMMAND} ${FLAGS} ${OUTPUT_FLAG} ${OUTPUT_PREFIX}${OUTPUT} ${INPUTS} -lws2_32