How to use object file with cmake?
Mimalloc docs say to link as the first object with an example of direct compiler invocation:
To ensure that the standard malloc interface resolves to the mimalloc library, link it as the first object file. For example:
> gcc -o myprogram mimalloc-override.o myfile1.c ...
However its not clear how or if this can even be done in a cmake project. I have specified it as the first source file like this:
add_executable(MyApp);
...
list(INSERT Sources 0 $<TARGET_OBJECTS:mimalloc-obj>) # Put mimalloc-obj before everything else in Sources.
list(APPEND APP_LIBRARIES pthread) # not documented but required for linking to succeed.
...
target_sources(MyApp PRIVATE ${Sources})
target_link_libraries(MyApp PRIVATE ${APP_LIBRARIES})
However when I look at the link command with VERBOSE=1 make, it is not placed anywhere near first. Despite this, the build succeeds and seems to run without any errors, I'm just not certain it's technically correct and would work the same on other systems.
Another point of confusion for me is the documentation saying this is specifically for "Unix-like systems". I am guessing this includes any Linux or Mac OSX system, but would mingw-based builds on Windows count as well?
Ah, I am not an expert in cmake so I do not know if this can be enforced inside cmake -- hopefully a cmake expert can chip in :-)
With regard to link order, as far as I know, on "Unix" systems the linker will process all archives (.a) and objects (.o) from left-to-right. There is a difference though how an archive and object file is processed: an object file is always linked completely and its exported symbols are available. On the other hand, with an archive only those object files in the archive that define a symbol that is already required by an earlier occurring object/archive are included. Here is a nice overview:
https://eli.thegreenplace.net/2013/07/09/library-order-in-static-linking
So, if we link, it we should either
-
make sure
mimalloc-override.ois first (so itsmallocetc is used), or at least occurring before any other object or archive defines it. Since the other definition is is usuallylibc.a, which implicitly comes last, in practice the requirement thatmimalloc-override.ocomes first is not really needed. (that is why it worked for you in cmake anyways) -
ensure
libmimalloc.ais linked right after all the object files that constitute our application (so itsmallocdefinition is used beforelibc.ais included). (Unless you use musl, the latter is a bit more tricky in reality though because usually libc is linked dynamically and there may be weak/strong symbols.).
So, the mimalloc manual recommends linking with the .o first as the most robust way, and as far as I know, it works on all common linkers (including msvc and I would think mingw as well). There is no "linker standard" though as far as I know (?) so no guarantees.
Generally, when overriding malloc, there is no common standard way to do it which is why mimalloc recommends different strategies depending on the platform and application.
Isn't .obj Windows object file? In that case, why not have 'target_link_libraries(mimalloc-override)` as the first entry?
I think I have found a definitive solution. It seems that using the $<TARGET_OBJECTS> generator is correct, but it should be linked as library, and not added as a source:
target_link_libraries( MY_TARGET PRIVATE $<TARGET_OBJECTS:mimalloc-obj>)
If cmake is 3.21 or greater, then apparently this is guaranteed to link before all other libraries.
From the documentation:
New in version 3.21.
The object files associated with an object library may be referenced by the $<TARGET_OBJECTS> generator expression. Such object files are placed on the link line before all libraries, regardless of their relative order.
--Source
Also I think I had misunderstood when I originally looked at the ordering of objects in the link command.
It was linking the mimalloc object file as the first library, but the project's sources (*.cc.o, etc.) will still appear before it in the command. Having project sources come first doesn't matter since none of them are defining malloc and related symbols themselves.
After CMake 3.24 there is a INTERFACE_LINK_LIBRARIES_DIRECT target property, which is used for this case:
Note: The
INTERFACE_LINK_LIBRARIES_DIRECTtarget property is intended for advanced use cases such as injection of static plugins into a consuming executable.
You can simply writing:
set_target_properties(target_name
PROPERTIES
INTERFACE_LINK_LIBRARIES_DIRECT $<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,EXECUTABLE>:mimalloc-obj>
)
then the mimalloc-obj target is propagated to the final executable.
However, if any target explicitly linked to mimalloc-obj (or privately linked to this target), then the object file is not propagated to the final executable. There is a solution [in the manual](https://cmake.org/cmake/help/latest/prop_tgt/INTERFACE_LINK_LIBRARIES_DIRECT.html#example-opt-in-static-plugins