最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c++ - Link multiple DLLs from one import library (lib) - Stack Overflow

programmeradmin7浏览0评论

In the CRT description on MSDN, there is the following sentence:

For binary compatibility, more than one DLL file may be specified by a single import library.

What does this mean?

Assuming I manually link msvcp140.dll and msvcp140_1.dll, does adding a single msvcprt.lib to dependencies mean that both DLLs will be linked?

For this, I looked into some options related to lib.exe (Microsoft Library Manager) and realized that it is impossible to create a single import library (lib) through multiple .def files.

However, I confirmed that it is possible to link multiple DLLs through a single lib by merging the Import Library (lib) generated when building two DLLs using the lib.exe command.

I'm not sure if this is the best way to do it.

How does msvcprt.lib work so that both msvcp140.dll and msvcp140_1.dll can be linked?

Additionally, I found that the C++Builder solution provided by Embarcadero has a utility called implib.exe and a method to create a single lib using multiple custom defs, but this is not a Microsoft standard (however, it is compatible with MVSC).

I'm a newbie to this area, so I'd appreciate some concrete examples, rather than just a simple answer like "look at msdn".

In the CRT description on MSDN, there is the following sentence:

For binary compatibility, more than one DLL file may be specified by a single import library.

What does this mean?

Assuming I manually link msvcp140.dll and msvcp140_1.dll, does adding a single msvcprt.lib to dependencies mean that both DLLs will be linked?

For this, I looked into some options related to lib.exe (Microsoft Library Manager) and realized that it is impossible to create a single import library (lib) through multiple .def files.

However, I confirmed that it is possible to link multiple DLLs through a single lib by merging the Import Library (lib) generated when building two DLLs using the lib.exe command.

I'm not sure if this is the best way to do it.

How does msvcprt.lib work so that both msvcp140.dll and msvcp140_1.dll can be linked?

Additionally, I found that the C++Builder solution provided by Embarcadero has a utility called implib.exe and a method to create a single lib using multiple custom defs, but this is not a Microsoft standard (however, it is compatible with MVSC).

I'm a newbie to this area, so I'd appreciate some concrete examples, rather than just a simple answer like "look at msdn".

Share Improve this question edited Mar 18 at 18:39 Remy Lebeau 601k36 gold badges507 silver badges850 bronze badges asked Mar 18 at 8:23 arcane22arcane22 311 silver badge1 bronze badge 1
  • "Assuming I manually link msvcp140.dll and msvcp140_1.dll": what does that mean? how ho you manually link them? – CristiFati Commented Mar 18 at 14:13
Add a comment  | 

2 Answers 2

Reset to default 4

Assuming I manually link msvcp140.dll and msvcp140_1.dll

That's not how it works. You link a .lib. When that's an import lib, you get a runtime dependency on one or more DLLs. The OS will then load those dependent DLLs (typically when the EXE is loaded i.e. the process is created).

It does not matter to you exactly what Microsoft did to create that import library. They're only telling you that there can be multiple DLLs involved because you might need to redistribute those DLLs with your executable.

The "binary compatibility" part is because there are existing EXE files in the wild which make (bad) assumptions about the content of msvcp140.dll.

an Embarcadero utility called implib

This is not a utility which you'll need as a newbie. In fact, I haven't needed it in 30 years.

The page where the quote is from ([MS.Learn]: C runtime (CRT) and C++ standard library (STL) .lib files) would have been useful.

This approach (one import library and multiple .dlls) is useful, especially since UCRT (might take a look at [SO]: How to circumvent Windows Universal CRT headers dependency on vcruntime.h (@CristiFati's answer)) arrived.
Note that it's a perpetual model: at the beginning it was (taking the simplest example) one .lib and one .dll, then they decided to add more functionality. Instead of rebuilding (and redistributing) the .dll (other existing apps using newer version might be negatively impacted), they just specified it in the .lib file(s) (and also .h file(s)), and they distribute a new .dll containing the new functionality (leaving the original one untouched).

There are several advantages to the approach:

  • Software is easily breakable into pieces. Related code is grouped in a separate .dlls. At runtime, only the specific .dll will be loaded, instead the huge monolithic one containing everything (less memory, less loading time)

  • What I talked about in the above paragraph: extending without rebuilding existing .dlls

  • Seamless build (link) step. There will be no change (as opposed to having one .lib file for each .dll), the big .lib file is specified (although for UCRT this is done automatically by VStudio), and the linker will pick only the .dlls containing referenced symbols

I created a MCVE that hopefully makes things clearer:

  • dll.h:

    #pragma once
    #include <stdio.h>
    
    #if defined(_WIN32)
    #  if defined(DLL_EXPORTS)
    #    define DLL_EXPORT_API __declspec(dllexport)
    #  else
    #    define DLL_EXPORT_API __declspec(dllimport)
    #  endif
    #else
    #    define DLL_EXPORT_API
    #endif
    
    #define PRINT_MSG_1S(ARG0) printf("  [%s] (%d) - [%s]:  ARG0: %s\n", __FILE__, __LINE__, __FUNCTION__, ARG0)
    
    #if defined(__cplusplus)
    extern "C" {
    #endif
    
    // dll.dll functions (initial version)
    DLL_EXPORT_API int dllFunc00();
    
    // dll00.dll functions (added in a later version)
    DLL_EXPORT_API int dll00Func00();
    
    // dll01.dll functions (TBR)
    
    // ...
    
    #if defined(__cplusplus)
    }
    #endif
  • dll.c:

    #define DLL_EXPORTS
    #include "dll.h"
    
    
    int dllFunc00()
    {
        PRINT_MSG_1S("dll.dll");
        return 0;
    }
  • dll00.c:

    #define DLL_EXPORTS
    #include "dll.h"
    
    
    int dll00Func00()
    {
        PRINT_MSG_1S("dll00.dll");
        return 1;
    }
  • main00.c:

    #include <stdio.h>
    #include "dll.h"
    
    
    int main()
    {
        int res = dllFunc00();
        printf("\nDone.\n\n");
        return 0;
    }
  • main01.c:

    #include <stdio.h>
    #include "dll.h"
    
    
    int main()
    {
        int res = dll00Func00();
        printf("\nDone.\n\n");
        return 0;
    }

Output:

[cfati@CFATI-5510-0:e:\Work\Dev\StackExchange\StackOverflow\q079516767]> sopr.bat
### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ###

[prompt]> "c:\Install\pc064\Microsoft\VisualStudioCommunity\2022\VC\Auxiliary\Build\vcvarsall.bat" x64 > nul

[prompt]>
[prompt]> dir /b
dll.c
dll.h
dll00.c
main00.c
main01.c

[prompt]>
[prompt]> :: Build initial .dll (and an executable depnding on it)
[prompt]> cl /nologo /MD /DDLL dll.c  /link /NOLOGO /DLL /OUT:libdll.dll /IMPLIB:libdll_.lib
dll.c
   Creating library libdll_.lib and object libdll_.exp

[prompt]>
[prompt]> lib /OUT:libdll.lib libdll_.lib
Microsoft (R) Library Manager Version 14.43.34809.0
Copyright (C) Microsoft Corporation.  All rights reserved.


[prompt]>
[prompt]> cl /nologo /MD /W0 main00.c  /link /NOLOGO /OUT:main00.exe libdll.lib
main00.c

[prompt]>
[prompt]> dir /b
dll.c
dll.h
dll.obj
dll00.c
libdll.dll
libdll.lib
libdll_.exp
libdll_.lib
main00.c
main00.obj
main01.c
main_win.exe

[prompt]>
[prompt]> :: Add new functionality (*.dll(s)) and another executable depending on it
[prompt]> cl /nologo /MD /DDLL dll00.c  /link /NOLOGO /DLL /OUT:libdll00.dll
dll00.c
   Creating library libdll00.lib and object libdll00.exp

[prompt]>
[prompt]> lib /OUT:libdll.lib libdll_.lib libdll00.lib
Microsoft (R) Library Manager Version 14.43.34809.0
Copyright (C) Microsoft Corporation.  All rights reserved.

libdll00.lib(libdll00.dll) : warning LNK4006: __NULL_IMPORT_DESCRIPTOR already defined in libdll_.lib(libdll.dll); second definition ignored

[prompt]>
[prompt]> cl /nologo /MD /W0 main01.c  /link /NOLOGO /OUT:main01.exe libdll.lib
main01.c

[prompt]>
[prompt]> dir /b
dll.c
dll.h
dll.obj
dll00.c
dll00.obj
libdll.dll
libdll.lib
libdll00.dll
libdll00.exp
libdll00.lib
libdll_.exp
libdll_.lib
main00.c
main00.exe
main00.obj
main01.c
main01.exe
main01.obj

[prompt]>
[prompt]> :: Run the 2 executables
[prompt]> main00.exe
  [dll.c] (7) - [dllFunc00]:  ARG0: dll.dll

Done.


[prompt]>
[prompt]> main01.exe
  [dll00.c] (7) - [dll00Func00]:  ARG0: dll00.dll

Done.


[prompt]>
[prompt]> :: List .exes dependencies
[prompt]> dumpbin /nologo /dependents main00.exe

Dump of file main00.exe

File Type: EXECUTABLE IMAGE

  Image has the following dependencies:

    libdll.dll
    KERNEL32.dll
    VCRUNTIME140.dll
    api-ms-win-crt-stdio-l1-1-0.dll
    api-ms-win-crt-runtime-l1-1-0.dll
    api-ms-win-crt-math-l1-1-0.dll
    api-ms-win-crt-locale-l1-1-0.dll
    api-ms-win-crt-heap-l1-1-0.dll

  Summary

        1000 .data
        1000 .pdata
        1000 .rdata
        1000 .reloc
        1000 .text

[prompt]>
[prompt]> dumpbin /nologo /dependents main01.exe

Dump of file main01.exe

File Type: EXECUTABLE IMAGE

  Image has the following dependencies:

    libdll00.dll
    KERNEL32.dll
    VCRUNTIME140.dll
    api-ms-win-crt-stdio-l1-1-0.dll
    api-ms-win-crt-runtime-l1-1-0.dll
    api-ms-win-crt-math-l1-1-0.dll
    api-ms-win-crt-locale-l1-1-0.dll
    api-ms-win-crt-heap-l1-1-0.dll

  Summary

        1000 .data
        1000 .pdata
        1000 .rdata
        1000 .reloc
        1000 .text

Might also want to check:

  • [MS.Learn]: Overview of LIB

  • [MS.Learn]: Linker options

  • [SO]: Discover missing module using command-line ("DLL load failed" error) (@CristiFati's answer)

  • [SO]: LNK4006, LNK4221 warnings when using static library that includes another static library

  • [SO]: LNK2005 Error in CLR Windows Form (@CristiFati's answer)

发布评论

评论列表(0)

  1. 暂无评论