Why can't I rename a shared library after it's been built? - macos

Here's a simple example:
lib.c:
#include <stdio.h>
void hello_world(void) {
puts("Hello, world!");
}
program.c:
void hello_world(void);
int main() {
hello_world();
return 0;
}
If I compile the library normally and link it, everything works fine:
$ cc lib.c -fPIC -shared -o libmylib.dylib
$ cc program.c -L. -lmylib
$ ./a.out
Hello, world!
But if I rename the library after building it (but before building the program), it doesn't work:
$ cc lib.c -fPIC -shared -o totally_different_name.dylib
$ mv totally_different_name.dylib libmylib.dylib
$ cc program.c -L. -lmylib
$ ./a.out
dyld: Library not loaded: totally_different_name.dylib
Referenced from: /private/tmp/./a.out
Reason: image not found
[1] 13229 abort ./a.out
Why is this the case? Why is dyld looking for the original library name?
This works okay on Linux, but when I try on macOS it completely fails (I don't know if it's a macOS vs Linux thing, or a clang vs gcc thing, since I'm using clang on macOS and gcc on Linux).
If it's relevant, cc --version is Apple LLVM version 8.0.0 (clang-800.0.42.1) x86_64-apple-darwin16.4.0.

Thanks to Florian Zwoch's comment, I was able to find a way to fix this. Run this command after renaming the dylib:
install_name_tool -id libmylib.dylib libmylib.dylib
That command changes the internal ID of the dylib. The command syntax is install_name_tool -id <new-id> <dylib-path>.
Originally, the dylib has the ID of totally_different_name.dylib. Renaming the file doesn't change the ID it has stored internally, and that has to be updated separately with install_name_tool.

Related

How do I resolve OSX rpath-referenced library?

I want to link a DLL using a couple of other DLLs but am having trouble getting them to properly resolve:
$ g++ -o libsuba.dylib -dynamiclib -Wl,-install_name,#rpath/libsuba.dylib suba.cpp
$ g++ -o liba.dylib -dynamiclib -Wl,-install_name,#rpath/liba.dylib -Wl,-reexport_library,libsuba.dylib a.cpp
The above gives me the two libraries, liba.dylib and libsuba.dylib.
$ otool -l liba.dylib
...
Load command 10
cmd LC_REEXPORT_DYLIB
cmdsize 48
name #rpath/libsuba.dylib (offset 24)
time stamp 2 Wed Dec 31 18:00:02 1969
current version 0.0.0
compatibility version 0.0.0
...
In another directory, I want to now link against liba.dylib:
$ cd build
$ c++ -o b b.cpp ../liba.dylib -Wl,-rpath,..
ld: file not found: #rpath/libsuba.dylib for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
However, this works:
$ c++ -o b b.cpp ../liba.dylib -L..
Can someone explain why the explicit linker rpath option doesn't replace the #rpath macro and allow the reexported library to be located?

How to create a shared library (.so) file in Mac os X using terminal

How to create a shared library (.so) file in Mac os X using terminal
Thanks in Advance.
This might be very late, but incase someone stumbles upon this I know how to make an so files for c++/c code. Assuming that you are in the directory with your .cpp/.c and .h files, in the terminal you must type:
g++ -c file1.cpp file2.cpp (add as many cpp/c files you want in the so file)
g++ *.o -dynamiclib -o lib_name.so
Then if you are using a cpp file that will run it:
g++ -c test.cpp -o test.o (compiling the program to see if the shared library works)
g++ -o test test.o -L. -l_name (create an executable to run)
./test (run the test)
For C code so files, it's the same but replace g++ with gcc.

How can I specify the rpath in a dylib?

I have a library: libfoo.dylib. The problem is illustrated in the commands:
$ install_name_tool -id "#rpath/libfoo.dylib" libfoo.dylib
$ install_name_tool -add_rpath "#executable_path/" libfoo.dylib
$ gcc -o foo foo.c -lfoo
$ ./foo #<==== I want this to work
dyld: Library not loaded: #rpath/libfoo.dylib
Referenced from: ~/./foo
Reason: image not found
$ install_name_tool -add_rpath "#executable_path/" foo #<=== I dont want to have to specify here where to look for the library
$ ./foo
Hello World
How do I achieve the goal of not having to specify at executable compile where the library is?
I must confess that I'm a little confused as to what you're trying to achieve. The entire point of using the runpath search path is that the images loading the library define the search path to be used when loading the library. What you're asking for is for the library to define where the executable should find it. That can be accomplished without using the runpath search path by simply setting the install name of the dylib to the appropriate value. Based on your particular example, it sounds like you want to set the install name to something like #loader_path/libfoo.dylib. Consider the following, which is along the same lines of your sample:
$ cat a.c
int a(void)
{
return 1;
}
$ cc -install_name "#loader_path/liba.dylib" -dynamiclib -o liba.dylib a.c
$ cat main.c
#include <stdio.h>
extern int a(void);
int main(int argc, char **argv)
{
fprintf(stderr, "A: %d\n", a());
return 0;
}
$ cc -L. -la -o main main.c
$ ./main
A: 1
$
The library tells executables that link against it how to find it by setting its install name, and nothing special needs to be done when linking the executable to have it find the library at runtime.
The only thing you need is to tell the linker to add the rpath in your binary. Actually, you tell gcc to tell the linker in the following way:
$ gcc -o foo foo.c -lfoo -Wl,-rpath=/some/path
Now if you use objdump to see what's in there:
$ objdump -x ./foo | less
You will see under Dynamic Section somthing like RPATH /some/path.
If having to type the same -Wl,-rpath=... is too cumbersome, ld accepts the #file option (I don't know about dyld but I suppose it does too):
$ echo "-rpath=/some/path" > ./ld-options
$ gcc ./foo.c -o foo -Wl,#ld-options

Standalone Rmath.h in native C/C++ program [2]

According to R-admin.pdf, I built the standalone Rmath library on my Mac. The first test program seemed compiled and linked well, but generated an error message. The followings are my procedures:
$ cc -o test test.c -I /library/frameworks/r.framework/headers
-L/users/ed/downloads/r-2.13.1/src/nmath/standalone/ -lRmath -lm
$ ./test
dyld: Library not loaded: libRmath.dylib
Referenced from: .....
Reason: image not found
Trace/BPT trap
$
Thanks in advance.
I found a way to compile and link C code including Rmath.h. When you choose default installation, the path for the header is /library/frameworks/r.framework/headers, and the path for the library is /library/frameworks/r.framework/libraries.
$ gcc -I/library/frameworks/r.framework/headers -c test.c
$ gcc -L/library/frameworks/r.framework/libraries test.o -lRmath -o progname
Single line implementation is also convenient:
$ gcc -I/library/frameworks/r.framework/headers test.c \
-L/library/frameworks/r.framework/libraries -lRmath -o progname
I found that Objective-C program can include standalone Rmath.h as well. Implementation is as follows: (name of the objective-c program is 'test.m.')
$ gcc -framework Foundation -I/library/frameworks/r.framework/headers test.m
-L/library/frameworks/r.framework/libraries -lRmath -o progname
I added this comment in the hope that it will be useful...
I'm not a mac guy, but you need to ensure your program finds libRmath.dylib. On Linux you would set LD_LIBRARY_PATH...

Beginner's question, trying to understand how the linker searches for a static library

I have a working setup, where all files are in the same directory (Desktop). The Terminal output is like so:
$ gcc -c mymath.c
$ ar r mymath.a mymath.o
ar: creating archive mymath.a
$ ranlib mymath.a
$ gcc test.c mymath.a -o test
$ ./test
Hello World!
3.14
1.77
10.20
The files:
mymath.c:
float mysqrt(float n) {
return 10.2;
}
test.c:
#include <math.h>
#include <stdio.h>
#include "mymath.h"
main() {
printf("Hello World!\n");
float x = sqrt(M_PI);
printf("%3.2f\n", M_PI);
printf("%3.2f\n", sqrt(M_PI));
printf("%3.2f\n", mysqrt(M_PI));
return 0;
}
Now, I move the archive mymath.a into a subdirectory /temp. I haven't been able to get the linking to work:
$ gcc test.c mymath.a -o test -l/Users/telliott_admin/Desktop/temp/mymath.a
i686-apple-darwin10-gcc-4.2.1: mymath.a: No such file or directory
$ gcc test.c -o test -I/Users/telliott_admin/Desktop/temp -lmymath
ld: library not found for -lmymath
collect2: ld returned 1 exit status
What am I missing? What resources would you recommend?
Update: Thanks for your help. All answers were basically correct. I blogged about it here.
$ gcc test.c /Users/telliott_admin/Desktop/temp/mymath.a -o test
edit: gcc only needs the full path to the library for static libraries. You use -L to give a path where gcc should search in conjunction with -l.
To include the math libraries, use -lm, not -lmath. Also, you need to use -L with the subdirectory to include the library when linking (-I just includes the header for compiling).
You can compile and link with:
gcc test.c -o test -I/Users/telliott_admin/Desktop/temp /Users/telliott_admin/Desktop/temp/mymath.a
or with
gcc test.c -o test -I/Users/telliott_admin/Desktop/temp -L/Users/telliott_admin/Desktop/temp -lmymath
where mymath.a is renamed libmymath.a.
See link text for comments (search for "bad programming") on the practices of using -l:
In order for ld to find a library with -l, it must be named according to the pattern libyourname.a. Then you use -lmymath
So, there is no way to get it to take /temp/mymath.a with -l.
If you named it libmymath.a, then -L/temp -lmymath would find it.

Resources