CMake - Undefined reference with static libraries / not with shared libraries - static

After having installed ZeroC Ice from source, I have static (.a) and shared (.so) libraries in my install/lib/x86_64-linux-gnu directory.
When I try to compile a program with CMake, every thing is fine when I write (in target_link_libraries) :
"${ICE_DIR}/lib/x86_64-linux-gnu/libIce.so"
"${ICE_DIR}/lib/x86_64-linux-gnu/libIceUtil.so"
But I get undefined reference when I try with static libraries :
"${ICE_DIR}/lib/x86_64-linux-gnu/libIce.a"
"${ICE_DIR}/lib/x86_64-linux-gnu/libIceUtil.a"
How could you explain that ?
Thanks.

Related

What is the correct linking order of SFML external libs in static mode?

I'm trying to compile a simple SFML program test in static mode, i defined SFML_STATIC before any sfml header inclusion, i use "-s-d" prefixed libs for it.
I added the extlibs using this order:
mingw32
user32
gdi32
winmm
dxguid
libfreetype.a
libglew.a
libjpeg.a
libopenal.a
libsndfile.a
I finally got a lot of undefined reference to glfunctions and GLEW_ARB_texture... to FT_Fond_Face, etc.
(Note: When i use dynamic linking which needs Dll files, no reference problem occurs, i use Windows 7, sfml-gcc-4.7.1-tdm-32bit, and codeBlocks 13.12)
The correct linking order of sfml extlibs are given here for each of sfml module http://www.sfml-dev.org/faq.php#tr-cb-linker :)

Linking error while customizing zcalloc and zcfree functions in the zlib library

While integrating the Nurbs library (http://www.rhino3d.com/opennurbs) into my project, I run into the following linking error with the library zlib.
1>zlib.lib(deflate.obj) : error LNK2019: unresolved external symbol _zcfree referenced in function _z_deflateInit2_
1>zlib.lib(inflate.obj) : error LNK2001: unresolved external symbol _zcfree
1>zlib.lib(deflate.obj) : error LNK2019: unresolved external symbol _zcalloc referenced in function _z_deflateInit2_
1>zlib.lib(inflate.obj) : error LNK2001: unresolved external symbol _zcalloc
I checked the function
z_deflateInit2
in the file deflate.c from ZLIB source code,
and guess that this function cannot find the implementation of the two functions zcfree adn zcalloc. The reason is that the Nurbs library customize the function zcfree and zcalloc, which is done in two steps.
Cusomize zcalloc and zcfree in the the Nurbs library code.
opennurbs_zlib.h
extern "C" {
voidpf zcalloc (voidpf, unsigned, unsigned);
void zcfree (voidpf, voidpf);
}
These two functions are implementated in the file opennurbs_zlib_memory.cpp as following
#define voidpf z_voidpf
voidpf zcalloc (voidpf, unsigned items, unsigned size)
{
return oncalloc(items, size);
}
void zcfree (voidpf, voidpf ptr)
{
onfree(ptr);
}
Compile the ZLIB library with the flag: MY_ZCALLOC and Z_PREFIX
As I checked, both these two steps are done, but why I still got the linking error.
Could you give me some advices?
Thanks so much!
Update:
#Dale Lear: thanks for your support. But my situation is different. Instead if linking with the opennurbs.lib, I tried to integrate the source code of opennurbs into my project (like the surface module of point cloud library: http://www.pointclouds.org/blog/trcs/moerwald/). I build zlib from the project zlib in opennurbs solution. This zLib is built with the modified zconfig.h (Z_PREFIX and Z_MYCALL, i guess so, is defined). This means that the function zfree and zalloc is still waiting for implementation. But why does ZLib does not take zcfree() and zcalloc from opennurbs_zlib_memory.cpp. I don't understand why does it take.
From your description and the error log you provided, I'm guessing that the situation is:
1) You are building a Windows program using some version of Microsoft's C++ compiler.
2) You want to statically link with zlib.lib
3) You want to statically link with opennnurbs_staticlib.lib
I cannot determine what version of Microsoft's C++ compiler or opennurbs you're using.
If you are using the latest public release of opennurbs (version 2013-07-11), then the zcfree() and zcalloc() functions are defined in the file opennurbs_zlib_memory.cpp.
If you build opennurbs_staticlib.lib using the opennurbs_staticlib.vcxproj project file that is included with the source code, it will compile opennurbs_zlib_memory.cpp and include the zcfree() and zcalloc() functions in it in opennurbs_staticlib.lib. If you build zlib using the zlib code and zlib/zlib.vcxproj file that is included with opennurbs 2013-07-11, then it will be built with all the necessary defines and you will have two static libraries, zlib.lib and opennurbs_staticlib.lib, that link with all dependencies resolved.
If you are using customized project files, the first thing to check is that you are statically linking the results of compiling opennurbs_zlib_memory.cpp in some way.
If you want to use opennurbs as a DLL, I'd suggest building opennurbs.dll with the opennurbs.vcxproj project file that comes with the source code. This opennurbs.dll will statically include zlib.lib when it links and you do not have to link with anything except the resulting opennurbs.lib to use the DLL version.
Does this help?
-- Dale Lear

Why including an h file with external vars and funcs results in undefined references

What if I want these externals to be resolved in runtime with dlopen?
Im trying to understand why including an h file, with shared library external vars and funcs, to a C executable program results in undefined/unresolved. (when linking)
Why do I have to add "-lsomelib" flag to the gcc linkage if I only want these symbols to be resolved in runtime.
What does the link time linker need these deffinitions resolutions for. Why cant it wait for the resolution in runtime when using dlopen.
Can anyone help me understand this?
Here something that may help understanding:
there are 3 types of linking:
static linking (.a): the compiler includes the content of the library into your code at link time so that you can move the code to other computers with the same architecture and run it.
dynamic linking (.so): the compiler resolves the symbols at link time (during compilation); but the does not includes the code of the library in your executable. When the program is started, the library is loaded. And if the library is not found the program stop. You need the library on the computer that is running the program
dynamic loading: You are in charge of loading the library functions at runtime, using dlopen and etc. Specially used for plugins
see also: http://www.ibm.com/developerworks/library/l-dynamic-libraries/ and
Difference between shared objects (.so), static libraries (.a), and DLL's (.so)?
A header file (e.g. an *.h file referenced by some #include directive) is relevant to the C or C++ compiler. The linker does not know about source files (which are input to the compiler), but only about object files produced by the assembler (in executable and linkable format, i.e. ELF)
A library file (give by -lfoo) is relevant only at link time. The compiler does not know about libraries.
The dynamic linker needs to know which libraries should be linked. At runtime it does symbol resolution (against a fixed & known set of shared libraries). The dynamic linker won't try linking all the possible shared libraries present on your system (because it has too many shared objects, or because it may have several conflicting versions of a given library), it will link only a fixed set of libraries provided inside the executable. Use objdump(1) & readelf(1) & nm(1) to explore ELF object files and executables, and ldd(1) to understand shared libraries dependencies.
Notice that the g++ program is used both for compilation and for linking. (actually it is a driver program: it starts some cc1plus -the C++ compiler proper- to compile a C++ code to an assembly file, some as -the assembler- to assemble an assembly file into an object file, and some ld -the linker- to link object files and libraries).
Run g++ as g++ -v to understand what it is doing, i.e. what program[s] is it running.
If you don't link the required libraries, at link time, some references remain unresolved (because some object files contain an external reference and relocation).
(things are slightly more complex with link-time optimization, which we could ignore)
Read also Program Library HowTo, Levine's book linkers and loaders, and Drepper's paper: how to write shared libraries
If you use dynamic loading at runtime (by using dlopen(3) on some plugin), you need to know the type and signature of relevant functions (returned by dlsym(3)). A program loading plugins always have its specific plugin conventions. For examples look at the conventions used for geany plugins & GCC plugins (see also these slides about GCC plugins).
In practice, if you are developing your application accepting some plugins, you will define a set of names, their expected type, signature, and role. e.g.
typedef void plugin_start_function_t (const char*);
typedef int plugin_more_function_t (int, double);
then declare e.g. some variables (or fields in a data structure) to point to them with a naming convention
plugin_start_function_t* plustart; // app_plugin_start in plugins
#define NAME_plustart "app_plugin_start"
plugin_more_function_t* plumore; // app_plugin_more in plugins
#define NAME_plumore "app_plugin_more"
Then load the plugin and set these pointers, e.g.
void* plugdlh = dlopen(plugin_path, RTLD_NOW);
if (!plugdlh) {
fprintf(stderr, "failed to load %s: %s\n", plugin_path, dlerror());
exit(EXIT_FAILURE; }
then retrieve the symbols:
plustart = dlsym(plugdlh, NAME_plustart);
if (!plustart) {
fprintf(stderr, "failed to find %s in %s: %s\n",
NAME_plustart, plugin_path, dlerror();
exit(EXIT_FAILURE);
}
plumore = dlsym(plugdlh, NAME_plumore);
if (!plumore) {
fprintf(stderr, "failed to find %s in %s: %s\n",
NAME_plumore, plugin_path, dlerror();
exit(EXIT_FAILURE);
}
Then use appropriately the plustart and plumore function pointers.
In your plugin, you need to code
extern "C" void app_plugin_start(const char*);
extern "C" int app_plugin_more (int, double);
and give a definition to both of them. The plugin should be compiled as position independent code, e.g. with
g++ -Wall -fPIC -O -g pluginsrc1.c -o pluginsrc1.pic.o
g++ -Wall -fPIC -O -g pluginsrc2.c -o pluginsrc2.pic.o
and linked with
g++ -shared pluginsrc1.pic.o pluginsrc2.pic.o -o yourplugin.so
You may want to link extra shared libraries to your plugin.
You generally should link your main program (the one loading plugins) with the -rdynamic link flag (because you want some symbols of your main program to be visible to your plugins).
Read also the C++ dlopen mini howto

linking a shared library with statics using CMake

cmake 2.8
gcc (GCC) 4.8.1
Edit ----------
Wrapping the static libraries in whole-archive works for every library except the pjmedia-videodev The problem now is that when I try and build I get the following error.
cbar_factory_init': colorbar_dev.c:(.text+0x2a0): undefined reference to pjmedia_format_init_video'
Hello,
I have created a shared library and I need to link that library with about 10 static libraries. I then link my executable with the shared library.
My question is that when I run make it fails to link as it wants the static libraries as well. The purpose of is to create a wrapper for the static libraries. So the executable only has to link with 1 single shared library. As I am linking the shared library with the statics, then the statics will automatically become part of the source code of the shared library.
Only code sippnets to make it short.
In my CMakeLists.txt that creates the shared library and links the static libraries:
add_library(app_module_sip SHARED app_module_sip_init.c)
set(PJSIP_LIBRARIES
g7221codec
gsmcodec
ilbccodec
milenage
pj
pjlib-util
pjmedia
pjmedia-codec
pjmedia-audiodev
pjmedia-videodev
pjnath
pjsip
pjsip-simple
pjsip-ua
pjsua
portaudio
resample
speex
srtp
)
target_link_libraries(app_module_sip pthread m uuid nsl rt asound crypto ssl ${PJSIP_LIBRARIES})
Now my CMakeLists.txt that makes the executable
add_executable(app sip_test.c)
target_link_libraries(app app_module_sip)
Is this correct what I am doing here. I don't want to link the executable with the static libraries. Just the single shared library as that is my wrapper what I will be calling the functions in.
It does link ok, if I link all the statics libraries when making the executable, but that is not the result I want.
Many thanks for any suggestions,
I tried to test my solution but your CMakeLists.txt worked for me without any changes. Still, looking at this question:
Include static lib in dynamic lib,
it appears that you should try
target_link_libraries(app_module_sip ... ssl -Wl,-whole-archive ${PJSIP_LIBRARIES} -Wl,-no_whole-archive)
(scroll to the end, it's a long line)
It's not that simple.
You can look at using '-Wl,--whole-archive' or '-Wl,--export-all-symbols' depending on your platform, but there's no good cross platform way of doing this. Everything does it differently, and windows plays a completely different game using lib.exe.
You probably want to do something like this:
http://www.mail-archive.com/cmake#cmake.org/msg01890.html
...and add support specifically for the platforms you want to support, one at a time.
# Location for shared library
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/libs)
# Create shared library
add_library(app_module_sip SHARED app_module_sip_init.c)
# compile and link for 32 bit mode
set_target_properties(app_module_sip PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
# PJSIP static libraries
set(PJSIP_LIBRARIES
pjsua
pjsip-ua
pjsip-simple
pjsip
pjmedia-codec
pjmedia-videodev
pjmedia
pjmedia-audiodev
pjnath
pjlib-util
resample
milenage
srtp
gsmcodec
speex
ilbccodec
g7221codec
portaudio
pj
)
# Wrap the static libraries in to the shared library
target_link_libraries(app_module_sip -Wl,--start-group ${PJSIP_LIBRARIES} -Wl,--end-group
m uuid nsl rt pthread asound crypto ssl)
Need to wrap the pjsip libraries will the following linker command -Wl,--start-group *.a -Wl,--end-group.
That solved my problem.

Is it possible to get CMake to build both a static and shared library at the same time?

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.

Resources