Why ar gives a warning when creates a static library? - compilation

I do not understand why ar gives a warning when it is creating a library.
I do this:
$ cat foo.c
int foo(int a) {
return a + 1;
}
$ clang -c foo.c
$ ar r foo.a foo.o
ar: warning: creating foo.a
$
Is r the right command to use with ar? Why do I get the warning?
I am using clang and FreeBSD. Not sure if ar comes from clang or from FreeBSD.

If the output file doesn't already exist, you are supposed to use the c modifier. From the man page:
c
Create the archive. The specified archive is always created if it did not exist, when you request an update. But a warning is issued unless you specify in advance that you expect to create it, by using this modifier.
So try ar rc foo.a foo.o to silence the warning.

Related

Force .o files in .a to use some symbols from within that .a

Let's say I have foo.a with
a.o
T aaa
U bbb
b.o
T bbb
How can I either modify foo.a or create a relocatable foo.o such that when it is linked in another project, a.o:bbb uses b.o:bbb instead of a bbb that might be defined elsewhere? Note that I can't use --whole-archive because main is defined in one the .o in foo.a. Also note that I can know the symbols to keep global (eg aaa) or to use local (eg bbb) if that helps.
I tried to create a relocatable object with a version script exporting only aaa in the hope bbb would be linked local implicitly. Unfortunately, the resulting .o contains no symbols:
$ cat version.script
{ global: aaa; local: *; };
$ ld -relocatable --version-script version.script foo.a -o foo.o
$ nm foo.o
nm: foo.o: no symbols
This might not even be the right approach so I'm open to suggestions. Thank you!
How can I either modify foo.a or create a relocatable foo.o such that
ld -r --whole-archive foo.a -o foo1.o &&
objcopy -w -L.* -Gaaa foo1.o foo.o &&
rm foo1.o
nm foo.o
0000000000000000 T aaa
0000000000000010 t bbb
U _GLOBAL_OFFSET_TABLE_
I tried to create a relocatable object with a version script
Linker version scripts don't work for relocatable objects, they can only control symbols in the dynamic symbol table which relocatable objects lack.
Note that I can't use --whole-archive because main is defined in one the .o in foo.a
That's trivial to fix:
ld -r -u aaa foo.a -o foo1.o
This will cause only the object which defines aaa (a.o here) and any other objects defining symbols referenced by a.o to be pulled in.
If you need to export multiple symbols (e.g. aaab, aaac, etc.) you'll need to adjust both the ld and the objcopy commands to list them.

How to create a makefile that will place object code in different folder

I am very new to Makefile. I had build the following makefile(Which don't work).I wan't put genarated object codes in differnt folder(the folder is in current directory).
$ ls
main.cpp Makefile object_code Time.cpp Time_.h
how can I do this ??
VER = Debug
CC = g++
OBJECTFIELS = ./object_code/main.o ./object_code/Time.o
../$(VER)/main: $(OBJECTFIELS)
$(CC) $(OBJECTFIELS) -o $#
$(OBJECTFIELS): Time_.h
./object_code/main.o: main.cpp
./object_code/Time.o: Time.cpp
clean:
rm $(OBJECTFIELS) main
this is error.
$ make
g++ ./object_code/main.o ./object_code/Time.o -o ../Debug/main
g++: error: ./object_code/main.o: No such file or directory
g++: error: ./object_code/Time.o: No such file or directory
g++: fatal error: no input files
compilation terminated.
Makefile:8: recipe for target '../Debug/main' failed
make: *** [../Debug/main] Error 1
please this is last question.
I don't see how you can possibly get that output given the makefile you've posted here.
Either the object files already exist in which case the link will succeed rather than printing that error.
Or the object files don't exist in which case make will complain because it doesn't know how to make them. There must be some difference between the makefile you're using and the one you've posted here.
In any event, make knows how to build a file foo.o from a file foo.cpp for any string foo. There's a built-in rule that tells it how to do that.
But, make doesn't know how to build a file ./object_code/foo.o from a file foo.cpp, regardless of foo. There's no built-in rule that tells make how to build object files in some random other directory. If you want make to do that, you'll have to tell it how. You should remove the lines:
./object_code/main.o: main.cpp
./object_code/Time.o: Time.cpp
and replace them with a pattern rule describing how to build object files into the object_code directory (I'm using CXX as the compiler variable here: by convention CC is the C compiler and CXX is the C++ compiler, and you should always stick with convention unless there's a good reason not to):
VER = Debug
CXX = g++
OBJECTFIELS = ./object_code/main.o ./object_code/Time.o
../$(VER)/main: $(OBJECTFIELS)
$(CXX) $(OBJECTFIELS) -o $#
$(OBJECTFIELS): Time_.h
./object_code/%.o : %.cpp
$(CXX) -c -o $# $<
clean:
rm $(OBJECTFIELS) main

Why doesn't this Makefile work?

I have this C file:
// test.c
#include <stdio.h>
int main()
{
printf("Hello World!\n");
return 0;
}
And this Makefile
OBJS=$(patsubst %.c,%.o,$(wildcard *.c))
EXEC=hello.exe
all: $(EXEC)
$(EXEC): $(OBJS)
.PHONY: all
When I do make it doesn't create my target hello.exe why?
$ make
cc -c -o hello.o hello.c
It doesn't either work with hello.exe:
$ make hello.exe
make: Nothing to be done for 'hello.exe'.
And hello.exe doesn't exist:
$ ls hello.exe
ls: cannot access 'hello.exe': No such file or directory
I use this version of GNU Make
$ make --version
GNU Make 4.2.1
Built for x86_64-unknown-cygwin
Copyright (C) 1988-2016 Free Software Foundation, Inc.
EDIT
It actually works when I name my executable the same of any of my files. So it works with:
EXEC=hello
See:
$ make
cc -c -o hello.o hello.c
cc hello.o -o hello
That said I don't understand why it only works that way.
The version with hello.exe does not work because make has no implicit rule to tell it how to turn a bunch of *.o into a single *.exe.
But it does have implicit rules (at least those specified by POSIX) to turn hello.c into hello.o and link into hello.
Remember, Unix is not DOS. Forget the .exe when you're on Unix.

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