# Project modularization using object libraries

**URL:** <https://discourse.cmake.org/t/project-modularization-using-object-libraries/3825>\
**Category:** Code\
**Created:** [July 23, 2021, 4:09pm UTC](https://discourse.cmake.org/t/project-modularization-using-object-libraries/3825 "2021-07-23T16:09:55Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![mredolatti](https://discourse.cmake.org/user_avatar/discourse.cmake.org/mredolatti/32/1658_2.png) [@mredolatti](https://discourse.cmake.org/u/mredolatti)\
**Post date:** [July 23, 2021, 4:09pm UTC](https://discourse.cmake.org/t/project-modularization-using-object-libraries/3825/1 "2021-07-23T16:09:55Z")

</div>

Hello Everyone, I hope you’re all doing well!

While i have some experience developing, i’m still trying to get familiar with CMake and trying to come up with a practical layout for a kinda-large library i’m working on. It’s intended to be an open-source (not yet public though) library, ideally built statically, but allowing the end users to build dynamically as well.

The project will consist on:

- A main library (that should build either static or shared)
- Bindings for python and other languages
- Probably a native app that will use such library

The library is currently structured as follows:

/CMakeLists.txt  
/include/main.hpp  
/src/main.cpp  
/basics/CMakeLists.txt  
/basics/libA/CMakeLists.txt  
/basics/libA/include/basics/libA  
/basics/libA/src  
/basics/libB/CMakeLists.txt  
/basics/libB/include/basics/libB  
/basics/libB/src  
…  
/examples/CMakeLists.txt  
/examples/ex01.cpp

the Main library depends on libA which in turn depends on libB (both built as OBJECT libraries).

Code looks somewhat like this:

/basic/libA/CMakeLists.txt

```auto
add_library(A OBJECT)
target_include_directories(A include/)
target_sources(A PRIVATE src/a.cpp)

```

/basic/libB/CMakeLists.txt

```auto
add_library(B OBJECT)
target_include_directories(B include/)
target_sources(B PRIVATE src/b.cpp)
target_link_libraries(B PUBLIC A)

```

/basics/CMakeLists.txt

```auto
add_subdirectory(libA)
add_subdirectory(libB)

```

/CMakeLists.txt

```auto
add_library(main)
target_include_directories(main include/)
target_sources(main PRIVATE src/main.cpp)
target_link_libraries(main 
    PUBLIC A
    PUBLIC B)

```

/examples/CMakeLists.txt

```auto
add_executable(ex01 ex01.cpp)
target_link_libraries(ex01 main)

```

So far I was mostly working on writing logic, and unit tests. Since I’m linking the tests directly with object libs, everything was working smoothly. Now, when I decided to build an actual example using the library, things didn’t work unless I linked the example directly with ALL object libraries as well.

When I build my example and link against my Main library, it fails to link because of unresolved symbols in libB.

Inspecting the static lib with `nm` confirms this, showing an `U` next to the symbols for which the linker complains.

Now, i’ve done some reading and I see that object libraries don’t propagate transitively, only the usage requirements from them do (at least when using only target\_link\_libraries).

Is there any way for OBJECT libraries to expose their build requirements and dependencies as well? I’ve read about using the TARGET\_OBJECTS generator inside the `add_library` directive, but my understanding was that it only propagated the objects, and not the usage/interface requirements.

Is it possible (and convenient) to have this degree of modularization?  
Are object libraries intended to be used this way?

Sorry for the long post, and my english, and thank you very much in advance for taking the time to read!

---

<div class="post-metadata">

**Author:** ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)\
**Post date:** [July 23, 2021, 6:06pm UTC](https://discourse.cmake.org/t/project-modularization-using-object-libraries/3825/2 "2021-07-23T18:06:04Z")

</div>

You’ve chosen a tricky situation to get familiar with CMake. There is one detail you should be aware of in this case: for shared libraries on Windows, you’ll need each `OBJECT` library to also privately specify the export symbols for dependent `OBJECT` libraries because they’ll end up in the same library and need to know that they come from “the same library” rather than “from outside”.

> [@mredolatti](#):
>
> Is there any way for OBJECT libraries to expose their build requirements and dependencies as well? I’ve read about using the TARGET\_OBJECTS generator inside the `add_library` directive, but my understanding was that it only propagated the objects, and not the usage/interface requirements.

The non-inheritibility of the objects themselves through usage requirements (to avoid adding the same object multiple times into a library and triggering duplicate symbols) was an important design decision when we added it. It is odd that A’s objects are not available in `main`, but maybe you’re hitting the export symbol issue mentioned above?

---

<div class="post-metadata">

**Author:** ![mredolatti](https://discourse.cmake.org/user_avatar/discourse.cmake.org/mredolatti/32/1658_2.png) [@mredolatti](https://discourse.cmake.org/u/mredolatti)\
**Post date:** [July 23, 2021, 6:17pm UTC](https://discourse.cmake.org/t/project-modularization-using-object-libraries/3825/3 "2021-07-23T18:17:20Z")

</div>

Thank you for the response @ben.boeckel !

While the goal is to be compatible across windows/linux & MAC, I’m hitting this issue with CLANG in macos, and I’m on purpose no setting any CXX\_VISIBILITY variable to `hidden`.

So, if I use the OBJECT library approach on windows i’ll need to create export macros for each object library?

If OBJECT libraries don’t support doing this? what is the best way to accomplish this level of modularization? I’ve been looking at some popular large c++ repos and see that most people just throw huge large of files on a single `CMakeLists.txt`, although most of them also rely on relatively old versions of CMake. Is this usually the preffered approach when building a library that consists of multiple components?

---

<div class="post-metadata">

**Author:** ![mredolatti](https://discourse.cmake.org/user_avatar/discourse.cmake.org/mredolatti/32/1658_2.png) [@mredolatti](https://discourse.cmake.org/u/mredolatti)\
**Post date:** [July 23, 2021, 9:45pm UTC](https://discourse.cmake.org/t/project-modularization-using-object-libraries/3825/4 "2021-07-23T21:45:09Z")

</div>

Would you mind checking if this can be an acceptable workaround? It basically required that I link all object libraries to the main one, and not only the one i’m using directly. I’m guessing this should work properly if i had say a third obj-lib `c` on which both `a` and `b` depended, right?

> **[GitHub - mredolatti/cmake-objlib-poc](https://github.com/mredolatti/cmake-objlib-poc)**
>
> Contribute to mredolatti/cmake-objlib-poc development by creating an account on GitHub.

Once again, thank you very much!

---

<div class="post-metadata">

**Author:** ![craig.scott](https://discourse.cmake.org/user_avatar/discourse.cmake.org/craig.scott/32/20_2.png) [@craig.scott](https://discourse.cmake.org/u/craig.scott)\
**Post date:** [July 24, 2021, 5:24am UTC](https://discourse.cmake.org/t/project-modularization-using-object-libraries/3825/5 "2021-07-24T05:24:24Z")

</div>

My general advice regarding libraries is to only use object libraries if you have no other choice. While it may be a more familiar paradigm for some people coming from a more traditional Makefile background where you manage object files directly, a regular static library will very often be the better choice and be _much_ simpler to work with.

---

<div class="post-metadata">

**Author:** ![mredolatti](https://discourse.cmake.org/user_avatar/discourse.cmake.org/mredolatti/32/1658_2.png) [@mredolatti](https://discourse.cmake.org/u/mredolatti)\
**Post date:** [July 24, 2021, 11:58am UTC](https://discourse.cmake.org/t/project-modularization-using-object-libraries/3825/6 "2021-07-24T11:58:15Z")

</div>

Thank you very much @craig.scott.

Would you mind sharing what the shortcoming would be when using the approach above?

I’ve seen some articles where people build many small static libs (one for each module) and then use ar/libtool to combine them into a single shippable archive. Is this the recommended practice? Would this work if the end-user has passed -DBUILD\_SHARED\_LIBS?

Thanks!

---

<div class="post-metadata">

**Author:** ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)\
**Post date:** [July 24, 2021, 11:49pm UTC](https://discourse.cmake.org/t/project-modularization-using-object-libraries/3825/7 "2021-07-24T23:49:20Z")

</div>

You can use `add_library(libname STATIC)` to force a target to be a static library regardless of `BUILD_SHARED_LIBS`’ value.

---

<div class="post-metadata">

**Author:** ![mredolatti](https://discourse.cmake.org/user_avatar/discourse.cmake.org/mredolatti/32/1658_2.png) [@mredolatti](https://discourse.cmake.org/u/mredolatti)\
**Post date:** [July 25, 2021, 12:12am UTC](https://discourse.cmake.org/t/project-modularization-using-object-libraries/3825/8 "2021-07-25T00:12:55Z")

</div>

@ben.boeckel Thanks!. I know about that, but if the end user wants to build a shared library I assume i would need a specific command to package all the static libraries inside the final shared one.

I think I read some hacks for doing this as well. But My main concern is whether the strategy previously discussed is if this a valid approach for structuring a project consisting of many modules, which will be used (in different combinations) to build both a library and an application (using different subsets of the aforementioned modules).

To give you an idea of the modules I have:

- An Expected template class that is used by almost every other module
- A simple event loop
- An http client that works on top of such loop
- A logger that is used by almost every other module as well
- Business-logic specific components that depends on all of the modules mentioned below

Thank you once again folks!

---

<div class="post-metadata">

**Author:** ![mortytheshorty](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/m/919ad9/32.png) [@mortytheshorty](https://discourse.cmake.org/u/mortytheshorty)\
**Post date:** [March 24, 2023, 8:56am UTC](https://discourse.cmake.org/t/project-modularization-using-object-libraries/3825/9 "2023-03-24T08:56:26Z")

</div>

Just created the account to say thank you. I was looking for a simple solution to build a library which depends on many other modules I would like to let the user compile as a standalone or as the whole big library. So now I can focus on defining the dependencies for the standalone parts. Thank you very much, I wasn’t able to find something like this on StackOverflow!

---

<div class="post-metadata">

**Author:** ![ihnorton](https://discourse.cmake.org/user_avatar/discourse.cmake.org/ihnorton/32/3293_2.png) [@ihnorton](https://discourse.cmake.org/u/ihnorton)\
**Post date:** [March 29, 2023, 7:00pm UTC](https://discourse.cmake.org/t/project-modularization-using-object-libraries/3825/10 "2023-03-29T19:00:31Z")

</div>

> [@craig.scott](#):
>
> My general advice regarding libraries is to only use object libraries if you have no other choice.

> Would you mind sharing what the shortcoming would be when using the approach above?

+1. Apologies for the 👻post, but also curious about the reasons, since someone pointed me to this comment as a point against using object libs. [VTK appears to use](https://github.com/Kitware/VTK/blob/249ec5bef281b13b24184d09326083d24567e311/CMake/vtkModule.cmake#L3681-L3687) OBJECT libs for all modules; ITK and ParaView do not (AFAICT).

---

<div class="post-metadata">

**Author:** ![craig.scott](https://discourse.cmake.org/user_avatar/discourse.cmake.org/craig.scott/32/20_2.png) [@craig.scott](https://discourse.cmake.org/u/craig.scott)\
**Post date:** [March 29, 2023, 9:53pm UTC](https://discourse.cmake.org/t/project-modularization-using-object-libraries/3825/11 "2023-03-29T21:53:44Z")

</div>

> [@ihnorton](#):
>
> …also curious about the reasons…

Object libraries have some differences to static libraries which can catch people out.

- They only add their objects to things that link to them _directly_. Usage requirements are carried transitively to consumers (meaning things like PUBLIC compile flags and header search paths can propagate to consumers of consumers), but the objects themselves do not. A relatively common query we see in the forums and in CMake’s issue tracker is people mistakenly expecting objects to be added transitively. In comparison, static libraries work intuitively when linked through multiple levels of dependencies. CMake will propagate linking them as needed, even when something links to them as PRIVATE (static libraries need to propagate their used symbols up to the shared library, module library or executable).
- Adding objects to a shared library, module library or executable has a different effect to linking a static library into a shared library, module library or executable. When linking a static library, the linker will only need to go looking in the static library for symbols it has not yet been able to resolve. If nothing uses a symbol, that symbol won’t be added to the binary from the static library (unless you add linker flags to specifically ask for that behavior, which should be rare). Adding objects is different, it puts all the objects’ symbols into the linker’s “need to resolve these” bucket. Depending on linker flags, the symbols provided by objects might not be discarded and therefore can still be present in the final binary, even if nothing actually uses them. I’ve seen projects take advantage of this to add code which is useful when run from within gdb, but not otherwise executed by anything in the program (think: pretty-printing custom types).

There are probably more reasons I’ve temporarily forgotten, but those are the two main ones that come to mind.

---

<div class="post-metadata">

**Author:** ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)\
**Post date:** [March 30, 2023, 4:56pm UTC](https://discourse.cmake.org/t/project-modularization-using-object-libraries/3825/12 "2023-03-30T16:56:35Z")

</div>

> [@ihnorton](#):
>
> [VTK appears to use](https://github.com/Kitware/VTK/blob/249ec5bef281b13b24184d09326083d24567e311/CMake/vtkModule.cmake#L3681-L3687) OBJECT libs for all modules; ITK and ParaView do not (AFAICT).

`OBJECT` libraries are an implementation detail of “kit” builds. Basically it allows for decoupling the target properties from the resulting target artifact so that multiple sets of target objects can live in a single shared library at the end (in order to reduce runtime loader work on HPC machines where MPI and shared filesystems can be a significant overhead). It’s complicated and something I only recommend following if you _really_ need it (i.e., a customer reported a problem and this complexity is worth how much it solves the problem at hand).

ParaView uses this same code via the VTK API.

---

<div class="post-metadata">

**Author:** ![jthemphill](https://discourse.cmake.org/user_avatar/discourse.cmake.org/jthemphill/32/3916_2.png) [@jthemphill](https://discourse.cmake.org/u/jthemphill)\
**Post date:** [October 16, 2023, 5:01am UTC](https://discourse.cmake.org/t/project-modularization-using-object-libraries/3825/13 "2023-10-16T05:01:13Z")

</div>

I followed [the example code](https://cmake.org/cmake/help/latest/command/target_link_libraries.html#linking-object-libraries) describing how `target_link_libraries()` works with `OBJECT` libraries and built a small project myself, with [a `CMakeLists.txt` file I copy-pasted from the example](https://gist.github.com/jthemphill/f212b087482c701fa924261f741d09a7).

The example only describes the `CMakeLists.txt` file, so each of my source files calls a function from a source file it depends on:

```auto
// a.c
void a() {}

// obj.c
void a(); // target_link_libraries(obj PUBLIC A)
void obj() { a(); }

// b.c
void obj(); // target_link_libraries(B PUBLIC obj)
void b() { obj(); }

// main.c
void b(); // target_link_libraries(main B)
int main() { b(); }

// obj2.c
void obj(); // `target_link_libraries(obj2 PUBLIC obj)`
void obj2() { obj(); }

// main2.c
void obj2(); // `target_link_libraries(main2 obj2)`
int main() { obj2(); }

```

`make main` builds properly, but `make main2` crashes the build with

```auto
~/cmake-test/build$ make VERBOSE=1 main2
[83%] Building C object CMakeFiles/main2.dir/main2.c.o
/usr/bin/clang -DA -DOBJ -Os -DNDEBUG -MD -MT CMakeFiles/main2.dir/main2.c.o -MF CMakeFiles/main2.dir/main2.c.o.d -o CMakeFiles/main2.dir/main2.c.o -c /home/jhemphill/cmake-test/main2.c
[100%] Linking C executable main2
/usr/bin/cmake -E cmake_link_script CMakeFiles/main2.dir/link.txt --verbose=1
/usr/bin/clang -Os -DNDEBUG CMakeFiles/main2.dir/main2.c.o CMakeFiles/obj2.dir/obj2.c.o -o main2 -Wl,-rpath,/home/jhemphill/cmake-test/build libA.so 
/usr/bin/ld: CMakeFiles/obj2.dir/obj2.c.o: in function `obj2':
obj2.c:(.text+0x11): undefined reference to `obj'

```

I feel like this is as close to a copy-paste of the official documentation as I can build, and it fails because cmake doesn’t link `main2` to `obj`. Is this somehow not a faithful representation of the given example, or of the real-world use-case that it represents?

---

<div class="post-metadata">

**Author:** ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)\
**Post date:** [October 19, 2023, 1:24am UTC](https://discourse.cmake.org/t/project-modularization-using-object-libraries/3825/14 "2023-10-19T01:24:34Z")

</div>

`A` and `B` are `SHARED`. Did you make them `OBJECT` libraries?

---

<div class="post-metadata">

**Author:** ![jthemphill](https://discourse.cmake.org/user_avatar/discourse.cmake.org/jthemphill/32/3916_2.png) [@jthemphill](https://discourse.cmake.org/u/jthemphill)\
**Post date:** [October 19, 2023, 5:57am UTC](https://discourse.cmake.org/t/project-modularization-using-object-libraries/3825/15 "2023-10-19T05:57:55Z")

</div>

No, `A` and `B` are marked as `SHARED` in [my CMakeLists.txt file](https://gist.github.com/jthemphill/f212b087482c701fa924261f741d09a7), just as they are in [the documentation](https://cmake.org/cmake/help/latest/command/target_link_libraries.html#linking-object-libraries).

---

<div class="post-metadata">

**Author:** ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)\
**Post date:** [October 20, 2023, 12:50am UTC](https://discourse.cmake.org/t/project-modularization-using-object-libraries/3825/16 "2023-10-20T00:50:36Z")

</div>

I think this makes sense; maybe the tutorial needs updated? `OBJECT` libraries only add their objects to targets which _directly_ link to them; other ways of access only get the usage requirements. This ends up working:

```cmake
target_link_libraries(obj2 INTERFACE obj2.o $<TARGET_OBJECTS:obj> $<TARGET_OBJECTS:obj2.o>)

```

Cc: @betsy.mcphail

---

<div class="post-metadata">

**Author:** ![jthemphill](https://discourse.cmake.org/user_avatar/discourse.cmake.org/jthemphill/32/3916_2.png) [@jthemphill](https://discourse.cmake.org/u/jthemphill)\
**Post date:** [October 20, 2023, 6:14am UTC](https://discourse.cmake.org/t/project-modularization-using-object-libraries/3825/17 "2023-10-20T06:14:54Z")

</div>

Yep, that works!
