Linking priority in cmake - cmake

Is there any way i can set a priority at linking some libs/classes in cmake?
I have a library BFciLib that i use in my class, and have added it in cmake like this
target_link_libraries(Main PRIVATE BFciLib GL ${GTKMM_LIBRARIES})
I had to overwrite some of the method of that lib so that i am able to develop on my pc (without having to connect my device for which the mentioned lib is used etc).
So i have C wrapped those methods, and basically now i have 2 definitions of the same method.
I need to link my newly created methods to be used in MyClass, instead of the original ones(the ones of the lib) without modifying the class. But still use the library since are more other methods used. So i believe that is to be done in the cmake file.
For that i have added another executable, but i fail to see what more should i do:
#new exe
add_executable(
NewMain
src/main.cpp
src/MyClass.hpp
src/MyClass.cpp
src/ClassWithCWrappers.hpp
src/ClassWithCWrappers.cpp
)
target_link_libraries(NewMain PRIVATE BFciLib GL ${GTKMM_LIBRARIES})
This still returns "duplicate definition" error.
How am i supposed to do?

Don't try to override global functions. Create an interface abstraction that can be implemented with either your device library or your PC alternative. Then have separate device and PC builds where you link in only one implementation each.

Related

Creating a executable out of a library in CMake, and linking the library in another library

I am trying to link foo-lib library into another target bar-lib however doing the following results in an error.
(add_executable):
Cannot find source file: foo-lib
How can I create an executable out of a library and the same library can be linked into another target?
add_library(foo-lib STATIC src/foo.cpp)
add_executable(foo-ut foo-lib)
target_include_directories(foo-ut PRIVATE include)
target_link_libraries(foo-ut PUBLIC lib1 lib2)
# second library that links foo-lib
add_library(bar-lib STATIC src/bar.cpp)
add_executable(bar-ut bar-lib)
target_include_directories(bar-ut PRIVATE include)
target_link_libraries(bar-ut PUBLIC foo-lib)
This worked the way I wanted but I am not sure if I should be adding foo.cpp for the bar-ut target
add_executable(bar-ut src/foo.cpp src/bar.cpp)
I'm not going to question the design choices and what you need it for and if it is a good idea in any way. I will just provide you with a "scalable" way of doing this.
As the others pointed out add_executable() requires source files.
Now assuming that the source files that you use to create a static library contain a main() function. Then you can create (out of the same source files) an executable, by passing to the add_executable the same source files as you would to add_library.
As the program grows these would get lengthy, so what you should do is something that is no longer recommended by "CMake best practices" and that is to introduce a SOURCES variable. I.e.:
set(PROJECT_SOURCES source1.cpp source2.cpp source3.cpp)
set(PROJECT_HEADERS header1.h header2.h header3.h)
add_library(foo-lib STATIC ${PROJECT_SOURCES} ${PROJECT_HEADERS})
add_executable(foo-ut ${PROJECT_SOURCES} ${PROJECT_HEADERS}
As your program grows you would just add the respective files into the designated variables. Now as to possible improvements:
fabian mentioned a very good thing which is OBJECT libraries, since you are rebuilding the same files for both the executable and library you could just create an object library and link it. This would make it twice as fast (you only need to compile once).
Since these SOURCES are already once passed to some target, you could just get them from the target's properties via get_target_properties(MY_SOURCES foo-lib SOURCES) this would give you a variable MY_SOURCES that contains sources which are used by the target library.

How to link a shared library without having to export its internal targets

The following repro cmake project fail to configure. The goal is to create a shared library that internally consists of a couple of static libraries. I want the internal symbols and include paths etc to be exported from the shared library. To do that I make the internal libs PUBLIC link libraries. But then cmake tells me I need to export my target. I don't want to "pollute" my package config with a bunch of internal targets. Is there no way to "merge" internal targets (static libs) into the public exported target (shared lib) or hide it in the config targets file?
The SystemC::systemc imported target does not show up in my target file and it also don't generate any error. I assume that is because this target is already exported in its own package? If so, would that mean I need to make my internal libs packages and so imported targets to make them go away from my exported targets list?
cmake_minimum_required(VERSION 3.16)
project(mylib)
find_package(SystemCLanguage 2.3.3 CONFIG REQUIRED)
add_library(mysublib STATIC mysublib.cpp)
add_library(mylib SHARED mylib.cpp)
target_link_libraries(mylib
PUBLIC SystemC::systemc
PUBLIC mysublib
)
export(
TARGETS mylib
NAMESPACE MyLib::
FILE MyLibTargets.cmake
)
Error generated at configure
CMake Error in CMakeLists.txt:
export called with target "mylib" which requires target "mysublib" that is
not in any export set.
The goal is to create a shared library that internally consists of a couple of static libraries. I want the internal symbols and include paths etc to be exported from the shared library. To do that I make the internal libs PUBLIC link libraries.
So, first, I'll note that PUBLIC has nothing at all to do with symbol visibility. Your example mysublib doesn't have any INTERFACE properties, so you could make it PRIVATE to mylib and avoid the need to export mysublib.
However, if you do need mysublib in the INTERFACE of mylib, then you do need to export it, period. There is no way to, as you say "'merge' internal targets [...] into the public exported target [...] or hide it in the config targets file". But this is also not a real problem.
If you're concerned about people relying on mysublib, then you can set the EXPORT_NAME property of mysublib to something that indicates it's not meant to be used, like _private_mysublib:
set_target_properties(mysublib PROPERTIES EXPORT_NAME _private_mysublib)
If you want to be really aggressive about it, you could even make the name random:
string(RANDOM LENGTH 12 mysublib_export)
set_target_properties(mysublib PROPERTIES EXPORT_NAME "x${mysublib_export}")
Prepending an x makes sure it doesn't start with a number. There is also a remote chance of collision if you do this a lot. If you want to be absolutely safe, you should write a function that records the names it's already returned in a global property and tries again if it chooses a collision.
The SystemC::systemc imported target does not show up in my target file and it also don't generate any error. I assume that is because this target is already exported in its own package? If so, would that mean I need to make my internal libs packages and so imported targets to make them go away from my exported targets list?
You are correct: because SystemC::systemc is imported, it does not need to be (and in fact cannot be) re-exported. You're expected to call find_dependency(SystemCLanguage 2.3.3) in your MyLibConfig.cmake file, both within the build tree (export) and after install (install(EXPORT)).
If you want this behavior to apply to mysublib, then yes, you will need to split your projects apart. I don't see a compelling reason to do that, though. Either make mysublib PRIVATE or just live with it being renamed in your package config. Targets aren't precious and they're namespaced, so there's no real reason to worry.

How to create a wrapper library without exposing the underlying library being used?

Using Cmake I would like to know how to create a wrapper library and let the users link their application with this library only. Users don't need to specify the original library in their linker flags.
For instance, I create a wrapper library for libwebsockets, named libcustomws.
add_library(customws main.c)
target_link_libraries(customws websockets)
I would like user (with no libwebsockets installed) to be able to do:
add_executable(user_app user_app.c)
target_link_libraries(user_app customws pthread)
Wrapper libraries without any additional code from within your project can best be implemented with small INTERFACE library targets with the IMPORTED tag. Example for your scenario:
add_library(customws INTERFACE IMPORTED)
target_include_directories(customws
INTERFACE
/some/include/path)
target_link_libraries(customws
INTERFACE
websockets)
This way, targets that use this library can just
add_executable(user_app user_app.c)
target_link_libraries(user_app customws pthread)
and get the usage requirements from the target customws, in this case an include directory and a linked library (websockets) are propagated through customws. This can be a good thing, as it might encapsulate implementation details of the dependency (different flags for different platforms etc.).
If you like to automatically link to compiled code (that is part of your project), this can be easily done by adding a small intermediate OBJECT library, e.g.
add_libraray(customwsenhanced
OBJECT
someCode.c)
target_link_library(customwsenhanced
PUBLIC
customws)
Depending on whether someCode.c depends on the usage requirements of customws, the target_link_library for customwsenhanced could also use INTERFACE propagation. Now, a client application can go with
add_executable(user_app user_app.c)
target_link_libraries(user_app customwsenhanced pthread)
and will get both the compiled object code of someCode.c as well as flags etc. from customws.

Transitive dependencies and OBJECT libraries

A somewhat similar question was asked here, Transitive target_include_directories on OBJECT libraries, but there was no real solution.
If I have a project b that depends on a project a I can build them as follows
add_library(a OBJECT ${a_srcs})
add_library(b OBJECT ${b_srcs})
When I want to build an excutable using I them I can write
add_executable(p ${p_srcs} $<TARGET_OBJECTS:b> $<TARGET_OBJECTS:a>)
Is there any way to not have to specify $<TARGET_OBJECTS:a>? I assume this means telling CMake in some way that there is a dependency. If I was building SHARED libraries rather than OBJECT ones the b project would contain
target_link_libraries(b a)
which creates this dependency, but I can't find some equivalent way for OBJECT libraries.
Insofar as I understand it, in the current setup, no. The add_executable for target p can either
Link against some library (shared or static), or
Merge object sources into itself.
You have chosen (2). The only other option I see here is create a third library c that merges in a and b into a full-blown library (see Usage section at the bottom, which is likely where you were already looking).
When you do that, you could then target_link_libraries(c). The compiled OBJECTs cannot be linked against on their own. You have to merge the sources into either an executable or a library for them to be used.
Your add_executable call could be thought of basically doing add_executable(p ${p_srcs} ${a_srcs} ${b_srcs}), only instead of compiling a_srcs and b_srcs (which has been done previously), just copy in the compiled objects instead of redoing the work. That's a really simple / bad explanation, but that's the general idea.
The best way I have found to do this is to wrap the OBJECT library in an INTERFACE library.
add_library(a-objects OBJECT ${a_srcs})
add_library(b-objects OBJECT ${b_srcs})
add_library(a INTERFACE)
add_library(b INTERFACE)
target_link_libraries(a INTERFACE a-objects)
target_link_libraries(b INTERFACE b-objects)
target_sources(a INTERFACE $<TARGET_OBJECTS:a-objects>)
target_sources(b INTERFACE $<TARGET_OBJECTS:b-objects>)
My rule is to use the OBJECT library to set requirements, but only ever link against the INTERFACE library.
target_link_libraries(b-objects INTERFACE a)
Setting it up this way should allow you to link against both libraries like this:
add_executable(p ${p_srcs})
target_link_libraries(p PRIVATE b)

Compile-time warning about missing category method implementation

In our Xcode project we have multiple targets which share some common code. Each target includes only sources which are actually used by it. So when we use some category methods inside classes which are shared between targets we need to make sure that this category implementation is also included in all targets. Xcode doesn't show any warnings during compile time or link time if we forget to include category implementation to some of the targets. And it is troublesome to do it by hand.
Is there any automated way to ensure that category implementations are included to the targets which use them?
Categories are not automatically linked to the final binary.
They are linked if the linker finds the file where they are defined is used (which was a source of constant bug some times ago).
What you can do is use a special flag on the linker: '-all_load' and '-ObjC' in Build Settings/Linking/Other Linker flags
-ObjC Loads all members of static archive libraries that implement an Objective-C class or category.
And from this discussion:
-all_load and -force_load tell the linker to link the entire static archive in the final executable, even if the linker thinks that parts
of the archive are unused.
Another way I use to force link the module is to put a C function in the file:
void _linkWithNBLogClass(void)
{
NSLog(#"%s", __FUNCTION__);
}
and call it at the start of my application:
linkWithNBLogClass();
This way, by the console feedback, I'm sure my module is loaded and ready to be used.
The described behavior is as intended and much existing code would break, if it is changed.
Prior to formal protocols there was a need to declare methods without defining them. This was for optional methods, i. e. for declaring a delegate API. The usual technique was to declare a so-called informal protocol, consisting of a category on NSObject that is never implemented.
But if you have a category implementation, of course the completeness of it is checked against the category interface. (Otherwise you get a "Method definition for X is not found" error.) So you do not have a missing method in the category implementation, but a missing category implementation.
I do not think that this is a big deal. You will get a runtime error instead of a compile time error and simply add the category implementation to the target.