I am trying to understand how makefiles work for a long time (however, quite inhomogeneously). I think, even though there is a hole bunch of discussion about makefiles, this is the first template that kind of lays out the structure and seems general enough, so I hope, that moderators will not close the question.
I have several parts of code in different c-files, but all in the same folder:
1)frprmn.c
2)mnbrak.c
3)nrutil.c
4)linmin.c
5)f1dim.c
6)dbrent.c
These codes are from Numerical Recipes and can be found elsewhere.
The main-function is in frprmn.c. The makefile is
program_NAME := MINIMIZE
program_C_SRCS := $(wildcard frprmn.c mnbrak.c nrutil.c linmin.c f1dim.c dbrent.c)
#program_CXX_SRCS := $(wildcard *.cpp)
program_C_OBJS := ${program_C_SRCS:.c=.o}
#program_CXX_OBJS := ${program_CXX_SRCS:.cpp=.o}
#program_OBJS := $(program_C_OBJS) $(program_CXX_OBJS)
#program_INCLUDE_DIRS :=
#program_LIBRARY_DIRS :=
#program_LIBRARIES :=
#CPPFLAGS += $(foreach includedir,$(program_INCLUDE_DIRS),-I$(includedir))
#LDFLAGS += $(foreach librarydir,$(program_LIBRARY_DIRS),-L$(librarydir))
#LDFLAGS += $(foreach library,$(program_LIBRARIES),-l$(library))
.PHONY: all clean distclean
all: $(program_NAME)
$(program_NAME): $(program_OBJS)
$(LINK.cc) $(program_OBJS) -o $(program_NAME)
clean:
#- $(RM) $(program_NAME)
#- $(RM) $(program_OBJS)
distclean: clean
The "template" for the makefile is from this tutorial. I was trying to follow the explanations when modifying it. By no means I have expected it to work as I don't get the following things:
Why don't we need header-files to link the libraries. Or do we? Maybe the author of the tutorial relies on it as common knowledge...
Why would I need an object file for each c-file? I need only one: frprmn.c. How do I do that?
How does makefile know which file contains main-function?
When I run it, I get the following error
c++ -o MINIMIZE
clang: error: no input files
make: *** [MINIMIZE] Error 1
I have no idea how it comes that I got c++ there. According to the tutorial, I have commented out all the c++-related lines. My guess is that it used C++ compiler as the default one, in which case, how to tell it to use gcc without forcing it explicitly?
All the placeholders, well, even thought I don't need them in this case, I still would like to be able to used them eventually. What do I do with
foreach includedir
Do I just list them there?
Can somebody give an example?
Thanks in advance!
Related
I know it is not optimal at all to rely on make's implicit rules but
my goal is to understand why they are not working in this case.
I want to write the simplest makefile one can write for a C project
without having to specify the sources.
I have tried to run make -d but the ouput is too big and verbose to
really be helpful.
I have written makefiles for some time and I believe I am familiar with how it
works. I am pretty sure I have managed to get implicit rules to work for me both
compiling and linking in the past but apparently I am forgetting something.
Here's what I have tried :
SRCS = $(wildcard *.c)
OBJS = ${SRCS:.c=.o}
NAME=exe
${NAME}: ${OBJS}
clean:
rm -rf *.o
fclean: clean
rm -rf ${NAME}
re: fclean ${NAME}
.PHONY: clean fclean re
It almost works but it doesn't link.
I am using gnu make version 4.3
Your Makefile doesn't execute the link step because there is only a very simple implicit rule for linking. From the documentation:
Linking a single object file
n is made automatically from n.o by running the C compiler to link the program. The precise recipe used is $(CC) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS).
This rule does the right thing for a simple program with only one source file. It will also do the right thing if there are multiple object files (presumably coming from various other source files), one of which has a name matching that of the executable file. Thus,
x: y.o z.o
In other words, for your Makefile to work, NAME needs to match the basename of one of your object files.
For example, if I have your Makefile and a single source file named hello.c, I can run:
make NAME=hello
And see the result:
cc -c -o hello.o hello.c
cc hello.o -o hello
I am pretty familiar with Makefiles and kernel modules, but recently I got a problem in my Makefile that doesn't make any sense -- on using wildcards.
To demonstrate this, I am compiling a hello world kernel module from scratch.
The directory structure is like this:
hello_mod/
|
--- hello.c
|
--- Makefile
Here is the actual makefile :
CFILES := $(wildcard hello.c*)
#CFILES := hello.c
OBJS := $(CFILES:.c=.o)
KSRC := /lib/modules/$(shell uname -r)/build
obj-m += hello_world.o
hello_world-y := $(OBJS)
all:
#echo $(CFILES)
$(MAKE) -C $(KSRC) M=$$PWD modules
clean:
$(MAKE) -C $(KSRC) M=$$PWD clean
.PHONY: clean
The problem is that even though the commented $(CFILES) and the uncommented $(CFILES) are exactly the same, the build fails on using the first $(CFILES) with the following error:
*** No rule to make target `/home/test/hello_mod/hello_world.c', needed by
/home/test/hello_mod/hello_world.o'. Stop.
If the commented $(CFILES) is used, it works perfectly.
If someone wants to test this out, I'm including the source for the hello world source which is hello.c :
#include <linux/kernel.h>
#include <linux/module.h>
static int mod_init()
{
printk("Hello\n");
return 0;
}
static void mod_exit()
{
printk("Bye world\n");
}
module_init(mod_init);
module_exit(mod_exit);
Does anyone know why it is behaving as such? And I need to use wildcards in the makefile. Any help will be appreciated.
There are two makes happening here. The first really only relies on the KSRC variable and the recursive make call. The second make only needs the CFILES, OBJS, obj-m, and hello_world-y variables, and doesn't make use of the all: target. So your debug is showing that CFILES is set correctly for the first Make, where it's not being used, and is not showing it in the second make, where it is.
You're wildcard expanding from a different directory, and not picking up the right files. Try this for CFILES:
CFILES := $(notdir $(wildcard $M/hello.c*))
SRCDIRS := subdir1 subdir2
CFILES := $(strip $(foreach dir,$(SRCDIRS),$(wildcard $(dir)/*.c)))
should probably be (see foreach example in documentation)
SRCDIRS := subdir1 subdir2
CFILES := $(foreach dir,$(SRCDIRS),$(wildcard $(dir)/*.c))
(no need to $(strip), .... or perhaps
CFILES := $(wildcard {subdir1,subdir2}/*.c)
Use remake, probably as remake -x, to debug such issues.
I have the following Makefile. How to add also some header files that I have in the project folder (e.g. header1.h with its relative header1.c) ?
CC := gcc
CFLAGS := -Wall -Wextra -Wpedantic -O3
CFILES := $(shell ls *.c)
PROGS := $(CFILES:%.c=%)
all: $(PROGS)
.PHONY: all clean
clean:
rm -f *~ $(PROGS)
Even adding them one by one would be ok (no need to use the wildcard).
I suppose I should edit the following line:
CFILES := $(shell ls *.c)
But how?
First, don't use $(shell ls *.c) but better $(wildcard *.c). Please take time to read the documentation of GNU make
Then, you usually don't want headers in Makefile-s, you want dependencies on headers.
For example, if you know that foo.o needs both foo.c and header.h (because you have some #include "header.h" in your foo.c) you would add a dependency like
foo.o: foo.c header.h
in your Makefile... See also this example.
There is some way to automate such dependencies, using GCC options; read about Invoking GCC, notably preprocessor options like -M
(details depend upon your project and coding conventions)
For a simple project of a few dozen of files totalizing a few thousand lines, you should first write your Makefile explicitly, with the dependencies. Later you might automatize that (but in simple projects that is not worth the trouble).
In some cases, a header file *.h or a C file *.c is generated by some utility (e.g. swig, bison, ... or your own script or program). Then you add appropriate specific rules in your Makefile.
You might use make --trace or remake with -x to debug your Makefile.
Look for inspiration into the source code of some existing free software project (e.g. on github).
So I've got the following folder structure
makefile
src/my_lib.c
src/myhead.h
and I'm trying to compile *my_lib.c* with the header myhead.h as a library. This is the makefile. I attempt to put the obj files in OBJFOLDER and the compiled library in the OUTPUTFOLDER
PLUGNAME=my_lib
SOURCEFOLDER=src
OUTPUTFOLDER=bin
OBJFOLDER=bin/obj
OBJS=$(PLUGNAME).o
DEPS=myhead.h
# Configuration finishes here
_OBJS = $(patsubst %,$(OBJFOLDER)/%,$(OBJS))
_DEPS = $(patsubst %,$(SOURCEFOLDER)/%,$(DEPS))
ifeq ($(OS),Windows_NT)
EXT = .dll
else
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Linux)
EXT = .so
endif
endif
all : $(OUTPUTFOLDER)/$(PLUGNAME)$(EXT)
$(OUTPUTFOLDER)/$(PLUGNAME)$(EXT) : $(_OBJS)
gcc -Wl,--add-stdcall-alias -shared -o $# $(_OBJS)
$(OBJFOLDER)/%.o: $(SOURCEFOLDER)/%.c $(_DEPS)
mkdir -p $(OUTPUTFOLDER)
mkdir -p $(OBJFOLDER)
gcc $(foreach d, $(INC), -I$d) -c $< -o $#
.PHONY: clean
clean :
rm -f $(OBJFOLDER)/*.o $(OUTPUTFOLDER)/$(PLUGNAME)$(EXT) $(SOURCEFOLDER)/TSDRPlugin.h
When I do make all it fails
make: *** No rule to make target `bin/obj/my_lib.o', needed by `bin/
my_lib.dll'. Stop.
I have no idea how this could be possible since I already have defined
$(OBJFOLDER)/%.o: $(SOURCEFOLDER)/%.c $(_DEPS)
Strangely if I change the above line in the makefile, to
bin/obj/my_lib.o: $(SOURCEFOLDER)/%.c $(_DEPS)
I now get
make: *** No rule to make target `src/%.c', needed by `bin/obj/my_lib.o'. Stop.
Your second error is because by removing the % in the target you've turned this into an explicit rule, not a pattern rule. So, the % in the prerequisite is not replaced.
Your first error means that for some reason make is deciding that your pattern rule doesn't match. This means, usually, that make can't find and doesn't know how to create one of the prerequisites. I recommend you run make with the -d flag and see why make decides your rule doesn't apply.
What version of GNU make are you using? Some very old versions would not match pattern rules if the directory that the target was to be placed into didn't exist already.
The problem was that header was missing... Stupid mistake on my side.
I overlooked it, because this was a snippet from a longer makefile that was supposed to copy over the header but it didn't which means that this line was outputting the error. Stupid me...
I am trying to write a makefile for a small scale application I wrote in C under Linux. Currently all my source files .c are in the top level directory and all header files in
an include directory. Here is the makefile I used for this.
IDIR =include
CC=gcc
CFLAGS=-I$(IDIR)
ODIR=obj
_OBJ = main.o kernel.o user_app.o myargs.o ofp_msgs.o pkt_ip.o pkt_ether.o pkt_tcp.o pkt_udp.o pkt_icmp.o
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
#DEPS = ofp_msgs.h
$(ODIR)/%.o: %.c
$(CC) -c -o $# $< $(CFLAGS)
all: jam
jam: $(OBJ)
gcc -o $# $^ $(CFLAGS) -lpthread
.PHONY: clean
clean:
rm -f $(ODIR)/*.o *~ jam
It works fine but what I want is that for example I make a sub directory called "Packet" and all my packet parsing files i-e "pkt_ip.c, pkt_tcp.c etc" should be in that directory where as their header files should still be in the top level directory i-t "toplevel/include". I did a bit of search and the most common way was to use recursive make. Then I see a lots of pages complaining about recursive make. Can anyone please help me in this as how to do this right ?
Thanks
I recommend checking out the method described in Recursive Make Considered Harmful.
I have used it on several projects (small to medium-size), and find it simpler to use, and easier to wrap ones head around, than the recursive approach.
Basically, you have a Makefile in the root directory which includes a (partial) makefile from each of the subdirectories:
SRC := main.c
MODULES := Packet lib etc
-include $(patsubst %, %/module.mk, $(MODULES))
OBJ := $(patsubst %.c, %.o, $(filter %.c,$(SRC)))
# (...)
Packet/module.mk:
SRC += Packet/pkt_ip.c Packet/pkt_tcp.c
LIBS += -lsome_library
These module makefiles can of course also define their own module targets, or special build requirements.
Unlike recursive make, "make" will only be invoked once, which for most use cases will lead to a faster build.
However, for most smaller projects neither build time nor complexity will be a major concern, so use what feels most natural.
there are several ways to do this but you can certainly use VPATH:=Packet to tell make to look for source files inside the 'Packet' directory. see make manual