compare the name of two files in a Makefile - makefile

I want to hold all the objects that I need to make in a variable, and to make things easier, I am using a wildcard function to get all the .c files in the source directory, but that file also needs a corresponding .h file, so how I would check that such pairs of files exist?
SRCDIR := src
C_SRCS := $(wildcard $(SRCDIR)/*.c)
C_HEADERS := $(wildcard $(SRCDIR)/*.h)
# check if the basename of a c src matches with the basename of a header file
For example if the .c files were:
foo.c
bar.c
baz.c
and the .h files were:
foo.h
baz.h
thing.h
then the .o files should be
foo.o
baz.o

If you just want to build any .c file that has a corresponding .h file but ignore any other .c file, you can do something like this:
ALL_HEADERS := $(wildcard $(SRCDIR)/*.h)
C_SRCS := $(wildcard $(ALL_HEADERS:%.h=%.c))
This will find all headers, then convert each one into a corresponding source file, then run wildcard on those which will result in only the ones that actually exist.

Related

How to compile files that reside in different directory in Makefile?

I have seen this questions asked before but was not able to decipher those answers.
Lets say I reside in working directory, lets call it proj and this proj directory contains src folder which contains all the *.cpp files. I want to compile those file staying on the proj directory because in future I will be creating bin directory and placing the *.o and binary in bin.
So my proj directory currently contains : Makefile and src
What I have done so far is :
SOURCE = src
# This gives the path to the proj directory
CURRENT_DIR = $(shell pwd)
# This gives list of all the *.cpp files
SRC = $(shell cd $(SOURCE) && echo *.cpp)
# Here all the name of the files stored in SRC are converted from *.cpp to *.o
OBJS = $(SRC:.cpp=.o)
.PHONY: all
all: $(TARGE)
# use the content of SRC to compile
$(TARGET): $(OBJS)
$(info $(OBJS))
$(OBJS): $(SRC)
$(CC) $(FLAGS) -c $?
When I try to run the make command it says
make: *** No rule to make target 'xxx.cpp', needed by 'xxx.o'. Stop
Now I know what it is trying to say. It gives error because although it knows the name of the file, since the file is not in the current directory makefile does not know about src folder and hence have no clue about the *.cpp files.
So my question is: Is there any macros or trick to use in makefile to make sure makefile see the xxx.cpp in src folder while staying in the current directory( I don't want to specify the folder by hand here)?

.cpp to .o files in Makefile

How can I generate .o file corresponding to all the .cpp files in a directory using Makefile?
I have a directory that contains .cpp files. Now, I want to compile them in .o files. The name of the .o files should be same as corresponding .cpp files. What should I do?
Actually, I already had an implementation but I am not sure how it work
SRCS := $(wildcard $(SRCDIR)/*.cpp)
OBJS := $(SRCS:$(SRCDIR)/%.cpp=$(OBJDIR)/%.o)
$(OBJS): $(OBJDIR)/%.o : $(SRCDIR)/%.cpp
// Recipe //
Try this
SRCS=$(wildcard *.cpp)
OBJS=$(SRCS:.cpp=.o )
%.o: %.cpp
$(CC) -c $< -o $#
Let me add some more explaination to it.
SRCS := $(wildcard $(SRCDIR)/*.cpp) - It will list all the .cpp files under SRCDIR directory and will assign to SRCS
OBJS := $(SRCS:$(SRCDIR)/%.cpp=$(OBJDIR)/%.o) - It will replace all the files with .cpp listed from the above statement to .o ex: main.cpp would be changed to main.o and assigned to OBJS
$(OBJDIR)/%.o : $(SRCDIR)/%.cpp - Object files depends on respective .cpp files and in the rule you can write rule to create object files
The % character can be used for wildcard pattern-matching, to provide generic targets. For example:
%.o: %.c
[TAB] actions
When % appears in the dependency list, it is replaced with the same string that was used to perform substitution in the target.
If the above explanation is not clear just go through the Makefile Basics once and try writing without using special variables and then go to the complex rules.

How to define a pattern which is valid for all files in the directory including subdirectories?

I'm writing a pattern for compiling all .c file in the test directory.
Details of the directory is as follows:
./prj/makefile
./prj/test
./prj/test/test1/a.c
./prj/test/test1/b.c
./prj/test/test2/c.c
./prj/test/test2/d.c
./prj/test/e.c
...
Just a demo. This is my content of makefile:
# Find all files
rwildcard := $(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2))
# All .c files
SRC_FILES := $(call rwildcard,test,*.c)
# All .o files
OBJ_FILES := $(SRC_FILES:.o=.c)
all : $(OBJ_FILES)
echo $(OBJ_FILES)
%.o : %.c
echo $# $<
Make prints No rule to make target '...'. I think make need know path of .o files and .c files. But I don't know how to setting the path, Since there is so many .c files in my prj.
Because OBJ_FILES has includes all .o files. Then I guess the pattern should be like this:
$(output_dir)/%.o : $(input_dir)/%.c
echo $# $
Since here may have many directories in ./prj/test, I cann't hardcoded it in makefile
Thanks for another friend, the above approach is right. since % can match many Multi-level directories。
We can't really solve your problem because you still have not specified where the object files should go. All in a specific directory? Always in the parent directory of the source file? Somewhere else?
Regardless of how you resolve that, you can add all your source directories to VPATH and have Make resolve the precise location while figuring out the dependencies.
VPATH=test:test/test1:test/test2
experiment: a.c d.c
echo $^
will echo test/test1/a.c test/test2/d.c with full paths.
So with this you can remove the hard-coded directory names from your %.o rule and simply specify which .o files you want built for the all target.
You can use this to get all c files in subdirectories:
$(wildcard */*.c)
Or also this to get all c files in subdirectories at any depth:
$(wildcard **/*.c)

How to ensure a target is run before all the other build rules in a makefile?

I have a C++ project which contains a generated file that all the other C++ files depend on. I'm trying to force that file to be generated and compiled before any other compilation begins. Usually it'd be as simple as putting that file first in the all: target, but the complication is that my Makefile is also generated by a build system, and I can only append fragments to the Makefile, not edit it in general.
So, is there a way to force that generated file target to run first, via dependencies or otherwise? I've thought of using something like this:
cpp_files := $(wildcard src/*.cpp)
$(cpp_files): generated_file.cpp
generated_file.cpp:
# generate the file here
But it doesn't seem to work. For reference, my source dir structure is like this, so I need to collect the cpp files recursively:
src/
|---file1.cpp
|---file2.cpp
|---subdir1/
|---file3.cpp
gen/
|---generated_file.cpp
If you're sure that's really what you want, here's one way to do it: have a rule for a dummy file which the makefile will include.
.PHONY: dummy
dummy:
# generate the file here
-include dummy
No matter what target you specify, Make will first run the dummy rule, then restart itself.
Actually, other cpp files don't depend on the generated one (in terms of Make rules). Dependency graph still looks like:
program
|
^- file1.o
| ^- file1.c
|
^- file2.o
| ^- file2.c
|
^- generated_file.o
^- generated_file.c
^- <generator prerequisites>
Your source files could only depend on some kind of generated header file (in case when it is #included by these sources).
If you need to generate only a cpp file then the following makefile should be sufficient:
srcs := $(wildcard src/*.cpp src/*/*.cpp)
gen_file := gen/generated_file.cpp
srcs += $(gen_file)
objs := $(srcs:.cpp=.o)
.PHONY : all
all : program
program : $(objs)
#$(LD) ...
%.o : %.c
#$(CC) ...
$(gen_file) :
# generate the file here
UPD.
A little improvement based on Beta's answer.
-include generator-task
.PHONY : generator-task
generator-task : $(gen_files)
$(gen_files) : $(gen_prerequisites)
# generate the file here
Instead of running generator on each invocation of Make, this will only regenerate a file when one of its prerequisites would change.

Writing makefile for source files across different directories

I am stuck in writing a Makefile when my source code files are across different directories.
The directory structure is as follows :
I have my source files (.cc) in the folders FOLDER1 and FOLDER2 and the header files are in folder named INCLUDE. My makefile is present in FOLDER1.
program_NAME := myprogram
program_C_SRCS := $(wildcard *.cc)
program_C_OBJS := ${program_C_SRCS:.cc=.o}
program_OBJS := $(program_C_OBJS)
program_INCLUDE_DIRS := ../INCLUDE
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
Here if I keep all my source (.cc) files in FOLDER1 then it works but on moving some files to FOLDER2 it gives errors of undefined reference.
Please help me understand how to modify my makefile so that I can keep all my header files in one directory say INCLUDE and distribute my source files across different directories.
Thanks !!!
The problem is, that
program_C_SRCS := $(wildcard *.cc)
only adds source files in the same directory. So when linking you don't have the object files of your second folder. You probably can solve the problem by simply adding the source files of the other folder to your program_C_SRCS:
program_C_SRCS += $(wildcard ../FOLDER2/*.cc)
Include directorys
I guess you are using the gcc/g++, in this case http://gcc.gnu.org/onlinedocs/cpp/Search-Path.html says, that header paths are searched from left to right, meaning the first path given is searched first. Therefore you only have to add -I INCLUDE2 before -I INCLUDE1 option to achive what you want.
Your starting makefile already has some transformation for more then one include path build in:
CPPFLAGS += $(foreach includedir,$(program_INCLUDE_DIRS),-I$(includedir))
So you only have to rewrite your include paths:
program_INCLUDE_DIRS := ../INCLUDE2
program_INCLUDE_DIRS += ../INCLUDE1

Resources