Is it possible to match sets in a make file? - c

I have a make file that uses pattern matching to automate compilation using a rule like this:
%.o : %.c
gcc -c $<
However in this project I have a number of source files which differ in case of their extension. Is there a way to match sets in make files like in regular expressions.
Pseudo-example:
%.o : %.[cC]
gcc -c $<
It is not possible to simply change the case of the source files as this is used for module testing of an existing project which mixes modules from several other.

I found the solution. It turns out that the makefile had several issues.
First the example I posted actually works as Banthar pointed out. However my problem was that my sourcefiles weren't in the root directory but in a src/ subdirectory which I had added to vpath. I honestly thought it was irrelevant to my question as I believed make would automatically scan its vpath for source files. Turns out vpath does not apply to rule checking.
To make it work do:
vpath = %.c src
vpath = %.C src
%o : src/%.[Cc]
gcc -c $<
Next as I was working through examples of how to get it done make would sometimes build sourcefiles behind my back. If you do:
all : main.o
gcc -o test main.o
... and not have rule to build the .o file make will build it using implicit inbuild rules. Quite confusing. It can be disabled using the -r flag.
make -r all
Third compiling .C files using gcc without any extra options will result in linker errors because gcc interprets .C files as C++ files as default. In order to compiles as C files use -x flag.
%.o : %.C
gcc -x c -c %<
Hope this helps someone.

The easiest option I can see is simply to link non-matching cases:
%.c : %.C
ln $< $#
and let rule chaining do the rest.

Related

Makefiles in C language

Hello I'm having a hard time understanding makefiles. I play with them to understand them better but here's the issue:
all: main
main: main.o funcIO.o funcMan.o
$(CC) -o $# $^
----------------------------------
funcIO.o: funcIO.c
$(CC) -c -o funcIO.o funcIO.c
funcMan.o: funcMan.o
$(CC) -c -o funcMan.o funcMan.c
This works regardless if everything below the punctured line is there or not. I'm told that this is the right way to write makefiles but why does it work without the targets funcIO.o and funcMan.o and if it works without them, why do we write them? Can you explain it like I'm 5 years old?
Thanks for your time!
Assuming you're using GNU Make (it might be the same for other Makes), this works due to built-in rules. Make already knows how to compile a C source file, and unless you tell it otherwise, it applies this recipe to it:
%.o: %.c
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -o $# $<
$# is the target of the rule (the filename of the .o file) and $< is the first prerequisite (the filename of the .c file). The other variables have sensible defaults (mostly empty).
The right way to use Makefiles is to keep them as small as possible. Makefiles are about determining dependencies and only incidentally can be used to build programs. Here's how I would rewrite your Makefile:
all: main
main: main.o funcIO.o funcMan.o
And I only put the all target there because you had it to begin with. Make has a list of builtin rules that know how to build things given certain files as inputs. If you ask it for a .o file, it will look for a file of the same name, but with the extension of .c, .cpp, .f77, etc., and run the rule that builds what you asked for using that prerequisite file. You don't even need to specify how to build those, they come for free! It's the more complex relationships (such as a final binary) that need to be spelled out, as shown in my above example. There's a similar rule for building a binary out of .o files (assuming one of them has the same name as the binary, which yours does), so you don't need to specify any tasks, just the dependencies. You can control how they are run by adjusting special flags:
CFLAGS += -Wall -Wextra -Wpedantic
main: main.o funcIO.c funcMan.o
main: LDLIBS += -lm
This version builds every C-compiled file with those CFLAGS, and builds main while linking in the -lm math library.
If you are building normal C programs, I strongly recommend this approach. Specify the prerequisites of the final binary, and control builds through these Make variables.

searching solution for creating generic makefile for compilation of multiple programs

Till now, I was using the following makefile that I have generated somehow for my school projects:
my makefile
But now I have a different situation: I am supposed to compile 4 programs for one project, while part of the code is supposed to be compiled as .so, for use for the 4 programs.
like described here:
1 - all the parts that are supposed to be compiled together as one .so file, using for example:
gcc -shared -fPIC src/file1.c src/file2.c src/file3.c -o libutils.so
3,4,5 should be compiled and linked together with this .so file, using for example:
gcc src/file4.c -L'pwd' lutils -o file4.out
the same way for all the 3 projects, and one more simple compilation of project 2.
I wandered across the net, google, your site, etc.
tried to find a solution for this situation,
without any luck.
already seen solutions like this one:
solution example
where you supply makefile with the details of the entire project structure.
I thought about dividing all the files into 4 folders, below the main folder, and creating a loop inside makefile that will compile each program in each cycle, with "if" statements to make a different compilation, according to the index. but I had no luck, it seems very complicated (maybe someone can show me a solution like that one...).
I am wondering if there is a way of making this whole compilation process generic and automatic like the current file (maybe little less),
if there is a way, I would like to study and discover it.
thank you in advance!!!
Arie
Since you have a nicely drawn tree of dependencies, you "just" need to translate this into a Makefile.
You might like to start with this:
.PHONY: all
all: reloader.exe block_finder.exe formatter.exe printdb.exe
MODULES = reloader block_finder formatter printdb linked_list bitcoin file_handler
SRCS = $(MODULES:%=%.c)
reloader.exe block_finder.exe formatter.exe printdb.exe: libbitcoin_manager.so
reloader.exe: reloader.o
block_finder.exe: block_finder.o
formatter.exe: formatter.o
printdb.exe: printdb.o
libbitcoin_manager.so: linked_list.o bitcoin.o file_handler.o
gcc -shared -fPIC $^ -o $#
%.exe: %.o
gcc $< -L. -lbitcoin_manager -o $#
%.o: %.c
gcc -c $< -o $#
%.d: %.c
gcc -MM -MT $# -MT $*.o -MF $# $<
include $(SRCS:%.c=%.d)
Because you don't have a loop in the diagram, you don't need a loop in the Makefile. Instead you put all dependent files on the left of a colon and the file they depend on on the right.
You might like to collect more "objects" in variables, for example the programs to build, the modules in the library, and so on.
I have also used a common pattern to generate the dependencies from the header files. The way shown is just one way to do it. It uses files with a ".d" extension, for "dependency." GCC has options to build these files, it scans the source and collects all included headers even if "stacked."
For example, "bitcoin.d" looks like this:
bitcoin.d bitcoin.o: bitcoin.c bitcoin.h linked_list.h definitions.h \
file_handler.h
The re-generate the dependency file on changes in the sources it is also a target, not only the object file.
EDIT:
First, using directories makes Makefiles more difficult. I don't like such structures not only for that reason, but also because they separate header files and implementation files that clearly belong to each other.
Anyway, here is an enhanced Makefile:
.PHONY: all
SRCDIR = src
INCDIR = include
BLDDIR = build
APPS = reloader block_finder formatter printdb
MODULES = reloader block_finder formatter printdb linked_list bitcoin file_handler
LIBNAME = bitcoin_manager
LIBMODULES = linked_list bitcoin file_handler
VPATH = $(SRCDIR)
SRCS = $(MODULES:%=%.c)
LIB = $(LIBNAME:%=lib%.so)
#win LIB = $(LIBNAME:%=%.lib)
EXES = $(APPS:%=%.exe)
all: $(BLDDIR) $(EXES)
$(BLDDIR):
mkdir $#
$(LIB): $(LIBMODULES:%=$(BLDDIR)/%.o)
gcc -shared -fPIC $^ -o $#
$(EXES): $(LIB)
$(EXES): %.exe: $(BLDDIR)/%.o
gcc $< -L. -l$(LIBNAME) -o $#
$(BLDDIR)/%.o: %.c
gcc -I$(INCDIR) -c $< -o $#
$(SRCDIR)/%.d: %.c
gcc -I$(INCDIR) -MM -MT $# -MT $(BLDDIR)/$*.o -MF $# $<
include $(SRCS:%.c=$(SRCDIR)/%.d)
It uses a lot more variables to simplify renaming and managing a growing library and application.
One important issue is the use of VPATH. This makes make search for sources in the list of paths assigned to it. Make sure you understand it thoroughly, search for articles and documentation. It is easy to use it wrong.
The pattern $(EXES): %.exe: $(BLDDIR)/%.o is a nice one. It consists of three parts, first a list of targets, second a generic pattern with a single target and its source. Here is means that for all executables each of them is built from its object file.
Now to your questions:
Is answered by the new proposal. I didn't add the directory but use VPATH.
Make stopped not because the exe-from-o pattern was wrong, but because it didn't find a way to build the object file needed. This is solved by the new proposal, too. To find out what happens if you delete these 4 recipes in the old proposal: you can experiment, so do it!
The dot is, like user3629249 tried to say, the present working directory. You had it in your Makefile with 'pwd' and I replaced it. This is not special to make, it is common in all major operating systems, including Windows. You might know .. which designates the parent directory.
When make starts it reads the Makefile or any given file. If this file contains include directives the files listed are checked if they need to be rebuild. make does this even if you call it with -n! After (re-)building all files to be included they are included finally. Now make has all recipes and continues with its "normal" work.

No rule to make something.o even though %.o is defined

I'm new to the forum, so I hope I'm doing things right.
I'm writing from scratch a Makefile for a C project. It was working at some point, then I tried to improve it a little (including separate folders), and I got the well-known error "No rule to make target "obj/autresFonctions.o", needed for "CUR"". Or similar, since it's not in english and I translated.
That seems quite weird since the rule I'm expecting to work is using %.o and should match anyhting. Thus I don't think it could be a typo.
Here is the Makefile :
EXE=prgm
CC=gcc
SRC_DIR=src
OBJ_DIR=obj
INCLUDE_DIR=include
_FICHIERS_H = autresFonctions.h calculPrealable.h constantes.h fonctionsAnnexes.h fonctionBoucles.h lectureFichiers.h main.h
FICHIERS_H = $(patsubst %, $(INCLUDE_DIR)/%, $(_FICHIERS_H))
_OBJ = autresFonctions.o calculPrealable.o fonctionsAnnexes.o fonctionsBoucles.o lectureFichiers.o main.o
OBJ = $(patsubst %, $(OBJ_DIR)/%, $(_OBJ))
FLAGS=-Wall -Wextra
CUR: $(OBJ)
$(CC) -o $(EXE) $^
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c $(FICHIERS_H)
$(CC) $(FLAGS) -c -o $# $<
clean:
rm $(OBJ) $(EXE)
I'm assuming it's the same for the others .o, because I also tried switching the first two .o in _OBJ , and I got the same error with calculPrealable.o
I'm just typing "make" when compiling, in order to get CUR, the main target. I'm located in the main directory, which contains include/ (with the .h), src/ (with the .c) and obj/ (empty).
EDIT : I forgot to say, but I'm using the usual GNU make.
The pattern rule only matches if ALL of the rule matches. It's not enough to just match the target: make must also be able to find (or make) the prerequisite pattern(s) and all other prerequisites listed in the rule.
If one thing doesn't match, then the rule doesn't match.
You can use make -d to see what files make is trying to build, and see which one doesn't exist and causes the rule to fail.
PS. This is all assuming you're using GNU make, which you don't say specifically.

Why does this makefile not apply includes to all objects?

This makefile does not behave as I expect. I want it to build .o files for each .c file in the current directory and subdirectories, and put them in a static library. However, it stops applying my $(INCS) after the first or second file. When it tries to build the second .o file, I don't see the -I paths in the build line and it complains about not finding a header file therein. Names have been genericized to simplify things. I'm using cygwin on Windows XP. I'm using an ARM cross compiler that is not under the cygwin tree. I based this makefile off an answer here. There are only about two dozen .c files so the overhead of creating the dependency files this way isn't a big deal.
# Project specific options
CC = my-cross-gcc
INCS := -I. -Iinc
INCS += -Imy/inc/path
CFLAGS := -Wall -fPIC -static -cross-compiler-specific-options
OUT := bin/libmylib.a
MKDIR:=mkdir -p
### Generic C makefile items below:
# Add .d to Make's recognized suffixes.
SUFFIXES += .d
NODEPS:=clean
#Find all the C files in this directory, recursively
SOURCES:=$(shell find . -name "*.c")
#These are the dependency files
DEPFILES:=$(patsubst %.c,%.d,$(SOURCES))
OBJS:= $(patsubst %.c,%.o,$(SOURCES))
#Don't create dependencies when we're cleaning, for instance
ifeq (0, $(words $(findstring $(MAKECMDGOALS), $(NODEPS))))
-include $(DEPFILES)
endif
#This is the rule for creating the dependency files
%.d: %.c
$(CC) $(INCS) $(CFLAGS) -MM -MT '$(patsubst %.c, %.o,$(patsubst %.c,%.o,$<))' $< > $#
#This rule does the compilation
%.o: %.c %.d %.h
$(CC) $(INCS) $(CFLAGS) -o $# -c $<
# Now create a static library
all: $(OBJS)
#$(MKDIR) bin
ar rcsvq $(OUT) $(OBJS)
clean:
rm -rf $(OBJS) $(OUT) $(DEPFILES)
Why does this makefile not apply $(INCS) when building subsequent .o files? How do I fix it? Output resembles this:
$ make all
my-cross-gcc -I. -Iinc -Imy/inc/path -<compiler options> -o firstfile.o -c firstfile.c
my-cross-gcc -I. -Iinc -Imy/inc/path -<compiler options> -o secondfile.o -c secondfile.c
my-cross-gcc -<compiler flags> -o thirdfile.o -c thirdfile.c
thirdfile.c:23:18: fatal error: myinc.h: No such file or directory
compilation terminated.
When I go to the command line and type in the gcc line to build thirdfile.o and use the -I paths, the object file is successfully built.
There are two different mechanisms for handling header files at work here:
When the compiler is trying to build foo.o from foo.c, and in foo.c it encounters #include "foo.h", it goes looking for foo.h. The -I flags tell it where to look. If it is invoked without the flags it needs to find foo.h, it will complain and die.
When Make is trying to build foo.o, and considering which rule to use, it looks at the prerequisites. The prerequisites for your rule are foo.c foo.d foo.h, so it goes looking for those prerequisites. How is it to know where foo.h is? Note that the compiler flag inside one of its commands is of no use-- it won't make any deductions about that. If it can't find (and doesn't know how to make) a prerequisite, it will reject that rule and look for another one, such as the implicit %.o rule which knows nothing about your $(INCS) variable, and that leads you to the problem described above.
If this is the problem (and you can check by looking at the locations of the headers and doing some experiments) you have a couple of options:
A) You can use the implicit rule, and it's variables. Just add INCS to CFLAGS and you'll probably get the results you want. This tells the compiler what to do, but it still leaves Make in the dark about the dependencies, so you'll probably have to double-check that your dependency handling is correct.
B) You can tell Make where to find the header files:
vpath %.h inc my/inc/path
(You may notice that this is redundant with your INCS variable, and redundancy is bad-- you can eliminate this redundancy, but I urge you to get it working first.)
I'm going to guess that you have files named firstfile.h, secondfile.h, but no file named thirdfile.h?
I would then suppose that make cannot use the rule you gave it because and can't find or build the .h file. So it decides to use the default implicit rule instead.
All I can imagine is that for "thirdfile" your depfile is somehow out-of-date or corrupt. Perhaps it is bad enough that it's confusing make into calling some other default target.

GNU Make - Dependencies on non program code

A requirement for a program I am writing is that it must be able to trust a configuration file. To accomplish this, I am using several kinds of hashing algorithms to generate a hash of the file at compile time, this produces a header with the hashes as constants.
Dependencies for this are pretty straight forward, my program depends on config_hash.h, which has a target that produces it.
The makefile looks something like this :
config_hash.h:
$(SH) genhash config/config_file.cfg > $(srcdir)/config_hash.h
$(PROGRAM): config_hash.h $(PROGRAM_DEPS)
$(CC) ... ... ...
I'm using the -M option to gcc, which is great for dealing with dependencies. If my header changes, my program is rebuilt.
My problem is, I need to be able to tell if the config file has changed, so that config_hash.h is re-generated. I'm not quite sure how explain that kind of dependency to GNU make.
I've tried listing config/config_file.cfg as a dependency for config_hash.h, and providing a .PHONY target for config_file.cfg without success. Obviously, I can't rely on the -M switch to gcc to help me here, since the config file is not a part of any object code.
Any suggestions? Unfortunately, I can't post much of the Makefile, or I would have just posted the whole thing.
Declaring the file in .PHONY is wrong. Any dependency listed there will not be checked in the filesystem. Just list it as a dependency for the hash header and go from there.
What happened when you added config/config_file.cfg to the dependancies of config_hash.h, and why wasn't it what you expected?
A rule like
config_hash.h:config/config_file.cfg
$(SH) genhash $< > $#
would regenerate config_hash.h if config/config_file.cfg was more recent. Your gcc generated dependancies would then recompile anything depending on config_hash.h.
The $# variable is the target, using this ensures you are creating the file you asked for (In your question, if srcdir is defined the rule says it will generate ./config_hash.h, but will actually create ./$(srcdir)/config_hash.h). Similarly $< and $^ give the first and all prerequisites respectively.
I'm assuming you have a makefile like
CPPFLAGS+=-MMD -MP
all:
# etc.
config_hash.h:config/config_file.cfg
$(SH) genhash $< > $#
%.d %.o:%.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $*.o $<
%.d %.o:%.cpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $*.o $<
-include $(wildcard *.d) /dev/null

Resources