Kyudos
Kyudos

Reputation: 735

Visual-Studio: Efficiently Dealing With Cyclic Library Dependency

I have a cross-language (C++ <-> FORTRAN) cyclic dependency that would be too much of a pain to eradicate, so I live with it. It only requires an occasional /FORCE with no linker dependencies on my C++ library. I have been doing this manually as required, but the new version of our product has eight configurations (and possibly more in future) and it is becoming more of a pain.

I could create 'Forced' configurations for each build in the Visual Studio configuration manager, or 'Forced' copies of my project(s). However, both these approaches are a bit of a maintenance headache - changes to the project have to be spread to all configurations / project copies.

Can anyone think of a method of quickly building my 'forced' configurations without have to flip-flop settings or maintaining a sync'd configuration just for that purpose?

Upvotes: 1

Views: 197

Answers (1)

IanH
IanH

Reputation: 21451

As mentioned in the comments, if the DLL's are closely coupled it may make more sense just to combine them into a single DLL.

However, if two DLLs are still required, then one solution to this is to split one of the projects that currently builds a DLL into two - a static library project that also builds an import library and an exports file from a module definition file, and a second project that builds the DLL.

These two projects then bookend the construction of the other DLL.

For example, choosing to split the Fortran DLL, as I am more familiar with its project system:

  • Create a module definition file, with the same base name as will be used for the Fortran DLL, that lists in its exports section all the symbols that the Fortran DLL will export.

  • Create a Fortran static library project with a name different from that of the final Fortran DLL, that is configured to compile all the Fortran sources. In the project properties, as a custom build step add an additional invocation of the librarian along the lines of lib /DEF:xxx.def /OUT:xxx.dll /MACHINE:x86 (where xxx is the base name that will be used for the Fortran DLL - prepend configuration names as path suffixes as appropriate, vary the machine option as appropriate). Building this Fortran static library project will now generate two libraries - one with the object code (named after the project) and one that is the import library (named after the DLL) and an exports file (also named after the DLL).

[Note that with this approach the import library doesn't actually depend on the object code generated when the Fortran source files are compiled - use of the custom build step of the static library project is just a convenience. If you don't already have a module definition file for the Fortran DLL, an alternative approach is to instead supply the individual object files in the invocation of the librarian in the custom build step, and let the librarian determine the exports from any directives in the source files. However, I prefer module definition files to in source directives.]

  • Create a C++ project that holds all the C++ sources and builds the C++ DLL. That project should depend on the Fortran static library project and link against the import library generated by the Fortran static library project.

  • Create a Fortran DLL project, with the same base name as the Fortran DLL, that holds a dummy Fortran source file which only has comments inside it (this is just to avoid the build system getting confused). This DLL project should depend on the C++ DLL project, and link against the import library generated by the C++ project. In the project properties, under Linker > Input > Additional Dependencies, also add in the static library (not the import library!) and exports file generated by the Fortran static library project.

Other direct clients of the Fortran DLL should link against the import library generated by the custom build step of the Fortran static library project.

Variations on this approach are possible.

Upvotes: 1

Related Questions