Situation:
i have a static library "lib1.a" ;
a second static library "lib2.a" that uses the functions of "lib1.a";
an application that directly uses just the functions of "lib2.a".
When i link the application i have to pass to the application dependencies also "lib1.a" even if the application do not calls directly none of lib1 functions. Lib2 is a sort of more high level wrapper library.
Is there a way to link lib1 inside lib2 (a sort of intermediate linking) so that the "app" does not even know about the existence of lib1?
I know that i can scompact lib1.a and include the objects files inside lib2.a but is there another way so that is done automatically and JUST the USED object files are included inside lib2? Linke when you link the final app.
{app} -uses-> {lib2} -uses-> {[lib1]}
Cheers,
Davide
is there another way
No, there is not (on any UNIX-like system I know of).
The best you can do, when using GNU-ld or gold, is to write a libcombined.a as a linker script, containing -l2 -l1, and point the application to it.
Related
I feel like I'm missing some key idea with this one.
I have a library that I'd like to create a CMakeLists.txt file for. I want to link against it with different applications.
This library expects a conf.h file to be defined. The application has to provide this. The library expects it. What is this relationship called?
My current solution in CMakeLists.txt is to have a variable like:
...
target_include_directories(lib PUBLIC
${CONF_DIR}
)
And then have CONF_DIR be defined by the application. This is uncool, because I can't have multiple applications linking against it.
The only other alternative is to keep a copy of the entire source library inside the application folder, which is also uncool.
I'm looking to maximize reusability. How do I approach this?
Side note: For anyone who's familiar, the library in question is STM32Cube's HAL library, and the pesky file is stm32h7xx_hal_conf.h.
This is a very common approach, when a library requires configuration. FreeRTOS would be another example.
I don't see the issue with modifying the target_include_directories for the library from the App's CMakeLists.txt.
Usually, I create a function to handle the library set-up. The call site would look something like this:
add_stm32_hal_lib(
PATH drivers/STM32H7xx_HAL_Driver
EXTRA_INCLUDES path/to/config
)
# ...
target_link_libraries(app PUBLIC stm32_hal)
The contents of the EXTRA_INCLUDES parameter get shoved into target_include_directories of the static library.
You can't do anything about this, so you'll have to copy the library code.
The header file is used during library compilation stage, so its code ends up being hardwired into the final binary. Because of this, if you want to change some parameters from the header, you need to recompile the library from scratch.
Ideally, the library should be rewritten in such way, that all parameters that are contained in the header can be set up dynamically, during the runtime, using some additional configuration API.
I want to make a static .a library for my project from multiple sources, some of them define weak functions and others implements them. Let's say as example I have :
lib1.c :
void defaultHandler()
{
for(;;);
}
void myHandler() __attribute__((weak, alias ("defaultHandler")));
lib2.c :
void myHandler()
{
/* do my stuff here */
}
Then I want to put them into one single library, so that it seems transparent for the end application
$ ar -r libhandlers.a lib1.o lib2.o
But there is now 2 symbols myHandler in libhandlers :
$ nm libhandlers.a | grep "myHandler"
00000001 W myHandler
00000581 T myHandler
And then when using the lib, the weak reference is linked. The only solution I have for the moment is to not include in the library lib2.c but to add it as source in the application's Makefileā¦ that's not satisfying since I would like to provide only a few libraries to use and not a whole bunch of files.
The --whole-archive option is also not satisfying since I work on embedded system and I don't want to include all things I don't need.
Is there a way to compile the library so that the weak symbol disappear if a strong one is provided?
NOTEĀ : I'm using arm-none-eabi-gcc v4.8
This is a byproduct of the way that .a libraries work - they're simply a collection of .o files.
What happens at compile link time is that the first reference to the name gets resolved to the weak reference and the strong name never gets a look in.
You can test this yourself by actually making both the identical name and strong and you'll see exactly the same behaviour.
If you want the strong references resolved first, then put them earlier in the archive, or create a separate strong archive and link that first in the link-line.
While not directly applicable to your case, as you're using an embedded environment, weak vs. strong references come into force properly when creating/consuming .so dynamic libraries rather than .a archives. When you create a .so, all the weak references that make up the library will not generate an error, and only one of them will be used for the final product; and if there is a strong definition anywhere then it gets used rather than any of the weak ones (this only works properly if, when you're creating a .so, you link all the .o files that make it up separately, or use the --whole-archive when creating the .so if linking to a .a).
I am using the DDK to build a project. Several of the build targets generate small internal libraries -- for simplicity, let's call them LibA.lib, LibB.lib, and LibC.lib. But the code for LibA references code from LibB and LibC. To use LibA in a project, you also need to include LibB.lib, and LibC.lib to resolve all of the dependencies. What I want to do is link LibB and LibC into LibA such that a user only needs to include LibA.lib. How can I accomplish this?
The SOURCES file for LibA looks something like this:
TARGETNAME=LibA
TARGETTYPE=LIBRARY
TARGETPATH=..\lib\$(DDKBUILDENV)
INCLUDES = .; \
..\LibB; \
..\LibC; \
$(CRT_INC_PATH) \
$(SDK_INC_PATH)
SOURCES = LibA_main.cpp \
LibA_file2.cpp \
LibA_file3.cpp
I understand that you can manually link libraries with link.exe; e.g.,
link.exe /lib LibA.lib LibB.lib LibC.lib
But if possible, I would like some way to achieve this same effect as a part of the build process for LibA, because some targets at a later point of the build process rely on LibA.
Thanks!
I realize this is a late answer and it may not even be what you want in the end. However, ddkbuild.cmd has a pretty nifty mechanism to run actions before and after a build inside a particular directory.
We use this in one of our driver libraries which necessarily gets built as a number of static libraries and as a final step linked into one big static library much like you want. If you are able to use something like ddkbuild.cmd in your project, this would provide a solution and it's a solution that would work in automated builds, too.
NB: as far as I'm aware you cannot achieve what you want directly with build.exe. However, it's well possible that with some make (NMake) file acrobatics you could achieve a similar result. So the question is whether it's worth reinventing the wheel when there is one already.
I have encountered the same situation as you. Google a lot of and still have no solution. Fortunately, I found a way to resolve it finally. You can try it, add the below statement in your libA sources file.
LIBRARIAN_FLAGS = $(LIBRARIAN_FLAGS) libB.lib libC.lib
The lib utility can combine libraries. Using your example, the command would be:
lib /out:CombinedLib.lib LibA.lib LibB.lib LibC.lib
In my SConscript I have the following line:
Program("xtest", Split("main.cpp"), LIBS="mylib fltk Xft Xinerama Xext X11 m")
How do I get scons to use mylib.a instead of mylib.so, while linking dynamically with the other libraries?
EDIT: Looking to use as few platform specific hacks as possible.
Passing the full filepath wrapped in a File node will force static linking. For example:
lib = File('/usr/lib/libfoo.a')
Program('bar', 'main.c', LIBS = [lib])
Will produce the following linker command line
g++ -o bar main.o /usr/lib/libfoo.a
Notice how the "-l" flag is not passed to the linker for this LIBS entry. This effectively forces static linking. The alternative is to modify LINKFLAGS to get what you want with the caveat that you are bypassing the library dependency scanner -- the status of the library will not be checked for rebuilds.
To make this platform independent you append the env['SHLIBSUFFIX'] onto the library you want to use. env['SHLIBSUFFIX'] gives you this environments suffix for shared libraries.
You also have the ['SHLIBPREFIX'], ['LIBPREFIX'], ['LIBSUFFIX'] and ['PROGSUFFIX'], all useful for situations like this.
Edit:
I obviously haven't made myself understood, so I will clarify.
The return value of these lookups are strings to the pre/suffixes that platform uses. In that way you can refer to the file you need on each platform. Note that you cannot use it as a pure string, it has to be embedded as a file node as BennyG suggests. Working with nodes are anyway the best solution as file nodes are much more versatile than a string.
Hope this helps.
Same source, all that, just want a static and shared version both. Easy to do?
Yes, it's moderately easy. Just use two "add_library" commands:
add_library(MyLib SHARED source1.c source2.c)
add_library(MyLibStatic STATIC source1.c source2.c)
Even if you have many source files, you can place the list of sources in a Cmake variable, so it's still easy to do.
On Windows you should probably give each library a different name, since there is a ".lib" file for both shared and static. But on Linux and Mac you can even give both libraries the same name (e.g. libMyLib.a and libMyLib.so):
set_target_properties(MyLibStatic PROPERTIES OUTPUT_NAME MyLib)
But I don't recommend giving both the static and dynamic versions of the library the same name. I prefer to use different names because that makes it easier to choose static vs. dynamic linkage on the compile line for tools that link to the library. Usually I choose names like libMyLib.so (shared) and libMyLib_static.a (static). (Those would be the names on linux.)
Since CMake version 2.8.8, you can use "object libraries" to avoid the duplicated compilation of the object files. Using Christopher Bruns' example of a library with two source files:
# list of source files
set(libsrc source1.c source2.c)
# this is the "object library" target: compiles the sources only once
add_library(objlib OBJECT ${libsrc})
# shared libraries need PIC
set_property(TARGET objlib PROPERTY POSITION_INDEPENDENT_CODE 1)
# shared and static libraries built from the same object files
add_library(MyLib_shared SHARED $<TARGET_OBJECTS:objlib>)
add_library(MyLib_static STATIC $<TARGET_OBJECTS:objlib>)
From the CMake docs:
An object library compiles source files but does not archive or link
their object files into a library. Instead other targets created by
add_library() or add_executable() may reference the objects using an
expression of the form $<TARGET_OBJECTS:objlib> as a source, where
objlib is the object library name.
Simply put, the add_library(objlib OBJECT ${libsrc}) command instructs CMake to compile the source files to *.o object files. This collection of *.o files is then referred to as $<TARGET_OBJECT:objlib> in the two add_library(...) commands that invoke the appropriate library creation commands that build the shared and static libraries from the same set of object files. If you have lots of source files, then compiling the *.o files can take quite long; with object libraries you compile them only once.
The price you pay is that the object files must be built as position-independent code because shared libraries need this (static libs don't care). Note that position-independent code may be less efficient, so if you aim for maximal performance then you'd go for static libraries. Furthermore, it is easier to distribute statically linked executables.
There is generally no need to duplicate ADD_LIBRARY calls for your purpose. Just make use of
$> man cmake | grep -A6 '^ *BUILD_SHARED_LIBS$'
BUILD_SHARED_LIBS
Global flag to cause add_library to create shared libraries if on.
If present and true, this will cause all libraries to be built shared unless the library was
explicitly added as a static library. This variable is often added to projects as an OPTION
so that each user of a project can decide if they want to build the project using shared or
static libraries.
while building, first (in one out-of-source directory) with -DBUILD_SHARED_LIBS:BOOL=ON, and with OFF in the other.
Please be aware that previous answers won't work with MSVC:
add_library(test SHARED ${SOURCES})
add_library(testStatic STATIC ${SOURCES})
set_target_properties(testStatic PROPERTIES OUTPUT_NAME test)
CMake will create test.dll together with test.lib and test.exp for shared target. Than it will create test.lib in the same directory for static target and replace previous one. If you will try to link some executable with shared target it will fail with error like:
error LNK2001: unresolved external symbol __impl_*.`.
Please use ARCHIVE_OUTPUT_DIRECTORY and use some unique output directory for static target:
add_library(test SHARED ${SOURCES})
add_library(testStatic STATIC ${SOURCES})
set_target_properties(
testStatic PROPERTIES
OUTPUT_NAME test
ARCHIVE_OUTPUT_DIRECTORY testStatic
)
test.lib will be created in testStatic directory and won't override test.lib from test target. It works perfect with MSVC.
It's possible to pack eveything in the same compilation breath, as suggested in the previous answers, but I would advise against it, because in the end it's a hack that works only for simple projects. For example, you may need at some point different flags for different versions of the library (esp. on Windows where flags are typically used to switch between exporting symbols or not). Or as mentionned above, you may want to put .lib files into different directories depending on whether they correspond to static or shared libraries. Each of those hurdles will require a new hack.
It may be obvious, but one alternative that has not been mentionned previously is to make the type of the library a parameter:
set( ${PROJECT_NAME}_LIBTYPE CACHE STRING "library type" )
set_property( CACHE ${PROJECT_NAME}_LIBTYPE PROPERTY STRINGS "SHARED;STATIC" )
add_library( ${PROJECT_NAME} ${PROJECT_NAME}_LIBTYPE ${SOURCE_FILES} )
Having shared and static versions of the library in two different binary trees makes it easier to handle different compilation options. I don't see any serious drawback in keeping compilation trees distinct, especially if your compilations are automated.
Note that even if you intend to mutualize compilations using an intermediate OBJECT library (with the caveats mentionned above, so you need a compelling reason to do so), you could still have end libraries put in two different projects.