In the following Makefile, I would like make not to remake the ALL md5 files when the final file: checksums.md5 already exists:
SOURCEDIR := .
SOURCES := $(shell find $(SOURCEDIR) -name '*.gz')
STAGES := .md5
CAT := checksums.md5
ALL := $(foreach I, $(STAGES), $(addsuffix $I, $(SOURCES)))
all : ${CAT}
%.md5: %
md5sum $< > $#
${CAT} : ${ALL}
cat $^ >> $#
rm *gz.md5
You can use conditionals. Example:
SOURCEDIR := .
SOURCES := $(shell find $(SOURCEDIR) -name '*.gz')
STAGES := .md5
CAT := checksums.md5
ALL := $(foreach I,$(STAGES),$(addsuffix $(I),$(SOURCES)))
ifeq ($(wildcard $(CAT)),)
all: $(CAT)
%.md5: %
md5sum $< > $#
$(CAT): $(ALL)
cat $^ >> $#
rm $(ALL)
else
all:
#echo "Nothing to be done"
endif
Explanation: if checksums.md5 exists, $(wildcard $(CAT)) will expand as checksums.md5 (not the empty string) and the ifeq conditional will instantiate what is between else and endif. If checksums.md5 does not exist, $(wildcard $(CAT)) will expand as the empty string and the ifeq conditional will instantiate what is between ifeq and else. It is a bit like if you had two different Makefiles for the two situations.
Notes:
I suppressed useless spaces in your foreach call (avoid useless spaces with make, they may have an impact on its behavior).
Do not suppress the space between ifeq and ($(wildcard..., it is needed.
I replaced curly braces (obsolete) by parentheses.
I added parentheses to references to non-automatic variables ($I => $(I)) because it is strongly advised.
I replaced rm *gz.md5 by rm $(ALL) which seems better if you have some of your sources in sub-directories.
General remark: what you do is not inline with the make philosophy. make decides what should be done and what should not, based on the last modification time of files and a set of target-prerequisites dependency specifications. If you do not use this feature of make you should probably not use it at all. Any scripting language (bash, python, perl...) would probably be better.
If you do not want these partial md5 files, why don't you directly put the sums in checksums.md5? Example:
SOURCEDIR := .
SOURCES := $(shell find $(SOURCEDIR) -name '*.gz')
CAT := checksums.md5
all: $(CAT)
$(CAT): $(SOURCES)
md5sum $^ > $#
clean:
rm -f $(CAT)
If checksums.md5 exists and is up-to-date (more recent than the sources), nothing will be done. Else, all md5sums will be recomputed and stored in checksums.md5.
If your problem is to avoid recomputing md5sums of files that did not change, you need to keep track of the last time you computed them and there is no better way than keeping these intermediate md5sum files. But you can put them all in a separate directory, if you wish:
SOURCEDIR := .
MD5DIR := .md5sums
SOURCES := $(shell find $(SOURCEDIR) -name '*.gz')
CAT := checksums.md5
ALL := $(addprefix $(MD5DIR)/,$(patsubst %,%.md5,$(SOURCES)))
all: $(CAT)
$(MD5DIR)/%.md5: %
mkdir -p $(dir $#) && \
md5sum $< > $#
$(CAT): $(ALL)
cat $^ > $#
clean:
rm -rf $(MD5DIR) $(CAT)
Notes:
Just for fun I used a different way of computing the md5sum file names ($(ALL)) using addprefix and patsubst.
The mkdir -p in the $(MD5DIR)/%.md5: % recipe is needed to create the destination directory before storing the md5sum file in it.
These destination sub-directories of $(MD5DIR) are needed if you have your sources also in sub-directories and some of them can have the same base name.
Related
The original makefile I have, which works, only involves one source folder and the makefile is stored inside this folder. Now I have multiple folders inside my src folder.
I am using an autogeneration script to work out dependencies and objective files. Each subfolder has a Make-deps and Make-objs file. These are generated from the $(AUTOGEN) command
Before I had this:
deps:
$(AUTOGEN) -d -s $(SRCDIR) -f ../scripts/fgenrc ;\
sed -i "" -e's/(SRCDIR)/(OBJDIR)/' Make-objs ; \
sed -i "" -e's/(SRCDIR)\(.*\)\.o/(OBJDIR)\1\.o/g' Make-deps ; \
So $(AUTOGEN) is just the shell script which makes the dependencies and $(SRCDIR) is where the source files are. Make-obj and Make-deps are the files containing the dependencies and objective file names.
Somewhere else I have the following:
$(OBJDIR)/%.o: %.f Makefile
#$(F90) $(FFLAGS) $(POPTIONS) -o $# $<
Now I want to this but where my %.f files are in various folders, and also where I have several Make-obj and Make-deps.
Maybe I should show an example of Make-obs and Make-deps:
Make-deps:
$(OBJDIR)/fluxes.o fluxes.o: \
path/to/src/folder1/fluxes.f90 \
$(OBJDIR)/mod.o \
$(OBJDIR)/ig.o ig.o: \
path/to/src/folder1/ig.f90 \
$(OBJDIR)/mod.o \
from the sed command I change the objective file path to be $(OBJDIR) because this is where I move them when being compiled.
Make-obj
OBJS = \
$(OBJDIR)/fluxes.o \
$(OBJDIR)/ig.o \
Now I have defined
SOURCE_FILES_c := $(shell find $(SRCDIR) -name '*.c')
SOURCE_FILES_f90 := $(shell find $(SRCDIR) -name '*.f90')
which are all source files found the SRCDIR and its subfolders. Also I have defined
DEPS_FILES := $(shell find $(SRCDIR) -name 'Makefile-deps')
OBJS_FILES := $(shell find $(SRCDIR) -name 'Makefile-objs')
which are all dependency and objective files. These are found in each subfolder containing some source code.
Then, I am trying to do following. (The target deps seems to work as when I comment out the compilation rule it does create the deps and objs file correctly in each folder.)
code: create_dir deps scripts
#make -j $(CORES) $(NAMEEXE)
$(NAMEEXE): $(LIBRARY) $(OBJS)
#$(F90) $(FFLAGS) $(OPTIONS) -o $(OBJDIR)/$(MAIN).o main/$(MAIN).f90
#$(F90) -o $(NAMEEXE) $(LOPTIONS) $(OBJS) $(LIBRARY) && \
deps:
${AUTOGEN} -d $(AUTOGEN_COMMAND) -f ${AUTOCONF} ; \
$(SEDI) -e "s/[(][^)]*[)]/\$$(OBJDIR)/g" $(OBJS_FILES) ; \
$(SEDI) -e "s/[(][^)]*[)]\(.*\)\.o/\$$(OBJDIR)\1\.o/g"
$(DEPS_FILES) ; \
$(OBJDIR)/%.o: $(SOURCE_FILES_f:.f90=.o) Makefile
#$(F90) $(FFLAGS) $(POPTIONS) -o $# $< && \
( mv -f *.mod $(OBJDIR) > /dev/null 2>&1;
$(OBJDIR)/%.o: $(SOURCE_FILES_c:.c=.o) Makefile
#$(F90) $(FFLAGS) $(POPTIONS) -o $# $< && \
( mv -f *.mod $(OBJDIR) > /dev/null 2>&1;
%.o: $(SOURCE_FILES_c:.c=.o) Makefile
#make $(OBJDIR)/$#
%.o: $(SOURCE_FILES_c:.c=.f90) Makefile
#make $(OBJDIR)/$#
I am including the deps and objs by this command
-include $(DEPS_FILES)
-include $(OBJS_FILES)
I obviously did not want put the entire makefile here, but if something is missing before you can understand what's going on please let me know.
When I type make the error I get is that my $(main) source file cannot open the compiled module file which is included in the main source.
This is because it is not compiled, but this also means that my dependency file is not working as intended?
When I look into my corresponding dep file which includes the main file, I can see that the dependency modules are added to the source file
For my master thesis, I am developing a tool to test and evaluate a formula for multipath networks.
I will be using the traceroute tool to trace the network between two multihomed hosts by passing to it -s flag, src IP and dst IP. I have multiple source and dest IPs. So the traceroute will be performed multiple times.
I am not good with compilation stuff. The downloaded code for traceroute-2.1.0 from the website https://sourceforge.net/projects/traceroute/files/traceroute/ has following "make" related files.
Makefile
make.defines
make.rules
default.rules
I have applied my changes to the code in traceroute.c, and I can compile it properly by "make" and "make install". But these changes are made to the traceroute tool for the system(obviously).
What I want to achieve is, to have it with a new name, for example "mytrace" instead of "traceroute". So it doesnt come in conflict with the traceroute tool and I could use both tools. Calling with "traceroute" and other with "mytrace" in cmd line.
Question is: What changes I must make before recompiling, in order to achieve it.
Here is the code of the file "makefile".
# Global Makefile.
# Global rules, targets etc.
#
# See Make.defines for specific configs.
#
srcdir = $(CURDIR)
override TARGET := .MAIN
dummy: all
include ./Make.rules
targets = $(EXEDIRS) $(LIBDIRS) $(MODDIRS)
# be happy, easy, perfomancy...
.PHONY: $(subdirs) dummy all force
.PHONY: depend indent clean distclean libclean release store libs mods
allprereq := $(EXEDIRS)
ifneq ($(LIBDIRS),)
libs: $(LIBDIRS)
ifneq ($(EXEDIRS),)
$(EXEDIRS): libs
else
allprereq += libs
endif
endif
ifneq ($(MODDIRS),)
mods: $(MODDIRS)
ifneq ($(MODUSERS),)
$(MODUSERS): mods
else
allprereq += mods
endif
ifneq ($(LIBDIRS),)
$(MODDIRS): libs
endif
endif
all: $(allprereq)
depend install: $(allprereq)
$(foreach goal,$(filter install-%,$(MAKECMDGOALS)),\
$(eval $(goal): $(patsubst install-%,%,$(goal))))
what = all
depend: what = depend
install install-%: what = install
ifneq ($(share),)
$(share): shared = yes
endif
ifneq ($(noshare),)
$(noshare): shared =
endif
$(targets): mkfile = $(if $(wildcard $#/Makefile),,-f
$(srcdir)/default.rules)
$(targets): force
#$(MAKE) $(mkfile) -C $# $(what) TARGET=$#
force:
indent:
find . -type f -name "*.[ch]" -print -exec $(INDENT) {} \;
clean:
rm -f $(foreach exe, $(EXEDIRS), ./$(exe)/$(exe)) nohup.out
rm -f `find . \( -name "*.[oa]" -o -name "*.[ls]o" \
-o -name core -o -name "core.[0-9]*" -o -name a.out \) -print`
distclean: clean
rm -f `find $(foreach dir, $(subdirs), $(dir)/.) \
\( -name "*.[oa]" -o -name "*.[ls]o" \
-o -name core -o -name "core.[0-9]*" -o -name a.out \
-o -name .depend -o -name "_*" -o -name ".cross:*" \) \
-print`
libclean:
rm -f $(foreach lib, $(LIBDIRS), ./$(lib)/$(lib).a ./$(lib)/$(lib).so)
# Rules to make whole-distributive operations.
#
STORE_DIR = $(HOME)/pub
release release1 release2 release3:
#./chvers.sh $#
#$(MAKE) store
store: distclean
#./store.sh $(NAME) $(STORE_DIR)
I wrote to the programmer of the tool, his solution worked for me. Here it is:
Just rename the sub-directory "traceroute" to another name, say "mytrace".
IOW, you'll have "include, libsupp, mytrace" instead of "include, libsupp, traceroute".
Additionally, if you plan to create a tarball with the changed name etc., it seems that you have to rename "NAME = traceroute" to "NAME = mytrace" in the Make.defines file.
Best regards,
Dmitry Butskoy
I just came across this makefile, and it's confusing to me:
PROJECT_ROOT = ../..
LIBDIR = $(PROJECT_ROOT)/src/lib
INCDIR = $(PROJECT_ROOT)/include
SRCS = proj_start.c function1.c
LIBS = $(LIBDIR)/libtest.a
OBJS = $(SRCS:.c=.o)
PROJECT = project1
FLAGS = -I$(INCDIR)
CC = gcc $(FLAGS)
.c.o:
$(CC) -c $<
$(PROJECT): $(OBJS)
$(CC) $(OBJS) $(LIBS) -o $#
it: $(PROJECT)
clean:
rm -f $(OBJS) $(PROJECT)
depend: $(SRCS)
$(CC) -M $(SRCS) > dependList
sed -e '1,/^# DO NOT DELETE/!d' Makefile > make.tmp
cat dependList >> make.tmp
mv make.tmp Makefile
rm dependList
# DO NOT DELETE THIS LINE
These are the parts that confuse me:
LIBDIR = $(PROJECT_ROOT)/src/lib
Why is LIBDIR in the root/src/lib library?
Shouldn't it be the root/lib directory (both directories are present in the file hierarchy)?
.c.o:
$(CC) -c $<
What the heck does this do? The "$<" evaluates to .c.o? I see that it is a 'suffix rule' but what are they really used for?
depend: $(SRCS)
$(CC) -M $(SRCS) > dependList
sed -e '1,/^# DO NOT DELETE/!d' Makefile > make.tmp
cat dependList >> make.tmp
mv make.tmp Makefile
rm dependList
# DO NOT DELETE THIS LINE
Why do we need this part? It seems all the dependencies have already been handled...?
Yeah, putting lib/ under src/ looks like a bad, counterintuitive design.
This:
.c.o:
...
is the old way of writing an implicit rule. These days we'd write it like this:
%.o: %.c
...
It's a slightly Rube Goldberg (i.r. clever but over-complicated) way of doing automatic dependency handling. So if foo.c contains the line #include bar.h, this rule will append the line foo.o: bar.h to the makefile. This is actually important.
I'm trying to learn how to use linux makefiles.
I have the following two files:
makefile.config
# Project Configurations
# Project Name
PROJECT_NAME = myapp
# Project Version
PROJECT_VERSION = 0.1
# Program or Shared Library
IS_LIBRARY = no
# Source Files Directory
SRC_DIRECTORY = src
# Header Files Directory
INC_DIRECTORY = inc
# Library Header Files Directory
LIB_DIRECTORY = lib
# Build Output Directory
BIN_DIRECTORY = ../Executable
# Installation Directory Exec
INS_DIRECTORY = /usr/local/bin/
# Installation Directory Headers
INS_HEARERS_DIRECTORY = /usr/local/include/
# Installation Directory SO
INS_SO_DIRECTORY = /usr/local/lib/
# C Flags
CFLAGS = -O3 -D_GNU_SOURCE -Wfatal-errors
# C++ Flags
CXXFLAGS = $(CFLAGS)
# Linker Flags
LDFLAGS = $(shell dpkg-buildflags --get LDFLAGS)
# Linker Libraries
LDLIBS = -fno-inline
# Debug Yes / No
DEBUG = yes
# C Compiler
CC = gcc
# C++ Compiler
CXX = g++
Makefile
$(info Starting building process)
# include configurations
include makefile.conf
$(info - Makefile.conf loaded)
# find project files
H_FILES := $(shell find -L ./ -name '*.h' -exec dirname {} \; | sed 's/ /\\ /g' | uniq)
C_FILES := $(shell find ./ -name '*.c' -type f | sed 's/ /\\ /g' | uniq)
CXX_FILES := $(shell find ./ -name '*.cpp' -type f | sed 's/ /\\ /g' | uniq)
O_FILES := $(C_FILES:.c=.o)
O_FILES += $(CXX_FILES:.cpp=.o)
H_FILES := $(notdir $(H_FILES))
C_FILES := $(notdir $(C_FILES))
CXX_FILES := $(notdir $(CXX_FILES))
INCLUDES := $(H_FILES:%=-I%)
$(info - Project Files Loaded)
ifeq ($(DEBUG),yes)
$(info - Debug flag added [makefile.conf DEBUG = yes])
CFLAGS := -g3 $(CFLAGS)
endif
ifeq ($(IS_LIBRARY),yes)
$(info - Set Parameters for Shared Library build process)
ALL_PARAMETERS = lib$(PROJECT_NAME).so.$(PROJECT_VERSION) clean
ALL_TYPE = lib$(PROJECT_NAME).so.$(PROJECT_VERSION): $(O_FILES)
LIBFLAGS = -shared -Wl,-soname,lib$(PROJECT_NAME).so
CFLAGS := -fPIC $(CFLAGS)
CXXFLAGS := -fPIC $(CXXFLAGS)
else
$(info - Set Parameters for Application build process)
ALL_PARAMETERS = $(PROJECT_NAME) clean
ALL_TYPE = $(PROJECT_NAME): $(O_FILES)
LIBFLAGS =
endif
# Build Process
all: $(ALL_PARAMETERS)
$(ALL_TYPE)
#echo - [OUTPUT][CXX] $# #[$(BIN_DIRECTORY)]
#$(CXX) $(CFLAGS) $(INCLUDES) $(LDFLAGS) $(LIBFLAGS) -o $(BIN_DIRECTORY)/$# $^ $(LDLIBS)
%.o: %.c
#echo - [CC] $#
#$(CC) $(CFLAGS) -c $(INCLUDES) -o $# $< $(LFLAGS)
%.o: %.cpp
#echo - [CXX] $#
#$(CXX) $(CXXFLAGS) -c $(INCLUDES) -o $# $< $(LFLAGS)
# Clear Objects
clean:
$(info - Remove all .o [object] files)
#find . -name \*.o -type f -delete
# Clear Objects & Executables
cleanall:
$(info - Remove all .o [object] files)
#find . -name \*.o -type f -delete
$(info - Remove all files in $(BIN_DIRECTORY))
#find $(BIN_DIRECTORY) -name \*.* -type f -delete
# Install Project
install:
#cp -r $(BIN_DIRECTORY)/lib$(PROJECT_NAME).so.$(PROJECT_VERSION) $(INS_SO_DIRECTORY)
#cp -r $(LIB_DIRECTORY)/* $(INS_HEARERS_DIRECTORY)
#ln -s $(INS_SO_DIRECTORY)/lib$(PROJECT_NAME).so.$(PROJECT_VERSION) $(INS_SO_DIRECTORY)/lib$(PROJECT_NAME).so
#ldconfig
$(info - Installation completed)
# Uninstall Project
uninstall:
#rm $(INS_SO_DIRECTORY)/lib$(PROJECT_NAME).so
#rm $(INS_SO_DIRECTORY)/lib$(PROJECT_NAME).so.*.*
#rm $(INS_HEARERS_DIRECTORY)/$(PROJECT_NAME).h
#ldconfig
$(info - Uninstallation completed)
Everything works perfect ...well at least for what i'm using it for.. however when i try to execute the makefile with -j option (ex.)
$ make -j4
the procedure cleans the objects (.o) before linking them.
iikem#isca-lab:Source Code$ make -j4
Starting building process
- Makefile.conf loaded
- Project Files Loaded
- Debug flag added [makefile.conf DEBUG = yes]
- Set Parameters for Shared Library build process
- [CXX] src/isca-streamer.o
- [CXX] src/isca-streamer-pause.o
- [CXX] src/isca-streamer-thread-image.o
- [CXX] src/isca-streamer-initialize.o
- [CXX] src/isca-streamer-start.o
- [CXX] src/isca-streamer-stop.o
- [CXX] src/isca-streamer-thread-socket.o
- [CXX] src/isca-streamer-clear.o
- Remove all .o [object] files
- [CXX] src/isca-streamer-settings.o
- [OUTPUT][CXX] libisca-streamer.so.0.1 #[../Executable]
g++: error: src/isca-streamer.o: No such file or directory
g++: error: src/isca-streamer-initialize.o: No such file or directory
g++: error: src/isca-streamer-thread-image.o: No such file or directory
g++: error: src/isca-streamer-pause.o: No such file or directory
g++: error: src/isca-streamer-start.o: No such file or directory
g++: error: src/isca-streamer-stop.o: No such file or directory
Makefile:71: recipe for target 'libisca-streamer.so.0.1' failed
make: *** [libisca-streamer.so.0.1] Error 1
How can i fix this problem? (prevent cleaning objects step to execute before linking step)
You can't add clean as a prerequisite for your all target if you use -j, because it will be run in parallel with the linker and deleting files is a lot faster than linking them.
So you have to remove the clean target from your ALL_PARAMETERS variable, then you won't delete objects in the middle of your link line anymore.
I have no idea why you want to delete all the objects after every run: you don't even need make or makefiles at all if you're going to rebuild everything from scratch every time: just create a shell script. The entire point of using a makefile is to avoid rebuilding parts of the project that haven't changed.
But, if you really do want to do that then the simplest way is probably using recursive make; for example:
all: $(ALL_PARAMETERS)
$(MAKE) clean
will only ever make clean after all the prerequisites of all have completely built, even if you run with -j.
I am a bit a beginner in using makefiles and I am trying to write a makefile for gcc that accepts the inputs from two different directories (in my case they are called kernel and drivers) and output the object files in a different directory (called tmp) using wildcards.
I have written this code to get the names of input files and output files
C_SOURCES = $(wildcard $(KERNEL_DIR)/*.c $(DRIVERS_DIR)/*.c)
#Creating a list for object files names
C_OBJ = $(C_SOURCES:.c=.o)
and I am using the following rule
%.o: %.c $(CC) $(CFLAGS) -c $< -o $#
but i can't get to output the object files in the desired directory.files
Something like this example should do it for you. I split things up a bit for readability, but I'm sure you'll get the idea:
KERNEL_SOURCES = $(wildcard $(KERNEL_DIR)/*.c)
DRIVER_SOURCES = $(wildcard $(DRIVER_DIR)/*.c)
OBJECTS = $(patsubst $(KERNEL_DIR)/%.c,tmp/%.o,$(KERNEL_SOURCES))
OBJECTS += $(patsubst $(DRIVER_DIR)/%.c,tmp/%.o,$(DRIVER_SOURCES))
Watch out for source files with the same name in both KERNEL_DIR and DRIVER_DIR!
You have to make a separate rule for each subdirectory, like this:
SOURCES := $(wildcard $(KERNEL_DIR)/*.c $(DRIVER_DIR)/*.c)
OBJECTS := $(patsubst %.c,$(OBJECT_DIR)/%.o,$(notdir $(SOURCES)))
all: $(OBJECTS)
$(OBJECT_DIR)/%.o : $(KERNEL_DIR)/%.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $# $<
$(OBJECT_DIR)/%.o : $(DRIVER_DIR)/%.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $# $<
Obviously you'll have big problems if you have a foo.c file in both source directories...