How is this complex generic Makefile rule constructed - gcc

Several modules each are tested independently with their own test_$(MODULE).c.
A shared library has been generated $(LIBRARY) containing modules without coverage. $(basename $<).o should override the one in $(LIBRARY). For some reason, I get results as if they are not overridden. Can someone review this and make suggestions on fixes? Currently I have non-generic gcov rules for each of the five objects. These gcovs work correctly. Below I show the generic rule and one specific use of the rule.
SHARED_OPTS=-O0 -Wall -Wextra -fPIC
GOPTS=$(SHARED_OPTS) -g -coverage -pg
%.gcov : %
#echo "\t$# generic (needs work)"
#-gcc $(GOPTS) -c -o test_$(basename $<).o test_$<
#-gcc $(GOPTS) -c -o $(basename $<).o $<
#-gcc $(GOPTS) -o gcov_test_$(basename $<) \
test_$(basename $<).o \
$(basename $<).o \
-L . -l $(LIBRARY)
#-./gcov_test_$(basename $<)
#-gcov $< >$#.out 2>&1
#echo "no Mac gprof: -gprof gcov_test_$(basename $<) gmon.out > $<.prof"
#$(call timestamp,$#)
Unicode.c.gcov: Unicode.c
If anyone is interested in collaborating on high efficiency high quality Unicode lexing/parsing support by developing a shared library, I would love to have reviewers or contributors.
The Makefile fragment shown above is in a github repository:
https://github.com/jlettvin/Unicode Specifically down the c subdirectory.

While you're trying to find problems in your makefile you should avoid using #, as it hides the command line and so you can't see issues. Also you should avoid - here: if any of those commands fail you certainly don't want to continue to run the rest of the recipe, I wouldn't expect.
I don't know if it's a cut/paste problem but I have to assume that these lines, at least, are wrong:
#-gcc $(GOPTS) -c -o test_$(basename $<).o test_$<
#-gcc $(GOPTS) -c -o $(basename $<).o $<
As far as I can tell from your makefile, the last words on these lines should be test_$<.c and $<.c respectively.

Related

problems with kernel not being loaded

I'm creating an OS and when I compile the code nothing happened, simply nothing(No errors, warnings or anything) I"m thinking that the make file has some issues.
Makefile:
build_kernel:
echo "Building kernel..."
${ASM} ./src/kernel/kernel_entry.asm -f elf64 -o ${BUILD_DIR}/kernel_entry.o
${C_COMPILER} -c ./src/kernel/kernel.c -o ${BUILD_DIR}/kernel_start.o
${C_COMPILER} -c ./src/kernel/drivers/printutils.c -o ${BUILD_DIR}/kernel_printutils.o
${C_COMPILER} -c ./src/kernel/drivers/port.c -o ${BUILD_DIR}/kernel_ports.o
echo "kernel build complete."
link:
echo "Linking..."
${LINKER} -o ${BUILD_DIR}/kernel.bin ${BUILD_DIR}/kernel_ports.o \
${BUILD_DIR}/kernel_printutils.o ${BUILD_DIR}/kernel_start.o \
${BUILD_DIR}/kernel_entry.o -Ttext 0x1000 --oformat binary
echo "Linking complete"
run:
echo "Running qemu..."
qemu-system-x86_64 -fda ${BUILD_DIR}/os.bin
merge_binary:
echo "Merging binary..."
cat ${BUILD_DIR}/boot.bin ${BUILD_DIR}/kernel.bin > ${BUILD_DIR}/os.bin
echo "Binary merged."
post_build:
rm -f ${BUILD_DIR}/boot.bin
rm -f ${BUILD_DIR}/kernel.bin
rm -f ${BUILD_DIR}/kernel.o
rm -f ${BUILD_DIR}/kernel_entry.o
rm -f ${BUILD_DIR}/kernel_ports.o
rm -f ${BUILD_DIR}/kernel_printutils.o
rm -f ${BUILD_DIR}/kernel_start.o
I'm wondering what is happening with the makefile and is this the correct way to compile all the code into object files and link them.
Any help will be appreciated.
I'm just commenting on your make style -- this does not answer why you are outputting nothing (and it is unclear what you mean by that -- if you run make, it should output at least echo "Building kernel..."...). As far as the makefile style goes, this seems to be built using a scripting mentality rather than a make mentality. Consider your first part:
build_kernel:
echo "Building kernel..."
${ASM} ./src/kernel/kernel_entry.asm -f elf64 -o ${BUILD_DIR}/kernel_entry.o
${C_COMPILER} -c ./src/kernel/kernel.c -o ${BUILD_DIR}/kernel_start.o
${C_COMPILER} -c ./src/kernel/drivers/printutils.c -o ${BUILD_DIR}/kernel_printutils.o
${C_COMPILER} -c ./src/kernel/drivers/port.c -o ${BUILD_DIR}/kernel_ports.o
echo "kernel build complete."
This has several issues. First is the name -- this looks to build a bunch of artifacts rather than building the kernel. Also, the recipe never produces a file named build_kernel, thus this should have been a phony target. Next, this is actually a script, which builds four separate things. These could be separated out into four separate rules, each which builds one thing, and then the main target would be dependent on this. Thus, it might look like:
.PHONY: build_kernel_objs
build_kernel_objs: ${C_OBJS} ${ASM_OBJS}
#echo done building $#
${BUILD_DIR}/kernel_start.o : ./src/kernel/kernel.c
${C_COMPILER} -c $< -o $#
${BUILD_DIR}/kernel_printutils.o : ./src/kernel/kernel_printutils.c
${C_COMPILER} -c $< -o $#
${BUILD_DIR}/kernel_ports.o : ./src/kernel/kernel_ports.c
${C_COMPILER} -c $< -o $#
Note that the above is repetitive, and if you have hundreds of files, will bolat very quickly. This can also be done using static pattern rules:
C_FILES := \
./src/kernel/kernel_start.c
./src/kernel/kernel_printutils.c
./src/kernel/kernel_ports.c
ASM_FILES := \
./src/kernel/kernel_entry.asm
C_OBJS := ${C_FILES :./src/kernel/%.c=${BUILD_DIR}/%.o}
ASM_OBJS := ${ASM_FILES :./src/kernel/%.asm=${BUILD_DIR}/%.o}
${C_OBJS} : ${BUILD_DIR}/%.o : ./src/kernel/%.c
${C_COMPILER} -c $< $#
.PHONY: build_kernel_objs
build_kernel_objs: ${C_OBJS} ${ASM_OBJS}
#echo "done building $#"
These have several advantages over what you've done -- first, make will only ever build the objects that are out of date, so it doesn't do needless work. It can also build the files in parallel if a -j option is specified on the make command line. Next, it's more maintainable -- if you have to add extra files, you can do it in one place, and everything works out. Also, the .PHONY prevents the make from failing if you happen to have a file named build_kernel_objs in your make directory. Lastly, the # in front of the echo lines prevents the actual echo command from being echoed, which will look nicer.
On caveat to this is that it does not handle modification of header files (as written, if a header file is updated, c files that depend on it would not be rebuilt. See here for some notes about getting around that.
The next section, link, the makefile recipe should reflect the target.
.PHONY: link
link : ${BUILD_DIR}/kernel.bin
${BUILD_DIR}/kernel.bin: ${C_OBJS} ${ASM_OBJS}
${LINKER} -o $# $^ -Ttext 0x1000 --oformat binary
This creates a phony target link, so you can type make link. It will only do the link if any of the C objects or ASM objects have been updated. The same concept applies to your merge_binary target
For run, this seems to be somewhat contentious, but a common rule of thumb is that a make should be used to make an executable, not to run it. A separate shell script is better suited if you want to invoke your built target with specific parameters.
Lastly, your post_build rule should likely be renamed to CLEAN, and declared as a phony.

Why does f77 -f fail and what should it do?

I am trying to run some old Fortran code of my project team in ubuntu 16.04. I have not done any modifications to the existing code.
All I have done is installed gfortran, opened a terminal, and went to the file location using "cd" command. Here I have many files, but just consider this three, a script file compile.sh, and two makefiles counter.make and remail.make.
In compile.sh
make -f counter.make
make -f remail.make
In counter.make
SOURCE_APPLI=../SOURCES_COUNTERFLOW/
SOURCES_f77 = $(SOURCE_APPLI)table.f
TARGET = unst.e
OBJECTS = $(SOURCES_f77:.f=.o)
COMPILE = f77 -f
.f90.o :
$(COMPILE1) -o $*.o -c $*.f90
.f.o :
$(COMPILE) -o $*.o -c $*.f
$(TARGET) : $(OBJECTS)
$(COMPILE) $(OBJECTS) -o $#
del :
$(DELETE) $(OBJECTS)
In remail.make
SOURCE_APPLI= ../SOURCES_COUNTERFLOW/
$(SOURCE_APPLI)grcom.f
TARGET = remail.e
OBJECTS = $(SOURCES_f77:.f=.o)
COMPILE = f90
.f90.o :
$(COMPILE) -o $*.o -c $*.f90
.f.o :
$(COMPILE) -o $*.o -c $*.f
$(TARGET) : $(OBJECTS)
$(COMPILE) $(OBJECTS) -o $#
del :
$(DELETE) $(OBJECTS)
When I run compile.sh, I got an error as shown below
f77: error: unrecognized command line option ‘-f’
counter.make:29: recipe for target 'unst.e' failed
make: *** [unst.e] Error 1
make: 'remail.e' is up to date.
So my question is what is the difference with and without using -f option in the f77 command line?
The f77 manual page at https://www.unix.com/man-page/v7/1/f77/ says
-f Use a floating point interpreter
(for PDP11's that lack 11/70-style floating point).
If you are not on a PDP-11, it appears that this option would perhaps not be useful at all in the first place.
Probably still review the local documentation, ideally for the system where this set of Makefiles was once created.
GNU Fortran 77 appears to use this option to specify various language options, but then it would not be useful on its own (it takes arguments like -fdollar-ok to enable something called "dollar ok", for example. See the linked manual for an extensive list of these options and their meaning).

makefile skips making the build directory

I want all my build files stored in a build directory inside the project root folder. Though, I don't want to have to rebuild all of the files if I add a debug flag. Thus, I have two directories .build_release and .build_debug. Then I make a symbolic link from build to the proper directory.
I want all of this to be handled by make. Here is my makefile:
## setup
ifdef DEBUG
BUILDDIR=.build_debug
else
BUILDDIR=.build_release
endif
BLACKLIST:=bayesP obsDataStats test3 test bayesPsamplesBR test2 tuneSp \
toyFeatures2Multi getCov getDist isConnected mergeClusters sample \
toyFeatures0 toyFeatures1 toyFeatures2 toyFeatures3 toyFeatures4 \
toyFeatures6 toyFeatures7 wnsFeatures0 wnsFeatures1 wnsFeatures2
## make code
PROGS:=$(shell find ./src/ -maxdepth 1 -name "*.cpp" -exec grep -l "int main" {} \;)
PROGS:=$(notdir $(basename $(PROGS)))
PROGS:=$(filter-out $(BLACKLIST),$(PROGS))
CPP_SRC:=$(wildcard src/*.cpp)
CPP_SRC:=$(notdir $(basename $(CPP_SRC)))
CPP_SRC:=$(filter-out $(PROGS) $(BLACKLIST),$(CPP_SRC))
PROGS:=$(PROGS:=.bin)
PROGS:=$(PROGS:%=$(BUILDDIR)/%)
CPP_SRC:=$(CPP_SRC:%=src/%.cpp)
CPP_OBJ:=$(CPP_SRC:src/%.cpp=$(BUILDDIR)/%.o)
LIB=$(BUILDDIR)/libspatialDecisionMaking.so
## test code
CPP_SRC_TEST:=$(wildcard src/test/*.cpp)
CPP_SRC_TEST:=$(notdir $(basename $(CPP_SRC_TEST)))
CPP_SRC_TEST:=$(filter-out $(BLACKLIST),$(CPP_SRC_TEST))
PROGS_TEST:=$(CPP_SRC_TEST:%=$(BUILDDIR)/test/%.bin)
CPP_OBJ_TEST:=$(CPP_SRC_TEST:%=$(BUILDDIR)/test/%.o)
CPP_SRC_TEST:=$(CPP_SRC_TEST:%=src/test/%)
## options
CC=g++-4.9
ifdef DEBUG
CPP_FLAGS=-std=c++11 -ggdb
else
CPP_FLAGS=-std=c++11 -O3
endif
LD_FLAGS=-Isrc -L$(BUILDDIR) -lgsl -larmadillo -fPIC -fopenmp
## rules
all: | $(BUILDDIR) $(LIB) $(PROGS) build
test: | $(BUILDDIR)/test $(LIB) $(PROGS_TEST) build
build: $(BUILDDIR)
ln -rfs $(BUILDDIR) build
$(BUILDDIR)/test: $(BUILDDIR)
mkdir $(BUILDDIR)/test
$(BUILDDIR):
mkdir $(BUILDDIR)
$(BUILDDIR)/%.bin: src/%.cpp $(LIB)
$(CC) $(CPP_FLAGS) -o $# $< $(LD_FLAGS) -l$(LIB:$(BUILDDIR)/lib%.so=%)
ln -rfs $# $(#:%.bin=%)
$(LIB): $(CPP_OBJ)
$(CC) $(CPP_FLAGS) -o $# $^ $(LD_FLAGS) -shared
$(BUILDDIR)/%.o: src/%.cpp $(BUILDDIR)/%.d
$(CC) $(CPP_FLAGS) -c $< -o $# $(LD_FLAGS)
$(BUILDDIR)/%.d: src/%.cpp
$(CC) $(CPP_FLAGS) -MM $< -MT $(#:%.d=%.o) > $# $(LD_FLAGS)
%.cpp:
%.hpp:
# include dependencies
-include $(CPP_OBJ:%.o=%.d)
clean:
rm -rf $(BUILDDIR)
Though, it seems to skip making $(BUILDDIR). I delete the directories before I run make every time and it goes directly to building the dependency makefiles based on the rules for target $(BUILDDIR)/%.d. However, it naturally complains when trying to build the dependencies because $(BUILDDIR) doesn't exist.
Any ideas why it would be skipping the recipe for making $(BUILDDIR)?
As I have one more question on SO than answers, so I had to find a question to answer :) , and you seemed to not like the answer that was already there, so OK, even though your question was not "minimal", I spent an hour to work on it.
Your Makefile is not bad generally, but it does not follow a number of "good practices". Once I tidied everything up, all the problems disappeared. I hope it helps you to learn from this example - how I changed your original makefile to follow good practices.
The only little problem left, is that build is always relinked every time. This is because normally Make does not "depend" on variable values (such as DEBUG), only on files. It is possible to fix that (in this small case it does not matter much, but maybe later you will need this solution), by creating "dependable variables". See my answer at
How do I force a target to be rebuilt if a variable is set?
Below is the complete working makefile, I put comments on changes outside the code.
## setup
use := when you can
ifdef DEBUG
BUILDDIR:=.build_debug
else
BUILDDIR:=.build_release
endif
do not use find to list files, better declare files explicitly
PROGS:=\
prog0 \
prog1 \
CPP_SRC:=\
spam \
eggs \
CPP_SRC_TEST:=\
spam_test \
eggs_test \
split off link targets, so only the target is created in a rule:
PROG_LINKS:=$(addprefix $(BUILDDIR)/, $(PROGS))
PROGS:=$(PROGS:=.bin)
PROGS:=$(PROGS:%=$(BUILDDIR)/%)
CPP_SRC:=$(CPP_SRC:%=src/%.cpp)
CPP_OBJ:=$(CPP_SRC:src/%.cpp=$(BUILDDIR)/%.o)
LIB:=$(BUILDDIR)/libspatialDecisionMaking.so
PROGS_TEST:=$(CPP_SRC_TEST:%=$(BUILDDIR)/test/%.bin)
PROGS_TEST_LINKS:=$(addprefix $(BUILDDIR)/test, $(CPP_SRC_TEST))
## options
CC=g++-4.9
you are confusing CPP_FLAGS and LD_FLAGS, I put correct flags in each
also, your method of finding your shared library, is too complicated, I made it simple
CPP_FLAGS:= -std=c++11 -Isrc -fPIC -fopenmp
ifdef DEBUG
CPP_FLAGS+= -ggdb
else
CPP_FLAGS+= -O3
endif
LD_FLAGS:= -L$(BUILDDIR) -lgsl -larmadillo
## rules
you have too many dependencies - list only those that are conceptually needed for the target at hand, and recurse
all: | $(PROGS) $(PROG_LINKS) build
test: | $(PROGS_TEST) $(PROGS_TEST_LINKS) build
link file does not depend on the link target in any way
in your case, it depends on the value of DEBUG really, but like I said above, it is not super-easy to implement that, so I skipped it here and have a phony instead, which relinks all the time
.PHONY: build
build:
ln -srf $(BUILDDIR) $#
this is the best way to handle directory creation
%/.:
mkdir -p $(#D)
unfortunately, this is needed, because mkdir -p is not re-entrant and subject to race conditions
$(BUILDDIR)/test/.: | $(BUILDDIR)/.
.SECONDEXPANSION:
$(PROGS_TEST_LINKS) $(PROG_LINKS): %: | %.bin
ln -sr $| $#
all non-trivial recipes should depend on this makefile, change Makefile to whatever is correct (there is a more complicated way, to handle this automatically)
$(BUILDDIR)/%.bin: src/%.cpp $(LIB) Makefile | $$(#D)/.
$(CC) $(CPP_FLAGS) -o $# $< $(LD_FLAGS) $(LIB)
$(LIB): $(CPP_OBJ) Makefile | $$(#D)/.
$(CC) $(CPP_FLAGS) -o $# $(CPP_OBJ) $(LD_FLAGS) -shared
this is the most efficient way to handle "automatic" dependency generation - it invokes the preprocessor only once, not twice as in your original makefile
I put this in quotes, because the whole method of automatic dependencies, is subtly flawed and cannot work in all cases - but in your simple case it is very unlikely you will run into that subtle flaw
Yes I am violating the good practice I mentioned above - only target created in rule. If one understands what a good practice is for, and still thinks better to violate it, then OK.
$(BUILDDIR)/%.o: src/%.cpp Makefile | $$(#D)/.
$(CC) $(CPP_FLAGS) -MMD -MP -c $< -o $# $(LD_FLAGS)
# include dependencies
-include $(CPP_OBJ:%.o=%.d)
clean:
rm -rf $(BUILDDIR)
The .d, .o, and .bin files logically depend on $(BUILDDIR), so tell make that's the case
$(BUILDDIR)/%.d: src/%.cpp | $(BUILDDIR)

How to enable quiet build using automake?

Imagine the following target and command generated by autoconf:
.c.lo:
$(LTCOMPILE) -MT $# -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $# $<
$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
I'm looking for a way in Makefile.am to manipulate that command, knowing that the command is generated by autoconf and I don't know what it is. In theory, something like this:
if BUILD_QUIETLY
Q=#
endif
.c.lo:
$(Q)$(autoconf-command-for-c-lo)
Or something like this (this is similar to Linux kernel's build output):
quiet_cmd_cc = CC $#
cmd_cc = $(autoconf-command-for-c-o)
.c.o:
$(call cmd,cc)
Where cmd is a function that executes cmd_$1 and either prints quiet_cmd_$1 or cmd_$1 based on a variable.
I looked for this on the internet, but most of the websites talk about the basics of autoconf. There doesn't seem to be any questions related to this here either.
Is this even possible?
Per chirlu's comment, automake has an option to generate quiet output builds.
This page has the necessary instructions. In short, put the following in configure.ac:
AM_SILENT_RULES([yes])
To then disable it, either do:
make V=0
after configuration, or:
./configure --enable-silent-rules
on configuration.
You can always pipe the output to /dev/null:
./configure 2>&1 >/dev/null
make 2>&1 >/dev/null

Makefile variable being ignored

I have the following makefile which is a slight modification on others that I have used in the past. There is an odd issue though with my variable ${CXXOPTS} not being used in the .c.o makefile rule. When I execute the makefile, this is what is executed g++ -c -o SeqPrep2.o SeqPrep2.cpp when I expect this to be executed: g++ -Iseqan-03-02-2012 -c -o SeqPrep2.o SeqPrep2.cpp. (Edit: I solved the problem but see my updated question below about why this makefile worked at all in the first place)
L=-lm -lz
SEQANINC=seqan-03-02-2012
DESTDIR=$(HOME)/
BINDIR=bin
CXXOPTS=-I${SEQANINC}
CXX=g++
A=SeqPrep2
USEROPTS=
O=$(patsubst %.cpp,%.o,$(wildcard *.cpp))
SOURCES=$(wildcard *.cpp)
all: ${A} ${O} ${SOURCES}
install: ${O} ${MYLIBS} ${SOURCES}
${CXX} ${USEROPTS} -o ${DESTDIR}${BINDIR}/${A} ${O} ${L}
${A}: ${O} ${MYLIBS} ${SOURCES}
${CXX} ${USEROPTS} -o ${A} ${O} ${L}
clean::
rm -f ${A} ${O}
.c.o:
${CXX} ${CXXOPTS} ${USEROPTS} -c $< -o $#
check-syntax:
${CXX} ${CXXOPTS} ${USEROPTS} -c -o .nul -S ${CHK_SOURCES}
UPDATE:
I changed .c.o to .cpp.o. Is this a case of gnu make guessing that when I asked for a .o file in one of my rules, that it should make it just by running g++ -c -o SeqPrep2.o SeqPrep2.cpp even though I didn't tell it to do that? I guess that is my new question, why did the above makefile work at all, and why did it have the odd behavior I observed. One thing to note is that even though it didn't come though in the formatting, there is a lot of white space between the g++ and the -c, kind of like it was trying to put in my variables, but it didn't. That is partially what originally lead me to believe that it was seeing my rule at all, even though it seems like it didn't now. Thanks for helping me understand how this stuff works.
You've got the rule .c.o but you're compiling cpp files, when I use .cpp.o: it works great! With files: me.cpp us.cpp you.cpp
I get:
Building file me.cpp
g++ -Iseqan-03-02-2012 -c me.cpp -o me.o
Building file us.cpp
g++ -Iseqan-03-02-2012 -c us.cpp -o us.o
Building file you.cpp
g++ -Iseqan-03-02-2012 -c you.cpp -o you.o
g++ -o SeqPrep2 me.o us.o you.o -lm -lz

Resources