When you man install_name_tool
, it doesn’t really tell you what’s the difference between install-name-id and install-name-value. id
is used at link time and value
is used at runtime. They are all information provided for the linker to locate the dylib. The example used below is inspired by this tutorial. Note that id
is only present for dynamic libraries. As for executables, only install name value
is available.
Let’s go through an example to get a concrete understanding.
$ cat a.cc
#include <iostream>
void a() { std::cout << "a()" << std::endl; }
$ clang++ -c a.cc
$ clang++ -o liba.dylib -dynamiclib a.o
$ otool -L liba.dylib
liba.dylib:
liba.dylib (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.4)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.250.1)
As you can see, the first line is the id
. Let’s link with libb.dylib
,
$ cat b.cc
#include <iostream>
void a();
void b() { std::cout << "b()" << std::endl; a(); }
$ clang++ -c b.cc
$ clang++ -o libb.dylib -dynamiclib b.o -L. -la
$ otool -L libb.dylib
libb.dylib:
libb.dylib (compatibility version 0.0.0, current version 0.0.0)
liba.dylib (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.4)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.250.1)
Just notice the second line, the id
of liba.dylib
is used during linking. In fact, lines below the second line are all install-name-values.
Let’s change the id
to foo/liba.dylib
and link them again. Notice -id
is used to change the id
(first line) and -change
is for value
.
$ install_name_tool -id foo/liba.dylib liba.dylib
$ otool -D liba.dylib
liba.dylib:
foo/liba.dylib
liba.dylib:
foo/liba.dylib (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.4)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.250.1)
As you can see, the -D
and -L
all outputs the current id
as foo/liba.dylib.
Let’s link again with liba.dylib
,
$ clang++ -o libb.dylib -dynamiclib b.o -L. -la
$ otool -L libb.dylib
libb.dylib:
libb.dylib (compatibility version 0.0.0, current version 0.0.0)
foo/liba.dylib (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.4)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.250.1)
See the difference? The run time location to find liba.dylib
is changed to foo/liba.dylib
at the second line. This means that libb.dylib
uses id
from liba.dylib
that it links against.
It tells libb.dylib
where to find liba.dylib
. liba.dylib
is located at directory foo
under the starting directory where the executable is invoked (some people call it working or current directory). Whereas @loader_path means the directory that contains the library or executable.
This answer is also posted in SO.