Working with Visual Studios C++ manifest files

前端 未结 4 1157
梦谈多话
梦谈多话 2021-01-31 03:47

I have written some code that makes use of an open source library to do some of the heavy lifting. This work was done in linux, with unit tests and cmake to help with porting it

相关标签:
4条回答
  • 2021-01-31 03:57

    All components in your application must share the same runtime. When this is not the case, you run into strange problems like asserting on delete statements.

    This is the same on all platforms. It is not something Microsoft invented.

    You may get around this 'only one runtime' problem by being aware where the runtimes may bite back. This is mostly in cases where you allocate memory in one module, and free it in another.

    a.dll
        dllexport void* createBla() { return malloc( 100 ); }
    
    b.dll
        void consumeBla() { void* p = createBla(); free( p ); }
    

    When a.dll and b.dll are linked to different rumtimes, this crashes, because the runtime functions implement their own heap.

    You can easily avoid this problem by providing a destroyBla function which must be called to free the memory.

    There are several points where you may run into problems with the runtime, but most can be avoided by wrapping these constructs.

    For reference :

    • don't allocate/free memory/objects across module boundaries
    • don't use complex objects in your dll interface. (e.g. std::string, ...)
    • don't use elaborate C++ mechanisms across dll boundaries. (typeinfo, C++ exceptions, ...)
    • ...

    But this is not a problem with manifests.

    A manifest contains the version info of the runtime used by the module and gets embedded into the binary (exe/dll) by the linker. When an application is loaded and its dependencies are to be resolved, the loader looks at the manifest information embedded in the exe file and uses the according version of the runtime dlls from the WinSxS folder. You cannot just copy the runtime or other modules to the WinSxS folder. You have to install the runtime offered by Microsoft. There are MSI packages supplied by Microsoft which can be executed when you install your software on a test/end-user machine.

    So install your runtime before using your application, and you won't get a 'missing dependency' error.


    (Updated to the "How does Linux avoid the use of Manifest files" question)

    What is a manifest file?

    Manifest files were introduced to place disambiguation information next to an existing executable/dynamic link library or directly embedded into this file.

    This is done by specifying the specific version of dlls which are to be loaded when starting the app/loading dependencies.

    (There are several other things you can do with manifest files, e.g. some meta-data may be put here)

    Why is this done?

    The version is not part of the dll name due to historic reasons. So "comctl32.dll" is named this way in all versions of it. (So the comctl32 under Win2k is different from the one in XP or Vista). To specify which version you really want (and have tested against), you place the version information in the "appname.exe.manifest" file (or embed this file/information).

    Why was it done this way?

    Many programs installed their dlls into the system32 directory on the systemrootdir. This was done to allow bugfixes to shared libraries to be deployed easily for all dependent applications. And in the days of limited memory, shared libraries reduced the memory footprint when several applications used the same libraries.

    This concept was abused by many programmers, when they installed all their dlls into this directory; sometimes overwriting newer versions of shared libraries with older ones. Sometimes libraries changed silently in their behaviour, so that dependent applications crashed.

    This lead to the approach of "Distribute all dlls in the application directory".

    Why was this bad?

    When bugs appeared, all dlls scattered in several directories had to be updated. (gdiplus.dll) In other cases this was not even possible (windows components)

    The manifest approach

    This approach solves all problems above. You can install the dlls in a central place, where the programmer may not interfere. Here the dlls can be updated (by updating the dll in the WinSxS folder) and the loader loads the 'right' dll. (version matching is done by the dll-loader).

    Why doesn't Linux have this mechanic?

    I have several guesses. (This is really just guessing ...)

    • Most things are open-source, so recompiling for a bugfix is a non-issue for the target audience
    • Because there is only one 'runtime' (the gcc runtime), the problem with runtime sharing/library boundaries does not occur so often
    • Many components use C at the interface level, where these problems just don't occur if done right
    • The version of libraries are in most cases embedded in the name of its file.
    • Most applications are statically bound to their libraries, so no dll-hell may occur.
    • The GCC runtime was kept very ABI stable so that these problems could not occur.
    0 讨论(0)
  • 2021-01-31 03:57

    If a third party DLL will allocate memory and you need to free it, you need the same run-time libraries. If the DLL has allocate and deallocate functions, it can be ok.

    It the third party DLL uses std containers, such as vector, etc. you could have issues as the layout of the objects may be completely different.

    It is possible to get things to work, but there are some limitations. I've run into both of the problems I've listed above.

    0 讨论(0)
  • 2021-01-31 03:59

    I finally came to the conclusion that the only way to get this to work (besides statically linking everything) is that all third party libraries must be compiled using the same version of Visual Studios - ie don't use precompiled dlls - download the source, build a new dll and use that instead.

    Alternatively (and the solution we have to use where I work) is that if the third-party libraries that you need to use all are built (or available as built) with the same compiler version, you can "just" use that version. It can be a drag to "have to" use VC6, for example, but if there's a library you must use and its source is not available and that's how it comes, your options are sadly limited otherwise.

    ...as I understand it. :)

    (My line of work is not in Windows although we do battle with DLLs on Windows from a user perspective from time to time, however we do have to use specific versions of compilers and get versions of 3rd-party software that are all built with the same compiler. Thankfully all of the vendors tend to stay fairly up-to-date, since they've been doing this sort of support for many years.)

    0 讨论(0)
  • 2021-01-31 04:10

    If a third party DLL allocates memory that you need to free, then the DLL has broken one of the major rules of shipping precompiled DLL's. Exactly for this reason.

    If a DLL ships in binary form only, then it should also ship all of the redistributable components that it is linked against and its entry points should isolate the caller from any potential runtime library version issues, such as different allocators. If they follow those rules then you shouldn't suffer. If they don't then you are either going to have pain and suffering or you need to complain to the third party authors.

    0 讨论(0)
提交回复
热议问题