Handling circular references with #implib

Circular references are unpleasant things. They happen when a procedure in DLLA calls a procedure in DLLB, which calls a procedure in DLLA.

There's some evidence that circular references contribute to app instability. I don't know whether that's been proven, although there's anecdotal evidence in support of the idea. 

But one thing is certain - circular references make the process of compiling and linking apps more complicated. That's because when you compile an app that uses a DLL, you're actually linking in the DLL's corresponding LIB file. 

In the above example, DLLA needs the LIB file from DLLB, and DLLB needs the LIB file from DLLA. Which comes first?

Actually it doesn't matter which comes first - just realize that while you'll get a successful compile without a required LIB you won't get a successful link. You have to compile one of the DLLs first (compile succeeds, own LIB is created, link fails), then the other (compile succeeds, own LIB is created, link succeeds), then the first one again (compile succeeds, own LIB is recreated, link succeeds). 

That's fine for small systems with just a couple of DLLs and a few circular references, but if you have a lot of DLLs and a lot of circular references (any one of which may involve numerous DLLs) two passes through the compile process may not do the job. I've seen a system where if all the LIB files were deleted it took four or five passes to get a clean compile and link. 

The better way

There is a way to create all the LIB files at once, before you begin compiling. The only thing you need to do is make sure you have up to date EXP files, which are created as part of the application generation process. EXP files 

You'll need a hand coded project file (with the PRJ extension). Here's one called CreateLibs.prj:

#implib DLLA.LIB DLLA.EXP
#implib DLLB.LIB DLLB.EXP

Each line of the prj is simply an #implib statement followed by the name of the LIB to be created and the EXP to use when creating the LIB.

In early versions of C7 #implib was broken, so if it's not working for you it's probably time to update.

Now you need to build that project. Create a new hand coded solution:

The easiest way to do this is as a Win32 EXE. A Win32 DLL works also but you'll need to edit the EXP file as it contains a line of reminder text. In either case you won't need the output of this solution, you just need a way to execute the project (you could include it with one of your existing apps, but I prefer to have it on its own so I control when it gets compiled).

Make sure you add the .prj (legacy project) file and now the .cwproj file.

Now just compile the app and all the LIB files specified in the #implib statements will be created. With those in hand you can compile all your apps with circular references in one pass. 

If you want your implib solution to clean up after itself you can always add a post-build task to delete the resulting EXE.

And if you really want to get rid of those circular references, I strongly recommend George Lehman's ClarionMag article: Eliminating Circular DLL Calls