How to create a makefile? - c

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

Related

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

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.

What does "linker input file unused because linking not done" mean? (C makefile)

I have created a makefile to compile and link my program, however, I can't figure out why I am getting this error. Is it to do with SDL?
GCC = gcc
CFLAGS = -c -std=c99 -lm -Wall -Wextra -pedantic -O3 -Wfloat-equal -g
SDL = -lSDL2 -lSDL2_ttf -lSDL2_image -lSDL2_mixer
all: ./game
game: global.o display.o player.o entities.o controls.o sound.o menu.o
$(GCC) $(CFLAGS) global.o display.o player.o entities.o controls.o sound.o menu.o -o game
global.o: global.c
$(GCC) $(CFLAGS) $(SDL) global.c
display.o: display.c
$(GCC) $(CFLAGS) $(SDL) display.c
player.o: player.c
$(GCC) $(CFLAGS) $(SDL) player.c
entities.o: entities.c
$(GCC) $(CFLAGS) $(SDL) entities.c
controls.o: controls.c
$(GCC) $(CFLAGS) $(SDL) controls.c
sound.o: sound.c
$(GCC) $(CFLAGS) $(SDL) sound.c
menu.o: menu.c
$(GCC) $(CFLAGS) $(SDL) menu.c
clean:
rm *o game
Your linking command expands to:
gcc -c -std=c99 -lm -Wall -Wextra -pedantic -O3 -Wfloat-equal -g global.o display.o player.o entities.o controls.o sound.o menu.o -o game
which, as you can see, has the -c flag in it. The -c flag tells gcc not to do linking. So it has nothing to actually do. (.o files can only be used for linking, and you've disabled linking, which is why you get that message)
You don't want to use the same flags for compiling and linking. For compiling you probably want -c -std=c99 -Wall -Wextra -pedantic -O3 -Wfloat-equal -g, and for linking you want -lm -lSDL2 -lSDL2_ttf -lSDL2_image -lSDL2_mixer -g.
there are several small oversights in the posted makefile.
Amongst them:
library names are only used during the link step, not the compile step
suggest using the 'wildcard' make operator to get a list of the source files. Then use a patterm replacement operator to get a list of the object files:
for instance:
SRC := $(wildcard *.c)
OBJ := $(SRC:.c=.o)
when a target (all, clean) will not produce a file of the same name, then insert a .PHONY: statement early in the make file:
similarly to:
.PHONY : all clean
the posted make file has no facilities to handle the associated header files, There are several ways to handle that. This follows the OPs lead and does not handle the header files, so changing a header file will not recompile/relink the effected source files.
this line: rm *o game will not remove the name.o files as it is missing the '.' between the root name and the 'o' extension. Also, the '-f' flag should be used with the 'rm' command.
suggest:
rm -f *.o game
this line: all: ./game can create problems
suggest:
all: game
once the list of object files is created (as above) then the compile rules can be reduced:
by using the make operators:
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $# -I.
the -g parameter to the compiler and linker allows for a debugger to be used. If that debugger is gdb then a better parameter is -ggdb
almost always, there is no need to evaluate a macro definition more than once, so rather than using = in a macro definition, use :=
If you want the game to be executable, then insert a chmod command as the last line in the 'link' rule
Suggest reading about the special operators that can be employed in a makefile to help you understand the following, suggested makefile
It is usually best to replace calls to the shell recognized commands with macros.
CC := /user/bin/gcc
RM := /usr/bin/rm
CFLAGS := -c -std=c99 -Wall -Wextra -pedantic -O3 -Wfloat-equal -ggdb
LFLAGS := -std=c99 -O3 -ggdb
SDL := -lSDL2 -lSDL2_ttf -lSDL2_image -lSDL2_mixer
SRC := $(wildcard *.c)
OBJS := $(SRC:.c=.o)
.PHONY : all clean
all: game
game: $(OBJS)
$(CC) $(LFLAGS) $(OBJS) -o $# $(SDL) -lm
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $# -I.
clean:
$(RM) -f *.o game
Do not put -lm or the SDL libraries into CFLAGS, library operands go to the end of the command line. Instead, use an extra variable LDLIBS and modify your game rule like this:
game: global.o display.o player.o entities.o controls.o sound.o menu.o
$(GCC) $(CFLAGS) -o $# global.o display.o player.o entities.o controls.o sound.o menu.o $(LDLIBS)
The -lm operand (it's not an option) and the operands for SDL only apply when linking, thus it should not be part of CFLAGS and should not be specified when compiling without linking (i.e. when -c is supplied).

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

Makefile for plugins compilation

I have this simple structure:
.
test.c
plugins/a.c
plugins/b.c
plugins/c.c
And I'm compiling this with a bash script:
gcc -o test test.c -std=gnu99 -ldl -Wl,--export-dynamic
gcc -c plugins/a.c -o plugins/a.o -pedantic -g -Wall -std=c99 -fpic -I.
gcc plugins/a.o -o plugins/a.so -shared
...same for b and c...
Anyways, I want to port that to a Makefile. Here's what I have:
CC = gcc
PLUGIN_DIR = plugins
PLUGINS_C = $(wildcard $(PLUGIN_DIR)/*.c)
PLUGINS_O = $(patsubst %.c,%.o, $(PLUGINS_C))
new: clean all
all: test plugins
test: test.o
$(CC) -o $# $^ -std=gnu99 -ldl -Wl,--export-dynamic
plugins:
???
$(PLUGIN_DIR)/*.c:
$(CC) -c $(PLUGIN_DIR)/$# $^ -pedantic -g -Wall -std=c99 -fpic -I.
$(PLUGIN_DIR)/*.o:
$(CC) $# $^ -shared
clean:
rm -rf test *.o *.a plugins/*.o plugins/*.so
But this won't work as the plugins rule is empty and I really can't find out what should I write in there to make it compile all the plugins inside the plugins folder.
Also, I'm not sure if I messed up things with $# and $^.
There are a number of problems with your makefile before we get to your question.
The wildcard character in a rule target is % not * (in lines like your $(PLUGIN_DIR)/*.c:).
Rules specify how the files named by the target/target pattern are built. So your %.c rule is telling make how to build .c files (which I trust you'll agree) isn't exactly what you meant. (Similarly your %.o rule is telling make how to build .o files).
You don't have any prerequisites (right-hand side of : in a target line) listed for your build rules so make cannot intelligently rebuild targets as their prerequisites are changed (and will never rebuild them instead).
To get to your question, you likely don't want anything in the body of the plugins target. Instead you want to list the desired plugins output files (the .so files) as the prerequisites of the plugins target. (You will also want to include .PHONY: plugins in your makefile to tell make that plugins is not a real file but instead a phony target.)
Your %.so rule wants to be more like:
$(PLUGINS_DIR)/%.so: $(PLUGINS_DIR)/%.o
$(CC) $^ -o $# -shared
and your %.o rule wants to be more like:
$(PLUGINS_DIR)/%.o: $(PLUGINS_DIR)/%.c
$(CC) -c $< -o $# -pedantic -g -Wall -std=c99 -fpic -I.

"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

Resources