Makefiles output directory - linux

I am a bit a beginner in using makefiles and I am trying to write a makefile for gcc that accepts the inputs from two different directories (in my case they are called kernel and drivers) and output the object files in a different directory (called tmp) using wildcards.
I have written this code to get the names of input files and output files
C_SOURCES = $(wildcard $(KERNEL_DIR)/*.c $(DRIVERS_DIR)/*.c)
#Creating a list for object files names
C_OBJ = $(C_SOURCES:.c=.o)
and I am using the following rule
%.o: %.c $(CC) $(CFLAGS) -c $< -o $#
but i can't get to output the object files in the desired directory.files

Something like this example should do it for you. I split things up a bit for readability, but I'm sure you'll get the idea:
KERNEL_SOURCES = $(wildcard $(KERNEL_DIR)/*.c)
DRIVER_SOURCES = $(wildcard $(DRIVER_DIR)/*.c)
OBJECTS = $(patsubst $(KERNEL_DIR)/%.c,tmp/%.o,$(KERNEL_SOURCES))
OBJECTS += $(patsubst $(DRIVER_DIR)/%.c,tmp/%.o,$(DRIVER_SOURCES))
Watch out for source files with the same name in both KERNEL_DIR and DRIVER_DIR!

You have to make a separate rule for each subdirectory, like this:
SOURCES := $(wildcard $(KERNEL_DIR)/*.c $(DRIVER_DIR)/*.c)
OBJECTS := $(patsubst %.c,$(OBJECT_DIR)/%.o,$(notdir $(SOURCES)))
all: $(OBJECTS)
$(OBJECT_DIR)/%.o : $(KERNEL_DIR)/%.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $# $<
$(OBJECT_DIR)/%.o : $(DRIVER_DIR)/%.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $# $<
Obviously you'll have big problems if you have a foo.c file in both source directories...

Related

How to create makefile target for obj files generated in temporary directory?

I am trying to learn using makefiles again. I have a directory structure like this:
build
|- Makefile
|- Project files, like visual studio project
tmp
|- $(os name)_$(compiler)
|- *.o and any other intermediate files
bin
|- $(os name)_$(compiler)
|- the compiled binary executable
|- debug info, if any
src
|- *.cpp, *.h
So I made this Makefile after a bit of googling and experimenting:
CXX := g++
CXXFLAGS := -std=c++17 -Wall
LDFLAGS := -lpthread
ASSUMED_OS := unknownOS
SRC_DIR := ../src
EXTENSION :=
# OS detection and extension assignment for windows redacted for brevity
# ... detect OS, set extension to .exe if windows
COMPILE_PATH := $(ASSUMED_OS)_gcc
TMP_DIR := ../tmp/$(COMPILE_PATH)
TARGET_DIR := ../bin/$(COMPILE_PATH)
TARGET := $(TARGET_DIR)/MyProject$(EXTENSION)
# $(wildcard *.cpp /xxx/xxx/*.cpp): get all .cpp files from the current directory and dir "/xxx/xxx/"
SRCS := $(wildcard $(SRC_DIR)/*.cpp)
# $(patsubst %.cpp,%.o,$(SRCS)): substitute all ".cpp" file name strings to ".o" file name strings
OBJS := $(patsubst %.cpp,%.o,$(SRCS))
all: $(TARGET)
# Compile all obj files into an executable
$(TARGET): $(OBJS)
#mkdir -p $(#D)
$(CXX) -o $# $^ $(LDFLAGS)
# Compile all CPP files in separate obj files
%.o: %.cpp
#mkdir -p $(#D)
$(CXX) $(CXXFLAGS) -c $< -o $#
clean:
rm -rf $(TARGET) ../*.o
.PHONY: all clean
This works, but it creates the .o files next to the sources.
So I tried to change the OBJS variable and replace the path:
OBJS := $(patsubst %.cpp,%.o,$(SRCS))
# Substitute src path for tmp directory path
OBJS := $(patsubst $(SRC_DIR)/%,$(TMP_DIR)/%,$(OBJS))
But then I get an error:
make: *** No rule to make target '../tmp/linux_gcc/Job.o', needed by '../bin/linux_gcc/MyProject'. Stop.
So I tried to create a different target, one that I thought would map the object file names that should be in ../tmp/linux_gcc to the source names from ../src:
# $(wildcard *.cpp /xxx/xxx/*.cpp): get all .cpp files from the current directory and dir "/xxx/xxx/"
SRCS := $(wildcard $(SRC_DIR)/*.cpp)
# $(patsubst %.cpp,%.o,$(SRCS)): substitute all ".cpp" file name strings to ".o" file name strings
OBJS := $(patsubst %.cpp,%.o,$(SRCS))
# Substitute src path for tmp directory path
OBJS := $(patsubst $(SRC_DIR)/%,$(TMP_DIR)/%,$(OBJS))
all: $(TARGET)
# Compile all obj files into an executable
$(TARGET): $(OBJS)
#mkdir -p $(#D)
$(CXX) -o $# $^ $(LDFLAGS)
# Compile all CPP files in separate obj files
$(OBJS): $(SRCS)
#mkdir -p $(#D)
$(CXX) $(CXXFLAGS) -c $< -o $#
But when I do that, make always compiles the same cpp file for each .o file:
g++ -std=c++17 -Wall -c ../src/Job.cpp -o ../tmp/linux_gcc/Job.o
g++ -std=c++17 -Wall -c ../src/Job.cpp -o ../tmp/linux_gcc/Worker.o
g++ -std=c++17 -Wall -c ../src/Job.cpp -o ../tmp/linux_gcc/WorkManager.o
I think I am quite close, but how can I get this to work? I think that in the compile command $(CXX) $(CXXFLAGS) -c $< -o $# I need something else than $< for the input file, but I am not sure what.
In your first makefile:
SRC_DIR := ../src
...
SRCS := $(wildcard $(SRC_DIR)/*.cpp)
...
OBJS := $(patsubst %.cpp,%.o,$(SRCS))
...
%.o: %.cpp
#mkdir -p $(#D)
$(CXX) $(CXXFLAGS) -c $< -o $#
Yes, this "creates the .o files next to the sources". If you have a source foo.cpp, the variable OBJS will contain ../src/foo.o, and the rule will build it.
In your second attempt you have changed the object, but you haven't changed the rule, so the only way Make knows to build ../tmp/linux_gcc/Job.o is from ../tmp/linux_gcc/Job.cpp, which doesn't exist.
On your third attempt you have the right idea, but there's a flaw in your rule:
$(OBJS): $(SRCS)
#mkdir -p $(#D)
$(CXX) $(CXXFLAGS) -c $< -o $#
The variable $(OBJS) is a list of objects, $(SRCS) is a list of sources, so each object depends on all sources. And the automatic variable $< expands to the first item in the prerequisite list, which in this case is ../src/Job.cpp, so no matter which object you choose, Make will try to build it by compiling that source.
This is a job for a static pattern rule:
$(OBJS): $(TMP_DIR)/%.o: $(SRC_DIR)/%.cpp
#mkdir -p $(#D)
$(CXX) $(CXXFLAGS) -c $< -o $#

Multiple SRCDIR folders for compilation using makefile

I am trying to do the following, where SRCDIRS includes all folders containing the source code by doing the following in the makefile:
SRCDIRS := $(shell find $(SRCDIR) -type d )
$(OBJDIR)/%.o: $(SRCDIRS)/%.f90 Makefile
#$(F90) $(FFLAGS) $(POPTIONS) -o $# $<
My make file seems to ignore the %.o rule?
I also have a defined $(OBJS) which includes all my %.o files
You can't "multiply" strings that way in Make. And even if you could, you'd be specifying the wrong paths. Use vpath:
vpath %.f90 $(SRCDIRS)
$(OBJDIR)/%.o: %.f90 Makefile
#$(F90) $(FFLAGS) $(POPTIONS) -o $# $<

Makefile Wildcard Issues

So I am having some issues understanding how exactly the % wildcard actually works using makefile. I have looked at static pattern rules in the GNU make man but i am still pretty confused and I feel like I have seen them do something similar to what I have below.
EXEC = a.out
CC = gcc
FLAGS = -Wall -c
$(EXEC): %.o
$(CC) -o $(EXEC) $<
%.o: %.c
$(CC) $(FLAGS) $<
clean:
rm -rf *.o
I keep getting an error that says %.o rule not defined. If someone could explain why this is wrong (probably in many ways, guessing the automatic variable part is incorrect as well) that would be appreciated !
I'm not sure what you intend, but I'm pretty sure that this rule:
$(EXEC): %.o
$(CC) -o $(EXEC) $<
doesn't do it. In this rule, '%' is not any kind of wildcard, it's just a character. So when Make tries build a.out, it goes looking for a file called %.o, can't find it, doesn't have a rule to build it (since there is no %.c and no way to build that), and gives up.
Your intention is unclear. If you want the rule to be able to build a.out from a.o (and likewise foo.out from foo.o, and bar.out from bar.o, and so on), write a pattern rule:
%.out: %.o
$(CC) -o $# $<
$(EXEC): # Make will not use a pattern rule as the default, so we need this
(Note the use of $#.) Or (to restrict it to executables in the EXEC list) a static pattern rule:
$(EXEC): %.out : %.o
$(CC) -o $# $<
If, on the other hand, you want Make to use all the source files it can find to build this executable, you must do something like this:
SOURCES = $(wildcard *.c) # make a list a.c foo.c bar.c
OBJECTS = $(patsubst %.c, %.o, $(SOURCES)) # translate it into a.o foo.o bar.o
$(EXEC): $(OBJECTS)
$(CC) -o $^ $<
Note the use of the wildcard function, and $^ which expands to the list of prerequisites, and also note that "*.o" wouldn't do you much good.
when I used to use makefiles long time ago they looked more like below. For each executable we listed the required object files explicitly.
CC = gcc
FLAGS = -Wall -c
prog1: mod1.o mod2.o
$(CC) mod1.o mod2.o -o prog1
prog2: mod1.o mod3.o
$(CC) mod1.o mod3.o -o prog2
%.o: %.c
$(CC) $(FLAGS) $<
clean:
rm -rf *.o

Makefile export .o file to a different path than .cpp

So my task is simple, I have created the makefile (New with makefiles) and I want to keep my .o files in a different folder to have a cleaner directory and allow the usage of .o files by others.
I searched and found many solution pointing to using -o $< $#
However, it is giving me that g++: cannot specify -o with -c or -S with multiple files
This is what I want to do:
$(OBJECT_PATH)/file1.o: $(SOURCE_PATH)/file2.cpp $(SOURCE_PATH)/file1.cpp
$(CC) $(CFLAGS) $(SOURCE_PATH)/file2.cpp $(SOURCE_PATH)/file1.cpp -o $#
file1.cpp has #include "file1.h", so from what I read I should include file1.cpp in the dependencies. However, now I can't export to a different directory.
Is there a solution? Or do I have the concept wrong?
Use make -d or even better remake -x to understand what commands are invoked.
Run also make -p to understand what builtin rules are used.
We cannot help you more, because we have no idea if you redefined CFLAGS.
And C++ compilation should better be done with g++ that is CXX and CXXFLAGS, e.g. with (I am extracting this from my make -p output)
LINK.cc = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
COMPILE.cc = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
CXX = g++
%.o: %.cc
$(COMPILE.cc) $(OUTPUT_OPTION) $<
I strongly suggest to have CXXFLAGS= -Wall -g at least during the development phase. Learn also to use gdb and valgrind.
You could have the following in your Makefile
CXXFLAGS= -g -Wall
SOURCES=f1.cc f2.cc
SOURCE_PATH=yoursourcedir/
OBJECT_PATH=yourobjectdir/
SRCFILES=$(patsubst %.cc,$(SOURCE_PATH)/%.cc,$(SOURCES))
OBJFILES=$(patsubst %.cc,$(OBJECT_PATH)/%.o,$(SOURCES))
PROGFILE=$(OBJECT_PATH)
.PHONY: all clean
all: $(PROGFILE)
$(PROGFILE): $(OBJFILES)
$(LINK.cc) $^ $(LOADLIBES) $(LDLIBS) -o $#
$(OBJECT_PATH)/%.o: $(SOURCE_PATH)/%.cc
$(COMPILE.cc) $(OUTPUT_OPTION) $<
clean:
$(RM) $(OBJECT_PATH)/*.o $(PROGFILE)
try
$(OBJECT_PATH)/file1.o: $(SOURCE_PATH)/file2.cpp $(SOURCE_PATH)/file1.cpp
$(CC) $(CFLAGS) $^ -c $#
and check that CFLAGS doesn't include -o -c or -s flags
also read about implicit rules. it might help you to orginzie your makefile

how to include .h document in makefile

I am programming for a big project, so I cooperate with others.
To make the directory easily managed, my directory is like below:
project:
--include (header files from others supplied for me)
--lib (libraries from others supplied for me)
--L3_CVS (this folder include all my files)
-- Makefile
-- sourceFile (all my source files here)
-- include_private(all header files used only by myself)
-- appl (all my C files here)
My Makefile is below:
####################################################
CROSS_COMPILE=/home/powerpc-wrs-linux-gnu/x86-linux2/powerpc-wrs-linux-gnu-ppc_e500v2-glibc_cgl-
EXTRA_CFLAGS += -g
EXTRA_LDFLAGS +=
LIBSB =-Wl,--start-group -ldiag -ldiag_esw -lacl -ldiagcint -lcint -lsal_appl -lsal_appl_editline -lsal_appl_plat\
-lbcm -lbcm_esw -lbcm_common -lfirebolt -ltitan -ltrident -lhumv -lbradley -lherc -ldraco -lscorpion\
-ltriumph -ltrx -ltriumph2 -lenduro -lkatana -lflexctr -lptp -lsoc_esw -lsoc -lsoc_phy -lsoc_mcm\
-lsoccommon -lsoc_shared -lshared -lsal_core -lsal_core_plat -lcustomer -lsoc_nemo -lsoc_clsbuilder\
-lsoc_sal \
-lbcm_compat -lbcm_rpc -lcpudb -ltrx -lstktask -llubde -ldrivers -ldiscover -lcputrans \
-lrcu -lpthread -lrt -lm -Wl,--end-group
LIBS = -ldiag -lrcu
CC = $(CROSS_COMPILE)gcc
LD = $(CROSS_COMPILE)ld
AR = $(CROSS_COMPILE)ar
STRIP = $(CROSS_COMPILE)strip
SRC_PATH := ./SourceFile/appl
HEAD_PATH := ./SourceFile/include-private
INC_DIR = ../include
LIB_PATH = ../lib
APP_NAME = L3appl
SRCS := $(wildcard $(SRC_PATH)/*.c)
export $(SRCS)
OBJS:= $(patsubst %.c,%.o,$(SRCS))
%.d: %.c
#set -e; rm -f $#; \
$(CC) -MM $< > $#.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $# : ,g' < $#.$$$$ > $#; \
rm -f $#.$$$$
sinclude $(SRCS:.c=.d)
INCLUDES = $(wildcard $(HEAD_PATH)/*.h)
$(APP_NAME):$(OBJS)
$(CC) -c -I$(INC_DIR) $(SRCS)
$(CC) -o $(APP_NAME) $(OBJS) -L$(LIB_PATH) $(LIBSB) -lpthread -lrt -lm
.PHONY:clean
clean:
rm -f $(OBJS) $(APP_NAME)
#################################################
My problem is that when I run make in terminal, it always show : ***No such file or directory
compilation terminated. which seems the .h files in ./SourceFile/include-private do not be included.
But, in fact, I have use "INCLUDES = $(wildcard $(HEAD_PATH)/*.h)" include these .h files.
I don't know where is wrong!
this is my first time to write makefile. So if there are mistakes in my makefile, I would appreciate that you would point them out !
thank you for your help very much!!!!!!!
You should have something like
CFLAGS = -Wall $(OPTIMFLAGS) $(INCLUDEFLAGS)
INCLUDEFLAGS = -I $(INC_DIR) -I $(HEAD_PATH)
OPTIMFLAGS = -g -O
You can use remake to debug your Makefile.
You can try to change $(CC) -c -I$(INC_DIR) $(SRCS) to $(CC) -c -I$(INC_DIR) -include $(INCLUDES) $(SRCS)
or $(CC) -c -I$(INC_DIR) $(SRCS) to $(CC) -c -I$(INC_DIR) -I$(INCLUDES) $(SRCS)
where INCLUDES is ./SourceFile/include-private (only the directory, no .h files)
Edit: Usually you don't have to explicitly include the .h files, but that's what the first change do. The second change does not add the .h files explicitely but provide the compiler another include directory where it could search for necessary .h files.
Refer to GCC man file for more info.
Regards

Resources