tags:

views:

599

answers:

2

Is there a way to find the version of a dylib using its path? I am looking for something that accepts the same arguments as dlopen. I have looked at NSVersionOfRunTimeLibrary, but from my reading of the documentation it looks like it gets the version of the current dylib, not the one specified in the path.

Thank you

+6  A: 

Run otool -L on it, and it will show its actually version. I choose libSystem.B as it has different version in the 10.4 and 10.5 SDKs:

$ otool -L /Developer/SDKs/MacOSX10.4u.sdk/usr/lib/libSystem.B.dylib
/Developer/SDKs/MacOSX10.4u.sdk/usr/lib/libSystem.B.dylib:
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 88.3.11)
    /usr/lib/system/libmathCommon.A.dylib (compatibility version 1.0.0, current version 220.0.0)
$ otool -L /Developer/SDKs/MacOSX10.5.sdk/usr/lib/libSystem.B.dylib 
/Developer/SDKs/MacOSX10.5.sdk/usr/lib/libSystem.B.dylib:
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 111.1.4)
    /usr/lib/system/libmathCommon.A.dylib (compatibility version 1.0.0, current version 292.4.0)

(see how the first one has 88.3.11 version, while the second has 111.1.4). This example also shows that not all libraries are symbolic links to files with the version number in them:

$ ll /Developer/SDKs/MacOSX10.*.sdk/usr/lib/libSystem.B.dylib
-rwxr-xr-x  1 root  wheel   749K May 15  2009 /Developer/SDKs/MacOSX10.4u.sdk/usr/lib/libSystem.B.dylib
-rwxr-xr-x  1 root  wheel   670K May 15  2009 /Developer/SDKs/MacOSX10.5.sdk/usr/lib/libSystem.B.dylib
-rwxr-xr-x  1 root  wheel   901K Sep 25 00:21 /Developer/SDKs/MacOSX10.6.sdk/usr/lib/libSystem.B.dylib

Here, the files don't have the version number in their name.

EDIT: a second solution is to use NSVersionOfRunTimeLibrary in a test program, in which you force load the library you want to check. Create a program libversion from the following C source:

#include <stdio.h>
#include <mach-o/dyld.h>

int main (int argc, char **argv)
{
  printf ("%x\n", NSVersionOfRunTimeLibrary (argv[1]));
  return 0;
}

Then, you call it like that:

$ DYLD_INSERT_LIBRARIES=/usr/lib/libpam.2.dylib ./a.out libpam.2.dylib
30000

(here, the version number is printed as hexadecimal, but you can adapt to your needs.)

FX
Much better answer, deleted mine.
EightyEight
+4  A: 

You can check the source code of NSVersionOfRunTimeLibrary here: http://www.opensource.apple.com/source/dyld/dyld-132.13/src/dyldAPIsInLibSystem.cpp

Based on that you can create your own version which replaces if(names_match(install_name, libraryName) == TRUE) with if(strcmp(_dyld_get_image_name(i), libraryName) == 0) That will fix the issue that the original expected the library name without full path, the edited version expects the full path, but it'll still search in the loaded dylibs.

#include <mach-o/dyld.h>
int32_t
library_version(const char* libraryName)
{
    unsigned long i, j, n;
    struct load_command *load_commands, *lc;
    struct dylib_command *dl;
    const struct mach_header *mh;

    n = _dyld_image_count();
    for(i = 0; i < n; i++){
        mh = _dyld_get_image_header(i);
        if(mh->filetype != MH_DYLIB)
        continue;
        load_commands = (struct load_command *)
#if __LP64__
                ((char *)mh + sizeof(struct mach_header_64));
#else
                ((char *)mh + sizeof(struct mach_header));
#endif
        lc = load_commands;
        for(j = 0; j < mh->ncmds; j++){
        if(lc->cmd == LC_ID_DYLIB){
            dl = (struct dylib_command *)lc;
            if(strcmp(_dyld_get_image_name(i), libraryName) == 0)
            return(dl->dylib.current_version);
        }
        lc = (struct load_command *)((char *)lc + lc->cmdsize);
        }
    }
    return(-1);
}
mfazekas
You are partially answering but still this should be part of the solution, I think.
Till
Regarding "That will fix the issue that now it expects the full name": I don't think it's really an issue, as adk is trying to query a library version by its path (which includes the name).
FX