Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a best practices guide to distributing native C libraries for Windows?

Tags:

c

windows

dll

Does anyone know of a best practices guide for deploying native (no COM, no .NET) ANSI C Windows shared libraries?

Our product uses zlib and we distribute pre-built binaries on our downloads page that differ from those on the official zlib page. I'm guessing that the reason for this is to avoid mixing C runtimes. The official ones are built against msvcrt using VC++ 6.0 and VS.NET/2005/2008 will use msvcrt71/80/90.

What I want to do is to create VS2005/8 solutions and projects that will properly build the zlib for us and distribute them in place of what we have now. I'd like to do this carefully and distribute a properly useful package that I could also then send off to the curators of zlib for inclusion in their source distribution. Finding reliable information has proven troublesome, though. I have a bunch of books on Win32 programming and I've found a lot of articles on the web but none of this seems to do a thorough job of describing what you really need to distribute.

For example, zlib distributes the .exp, .lib stub and .def files where the fftw distributes the .def files but not the .lib stubs and .exp files. I guess I could just dump everything that looks useful in there (or just mirror what the official zlib currently has) but I'd like to know why it has to be there and in what directories it belongs.

Are there good examples of well-maintained Windows distributions of libraries that originated in the unix world?

Official zlib binary distributions (scroll down)

Our windows distributions

TO CLARIFY:

We distribute a library and provide the zlib to (mostly) Windows users since they typically don't have it available. I want our build of the zlib to be useful as a component in general, not just as a .dll that our product consumes. We're open source and widely used so we do want to make our entire build environment available and easily adaptable to any compiler you'd like to use.

like image 357
Dana Robinson Avatar asked Nov 05 '22 19:11

Dana Robinson


2 Answers

As you know, mixing C runtimes is a real problem. So one dimension of a DLL distribution will always be a choice of runtime. Sometimes that is not a free choice. A DLL that will be loaded at runtime by an existing application (think plugin) must (usually) match the choice of CRT used by the hosting application.

You might imagine that you could statically link the CRT into your DLL and avoid the concern. The problem that arises then is when you have to pass allocated pointers between the DLL and its hosting app since most of the trouble with mixed runtimes comes from having more than one implementation of malloc() and free() in a process. With a carefully designed and implemented API for a DLL, this can be the solution, however.

Distributions like Lua Binaries described by Mark Rushakoff's answer use a large amount of build automation to arrange to make so many combinations of platform and compiler available. Maintaining the build process is a fair amount of work for its team. When a separate group decided to create a Windows installer for Lua to provide a simple first use experience for Windows users, they decided (I believe sensibly) to pick a single CRT version for their product and to require that all of the extension DLLs they ship with it are compiled against that single version.

One practice that you should follow as part of your release packaging is to use Dependency Walker to verify that the expected CRT is used, and that all other dependencies are either a system DLL, from your hosting application's installation, or also included in your package. Dependency walker can be run from a batch file, so it can be used as part of a regression test suite to do this validation automatically. When releasing projects based on Lua, for instance, I run my final build under Dependency Walker from the Makefile as part of the target that builds the installation package and use a perl script to inspect the log to verify that the only DLLs used are either part of my install or from the system.

As others have said, if your DLL is consumed by end users that don't expect to develop with it (such as a plugin to a larger application distributed indepently) then all you should need to package is the DLL itself (and any dependencies it has, end-user documentation, as so forth). In that case, you just make sure that the DLL uses the same runtime as the application.

If the DLL is for a developer community, then you are likely in the many-builds case of Lua Binaries. Each distribution package would contain the correctly build DLL, along with an import library (.LIB) and all documentation. For DLLs built by VS that are expected to be linked against code from other compilers, it can be friendly to include the .DEF file which documents the actual exported names. Modern MinGW doesn't actually need it, but users of Borland C or possibly languages other than C can use all the help they can get.

Given the recent rise in popularity of dynamic languages such as Lua, Perl, TCL, and Python that often can be easily bound to libraries implemented in C, it can also be greatly appreciated by those user communities if you can supply bindings to those languages, along with binaries compiled against the "local custom" for choice of CRT.

like image 139
RBerteig Avatar answered Nov 15 '22 00:11

RBerteig


As a point of reference, I'd like to bring up LuaBinaries. The short backstory is that since Lua is fairly configurable, they thought it would be good to have a "standard" distribution so that anyone could, for instance, distribute bytecode-compiled Lua scripts, and anyone using the "standard" Lua binaries would be able to run them with equivalent results.

You'll see in the Windows section that the downloads match the form Lua_5_1_4_Win32_{PLAT}{VER}_lib.zip. {PLAT} can be Cygwin, VC[6-9], MinGW, or just DLL, among others.

If you were to grab, for instance, lua5_1_4_Win32_vc9_lib.zip, you'd find just a lua5.1.lib file (plus headers), because that's the static library (and this one was compiled in VS2008).

lua5_1_4_Win32_dll9_lib.zip contains lua5.1.lib and lua5.1.dll - you can link against that .lib at compile time, and that's really all you need.

If your only target is Visual Studio, the .lib that gets generated when you compile to DLL should be the only file you need besides the DLL and headers -- unless you want your users to just call LoadLibrary and GetProcAddress to access all of your DLL's functionality.

As far as I've been able to tell, the only need for a .def file is to interoperate DLLs between MinGW and VS. My understanding was that a long time ago, VS used .def files in addition to .libs, but now all the information VS needs is contained only in the .lib. You can convert between .lib and .def files (if you can't compile code on one or the other), but it's a bit of a hassle -- you'll have to use pexports to generate a .def file, for instance.

Hopefully LuaBinaries is a good reference for how to support the many Win32 compilers out there. But I'm really not sure if it's necessary to make a .lib stub for each version of VS, because I'm pretty sure I've sent a VS2003 .lib and .dll to someone using VS2008, without trouble.

like image 38
Mark Rushakoff Avatar answered Nov 14 '22 23:11

Mark Rushakoff