Automatic variable not expanding properly in Makefile - c

I am using the following code:
HELLO_WORLD=hello
$(HELLO_WORLD): $(addsuffix .c,$#)
gcc $< -o $#
However, when I run the code, I receive the following error, implying that $< is not evaluating to anything:
gcc -o hello
gcc: fatal error: no input files
When I use the following code...
HELLO_WORLD=hello
$(HELLO_WORLD): $(addsuffix .c,$#)
gcc $(addsuffix .c,$#) -o $#
...the Makefile evaluates to the following command...
gcc hello.c -o hello
...which is precisely what I would like. However, I do not want to use addsuffix twice. I would like to use $< in the event that I change the prerequisite. How would I go about doing this?

The problem is not with the expansion of $< in the recipe. The problem is the expansion of $# in the prerequisite list.
Automatic variables, such as $#, are only defined in the recipe, not in the target or prerequisite lists. This is highlighted in the GNU Make manual section on automatic variables:
A common mistake is attempting to use $# within the prerequisites list; this will not work.
The fact that hello.c is not actually in the prerequisite list does not prevent you from invoking make hello. It just means that make hello will always invoke the compiler, even if hello.c has not been modified. But it does mean the $< will be as empty as the computed prerequisite list.
GNU make does have a feature to let you do a second expansion of prerequisites; this is explained in the manual. But the simpler solution is to simply not rely on $# in the prerequisite list. If you're trying to create your own generic C compile recipe, use a pattern rule for object file (.o) targets. For the final executable, list all the prerequisites for the final executable (which will almost certainly be more than one file).
Typically this is done using separate variable with names like SRCS and OBJS (or SOURCES and OBJECTS if you don't mind typing vowels). Normally you make the object files prerequisites for the final executable (which will be a link operation), since each individual source file will have its own header prerequisites.

The fundamental problem is automatic variables are only defined in the recipe. So, in the prerequisite, $# is not defined. Because $< will refer to an expression that depends on $#, which does not exist, $< will therefore not exist as well.
So, there are really two ways to resolve the issue. The first way is a bit clunky, but you can use secondary expansions. This essentially allows us to do what we want without adding much code...
HELLO_WORLD=hello
SECONDEXPANSION:
$(HELLO_WORLD): $(addsuffix .c,$$#)
gcc $< -o $#
The more proper way to do this involves restructuring the Makefile and using pattern rules. This gives us a generic recipe for building any C file. With the following Makefile, we can either run "make" or "make hello" to build the executable.
HELLO_WORLD=hello
all:
$(MAKE) $(HELLO_WORLD)
%: %.c
gcc $< -o $#

Related

What does ` $($#.c) ` mean in a Makefile when it appears in the prerequisites of a rule?

TARGETS = a b c d
$(TARGETS) : $($#.c)
$(CC) -c $#.c
$(CC) $#.o -o ../bin/$#
rm -f $#.o
I know how it works, this rule iterates over the variable TARGETS to compile the .c file with filename identical to its corresponding part in TARGETS. But I was not capable of finding the detail of this grammar in the mannul.
Which part should I refer to to know more about it?
$# only has a value within the recipe, so the obvious:
$(TARGETS) : $#.c
...
doesn't work, because when the rule is read, $# has no value. It's explicitly called out in https://www.gnu.org/software/make/manual/make.html#Automatic-Variables
However, if you enable secondary expansion, which applies to rules after the special target
.SECONDEXPANSION:
then $($#.c) is expanded to $#.c when the rule is first read, and when the rule is used, $# will have a value (of the target being built) thanks to secondary expansion. See: https://www.gnu.org/software/make/manual/make.html#Secondary-Expansion
Incidentally, I'm not sure why the rule is so complicated. I don't see why it needs to build the .o file only to delete it later, when C compilers can build a binary from source files without generating an intermediate .o file.
$(TARGETS) : $($#.c)
$(CC) $#.c -o ../bin/$#
And the rule is faulty anyway, because the target of the rule is not generated by the recipe: the target is for example "a", but the file generated is "../bin/a".
As there is no .SECONDEXPANSION:, and, very likely, you don't have a make variable named .c, this rule is the same as:
$(TARGETS) :
$(CC) -c $#.c
$(CC) $#.o -o ../bin/$#
rm -f $#.o
Moreover, the targets (a b c d) are not the files produced by the recipe (../bin/a...). This is wrong because make has no way to know when the executables are up-to-date (no prerequisites and wrong targets). The executables will always be rebuilt, even if the source files do not change. A much better and simpler solution would be to use a static pattern rule, and also to use the real target files, instead of non-existing files. If you use GNU make and your compiler knows how to compile and link at once:
$(TARGETS) := $(addprefix ../bin/,a b c d)
$(TARGETS): ../bin/%: %.c
$(CC) $< -o $#
Now the targets are the real executable files produced by the recipe, and they really depend on their respective source file.
It just evaluates to an empty string and has no effect. Sorry to bother you.
To make this rule work as expected, one should add '.SECONDEXPANSION' before the rule, and write $$#.c in the prerequisite.
During the first expansion, it becomes $#.c and during the second expansion, automatic variable $# is visible and it is expanded.

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.

Makefile: "ld: can't link with a main executable file" in C

I am trying to compile two c files, calutil.c and calutil.h into one executable. Here is my makefile:
CC = gcc
CFLAGS = -Wall -std=c11 -DNDEBUG
all: caltool
caltool: calutil.o caltool.o
$(CC) $(CFLAGS) calutil.o caltool.o
caltool.o: caltool.c
$(CC) $(CFLAGS) caltool.c -o caltool.o
calutil.o: calutil.c
$(CC) $(CFLAGS) -c calutil.c -o calutil.o
clean:
rm -rf *.o *.out
calutil.c has no main, while caltool.c has a main. I get the error
ld: can't link with a main executable file when I make. What is the cause of this?
The main problem is that some your recipe for linkage is missing the output file, and that your compilation is missing -c.
In case you're using GNU make, the following Makefile would be sufficient to do what you want to do:
CFLAGS:=-Wall -std=c11
CPPFLAGS:=-DNDEBUG
.PHONY: all
all: caltool
caltool: caltool.o calutil.o
.PHONY: clean
clean::
$(RM) *.o
Explanation:
When you're not using target-specific variables, you should use := instead of = to assign variables so that they're expanded at assignment and not at evaluation.
When your Makefile grows and you split it, you might want to have multiple targets called clean which all would be executed. In that case use clean:: instead of clean:.
There's a predefined variable to call rm, it is $(RM) and it includes the -f flag to prevent the Makefile from failing in case one or more of the files to be removed do not exist in the first place.
The pattern for clean should be *.[adios] (that's really easy to remember, adios is Spanish for goodbye) so that it removes intermediate archives (.a when you build your own static libraries), dependency files (.d), preprocessor output (.i) and assembler files (.s) in case you use -save-temps to see what the compiler is doing.
GNU make has built-in rules to compile and link, see http://git.savannah.gnu.org/cgit/make.git/tree/default.c?id=3.81
The built-in rule for compilation calls $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -o $# $< so you don't need to write your own rule.
The built-in rule for linkage calls $(CC) $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $#
Targets which are not files themselves should be declared .PHONY to prevent confusion when a user creates a file with the same name, like all or clean.
I do not see how any of your commands would create a file matching the glob pattern *.out, so I removed that part of the clean rule.
Flags for the preprocessor should go into CPPFLAGS instead of CFLAGS. Preprocessor flags typically are all those -D and -I flags and would also be passed to other tools that use a C preprocessor in the same project, like splint or PC-Lint.
When the Makefile is run, it is looking how to make all, and it finds that for all it has to make caltool. For caltool it finds that it has to first make calutil.o and caltool.o. When it tries to make calutil.o and caltool.o, it finds that it can make them from calutil.c and caltool.c and will do so. Then it will link caltool.o and calutil.o into caltool.
From your naming I guessed that it's caltool.c that contains the main() function. It is helpful to place the object which contains main() first once you use static link libraries.
Edit: Here's some more magic for you. I assume that you have a header file calutil.h which is included by caltool.c to access extern symbols provided by calutil.c. You want to rebuild all objects that depend on these header files. In this case, add the following lines to your Makefile:
CPPFLAGS+=-MMD
-include caltool.d calutil.d
In order to not have the list of objects multiple times, you could add a variable objects like this:
objects:=caltool.o calutil.o
You would then build the application with this rule:
caltool: $(objects)
And include the dependency files like this:
-include $(objects:.o=.d)
In case you keep your working tree "clean", i.e. do not "pollute" it with "alien" code, i.e. you always want to include all .c files in your project, you can change the definition of objects as follows:
sources:=$(wildcard *.c)
objects:=$(sources:.c=.o)
In case you wonder why it is CPPFLAGS (uppercase) but objects (lowercase): it is common to use uppercase for all variables which configure the recipes of rules and control the built-in behavior of make, tools built on top of it, and classic environment variables, and lowercase variables for everything else.
I just removed the .o files from the directory, and edited my makefile to add -c to the caltool.o line.

Make: compile object file twice in the same target

I have the following simple problem in a Makefile:
%.o:: %.c
gcc -o $# -c $<
lib1.a: test.o
ar -r $# test.o
rm *.o
lib2.a: test.o
ar -r $# test.o
rm *.o
all: lib1.a lib2.a
make lib1.a or make lib2.a work properly. However, make all gives:
gcc -o test.o -c test.c
ar -r lib1.a test.o
rm *.o
ar -r lib2.a test.o
ar: test.o: No such file or directory
make: *** [lib2.a] Error 1
I need to do the rm *.o cause I want the object file to compile each time (in my real Makefile, I have a more complex use case where I compile with different flags).
How can I fix this problem? It seems that make compiles the object file only once.
I tried with .PHONY instead of doing the rm, but again, it compiles only once.
Your makefile is a bit against the make logic, this is why the result is not what you expect:
Here you define two targets (lib1.a and lib2.a) with a common dependency: test.o.
Then you define the rule all (which, by the way, should be .PHONY but this isn't a problem here) that depends on lib1.a and lib2.a.
So, in order to "do" all, make have to build lib1.a and lib2.a. They both depend on test.o, so make builds test.o once, then build lib1.a and lib2.a, expecting that the recipes you defined will just build those files, and nothing more.
The problem is that you delete test.o in the recipe for lib1.a and lib2.a, although this action is not needed to build them, this is something you want to do when cleaning, not building.
There are two solutions:
Move the deletion operation in a rule that is meant to do that (a .PHONY rule named clean for example).
The use of intermediate targets which will be deleted when they're not needed anymore. In fact, you can achieve that without even thinking about intermediate targets if you simply delete the first rule of your makefile (the %.o:: %.c one), because make already has an implicit rule that does that using intermediate targets.
Make is a rule-based system. Rules are declarative: you declare what you want built from what, you don't specify the order in which this happens (unless you can't avoid it). So a good Makefile is declarative: all results are declared like in a declarative programming language. They are like final variables in Java: you bind them to a value, you don't reassign them to a different value afterwards.
Make is also file-based: its "variables", targets and prerequisites are files.
So if you want to build two different things, don't call them by the same name! If you want two different test.o files, call them differently. The problem will go away without you needing to try and convince make that it should be like an imperative programming language, which it was specifically designed not to be. If you want an imperative build specification, use a shell script.

Resources