Issue with dependency files using Makefiles; file.d exist - linux

I have the following sub-section of makefile that's used to generate the .d files
-include $(wildcard $(patsubst %,$(OBJ_PATH)/%.d,$(basename $(SRCS))))
%.o: %.cpp
#$(CC) -I$(INCLUDE_PATH) $(CFLAGS) $< -MM -MT $(#:.d=.o) > $(OBJ_PATH)/$(notdir $*.d)
${CC} -I$(INCLUDE_PATH) $(CFLAGS) -c $< -o $(OBJ_PATH)/$(notdir $#)
Sometimes when I build the project, I get the following error /bin/sh: /path/to/my/build/dir/file.d: File exists, although .d files does not exist.
Then I keep getting this error, the only way to get rid of it is to remove the whole enclosing directory and use git restore and the system will build successfully.
System info:
git version 2.27.0
GNU Make 4.2.1
Red Hat Enterprise Linux 8.5 (Ootpa)
Free inodes: 426798634

You should remove the # from your line that creates the .d file, so you can see what the command line actually is. It's always a bad idea to add # before your makefile is working 100% correctly. Then you could cut and paste a full failure example into your question, including the command that generated the error message.
Your build lines are not right. During the compilation, you need to use $# not $(OBJ_PATH)/$(notdir $#). It's always wrong to build a file that is not exactly $#.
During the creation of the dependency file $(#:.d=.o) is useless because $# is already set to xxx.o so changing the .d suffix to .o doesn't do anything. You should just use -MT $# here.
You can replace $(OBJ_PATH)/$(notdir $*.d) with the simpler %*.d.
This error is being shown by the shell and there's really no way we can understand what the problem is with the info given. Why would the shell give a "File exists" error when you use ">" to overwrite it?
I have a suspicion that it's not actually this command that is generating that error.

Related

Getting dependencies of a shared library that could be located at any folder

I'm creating a Rules.make file, similar to Linux's 2.0 version, which contains all kinds of targets - including .so files. My goal is to then only need to make minimalistic Makefiles like so:
include $(DIR_TOP)/Rules.make
in the directories that contain any source files I need compiled. The rules also enable me to create targets like so in the "main" Makefile:
something: something_else lib.so
, so that something_else is done first, and then lib.so is built.
Everything has been going smoothly, until I decided to add dependencies to the aforementioned shared library target. I figured something like the following would do the trick:
${DIR_OUT}/%.so: $(shell find $(dir $#) -name *.o)
$(CC) $(CFLAGS) -o $# $(CLIBS) -shared $^
However, to my demise, $(dir $#) apparently expands to $(dir ${DIR_OUT}/%.so), which then results in simply ${DIR_OUT}, which is exactly not what I need. DIR_OUT is simply the top-level directory string, but the target may be invoked from any sub-directories, or simply like target: $(DIR_OUT)/path/to/lib.so. I was hoping that % could match not only file names, but also any directories (which it does), and then have that expanded to $# once it's already decided what the full path is. Doesn't work like that. With this solution, not only the object files I need are included in the building process, but also any other object files that are there in the output folder, and that then produces errors of kind multiple definition of x y z etc.
Is there any other way to get the list of dependencies for the shared library I want to build? Ideally a purely Makefile based solution, but if there isn't one, I'm fond of some bash scripting too.
The solution turns out to be secondary expansion:
.SECONDEXPANSION:
${DIR_OUT}/%.so: $$(shell find $$(dir $$#) -name *.o)
$(CC) $(CFLAGS) -o $# $(CLIBS) -shared $^

Primitive makefile failure for compiling

I am trying to learn makefile, but I fail badly.
One example (which is very primitive) but I should understand it to go ahead is this one
f90_simple: f1.o
gfortran f1.o
mv a.out f90_simple
f90_simple.o: f1.f90
gfortran -c f1.f90
it does not work, and I get this error
I get this error
make: *** No rule to make target `f1.o', needed by `f90_simple'. Stop.
could you please advise me?
thanks
Your first rule says that before f90_simple can be built, the target f1.o must be built.
But there's no rule in your makefile that tells make how to build the target f1.o, and make can't find any built-in rule that can build it (based on the source files make has available), so it prints that error.
You do have a rule that tells make how to build a target f90_simple.o... but that's not the target make is looking for. Most likely you want your makefile to either be:
f90_simple: f1.o
gfortran $^
mv a.out $#
f1.o: f1.f90
gfortran -o $# -c $<
or else:
f90_simple: f90_simple.o
gfortran $^
mv a.out $#
f90_simple.o: f1.f90
gfortran -o $# -c $<
but you can't mix and match them, or make doesn't know what to do.
I think you would really benefit from reading at least the introductory chapters in The GNU Make Manual.

Makefile: compiling several objects with single target

I have several c++ objects that I'd like to compile using a single target. If possible I'll make a variable in the makefile that list all the object files and then have a single target that compiles them all.
Following this question I have the following "Makefile" so far:
#### Directories and flags
ifndef $(DIR_MAIN)
DIR_MAIN=../..
endif
DIR_EXE=$(DIR_MAIN)
DIR_SRC=$(DIR_MAIN)/src/Analyse_MC
DIR_MISC_SRC=$(DIR_MAIN)/src/Misc
DIR_BLD=$(DIR_MAIN)/build/Analyse_MC
DIR_MISC_BLD=$(DIR_MAIN)/build/Misc
COMP=g++
COMPILE_FLAGS= -std=c++11 -O3 -lstdc++ `pkg-config --cflags eigen3` -msse2 -I${DIR_MISC_SRC}
LINK_FLAGS= -O3 -fopenmp -lgsl -lgslcblas -lm -lhdf5_cpp -lhdf5
OBSERVABLE_OBJECTS=g_decomp_IP_orthog_sphere.o g_decomp_LS_orthog_sphere.o g_decomp_IP_disk.o g_decomp_LS_disk.o find_rank.o eigenvectors.o GramSchmidt.o diagonal_Hamiltonian.o mean_log_WF.o energy.o JK_EP_overlap.o overlap.o geo_mean_eigstate_overlap.o eigstate_overlap.o pair_corr_bins.o
#### Compile all
all: setup observables $(DIR_EXE)/Analyse_MC
setup:
#mkdir -p $(DIR_BLD)
#### Compile observable objects
observables: $(addsuffix -stamp,$(OBSERVABLE_OBJECTS))
%.-stamp : %.o
${COMP} -c -o $# $<
However when running make I get the following:
make: *** No rule to make target `g_decomp_IP_orthog_sphere.o-stamp', needed by `observables'. Stop.
So I've misunderstood something.
If possible I'd also like each of the objects to be updated with changes in .h-files with the name of the object in addition to some common .h-files for all of the objects. Is this possible?
Or do I have to / is it recommended to write a separate target for each object?
EDIT:
Some info about the variables:
DIR_MAIN is defined the way it is because usually this makefile will be called from another makefile which defines DIR_MAIN from its directory using pwd; but ut can also be called on its own from its own directory.
DIR_MISC_SRC points to some header files necessary for the files in DIR_SRC.
DIR_BLD and DIR_MISC_BLD will contain the corresponding resulting object files.
The error message does show you what you've done wrong, but a bit obliquely:
make: *** No rule to make target g_decomp_IP_orthog_sphere.o-stamp, needed by observables. Stop.
Your rule to make stamp files is:
%.-stamp: %.o
You probably wanted that to be
%.o-stamp: %.o
Compiling %.o to %.o-stamp looks very strange to begin with - probably you just want
observables: $(OBSERVABLE_OBJECTS)
.PHONY: observables
Stamp files are sometimes useful for actions you want to perform once but have no output file. For compilation, the object file is the output file, and that's all that make requires.
If possible I'd also like each of the objects to be updated with changes in .h-files with the name of the object in addition to some common .h-files for all of the objects. Is this possible?
That's a whole nother question in itself - you want to search for "makefile auto-dependency generation" for starting points.

Makefile rule is not executing in Linux

I am trying to build the Atmel BitCloud v3.2 sample application Blink with the makefile in Linux and Mac. Everything works fine in Windows. But in Posix-like systems the following lines are not working:
all: directories images root_files size
$(OBJ_PATH)/%.o: $(SRCS)
$(CC) $(CFLAGS) $(filter %/$(subst .o,.c,$(notdir $#)), $(SRCS)) -o $#
Therefore, the compiler is not being executed and object files are not being created. As the result the linker displays error messages such as
avr-gcc: error: All_MegaRf_Atmega256rfr2_8Mhz_Gcc/Obj/blink.o: No such file or directory
The line $(OBJ_PATH)/%.o: $(SRCS) is the source of the problem.
If I substitute it with smth like $(OBJ_PATH)/blink.o: ../../src/blink.c the corresponding object-file is being successfully created.
I was even able to build the whole application by manually setting build targets as follows:
$(OBJ_PATH)/blink.o: ../../src/blink.c
$(CC) $(CFLAGS) $(filter %/$(subst .o,.c,$(notdir $#)), $(SRCS)) -o $#
$(OBJ_PATH)/stdPdsEvents.o: ../../../../BitCloud/Components/PersistDataServer/std/src/stdPdsEvents.c
$(CC) $(CFLAGS) $(filter %/$(subst .o,.c,$(notdir $#)), $(SRCS)) -o $#
for all the .c files in the project.
The list of sources on the other hand is defined like this:
SRCS = \
../../src/blink.c \
../../../../BitCloud/Components/PersistDataServer/std/src/stdPdsMemAccess.c \
../../../../BitCloud/Components/PersistDataServer/std/src/stdPdsTimer.c \
Can anyone help me to figure out why is the pattern matching not working and how to recover it.
Note: Similar topic has already been open here, but the solution found by th author himself wasn't explained well in my opinion, so I couldn't solve my problem.
The construct to have each object file depend on all source files and then have the compilation step fish the actually useful file out of the list of sources is quite dubious. A better approach would be to generate a Makefile snippet and include it, something like this:
makefile.d:
echo "$(SRCS)" \
| tr ' ' '\n' \
| sed -n 's%\(.*\)/\([^/]*\)\.c$$%$(OBJ_PATH)/\2.o: \1/\2.c%p' >$#
include makefile.d
All details of sed are not properly standardized, so you may be better off rewriting the substitution in Perl or something. The beef here is how we capture the path and the base name and generate a specific rule for each dependency.
Managed to solve it finally.
In order to make it compile both in Windows and Linux one should change the makefile as shown below:
objects := $(patsubst %.c,$(OBJ_PATH)/%.o,$(notdir $(SRCS)))
$(objects): $(SRCS)
#$(OBJ_PATH)/%.o: $(SRCS)
$(CC) $(CFLAGS) $(filter %/$(subst .o,.c,$(notdir $#)), $(SRCS)) -o $#
where $(OBJ_PATH)/%.o: $(SRCS) shall be commented or removed.
After having done this way the project can be built under linux or mac and under windows both in Atmel Studio 6.2 and Atmel Studio 7. The latter was not able to build just like it was not possible in linux or mac.

Make could not see commands (recipes) except gcc

My system is windows 8.1. I'm working on cygwin 32 bit version (first i set up 64 bit version and could not uninstall completely , later set up 32 bit version).I simply want to use 'make' utility. All my makefiles' extensions are 'makefile'.
When i try this below (to see them work , I only use simple makefiles)
make kernel.o (in shell)
kernel.o : kernel.c
<tab>gcc - ffreestanding -c $< -o $#
it works , and compiles.
But these ones below do not work. And for testing purposes and keeping things simple, each source and corresponding makefiles are in own directory. And all make commands've been made in the current directory where source and corresponding makefiles are located.
All executables (nasm ,ld ,objcopy ,cat) that cygwin needs to run the recipes are in the same directory (that is c:\cygwin\bin\)
If i command the recipes from shell, they work.
I also changed source files to see what would happen.
I also thought that maybe the problem is from cygwin itself , and i set up linux ubuntu desktop version to my machine. But they are (recipes below) not working too.(and also If i command the recipes from shell, they work.)
make kernel_entry.o (in shell)
make: *** No rule to make target 'kernel_entry.o'.
Rule:
kernel_entry.o : kernel_entry.asm
<tab>nasm $< -o $# -f coff (coff for windows)
//--------------------------------
make os-image.bin (in shell)
make: *** No rule to make target 'os-image.bin'.
Rule:
os-image.bin: boot.bin kernel.bin
<tab>cat $< > $#
//--------------------------------
make boot.bin
make: *** No rule to make target 'boot.bin'.
Rule :
boot.bin : boot.asm
<tab> nasm $< -f bin -o $#
*recipes with ld and objcopy also does not work.*
Thank you in advance...
These are my files and directory appearance :
C:\cygwin\bin --> where gcc.stays
C:\cygwin\bin --> where make.exe stays
C:\cygwin\bin --> where objcopy stays
C:\cygwin\bin --> where nasm.exe stays
C:\cygwin\bin --> where ld stays
C:\cygwin\home\me\OS\boot --> where boot.makefile stays and also boot.asm source code
C:\cygwin\home\me\OS\kernel --> where kern.makefile stays ( working sample ) and also kernel.c source code
And this is cygwin shell appearance:
me#Me ~/os/kernel
$ dir
kern.makefile kernel.c kernel_entry.asm
**in my kern.makefile the existing rule is as follows
kernel_entry.o : kernel_entry.asm
nasm $< -o $# -f coff
and boot directory
me#Me ~/os/boot
$ dir
boot.asm disk_load.asm print_hex.asm print_string_pm.asm
boot.makefile gdt.asm print_string.asm switch_to_pm.asm
**in my boot.makefile the existing rule is as follows
boot.bin : boot.asm
nasm $< -f bin -o $#
Make does not see your makefiles.
From the GNU make manual:
If no -f option is present, make will look for the makefiles GNUmakefile, makefile, and Makefile, in that order.
From what I see, your makefiles (kern.makefile, boot.makefile) are simply not found by your call to make (which does not have a -f option). This makes make rely on its internal rules, which do not include any %.o: %.asm dependency or somesuch (for make, assembly ends in .s, assembly with preprocessing to be done in .S).
This can become bloody confusing when your *.c and *.S files are compiled into *.o files, because make does have internal rules for those -- which, of course, stubbornly refuse to take any compiler options into account that you might have defined in that makefile of yours that make doesn't actually read. ;-)
So either call
make -f kern.makefile kernel.o
or (and this is my recommendation), rename <whatever>.makefile to Makefile (which is the canonical way of naming those).

Resources