How do I get a makefile to compile multiple sources? - c

I would like my makefile to compile two sources, osmprun.c and echoall.c.
Currently it's just compiling osmprun.c, which creates errors.
Im at my wits end, Im not experienced with makefiles at all and I just don't understand what im doing wrong.
My makefile is:
CC=gcc
CFLAGS= -Wall -Wconversion -g
LIBS=-lm -lpthread
DEPS=
BUILD_DIR := build
SRCS := osmprun.c echoall.c
OBJS := $(addprefix $(BUILD_DIR)/,$(patsubst %.c,%.o,$(SRCS)))
$(BUILD_DIR)/%.o: %.c $(DEPS)
mkdir -p $(BUILD_DIR)
$(CC) -c $(CFLAGS) $< -o $#
echoall: $(OBJS)
mkdir -p $(BUILD_DIR)
$(CC) $(CFLAGS) $< $(LIBS) -o $#
osmprun: $(OBJS)
mkdir -p $(BUILD_DIR)
$(CC) $(CFLAGS) $< $(LIBS) -o $#
.PHONY: clean
clean:
rm -f $(BUILD_DIR)/*.o *~ core
test:
./osmprun
Can somebody help me figure out my mistake and explain what the problem is?
EDIT:
I've now changed the part where it is supposed to compile the two files to:
echoall: echoall.c
$(CC) $(CFLAGS) $^ $(LIBS) -o $#
osmprun: osmprun.c
$(CC) $(CFLAGS) $^ $(LIBS) -o $#
But it is still only compiling echoall, not osmprun

It would help greatly if you included the command you typed and the output you got, and what you wanted to get, especially because your terminology is not quite accurate. It's not true that make is not compiling all the object files. The problem is at the link stage.
However, I don't understand what your makefile is intended to do. You have two targets and they both depend on the SAME set of object files:
echoall: $(OBJS)
osmprun: $(OBJS)
Do you need to link both of those object files together? If so then what is the difference between the echoall program and the osmprun program, if they both contain the same set of object files?
Or, do you want to create the echoall program from the echoall.c source file and the osmprun program from the osmprun.c source file? If so, why do you list both objects as a prerequisite for both programs?
In any event your problem is here:
echoall: $(OBJS)
mkdir -p $(BUILD_DIR)
$(CC) $(CFLAGS) $< $(LIBS) -o $#
osmprun: $(OBJS)
mkdir -p $(BUILD_DIR)
$(CC) $(CFLAGS) $< $(LIBS) -o $#
(the mkdir here are useless: you know that the directory already exists because you already built the object files, but they don't hurt anything).
The problem is you're using $< which is the first prerequisite. Because both prerequisite lists are the same, you're building both programs from the same, single source file.
If you want both programs to contain both object files, you should use $^ here not $<. If you want each program to contain only its related object file, you should change the prerequisites to contain only the object file it should be built from (and also use $^).

Related

How to make static libraries with Makefile?

This is the Makefile
CC=gcc
CFLAGS=-Wall -pedantic -Werror -g
LDFLAGS=-lm
RM=rm -f
SOURCES=$(wildcard *.c)
TARGETS=$(SOURCES:.c=)
OBJECTS=$(SOURCES:.c=.o)
.PHONY: all clean
all: test_stack
%: %.c
$(CC) $(CFLAGS) $(LDFLAGS) $< -o $#
%.o: %.c
$(CC) $(CFLAGS) -c -o $# $<
%.a: %.o
ar rcs $# $<
ranlib $#
test_stack: genstacklib.a test_stack.o
$(CC) $(CFLAGS) -o $# $^ $(LDFLAGS)
clean:
$(RM) $(OBJECTS) $(TARGETS)
I have the files genstacklib.c, genstacklib.h and test_stack.c
Now I want to compile genstacklib as static library
When test_stack calls the methods of genstacklib, it throws an exeception:
for example: "undefined reference to `genStackNew'"
I don't get why test_stack can't access the methods, for my current understanding it should have access to the library.
Please copy and paste the exact errors you get into your question, with proper formatting, and also including the compile or link command that make printed. A statement like "throws an exception" is not precise and in fact is not really accurate because exceptions are thrown from running programs, but (if I understand your problem correctly) you are not able to link your program.
The problem is that the order of arguments to the linker is critical: all libraries must appear on the link line after all object files. Also the order of libraries matters but since you have only one that's not an issue.
In your rule:
test_stack: genstacklib.a test_stack.o
$(CC) $(CFLAGS) -o $# $^ $(LDFLAGS)
The $^ variable expands to the prerequisites, in this case genstacklib.a test_stack.o. So on your link line the library will appear before the object file, which won't work. Rewrite your rule like this:
test_stack: test_stack.o genstacklib.a
$(CC) $(CFLAGS) -o $# $^ $(LDFLAGS)
so the library comes after the object files and it will probably work.
As an aside, the variable LDFLAGS generally contains flags that manage the linker. Library references like -lm are traditionally put into a variable LDLIBS instead. Of course this is just convention but it's useful to follow conventions unless there's a good reason not to.

Makefile how to use logical OR between prerequisites?

My source files are organized nicely in a folder, that contains subfolders, that also contains source files.
The subfolders don't branch any further.
All object files are just meant to be created and stored in the same folder.
I don't want to manually list the name of the subdirs in the prerequisites when writing the target that generates my object files:
Right now this works:
$(OBJ)/%.o: $(SRC)/%.c
$(CC) -c $< -o $# $(CFLAGS)
$(OBJ)/%.o: $(SRC)/$(subdir1)/%.c
$(CC) -c $< -o $# $(CFLAGS)
$(OBJ)/%.o: $(SRC)/$(subdir2)/%.c
$(CC) -c $< -o $# $(CFLAGS)
...
But I want it to look something like this:
$(OBJ)/%.o: $(SRC)/%.c OR $(SRC)/*/%.c
$(CC) -c $< -o $# $(CFLAGS)
I understand that the title most likely isn't the real question to be asked, but I'm looking for any solution. Also, I know that the * doesn't work as a placeholder here.
First, you can simplify the makefile you have by using vpath:
$(OBJ)/%.o: %.c
$(CC) -c $< -o $# $(CFLAGS)
vpath %.c $(SRC) $(SRC)/$(subdir1) $(SRC)/$(subdir2)
Then, if you really don't want to specify the subdirectories:
vpath %.c $(shell find $(SRC) -type d)

How can I improve this Makefile to optimize the usage of the SRC and BIN folders?

This is my first attempt at making a Makefile after having gone through several tutorials and the gnu make manual. The Makefile works and creates the .o, .a and .exe files in the BIN folder. However, I have have added src\ and bin\ prefixes to all files. I know there must be a better way of addressing folder issues while using Makefiles. Only problem is, I am unable to figure it out after hours of editing and trying out different things, based on the tutorials. I find GNU make manual too overwhelming at this stage of my learning curve.
I am using MinGW GCC toolchain on Windows 7. I have copied mingw32-make.exe to make.exe for the purpose of trying out the tutorials and exampples I have been going through.
I would really appreciate any help on the subject. Thank you.
My Makefile is as follows:
CC = gcc
CFLAGS = -O3 -Wall -c
BIN = bin/
LDFLAGS = -L$(BIN) -lmyLib
all: test.exe
test.exe: test.o libmyLib.a
gcc bin\test.o -o bin\test.exe $(LDFLAGS)
test.o: src\test.c src\myLib.h
$(CC) $(CFLAGS) -o bin\test.o src\test.c
libmyLib.a: myLib.o
ar rcs bin\libmyLib.a bin\myLib.o
myLib.o: src\test.c src\myLib.h
$(CC) $(CFLAGS) -o bin\myLib.o src\myLib.c
clean:
del bin\*.* /Q
First, there are some issues with your Makefile, even if it apparently works. When you write:
myLib.o: src\test.c src\myLib.h
$(CC) $(CFLAGS) -o bin\myLib.o src\myLib.c
you are lying to make:
You tell it that the result of the rule is myLib.o while it is bin\myLib.o, that is, a different file.
You tell make that myLib.o depends on src\test.c while it in fact depends on src\myLib.c.
Same with your other rules as in:
libmyLib.a: myLib.o
ar rcs bin\libmyLib.a bin\myLib.o
You tell make that the rule shall be executed if myLib.o is newer than libmyLib.a while the real prerequisite is bin\myLib.o and the real target is bin\libmyLib.a.
By doing so you totally prevent make from doing what it is supposed to do: decide if a recipe must be executed or not, depending on the last modification times of target files and prerequisite files. Give it a try: run make twice and you'll see that it uselessly redoes what it did already. Never, never lie to make.
Second, you can improve your Makefile by using several advanced features like automatic ($#, $<, $^), standard (LDLIBS, AR, ARFLAGS) and regular (BIN, SRC) make variables. Here is an example of what you could try, after fixing the above mentioned issues and better using variables (plus adding the missing -I gcc option, and declaring all and clean as phony because these targets are not real files and we do not want to lie to make):
BIN = bin
SRC = src
CC = gcc
CFLAGS = -O3 -Wall -c -I$(SRC)
LDFLAGS = -L$(BIN)
LDLIBS = -lmyLib
AR = ar
ARFLAGS = rcs
.PHONY: all clean
all: $(BIN)/test.exe
$(BIN)/test.exe: $(BIN)/test.o $(BIN)/libmyLib.a
$(CC) $< -o $# $(LDFLAGS) $(LDLIBS)
$(BIN)/test.o: $(SRC)/test.c $(SRC)/myLib.h
$(CC) $(CFLAGS) -o $# $<
$(BIN)/libmyLib.a: $(BIN)/myLib.o
$(AR) $(ARFLAGS) $# $^
$(BIN)/myLib.o: $(SRC)/myLib.c $(SRC)/myLib.h
$(CC) $(CFLAGS) -o $# $<
clean:
del $(BIN)\*.* /Q
Now, all non-phony targets and prerequisites are regular files, the ones that are really involved in the rules. Again, give it a try and you'll see that make rebuilds only what is out of date and thus needs to be rebuilt.
If you want to get rid of the $(SRC)/ prefix you can use the vpath directive that tells make where to look for source files (I insist on source, many people try to use it for target files, this is not what it is intended for):
vpath %.h $(SRC)
vpath %.c $(SRC)
And then:
$(BIN)/test.o: test.c myLib.h
$(CC) $(CFLAGS) -o $# $<
$(BIN)/myLib.o: myLib.c myLib.h
$(CC) $(CFLAGS) -o $# $<
Note: you could also use the VPATH variable instead of the vpath directive.
Pattern rules are used to factor similar rules, like, for instance, your compilation rules that differ only by the names of the source file and object file:
$(BIN)/%.o: %.c myLib.h
$(CC) $(CFLAGS) -o $# $<
All in all:
BIN = bin
SRC = src
CC = gcc
CFLAGS = -O3 -Wall -c -I$(SRC)
LDFLAGS = -L$(BIN)
LDLIBS = -lmyLib
AR = ar
ARFLAGS = rcs
vpath %.h $(SRC)
vpath %.c $(SRC)
.PHONY: all clean
all: $(BIN)/test.exe
$(BIN)/test.exe: $(BIN)/test.o $(BIN)/libmyLib.a
$(CC) $< -o $# $(LDFLAGS) $(LDLIBS)
$(BIN)/%.o: %.c myLib.h
$(CC) $(CFLAGS) -o $# $<
$(BIN)/libmyLib.a: $(BIN)/myLib.o
$(AR) $(ARFLAGS) $# $^
clean:
del $(BIN)\*.* /Q
Finally, if you really want to avoid the $(BIN)/ prefix in your rules you will have to move to the $(BIN) directory and call make from there. You can leave the Makefile in the main directory and use the -f ../Makefile option, if you wish.
But of course this is less convenient that just typing make [goals] from the main directory. There are ways to let make test from where it has been called, and if it is not from the build directory, re-call itself with the -C and -f options such that it does its job from the build directory. But it is probably a bit too complicated if you are new to make.
If you are however interested have a look at this post that covers this topic (and more). If we simplify as much as possible what the post suggests and specialize it for your case, the final Makefile could be something like:
# here starts the black magic that makes it possible
.SUFFIXES:
BIN := bin
SRC := src
ifneq ($(notdir $(CURDIR)),$(BIN))
.PHONY: $(BIN) clean
$(BIN):
#$(MAKE) --no-print-directory -C $# -f ../Makefile SRC=$(CURDIR)/$(SRC) $(MAKECMDGOALS)
Makefile: ;
% :: $(BIN) ; :
clean:
del $(BIN)\*.* /Q
else
# here ends the black magic that makes it possible
# here starts the Makefile you would really like to write
CC := gcc
CFLAGS := -O3 -Wall -c -I$(SRC)
LDFLAGS := -L.
LDLIBS := -lmyLib
AR := ar
ARFLAGS := rcs
vpath %.h $(SRC)
vpath %.c $(SRC)
.PHONY: all
all: test.exe
test.exe: test.o libmyLib.a
$(CC) $< -o $# $(LDFLAGS) $(LDLIBS)
%.o: %.c myLib.h
$(CC) $(CFLAGS) -o $# $<
libmyLib.a: myLib.o
$(AR) $(ARFLAGS) $# $^
# here ends the Makefile you would really like to write
# a last bit of black magic
endif
The Makefile you would really like to write is what you would write if your source files and target files were all in the source directory. No prefixes any more; vpath takes care of the $(SRC)/ prefix and $(BIN)/ is useless because when this part of the Makefile is used we are already inside $(BIN).
Note: I know nothing about Windows and its various command line interfaces so there are probably some things to adapt (backslashes instead of slashes for instance).

Makefile not compiling all C files in directory

Iam working with gcc and MinGW on a Windows platform. I have a directory containing two *.c files:
main.c and funcs.c
I am using the following makefile:
CC=gcc
CFLAGS=-c
LDFLAGS=
SOURCEDIR = src
BUILDDIR = build
SOURCES=$(wildcard $(SOURCEDIR)/*.c)
OBJECTS=$(patsubst $(SOURCEDIR)/%.c,$(BUILDDIR)/%.o,$(SOURCES))
LIBRARIES=-L/mingw64/lib
INC= -I./include
EXECUTABLE=testLink
VPATH = src include build
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) $(LIBRARIES) -o ./dist/$#
$(OBJECTS): $(SOURCES)
$(CC) $(INC) $(CFLAGS) $< -o $#
Which should take the *.c files and generate *.o files with the same name. However I get the following output on make -
$ make
gcc -I./include -c src/funcs.c -o build/funcs.o
gcc -I./include -c src/funcs.c -o build/main.o
gcc build/funcs.o build/main.o -L/mingw64/lib -o ./dist/testLink
followed of course by a bunch of multiple definition errors. As you can see from the first two lines it is taking the same *.c file and compiling it twice into two different *.o files.
I am new to makefiles but I assume it is something wrong with my $(OBJECTS) rule and I'm pretty sure it's the $< which is causing the problem. I'm trying to create a generic makefile which will always work on my projects which have the same directory structure and take .c files turn them into .o files and link. Am I going about this entirely the wrong way or is there a simple fix to my makefile?
Thanks!
James
This rule:
$(OBJECTS): $(SOURCES)
$(CC) $(INC) $(CFLAGS) $< -o $#
expands to:
funcs.o main.c: funcs.c main.c
$(CC) $(INC) $(CFLAGS) $< -o $#
which is equivalent to:
funcs.o: funcs.c main.c
$(CC) $(INC) $(CFLAGS) $< -o $#
main.o: funcs.c main.c
$(CC) $(INC) $(CFLAGS) $< -o $#
$< refers to the first dependency (funcs.c) so your Makefile is trying to generate both funcs.o and main.o from the same source.
You just want a generic rule using % wildcard matching:
%.o: %.c
$(CC) $(INC) $(CFLAGS) $< -o $#
See https://www.gnu.org/software/make/manual/html_node/Pattern-Rules.html
Jeff pointed the mistake in his answer (all objects depend on all sources: that isn't a generic compilation rule for c sources).
However, the generic rule must have source & object paths. To sum it up, just replace
$(OBJECTS): $(SOURCES)
$(CC) $(INC) $(CFLAGS) $< -o $#
by
$(BUILDDIR)/%.o : $(SOURCEDIR)/%.c
$(CC) $(INC) $(CFLAGS) $< -o $#
(as explained in How to generate a Makefile with source in sub-directories using just one makefile)
note that this kind of dependency test doesn't take included .h files into account, so it's only intended for first builds. Modifying .h files afterwards doesn't trigger a compilation since the header files are not listed as dependencies.

Set Option in MakeFile to send object files to specific Folder

I made a test makefile using an online tutorial. It works, but I also want to have all of my .o files go to a specific sub-folder. Is there a way to do this using a makefile? Here is what I have so far.
CC=gcc # specifies the compiler to use.
CFLAGS=-I. # specifies to look in the current directory.
DEPS = path_tools.h # DEPS stores each .h file to be added.
OBJ = checkpath.o path_tools.o # OBJ stores each object file to compile.
%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
checkpath.exe: $(OBJ)
gcc -o $# $^ $(CFLAGS)
For GNU make you can use this Makefile.
ODIR:=obj
CC:=gcc
CFLAGS:=-I.
DEPS:=path_tools.h
OBJ_:= checkpath.o path_tools.o
OBJ:=$(addprefix $(ODIR)/, $(OBJ_))
PROG=checkpath.exe
all:$(PROG)
$(OBJ): $(DEPS)
$(ODIR)/%.o: %.c
$(CC) -c -o $# $&lt $(CFLAGS)
$(PROG): $(OBJ)
$(CC) -o $# $^ $(CFLAGS)
clean:
rm -f $(OBJ) $(PROG)
You can pass the path of your folder to makefile to create and put the results in.
To pass parameter to makefile:
make DPATH=your-path
To use in makefile:
$(DPATH)
Create this path and add it to head of your *.o files as a path.

Resources