[CMake] CMAKE uses wrong symlink to so

Michael Hertling mhertling at online.de
Sat Jan 1 11:56:31 EST 2011


On 12/31/2010 03:43 PM, Michael Wild wrote:
> On 12/31/2010 02:48 PM, Michael Hertling wrote:
>> On 12/31/2010 11:56 AM, Michael Wild wrote:
>>> On 12/30/2010 07:55 PM, j s wrote:
>>>> Hello Michael Wild,
>>>>
>>>> I regret deciding to go with an Python parser for my application.  I use
>>>> such a small subset of the API, I was hoping to be able to rerelease my app
>>>> everytime it changes.
>>>>
>>>> Apparently Python 2.6 is frozen.
>>>>
>>>> In the future, the Python people are hoping to stabilize the ABI in the 3
>>>> series so that I can just link against a libpython3.so:
>>>> http://www.python.org/dev/peps/pep-0384/
>>>>
>>>> As stated by Michael Hertling, the symlinks are not being recursively
>>>> resolved.  The soname is encoded into the so, so the linker chooses to
>>>> ignore the original filename.
>>>>
>>>> Regards,
>>>>
>>>> Juan
>>>>
>>>> On Thu, Dec 30, 2010 at 6:23 AM, Michael Wild <themiwi at gmail.com> wrote:
>>>>
>>>>> On 12/30/2010 12:28 AM, j s wrote:
>>>>>> I specified the full name to an so in CMAKE 2.8.1.  Unfortunately it
>>>>> links
>>>>>> against the versioned so name,
>>>>>> libpython2.6.so.1.0
>>>>>>
>>>>>> instead of the exact name I specified.
>>>>>> /usr/lib/libpython2.6.so
>>>>>>
>>>>>> SET (PYTHON_ARCHIVE /usr/lib/libpython2.6.so)
>>>>>> TARGET_LINK_LIBRARIES (myapp  parser engine ${PYTHON_ARCHIVE}
>>>>>> ${OPENSSL_ARCHIVE})
>>>>>>
>>>>>> Is there any way to tell cmake to do the right thing in Linux?  For some
>>>>>> strange reason using -l on the link line, and doesn't even use the
>>>>>> corresponding -L to the path I specify.
>>>>>>   -lpython2.6
>>>>>>
>>>>>>
>>>>>> Regards,
>>>>>>
>>>>>> Juan
>>>>>
>>>>> There's nothing CMake can do about this, this is the linker getting in
>>>>> your way. E.g. on my Ubuntu, /usr/lib/libpython2.6.so is a symlink to
>>>>> /usr/lib/libpython2.6.so.1 which itself is a symlink to
>>>>> /usr/lib/libpython2.6.so.1.0. The linker recursively resolves all
>>>>> symlinks during the linking, and CMake can't do anything about it. You
>>>>> could pass the full path to the /usr/lib/libpython2.6.so symlink instead
>>>>> of -lpython2.6 and you would still get the same result.
>>>>>
>>>>> Actually, this is considered to be a feature. This way, newly compiled
>>>>> programs will always link against the "current" version (the one pointed
>>>>> to by the symlink-chain), while old programs can still use  older
>>>>> versions of the library without requiring to be recompiled.
>>>>>
>>>>> Michael
>>>
>>>
>>> Huh?
>>>
>>> $ echo "int main(){}" | gcc -x c -c -o test.o -
>>> $ gcc test.o /usr/lib/libpython2.6.so
>>> $ ldd a.out | grep libpython2.6
>>> libpython2.6.so.1.0 => /usr/lib/libpython2.6.so.1.0 (0x00007fbb350f1000)
>>>
>>> $ ls -l /usr/lib/libpython2.6.so*
>>> ... /usr/lib/libpython2.6.so -> libpython2.6.so.1
>>> ... /usr/lib/libpython2.6.so.1 -> libpython2.6.so.1.0
>>> ... /usr/lib/libpython2.6.so.1.0
>>>
>>> Sure looks like recursive symlink resolution to me...
>>
>> No, it's the soname that gets incorporated in the resulting binary;
>> recursively resolving the symlinks is insignificant in this regard:
>>
>> echo "void f(void){}" > f.c
>> echo "void g(void){}" > g.c
>> gcc -o libf.so -shared -fPIC -Wl,-soname,xyz f.c
>> gcc -o libg.so.1.0 -shared -fPIC g.c
>> ln -sf libg.so.1.0 libg.so.1
>> ln -sf libg.so.1 libg.so
>> ls -l libg.so*
>> ... libg.so -> libg.so.1
>> ... libg.so.1 -> libg.so.1.0
>> ... libg.so.1.0
>>
>> echo "int main(void){return 0;}" > main.c
>> gcc -o main main.c libf.so libg.so
>> LD_LIBRARY_PATH=. ldd main
>> ...
>>         xyz => not found
>>         libg.so => ./libg.so (0xb7fbd000)
>> ...
>>
>> A recursive symlink resolution would make the main executable being
>> linked against libg.so.1.0 instead of libg.so. In fact, main is linked
>> against the library specified by the soname - if present - even if that
>> library doesn't exist at all like xyz in the example above. If there is
>> no soname the linker incorporates the library as denoted on the command
>> line. With libpython2.6, the executable is linked against .so.1.0 since
>> this is the library's soname, but not due to the .so-->so.1-->.so.1.0
>> symlink resolution. BTW, the soname denoting the non-existing xyz is
>> completely artificial, of course, and designed only to clarify the
>> concern. Usually, ldconfig ensures that there is a valid symlink
>> soname --> actual library file.
>>
>> Regards,
>>
>> Michael
> 
> 
> Ahh, yes, I see. Learned something new ;-) But still, not exactly a
> CMake-issue, [...]

It's usual *nix/ELF business.

> [...] although replacing full paths with -l flags might cause
> wrong libraries from being picked up if a -L flag happens to be
> specified before the library, right?

Even if -L appears after the library it remains a pitfall as all -L
options apply to all -l ones, regardless of their order. So, IMO, the
rule of thumb should be: Always use full paths for libraries but never
use -L, neither explicitly in TARGET_LINK_LIBRARIES(), LINK_FLAGS etc.
nor indirectly via LINK_DIRECTORIES(), and if there's any trouble with
CMake's decision to use -l because the library resides in a well known
system directory, use the imported-target approach to enforce a full
path in that case, too.

Regards and Happy New Year,

Michael


More information about the CMake mailing list