C : Unix SDL2 library : undefined reference, issue in the Makefile? - c

I'm looking to make a Makefile that can compile a C program on Unix (Ubuntu). That Makefile should include the SDL library (2.0), as well as SDL_image.
So here's my current Makefile :
CC = gcc
OBJECTS = $(patsubst %.c,%.o,$(wildcard *.c))
EXEC = main
LDFLAGS = `sdl2-config --libs` -L/usr/lib -lSDL2_image
CCFLAGS = `sdl2-config --cflags` -I/usr/include/SDL_image.h
$(EXEC): $(OBJECTS)
$(CC) $(LDFLAGS) $< -o $#
%.o: %.c
$(CC) -c $(CCFLAGS) $< -o $#
.PHONY: clean
clean:
rm -f $(OBJECTS) $(EXEC)
And here's my current code (minimal code just to test the Makefile):
#include <stdio.h>
#include <SDL.h>
#include <SDL2/SDL_image.h>
int main(int argc, char **argv) {
SDL_Window* window = NULL;
SDL_Surface* screenSurface = NULL;
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
printf("Initialization error: %s\n",SDL_GetError());
return 1;
}
window = SDL_CreateWindow("Test",SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,640, 480,SDL_WINDOW_SHOWN);
SDL_Quit();
return 0;
}
So when I write the command : make
I get errors on all of the SDL functions.
Here's an example : undefined reference to `SDL_Init'
I have tried many things (such as different paths for the Include and Link in the Makefile), but nothing seems to work.
So my question is : How can I solve theses undefined references to SDL2 functions ?

You are specifying linker flags in the wrong order.
This is wrong:
LDFLAGS = `sdl2-config --libs` -L/usr/lib -lSDL2_image
$(EXEC): $(OBJECTS)
$(CC) $(LDFLAGS) $< -o $#
This is correct:
LIBS = `sdl2-config --libs` -L/usr/lib -lSDL2_image
$(EXEC): $(OBJECTS)
$(CC) $(LDFLAGS) $^ $(LIBS) -o $#
With GNU Binutils, the order of libraries is important. Libraries must come after the objects which have undefined references to symbols in those libraries. It sucks, it's stupid, but it's the way GNU Binutils works and you're stuck with it.
Other fixes
You want $^ instead of $<, because $< is only the first dependency.
Probably best to use pkg-config which can find SDL2_image for you:
LIBS = `pkg-config --libs sdl2 SDL2_image`
You probably want := not = when you invoke shell programs, this will expand the variable once, instead of every time it is used:
LIBS := $(shell pkg-config --libs sdl2 SDL2_image)
CFLAGS := $(shell pkg-config --cflags sdl2 SDL2_image)
Full example
Here is a cleaned up example, close to how I would write it:
# use := not =
# convention: objects, exec are lower-case because they're private
objects := $(patsubst %.c,%.o,$(wildcard *.c))
CFLAGS := $(shell pkg-config --cflags sdl2 SDL2_image)
LIBS := $(shell pkg-config --libs sdl2 SDL2_image)
# Don't define CC, because the default (cc) is fine
# It's probably linked to gcc on your system anyway
# = or := doesn't matter here
exec = main
# must use = here
depflags = -MF $(patsubst %.o,%.d,$#) -MMD -MP
-include $(wildcard *.d)
$(exec): $(objects)
$(CC) $(LDFLAGS) $^ $(LIBS) -o $#
%.o: %.c
$(CC) $(depflags) -c $(CCFLAGS) $< -o $#
.PHONY: clean
clean:
rm -f *.o *.d $(exec)

You inverted some compiler/linker options:
# linker options
LDFLAGS = `sdl2-config --libs` -I/usr/include/SDL_image.h
# compiler options
CCFLAGS = `sdl2-config --cflags` -L/usr/lib -lSDL2_image
It should be:
# linker options
LDFLAGS = `sdl2-config --libs` -L/usr/lib -lSDL2_image
# compiler options
CCFLAGS = `sdl2-config --cflags` -I/usr/include
Details:
-L Is to indicate to the linker where to find .so files
-l Is to link to a given library
-I Is to indicate to the compiler where to find .h files

As can be seen in the Catalogue of Built-In Rules:
Linking a single object file
n is made automatically from n.o by running the linker (usually called
ld) via the C compiler. The precise recipe used is:
$(CC) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS)
and Variables Used by Implicit Rules:
LDFLAGS
Extra flags to give to compilers when they are supposed to invoke the linker,
ld, such as -L. Libraries (-lfoo) should be added to the LDLIBS variable
instead.
So in this case -lSDL2_image should be set or added to LDLIBS, not LDFLAGS.

Related

How to create a makefile?

I need to create a makefile for an assignment I need to run on Linux. I have no idea how to write makefiles.
The structure of the project is as follows:
Logic.h
Max.h which includes Logic using a header guard in the following way:
#ifndef _GUI
#include "Logic.h"
#endif
GUI.h which includes max.h and logic.h in the following way:
#ifndef _GUI
#define _GUI
#include "Logic.h"
#include "Minimax.h"
#endif
prog.h which includes GUI.h (prog is the main file - the main function is there)
All the header files have corresponding .c files that include only their respective header.
GUI.h uses SDL 1.2 so it includes also the following
#include "SDL.h"
#include "SDL_video.h"
I understand that special flags have to be inserted to the makefile so the SDL can run properly.
This is an example of a makefile that includes only one SDL file so it has the flags for sdl and the flags they require for notifying about errors and warnings:
all: sdl_test
clean:
-rm sdl_test.o sdl_test
sdl_test: sdl_test.o
gcc -o sdl_test sdl_test.o -lm -std=c99 -pedantic-errors -g `sdl-config --libs`
sdl_test.o: sdl_test.c
gcc -std=c99 -pedantic-errors -c -Wall -g -lm sdl_test.c `sdl-config --cflags`
But I don't know how to create a makefile for this file (project) structure, and where to put the SDL flag - only for the files that have SDL, or only the file that have SDL and include files that have SDL or all files.
This is a simple example
OBJECTS = sdl_test.o # add more files just separated by spaces -> filename.o
LDFLAGS = -lm `sdl-config --libs`
CFLAGS = -Wall -Werror -pedantic -g3 -O0 # full debugging on
CC = gcc
TARGET = sdl_test
all:
$(CC) -o $(TARGET) $(OBJECTS) $(LDFLAGS)
clean:
#rm $(OBJECTS) $(TARGET)
%.o: %.c
$(CC) $(CFLAGS) -c $<
Don't copy and paste because Makfiles require tabs for indentation.
A quick and dirty Makefile (i.e., one you don't really want to distribute for a finished product) could be just
SRCS = Max.c GUI.c prog.c
OBJS := $(patsubst %.c, %.o, $(SRCS))
.PHONY: all clean
.DEFAULT_GOAL = all
all: sdl_test
clean:
-rm $(OBJS) sdl_test
sdl_test: $(OBJS)
gcc -o $# $^ -lm -std=c99 -pedantic-errors -g `sdl-config --libs`
%.o: %.c
gcc -std=c99 -pedantic-errors -c -Wall -g -lm $< `sdl-config --cflags`
See Make automatic variables for details, but briefly the special make variables mean
$# - the thing that comes before the colon
$< - the first thing that comes after the colon
$^ - everything that comes after the colon

Makefile: wildcard and patsubst does not change file source names

I am trying to write a Makefile for my project, all the *.c and *.h files are in a folder called src, and the Makefile looks like this --
CC := gcc
CFLAGS := -g -Wall -ansi -pedantic -std=gnu99
LDFLAGS := -lm
INCLUDES := $(wildcard src/*.h)
IFLAGS := $(addprefix -I/,$(INCLUDES))
SRC := $(wildcard src/*.c)
OBJS := $(patsubst %.c, %.o, $(SRC))
APP := app
all: $(OBJS)
$(APP): $(OBJS)
$(CC) $(CFLAGS) $< -o $# $(LDFLAGS)
$(OBJS): $(SRC) $(INCLUDES)
$(CC) $(CFLAGS) $(IFLAGS) -c $< -o $#
clean:
rm -rf $(OBJS)
rm -rf *.out
rm -f $(APP)
At this point I am not building the executable, just trying to compile them to object files, so when I run, I am getting this output --
gcc -g -Wall -ansi -pedantic -std=gnu99 -I/src/structure.h -I/src/rng.h -c src/allocate.c -o src/allocate.o
gcc -g -Wall -ansi -pedantic -std=gnu99 -I/src/structure.h -I/src/rng.h -c src/allocate.c -o src/auxiliary.o
gcc -g -Wall -ansi -pedantic -std=gnu99 -I/src/structure.h -I/src/rng.h -c src/allocate.c -o src/decode.o
gcc -g -Wall -ansi -pedantic -std=gnu99 -I/src/structure.h -I/src/rng.h -c src/allocate.c -o src/display.o
You can see that in each gcc invocation, the source file names do not change, they are all always src/allocate.c why ? However, the object names are correctly expanded like src/allocate.o, src/auxiliary.o and src/decode.oetc.
It seems you've mixed up some things here.
They are basically two type of rules you need to use here, and they both share the same syntax:
targets : prerequisites
recipe
When you write this:
$(APP): $(OBJS)
$(CC) $(CFLAGS) $< -o $# $(LDFLAGS)
You're saying to make that you want to create $(APP), and to do that you need $(OBJS) to exist or to be created.
Now when you write this:
$(OBJS): $(SRC) $(INCLUDES)
$(CC) $(CFLAGS) $(IFLAGS) -c $< -o $#
You're telling make you want to create a list of .o files, and for each individual file that you need all $(SRC) and $(INCLUDES).
Since in the recipe you're using $<, which is a shortcut for the first entry in the prerequisites list, you always end up with the same source file being compiled.
To do what you want, you must abstract things a little bit and tell make "Here is how I want you to build any .o file that depends on a corresponding .c". That is the job of pattern rules:
%.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -o $# -c $<
Ultimately, your Makefile should look like this:
APP := app
SRC := $(wildcard src/*.c)
OBJ := $(SRC:.c=.o)
CFLAGS := -W -Wall -g -std=c99 -pedantic
LDLIBS := -lm
all: $(OBJS)
$(APP): $(OBJ)
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $#
clean:
$(RM) $(APP) $(OBJ)
Note another couple of things here that you missed:
The -I preprocessor flag (that should be placed in the CPPFLAGS variable) accept a directory, not a file.
The -ansi compiler flag is a synonym of -std=c89. You're using -std=gnu99 right after so that one will be picked ultimately
You don't need to list your header files at all. Don't bother.
Don't use the -r flag of the rm command without care, you'll end up removing folders. It is not used to remove multiple files but to remove recursively, read up your man.
You used $< instead of $^ at the linking phase, so your executable will miss many object files.
To address the comments:
GNU make has a lot of predefined rules, functions and variables that you should be using before rolling your own. It has basic rules for compiling and linking C and C++ programs, among other, this is why your Makefile does not need te redefine the %.o: %c rule that already exists.
You can see all of these by typing this in your favorite shell:
$ make -p > predefined.mk
$(RM), $(CC) are one of these predefined variables, you can see by yourself what they actually contain.
Now, as many users are concerned with header files dependencies, let's adress this issue. You won't have to manually do that, modern compilers like GCC and Clang do this for you once you set them up.
The dependencies for each .c file will be generated in a .d file that must be included in the Makefile.
To tell the compiler to generate these files while compiling, you need to pass a preprocessor flag:
CPPFLAGS := -MMD
Now the dependencies are auto-generated, we need to include them:
DEP := $(OBJ:.o=.d)
-include $(DEP)
You'd also want to clean them:
clean:
$(RM) $(APP) $(OBJ) $(DEP)
Now your Makefile looks like this:
APP := app
SRC := $(wildcard src/*.c)
OBJ := $(SRC:.c=.o)
DEP := $(OBJ:.o=.d)
CPPFLAGS := -MMD
CFLAGS := -W -Wall -g -std=c99 -pedantic
LDLIBS := -lm
all: $(OBJS)
$(APP): $(OBJ)
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $#
clean:
$(RM) $(APP) $(OBJ) $(DEP)
-include $(DEP)
Last point: the syntax $(SRC:.c=.o) is a shortcut for $(SRC:%.c=%.o) which is also a shortcut for $(patsubst %.c,%.o,$(SRC)).

makefile for creating (.so) file from existing files

I have 4 files: 1.c, 1.h, 2.c, 2.h.
I need a makefile, which will create a dynamic library (.so) from those 4 files.
I have tried to write a makefile like this:
library.so : 1.c 1.h 2.c 2.h
but it did not work. It would be great, if someone helps me, thanks.
Something like
CC=gcc
CFLAGS= -Wall -g -O -fPIC
RM= rm -f
.PHONY: all clean
all: library.so
clean:
$(RM) *.o *.so
library.so: 1.o 2.o
$(LINK.c) -shared $^ -o $#
1.o: 1.c 1.h 2.h
2.o: 2.c 1.h 2.h
But this is untested! I am assuming Linux with GNU make, and a directory containing only the source code of your library (with the above Makefile), which might be bad practice -you might want a test case- (you could have a special Makefile rule for %.pic.o depending on %.c, etc...)
Hints: use make -p to understand the builtin rules. Then make --trace or (with remake) remake -x to understand a bit more what make is doing.
Read also Drepper's paper: How to Write Shared Libraries, documentation of GNU make, Program Library HowTo, this answer, ...
The simplest way is:
CXXFLAGS += -fPIC
CXXFLAGS += -O3
x.so: 1.o 2.o
$(LINK.cc) -shared $^ $(LOADLIBS) $(LDLIBS) -o $#
Slightly more advanced:
CC = gcc
FLAGS = # -std=gnu99 -Iinclude
CFLAGS = -fPIC -g #-pedantic -Wall -Wextra -ggdb3
LDFLAGS = -shared
DEBUGFLAGS = -O0 -D _DEBUG
RELEASEFLAGS = -O2 -D NDEBUG -combine -fwhole-program
TARGET = example.so
SOURCES = $(wildcard *.c)
HEADERS = $(wildcard *.h)
OBJECTS = $(SOURCES:.c=.o)
all: $(TARGET)
$(TARGET): $(OBJECTS)
$(CC) $(FLAGS) $(CFLAGS) $(DEBUGFLAGS) -o $(TARGET) $(OBJECTS)
CC = gcc # C compiler
CFLAGS = -fPIC -Wall -Wextra -g # C flags
LDFLAGS = -shared # linking flags
RM = rm -f # rm command
TARGET_LIB = sh_main.so # target lib
SRCS = add.c sub.c main.c # source file
DEPS = header.h # header file
OBJS = $(SRCS:.c=.o) # object file
.PHONY: all
all: ${TARGET_LIB}
$(TARGET_LIB): $(OBJS)
$(CC) ${LDFLAGS} -o $# $^ # -o $# says, put the output of the compilation in the file named on the left side of the :
$(SRCS:.c=.d):%.d:%.c
$(CC) $(CFLAGS) -MM $< >$# # the $< is the first item in the dependencies list, and the CFLAGS macro is defined as above
include $(SRCS:.c=.d)
.PHONY: clean
clean:
-${RM} ${TARGET_LIB} ${OBJS} $(SRCS:.c=.d)
After the shared library created successfully. We need to install it.
Become the root user.
Copy the shared library into standard directory "/usr/lib".
Run ldcofig command.
Recompile your .c file with shared library.
root#Admin:~/C/SharedLibrary# gcc -c main.c
root#Admin:~/C/SharedLibrary# gcc -o main main.o sh_main.so
root#Admin:~/C/SharedLibrary# ldd main
Note: In my case.
main.c: main C file
sh_main.so: shared library.
I'm no gnu make expert, this seems reasonable to me
CFLAGS+=-fPIC
%.so: ; $(LINK.c) $(LDFLAGS) -shared $^ -o $#
library.so: 1.o 2.o # default target first
# changes to `1.h` imply `1.o` needs to be rebuilt
1.o: 1.h
2.o: 2.h

error in compiling but libraries required are mentioned

I made the following makefile to run a code
MODE := 3
FRICTION := 7
EREST:= 1
CC := gcc -g
CFLAGS := -lpthread -lGLU -lglut -lGL -lm
vpath %.h header
vpath %.c src
vpath %.o src
CFILES := aibot1.c start.c physics.c bothandler.c man.c manageer.c network.c rules.c msghandler.c
%.o: %.c headers.h
#$(CC) $(CFLAGS) -c $< -o src/$#;
type:
#cd header;\
echo "#define FRICTION $(FRICTION) \n#define MODE $(MODE) \n#define EREST $(EREST) \n" > mainhead1.h;\
cd .. ;
carrom: type
#cd src;\
echo $(CFLAGS);\
$(CC) $(CFLAGS) $(CFILES) -o carrom;\
mv carrom ..;\
but it showing me errors undefined reference to 'sqrt' and 'pthread_create', but I have included -lm and -lpthread respectively.
Libraries needs to be specified after the files on your command line. It's also traditional to put them in LDFLAGS, not CFLAGS.
With what you have, if you change:
$(CC) $(CFLAGS) $(CFILES) -o carrom;
to:
$(CC) $(CFILES) -o carrom $(CFLAGS)
then it ought to work.
Also, you only need to specify libraries when linking, not when compiling (hence why they go in LDFLAGS, not CFLAGS), so in this line:
#$(CC) $(CFLAGS) -c $< -o src/$#
specifying the libraries (which is all CFLAGS contains) does nothing.

simple Makefile for c program

I have this (working) Makefile for single-file C-Application.
all: simpleua
simpleua: simpleua.c
$(CC) -o $# $< `pkg-config --cflags --libs libpjproject`
now I want to extend this Makefile for a multiple-file C-Application.
The files are main.c simpleua.c simpleua.h
I have found some samples on the Internet but nothing simple and working with pkg-config
Thanks alot
florian
This is simple example Makefile for you
CC = gcc
XX = g++
CFLAGS = -g
INC := -I test.h
$(LIBS)
TGT = ./sample
OUTPUT = ../output/
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $#
SOURCES = $(wildcard *.c *.cpp)
OBJS = $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCES)))
$(TGT) : $(OBJS)
$(CC) $(OBJS) -o $(TGT)
chmod 777 $(TGT)
cp $(TGT) $(OUTPUT)
clean:
rm -rf *.o *~ $(OUTPUT)/*
It works for both C and C++ for this you just need change from CC to XX.
For example purpose i have two directory as in Makefile
1)sample
2)output
In sample directory all my source resides and in output folder my final binary copied (you can give any name to directory as you want but make sure you also give same name in Makefile ).so you can put as many source file in sample directory and able to compile it.
This may take a few iterations (and you've left out a lot of details). Try this:
all: simpleua
simpleua: simpleua.o main.o
$(CC) -o $# $^ `pkg-config --cflags --libs libpjproject`
simpleua.o main.o: %.o: %.c simpleua.h
$(CC) -c -o $# $< `pkg-config --cflags --libs libproject`
EDIT: second try (with thanks to Jonathan Leffler). The use of --libs in the pattern rule may be unnecessary, but try it and see.

Resources