# Building a combined static library

**URL:** https://discourse.cmake.org/t/building-a-combined-static-library/12962
**Category:** Code
**Tags:** os:linux, os:windows
**Created:** [November 13, 2024, 12:54pm UTC](https://discourse.cmake.org/t/building-a-combined-static-library/12962 "2024-11-13T12:54:37Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![zaufi](https://discourse.cmake.org/user_avatar/discourse.cmake.org/zaufi/32/116_2.png) [@zaufi](https://discourse.cmake.org/u/zaufi)
#### Post date: [November 13, 2024, 12:54pm UTC](https://discourse.cmake.org/t/building-a-combined-static-library/12962/1 "2024-11-13T12:54:37Z")

</div>

I have a project that builds a static library. It depends on a dozen other projects (some of 'em are mine, also building static libraries) that look up through `find_package()` and have imported targets. Giving a build option `-DBUILD_COMBINED_STATIC=ON`, I’d like to be able to build a combined static library that includes all dependent static libraries into a single one. With GNU `ar`, I need to render an [MRI file](https://sourceware.org/binutils/docs/binutils/ar-scripts.html) and run `ar -M combined.mri`. With MSVC’s librarian, it’s possible by mentioning source libraries in CLI. Looks like a task for `add_custom_command()` + `add_custom_target()`…

The most problematic part is getting a list of paths to all static libraries a project’s target should combine. First of all, it must include indirect dependencies as well. Secondly, `LINK_LIBRARIES` (or `INTERFACE_LINK_LIBRARIES` of dependencies) may have generator expressions. The latter means I have to use `file(GENERATE…)`. Thanks to transitive `$<TARGET_PROPERTY:…>` genex evaluation, I can relatively easily get all dependencies recursively, having a list of all CMake targets at the end:

```auto
set_property(
    TARGET mylib
    PROPERTY
        TRANSITIVE_LINK_PROPERTIES INTERFACE_LINK_LIBRARIES
  )
file(
    GENERATE
    OUTPUT mylib-all-dependencies.lst
    CONTENT [=[
        $<LIST:REMOVE_DUPLICATES,$<TARGET_PROPERTY:mylib,INTERFACE_LINK_LIBRARIES>>
      ]=]
  )

```

The list of CMake targets needs to be resolved into particular file paths and then used to form an MRI file. It’ll be nice to use `$<LIST:TRANSFORM…>` somehow to replace a CMake target with `$<TARGET_PROPERTY:ARCHIVE_OUTPUT_NAME>` (with fallback to `OUTPUT_NAME`) for all list items… Apparently, it’s not possible for now anyway…

So, the maximum I can get after the initial CMake configuration step is this list of CMake targets that must be resolved into paths to particular static libraries (filtering out all non-static library dependencies in the middle). This also means that at build time, running `cmake -P render-mri-file.cmake` via `add_custom_xxx` command wouldn’t work cuz the script doesn’t have any targets, and even usage of imported targets is prohibited, so there is no way to resolve `OUTPUT_NAME` property into a filename. That eventually means `add_custom_command()` or `…_target()` should run `cmake` at build time to configure another “dummy” project that must perform all the same `find_package` calls, import all the same targets and reading the list file rendered by the top-level `cmake` configure step tries to render the MRI file…

That is the current “solution” I’m thinking about. I appreciate any advice (in case I’ve missed something).

The other approach I’ve tried, or I’m researching now, is to replace archive-creating commands somehow:

- It looks like it is impossible to do this per target because these commands are not properties of a target but global scope variables (set by a toolchain file?).
- Unlike shared libraries, static libraries do not have a “link” step, so overriding the `CXX_LINKER_LAUNCHER` property for the target won’t help as well ;-(
- Maybe add an `MRI` “language” and redefine `CMAKE_MRI_ARCHIVE_APPEND`, `CMAKE_MRI_ARCHIVE_CREATE`, and `CMAKE_MRI_ARCHIVE_FINISH` into CMake scripts that will start rendering MRI file (adding `CREATE <archive>` preamble), append `ADDLIB` commands, finalize the MRI script w/ `SAVE` command and execute `ar` at the end. But, I’m not sure (yet) how to use `add_library` and specify this MRI “language”…

Any alternative suggestions are also very welcome.

PS However, in the future, I’d prefer to have a solution to build combined static libraries out of the box in CMake. I will research how to do it and make an MR. Any thoughts on this implementation are also very welcome.

PSS Casting @craig.scott into discussion 😉

---

<div class="post-metadata">

### Author: ![jhol](https://discourse.cmake.org/user_avatar/discourse.cmake.org/jhol/32/5042_2.png) [@jhol](https://discourse.cmake.org/u/jhol)
#### Post date: [November 13, 2024, 5:17pm UTC](https://discourse.cmake.org/t/building-a-combined-static-library/12962/2 "2024-11-13T17:17:01Z")

</div>

> [@zaufi](#):
>
> It’ll be nice to use `$<LIST:TRANSFORM…>` somehow to replace a CMake target with `$<TARGET_PROPERTY:ARCHIVE_OUTPUT_NAME>` (with fallback to `OUTPUT_NAME`) for all list items… Apparently, it’s not possible for now anyway…

I found a way of doing list-maps with generator expressions, by writing a generator expression to apply to each element, escaping the generator expression and feeding it through `$<LIST:TRANSFORM>` and `$<GENEX_EVAL>`:

> [@Mapping lists in generator expressions](https://discourse.cmake.org/t/mapping-lists-in-generator-expressions/12833/3):
>
> Ok, that works! Thank you. It even works recursively!: set(targets picolibc::picolibc ZLIB::ZLIB) function(escape\_generator\_expression var) string(REPLACE "\>" "\_\_ANGLE\_R\_\_" ${var} "${${var}}") string(REPLACE "$" "$\<1:$\>" ${var} "${${var}}") string(REPLACE "," "$\<COMMA\>" ${var} "${${var}}") string(REPLACE "\_\_ANGLE\_R\_\_" "$\<ANGLE-R\>" ${var} "${${var}}") return(PROPAGATE ${var}) endfunction() set(prop "INTERFACE\_INCLUDE\_DIRECTORIES") set(get\_prop "$\<TARGET\_PROPERTY:\\1,${prop}\>…

---

<div class="post-metadata">

### Author: ![trmagma](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/t/74df32/32.png) [@trmagma](https://discourse.cmake.org/u/trmagma)
#### Post date: [November 18, 2024, 3:20pm UTC](https://discourse.cmake.org/t/building-a-combined-static-library/12962/3 "2024-11-18T15:20:19Z")

</div>

Have you taken so called object-libraries (at least for your own libraries) into accoun?. They are a similar to ar (archiv) Files on linux/unix and are going to solve an at least similar problem.

---

<div class="post-metadata">

### Author: ![zaufi](https://discourse.cmake.org/user_avatar/discourse.cmake.org/zaufi/32/116_2.png) [@zaufi](https://discourse.cmake.org/u/zaufi)
#### Post date: [November 18, 2024, 3:23pm UTC](https://discourse.cmake.org/t/building-a-combined-static-library/12962/4 "2024-11-18T15:23:53Z")

</div>

It doesn’t work for me cuz most of the libraries I need to combine into a single one are found via `find_package` in the project I build.
