A Makefile Puzzle: Multiple Programming Languages - c

I have a simple test Makefile:
hello: hello.o
.SUFFIXES: .c .f90 .o
.f90.o:
pgf90 -c -o $# $<
.c.o:
cc -c -o $# $<
You don't have to tell me that it having a foo.c and a foo.f90 in the same directory will create confusion. I would never do this for real. I am simply trying to get an idea of how Make handles some precedents. So, when I simply issue the make command, make runs:
pgf90 -c -o hello.o hello.f90
cc hello.o -o hello
And of course, the "cc" link fails because "cc" can't link a FORTRAN object to make an executable. Fine. But my question is: I have tried everything I can think of to discourage make from using the pgf90 command as its first compile command, and to opt for the cc command instead. I have changed the order of the suffix rules. I have changed the order of the suffixes in the .SUFFIXES statement. The only thing that seems to work is leaving the .f90 suffix rule out altogether. Why is this and can it be changed? Thanks. (In case it doesn't go without saying, I do have simple hello.f90 and hello.c source files in my directory, and they do compile and execute just fine.)
UPDATE: Ran make with -d. The relevant output (AFAICT) looks like:
Considering target file 'hello.o'.
File 'hello.o' does not exist.
Looking for an implicit rule for 'hello.o'.
Trying pattern rule with stem 'hello'.
Trying implicit prerequisite 'hello.c'.
Not being impressed with "implicit prerequisite 'hello.c'", make tries a whole bunch of other things before it comes to
Found an implicit rule for 'hello.o'.
Considering target file 'hello.f90'.
Looking for an implicit rule with stem 'hello.f90'
.
.
.
No implicit rule found for 'hello.f90'. #???????
.
.
Must remake target 'hello.o'
pgf90 -c -o hello.o hello.f90
Curiouser and curiouser

For reasons that are a mystery to me (but are probably obscure and historical), you can change this behavior by changing the suffix rules
.f90.o:
pgf90 -c -o $# $<
.c.o:
cc -c -o $# $<
into pattern rules (and reversing the order):
%.o : %.c
cc -c -o $# $<
%.o : %.f90
pgf90 -c -o $# $<

Related

No rule to make target - makefile

This is my makefile:
CC=gcc
CFLAGS=-c -O2 -Wall -fcommon -I./INC
#umiestnenie zdrojakov kniznice
SRC_LIB_DIR=SRC_LIB
#automateicke generovanie zdrojakov kniznice
SRC_LIB := $(wildcard $(SRC_LIB_DIR)/*.c)
OBJ_LIB=$(SRC_LIB:.c=.o)
#meno vykonatelneho programu
EXECUTABLE=test_rx test_tx
#vymenovanie zdrojakov aplikacie
SRC_EXE=demo_rx.c demo_tx.c
OBJ_EXE=$(SRC_EXE:.c=.o)
all: $(SRC_EXE) $(SRC_LIB) $(EXECUTABLE)
%: %00.o
$(CC) -o $# $+
.c.o:
$(CC) $(CFLAGS) $< -o $#
clean:
rm -f $(EXECUTABLE).exe *.o *.a SRC_LIB/*.o
The folder looks like this:
example_RS232
|__INC (rs232.h, example_modified_rs232.h)
|__SRC_LIB (rs232.c, example_modified_rs232.c)
|__demo_rx.c
|__demo_tx.c
|__makefile
Compiled in C in mingw on Windows.I'm trying to compile the demo_rx.c and demo_tx.c files into the test_rx and test_tx executables. I get an error when compiling:
make: *** No rule to make target 'test_tx', needed by 'all'. Stop.
I don't know why I have got this error.
Basically, you should try to never use "match-anything" rules. A match-anything rule is a rule where the target is just %. That rule can (as the name implies) match ANY target. It could match foo, foo.o, foo.c, foo.h, or any other thing anywhere in the makefile.
This makes these types of rules REALLY inefficient as make has to consider this rule, and the prerequisites, etc. for every target. It's also easy to get into loops this way.
Because of this, make installs a whole bunch of extra restrictions on match-anything rules that don't exist for other pattern rules. You can read all about this in the GNU make manual discussion but the best take-away is, "don't use them".
I recommend you replace this with a static pattern rule:
$(EXECUTABLE) : %: %00.o
$(CC) -o $# $+

Why am I getting this error Makefile: No rule to make target 'timer.c', needed by 'timer.o'. Stop

My working directory looks like this:
main.c
Makefile
my_memmove.h
my_memmove.c
c-timer-lib
timer.c
timer.h
My makefile looks like this:
CC := gcc
CFLAGS := -std=gnu99 -g -Wall -Wextra -Ic-timer-lib
TARGET := output
output: main.o my_memmove.o timer.o
$(CC) $(CFLAGS) main.o my_memmove.o timer.o -o $(TARGET)
main.o: main.c
gcc -c main.c
my_memmove.o: my_memmove.c my_memmove.h
gcc -c my_memmove.c
timer.o: c-timer-lib/timer.c c-timer-lib/timer.h
gcc -c c-timer-lib/timer.c -o $#
clean:
rm *.o $(TARGET)
I don't understand why I keep getting the "Makefile: No rule to make target 'timer.c', needed by 'timer.o'. Stop." error. I believe that it's because the timer.c and timer.h files can't be found.
So much confusion here! :)
First, this is definitely wrong:
$(CC) $(CFLAGS) -I main.o ...
The -I main.o tells the compiler that it should use main.o as the name of a directory to search for include files. That clearly won't work. You should remove the -I here.
On to your problem: you have to realize that there are two completely different programs at play here: make which figures out how to run commands, and the commands that are being run, in this case the compiler gcc.
The -I option is an option to the compiler so that the compiler knows where to look for header files that are included by your source code with #include.
That option means nothing to make; it doesn't understand that option. It's just some text to pass to the compiler. Make is looking for the source file timer.c and it can't find it because you haven't told make where it is.
You have to write your rule to look in the correct place, like this:
timer.o: c-timer-lib/timer.c c-timer-lib/timer.h
gcc -c c-timer-lib/timer.c -o $#
(you should always use -o $# so that your compile line puts the output file where make expects to find it, which will be put into the $# variable by make before it evaluates your recipe.)
ETA
Also, are you sure that -DUNITS="ms" is right? We can't tell without seeing how UNITS is used in the source, but I suspect you probably need an extra level of quotes here, like -DUNITS='"ms"'
Really, you are trying to do too much in this makefile. Make already knows how to correctly build object files from source files. If you don't force the issue by writing your own rules, then make's built-in rules will do the job for you. Your makefile can be written like this:
CC := gcc
CFLAGS := -std=gnu99 -g -Wall -Wextra -Ic-timer-lib -DUNITS='"ms"'
TARGET := output
$(TARGET): main.o my_memmove.o c-timer-lib/timer.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $# $^ $(LDLIBS)
my_memmove.o: my_memmove.h
c-timer-lib/timer.o: c-timer-lib/timer.h
clean:
rm *.o $(TARGET)
make doesn't know which headers your source requires so you have to add the prerequisites by hand, although you can add extra rules to allow it to figure that out for itself.

Rule not recognized in makefile?

I have a basic makefile to compile C files necessary for compiling a shared library, I have an error because the makefile is not recognized:
SOURCES=/home/test/project/sources
OBJECTS=/home/test/project/objects
$(OBJECTS)/%.o:$(SOURCES)/%.c
$(CC) -fPIC -c $^ -o $#
sharedlib: $(OBJECTS)/%.o
$(CC) -shared -o libsharedlib.so $<
When I run make I get that there is no rule for target: $(OBJECTS)/%.o needed by sharedlib. While the rule is written right before sharedlib.
The main problem is that nowhere you are explicitly telling make what your source files are. Start by doing that:
SOURCEDIR=/home/test/project/sources
SOURCES=$(wildcard $(SOURCEDIR)/*.c)
Then, derive the object file names from the source file names by substituting .c for .o:
OBJECTDIR=/home/test/project/objects
OBJECTS=$(patsubst $(SOURCEDIR)/%.c,$(OBJECTDIR)/%.o,$(SOURCES))
You can still keep your generic rule to build object files:
$(OBJECTDIR)/%.o: $(SOURCEDIR)/%.c
$(CC) -fPIC -c $^ -o $#
But you give the explicit list of object files to the rule to make sharedlib:
libsharedlib.so: $(OBJECTS)
$(CC) -shared -o $# $<
Note that I made the name of the rule the same as the file that is being generated. That's important, because calling make twice in a row will then skip building the library a second time. You can always add an alias if you want:
sharedlib: libsharedlib.so
In that case, it's also good to tell make that sharedlib is not a real file:
.PHONY sharedlib
This prevents weird things from happening if you ever did have a file called sharedlib in the directory.
The library rule
sharedlib: $(OBJECTS)/%.o
is not enough to tell Make which objs are needed for the library.
This should work, and gives explicit control on which are the sources/objs pairs you want in the library:
SOURCESDIR=/home/test/project/sources
OBJECTDIR=/home/test/project/objects
OBJLIST = \
$(OBJECTS)/file1.o \
$(OBJECTS)/file2.o
$(OBJECTDIR)/%.o: $(SOURCESDIR)/%.c
$(CC) -fPIC -c $^ -o $#
sharedlib: $(OBJLIST)
$(CC) -shared -o libsharedlib.so $<

Resulting file names as a input of a variable

I have many functions in different files.
eg: OBJ_SRC=sum.c sub.c mul.c div.c remainder.c
When I am creating a library I do like this:
libarithmatic.a: $(OBJ_SRC)
gcc -c $(OBJ_SRC) # creates sum.o sub.o..
ar rcs libarithmatic.a $(OBJS) #<--- problem #OBJS
How to store the output of gcc -c $(OBJ_SRC): add.o sub.o mul.o.. (newly created/updated file names) into OBJS variable?
The usual way is with patsubst
OBJS=$(patsubst %.c,%.o,$(OBJ-SRC))
Now calling gcc as part of the target to build the library is a bad idea. It misses the main point of using make at all as you are asking gcc to blindly recompile all the objects instead of having make find which have changed. The usual rule is:
libarithmatic.a: $(OBJS)
ar rcs libarithmatic.a $(OBJS)
You can put in the pattern rule for compiling the .c files, but if you'd just put in
%.o: %.c
gcc -c $<
you don't have to bother as that is implicit. Well, the default implicit rule is really
%.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -o $# $<
where CC defaults to suitable compiler and you can override it and CPPFLAGS and CFLAGS default to empty and you can set them to whatever flags you want to use for compilation. CPPFLAGS is for both C and C++, CFLAGS is for C only, CXXFLAGS is for C++ only (C++ compiler is CXX).
On a side-note, I'd suggest looking at CMake, which supports generating build files for various platforms, IDEs and the new ultra-fast ninja. The corresponding CMakeLists.txt would be as trivial as
project(arithmatic)
add_library(arithmatic sum.c sub.c mul.c div.c remainder.c)
and making it a shared library as trivial as adding SHARED keyword when you want to.
Note, that the % placeholder does not have to be at the beginning. If you want to put the objects in different directory from the sources, you can write things like
OBJS=$(patsubst src/%.c,obj/%.o,$(SOURCES))
(the sources have to be listed with the directory prefix in this case) or perhaps
OBJS=$(patsubst %.c,.objs/%.o,$(SOURCES))
And you can similarly use the pattern in the rules, so
obj/%.o: src/%.c
mkdir -p obj
$(CC) $(CPPFLAGS) $(CFLAGS) -o $# $<
or
.objs/%.o: %.c
mkdir -p .objs
$(CC) $(CPPFLAGS) $(CFLAGS) -o $# $<
You have to make sure the output directory exists as the compiler won't create it (so I include the mkdir in the rules) and you have to explicitly specify compiler output, because it would create it in current directory otherwise.

Using the make command without makefiles?

I was compiling some C code for an assignment and I ran "make codeFile", where "codeFile" was the name of my C program, and even though I didn't have a makefile, an executable was created, and it ran and worked correctly.
Does anyone know why this worked? Why does make compile something even if I don't have a makefile? The only reference I could find was this:
http://daly.axiom-developer.org/TimothyDaly_files/class5/node5.html
Make has an internal database with implicit rules. You can use make -p to list them. Also make -d will tell you which rules are being applied, so that would help you discover which implicit rules are being used in this case.
Make has several pre-defined implicit rules. In particular, in your case, it uses two such rules when trying to determine what to do for the target codeFile:
%: %.o # Link object file
$(CC) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS)
%.o: %.c # Compile C source code
$(CC) $(CPPFLAGS) $(CFLAGS) -c
Using the make command without makefiles?
make has implicit rules that work as defaults unless you override them.
According to the make man page:
make -p -f/dev/null
will list all of the implicit rules (and relevant environment variables) without attempting to actually remake files.
To demonstrate the usage, I ran make in Cygwin, which gave me an exe file. Note no .c on the name passed to make:
$ ls
hello.c
$ make hello
cc hello.c -o hello
$ ls
hello.c hello.exe
I also ran this in Ubuntu Linux, and my result was nearly the same as above, but the .exe extension was not there, instead I had the plain hello executable:
$ ls
hello.c hello
Step by step derivation
I believe the relevant pieces of the make implicit rules are as follows:
CC = cc
cc is aliased to CC
LINK.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
a LINK format is created, where the flags will be empty, and the TARGET_ARCH variable is also empty (to allow users to set values for various target architectures.) Then we have:
%: %.c
# recipe to execute (built-in):
$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $#
The ^ variable is the prerequisite, hello.c. The other variables are empty. These are followed by the -o flag and the target name. The empty variables explain the extra spaces in the command make ran:
cc hello.c -o hello
And the %: %.c matched the target given to make with the filename of the same target name ending in .c, which caused the recipe to execute.

Resources