How to link static lib in gcc make? - c

A static library is linked fine in the command line, but not through makefile. Compiling part accessing include files seems ok, but ld process must be wrong in the makefile.
Thanks for your help in advance!
Here is my command line:
gcc -o quadEq.exe quadEq.c -I../include -L../lib -lnowic
Here is my Makefile:
CFLAGS = -Wall -g -c
INCLUDE = -I../include
LDFLAGS = -L../lib
LDLIBS = -lnowic
SOURCES = quadEq.c
OBJECTS = $(SOURCES:.c=.o)
EXE = quadEq
all: $(SOURCES) $(EXE)
$(EXE): $(OBJECTS)
gcc $(OBJECTS) $(LDFLAGS) $(LDLIBS) -o $#
.c.o:
gcc $(CFLAGS) $(INCLUDE) $< -o $#
Here is my screen capture that ran Makefile and the command line.

Static libraries care in which order you link them. If libA.a depends on libB.a, then you have to do -lB -lA.
If a libA.a symbol depends on libB.a that depends on a libA.a symbol, you have to cyclically link: -lB -lA -lB. I've seen some cycles get to about 3 or 4 loops, but generally 2 is enough in my experience.
This is different from dynamic library linking which not only doesn't care what order you link them, but you don't need to also link dependent libraries since the .so specifies them.

Based on Aggieboy's suggestions, I rewrote the makefile and made it work.;
CC = gcc
CFLAGS = -x c -Wall -g
INCPATH = -I../include
LIBPATH = -L../lib
LLIBS = -lnowic
%: %.c
$(CC) -o $# $(CFLAGS) $(INCPATH) $< $(LIBPATH) $(LLIBS)
By the way, this accepts a filename to make from the command line argument.
Thank you Aggieboy again!

Related

How to resolve GNU make producing a "circular main.c" error

//makefile.conf
.SUFFIXES : .c .o
cc = gcc
CFLAG = -c
OFLAG = -o
O2FLAG = -O2
WPIFLAG = -lwringPi
RM = rm -rf
TARGET_SRCS = main.c
TARGET_OBJS = $(TARGET_SRCS:$.c=$.o)
TARGET_NAMES = $(TARGET_SRCS:$.c=$)
BINARY_NAME = LED_TEST
// makefile
include makefile.conf
$(TARGET_OBJS) : $(TARGET_SRCS)
$(CC) $(O2FLAG) $(CFLAG) $(OFLAG) $^
I'm trying to figure out how gnu make works and how to use it. Yet, I'm a beginner.
I'm trying to use make on my assignment (not mandatory, just my passion) for running simple code which lights up LED by using wiringpi.
Actually there's only one main.c and what I want to make is the makefile that runs
gcc -O2 -c -o main.o main.c
gcc -o main main.o -lwiringPi
Since my last code didn't worked, (constantly getting circular main.c <- main.c dependency dropped error)
I tried to make a code that only runs
gcc -O2 -c -o main.o main.c
but I still get circular main.c error and I don't know what that means.
I tried to look up gnu make manuals but I thought through that, it will take my life to understand.
So I'm trying to see the codes and make one with what I saw.
I think I understand the concept of makefile.conf but still don't understand the function of .SUFFIXES.
I understood it as noticing make that I'll make a rule with .c and .o, codes after that in makefile.conf defines the variables those will be used in makefile.
How can I correct the code? When actual 'assignment' took only five minute including adding comments.
First makefile:
main:
gcc -O2 -c -o main.o main.c
gcc -o main main.o -lwiringPi
When that works perfectly, second makefile:
main: main.o
gcc -o main main.o -lwiringPi
main.o: main.c
gcc -O2 -c -o main.o main.c
When that works perfectly, third makefile:
main: main.o
gcc -o $# $^ -lwiringPi
main.o: main.c
gcc -O2 -c -o $# $<
When that works perfectly, you will be ready for more advanced techniques.
If you are really new, it's often helpful to start off with simple makefiles till you need the extra features.
main: main.c
gcc -O2 -o main -lwiringPi main.c
Note the white space before the gcc is a single tab character.
Once you get the hang of that, you can then substitute various items to make your "make rules" easier to duplicate and maintain. For example, %^ means "every dependent source, so a rewrite of the rule would be
main: main.c
gcc -O2 -o main -lwiringPi $^
Occasionally, you might want to offer easy reconfiguration of the compiler, so if you had a dozen rules, and wanted to configure the compiler all in one place
CC=gcc
main: main.c
$(CC) -O2 -o main -lwiringPi $^
would expand the CC variable to the value gcc at make time. There's an upper limit to the utility of this expansion, for example, if something is "one of many of the same thing" You might not want to declare a variable for that individual item. For example, your WPIFLAG is likely always required, and probably not very successfully reconfigurable. Mabye a loader flags variable makes more sense.
LDFLAGS=-lwiringPi -lm -lwhatever
and a compiler flags variable
CFLAGS=-O2 -Werror -Wfatal-errors
Which would lead to the more sensible
main: main.c
$(CC) $(CFLAGS) -o main $(LDFLAGS) $^
Finally, you can replace the target main in this case, with another special variable. $# which means "the target being built"
main: main.c
$(CC) $(CFLAGS) -o $# $(LDFLAGS) $^
Note that for object files, you are listing all your objects as being dependent on all of your sources. If you want to support independent rules for object building, you need to do something different
main: main.o
$(CC) $(CFLAGS) -o $# $(LDFLAGS) $^
And you'll need rules for each object.
main.o: main.c
$(CC) $(CFLAGS) -c -o $# $(LDFLAGS) $^
but it will become a labor typing this rule for each object. To automate this rule, you will use a pattern based on the file suffixes, and a suffix rule.
.SUFFIXES : .o .c
.c.o :
$(CC) $(CFLAGS) -c $<
Note the rule above relies on the default behavior of $(CC) which is to generate a something.o when something.c is compiled with the -c flag. If you wanted to make the output file explicit
.SUFFIXES : .o .c
.c.o :
$(CC) $(CFLAGS) -c -o $# $<
This Suffix Rule acts as a macro. When someone needs thing.o, it will build it from thing.c if thing.c exists, even if there isn't an explicit rule for thing.c
With this, you can then collect all your object on the original main target. (We will remove CFLAGS, as no compiling will be happening, only linking)
main: main.o other.o first.o list.o end.o
$(CC) -o $# $(LDFLAGS) $^
But some find listing the object to be a pain, and like to put them in a variable
main: $(OBJS)
$(CC) -o $# $(LDFLAGS) $^
which means you will need to declare and set OBJS
OBJS = main.o other.o first.o list.o end.o
But it's sort of weird to track intermediate files, so why not track the actual sources
SOURCES = main.c other.c first.c list.c end.c
Ok, but how will we get the required OBJS from SOURCES? We will derefence SOURCES, modifying the suffixes to .o
OBJS = ${SOURCES:.c=.o}
The end result
SOURCES = main.c other.c first.c list.c end.c
OBJS = ${SOURCES:.c=.o}
CC=gcc
CFLAGS=-O2 -Werror -Wfatal-errors
LDFLAGS=-lwiringPi -lm -lwhatever
.SUFFIXES : .o .c
.c.o :
$(CC) $(CFLAGS) -c -o $# $<
main: ${OBJS}
$(CC) -o $# $(LDFLAGS) $^

fedora 22 multiple undefined reference errors when linking shared object

I am trying to compile a C language library as a shared object on my new install of Fedora 22. The project compiled fine on my old install of Fedora 20. But now, when I run my makefile:
CC=gcc
vpath %.c src
vpath %.h inc
CFLAGS = -fPIC
INCLUDE = -Iinc -I/usr/include -I/usr/local/include
LIBPATH = -L/usr/lib -L/lib64
LIBS = -lportaudio -lm -lpthread -ldl
OBJ_PATH = ./objs
SRCS = my_code1.c my_code2.c # etc.
OBJS = $(SRCS:.c=.o)
.PHONY: libmylib.so
all: libmylib.so
debug: $(CFLAGS) += -DDEBUG -O0 -g3 -DPD
debug: all
release: $(CFLAGS) += -DTESTING -O2 -DPD -funroll-loops -fomit-frame-pointer
release: all
%.o: %.c
$(CC) $(CFLAGS) $(INCLUDE) $(LIBPATH) $(LIBS) -c -o $# $^
libmylib.so: $(OBJS)
$(CC) -shared -Wl,-soname,libmylib.so \
-Wl,--no-undefined $(OBJS) -lc -lportaudio -ldl -lm -lpthread
mv libmylib.so ./bin
mv *.o $(OBJ_PATH)
clean:
rm $(OBJ_PATH)/*.o
rm bin/libmylib.so
I get very many undefined reference errors:
my_code1.o: In function `func_in_my_code1':
my_code1.c:(.text+0x1b8): undefined reference to `func_from_my_code2'
my_code2.o: In function `func_in_my_code2':
my_code2.c:(.text+0x310): undefined reference to `func_from_my_func1'
The functions in question are most certainly defined in the code. Presumably these are compiled into .o files in the compile stage.
The exact same build environment worked on my previous fedora installation. I am at a loss as to why I should get these errors.
Also, if I compile without the -Wl,--no-undefined flag, it compiles fine, but when I try to load the library from another application, it tosses the same set of undefined errors.
This may have nothing to do with the new version of Fedora. It is possible that there are some environment variables or something that didn't make through to my new install, but I have no idea what they could be.
Apparently I now need to insert the extern keyword into these functions. The code compiled and ran perfectly well before... I would like to reiterate, for posterity's sake, that I did post the entire makefile in my question.

Undefined reference and linking libraries

I'm experiencing some compilation issues with my dynamic library. It should be linked to main.c but for all references to it I receive "undefined reference to function_name".
The contents of main.c isn't really that important; I include my library:
#include "matrix.h"
Then I have a simple Makefile to link the two.
#Variables
LIB = matrix
# Usual compilation flags
CFLAGS = -std=c99 -Wall -Wextra -g
CPPFLAGS = -I../include -DDEBUG
LDFLAGS = -lm
# Special rules and targets
.PHONY: all clean help
all: $(LIB).o libmatrix.so main
$(LIB).o: $(LIB).c $(LIB).h
$(CC) $(CFLAGS) $(CPPFLAGS) -fPIC -c -o $# $<
libmatrix.so: $(LIB).o
$(CC) $(CFLAGS) -fPIC -shared -o $# $< $(LDFLAGS)
main: main.o libmatrix.so
$(CC) $(CFLAGS) -o $# $< -L -lmatrix
Can anyone direct me to where I might be going wrong? Many thanks in advance.
You probably want -L. not -L in your last line, so:
main: main.o libmatrix.so
$(CC) $(CFLAGS) -o $# $< -L. -lmatrix
You should read Program Library HOWTO and Drepper's paper: How to Write Shared Libraries; you might want to set some -rpath at link time (maybe using -Wl,-rpath,. ...), and you might want to link with -rdynamic ....
Alternatively, set your LD_LIBRARY_PATH environment variable to contain . (I don't recommend that), or install your shared library in /usr/local/lib/ (and add it to /etc/ld.so.conf then run ldconfig). See also dlopen(3), environ(7), ld.so(8), ldconfig(8)

"make clean" causes "make all" failure

When I execute this Makefile without clean, it functions OK and both the shared library and the main executable are created correctly. However, when I add the clean target, the "make all" fails. What could be the reason?
CC = gcc
CFLAGS = -fPIC -Wall -Werror
LDFLAGS = -shared
TARGET_LIB= libnsd.so
lib: nsd.o nd.o
$(CC) $(LDFLAGS) -o ${TARGET_LIB} nsd.o nd.o -lm
nd.o : nd.c nd.h
$(CC) -c $(CFLAGS) nd.c
nsd.o : nsd.c nsd.h
$(CC) -c $(CFLAGS) nsd.c
all: main.c
$(CC) -o -I. -L. main.c -lnsd
clean:
rm -f libnsd.so nd.o nsd.o
Your all: target needs to depend on the lib target, so the library is built first.
The -o argument to the compiler also needs a name for executable it should create.
all: lib main.c
$(CC) -o main -I. -L. main.c -lnsd
Normally you want the target name to be the file that you create, otherwise things get rebuilt when it's not needed. (the lib: target has the same issue) but as an exampe for the executable:
.PHONY: all
all: lib main
main: lib main.c
$(CC) -o main -I. -L. main.c -lnsd
nos's answer is on the right track.
It only appeared to work before, because you happened to run make in the right order. It won't work after a clean operation because, as nos points out, you have not declared all of your prerequisites. The rule that links main.o must depend on the shared library target, so make knows the right order to build things.
Also, you REALLY want your targets to be the actual file you're building. If they're something else, then make will always think they're out of date even if you haven't changed anything, and always rebuild them.
Something like this will be better:
CC = gcc
CFLAGS = -fPIC -Wall -Werror
CPPFLAGS = -I.
LDFLAGS = -shared
PROGRAM = main
TARGET_LIB= libnsd.so
all: $(PROGRAM)
$(PROGRAM): main.o $(TARGET_LIB)
$(CC) -o $# -L. main.o -lnsd
$(TARGET_LIB): nsd.o nd.o
$(CC) $(LDFLAGS) -o $# nsd.o nd.o -lm
nd.o : nd.c nd.h
nsd.o : nsd.c nsd.h
clean:
rm -f libnsd.so *.o

Unable to link math lib using a makefile [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Linker errors when compiling against glib…?
Okay, I know this may be a duplicate, but I can't find any other answer to my problem.
I am trying to install Pintos and when I run 'make' in the src/utils directory, I get the error that there is an undefined reference to 'floor'. I checked the makefile and here's what I got:
all: setitimer-helper squish-pty squish-unix
# 2207718881418
CC = gcc
CFLAGS = -Wall -W
LDFLAGS = -lm
setitimer-helper: setitimer-helper.o
squish-pty: squish-pty.o
squish-unix: squish-unix.o
clean:
rm -f *.o setitimer-helper squish-pty squish-unix
I tried adding LIBS = -lm but that didn't help.
Output of make:
gcc -lm setitimer-helper.o -o setitimer-helper
setitimer-helper.o: In function `main':
setitimer-helper.c:(.text+0xbb): undefined reference to `floor'
collect2: ld returned 1 exit status
make: *** [setitimer-helper] Error 1
Any solutions to this dilemma?
Your original makefile defines a bunch of variables
CC = gcc
# etc
and lists some dependencies
setitimer-helper: setitimer-helper.o
# etc
but doesn't have any recipes giving the exact commands to be used to remake the targets, except for the clean rule. This means that built-in implicit rules will be used; e.g., to link setitimer-helper the following built-in rule will be used:
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $#
For setitemer-helper, the automatic variables are filled in using the relevant dependency:
$(CC) $(LDFLAGS) setitimer-helper.o $(LDLIBS) -o setitimer-helper
and from this you can see how the remaining variables -- $(CC), $(LDFLAGS), and $(LDLIBS) -- were filled in to give the output of make that you saw.
As various people have noted, you need to make sure that -lm goes at the end of the link command so that it can be used to satisfy references to library functions like floor(). At the moment, your makefile sets $(LDFLAGS) to -lm, but that variable is used at the start of the link command.
The conventional variables are set up in this built-in rule so that LDFLAGS can be used for options (a.k.a. "flags") that (historically) need to be at the start of the link command, and LDLIBS can be used for libraries that need to be specified after the *.o object files.
So to fix this in terms of the makefile you are using, you need to remove -lm from the LDFLAGS variable that is defined, and instead add another variable definition for LDLIBS:
LDLIBS = -lm
(I'm oversummarising slightly: the built-in rule also contains $(TARGET_ARCH) and $(LOADLIBES), but those aren't of interest here.)
It's compiled in wrong order, the way to proceed is:
CC = gcc
CFLAGS = -Wall -W
LDFLAGS = -lm
myprog: myprog.o more_code.o
${CC} ${CFLAGS} myprog.o more_code.o ${LDFLAGS} -o myprog
myprog.o: myprog.c
${CC} ${CFLAGS} -c myprog.c
more_code.o: more_code.c
${CC} ${CFLAGS} -c more_code.c
clean:
\rm myprog.o more_code.o myprog
More info: http://www.physics.utah.edu/~p5720/rsrc/make.html
Can you show me in terms of the original makefile?
I can try :)
CC = gcc
CFLAGS = -Wall -W
LDFLAGS = -lm
OBJECTS = setitimer-helper.o squish-pty.o squish-unix.o
all: setitimer-helper
setitimer-helper: $(OBJECTS)
${CC} ${CFLAGS} $(OBJECTS) ${LDFLAGS} -o setitimer-helper
setitimer-helper.o: setitimer-helper.c
${CC} ${CFLAGS} -c setitimer-helper.c
squish-pty.o: squish-pty.c
${CC} ${CFLAGS} -c squish-pty.c
squish-unix.o: squish-unix.c
${CC} ${CFLAGS} -c squish-unix.c
And since you are new to Makefile, it's a good idea to add -Wextra -pedantic to CFLAGS

Resources