Create archive of other library targets
Scenario
We have a complex code base with lots of smallish libraries generated by CMake. For internal use, we can just link against these libraries.
However, we also want to provide a public library for 3rd parties to use. The code in this library is implemented using many of our internal libraries. However, we only want to ship a single library. This is partly for convenience, and partly because we don’t want to expose more of our internal architecture than we need to.
Prior to moving to CMake, we had an archiving step that collapsed all the smaller libraries into a single exportable libraries. On some platforms, this was supported by the archiver (e.g. MacOS libtool). On others, we unpacked the sub-libraries and re-packed them into a single large library.
Feature request
Ability to create an 'archive' target that re-archives some set of libraries into a single output library.
- Primary purpose is to single archive from multiple for external distribution
- For development & testing, important that archive targets can be dependencies of other targets. Coherent compile and link interfaces must be created.
Considerations
Recursion
If I add a library to the archive and that library depends on other libraries, what happens?
Naive answer is that they get added recursively (as would happen with object libraries). However, this might not be desirable. One obvious problem is that 3rd party or OS library dependencies should not automatically be aggregated.
One possibility is to mark library targets as "willing to be archived". But this is a one-size-fits-all approached - some library targets might be good-to-archive in one context and not in another.
Possible solutions:
- flat inclusion only. Only libraries that are explicitly added as dependencies of the archive get re-archived.
- This is the least flexible but most robust solution.
- when adding dependencies to a library, can mark them as "archive with me". If the current library gets archived, the marked dependencies will be archived as well.
- This won't solve all issues, but will enable recursion to function correctly in some subset of cases.
- Is there value in having a never-archive flag that can be set on a target? This flag will cause a CMake error if the target is added to an archive. Can use to protect against "this won't do what you expect" scenarios.
Variant
Rather than have 'archive' as a target type, allow any add_dependency on a library to be tagged as:
- add_as_archive: archive dependent library within the library target being built, rather than adding it to the link interface
- archive_with_me: if the current target is archived, also archive this dependency
Risk with this model is that rather than calling out archiving as something unusual, it can be buried anywhere, which may cause coherency issues (see below) to be hidden.
Compile interfaces
As a first pass, the archive library should only affect the link interface. Any compile settings (include paths, options, ...) should be passed as if the archive was a normal library target.
Compatibility & coherency
There is a possibility that component libraries have incompatible compile or link options.
- static vs shared - OK to require all components to be same library type
- link options
- require them to be explicitly set on archive? Easier with flat archives
- attempt to unify?
- not necessarily easy without understanding what they do in a particular build-system
- might work on some platforms and not on others
For my scenarios I'm happy with a clean failure, but others might not be.
Extensions
Header files and include paths
For an in-tree build, header information can propagate as normal (see above).
Is there value in providing a mechanism to generate as an output the headers associated with a library? I see two points of complexity:
- For each component library, need to distinguish between headers that are required for the archive's public interface and normal headers. It might be that the published interface is more restrictive than the "public" interface of the archive when viewed in the tree.
- Is it possible to sensibly "normalise" the exported headers from several distinct libraries into a sane inclusion tree?