4

I have a c++ project that uses CMake to generate the build files. This project depends on external libraries for which I downloaded the necessary files from the internet (header, .lib and .dll). My project can compile and if the DLLs of the libraries are included in the PATH, or the DLLs are copied to the same place as the .exe of my project, it runs without a problem. Now I want to be able to run this program on another computer. For that, I need to know which DLLs I have to include alongside my .exe file.

I have seen that the DLLs dependencies of any given dll or exe can be found using MVSC dumpbin. For example for this main:

#include <QApplication>
#include <QStyleFactory>
#include <QFileDialog>
#include <QStandardPaths>
#include <opencv2/highgui/highgui.hpp>

int main(int argc, char** argv)
{
  // Create application
  QApplication app(argc, argv);
  app.setStyle(QStyleFactory::create(QStringLiteral("Fusion")));

  // Get file name
  QString file_name = QFileDialog::getOpenFileName(nullptr, QObject::tr("Open File"),
                                                QStandardPaths::displayName(QStandardPaths::HomeLocation),
                                                QObject::tr("Images (*.png *.xpm *.jpg)"));

  // Read image
  cv::Mat mat = cv::imread(file_name.toStdString());

  // Show image in opencv
  cv::namedWindow("display",cv::WINDOW_KEEPRATIO |cv::WINDOW_GUI_NORMAL );
  cv::imshow("display",mat);
  cv::waitKey(0);

  // Run application
  return app.exec();
}

The output of the command dumpbin /dependents main.exe is:

Microsoft (R) COFF/PE Dumper Version 14.28.29912.0
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file .\src\RelWithDebInfo\main.exe

File Type: EXECUTABLE IMAGE

  Image has the following dependencies:

    Qt5Widgets.dll
    opencv_world347.dll
    Qt5Core.dll
    VCRUNTIME140.dll
    VCRUNTIME140_1.dll
    api-ms-win-crt-runtime-l1-1-0.dll
    api-ms-win-crt-math-l1-1-0.dll
    api-ms-win-crt-stdio-l1-1-0.dll
    api-ms-win-crt-locale-l1-1-0.dll
    api-ms-win-crt-heap-l1-1-0.dll
    KERNEL32.dll
    SHELL32.dll

  Summary

        1000 .00cfg
        1000 .data
        2000 .idata
        1000 .pdata
        3000 .rdata
        1000 .reloc
        1000 .rsrc
        6000 .text

In this case, I need this list of DLLsfor my program to run. However, some are system DLLs (KERNEL32.dll, SHELL32.dll...) and some are libraries that are not system DLLs (Qt5Widgets.dll, opencv_world347.dll...).

Where should I decide to stop copying DLLsto ship my program? Should I ship it with KERNEL32.dll and SHELL32.dll, should I include api-ms-win*.dll or should I only include Qt5Widgets.dll, Qt5Core.dll, and opencv_world347.dll? How can I know from the list which are system DLLs and which are not?

PS2: I know that specifically for Qt there is windeployqt that will automatically handle the Qt DLLs part and that the VCRUNTIME140*.dll part is also handled by installing vc_redist

Note: The scope of this question is just to know where to stop. I am not interested in how to build an installer or how to automate that copy of the files or where to look for the dependent DLLs.

Note2: Questions Find dependent modules of dll and how do I include dll's such as kernel32.dll which my unmanaged dll needs did not provide an answer to my question.

apalomer
  • 1,895
  • 14
  • 36
  • Shipping Windows dlls (kernel32, shell32) is not allowed and would be pointless anyway as the target O/S already has them installed. – 500 - Internal Server Error Jul 12 '21 at 09:49
  • @500-InternalServerError I know of these two, but what about `api-ms-win*.dll`? are they system? should I copy them and put them to the folder where I install my executable? I have updated the question title to try to make it more clear that what I am looking for is the limit on where to stop copying dlls as they are part of the system already. – apalomer Jul 12 '21 at 09:53
  • 1
    *"should I only include Qt5Widgets.dll, Qt5Core.dll, and opencv_world347.dll"* ← yes – spectras Jul 12 '21 at 09:53
  • @spectras I know for this specific example. But more in general, how can I know from the list which are system DLLs and which are not? – apalomer Jul 12 '21 at 09:55
  • Start from the build side where the information is available instead of trying to reconstruct it by reverse-engineering your final artifact. You need whatever you build with, plus what they need, recursively. – spectras Jul 12 '21 at 09:58
  • @spectras The "plus what they need, recursively" is my problem. I can know that `Qt*.dll` and `opencv_world347.dll` are my dependencies. But imagine that opencv depends on `gdal204.dll`. If I ship my executable with only `Qt*.dll` and `opencv_world347.dll` it won't work because opencv depends on `gdal204.dll`. But when I run `dumpbin` on opencv_world347.dll` how can I know that I should cpy `gdal204.dll` but not `api-ms-*.dll`? Obviously, I'm looking for a way to automate this so I can modify my project and not have to generate the list manually if any external dependency changes. – apalomer Jul 12 '21 at 10:02
  • You cannot do this with `dumpbin`, the information does not exist there anymore. You depend on Qt and OpenCV, so you need them plus whatever they need. I don't mean the dlls, I mean the packages. Thus you need OpenCV package, with whatever dll it includes. — if you are not convinced, here is a further point: `dumpbin` will not find dynamically loaded DLLs (for instance Qt needs platform plugins to run correctly, but you won't find that with dumpbin) – spectras Jul 12 '21 at 10:05
  • Ok, I see what you mean. My problem is that I installed most of my dependencies with [miniconda](https://docs.conda.io/en/latest/miniconda.html). Miniconda puts all the dlls into the same folder. Since I installed miniconda packages also for other projects I don't know which dlls from all in the folder to copy. That's why I am looking for a way to list them using `dumpbin` and then copy from the miniconda folder. However, I need to know if one is missing because its from another folder or becaues it's system. – apalomer Jul 12 '21 at 10:10
  • @spectras should I include the `api-ms-*.dll` or not? – apalomer Jul 12 '21 at 10:13
  • 1
    No, those are windows files. — If you use some tool to manage dependencies (it's a good idea), then it is its job to provide you with those answers. It tool should have some command or some way to get a list of files you have to deploy. – spectras Jul 12 '21 at 10:21

2 Answers2

2

DLLs unfortunately don’t come with a marker that says “this one’s on the system” and “this one’s included with the program”. You have to decide if a particular DLL should be installed on a case-by-case basis.

There are some rules to follow to help you, though.

Legality

First, are you legally able to redistribute that DLL? For kernel32.dll and shell32.dll, the answer is “no”.

Microsoft provides lists of DLLs you're allowed to redistribute in a Redist.txt file and those ain’t on it.

So, these are out. They will invariably be provided by the user’s OS and should not be distributed by you.

API Sets

Second, are the things dependency walker/objdump/dumpbin picking up actually DLLs? In fact, no.

Things that start with api- or ext- are not even files on disk, they’re something called API sets which are a level of indirection on top of DLLs, or something... suffice to say, don’t include them. They trip up many dependency walking tools, and have to be manually excluded with a regex or something. Luckily that “API sets” link provides clear rules on their name format.

System Redistributables

Third, we have system DLLs like vcruntime that are on the Redist.txt list. Contrary to many comments on your question, you probably do want to redistribute these. These are redistributable DLLs provided by visual studio.

Microsoft highly recommends installing these with their own installers as a prerequisite to installing your app on the target device. They provide some fancy ways to allow these to be installed and also upgraded with the user’s windows update.

Microsoft also begrudgingly mentions that you are technically allowed to just copy the ones from your visual studio installation into your app’s install folder.

App installers deal with this problem in a plethora of ways, from completely ignoring it and hoping the user already has the DLLs, to embedding the redistributable installer inside the app’s. Thinking this through is especially important if you are targeting multiple windows versions, or if your dependencies require different DLL versions from yours or each other.

Third-party Dependencies

Finally, we have third party DLLs that Microsoft didn’t provide. Unless you also control your users’ systems, you don’t really have any option but to include them with your app in the same folder as your exe. You’ll also have to recursively include any of their dependencies, using the same rules.

To add to the confusion, some third parties (like maybe Intel’s MKL libraries? Don’t quote me on that) might have their own rules about redistribution that require something similar to Microsoft’s installer method above. OpenCV and QT don’t care, as far as I know. So bundle away.

MHebes
  • 2,290
  • 1
  • 16
  • 29
1

General case :

In my experience, the question often occurs much earlier in the development process.

As I see it : when one start an empty project, there is no need to embed any dll with i. As you said : system dlls are not to be provided.

At some point, one decide to use opencv, QT, or any external dependency in the project. At this point one may add the required headers in the making file (or the project/solution file), and dll in the build script.

In fact adding the dll to the shipment is part of the decision to use the dependency.

So the short answer to your question would be : you know which dll to embed, because it is specified in the documentation of the dependency you are trying to add to your project. (doc sample for opencv)

Specific case :

We can imagine, that someone find a piece of code in some obscure repository, without any documentation, history information and no "build" script or equivalent. this guy wants to build and ship it, so he must decide which dll to embed.

This guy would do exactly what you did : use a dependency walker to get all dependencies list, then would decide with his own judgement which one he wants to provide.

I assume that, if the application runs on windows, this guy would embed everything but the windows specific dlls, or do an installer.

mgueydan
  • 356
  • 1
  • 13