I am trying to link to a shared library. But I kept getting the undefined reference error. The following is makefile:
LIBDIR :=./lib
LIB :=-lminus
OBJDIR :=objdir
SOURCES=$(wildcard ./src/*.c)
OBJS :=$(patsubst ./src/%.c, $(OBJDIR)/%.o, $(SOURCES))
INCPATH = -Ilib -Isrc
vpath %.h ./src ./lib
vpath %.c ./src ./lib
optest : $(OBJS)
cc -o optest $(OBJS)
$(OBJDIR)/main.o : main.c add.h mul.h did.h minus.h
cc $(INCPATH) -o $# -c $< -L$(LIBDIR) $(LIB)
$(OBJDIR)/%.o: %.c %.h | $(OBJDIR)
cc -o $# -c $<
$(OBJDIR):
mkdir $#
clean :
rm -rf $(OBJDIR)
rm -f optest
rm -f ./src/*.o
The shared library is called libminus, which is put in the ./lib directory. The main function in main.c uses the function minus defined in this library. I searched online, people met this problem before. Most of their problems were solved after the shared libraries were put after the object files in the rule command. I also tried this, but it didn't work for me. The error I got is as follows:
mkdir objdir
cc -o objdir/mul.o -c ./src/mul.c
cc -o objdir/did.o -c ./src/did.c
cc -Ilib -Isrc -o objdir/main.o -c ./src/main.c -L./lib -lminus
cc -o objdir/add.o -c ./src/add.c
cc -o optest objdir/mul.o objdir/did.o objdir/main.o objdir/add.o
objdir/main.o: In function `main':
main.c:(.text+0xa5): undefined reference to `minus'
collect2: error: ld returned 1 exit status
makefile:11: recipe for target 'optest' failed
make: *** [optest] Error 1
Can any one give some suggestion? Thank you.
You're putting the lib stuff into the wrong rule:
$(OBJDIR)/main.o : main.c add.h mul.h did.h minus.h
cc $(INCPATH) -o $# -c $< -L$(LIBDIR) $(LIB)
This just compiles main.c to main.o. The -L and $(LIB) don't belong here. They have to be in the build recipe of this rule, which links the executable:
optest : $(OBJS)
cc -o optest $(OBJS)
Related
I'm trying to compile my C project using clang (I'm on MacOS Monterry) and a Makefile, but I keep getting the same error from clang in the command line:
> make
gcc -c src/ji.c src/main.c -o src/ji.o
clang: error: cannot specify -o when generating multiple output files
make: *** [src/ji.o] Error 1
These are the only files I have in the project so far:
src/main.c
src/ji.c
include/ji.h
The Makefile looks like this:
cc = gcc
src = $(wildcard src/*.c)
obj = $(src:.c=.o)
exec = ji
$(exec): $(obj)
$(cc) -Iinclude $< -o build/$#
%.o: %.c
$(cc) -c $(src) -o $#
clean:
-rm src/*.o
-rm ji
From YouTube videos I've seen, this should be the ideal Makefile for the project but no matter what I change I get the error.
There are a few issues:
-Iinclude needs to be on the %.o: %.c rule command
In %.o: %.c, we don't want $(src) but rather $<
We want patsubst to get the .o list obj
The $(exec) target doesn't match the -o option
The clean doesn't match the placement of the executable
Here's a refactored version (e.g. one way to do this--there are others):
cc = gcc
src = $(wildcard src/*.c)
obj = $(patsubst %.c,%.o,$(src))
exec = build/ji
$(exec): $(obj)
mkdir -p build
$(cc) $^ -o $#
%.o: %.c
$(cc) -c $< -o $# -Iinclude
clean:
rm -f src/*.o
rm -fr build
Here's the output of make:
gcc -c src/ji.c -o src/ji.o -Iinclude
gcc -c src/main.c -o src/main.o -Iinclude
mkdir -p build
gcc src/ji.o src/main.o -o build/ji
Here's the output of make clean:
rm -f src/*.o
rm -fr build
I'm trying to create a makefile for my project but it's not working at all.
I have the following directory structure
projectroot
|
|-----main.c
|
|-----makefile
|
|-----folder1
| |
| |-----Foobar1.c
| |-----Foo1.c
| |-----Bar1.c
| |-----Foobar1.h
|
|-----folder2
| |-----Foo2.c
| |-----Foo2.h
Foo1.c and Bar1.c are used in Foobar1.c and they are included in the Foobar.h and it workes if i run them (Foobar1.c) in the folder1 directory.
The main.c is useing functions from both Foobar1.c and Foo2.c
CC = gcc
CFLAGS = -c -Wall
LIBS = -lm
all: run
run: main.o Foobar1.o Foo2.o
$(CC) main.o Foobar1.o Foo2.o -o run $(LIBS)
main.o: main.c
$(CC) $(CFLAGS) main.c $(LIBS)
Foobar1.o: folder1/Foobar1.c folder1/Foo1.c folder1/Bar1.c
$(CC) $(CFLAGS) folder1/Foobar1.c folder1/Foo1.c folder1/Bar1.c $(LIBS)
Foo2.o: folder2/Foo2.c
$(CC) $(CFLAGS) folder2/Foo2.c $(LIBS)
clean:
rm -rf *o run
I tried to create a Makefile for whole project in the root directory and I got this error:
gcc -Wall main.c -lm
gcc -Wall folder1/Foobar1.c folder1/Foo1.c folder1/Bar1.c -lm
gcc -Wall folder2/Foo2.c -lm
gcc main.o Foobar1.o Foo2.o -o run -lm
Foobar.o: In function 'Foo1_func1':
Foobar.c: (.text+0x0): multiple definitions of 'Foo1_func1'
main.o:main.c:(.text+0x0): first defined here
Foobar.o: In function 'Bar1_func1':
Foobar.c: (.text+0x6a4): multiple definitions of 'Bar1_func1'
main.o:main.c:(.text+0x6a4): first defined here
Foobar.o: In function 'Bar1_func2':
Foobar.c: (.text+0xed8): multiple definitions of 'Bar1_func2'
main.o:main.c:(.text+0xed8): first defined here
collect2: error: ld returned 1 exit status
makefile:13: recipe for target "run" failed
make: *** [run] error 1
and I also tried to create a makefile for each sub-folder and one in the root directory it did work for the sub-makefile but I don't know how to write the root makefile I tried with this
in folder1
CC = gcc
CFLAGS = -c -Wall
LIBS = -lm
all: bar
bar: Foobar1.o
$(CC) Foobar1.o -o bar $(LIBS)
Foobar1.o: Foobar1.c Foo1.c Bar1.c
$(CC) $(CFLAGS) Foobar1.c $(LIBS)
clean:
rm -rf *o bar
in folder2
CC = gcc
CFLAGS = -c -Wall
LIBS = -lm
all: foo
foo: Foo2.o
$(CC) Foo2.o -o bar $(LIBS)
Foo2.o: Foo2.c
$(CC) $(CFLAGS) Foo2.c $(LIBS)
clean:
rm -rf *o foo
and in the root directory. is it the correct way to do this?
CC = gcc
CFLAGS = -c -Wall
LIBS = -lm
all:
+$(MAKE) -C folder1
+$(MAKE) -C folder2
run: main.o folder1/Foobar1.o folder2/Foo2.o
$(CC) main.o folder1/Foobar1.o folder2/Foo2.o -o run $(LIBS)
main.o: main.c
$(CC) $(CFLAGS) main.c $(LIBS)
clean:
rm -rf *o run
Please help, it is my first time to write a makefile.
You're running the executable (.o) without first compile the .c
run: main.o Foobar1.o Foo2.o
$(CC) main.o Foobar1.o Foo2.o -o run $(LIBS)
[...]
And here you should rm using *.o, its safer.
clean:
rm -rf *o run
The right order is:
1 - .h (library)
2 - .c (code)
3 - .o (executable)
On my Mac OSX 10.13, I always use the following makefile to compile C codes:
TARGET = run
LIBS = -O2 -lm -lrt
CC = gcc
.PHONY: default all clean
all: $(TARGET)
OBJECTS = $(patsubst %.c, %.o, $(wildcard *.c))
HEADERS = $(wildcard *.h)
%.o: %.c $(HEADERS)
$(CC) $(CFLAGS) -c $< -o $#
.PRECIOUS: $(TARGET) $(OBJECTS)
$(TARGET): $(OBJECTS)
$(CC) $(OBJECTS) $(CFLAGS) $(LIBS) -o $#
clean:
-rm -f *.o
-rm -f $(TARGET)
Note that I use -lrt on purpose because I use #include <aio.h> for some of my codes. Because of that, I keep getting this error:
ld: library not found for -lrt
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [run] Error 1
This error does not show up when running on Linux systems. How do I fix that to be runnable on Mac OSX?
I am using pro*c in AIX,I want make my .pc file compile to a .so libary. And link it. This is my directory:
ls
connect.pc func.c get_log.pc main.c makefile sql_err.pc
This is my makefile:
#Makefile
CC = cc -g -brtl
CFLAGS = -g -c
ESQL = proc
RM = rm -f
MYHOME = /home/xxx
OBJ = main.o func.o
LIBOBJ = get_log.o connect.o sql_err.o
DBINC = -I$(ORACLE_HOME)/precomp/public
DBLIB = -L$(ORACLE_HOME)/lib -lclntsh
INCLUDE = -I$(MYHOME)/include
.SUFFIXES: .pc .c .o
.pc.o:
$(ESQL) include=$(MYHOME)/include iname=$*.pc
$(CC) -o $*.o $(CFLAGS) $*.c $(INCLUDE) $(DBINC) $(DBLIB)
$(RM) $*.c
$(RM) $*.lis
libmydb.so:$(LIBOBJ)
$(CC) -qmkshrobj -o $# $(LIBOBJ) $(DBLIB)
mv $# $(MYHOME)/lib
query:$(OBJ)
cc -o $# $(OBJ) -L$(MYHOME)/lib -lmydb
mv $# $(MYHOME)/bin
func.o:func.c
$(CC) -c $(CFLAGS) $< $(INCLUDE)
main.o:main.c
$(CC) -c $(CFLAGS) $< $(INCLUDE)
clean:
rm -f *.o *.lis
when I make I get this:
.......
cc -g -brtl -o sql_err.o -g -c sql_err.c -I/home/xxx/include -I/oracle/product/10.2.0/precomp/public -L/oracle/product/10.2.0/lib -lclntsh
rm -f sql_err.c
rm -f sql_err.lis
cc -g -brtl -qmkshrobj -o libmydb.so get_log.o connect.o sql_err.o -L/oracle/product/10.2.0/lib -lclntsh
mv libmydb.so /home/xxxlib
when it done mv libmydb.so ,it exit!!!without wrong message.why?? I also need my .c to compile to .o and finally to an executable file query link libmydb.so.
when I change the squeuce like this put .c.o before .pc.o:
query:$(OBJ)
cc -o $# $(OBJ) -L$(MYHOME)/lib -lmydb
mv $# $(MYHOME)/bin
func.o:func.c
$(CC) -c $(CFLAGS) $< $(INCLUDE)
main.o:main.c
$(CC) -c $(CFLAGS) $< $(INCLUDE)
.pc.o:
$(ESQL) include=$(MYHOME)/include iname=$*.pc
$(CC) -o $*.o $(CFLAGS) $*.c $(INCLUDE) $(DBINC) $(DBLIB)
$(RM) $*.c
$(RM) $*.lis
libmydb.so:$(LIBOBJ)
$(CC) -qmkshrobj -o $# $(LIBOBJ) $(DBLIB)
mv $# $(MYHOME)/lib
it give this message,although I have libmydb.so last step:
prepaid(wmfe)/home/xxx/src>make
cc -g -brtl -c -g -c main.c -I/home/xxx/include
cc -g -brtl -c -g -c func.c -I/home/xxx/include
cc -o query main.o func.o -L/home/xxx/lib -lmydb
ld: 0706-006 Cannot find or open library file: -l mydb
ld:open(): A file or directory in the path name does not exist.
make: 1254-004 The error code from the last command is 255.
Stop.
I can't handle this ,very strange,Help!!
By default make will make the first rule in your makefile, but it must not start with a dot. So the default rule in your makefile is libmydb.so and that is being built.
That rule is only dependent on the LIBOBJ and OBJ is not a dependency so it doesn't care about those. It doesn't exit with no reason, it exits because it has done the job you defined for it. There is no error to report.
If you change the order then the default rule is changed and it tries to compile query. This has no dependencies to the library, so it doesn't try to compile that.
If you want to compile everything you should have, for example, a rule all that lists the dependencies. In this case probably libmydb.so and query at least, in correct order. If this is the first rule it will be the default and your compilation will succeed.
I have object code that I have compiled using -fPIC switch in clang that also used the -shared switch. I have then linked all of these into a single .so shared object. Now I want to link this into a single executable file, I'm told by the man page that I should be able to do this using the
ld command and the -l switch. But when I do this, I get the following error:
ld -r -L./ -l:libmymath.so simpleone
ld: attempted static link of dynamic object `libmymath.so'
make: *** [simpleone] Error 1
I have tried doing the same thing with the -dy switch, but it gives me the same error.
I really don't understand why this wouldn't be working.
Here is the makefile I am using to do all of this.
CC= clang
LD= ld -r
CFLAGS= -std=gnu99 -g -Oz -c
CSECFL= -fPIC -I -L
CFLAG3= -shared
RM= /bin/rm -f
OBJ= math.o my*.o
SO= libmymath.so
all: math my_add my_mul
math: math.c
$(CC) $(CFLAGS) $#.c $(CSECFL)
my_add: my_add.c
$(CC) $(CFLAGS) $#.c $(CSECFL)
my_mul: my_mul.c
$(CC) $(CFLAGS) $#.c $(CSECFL)
simplemath: $(OBJ)
$(CC) $(OBJ) -o $#
simplemath.o: $(OBJ)
$(LD) $(OBJ) -o $#
lib1: my_add.o
$(CC) $(CFLAG3) my_add.o -o $(SO)
lib2: $(OBJ)
$(CC) $(CFLAG3) my_mul.o -o $(SO)
lib3: $(OBJ)
$(CC) $(CFLAG3) math.o -o $(SO)
simpleone: $(OBJ)
$(LD) -L./ -l:libmymath.so $#
clean:
$(RM) *.o simplemath* *.t $(SO)
You need to link the objects (*.o) into a static executable, not the shared lib (.so) .so can be opened by the run-time dynamic linker or via a dlopen() call.