"undefined reference to function" error on a function in the library - c

I am trying to work with id3 tags with C, so I downloaded mplib and installed it.
I am trying to call this function inside mplib.h where __P is a Macro
extern id3_tag_list* mp_get_tag_list_from_file __P((const char* path));
by writing in
example.c:
int main() {
char* pa = "R U MINE";
id3_tag_list* list = mp_get_tag_list_from_file(pa);
id3_tag *newTag = list->tag;
printf("tag %d\n", newTag->version);
return 0;
}
but when I link, I get an error:
example.o: In function `main':
example.c:(.text+0x27): undefined reference to `mp_get_tag_list_from_file'
collect2: error: ld returned 1 exit status
make: *** [example] Error 1
My makefile looks like this
OBJECTS = example.o
target=example
misc=Makefile
cflags=-Wall -g -O0 -Werror -pedantic -std=c99
all: $(target)
$(target) : $(OBJECTS) $(misc)
gcc $(cflags) -o $(target) $(OBJECTS)
clean:
rm -f $(OBJECTS) $(target)
I am having trouble compiling this. I believe the problem is that I am having issues with linking it to the actual mplib.c file where that function is actually defined, but I am not sure how to do it exactly. I got the library from http://mplib.sourceforge.net/ and I installed it by using 'make' and 'make install'. Am I supposed to manually move the mplib.c file somewhere?

If you build mplib 1.0.3, it creates a library libmp.a. Therefore, you need to specify -lmp on the linker command line, and perhaps -L /where/you/installed/it/lib to specify the directory where the library was installed.
The linker command line should probably look like:
LDFLAGS = -L/usr/local/lib
LDLIBS = -lmp
gcc $(cflags) -o $(target) $(OBJECTS) $(LDFLAGS) $(LDLIBS)
Actually, it would be better if it looked like:
$(CC) $(CFLAGS) -o $# $(OBJECTS) $(LDFLAGS) $(LDLIBS)
The upper-case macro CFLAGS is used for flags to the C compiler. $# means 'the name of the current target'. LDFLAGS are flags for the linker, such as where to find libraries, and LDLIBS contains the specification of libraries. An option such as -lmp means 'look for libmp.so or libmp.a in each of the directories on the list of places searched for libraries' (to a sufficiently close approximation). The -L option prefixes the following directory to the list of places searched for libraries.

Related

Makefiles giving the compiler files that dont/shouldnt exist

I have a basic Makefile setup for C OpenGL programming but when running there are 2 files passed to clang that shouldnt exist and i have no idea why. The problem happened after i added glad and glfw to the project.
code:
CC = clang
`CCFLAGS = -lGL -lglfw -std=c++20 -v -Wall -Wextra -Wepedantic -g -lgdi32
LDFLAGS = lib/glad/src/glad.o lib/glfw/src/libglfw3.a -lgdi32 -lm
SRC = $(wildcard src/*.c)
OBJ = $(SRC:.c=.o)
BIN = bin
all: libs build
libs:
cd lib/glad && $(CC) -o src/glad.o -Iinclude -c src/glad.c
cd lib/glfw && cmake . -G 'Unix Makefiles' && make
build: $(OBJ)
$(CC) -o $(BIN)/build $^ $(LDFLAGS)
%.o %.c:
$(CC) -o $# -c $< $(CCFLAGS)
run:
./bin/build.exe
ERROR:
clang: error: no such file or directory: 'all.o'
clang: error: no such file or directory: 'libs'
clang: error: no such file or directory: 'build'
When asking questions please include the command you typed, the command make printed, plus at least the first and last few lines of error messages (properly formatted as code blocks).
I'm assuming that the extra quote character is an error in your cut and paste; please take a moment to review your question after you post it (or even better, using the preview before you post it). You are writing this one time, but tens or hundreds of people will spend their time reading it. Please be considerate enough to make it easy for them.
Your problem is this:
%.o %.c:
$(CC) -o $# -c $< $(CCFLAGS)
You want to say "build a .o file from a .c file using this rule", but %.o %.c: says instead, "build both a .o and a .c file, from nothing, using this rule".
You need:
%.o: %.c
$(CC) -o $# -c $< $(CCFLAGS)

How do you construct a C makefile so that it compiles the source.c file?

I have three files. main.c, graph.c, and graph.h.
I know the code works without a makefile because I tested it on the onlinegbd compiler. Everything runs smoothly.
When I try to run my makefile in terminal, I get an error of:
undefined reference to "function"
Where "function" is every function I call in main that is in graph.c.
So this leads me to think I'm not compiling graph.c in my makefile.
edit
I have confirmed it is the makefile. I compiled it using:
gcc -o xGraph main.c graph.c
And it ran without issue.
Here is the makefile:
CC = gcc
VPATH = SRC INCLUDE
TARGET = XGraph
CFLAGS = -g -Wall
all: $(TARGET)
$(TARGET): main.o graph.o
$(CC) main.o graph.o -o $(TARGET)
main.o: main.c graph.h
$(CC) $(CFLAGS) main.c
graph.o: graph.c graph.h
$(CC) $(CFLAGS) graph.c
clean:
rm *.o *~ $(TARGET)
When compiling C code the first stage is to generate .o files. Pass the -c flag to gcc to do this.
main.o: main.c graph.h
$(CC) $(CFLAGS) -c main.c
graph.o: graph.c graph.h
$(CC) $(CFLAGS) -c graph.c
In C, there are two types of undefined reference errors. The first results in an implicit declaration of function error, while the second gives your undefined reference. The first says gcc cannot find a definitition of your function. but the second means gcc sees nothing wrong with your code, then tries to link object files using ld and that crashes the code. Make sure that your source files are included in compilation and they have declarations, not just definitions. Also, providing a minimum reproducible example of your code might be helpful here.
Your simplest Makefile can be:
CFLAGS = -g -Wall
xGraph_objs = main.o graph.o
xGraph: $(xGraph_objs)
$(CC) $(CFLAGS) $(LDFLAGS) -o $# $(xGraph_objs)
main.o graph.o: graph.h
as there are implicit rules (that use the $CFLAGS variable, so you don't need to add rules to do the compilation, just to specify the extra dependencies between the objects and the header file)
The structure I use frequently for small projects is very similar to yours:
targets = xGraph
toclean = $(targets)
xGraph_deps = # no dependencies to link the executable. (E.g. creating a library needed to link this)
xGraph_objs = main.o graph.o
xGraph_libs = # no libs to specify at link time. (E.g. -lm -lX11)
xGraph_ldfl = # no flags for the linker. (E.g. -L/usr/local/lib)
toclean += $(xGraph_objs)
all: $(targets)
clean:
$(RM) $(toclean)
xGraph: $(xGraph_deps) $(xGraph_objs)
$(CC) $(LDFLAGS) $(xGraph_ldfl) $(xGraph_objs) -o $# $(xGraph_libs)

gcc - how to create an so from a source file and other o files?

I am working on a c project. https://github.com/eantoranz/gitmod It's broken up into separate c/h files. In my current Makefile, I take each one of the c files and compile them into their own .o file, then when I want to create the final program, I ask to compile a c file that has a main and provide all the other .o files. So far, so good (let me know if this approach is not correct).
As a next step, I want to separate the main part of the program from all the other pieces of the code and would like to pack all of the previous o files into a single so file (that had been compiled as just another .o file so far).
So, old approach was like this:
gitmod.o: src/gitmod.c include/gitmod.h lock.o root_tree.o thread.o object.o cache.o
$(CC) -c -o $# $< $(CFLAGS)
gitmod: src/main.c gitmod.o
$(CC) $< *.o -o $# $(CFLAGS)
These would be the last 2 steps of this process using the so replacing gitmod.o for libgitmod.so, after creating all the previous .o files:
libgitmod.so: src/gitmod.c include/gitmod.h lock.o root_tree.o thread.o object.o cache.o
$(CC) $< *.o -shared -o $# $(CFLAGS)
gitmod: src/main.c libgitmod.so
$(CC) $< -llibgitmod.so -o $# $(CFLAGS)
libgitmod.so would be the shared library that I would like to actually contain all the other sections of code (I really hope that is possible).
When make is going through libgitmod.so, I am getting this:
gcc src/gitmod.c *.o -shared -o libgitmod.so -Iinclude `pkg-config fuse3 libgit2 glib-2.0 --cflags --libs` -DGITMOD_DEBUG -Wall -g
/usr/bin/ld: object.o: warning: relocation against `stderr##GLIBC_2.2.5' in read-only section `.text'
/usr/bin/ld: /tmp/ccir4Ou9.o: relocation R_X86_64_PC32 against symbol `stderr##GLIBC_2.2.5' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: bad value
collect2: error: ld returned 1 exit status
make: *** [Makefile:32: libgitmod.so] Error 1
What am I doing wrong?
-fPIC, which means Position Indepent Code, flags is required to create shared object.
You can add the flag in the compile flag, then you can create a shared object.

Handling #include <folder/file.h> in C with makefiles

I am in the process of porting some code that was developed in the codeblocks IDE. I am transferring it to a Linux server where I can only use the command line to compile the code. The code is quite large (maybe 100 files) and I need to update the include commands in many files. For when I try to compile it errors on for instance: #include <gsl/gsl_math.h> with a file cannot be found error. I am assuming it cannot be found because the location of the gsl folder was declared in one of the search directory field options in the IDE. I could go through each file an update to the correct path, but is there a better way of doing this for use with a makefile?
Thanks!
EDIT Makefile In Question
# -c : do not link, just create object file
# -o : output file name
CFLAGS += -c -O2 -I../ctraj -I../cspice/include -I../SGP4 -I../cconj -I../GSL-1.13/include
LIBS = -L../ctraj -lctraj -L../cspice/lib -lcspice -L../SGP4 -lsgp4 -L../cconj -lcconj -L./ -lgsl-0 -lgslcblas-0 -lm
DEPS = light.h ../ctraj/ctraj.h ../cconj/cconj.h
OBJ = light.o tle.o propagator.o orbitfit.o conjunction.o light_displacement.o forces_LF.o
OUT = light.exe
%.o: %.c $(DEPS)
gcc -o $# $< $(CFLAGS)
light: $(OBJ)
cd ../ctraj/; make
gcc -o $(OUT) $(OBJ) $(LIBS)
clean:
rm *.o $(OUT)
Edit 2
Folder Structure
light->(GSL-1.13, Light, cconj, ctraj)
the makefile is inside the Light folder.
Error Message
cd ../ctraj/; make
make[1]: Entering directory `/light/ctraj'
gcc -o forces.o forces.c -c -Wall -Wno-maybe-uninitialized -Wno-unused-but-set-variable -O2 -I../cspice/include -Inrlmsise
In file included from ../Light/../cconj/cconj.h:12:0,
from ../Light/light.h:13,
from forces.c:3:
../Light/../cconj/../GSL-1.13/include/gsl/gsl_blas.h:26:28: fatal error: gsl/gsl_vector.h: No such file or directory
compilation terminated.
make[1]: *** [forces.o] Error 1
make[1]: Leaving directory /light/ctraj'
make: *** [light] Error 2
EDIT 3
Second makefile in cconj
# -c : do not link, just create object file
# -o : output file name
#-L../cconj -lcconj
CFLAGS += -c -O2 -I./ -I../GSL-1.13/include
LIBS = -L./ -lgsl-0 -lgslcblas-0 -lm
INC= -I../GSL-1.13/include
DEPS = cconj.h
OBJ = cconj_util.o ellipse_intersect.o collision_prob_real.o rcs2size.o
OUT = libcconj.a
%.o: %.c $(DEPS)
gcc -o $# $< $(CFLAGS)
cconj: $(OBJ)
ar rcs $(OUT) $(OBJ)
clean:
rm *.o $(OUT)
Try adding this line to your makefile, and tell us if it works:
CFLAGS += -I../GSL-1.13/include
In order to compile source code and produce object files, Make must use a rule. (If you don't put such a rule in the makefile, Make has a default rule for that purpose.) It looks something like this:
%.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $#
Without digging too deeply into how that works, we can say that CFLAGS is a list of arguments to be passed to the compiler. When we add -I../GSL-1.13/include, we tell the compiler "if you want to #include something and can't find it elsewhere, look in ../GSL-1.13/include".
If this approach doesn't work, then there's probably a rule in the makefile we must find and alter.
EDIT:
The problem isn't in this makefile (which already contains a reference to GSL-1.13/include). In this command:
cd ../ctraj/; make
this makefile launches a second Make process, which uses the Makefile in light/cconj/. According to the compiler output (gcc -o forces.o ...), that makefile does not include the reference. So try adding the same line there, and if that doesn't work, post that makefile and we'll keep looking.
Use -I option of gcc to specify where to look for includes.

C Makefile trouble: "gcc: -lm: linker input file unused because linking not done mpicc -lm 3D-ELM.o -o 3D-ELM.exe"

I'm having some trouble with a C Makefile.
Here are the contents of the Makefile:
PROJECT = 3D-ELM
MPICC = mpicc
CLAGS = -g -O3
LIBS = -lm
SRC = src_el
OBJECTS = $(PROJECT).o
$(PROJECT).exe : $(OBJECTS)
$(MPICC) $(CFLAGS) $(LIBS) $(OBJECTS) -o $(PROJECT).exe
$(PROJECT).o : $(SRC)/$(PROJECT).c
$(MPICC) $(CFLAGS) $(LIBS) -c $(SRC)/$(PROJECT).c
clean:
rm -rf *o $(PROJECT)
When I make, here is the error:
gcc: -lm: linker input file unused because linking not done
Does anyone know what's wrong?
Many thanks in advance,
EDIT: Got it. I don't need to pass libs when making the object file... Doh! bangs head off desk
Thanks for all your help guys,
The problem comes from this part of the makefile:
$(PROJECT).o : $(SRC)/$(PROJECT).c
$(MPICC) $(CFLAGS) $(LIBS) -c $(SRC)/$(PROJECT).c
At this step you are only invoking the compiler. The -c switch tells the compiler only to compile to an object file, and the linker is not involved at all. Since there is nothing to link, the $(LIBS) part is unnecessary.
The actual linking is done at the following stage:
$(PROJECT).exe : $(OBJECTS)
$(MPICC) $(CFLAGS) $(LIBS) $(OBJECTS) -o $(PROJECT).exe
This is where the individual object files are merged together with the libraries to produce an executable. The compiler itself is not invoked at this point because the source files have already been transformed into object files.

Resources