How to make specific binary from specific object file? - makefile

Here is my makefile, i have object files in obj/ directory, and i need to compile them into binaries in bin/ folder, but somehow it doesn't work as i wanted it to work, any ideas?
SOURCES= $(wildcard *.c)
OBJECTS:= $(patsubst %.c, %.o, $(SOURCES))
OBJECTS:= $(addprefix obj/,$(OBJECTS))
NAMES:= $(patsubst %.c, %, $(SOURCES))
NAMES:= $(addprefix bin/,$(NAMES))
CC=gcc
CFLAGS= -Wall -c -o
DIRS = bin obj
all: $(DIRS) $(NAMES)
$(NAMES): $(OBJECTS)
$(CC) -o $# $<
obj/%.o: %.c
$(CC) $(CFLAGS) $# $<
$(DIRS):
mkdir -p $#
clean:
rm -rf $(DIRS)
Actual output:
mkdir -p bin
mkdir -p obj
gcc -Wall -c -o obj/task1.o task1.c
gcc -Wall -c -o obj/task2.o task2.c
gcc -Wall -c -o obj/task3.o task3.c
gcc -o bin/task1 obj/task1.o
gcc -o bin/task2 obj/task1.o
gcc -o bin/task3 obj/task1.o
Expected output:
mkdir -p bin
mkdir -p obj
gcc -Wall -c -o obj/task1.o task1.c
gcc -Wall -c -o obj/task2.o task2.c
gcc -Wall -c -o obj/task3.o task3.c
gcc -o bin/task1 obj/task1.o
gcc -o bin/task2 obj/task2.o
gcc -o bin/task3 obj/task3.o

In this rule:
$(NAMES): $(OBJECTS)
$(CC) -o $# $<
each executable depends on all objects. And since $< grabs only the first prerequisite, all you see is obj/task1.o.
Do it this way:
bin/%: obj/%.o
$(CC) -o $# $<
or this way:
$(NAMES): bin/% : obj/%.o
$(CC) -o $# $<

Related

How can I store my .o files in a sepparate folder?

INCDIR=include
SRCDIR=src
SRC = $(wildcard $(SRCDIR)/*.cpp)
DEPS = $(wildcard $(INCDIR)/*.h)
OBJ = $(SRC:.cpp=.o)
CFLAGS = -I$(INCDIR) -Wall -Weffc++ -Wextra -Wsign-conversion
CC=g++
preprocessor: $(OBJ)
$(CC) $(OBJ) -o $# $(CFLAGS)
$(SRCDIR)/%.o: $(SRCDIR)/%.cpp
$(CC) -c $(CFLAGS) $^ -o $#
clean:
rm $(SRCDIR)/*.o preprocessor
This is my current makefile, if I wanted to store my .o files in a sepparate directory, src/obj for example, how would I have to modify it?
Many ways to do it, but according to your own code, you could do:
INCDIR=include
SRCDIR=src
OBJDIR=obj
SRC= $(wildcard $(SRCDIR)/*.cpp)
DEPS= $(wildcard $(INCDIR)/*.h)
OBJ=$(patsubst %.cpp, $(OBJDIR)/%.o, $(notdir $(SRC)))
CFLAGS= -I$(INCDIR) -Wall -Weffc++ -Wextra -Wsign-conversion
CC=g++
$(OBJDIR):
#if ! [ -d $(#) ]; then\
echo "==> creating dir: $(#)";\
mkdir $(#);\
fi
preprocessor: $(OBJDIR) $(OBJ)
$(CC) $(OBJ) -o $# $(CFLAGS)
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
$(CC) -c $(CFLAGS) $^ -o $#
clean:
rm $(OBJDIR)/*.o preprocessor
printobj: $(OBJDIR)
#echo "$(OBJ)"
will output:
$ gmake preprocessor
g++ -c -Iinclude -Wall -Weffc++ -Wextra -Wsign-conversion src/a.cpp -o obj/a.o
g++ -c -Iinclude -Wall -Weffc++ -Wextra -Wsign-conversion src/b.cpp -o obj/b.o
g++ obj/a.o obj/b.o -o preprocessor -Iinclude -Wall -Weffc++ -Wextra -Wsign-conversion
NOTE: the target printobj is just here to output what you could expect, the target $(OBJDIR) ensure your directory exist before creating object files.
The are just a few things to change:
INCDIR := include
SRCDIR := src
OBJDIR := $(SRCDIR)/obj
SRC := $(wildcard $(SRCDIR)/*.cpp)
DEPS := $(wildcard $(INCDIR)/*.h)
OBJ := $(patsubst $(SRCDIR)/%.cpp,$(OBJDIR)/%.o,$(SRC))
CFLAGS := -I$(INCDIR) -Wall -Weffc++ -Wextra -Wsign-conversion
CC := g++
preprocessor: $(OBJ)
$(CC) $^ -o $# $(CFLAGS)
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp | $(OBJDIR)
$(CC) -c $(CFLAGS) $< -o $#
$(OBJDIR):
mkdir -p "$#"
clean:
rm -f $(OBJ) preprocessor
Note some other minor modifications:
the | $(OBJDIR) order-only prerequisite and the $(OBJDIR): rule to ensure the objects directory exists before compiling,
:= instead of = for all make variable assignments because you don't need recursively expanded variables here,
$^ instead of $(OBJ) in the link recipe because using automatic variables in recipes makes them more generic,
$< instead of $^ in the compile recipe because you compile only the first prerequisite, not all of them,
rm -f $(OBJ) preprocessor instead of rm $(SRCDIR)/*.o preprocessor to remove only the object files of the project and avoid errors if none exists.

Loop through list of files in Makefile

I compiling my C source files with this code:
CC=clang -std=c11
CFLAGS=-Wall -g
ASSEMBLY=-S -masm=intel
OPTIMIZE=-Ofast
FOLDER_SRC=./src/
FOLDER_BIN=./bin/
FOLDER_ASSEMBLY=./ass/
clean:
rm -f \
$(FOLDER_BIN)1.1-hello $(FOLDER_ASSEMBLY)1.1-hello \
$(FOLDER_BIN)1.2-fahrenheit $(FOLDER_ASSEMBLY)1.2-fahrenheit \
$(FOLDER_BIN)1.2-fahrenheit-floating $(FOLDER_ASSEMBLY)1.2-fahrenheit-floating
all:
$(CC) $(CFLAGS) $(OPTIMIZE) $(FOLDER_SRC)1.1-hello.c -o $(FOLDER_BIN)1.1-hello
$(CC) $(CFLAGS) $(OPTIMIZE) $(FOLDER_SRC)1.2-fahrenheit.c -o $(FOLDER_BIN)1.2-fahrenheit
$(CC) $(CFLAGS) $(OPTIMIZE) $(FOLDER_SRC)1.2-fahrenheit-floating.c -o $(FOLDER_BIN)1.2-fahrenheit-floating
assembly:
$(CC) $(ASSEMBLY) $(OPTIMIZE) $(FOLDER_SRC)1.1-hello.c -o $(FOLDER_ASSEMBLY)1.1-hello
$(CC) $(ASSEMBLY) $(OPTIMIZE) $(FOLDER_SRC)1.2-fahrenheit.c -o $(FOLDER_ASSEMBLY)1.2-fahrenheit
$(CC) $(ASSEMBLY) $(OPTIMIZE) $(FOLDER_SRC)1.2-fahrenheit-floating.c -o $(FOLDER_ASSEMBLY)1.2-fahrenheit-floating
I try to implement some kind of loop to write less. I added this code, but it just generating errors:
FILENAME_SRC := $(wildcard $(FOLDER_SRC)*.c)
FILENAME_BUILD := $(patsubst $(FOLDER_SRC)%.c,%,$(FILENAME_SRC))
echo : $(FILENAME_SRC)
#echo $^
#echo $(FILENAME_BUILD)
build : $(FILENAME_SRC)
$(CC) $(CFLAGS) $(OPTIMIZE) $^ -o $(FILENAME_BUILD)
make echo printing this to the console:
$ make echo
src/1.2-fahrenheit.c src/1.1-hello.c src/1.2-fahrenheit-floating.c
1.2-fahrenheit 1.1-hello 1.2-fahrenheit-floating
make build command generating this error:
$ make build
clang -std=c11 -Wall -g -Ofast src/1.2-fahrenheit.c src/1.1-hello.c src/1.2-fahrenheit-floating.c -o 1.2-fahrenheit 1.1-hello 1.2-fahrenheit-floating
clang.exe: error: no such file or directory: '1.1-hello'
clang.exe: error: no such file or directory: '1.2-fahrenheit-floating'
make: *** [Makefile:21: build] Error 1
I want the expected output to look like when I do make all:
$ make all
clang -std=c11 -Wall -g -Ofast ./src/1.1-hello.c -o ./bin/1.1-hello
clang -std=c11 -Wall -g -Ofast ./src/1.2-fahrenheit.c -o ./bin/1.2-fahrenheit
clang -std=c11 -Wall -g -Ofast ./src/1.2-fahrenheit-floating.c -o ./bin/1.2-fahrenheit-floating
Final solution
CC := clang -std=c11
GCC := gcc -std=c11
CFLAGS := -Wall -g
ASSEMBLY := -Wall -S -masm=intel
OPTIMIZE := -O3 -march=native
SRC := $(wildcard src/*.c)
BIN := $(patsubst src/%.c,bin/%,$(SRC))
ASS := $(patsubst src/%.c,ass/%,$(SRC))
clean:
rm -f bin/* ass/*
build: $(BIN)
$(BIN): bin/%: src/%.c
$(CC) $(CFLAGS) $(OPTIMIZE) $^ -o $#
assembly: $(ASS)
$(ASS): ass/%: src/%.c
$(CC) $(ASSEMBLY) $(OPTIMIZE) $^ -o $#
Really sorry for the clean ass/* though, it cannot be called assembly because the similar folder name in the project.
Your all rule needs to look something like
CC := clang
CFLAGS := -std=c11 -Wall -g -Ofast
targets := bin/1.1-hello bin/1.2-fahrenheit bin/1.2-fahrenheit-floating
.PHONY: all
all: $(targets)
$(targets): bin/%: src/%.c
$(LINK.c) $^ $(LDLIBS) -o $#

Makefile causes `gfortran: error: No such file or directory`

I am trying to compile this code with gfortran.
Makefile:
# makefile for BIRRP
FC = gfortran
FCFLAGS = -g -fbounds-check
FLFLAGS = -g -fbacktrace
SRC = birrp.f coherence.f dataft.f diagnostic.f fft.f filter.f math.f rarfilt.f response.f rtpss.f utils.f weight.f zlinpack.f
# "make" builds all
PROGRAM = birrp
all: $(PROGRAM)
$(PROGRAM): $(SRC)
$(FC) $(FCFLAGS) $# $<
%.o: %.f
$(FC) $(FLFLAGS) -o $# $^
clean:
rm -f *.o
It doesn't work
gfortran -g -fbounds-check birrp birrp.f
gfortran: error: birrp: No such file or directory
Makefile:13: recipe for target 'birrp' failed
make: *** [birrp] Error 1
I am using the gfortran compiler. I have copied the Makefile from my other program.
After adding -o:
FC = gfortran
FCFLAGS = -g -c -fbounds-check
FLFLAGS = -g -fbacktrace
SRC = birrp.f coherence.f dataft.f diagnostic.f fft.f filter.f math.f rarfilt.f response.f rtpss.f utils.f weight.f zlinpack.f
# "make" builds all
PROGRAM = birrp
all: $(PROGRAM)
$(PROGRAM): $(SRC)
$(FC) $(FCFLAGS) -o $# $<
%.o: %.f
$(FC) $(FLFLAGS) -o $# $^
clean:
rm -f *.o
Now it just compiles
gfortran -g -c -fbounds-check -o birrp birrp.f
Why?
gfortran interprets birrp as a source-file, but you want it as the outfile.
man gfortran
says the outfile is specified by the -o parameter, so your target becomes this:
$(PROGRAM): $(SRC)
$(FC) $(FCFLAGS) -o $# $<
But this doesn't solve all your problems. According to the GNU Make manual $< specifies the first dependency and not all of them. You always want to have the whole list of dependencies, which would be $^.
So your target becomes this:
$(PROGRAM): $(SRC)
$(FC) $(FCFLAGS) -o $# $^

gcc cannot specify -o with -c or -S with Multiple files

Whenever I am trying to build something like this in my Makefile -
gcc -o main.o -IStarterWare_Files -c main.c StarterWare_Files/test.h StarterWare_Files/add.h
It throws me error that gcc: cannot specify -o with -c or -S with multiple files. Basically I want my makefile to build the target again if I change for example some macro in one of my header files. My current Makefile is -
EXE = nextgenrsm
CC = gcc
LIBS = StarterWare_Files/
CPPFLAGS = _IStarterWare_Files/
MAIN_OBS = $(patsubst %.c,%.o,$(wildcard *.c))
LIB_OBS = $(patsubst %.c,%.o,$(wildcard StarterWare_Files/*.c))
all: $(EXE)
$(EXE): $(MAIN_OBS) $(LIB_OBS)
$(CC) -o $# $(LDFLAGS) $(MAIN_OBS) $(LIB_OBS) $(LDLIBS)
%.o: %.c
$(CC) -o $# -MD -MP $(CPPFLAGS) $(CFLAGS) -c $^
ALL_DEPS = $(patsubst %.o,%.d,$(MAIN_OBS), $(LIB_OBS))
-include $(ALL_DEPS)
clean:
rm -f $(LIB_OBS) $(EXE) $(MAIN_OBS) $(ALL_DEPS)
.PHONY: all clean
I can't figure out what changes to make to build my executable again if one of the header files is modified. I don't want to do make clean and make again.
The way the automake system handles this is to not use %.o: %.c but instead list the C file and all of the headers in the C file.
So for example:
main.o: main.c StarterWare_Files/test.h StarterWare_Files/add.h
$(CC) -o $# -MD -MP $(CPPFLAGS) $(CFLAGS) -c $^
See makedepends for a tool that will read C files and figure out the make dependencies.

makefile putting objs in separate directory

Why does
$(OBJDIR)\%.o:$(SRDDIR)\%.s
$(GCC) -c -g -I$(SRCDIR) $(ASFLAGS) $< -o $#
$(OBJDIR)\%.o:$(SRDDIR)\%.c
$(GCC) -c -g -I$(SRCDIR) $(CFLAGS) $< -o $#
gives warning (says ignoring the first rule)
where as
%.o:%.s
$(GCC) -c -g -I$(SRCDIR) $(ASFLAGS) $< -o $#
%.o:%.c
$(GCC) -c -g -I$(SRCDIR) $(CFLAGS) $< -o $#
works fine but I will have all my sources and objs in the same directory.
I would like to put the objs (generated from assembly files and c files) in a separate directory( and I am running make on windows).
Try using forward slashes ("/") instead of backward ones ("\").
The -o flag of GCC determines where the output file are made.
So this may work if you change:
%.o:%.s $(GCC) -c -g -I$(SRCDIR) $(ASFLAGS) $< -o $#
TO
%.o:%.s $(GCC) -c -g -I$(SRCDIR) $(ASFLAGS) $< -o myoutputdir/$#

Resources