makefile select prerequisites depending on source - makefile

Suppose I have the following files:
.: include/ 01.src 02.src 03.src Makefile
./include: 01.inc 02-source1.inc 02-source2.inc
for which I have the following Makefile (source: Complex pattern rule in Makefile):
exe = ${patsubst %.src, %.exe, ${wildcard *.src}}
all : ${exe}
.SECONDEXPANSION:
${exe} : %.exe : %.src $${wildcard include/%*.inc}
#echo compile $# using $^
This says that 01.exe will be compiled using 01.src and include/01*.inc (something similar for 02.exe and 03.exe). In fact, make outputs:
compile 01.exe using 01.src include/01.inc
compile 02.exe using 02.src include/02-source1.inc include/02-source2.inc
compile 03.exe using 03.src
My question is: How should I modify this Makefile if 01.src, 02.src, and 03.src are renamed to 01-first.src, 02-second.src, and 03-third.src? The desired output is:
compile 01-first.exe using 01-first.src include/01.inc
compile 02-second.exe using 02-second.src include/02-source1.inc include/02-source2.inc
compile 03-third.exe using 03-third.src

try this:
${exe} : %.exe : %.src $${wildcard include/$$(shell echo % | head -c 2)*.inc}
#echo compile $# using $^
output:
compile 03-third.exe using 03-third.src
compile 02-second.exe using 02-second.src include/02-source1.inc include/02-source2.inc
compile 01-first.exe using 01-first.src include/01.inc

Related

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!

Including another Makefile results in a failed build, why?

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

jom with --silent mode

I'm using QtCreator (MinGW32 kit) on Windows and trying to make qt project with jom. Project build succeds. But! If I use silent mode :
CONFIG += silent
- build fails. If I look at Compile Output I'll see the error:
jom: .....\Makefile Error
Unexpected appearance: &&.
Also what I'll see in Makefile (I'm only displaying blocks where chars "&&" appear):
Compiler, tools and options
CC = #echo compiling $< && gcc
CXX = #echo compiling $< && g++
LINKER = #echo linking $# && g++
And then Build rules:
#echo moc BooleanSimulationModule.h && C:\Qt\Qt5.6.0\5.6\mingw49_32\bin\moc.exe $(DEFINES) -D__GNUC__ -DWIN32 -IC:/Qt/Qt5.6.0/5.6/mingw49_32/mkspecs/win32-g++ -IE:/qtregistrar/plugins/BooleanSimulationModule -IE:/qtregistrar/tools/widgets/QRWidgets/src -IE:/qtregistrar/tools/widgets/InfPlotWidget -IE:/qtregistrar/reglib -IC:/Qt/Qt5.6.0/5.6/mingw49_32/include -IC:/Qt/Qt5.6.0/5.6/mingw49_32/include/QtWidgets -IC:/Qt/Qt5.6.0/5.6/mingw49_32/include/QtGui -IC:/Qt/Qt5.6.0/5.6/mingw49_32/include/QtANGLE -IC:/Qt/Qt5.6.0/5.6/mingw49_32/include/QtCore BooleanSimulationModule.h -o moc_BooleanSimulationModule.cpp
Does anyone have any ideas why jom can't resolve command "&&" and how to fix this?
By the way, mingw32-make can build such Makefile without any probles.

Default link script in GNU Make

I have this very simple makefile:
P = hello_world.exe
OBJECTS = main.o
CFLAGS = -g -Wall -O3
LDLIBS =
CC = clang
$(P): $(OBJECTS)
When I run make it will compile main.c but it will not link to hello_world.exe. Shouldn't that be happening automatically?
My environment is cygwin 64bit.
The output of make -p is here: http://pastebin.com/qbr0sRXL
There's no default rule for .exe files that I'm aware of (or can find in that output).
You'll need to write one yourself.
If your output was hello_world and you had a hello_world.c/hello_world.cpp source file and also a main.c/main.cpp file then your makefile as written would work I believe (since the default %: %.o rule would apply and your added prerequisite would be added to the hello_world prerequisite list).

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.

Resources