"Linking" my static lib with a third-party static lib - cmake

I'm writing a CMake script that makes a static library MyLib. I'd like to concatenate it with a 3rd party static library AnotherLib. I try to accomplish this as follows:
"Deconstruct" AnotherLib to object files by invoking ar as a part of ADD_CUSTOM_COMMAND.
Prepare an intermediate MyLibObj using ADD_LIBRARY(MyLibObj OBJECT ${MYLIB_SOURCES})
Make the final MyLib using (1) and (2) -- here is the problem. How to do this? Is it possible to make CMake treat the object files made in (1) as OBJECT library?

This CMake script merges several static libraries - but in a straightforward way, without the new OBJECT feature. It's a part of MERGE_STATIC_LIBS macro referenced in this answer.

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.

Linking priority in 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.

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.

Is all of a static library included in a final product after linking?

Suppose I create an iOS application. I include a static library. I create an object of a class that is defined and implemented in static library. This object doesn't use other classes defined in the library. Will all of the static library be present in the application I build? The idea is that much of the static library contains unused code and wouldn't need to be present.
I believe there a flags that help determine the behavior -- if someone can spell out how this works, I sure would appreciate it.
A static library is an archive of object files. If you link against a static library libfoo.a then
the linker by default will link into your final executable all and only those object files in libfoo.a
that are required to provide definitions for the public symbols that are referenced by the program.
More specifically, if the linker finds the library requested (via the option -lfoo) at a given
point in the commandline sequence of object files and libraries to be linked, then it will
extract from the archive and link into the executable each object file in the archive that provides
a definition for any symbol that remains undefined up to that point in the linkage.
In so doing, definitions of unused public symbols may be redundantly linked into
your program, but only if they are found in an object file (whether free-standing or a member of
a library) that is not completely redundant.
If you do not want to tolerate even those potential redundancies, then a combination of
compiler and linker options can eliminate them: see this answer

Converting static link library to dynamic dll

I have .lib file with its header (.h) file. This file have a few functions that need to be used in C# application.
After googling I found that I need to create a dynamic DLL from this static library and call this dynamic DLL from C# code using interop.
I have created a win32 project and selected type DLL.
Included header file and added .lib to additional dependencies.
I am able to see the functions defined in the static library (when I press ctrl + space).
As a total newbie I do not know how I can export the function, which is, in .lib with following signature:
void testfun( char* inp_buff, unsigned short* inp_len, char* buffer_decomp,unsigned *output_len,unsigned short *errorCode)
I want same signature in my dynamic DLL with a different name.
What to write in header file and .cpp file?
If you can recompile your lib, just add __declspec(dllexport) to the signatures of all of the functions you want to be exported.
void __declspec(dllexport) testfun( char* inp_buff, unsigned short* inp_len, char* buffer_decomp,unsigned *output_len,unsigned short *errorCode)
If you can't do that, then you can export them by writing a .def file instead. Using def files you can even change the name of a function as it is exported.
http://msdn.microsoft.com/en-us/library/28d6s79h.aspx
---- contents of mylib.def ----
LIBRARY
EXPORTS
testfun
newname=testfun2
Then when you link the dll, include mylib.def
link /dll /machine:x86 /def:mylib.def mylib.lib
Edit2:
note that pinvoke assumes that the functions you import will have _stdcall calling convention unless you say otherwise. So you might need to do this as well, in your C# code.
[DllImport("mylib.dll", CallingConvention=CallingConvention.Cdecl)]
Or, you could change your C++ code to be __stdcall
void __declspec(dllexport) __stdcall testfun( char* inp_buff, ...
This is what you can do
Add the following code to you .H file. rename "MYPROJECT" to your project name
#ifdef MYPROJECT_EXPORTS
#define MYPROJECT_API __declspec(dllexport)
#else
#define MYPROJECT_API _declspec(dllimport)
#endif
Go to Properties->C++->Preprocessor and Add the defenition - MYPROJECT_EXPORTS
Add MYPROJECT_API to all the functions you want the dll to expose eg:
MYPROJECT_API void Test();
Go to Project properties General -> Configuration Type change it to Dynamic Dll
You are done
Create new Dll project using Visual Studio Application Wizard, and check "Exports Symbols" in one of the Wizard steps. It creates sample Dll which exports class, function and variable. You can learn from this sample, how to do this.
Generally, every exported function is declared as __declspec(dllexport). In a client project it is declared as __declspec(dllimport). Dll code uses the constant which is defiled as __declspec(dllexport) inside of Dll project, and __declspec(dllimport) in any other place.
there are two versions of LIB can be generated,
the fist is the dynamic lib, (source file + header+ dynamic lib) --> to access the DLL
or static lib=(dynamic lib+DLL) --> (Source file+header) --> to access the DLL.
if you have the Dynamic Lib > there is no way to create the DLL (you cannot get something from nothing), dynamic lib is just an interface,
but if you have the Static Lib then there is no need to DLL to access it is functions.
Take a look at my answer to this question for a possible solution. Almost positive this will work for you...
In short: Enable the "Use Library Dependency Inputs" option in your Linker settings. If set to "true", it will force linking ALL symbols & code declared in every LIB specified as input to the project.
The issue here is not how the code is decorated, it's the extra step of creating a static library that contains all of the entry points, and trying to build the dll out of that.
If you go with the __delcspec approach and build the static library first, then try to link to it when building a DLL, you'll have to solve the dead-code stripping problem.
When you link, the obj srcs are used to find all of the decorated exports and dependencies are resolved, everything else is stripped. If you have no DLL src, so no obj files (except maybe a dll main), all of the code in the lib you want to export will be stripped (regardless of the attributes).
So, you either have to:
Tell the linker not to strip unused code, which is probably going to give you a lot of stuff you don't want.
Use a def file to expose the exports manually
Link the dll against the obj files used to create the lib instead of linking to the lib directly.
Or maybe create dummy code that references the functions you want to export from something you are exporting.