How to compile files that reside in different directory in Makefile? - 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)?

Related

Makefile to generate a binary file for each source file

I have the following structure in my project.
/
src/
bin/
Makefile
In src directory there will be multiple src files (each has a main function). I need to write makefile such that when I run
make program1
It should search for program1.c in src folder and compile the executable as program1* in bin folder.
I have came across this question How can Makefile use separate directories for source code and binaries?
But, it seems that I need to manually enter all program names into PROG variable.
I just need to supply binary name with make and it should do the compilation for that respective src file?
Okay, after a bit of experimentation with my Makefile. I finally got the solution for my problem.
Current Build System
CC = gcc
CFLAGS = -g -Wall
SRC = ./src/
BIN = ./bin/
%: $(SRC)%.c
$(CC) $(CFLAGS) $< -o $(BIN)$#
.PHONY: clean
clean:
rm $(BIN)*

Makefile pattern to compile all source files to executables

I want my makefile to identify and build every source file in the directory.
Both .f files and their executables exists in the current directory. All source files are short, independent pieces (no linking to each other). I want executables to be named the same as the source files sans .f (foo.f -> foo)
The following does not work:
FC=gfortran
% :: %.f
${FC} -Wall $< -o $#
When I run Make I get
make: *** No targets. Stop.
How can I get make to do what I want?
The following makefile does what I want:
FC=gfortran
FFLAGS=-Wall
SRC = $(wildcard *.f)
EXE = $(SRC:.f=)
all : $(EXE)

Create directories when generating object files in gcc

gcc -o abc/def.o def.c generates def.o file in a directory abc; only when there exists a directory abc.
Is there a way to make gcc to create a directory when the enclosing directory of the generated object file does not exist? If not, what could be the easiest way to make the directory in advance automatically, especially for Makefile?
From this post, it seems like that there is no way to create a directory from gcc.
For makefile, I can use this code snippet.
OBJDIR = obj
MODULES := src src2
...
OBJDIRS := $(patsubst %, $(OBJDIR)/%, $(MODULES))
build: $(OBJDIRS)
echo $^
$(OBJDIRS):
mkdir -p $#
make build will create directories, and echo the results.
We also can make the object files are created automatically without invoking the make build.
PROG := hellomake
LD := gcc
...
$(PROG): $(OBJDIRS) obj/src/hellofunc.o obj/src/hellomake.o
$(LD) $(filter %.o, $^) -o $(PROG)
The way I do it is I find out what the paths will be, and create the dirs for them:
SOURCES:=$(shell find $(SRC)/ -type f -name '*.c') #Get all the c files
#Get the files they're gonna be compiled to
OBJECTS:=$(patsubst $(SRC)/%.c, $(OBJ)/%.o, $(SOURCES))
#Get just the paths so you can create them in advance
OBJDIRS:=$(dir $(OBJECTS))
#call mkdir with the directories (using a dummy var because too much
#trouble to deal with priorities) someone could prob do better
#--parents ignores the repeated and already existing errors
DUMMY:=$(shell mkdir --parents $(OBJDIRS))
Sauce:
https://www.gnu.org/software/make/manual/html_node/File-Name-Functions.html
In addition to precedent solutions, you can create the directories in your rule for building your .o files
$(OBJ_DIR)/%.o: $(SRCS_DIR)/%.c
#mkdir -p $(shell dirname $#)
$(CC) $(CFLAGS) $(INC) -c $< -o $#
The "#" before mkdir silent the output of mkdir (we don't want a message for each directory created).
The "-p" option tell mkdir to create all intermediate directories in path if they do not exist.
The "dirname" method takes the file path ("$#") and keep only the file directory path.

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)

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