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

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...

Related

How to link different object file with LLVM library?

I am following the LLVM tutorial : Kaleidoscope: Code generation to LLVM IR, which will use LLVM libraries like LLVMContext, Module and so on. Different from the tutorial, I am trying to write the lexer, parser and code generator in different source file and link them into one executable file.
Here is my compile command on the Ubuntu 20.04:
clang++ -g -O3 -I /home/therlf/LLVM/include -I ./ -I /home/therlf/LLVM_Temp/llvm/include `llvm-config --cxxflags --ldflags --system-libs --libs all` ast/CallExprAST.o ast/NumberExprAST.o ast/PrototypeAST.o ast/FunctionAST.o ast/BinaryExprAST.o ast/VariableExprAST.o lexer/lexer.o logger/logger.o parser/parser.o main.cpp -o main
But I only get lots of "undefined error".
Here are some of them:
/usr/bin/ld: /tmp/main-2b71c8.o:(.data+0x0): undefined reference to `llvm::DisableABIBreakingChecks
/home/therlf/MyProject/tmp/ast/CallExprAST.cpp:6: undefined reference to `llvm::Module::getFunction(llvm::StringRef) const'
/home/therlf/LLVM/include/llvm/IR/InstrTypes.h:1112: undefined reference to `llvm::Instruction::Instruction(llvm::Type*, unsigned int, llvm::Use*, unsigned int, llvm::Instruction*)'
/usr/bin/ld: /home/therlf/LLVM/include/llvm/IR/InstrTypes.h:977: undefined reference to `llvm::VectorType::get(llvm::Type*, llvm::ElementCount)'
At first I thought it's including path's error. But when I compiled and ran the source file in the tutorial successfully, which is just a whole source file with everything packed into file, I knew the including path is nothing wrong.
I have searched for this question, and some blogs say that you should link them with lld and use the -fuse-ld=lld in the compile command. But I don't have lld, and the clang++ doesn't know the argument -fuse-ld, which will report an error. The blog says that you should have lld as long as you have installed LLVM. In fact here are what I got: LLVM tools
And I know the llvm-link is used to link IR file, not the object file compiled from cpp source file.
Here is my LLVM version:
10.0.0svn
And here is my Makefile:
SOURCES = $(shell find ast kaleidoscope lexer logger parser -name '*.cpp')
HEADERS = $(shell find ast kaleidoscope lexer logger parser -name '*.h')
OBJ = ${SOURCES:.cpp=.o}
CC = clang++
# -stdlib=libc++ -std=c++11
CFLAGS = -g -O3 -I /home/therlf/LLVM/include -I ./ -I /home/therlf/LLVM_Temp/llvm/include
LLVMFLAGS = `llvm-config --cxxflags --ldflags --system-libs --libs all`
.PHONY: main
main: main.cpp ${OBJ}
${CC} ${CFLAGS} ${LLVMFLAGS} ${OBJ} $< -o $#
clean:
rm -r ${OBJ}
%.o: %.cpp ${HEADERS}
${CC} ${CFLAGS} ${LLVMFLAGS} -c $< -o $#
In fact, I follow the project structure from the repository : ghaiklor/llvm-kaleidoscope and the Makefile is nearly identical.
Sincerely thank you for your answers!
I have sloved this problem by exchanging my linker ld with linker lld.
You should install lld first by this command in ubuntu if you can't find it in the LLVM/tools directory like I did.
sudo apt-get update
sudo apt-get -y install lld
And then you can add -fuse-ld=lld to your compile command
or you can
cd /usr/bin
ln -s /path/to/ld.lld /usr/bin/ld
This should work if everything goes well.
But I still can't figure out the reason behand this situation :-(

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

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.

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

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