Makefile confusion phony hack - c

Folder structure:
Makefile
rect_01.c
rect_02.c
square_01.c
Makefile (relevant parts):
%.c:
echo 'Building $# for $(PLATFORM)...'
$(CC) $(CFLAGS) $# -o '$(DESTDIR)/$*'
Command:
make rect_01.c PLATFORM=FOO
Problem - gave me the output:
'rect_01.c up already to date'
So I tried a hack and added a dependency which I added to .Phony,
so that %.c should be executed every time. But now it tries to compile my
makefile even it hasn't the extension .c.
I wrote the following updated makefile (relevant parts):
.PHONY: phonyDummy
%.c: phonyDummy
echo 'Building $# for $(PLATFORM)...'
$(CC) $(CFLAGS) $# -o '$(DESTDIR)/$*'
Which gives me the following output:
make rect_01.c PLATFORM=LINUX_X86
echo 'Building Makefile.c for LINUX_X86...'
Building Makefile.c for LINUX_X86...
g++ -Wall -g Makefile.c -o '../Executables/Makefile'
Makefile: file not recognized: File format not recognized
Makefile:55: recipe for target 'Makefile.c' failed
make: *** [Makefile.c] Error 1
Can you explain this behaviour?

You should learn more about Makefile. You mix two important things: target and dependency.
The target is a file (in most cases) which should create with a rule. The dependency is the "source".
If you write:
%.c:
echo 'Building $# for $(PLATFORM)...'
$(CC) $(CFLAGS) $# -o '$(DESTDIR)/$*'
it means: "I want to create files with .c extension". You don't want to create .c files because you've many (three) .c files. The make checks the rect_01.c: it exists and it's up-to-date because it hasn't any dependency (after the : there isn't anything).
I think you want to build rect_01.so (or similar) - this is the target! So you want similar:
%.o: %.c
echo 'Building $# for $(PLATFORM)...'
$(CC) $(CFLAGS) -o $# $<
In this case if you want to build rect_01.o you should run make rect_01.o. The $(CC) will run if rect_01.o doesn't exist or older than rect_01.c (so the source rect_01.c is newer and doesn't rebuild yet).

Related

Makefiles giving the compiler files that dont/shouldnt exist

I have a basic Makefile setup for C OpenGL programming but when running there are 2 files passed to clang that shouldnt exist and i have no idea why. The problem happened after i added glad and glfw to the project.
code:
CC = clang
`CCFLAGS = -lGL -lglfw -std=c++20 -v -Wall -Wextra -Wepedantic -g -lgdi32
LDFLAGS = lib/glad/src/glad.o lib/glfw/src/libglfw3.a -lgdi32 -lm
SRC = $(wildcard src/*.c)
OBJ = $(SRC:.c=.o)
BIN = bin
all: libs build
libs:
cd lib/glad && $(CC) -o src/glad.o -Iinclude -c src/glad.c
cd lib/glfw && cmake . -G 'Unix Makefiles' && make
build: $(OBJ)
$(CC) -o $(BIN)/build $^ $(LDFLAGS)
%.o %.c:
$(CC) -o $# -c $< $(CCFLAGS)
run:
./bin/build.exe
ERROR:
clang: error: no such file or directory: 'all.o'
clang: error: no such file or directory: 'libs'
clang: error: no such file or directory: 'build'
When asking questions please include the command you typed, the command make printed, plus at least the first and last few lines of error messages (properly formatted as code blocks).
I'm assuming that the extra quote character is an error in your cut and paste; please take a moment to review your question after you post it (or even better, using the preview before you post it). You are writing this one time, but tens or hundreds of people will spend their time reading it. Please be considerate enough to make it easy for them.
Your problem is this:
%.o %.c:
$(CC) -o $# -c $< $(CCFLAGS)
You want to say "build a .o file from a .c file using this rule", but %.o %.c: says instead, "build both a .o and a .c file, from nothing, using this rule".
You need:
%.o: %.c
$(CC) -o $# -c $< $(CCFLAGS)

How to run and execute a makefile C

I'm trying to make a Makefile for my program. It is so difficult because i've read a lot of guide but none is clear. I have 3 files : main.c , library.c , library.h . Main.c and library.c depend on library.h . The structure of my directory project is formed by :
MyProject directory -> Build directory and Exercise1 directory -> all of my files . In compiler I wrote make and it compiled ; then when I write make execute command, it gives me this error:
cd ../build; ./test
Error: No such file or directory
makefile:23: recipe for target 'execute' failed
make: *** [execute] Error 1
MAKEFILE
CC=gcc
CFLAGS=-Wall
ODIR=../build
DIR = build
.PHONY: all
all: main.o library.o test
$(ODIR)/%.o: %.c $(DEPS)
$(CC) -std=c99 -c -o $# $< $(CFLAGS)
library.o: library.c library.h
$(CC) -std=c99 -c -o $(ODIR)/$# $< $(CFLAGS)
main.o: main.c library.h
$(CC) -std=c99 -c -o $(ODIR)/$# $< $(CFLAGS)
test: $(ODIR)/library.o $(ODIR)/main.o
$(CC) -std=c99 -o $(ODIR)/$# $^ $(CFLAGS)
execute:
cd $(ODIR); ./test
clean:
rm -f $(ODIR)/*.o
These lines:
execute:
cd $(ODIR); ./test
tell make that, when you give the command make execute, it should change the working directory to $(ODIR) and then execute ./test, which means to execute the file test in the current working directory. However, there is no file test in the $(ODIR) directory because you have not built it yet.
You can make that file by executing make test, but that is a bad way to do it. It is better to tell make that the execute target depends on $(ODIR)/test:
execute: $(ODIR)/test
cd $(ODIR); ./test
Then we should change the rule for test to $(ODIR)/test:
$(ODIR)/test: $(ODIR)/library.o $(ODIR)/main.o
$(CC) -std=c99 -o $(ODIR)/$# $^ $(CFLAGS)
Next, delete the rule for all and the .PHONY rule. A rule for all should be used when a makefile can make several different final targets, like ProgramA, ProgramB, and ProgramC, and you want one target that makes all of them. It should not be used to make all of the intermediate object files for a target. The intermediate files should arise out of the rules for building a final target.
Then delete the rules for library.o and main.o. Those are names for files in the current directory, but you are building in $(ODIR). We will let the pattern rule for $(ODIR)/%.o build those.
But we need to fix the pattern rule. It uses DEPS, but that is not defined. Add a line above that says what all the object files depend on:
DEPS=library.h
Nothing in the makefile uses DIR, so delete the line DIR = build.
Finally, you might want to put the execute target first, so that it is the default. Then your makefile is:
CC=gcc
CFLAGS=-Wall
ODIR=../build
DEPS=library.h
execute: $(ODIR)/test
cd $(ODIR); ./test
$(ODIR)/%.o: %.c $(DEPS)
$(CC) -std=c99 -c -o $# $< $(CFLAGS)
$(ODIR)/test: $(ODIR)/library.o $(ODIR)/main.o
$(CC) -std=c99 -o $(ODIR)/$# $^ $(CFLAGS)
clean:
rm -f $(ODIR)/*.o
You might also change the command for clean to remove test:
rm -f $(ODIR)/*.o $(ODIR)/test

Makefile cannot create a seperate Object Folder for simple project

I am using this Makefile Tutorial for understanding how to use Makefiles.
This Question might be a duplicate for this thread but I think I need more clarity here.
My Project structure:
--exercise_14/
--> ex14.c
--> ex14.h
--> main.c
--> Makefile
There is nothing complex about ex14.*, just simple header file with 3 function declarations (ex14.h) and their implementation (ex14.c) and main.c calls them.
My Makefile is as follows:
CC = gcc
CFLAGS = -Wall -g
DEPS = ex14.h
ODIR=obj
_OBJ=ex14.o main.o
OBJ=$(patsubst %,$(ODIR)/%,$(_OBJ))
all: ex14
$(ODIR)/%.o: %.c $(DEPS)
$(CC) $(CFLAGS) -c -o $# $<
ex14: $(OBJ)
$(CC) $(CFLAGS) -o $# $^
clean:
rm -f ex14 $(ODIR)*.o
rm -rf $(ODIR)
I am currently understanding how the patsubst in the file should work and everytime I run
make clean all
I get:
gcc -Wall -g -c -o obj/ex14.o ex14.c
Assembler messages:
Fatal error: can't create obj/ex14.o: No such file or directory
Makefile:16: recipe for target 'obj/ex14.o' failed
make: *** [obj/ex14.o] Error 1
Which makes sense that there is no obj/ folder created and no ex14.o is found for further compilation. A way around is to use mkdir obj and then perform make but I want to avoid that.
Question
What lines should be added to let my Makefile make a folder as ODIR=obj and put all the object files within it?
The correct solution is to make your object files depend on their directory via order-only dependency:
Consider an example where your targets are to be placed in a separate directory, and that directory might not exist before make is run. In this situation, you want the directory to be created before any targets are placed into it but, because the timestamps on directories change whenever a file is added, removed, or renamed, we certainly don’t want to rebuild all the targets whenever the directory’s timestamp changes. One way to manage this is with order-only prerequisites: make the directory an order-only prerequisite on all the targets:
$(ODIR)/%.o: %.c $(DEPS) | $(ODIR)
<same-original-recipe>
$(ODIR):
mkdir -p $#
As commented by others, but you can explicitly put a dependency to the $(ODIR) directory (it must be created before any dependent files ---compilation):
$(OBJS): $(ODIR)
$(ODIR):
mkdir -p $#
This will ensure you have created the $(ODIR) directory before any dependent files (any *.o file) and that it will be created only once.
The final contents of your Makefile should be as this:
CC = gcc
CFLAGS = -Wall -g
DEPS = ex14.h
ODIR=obj
_OBJ=ex14.o main.o
OBJ=$(patsubst %,$(ODIR)/%,$(_OBJ))
all: ex14
$(ODIR)/%.o: %.c $(DEPS)
$(CC) $(CFLAGS) -c -o $# $<
ex14: $(OBJ)
$(CC) $(CFLAGS) -o $# $^
clean:
rm -f ex14 $(ODIR)*.o
rm -rf $(ODIR)
$(OBJ): $(ODIR)
$(ODIR):
mkdir -p $#
EDIT 2
After posting the correct rule I found some errors in the $(patsubst) variable expansion, that made make to fail when not everything was erased.
Following is a correct, optimized Makefile:
$ cat Makefile
CC = gcc
CFLAGS = -Wall -g
DEPS = ex14.h
ODIR=obj
OBJS=ex14.o main.o
POBJS=$(foreach i,$(OBJS),$(ODIR)/$(i))
LIBS= # for example: -lm for math library.
.PHONY: all ex14 clean
$(ODIR)/%.o: %.c
$(CC) $(CFLAGS) -c $< -o $#
all: ex14
ex14: $(POBJS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $# $(POBJS) $(LIBS)
clean:
rm -rf $(ODIR)
$(POBJS): $(ODIR) $(DEPS)
$(ODIR):
mkdir -p $#
putting the dependency on $(DEPS) in the
$(OBJS): $(ODIR) $(DEPS)
makes the automatic default dependency rule for .c -> .o files valid, and not needed anymore in the makefile. Also, I have used P prefix to mean pathed file in POBJS against OBJS (which is the plain list of object files) Also removing recursively the objs subdirectory makes unnecessary to remove the object files first, and then the subdirectory (only the last command is needed) Also, when linking, it is common use, to pass the compiler the $(LDFLAGS) for it to pass them to the linker. And finally, if you have some libraries to include at the end, just use a $(LIBS) library (not needed for your sample).
As stated in one of the comments, the compilation of just one source file makes the $(ODIR) directory to be touched, and all the other files to be out of date, and this will make all the files but the one just compiled to be compiled next time. There's no solution to this problem as there's a circular dependency on this (the objects depend on the directory to exist, and the directory is touched on each compilation which makes the dependency to be triggered again for all the files compiled before the last one) The only possible solution to this problem is to eliminate the dependency on the directory and construct it by hand before calling make.
Berkeley make (pmake or bmake, it depends) has a workaround to this problem, by allowing you to define a .BEGIN dependency, that is to be solved before any other work. You can create the directory there. I think GNU make doesn't have this feature:
.BEGIN:
mkdir -p $(ODIR)
But this is out of scope for this question that is directed to GNU make.

Handling #include <folder/file.h> in C with makefiles

I am in the process of porting some code that was developed in the codeblocks IDE. I am transferring it to a Linux server where I can only use the command line to compile the code. The code is quite large (maybe 100 files) and I need to update the include commands in many files. For when I try to compile it errors on for instance: #include <gsl/gsl_math.h> with a file cannot be found error. I am assuming it cannot be found because the location of the gsl folder was declared in one of the search directory field options in the IDE. I could go through each file an update to the correct path, but is there a better way of doing this for use with a makefile?
Thanks!
EDIT Makefile In Question
# -c : do not link, just create object file
# -o : output file name
CFLAGS += -c -O2 -I../ctraj -I../cspice/include -I../SGP4 -I../cconj -I../GSL-1.13/include
LIBS = -L../ctraj -lctraj -L../cspice/lib -lcspice -L../SGP4 -lsgp4 -L../cconj -lcconj -L./ -lgsl-0 -lgslcblas-0 -lm
DEPS = light.h ../ctraj/ctraj.h ../cconj/cconj.h
OBJ = light.o tle.o propagator.o orbitfit.o conjunction.o light_displacement.o forces_LF.o
OUT = light.exe
%.o: %.c $(DEPS)
gcc -o $# $< $(CFLAGS)
light: $(OBJ)
cd ../ctraj/; make
gcc -o $(OUT) $(OBJ) $(LIBS)
clean:
rm *.o $(OUT)
Edit 2
Folder Structure
light->(GSL-1.13, Light, cconj, ctraj)
the makefile is inside the Light folder.
Error Message
cd ../ctraj/; make
make[1]: Entering directory `/light/ctraj'
gcc -o forces.o forces.c -c -Wall -Wno-maybe-uninitialized -Wno-unused-but-set-variable -O2 -I../cspice/include -Inrlmsise
In file included from ../Light/../cconj/cconj.h:12:0,
from ../Light/light.h:13,
from forces.c:3:
../Light/../cconj/../GSL-1.13/include/gsl/gsl_blas.h:26:28: fatal error: gsl/gsl_vector.h: No such file or directory
compilation terminated.
make[1]: *** [forces.o] Error 1
make[1]: Leaving directory /light/ctraj'
make: *** [light] Error 2
EDIT 3
Second makefile in cconj
# -c : do not link, just create object file
# -o : output file name
#-L../cconj -lcconj
CFLAGS += -c -O2 -I./ -I../GSL-1.13/include
LIBS = -L./ -lgsl-0 -lgslcblas-0 -lm
INC= -I../GSL-1.13/include
DEPS = cconj.h
OBJ = cconj_util.o ellipse_intersect.o collision_prob_real.o rcs2size.o
OUT = libcconj.a
%.o: %.c $(DEPS)
gcc -o $# $< $(CFLAGS)
cconj: $(OBJ)
ar rcs $(OUT) $(OBJ)
clean:
rm *.o $(OUT)
Try adding this line to your makefile, and tell us if it works:
CFLAGS += -I../GSL-1.13/include
In order to compile source code and produce object files, Make must use a rule. (If you don't put such a rule in the makefile, Make has a default rule for that purpose.) It looks something like this:
%.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $#
Without digging too deeply into how that works, we can say that CFLAGS is a list of arguments to be passed to the compiler. When we add -I../GSL-1.13/include, we tell the compiler "if you want to #include something and can't find it elsewhere, look in ../GSL-1.13/include".
If this approach doesn't work, then there's probably a rule in the makefile we must find and alter.
EDIT:
The problem isn't in this makefile (which already contains a reference to GSL-1.13/include). In this command:
cd ../ctraj/; make
this makefile launches a second Make process, which uses the Makefile in light/cconj/. According to the compiler output (gcc -o forces.o ...), that makefile does not include the reference. So try adding the same line there, and if that doesn't work, post that makefile and we'll keep looking.
Use -I option of gcc to specify where to look for includes.

Using assembly object files from a subdirectory

I have a small project with several .c files and one .s assembly file (crt0.s). The .c files are compiled into .o files, and are stored in the ./build subdirectory. These files compile and link correctly.
I would like the .s file to be stored in the ./build directory as well. So far, my makefile compiles the .s file and stores it in the correct location, however the linker can't find it.
The error I get is "ld.exe cannot find crt0.o". crt0.o is definitely being created in the ./build directory.
Here is the makefile:
CC=arm-none-eabi-gcc
AS=arm-none-eabi-as
CFLAGS=-nostartfiles -nodefaultlibs -fno-builtin -Wall -T linker.ld -I./Include
objects=$(addprefix $(OBJDIR)/,crt0.o main.o gpiopins.o framebuffer.o drawchar.o putchar.o intconv.o strlen.o kprintf.o kputchar.o)
OBJDIR=./build
$(OBJDIR)/%.o: %.s
$(AS) -o $# $<
$(OBJDIR)/%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
kernel.img: $(objects)
$(CC) -o kernel.img $(objects) $(CFLAGS)
.PHONY : clean
clean:
rm -f kernel.img
rm -f *.o
rm -f $(OBJDIR)/*.o
Any Ideas where I may be going wrong?
Thank you
EDIT:
If I do it manually, it is fine. eg:
kernel.img: $(objects)
arm-none-eabi-as -o crt0.o crt0.s
$(CC) -o kernel.img $(objects) $(CFLAGS)
However, this means that crt0.o is not in the ./build directory
How can the "manual" variant be ok? The var objects contains ./build/crt0.o which is what your linker needs. The as command you pushed in is not providing it, so how does it help? And even if it did, it would come too late, because all objects together are dependencies of the rule.
Do make clean and show us the output, that might help to spot what's going on.

Resources