Makefile, Anonymous rm command executed at last - makefile

Required stripe of the Makefile is as follows
PCS=$(wildcard $(PC)/*.pc)
SRCS=$(PCS:$(PC)/%.pc=$(SRC)/%.cpp)
OBJS=$(SRCS:$(SRC)/%.cpp=$(OBJ)/%.o)
f2db : $(OBJS)
$(CC) $(INCS) $(LIBS) $(FLAGS) $(OBJS) f2db.cpp -o $#
$(OBJ)/%.o : $(SRC)/%.cpp
$(CC) $(INCS) $(FLAGS) -c $< -o $#
$(SRC)/%.cpp : $(PC)/%.pc
$(PROC) $< CODE=CPP CPP_SUFFIX=cpp INCLUDE=inc INCLUDE=/usr/include
mv $(PC)/*.cpp $(SRC)
On gmake command invoke all is as expected except the remove command at last. The last two lines of the output as follows
gmake: warning: Clock skew detected. Your build may be incomplete.
rm src/fileName.cpp
Tool used GNU Make 3.80 in Solaris OS, why is this happening?

The clock skew warning is most likely because the directory you're building in is mounted from a remote system using something like NFS, etc., and the remote filesystem's clock is not synchronized with your local system clock. Anyway, that's not related to the rm command.
The rm command is happening because the src/fileName.cpp is an intermediate file and intermediate files are removed by make after they're built.
If you don't want them to be removed, just declare them as prerequisites of a rule so that they're not intermediate any longer:
f2db : $(OBJS) $(SRCS)

Related

Good form method to write rules in Makefile for subdirs

I'm trying to do good logic in Makefile for my project. Let's assume i have a Makefile with rules:
...
NAME := prog_name
...
all: subsystem
subsystem:
#$(MAKE) -sC $(D_LIB)
#$(MAKE) -s $(NAME)
$(D_OBJ):
#mkdir -p $(D_OBJ)
$(NAME): $(D_OBJ) $(OBJ) $(H) $(LIB)
$(CC) ... -o $(NAME)
$(D_OBJ)%.o: $(D_SRC)%.c $(H) $(LIB)
#$(CC) ... -c $< -o $#
.PHONY: all subsystem
When i run command:
make (make all)
It check $(D_LIB) for any changes, then run make for $(NAME) rule. And if there were changes in the library or program files my program recompiles.
But if i run command:
make prog_name
It would not run subsystem rule and i will not know about the changes in the library in any way. Accordingly, the program won't be rebuilt. So I am tormented by the question of how to make it interconnected. If i run command make (all) or run command make prog_name, i should check every dependies for my programm and re-build it if necessary.

build directory with Makefile - compiles everytime

I have 3 files in my directory as follows:
foo.h
foo.cc
main.cc
build/ <-- Created if doesn't exist.
I want the .o and executable files to be generated in a build folder in the same directory.
I also don't want the code recompiling if nothing has changed.
Here is my Makefile:
CC=g++
CFLAGS=-std=c++17
OBJS=build/foo.o
.PHONY: all clean
all: build/main
build/main: main.cc $(OBJS)
$(CC) $(CFLAGS) -o $# $^
build/%.o: %.cc build
$(CC) $(CFLAGS) -c -o $# $<
build:
mkdir -p build
clean:
rm -rf build
If I run make build/foo.o, it doesn't re-compile if nothing has changed in the source code.
But make all or make build/main always re-compiles everything. What am I doing wrong?
I don't have this issue if I output the compiled code in the same directory.
Ugh, just minutes after posting this, I found the answer on Google.
Problem is that because the build directory timestamp gets updated even if one file in the directory is created/updated, it will rebuild always from scratch.
There are several approaches listed in the link above to fix it. I ended up just adding a pipe (|) operator to the build rule to make it an order-only pre-requisite. i.e. this line:
build/%.o: %.cc |build
$(CC) $(CFLAGS) -c -o $# $<
and that seems to have fixed it :|

Why is my Makefile rule not deleting .o files?

My Makefile works but I'm still getting the main.o file created when calling make.
I've been looking through Stack Overflow for topics like mine but I haven't been able to understand the reason.
Here's the Makefile's content:
EXEC=program
SOURCES=main.c
OBJECTS=$(SOURCES:.c=.o)
CC=gcc -pthread -lpthread
CFLAGS=-std=gnu99 -g
.PHONY: clean
default: $(EXEC)
main.o: main.c
clean:
-rm *.o $(objects) program
%.o: %.c
$(CC) -o $# -c $< $(CFLAGS)
$(EXEC): $(OBJECTS)
$(CC) -o $# $^
If you want your object files removed after the build step just append the rm -f *.o command to the $(EXEC) target.
Also, a few notes pointed out in the comments:
Makefile variable names are case-sensitive. Use either objects or OBJECTS, not both.
Instead of hard-coding program in your clean target, you should instead use $(EXEC). That way you won't have to change it every time you change your program's name.
You usually want .o files to be left after compiling so you don't have to recompile everything after a small change.
You can have Make delete your object files automatically -- and not rebuild them needlessly when the sources have not been changed -- by making them intermediate files by means of the .INTERMEDIATE special target. Just add this line:
.INTERMEDIATE: $(OBJECTS)

GNU Make reports no rule when dealing with a target under subdirectory with source from another directory

My project's directory is mounted via NFS. From the directory under which it is mounted, I call make -f msh/Makefile cd=msh. (msh is my mount.) cd is a variable in the Makefile that is prepended to source files. This works fine with source files directly under cd. However, if the source files are under a subdirectory within cd, Make fails, saying that there is no rule to make that target. It does not fail if I call Make from within my mount.
This is my Makefile.
CC?=gcc
CFLAGS:=-Wall -Werror -D_POSIX_C_SOURCE=200112L $(CFLAGS)
cd?=.
objects_nix=if/tty.o
objects:=sub.o if.o $(objects_nix)
ifdef SO
CFLAGS+=-fPIC
bin=libmsh.so
else
bin=libmsh.a
endif
.PHONY : clean
$(bin) :
libmsh.a : $(objects)
$(AR) -r -c -s $# $(objects)
libmsh.so : $(objects)
#echo
#echo If you have resumed compilation after not having used the SO flag,
#echo you should run make clean.
#echo
$(LD) $(LDFLAGS) -shared -o $# $(objects)
test : $(cd)/test.c $(bin)
ifdef SO
$(CC) $(CFLAGS) -I$(cd) $(LDFLAGS) -L. -lmsh -Wl,-rpath,. -o $# $(cd)/test.c
else
$(CC) $(CFLAGS) -I$(cd) $(LDFLAGS) -o $# $(cd)/test.c $(bin)
endif
%.o : $(cd)/%.c
$(CC) $(CFLAGS) -c -o $# $<
clean :
rm -f libmsh.so libmsh.a
rm -f $(objects)
rm -f test.o test
I have tried creating another rule for the subdirectory, and this works. But I'd like it to work with only the one rule.
You have told Make how to make a .o file from .c file in $(cd). It does not know how to make a .o file if the .c file in some other directory. You can solve this in various ways, such as:
Add an explicit rule for all directories. You have already done that.
Use VPATH.
Create a Makefile for each directory.

How can I have a step in a makefile to generate preprocess files and compile from those files?

I took a makefile from a previous project that compiles programs for an avr microcontroller. I ran into some problems with what IO ports/data directional addresses I was setting which was causing the microcontroller to fault and reset. Because of this I wanted to add a step in my makefile to have it generate the pre-proccessed files and then compile from these preprocessed files. I'm not too familiar with how rules/dependencies work in makefiles so I've made, what I believe is, a simple mistake in my understanding of how makefiles work. My rules to make the preprocessed files/object files and eventually the .elf file must be wrong. Up until I added the steps which attempted to create the preprocessed files creating the .elf file work fine. What is my simple mistake/understanding in how rules/dependencies work in make?
How I view this working is when I ask to make all it sees that it has a dependency of led.elf. To create this it has the dependency of the preprocessed files based on the line of $(OUTPUT).elf: $(PROCESS_FILES) so it starts with this line. When I try to make all however I get the error make: *** No rule to make target 'main.c', needed by 'main.e'. Stop. and I don't understand why. Can anyone help my understanding in make files?
SRC_FILES=\
main.c led.c comm.c
#Object files
PROCESS_FILES=$(SRC_FILES:.c=.e)
OBJ_FILES=$(PROCESS_FILES:.e=.o)
#Directories where to look for include files
INC_DIRS=\
-I. \
#Output file name
OUTPUT=led
#Programmer and port
PROG=dragon_isp
PORT=usb
#Debugging host and port
DHOST=localhost
DPORT=6423
#Compiler related params
MCU=atmega2560
CC=avr-gcc
OBJCOPY=avr-objcopy
CFLAGS= -mcall-prologues -std=gnu99 -funsigned-char -funsigned bitfields \
-fpack-struct -fshort-enums -mmcu=$(MCU) -Wall -Wstrict-prototypes \
$(INC_DIRS)
#Optimization level
CFLAGS+=-Os
#Debug info
CFLAGS+=-gdwarf-2
#Generate hex file ready to upload
all: $(OUTPUT).elf
$(OBJCOPY) -R .eeprom -O ihex $(OUTPUT).elf $(OUTPUT).hex
#Link output files
$(OUTPUT).elf: $(PROCESS_FILES)
$(CC) $(CFLAGS) $(OBJ_FILES) -o $(OUTPUT).elf -Wl,-Map,$(OUTPUT).map
#Create object files
$(PROCESS_FILES): %.e : %.c
$(CC) -E $(CFLAGS) $< -o $#
$(OBJ_FILES): %.o : %.e
$(CC) -x $(CFLAGS) $< -o $#
#Create assembler file of a C source
%.s: %.c
$(CC) -S $(CFLAGS) $< -o $#
#Cleans all generated files
clean:
rm -f $(OBJ_FILES)
rm -f $(OUTPUT).elf
rm -f $(OUTPUT).hex
rm -f $(OUTPUT).map
Edit: I'm away from my computer now so I can't check this but thinking about my issue I'm starting to think I don't have a file named main.c in that directory. Even if I did I still think the makefile would not work correctly because I don't fully understand rules in makefiles.
My error was coming from the fact that I did not have a main.c file in my directory. Make sure you backup files when you're messing with the OBJ_FILES or similar variable and have a line that will delete whatever is in that variable upon a make clean.
As for the rules, I had to make one small fix to achieve what I wanted. I changed
$(OUTPUT).elf: $(PROCESS_FILES)
$(CC) $(CFLAGS) $(OBJ_FILES) -o $(OUTPUT).elf -Wl,-Map,$(OUTPUT).map
to
$(OUTPUT).elf: $(OBJ_FILES)
$(CC) $(CFLAGS) $(OBJ_FILES) -o $(OUTPUT).elf -Wl,-Map,$(OUTPUT).map
This then sees it needs the object files which in turn needs the preprocessed files.
Edit: I also changed OBJ_FILES=$(PROCESS_FILES:.e=.o) to OBJ_FILES=$(SRC_FILES:.c=.o). I also added $(PROCESS_FILES) to $(OUTPUT).elf: $(OBJ_FILES) so the rule would generate both the preprocessed files and object files independently. I had to change $(OBJ_FILES): %.o : %.e to $(OBJ_FILES): %.o : %.c to make this work.

Resources