Makefile not invoking rule dependencies - makefile

So here's my question: Why is the following makefile failing to build the only .c file in the directory? I have a fairly simple makefile for building my operating system kernel, and for some reason, it's not building the .c files required for the kernel rule to build.
The directory only contains a single .c file and the following Makefile:
GCCPARAMS = -m32 -ffreestanding -Wall -Wextra -nostdinc -nostdlib
GPPPARAMS = -m32 -ffreestanding -O2 -Wall -Wextra -fno-exceptions -fno-rtti -nostdinc -nostdlib
ASPARAMS = --32
LDPARAMS = -m32 -ffreestanding -O2 -nostdlib
C_FILES := $(wildcard *.c)
CPP_FILES := $(wildcard *.cpp)
S_FILES := $(wildcard *.s)
OBJ_FILES := $(C_FILES:.c=.o) $(CPP_FILES:.cpp=.o) $(S_FILES:.s=.o)
all: kernel
%.o: %.cpp
g++ $(GPPPARAMS) -c $< -o $#
%.o: %.c
gcc $(GCCPARAMS) -c $< -o $#
%.o: %.s
as $(ASPARAMS) $< -o $#
kernel: $(C_FILES) $(CPP_FILES) $(A_FILES)
ld -r $(OBJ_FILES) -o ../kernel.o
As you can see, I clearly have $(C_FILES) in the list. However, running make all or make kernel yields the following output:
ld -r core.o -o ../kernel.o
ld: cannot find core.o: No such file or directory
Makefile:23: recipe for target 'kernel' failed
make: *** [kernel] Error 1
Now, I've called even added to the kernel rule a print routine to test the C_FILES variable which does, in fact, print core.c (The one .c file in the directory), and the linker clearly received the OBJ_FILES list, so why is it not building core.c?

You need to define your object files as prerequisite to the kernel rule, because the kernel rule depends on them. It only depends indirectly from the source files.
kernel: $(C_FILES) $(CPP_FILES) $(A_FILES) $(OBJ_FILES)
ld -r $(OBJ_FILES) -o ../kernel.o

Related

Makefile cant find libraries

I'm trying to write my own makefile for a paho.mqtt project on a Raspberry Pi 4.
I've downloaded & tested the paho.mqtt install and its all working as expected.
So I'm now testing some C code but I just cant figure out the makefile (I'm new to this), my file so far,
NAME = mqtt_test
OBJ = $(NAME).o
LIBS = -libpaho-mqtt3c -libpaho-mqtt3cs
CFLAGS = -Wall -I/usr/local/include -L/usr/local/lib
CC = gcc
EXTENSION = .c
all: $(NAME)
%.o: %$(EXTENSION) $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
$(NAME): $(OBJ)
$(CC) -o $# $^ $(CFLAGS) $(LIBS)
.PHONY: clean
clean:
#rm -f *.o *~ core $(NAME)
This returns,
gcc -o mqtt_test mqtt_test.o -Wall -I/usr/local/include -L/usr/local/lib -libpaho-mqtt3c -libpaho-mqtt3cs
/usr/bin/ld: cannot find -libpaho-mqtt3c
/usr/bin/ld: cannot find -libpaho-mqtt3cs
collect2: error: ld returned 1 exit status
make: *** [makefile:14: mqtt_test] Error 1
I've checked & the includes and libraries are in the directories I put after the-I and -L flags.
When I look in /usr/bin there is no ld but there are paho files prefixed with paho_ but no library files.
What am I missing?
You don't use -libpaho-mqtt3c (etc.)
The option is -l so when you write -libpaho-mqtt3c the linker is looking for libraries named ibpaho-mqtt3c which of course do not exist: that would be either libibpaho-mqtt3c.a or libibpaho-mqtt3c.so.
You want to use -lpaho-mqtt3c: remove the lib at the front and the extension .a or .so, and add in the option -l.

Using Blas and Lapack libraries in Fortan90 on Linux

I am trying to use the Lapack and Blas libraries in my Fortran90 code on Linux Mint. I believe I have installed both libraries correctly in the following directory: /usr/local/lib
When I compile my code using a makefile I get the error message:
gfortran -m64 -O3 -fdefault-real-8 -fdefault-double-8 -c MainHPC2.f90
gfortran -m64 MainHPC2.o Central2Scheme.o Central5Scheme.o
WriteDataFiles.o -o P1
MainHPC2.o: In function `MAIN__':
MainHPC2.f90:(.text+0x2b0): undefined reference to `dgesv_'
collect2: error: ld returned 1 exit status
makefile:56: recipe for target 'P1' failed
make: *** [P1] Error 1
My Fortran code is simply trying to call a test function:
call dgesv(nn,nrhsl,al,ldal,ipivl,xl,ldbl,infol)
The makefile I am using is the following:
I believe it is not linking to the libraries properly.
FC = gfortran
FFLAGS = -m64 -O3 -fdefault-real-8 -fdefault-double-8
TARGET_ARCH =
LDFLAGS = -m64
BLIBS = -L/usr/local/lib -llapack -lblas
EXE = P1
.SUFFIXES:
.SUFFIXES: .o .f90 .plt
SRC = \
MainHPC2.f90 \
Central2Scheme.f90 \
Central5Scheme.f90 \
WriteDataFiles.f90 \
$(OBJECTS):
OBJ = ${SRC:.f90=.o}
$(EXE): $(OBJ)
$(FC) $(LDFLAGS) $(OBJ) $(LIBS) -o $(EXE)
%.o : %.f90
$(FC) $(FFLAGS) -c $<
# Define dependencies for modules
# $(OBJ): $(MOD)
clean:
rm -f *.mod *~ core
rm -f *.o
Thank you for your help.
Alex
solution 1
In your makefile, The sections that compile and link never add the $(BLIBS) which contains the BLAS and LAPACK libraries into the linking process.
$(EXE): $(OBJ)
$(FC) $(LDFLAGS) $(OBJ) $(LIBS) $(BLIBS) -o $(EXE)
solution 2
or you made a typo and wrote BLIBS instead of LIBS,
LIBS = -L/usr/local/lib -llapack -lblas
note: This should be more a comment than an answer

Why recipe for target 'mykernel.bin' failed?

I'm trying to create a simple mykernel.bin file using Ubuntu.
GPPPARAM = -m32 -fno-use-cxa-atexit -nostdlib -fno-builtin -fno-rtti -fno-exception -fno-leading-underscore
ASPARAMS = --32
LDPARAMS = -m elf_i386
objects = loader.o kernel.o
%o: %.cpp
g++ $(GPPPARAM) -o $# -c $<
%o: %.s
as $(ASPARAMS) -o $# $<
mykernel.bin : linker.ld $(objects)
ld $(LDPARAMS) -T $< -o $# $(objects)
the output is:
make mykernel.bin
ld -m elf_i386 -T linker.ld -o mykernel.bin loader.o kernel.o
ld: i386:x86-64 architecture of input file loader.o' is incompatible with i386 output
ld: i386:x86-64 architecture of input filekernel.o' is incompatible with i386 output
Makefile:13: recipe for target 'mykernel.bin' failed
make: *** [mykernel.bin] Error 1
If you were to show the complete output, including the compile lines for your object files, then it would be clear that your compiler flags are not being used to compile your source code. As a result, the object files being generated are for your native operating system which is most likely 64bit, when you want 32bit.
The reason for this is as I described above: your pattern rule is wrong. You have written %o : %.cpp when you wanted to write %.o : %.cpp. The pattern rule you've written tells make that if it wants to build a file loader.o (so the stem of the pattern %o matches loader.) it can do so by compiling a file loader..cpp (because the pattern character % in %.cpp is replaced with the stem loader.). Since there's no loader..cpp file, your pattern is discarded as not matching and make proceeds to look for another pattern and it finds one, as a built-in rule.
But since you are using non-standard variable names GPPPARAM instead of the standard CXXFLAGS, none of your flags are used by the default rule.
You have two choices: you can either fix your pattern rules so they're correct:
%.o: %.cpp
g++ $(GPPPARAM) -o $# -c $<
%.o: %.s
as $(ASPARAMS) -o $# $<
Or you can get rid of your own pattern rules and use make's built-in rules, and set the standard variables to ensure your options are used:
CXX := g++
CXXFLAGS := -m32 -fno-use-cxa-atexit -nostdlib -fno-builtin -fno-rtti -fno-exception -fno-leading-underscore
AS := as
ASFLAGS := --32

Simplifying a makefile

I have written a scary-looking Makefile by copy/pasting suggestions from Stack Overflow. However, I have read that it might not be necessary to provide explicit compiler invocations so many times (for example, the -O3 flag is everywhere). How can I simplify this Makefile?
CFLAGS = -Weverything -Wno-padded -Wno-unused-parameter -Wno-unused-variable -Wno-sign-conversion
all: fianchetto.o util.o ttable.o movegen.o
clang -O3 $(CFLAGS) -D NDEBUG $^ -o fianchetto
debugf: fianchetto.o ttable.o movegen.o
clang -O3 $(CFLAGS) -g3 $^ -o fianchetto
clean:
rm *.o && rm *.gch & rm fianchetto && rm -rf fianchetto.dSYM
%.o: %.c
clang -O3 -c $(CFLAGS) $< -o $#
fianchetto.o: fianchetto.c
ttable.o: ttable.h ttable.c
movegen.o: movegen.h movegen.c
util.o: util.h util.c
I am mystified by a lot of the syntax, and would appreciate links or explanations of why simplifications work!
CFLAGS and defines (which should be in CPPFLAGS anyway) are useless when linking
You're reinventing make's built-in rules, make will automatically link a target if one of its dependencies is "target.o" (in this case fianchetto: fianchetto.o). Make also knows how to compile C source files (as long as the source and object path match), so your pattern rule is superfluous too.
The object prerequisites aren't necessary as both clang and GCC can generate dependencies for you with the -M set of flags.
Compiling release and debug builds in the same dir makes for a more simple makefile, although you will need to remember to clean the object files when switching.
By default make assigns cc to CC, and cc should be a link to your system's default compiler, so you might not even need the first line below
CC := clang
CPPFLAGS := -MMD -MP
CFLAGS := -Weverything -Wno-padded -Wno-unused-parameter -Wno-unused-variable -Wno-sign-conversion -O3
objs := fianchetto.o util.o ttable.o movegen.o
deps := $(objs:.o=.d)
.PHONY: all debugf clean
all: CPPFLAGS += -DNDEBUG
debugf: CFLAGS += -g3
all debugf: fianchetto
fianchetto: $(objs)
clean: ; $(RM) $(objs) $(deps) fianchetto fianchetto.dSYM
-include $(deps)

How to define rules in the Makefile to compile only that *.cpp files which was modified (and their dependencies), not all *.cpp files

Lets say I have files:
Libs:
one.cpp, one.h
two.cpp, two.h
three.cpp, three.h
Program:
program.cpp
Is there way, to create Makefile which will compile only that *.cpp which were modified from last compilation?
Currently I have something like that:
SRCS = one.cpp two.cpp three.cpp
OBJS = $(SRCS:.cpp=.o)
all: $(OBJS) program
.cpp.o:
g++ -Wall -c $<
program:
g++ -Wall $(OBJS) program.cpp -o program
clean:
rm -f $(OBJS) program
I works fine, but when I compile my program and then change two.cpp or two.h I need to run "make clean" first, because when I secondly run "make" I get:
Nothing to be done for 'all'.
I would like to change my Makefile in that way, it would recognize my changes and recompile that file and its dependencies (if one.cpp uses code from two.cpp which was modified, both files should be recompiled).
So if I modify two.cpp, make should do:
g++ -Wall -c two.cpp
g++ -Wall $(OBJS) program.cpp -o program
But if one.cpp uses code from two.cpp which was modified, make shold do:
g++ -Wall -c one.cpp
g++ -Wall -c two.cpp
g++ -Wall $(OBJS) program.cpp -o program
First we make the object files prerequisites of the executable. Once this is done, Make will rebuild program whenever one of the SRCS changes, so we don't need OBJS as an explicit target:
all: program
program: $(OBJS)
g++ -Wall $(OBJS) program.cpp -o program
Then we make the header files prerequisites of the objects, so that if we change three.h, Make will rebuild three.o:
$(OBJS): %.o : %.h
And finally since one.cpp uses code from two.cpp by means of two.h (I hope), we make two.h a prerequisite of one.o:
one.o: two.h
And to make things cleaner and easier to maintain we use automatic variables:
program: $(OBJS)
g++ -Wall $^ program.cpp -o $#
Put it all together and we get:
SRCS = one.cpp two.cpp three.cpp
OBJS = $(SRCS:.cpp=.o)
all: program
$(OBJS): %.o : %.h
one.o: two.h
.cpp.o:
g++ -Wall -c $<
program: $(OBJS)
g++ -Wall $^ program.cpp -o $#
clean:
rm -f $(OBJS) program
There are a few more things we could do (like adding program.o to OBJS), but this is enough for today.
Add the files a command depends upon to run to the right of the target name.
Example:
default: hello.c
gcc -o hello.bin hello.c
install: hello.bin
cp hello.bin ../
All you need to do is tell make that the .o file depends on the .cpp file:
%.cpp.o: %.cpp
g++ -Wall -c -o $# $<

Resources