Including another Makefile results in a failed build, why? - makefile

Problem
Including an external Makefile makes my previously stable build fail with the following error :
make: *** No rule to make target 'build/main.o', needed by 'all'. Stop.
Context
The context is that I currently manage the build of each of my projects with one Makefile per project. Since the projects Makefiles have a lot of redundancy, I want to put the common things in an external Makefile that will be included in each project's Makefile.
Minimal example to reproduce the issue
In this simple and minimalist example I try to build srcs/main.c into build/main.o and I also try to display what is inside the variable FOO which in is tools.mk :
Folder structure :
| Makefile
|
+---build
| (main.o)
+---mkf
| tools.mk
|
\---srcs
main.c
Content of Makefile :
include ./mkf/tools.mk
mkfile_path :=$(realpath $(lastword $(MAKEFILE_LIST)))
current_dir :=$(dir $(mkfile_path))
VPATH = $(current_dir)/srcs
./build/%.o: %.c
#echo $< $#
gcc $< -o $#
all: ./build/main.o test
#echo Done !
test:
#echo Testing include : $(FOO)
.PHONY: all test
Content of tools.mk :
FOO = 42
Content of main.c (basic hello world) :
# include <stdio.h>
# include <stdlib.h>
int main(void)
{
printf("Hello, world!");
return EXIT_SUCCESS;
} /*main*/
Now basically my problem is that if I place myself in the root folder and type make all, the build will fail with the error mentioned above. However if I comment the line include ./mkf/tools.mk the build succeeds. Thus I guess it fails because of the include line, but I cannot figure out why.
Can someone enlighten me on this ?
The build is performed with GNU Make 4.2 on Windows 7 64-bits.

In
mkfile_path :=$(realpath $(lastword $(MAKEFILE_LIST)))
That yields the path of the last included makefile, which is ./mkf/tools.mk. See Other Special Variables for details.
A fix:
mkfile_path :=$(realpath $(lastword $(MAKEFILE_LIST)))
current_dir :=$(dir $(mkfile_path))
include ./mkf/tools.mk

Related

How to build a programs that's output will be used in a Make variable name

I want to create a Makefile which will build a program which when run's output will be used as a value for a variable in the same Makefile.
Consider the program:
print_name.c:
#include <stdio.h>
int main() {
printf("foo\n");
return 0;
}
I'd like to use the standard output of this program to then determine a directory name to be stored in a variable used in the makefile and used for other rules, so far I've tried:
all: $(MY_DIRECTORY_NAME)/my_program
print_name: print_name.c | print_name
gcc $^ -o $#
MY_DIRECTORY_NAME:=$(shell ./print_name)
$(MY_DIRECTORY_NAME)/my_program: my_program.c
mkdir -p $(MY_DIRECTORY_NAME)
gcc $^ -o $#
However when I run:
make all
I get:
make: *** No rule to make target '/my_program', needed by 'all'. Stop
Whereas I'd like:
mkdir -p foo
gcc my_program.c -o foo/my_program
So basically, I want to compile print_name before the assignment to MY_DIRECTORY_NAME, and then that variable in then used in the following rules. Is this possible, and if not are there any workarounds for this?
The basic problem is that you need to build (and run) print_name before you can parse the rules that use it -- but all rules are read and parsed before anything is built. So you need to run make twice -- first to build print_name and second to build everything that depends on it. Something like
all: print_name
$(MAKE) `./print_name`/my_program
should do the trick

makefile target-specific changing srcs files

I'm trying to write a Makefile with a rule to make the project with another main.cpp file, because I'm testing my code with different options
I have different versions of the main function, that I put inside differents files : main.cpp, main_1.cpp, main_2.cpp, ..., to test different versions of my code, and they all have the same dependencies
first I was just commenting and un-commenting the Makefile variable MAIN that define the main.cpp file, but I was hoping there is a way to choose the one I want to try with a specific rule ?
I tried something with target-specific variables but it didn't work :
# # # # # # #
# VARIABLES #
# # # # # # #
NAME = my_program
VPATH = srcs
CXX = c++
CXXFLAGS = -I ./headers
OBJS = $(SRCS:%.cpp=%.o)
MAIN = main.cpp
#MAIN = main_1.cpp
SRCS = $(MAIN) file.cpp
# # # # #
# RULES #
# # # # #
all: $(NAME)
# target-specific variables
test-1: MAIN = main_1.cpp
test-1: re
$(NAME) : $(OBJS)
$(CXX) $(OBJS) -o $(NAME)
clean:
rm -f $(OBJS)
fclean: clean
rm -f $(NAME)
re: fclean all
.PHONY : all clean fclean re
the error output for main test_1 is :
c++ -I ./headers -c -o main.o srcs/main.cpp
c++ -I ./headers -c -o file.o srcs/file.cpp
c++ main_1.o Webserv.o -o my_program
c++: error: main_1.o: No such file or directory
Makefile:21: recipe for target 'my_program' failed
make: *** [my_program] Error 1
I think, then, that target-specific is not the right tool for what I'm trying to do.
Does Make provide a way to accomplish that (modifying the list of srcs files when calling a specific rule, and having the compilation working great with the new srcs files) ?
I'm vaguely thinking something like this.
test-%: main_%.cpp file.cpp
Now, make test-1 will produce an executable with that name from main_1.cpp instead of main.cpp, and similarly test-2 from main_2.cpp, etc.
If you have subsequent targets which hardcode my_program which should actually depend on which version you made, this might not be suitable, or at a minimum, you'd have to refactor those to use the current output executable. Similarly, you might want to add test-[1-9] to the files to remove in the clean target (or perhaps add a realclean target to remove them too).
Tangentially, several of your make variables don't seem to serve any immediate purpose. Putting stuff in variables makes sense for things you want to be able to override at compile time, or vaguely for making a general-purpose Makefile which can be applied with only minor modifications across several projects; but in isolation, these seem like unnecessary complexities you should probably avoid for the time being.
Your immediate problem could perhaps be solved by refactoring the dependency chain, but on the whole, I'd recommend keeping it as simple as possible. make already knows how to compile common source formats; all you really need to put in the Makefile are the dependencies which are not trivially obvious and any .PHONY targets, and overrides to select e.g. a specific default action.

Defining path variable for a make file

In my assignment instructions, I was told to make a
Makefile without absolute directory names or derived binary files. Execution of make with no parameters should build the target program "wordpairs". Assume that the environment variable GET_WORD is defined as the pathname of a directory which contains directories "include" and "lib" containing getWord.h and libget.a
My directory for my code contains: pic
And my Makefile is:
#DIR := ${GET_WORD}
DIR := ${CURDIR}
Main : getWord.o crc64.o sTools.o hashingTools.o Main.c libget.a
gcc -g -o wordpairs Main.c getWord.o crc64.o sTools.o hashingTools.o $(DIR)/lib/libget.a
getWord.o : getWord.c getWord.h
cc -c $(DIR)/include/getWord.c $(DIR)/include/getWord.h
# cc -c getWord.c getWord.h
crc64.o : crc64.c crc64.h
cc -c crc64.c crc64.h
sTools.o : sTools.c sTools.h
cc -c sTools.c sTools.h
hashingTools.o : hashingTools.c hashingTools.h
cc -c hashingTools.c hashingTools.h
clean :
rm $(DIR)/include/*.h.gch
But when I run make, I get
make: *** No rule to make target 'getWord.c', needed by 'getWord.o'. Stop.
The files are in the folders include/lib.
I only understand the basic of make files, so can someone help me out how to achieve what I was assigned to do? What's causing this error?
(updated makefile code)
So apparently I just need to define GET_WORD variable where the grade can change it to a specific location. The thing is that apparently you cant call variables in the requirement file line (see how I didnt specific anything for getWord.o)
GET_WORD = /home/tam#change this!
wordpairs : Main.c crc64.o hashingTools.o sTools.o getWord.o
gcc -o wordpairs $^ -I ${GET_WORD}/include ${GET_WORD}/lib/libget.a
getWord.o :
cc -c ${GET_WORD}/include/getWord.c ${GET_WORD}/include/getWord.h
crc64.o : crc64.c crc64.h
cc -c $^
hashingTools.o : hashingTools.c hashingTools.h
cc -c $^
sTools.o : sTools.c sTools.h
cc -c $^
clean :
rm wordpairs crc64.o hashingTools.o sTools.o *.h.gch
#echo $(GET_WORD) ${GET_WORD}
getWord.o : getWord.c getWord.h looks for these files in the current directory.
You should apparently use GET_WORD to define a couple of additional variables, not redefine it to something else than what's given explicitly in the assignment.
If you figure out how to set INC to the include/ directory, your rule for these files should look something like
getWord.o : $(INC)/getWord.c $(INC)/getWord.h
cc -c $^
Notice how a dependency on a file in another directory must include the directory name; and how make won't actually look at how to make a new thing until the dependency resolution forces it to (and even then it doesn't know that a string in the command it runs is equal to one of the dependencies just because the strings are identical, let alone then when they are different, as in your attempt).
Notice also the use of $^ to say "the things in the dependencies". Generally, you want to avoid repeating information - if you change something, you don't want to change it in many places because it's easy to forget (see also DRY principle.)
... I don't think the professor wants the .c file in the include directory, actually, though; just the .h file would be my guess.
As a further aside, to have just make without arguments create a particular target, put it as the first target in your Makefile.
I hope this is sufficient to help you see how to solve your assigment!

Compile multiple executables from multiple source directories to single bin directory using makefile

I'm trying to create a makefile for a suite of programs that I am working on. The programs are all written in fortran and the source files are contained in different directories. I can't seem how to figure out how to get things to work. My current sumfile is
#Compiler and compiler flag variables
FCOMP=/usr/local/bin/gfortran
F_FLAGS=-O2 -fbounds-check -Wall
F_FLAGSDB=-g -fbounds-check -Wall
#paths to libraries
COMMON_LIB=/usr/local/lib/libspc_common.a
SPICE_LIB=/usr/local/lib/spicelib.a
# Paths to directories
BIN_DIR=BIN
# Get file names of component source files
#get names of files in src1
FORT_FILES=$(wildcard ./SRC1/*.f)
#get names of files in src2
FORTFILES+=$(wildcard ./SRC2/*.f)
#get names of files in src3
FORTFILES+=$(wildcard ./SRC3/*.f)
#get file names for output
EXE_FILES=$(addprefix $(BIN_DIR),$(notdir $(patsubst %.f, % , $(FORTFILES))))
# make commands
# Set the default option to compile the library with optimization
default: all
# create all command
all: $(EXE_FILES)
#echo toolkit has been built with optimization
#If compiling for debugging replace the compiler flags to remove optimization and add debugging
debug: F_FLAGS=$(F_FLAGSDB)
#Run compiler with debugging flags
debug: $(EXE_FILES)
#echo toolkit has been built with debugging
# Compile all of the source files into executables
$(EXE_FILES): % : %.f
$(FCOMP) $(F_FLAGS) $^ $(COMMON_LIB) $(SPICE_LIB) -o $(BIN_DIR)/$#
# install the library in /usr/local/lib
install:
cp -p $(BIN_DIR)* /usr/local/bin/toolkit/
# remove executable files for a clean build
clean:
rm $(BIN_DIR)*
The problem I am running into is that I get the following error when I try to run make:
make: *** No rule to make target `Display.f', needed by `Display'. Stop.
which I am assuming is because I have lost the directory that the source file comes from. Can someone help me here? I am totally stuck and don't know how to proceed.
In addition (this is more a general question about make), is there a way to tell make to recompile everything if the COMMON_LIB changes?
Thanks for your help!
Suppose your source files are
SRC1/alpha.f
SRC1/beta.f
SRC2/gamma.f
SRC3/delta.f
1) There is a flaw here:
EXE_FILES=$(addprefix $(BIN_DIR),$(notdir $(patsubst %.f, % , $(FORTFILES))))
This will produce
BINalpha BINbeta BINgamma BINdelta
when I think you intended
BIN/alpha BIN/beta BIN/gamma BIN/delta
A simple fix:
EXE_FILES=$(addprefix $(BIN_DIR)/,$(notdir $(patsubst %.f, % , $(FORTFILES))))
2) Now look at the static pattern rule:
$(EXE_FILES): % : %.f
...
So to build BIN/alpha, Make must first find BIN/alpha.f, which doesn't exist. To make it look for alpha.f, do this:
$(EXE_FILES): $(BIN_DIR)/% : %.f
...
3) How to find the sources?
You could do some delicate coding to help Make remember where it found alpha.f, but there's no need when we can use the vpath directive:
vpath %.f SRC1 SRC2 SRC3
4) One last look at that rule:
This command:
$(FCOMP) $(F_FLAGS) $^ $(COMMON_LIB) $(SPICE_LIB) -o $(BIN_DIR)/$#
Will produce e.g. BIN/BIN/alpha, which is silly. A non-PHONY Make rule should produce a file whose name is the target of the rule. It prevents a lot of trouble.
$(FCOMP) $(F_FLAGS) $^ $(COMMON_LIB) $(SPICE_LIB) -o $#
A few further refinements may be possible, once you have this working perfectly.

Different set of files and flags for different builds

Using GNU make for a project in Linux. I'd like to have a test and a prod build, and trying to implement it with conditional directives. Test build has different source files and flags etc. from the prod build.
First I found that if block only works when it's following a target.
# More variable definition skipped.
SRCS := some source files
CXXFLAGS := some complile flags
test: ${myBinary}
ifeq (${BUILD}, UNIT)
#echo BUILD == ${BUILD}
SRCS += ${TEST_SRCS}
CXXFLAGS += some test flags
endif
I use this way so that later I can use a pattern to build .o files, instead of listing all source files for 2 different builds. Basically I try to find a way to use patterns to build .o files, yet still have different files, flags, etc. for test/prod builds.
${BUILD_DIR}/%.o : %.cpp
${CXX} -c ${CXXFLAGS} ${INCS} $< -o $#
But after I put it next to a target, still got this error:
make: SRCS: Command not found
make: *** [test] Error 127
How to fix it to meet my goal?
Other advice on organizing the makefile to meet the goal is most welcomed too.
Edit:
The 2 executables produced can have different names but can be in same location.
I wanna put object files are in ${BUILD_DIR} to separate them from source files.
"Command not found" error is gone after unindenting SRCS line.

Resources