GET_RUNTIME_DEPENDENCIES has difficulties with windows API sets

GET_RUNTIME_DEPENDENCIES return dlls that do not physically exist and are part of the concept that Microsoft refers to as API sets.

Examples:

  • api-ms-win-core-libraryloader-l1-2-1.dll
  • api-ms-win-core-atoms-l1-1-0.dll
  • api-ms-win-core-winrt-error-l1-1-1.dll
  • api-ms-win-core-sidebyside-l1-1-0.dll
  • api-ms-win-core-localization-obsolete-l1-3-0.dll
  • api-ms-win-core-heap-l1-2-0.dll
  • api-ms-win-core-heap-l2-1-0.dll
  • api-ms-win-core-delayload-l1-1-1.dll
  • api-ms-win-core-libraryloader-l1-2-0.dll
  • api-ms-win-core-rtlsupport-l1-2-0.dll
  • api-ms-win-core-shlwapi-obsolete-l1-2-0.dll
  • api-ms-win-security-base-l1-2-0.dll
    There are other with the prefix “ext-ms-win” or “ext-ms”.

I can add exclusion patterns to GET_RUNTIME_DEPENDENCIES using pre_exclude_regexes but this is very fragile, because it depends on OS versions. I think it would be better if cmake handles these tricky aspects. It would fit better into the philosophy of cmake to provide abstraction of the OS, makesystem, …

References: On API-MS-WIN-XXXXX.DLL, and Other Dependency Walker Glitches

And why did MS added those to the VC runtime installers for e.g. Windows XP? Because sometimes they are needed.

I probably did not phrase the problem I have with the implementation in cmake very well.

I use GET_RUNTIME_DEPENDENCIES to figure out which external DLLs I need to add to my application kit. This can be tricky because I need to classify into “own”, “used 3rd party”, “part of the OS”, “part of the VC runtime”.
Ideally cmake could help classify the latter two classes.
I would not add “part of the OS” to my kit.
I would not add “part of the VC runtime” to my kit but reference it so that it can be installed seperatly.

The API set “DLLs” are (to my knowledge) not a physical DLL but an abstract concept which is part of the OS. So actually they should never be output by GET_RUNTIME_DEPENDENCIES.

They are “part” of Windows 8 and later. This is a problem when deploying to older Windows versions. That’s why they are part of the redistributable files.

Aha! Maybe the problem I am facing has a different reason. I am running Visual Studio 2015 on Windows 10.

file (GET_RUNTIME_DEPENDENCIES …)

returns

file Could not resolve file api-ms-win-crt-convert-l1-1-0.dll

Searching for api-ms-win-crt-convert-l1-1-0.dll locates in a multitude of locations, e.g. Appdata or installation directory of MS-Teams, MS-Office, MS-Onedrive, firefox, …
as well as
C:\Programs(x86)\Windows Kits\10\Redist…
C:\Programs(x86)\Microsoft Visual Studio 14.0\Common7…

As I build with VS2015 I would have expected that cmake locates the DLL in the installation directory of VS2015. Maybe it would even be better if it additionally treats it as something special, i.e. part of a redistributable. This would allow the programmer to decide if he/she wants to add the DLLs to his/her own kit or have it installed via the original Microsoft redistributable package.

With the way it is now I do not know if I should treat unresolved files as error. I could maintain a whitelist. This would force me to update this list with every new VS or redistributable version. This might better be done with cmake. Also I cannot add these files to my install kit because my code does not know where they are located.

Ideas warmely welcome.

I did this in the Python prototype the CMake implementation was based on. I remember @kyle.edwards and I discussing these cases, but can’t remember exactly what we decided to do about them. It seems that yes, PRE_EXCLUDE_REGEXES is the thing to do right now. Maybe we could add something like PRE_EXCLUDE_SYSTEM_LIBRARIES which is defined to be some sensible, but still restricted set of libraries for each platform (libSystem.dylib, api-ms-*.dll (and friends), and libc.so is about as high as I think we’d want to go).

Though this does open up a huge hole of keeping compatibility if we ever try to change it… Maybe we just have regexes for classes of libraries in a module?

# CMakeSystemLibraryRegexes.cmake
set(CMAKE_SYSTEM_WINDOWS_API_DLLS "...")
set(CMAKE_SYSTEM_APPLE_LIBSYSTEM "...")

Then users can use them as wanted in PRE_EXCLUDE_REGEXES and we can add new variables as new “classes” of libraries appear?

At first glance the provisioning of regex looks good. It could give users a good starting point for further modifications. Some ideas and design considerations.

  • the regex should probably depend on compiler+version, build platform, target platform
  • the required classes will need some thought especially if they abstract well from the OS

I think it’s sufficient to have a blanket exclusion for the pseudo DLL names that never actually is exist. MSVC runtime DLLs might warrant a per-toolchain regex, but who is packaging up more than one at a time anyways?

It seems that my initial assumption that windows API sets are the problem is incorrect. Hendrik Sattler’s reply (see above) started me having a closer look at the topic. See replies below.

I now have an additional dll that cannot be resolved: “gdiplus.dll”. It seems that GET_RUNTIME_DEPENDENCIES does not search in all required directories. The problem occurs on a Windows 7 build machine.