SRC_DIRS += $(CMM_DIR)
SRC_DIRS += $(ABC_DIR)
VPATH = $(SRC_FILES)
tear_abc123: $(OBJ)/ur23.o
$(CC) $(CFLAGS) -c $(subst tear_,,$#.c) $#.c $#_compiletime.c -o $#
In this, $#_compiletime.c (say tear_abc123_compiletime.c) gets generated before $(CC). make throws an error that abc123.c is not found. where abc123.c is present in $(ABC_DIR). Why vpath is could not find the c file.
The main problem is that VPATH works only for Prerequisites. And it does not work from the 'command' part of the target.
To make VPATH work you should specify list of sources in Prerequisites and reference it in the command using $^.
Please see the following example (for file tree as below)
.
|-- abc
| |-- abc123.c
| |-- tear_abc123.c
| `-- tear_abc123_compiletime.c
`-- Makefile
Makefile contains
SRC_DIRS := abc
VPATH := $(SRC_DIRS)
TARGET := tear_abc123
SOURCE_FILES := $(TARGET).c $(TARGET)_compiletime.c $(subst tear_,,$(TARGET).c)
tear_abc123: $(SOURCE_FILES)
#echo "SOURCE_FILES := $(SOURCE_FILES)"
#echo "prerequisites = $^"
The output will be
$ make
SOURCE_FILES := tear_abc123.c tear_abc123_compiletime.c abc123.c
prerequisites = abc/tear_abc123.c abc/tear_abc123_compiletime.c abc/abc123.c
As you can see
the SOURCE_FILES really contains only source files names
the prerequisites is automatically substituted with correct path
Related
I have been working with a project that only compiles C sources but I've found I need some assembler too, I'm reticent to inline the asm code in a C file as GCC may not interpret it correctly.
My predecesor created the makefile for the project (apologies, it's fairly long):
# Compiler and options
CC := sparc-rtems-gcc
# The application software binary
TARGET := icu_asw
# Source and build directories
SRCDIR := src
BUILDDIR := obj
TARGETDIR := bin
HDSWROOT := ../../hdsw
BSWTOOLS := ../../bsw/sw/tools
SRCEXT := c
DEPEXT := d
OBJEXT := o
MRAMEXT := img.elf
# Flags, libraries and includes
CFLAGS := -std=gnu99 -Wall -Wextra -g
LIBDRV := $(HDSWROOT)/lib/libdrv.a
INCFLAGS := -I$(HDSWROOT)/include -I$(HDSWROOT)/osal/rtems
# Debug flags
DEBUGFLAGS = -DLOGERROR=1 -DLOGWARN=1 -DLOGDEBUG=1 -DLOGINFO=1 -DMAKECHECKS=1
NODEBUGFLAGS = -DLOGERROR=1 -DLOGWARN=0 -DLOGDEBUG=0 -DLOGINFO=0 -DMAKECHECKS=1
#-----------------------------------------------------------------------
# Build instructions
#-----------------------------------------------------------------------
SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT))
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.$(OBJEXT)))
# Default make
all: $(TARGET)
# Remake
remake: cleaner all
# Clean only objects
clean:
#$(RM) -rf $(BUILDDIR)
# Full clean (objects and binaries)
cleaner: clean
#$(RM) -rf $(TARGETDIR)
# Pull in dependency info for *existing* .o files
-include $(OBJECTS:.$(OBJEXT)=.$(DEPEXT))
# Link (uses an order-only prerequisite for the directories so that they
# don't affect the use of the $^)
$(TARGET): $(OBJECTS) | directories
$(CC) -o $(TARGETDIR)/$(TARGET) $^ $(LIBDRV)
# Make the build and target directories
directories:
#mkdir -p $(TARGETDIR)
#mkdir -p $(BUILDDIR)
# Compile
$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT)
#mkdir -p $(dir $#)
$(CC) $(CFLAGS) $(INCFLAGS) $(NODEBUGFLAGS) -c -o $# $<
#$(CC) $(CFLAGS) $(INCDEP) -MM $(SRCDIR)/$*.$(SRCEXT) > $(BUILDDIR)/$*.$(DEPEXT)
#cp -f $(BUILDDIR)/$*.$(DEPEXT) $(BUILDDIR)/$*.$(DEPEXT).tmp
#sed -e 's|.*:|$(BUILDDIR)/$*.$(OBJEXT):|' < $(BUILDDIR)/$*.$(DEPEXT).tmp > $(BUILDDIR)/$*.$(DEPEXT)
#sed -e 's/.*://' -e 's/\\$$//' < $(BUILDDIR)/$*.$(DEPEXT).tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $(BUILDDIR)/$*.$(DEPEXT)
#rm -f $(BUILDDIR)/$*.$(DEPEXT).tmp
# Non-File Targets
.PHONY: all remake clean cleaner
I want to also bring in and compile two .S files, so, I edited the following line
SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT) -or -name *.$(ASMEXT))
To bring in the .S files, then I edited the OBJECTS to also include the ASM sources ("*.S")
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.$(OBJEXT)),$(SOURCES:.$(ASMEXT)=.$(OBJEXT)))
But when recompiling with 'make all' I'm getting:
$ make all
make: *** No rule to make target `obj/asi_access.S', needed by `icu_asw'. Stop.
I don't suppose someone could spot where I am going wrong? I think I have not correctly added to the OBJECTS line!
Thanks
The expression $(var:.ext1=.ext2) does not filter by .ext1, i.e.
$(SOURCES:.$(SRCEXT)=.$(OBJEXT)) $(SOURCES:.$(ASMEXT)=.$(OBJEXT))
gives for a test source list the following result
a.o b.o c.S a.c b.c c.o
I.e. you duplicated your files and you have source files in the OBJECTS definition.
The following would be a correct approach:
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%, \
$(patsubst %.$(SRCEXT),%.$(OBJEXT), \
$(patsubst %.$(ASMEXT),%.$(OBJEXT),$(SOURCES)) \
) \
)
UPDATE: you should consider to use 2 separate object lists, so that you can apply different rules for them, e.g.
SOURCES_C := $(filter %.$(SRCEXT),$(SOURCES))
OBJECTS_C := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES_C:%.$(SRCEXT)=%.$(OBJEXT)))
SOURCES_ASM := $(filter %.$(ASMEXT),$(SOURCES))
OBJECTS_ASM := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES_ASM:%.$(ASMEXT)=%.$(OBJEXT)))
$(OBJECTS_C): $(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT)
.... C compiler recipe ....
$(OBJECTS_ASM): $(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(ASMEXT)
.... assembler recipe ....
$(TARGET): $(OBJECTS_C) $(OBJECTS_ASM) | directories
I'm using GNU Make and attempting to design Makefiles using non-recursive approach. The issue I have - there doesn't seem to be a way to limit the scope of variables in different Makefiles.
For example, if I have two Makefiles for modules libA and libB
libA Makefile.inc:
src_dir := libA/src
inc_dir := libA/inc
libB Makefile.inc:
src_dir := libB/src
inc_dir := libB/inc
Then when I include the above Makefiles into a master Makefile
include libA/Makefile.inc
include libB/Makefile.inc
Values in variables src_dir and inc_dir are overwritten by the very last Makefile that was included. OK this is probably expected since variables are global in scope here, and this messes up build commands that use those variables, i.e. build command for libA finds variable values for libB.
A way around it is to create unique variables for each Makefile
libA Makefile.inc:
src_dir_libA := libA/src
inc_dir_libA := libA/inc
libB Makefile.inc:
src_dir_libB := libB/src
inc_dir_libB := libB/inc
This solves the issue, but it's a bit awkward to use, since each variable has to be renamed. Does anyone know if there is a better way to solve this, e.g. if GNU Make has some notion of scope or namespace? I've looked at documentation, but can't seem to find anything of that sort. There are target-specific variables, but they appear to have nasty side-effects.
OK, just to be very specific, below is an example Makefile
dep_all :=
all:
# Begin Makefile.inc for project1
# ------------------------------------------------------------------------------
$(foreach var,$(filter local_%,$(.VARIABLES)),$(eval $(var) := ))
local_src_dir := project1/src
local_obj_dir := project1/obj
local_src := $(local_src_dir)/fileA.c $(local_src_dir)/fileB.c
local_obj := $(patsubst $(local_src_dir)/%.c,$(local_obj_dir)/%.o,$(local_src))
dep_all += $(local_src)
dep_all += $(local_obj)
$(info local_obj="$(local_obj)")
$(local_obj): $(local_obj_dir)/%.o: $(local_src_dir)/%.c
gcc -L$(local_obj_dir) -c -o $# $<
# ------------------------------------------------------------------------------
# End Makefile.inc for project1
# Begin Makefile.inc for project2
# ------------------------------------------------------------------------------
$(foreach var,$(filter local_%,$(.VARIABLES)),$(eval $(var) := ))
local_src_dir := project2/src
local_obj_dir := project2/obj
local_src := $(local_src_dir)/fileX.c $(local_src_dir)/fileY.c
local_obj := $(patsubst $(local_src_dir)/%.c,$(local_obj_dir)/%.o,$(local_src))
dep_all += $(local_src)
dep_all += $(local_obj)
$(info local_obj="$(local_obj)")
$(local_obj): $(local_obj_dir)/%.o: $(local_src_dir)/%.c
gcc -L$(local_obj_dir) -c -o $# $<
# ------------------------------------------------------------------------------
# End Makefile.inc for project2
$(info dep_all="$(dep_all)")
.PHONY: all
all: $(dep_all)
.PHONY: clean
clean:
rm -f project1/obj/* project2/obj/*
If I run it then the -L<object_path> option passed to gcc contains value from the last included Makefile, i.e. when building project1, it runs gcc with -Lproject2/obj, which is not the right object path for this project. This is the problem I'm trying to solve.
mkdir -p project1/{src,obj} project2/{src,obj}
touch project1/src/{fileA.c,fileB.c} project2/src/{fileX.c,fileY.c}
$ make
local_obj="project1/obj/fileA.o project1/obj/fileB.o"
local_obj="project2/obj/fileX.o project2/obj/fileY.o"
dep_all=" project1/src/fileA.c project1/src/fileB.c project1/obj/fileA.o project1/obj/fileB.o project2/src/fileX.c project2/src/fileY.c project2/obj/fileX.o project2/obj/fileY.o"
gcc -Lproject2/obj -c -o project1/obj/fileA.o project1/src/fileA.c
gcc -Lproject2/obj -c -o project1/obj/fileB.o project1/src/fileB.c
gcc -Lproject2/obj -c -o project2/obj/fileX.o project2/src/fileX.c
gcc -Lproject2/obj -c -o project2/obj/fileY.o project2/src/fileY.c
The solution is to name all your variables local to a specific file with some prefix.
For example, I use this_ prefix.
Then, in the beginning of each submakefile those variales which have this_ prefix can be cleared as follows:
$(foreach var,$(filter this_%,$(.VARIABLES)),$(eval $(var) := ))
PS. I use this approach in my implementation of non-recursive makefiles, clearing the variables described in the WIKI here: https://github.com/cppfw/prorab
I think I've just figured out a solution. I was reading "The GNU Make Book" and it states a side effect of target specific variables
Target-specific variables apply not just to a target, but also to all
that target’s prerequisites, as well as all their prerequisites, and
so on. A target-specific variable’s scope is the entire tree of
targets, starting from the target for which the variable was defined.
This is not the behaviour I want, however starting with GNU Make 3.82 there is support for private target specific variables
A target-specific variable is normally defined for a target and all
its prerequisites. But if the target-specific variable is prefixed
with the keyword private, it is defined only for that target, not its
prerequisites.
So the following Makefile seems to work correctly for those private variables
dep_all :=
all:
# Begin Makefile.inc for project1
# ------------------------------------------------------------------------------
inc_dir := project1/inc
src_dir := project1/src
obj_dir := project1/obj
src := $(src_dir)/fileA.c $(src_dir)/fileB.c
obj := $(patsubst $(src_dir)/%.c,$(obj_dir)/%.o,$(src))
# These flags will be overwritten by another Makefile
CFLAGS := -I$(inc_dir)
# These flags will be private and not be overwritten by another Makefile
CFLAGS_priv := -I$(inc_dir) -L$(obj_dir)
dep_all += $(src)
dep_all += $(obj)
# Private target specific variables
$(obj): private CFLAGS_priv:=$(CFLAGS_priv)
$(obj): $(obj_dir)/%.o: $(src_dir)/%.c
gcc $(CFLAGS) $(CFLAGS_priv) -c -o $# $<
# ------------------------------------------------------------------------------
# End Makefile.inc for project1
# Begin Makefile.inc for project2
# ------------------------------------------------------------------------------
inc_dir := project2/inc
src_dir := project2/src
obj_dir := project2/obj
src := $(src_dir)/fileX.c $(src_dir)/fileY.c
obj := $(patsubst $(src_dir)/%.c,$(obj_dir)/%.o,$(src))
# These flags will be overwritten by another Makefile
CFLAGS := -I$(inc_dir)
# These flags will be private and not be overwritten by another Makefile
CFLAGS_priv := -I$(inc_dir) -L$(obj_dir)
dep_all += $(src)
dep_all += $(obj)
# Private target specific variables
$(obj): private CFLAGS_priv:=$(CFLAGS_priv)
$(obj): $(obj_dir)/%.o: $(src_dir)/%.c
gcc $(CFLAGS) $(CFLAGS_priv) -c -o $# $<
# ------------------------------------------------------------------------------
# End Makefile.inc for project2
.PHONY: all
all: $(dep_all)
.PHONY: clean
clean:
rm -f project1/obj/* project2/obj/*
The output is what I wanted, since now for each project I can define private CFLAGS_priv variable that sets -I<dir>, -L<dir> paths and it won't be overwritten by other Makefiles.
$ make
gcc -Iproject2/inc -Iproject1/inc -Lproject1/obj -c -o project1/obj/fileA.o project1/src/fileA.c
gcc -Iproject2/inc -Iproject1/inc -Lproject1/obj -c -o project1/obj/fileB.o project1/src/fileB.c
gcc -Iproject2/inc -Iproject2/inc -Lproject2/obj -c -o project2/obj/fileX.o project2/src/fileX.c
gcc -Iproject2/inc -Iproject2/inc -Lproject2/obj -c -o project2/obj/fileY.o project2/src/fileY.c
I'm hoping this will resolve all issues I had and I don't have to use recursive make with it's various associated pitfalls.
I am grouping some type of files like:
https://www.gnu.org/software/make/manual/html_node/Wildcard-Function.html
about 100 sub directories...
CC_FILES_TO_BUILD += $(wildcard $(SRC_DIR)/01-Application/*.c)
ASM_FILES_TO_BUILD += $(wildcard $(PROJECT_ROOT)/01-Sources/07-Target/01-MC9S12G/04-STARTUP/01-CPL_LIB/*.s)
When I dump for example CC_FILES_TO_BUILD per rule, I get nice lists of files names:
E:\1983_1\02-Safety>make dump-CC_FILES_TO_BUILD
make[1]: Entering directory `E:/1983_1/02-Safety/01-Application'
E:\1983_1\02-Safety\01-Application/01-Sources//01-Application/01-INIT/app_init.c E:\1983_1\02-Safety\01-Application/01-Sources//01-Applicat
ion/02-MAIN/app.c E:\1983_1\02-Safety\01-Application/01-Sources//01-Application/03-FM/fm.c E:\1983_1\02-Safety\01-Application/01-Sources//01
-Application/05-SMCM/SMCM.c E:\1983_1\02-Safety\01-Application/01-Sources//01-Application/06-LIM/LIM.c E:\1983_1\02-Safety\01-Application/0
1-Sources//02-Services/01-CanM/can_user.c E:\1983_1\02-Safety\01-Application/01-Sources//02-Services/01-CanM/v_par.c E:\1983_1\02-Safety\01-
Application/01-Sources//02-Services/01-CanM/vstdlib.c E:\1983_1\02-Safety\01-Application/01-Sources//02-Services/01-CanM/sip_vers.c ...
......make[1]: Leaving directory `E:/1983_1/02-Safety/01-Application'
I then build new lists out these by normal subst to get the corresponding lists of depend and obj files, like:
CC_TO_MAK_BUILD_LIST = $(call unique, $(foreach src,$(CC_FILES_TO_BUILD ),
$(DEP_PATH)\$(basename $(notdir$(subst,\,/,$(SRC)))).$(MAK_FILE_SUFFIX)))
I then want to use these depend and obj lists as targets in rules like:
$(filter-out $(GCC_IGNORE_LIST), $(CC_TO_MAK_BUILD_LIST)) :$(DEP_OUTPUT_PATH)\\%.$(MAK_FILE_SUFFIX):$(DEPEND_FORCE) | $(DEPEND_CPP_OPTIONS_FILE) $(DIRECTORIES_TO_CREATE)
$(SEPARATOR) [depend] $(notdir $#)
$(CPP) #$(DEPEND_CPP_OPTIONS_FILE) -undef -MM -MF "$#" -MT "$(call depend_get_target,$#)" -MT "$#" "$(getSourceFile)"
Then the target depend:
depend: $(LIB_TO_MAK_BUILD_LIST) $(CC_TO_MAK_BUILD_LIST) | $(DEPEND_CPP_OPTIONS_FILE) $(DIRECTORIES_TO_CREATE)
and the output:
E:\1983_1\02-Safety\01-Application>make depend
* [build] depend.cpp_options
E:\1983_1\02-Safety\01-Application>
apparently nothing to be done although the dependcies files(*.mak) are not there. No force or phony could solve it for me.
I have a project that has many makefiles inside it. Because sometimes I need to compile only some parts of my project so I decided to have one makefile in each directory. But when I want to run the main makefile that includes all other ones to compile my project it gives me lots of errors.
This is my project tree:
root 'makefile'
-folder1 'foo1.c foo2.c makefile'
-folder2 'makefile'
--folder2-1 'foo3.c foo4.c makefile'
--folder2-2 'foo5.c makefile'
Each makefile in the very last directory has been included to it's upper makefile. But it doesn't run the main makefile. I'm really new to GNU make and I want to have something like this but I don't know how. I just wrote some make scripts but it doesn't work.
I just want to have something that I can compile the projects parts separately or compile the whole project using multiple makefiles.
any way, I show you something and hope can help you:
all:
#$(MAKE) -C subfolder
or if you want to use *.mk as your sub makefile, you can write:
all:
#$(MAKE) -C busfolder -f somename.mk
I show you my example, my DIR looks like:
TOPDIR-- Makefile
|
|-- debug
| |-- debug.c
| |-- debug.h
| |-- debug.mk
| |-- instrument.c
| `-- uart_print.c
|-- driver
| |-- driver.c
| |-- driver_ddi.c
| |-- driver_ddi.h
| |-- driver.h
| `-- driver.mk
|-- include
| `-- common.h
|-- Makefile
|-- mw
| |-- manager.c
| `-- mw.mk
|-- root
| |-- main.c
| `-- root.mk
and my TOP makefile looks like:
MAKE_DIR = $(PWD)
ROOT_DIR := $(MAKE_DIR)/root
DRV_DIR := $(MAKE_DIR)/driver
INCLUDE_DIR := $(MAKE_DIR)/include
DEBUG_DIR := $(MAKE_DIR)/debug
INC_SRCH_PATH :=
INC_SRCH_PATH += -I$(ROOT_DIR)
INC_SRCH_PATH += -I$(DRV_DIR)
INC_SRCH_PATH += -I$(INCLUDE_DIR)
INC_SRCH_PATH += -I$(DEBUG_DIR)
LIB_SRCH_PATH :=
LIB_SRCH_PATH += -L$(MAKE_DIR)/libs
COLOR_ON = color
COLOR_OFF =
CC = $(COLOR_ON)gcc
#CC = $(COLOR_OFF)gcc
LD = ld
LINT = splint
LIBS := -ldriver -ldebug -lmw -lm -lpthread
CFLAGS :=
CFLAGS += $(INC_SRCH_PATH) $(LIB_SRCH_PATH)
CFLAGS += -Wall -O -ggdb -Wstrict-prototypes -Wno-pointer-sign -finstrument-functions -fdump-rtl-expand
CFLAGS += -DDEBUG -D_REENTRANT
LDFLAGS :=
export MAKE_DIR CC LD CFLAGS LDFLAGS LIBS LINT INC_SRCH_PATH
all:
#$(MAKE) -C debug -f debug.mk
#$(MAKE) -C driver -f driver.mk
#$(MAKE) -C mw -f mw.mk
#$(MAKE) -C root -f root.mk
.PHONY: clean
clean:
#$(MAKE) -C debug -f debug.mk clean
#$(MAKE) -C driver -f driver.mk clean
#$(MAKE) -C mw -f mw.mk clean
#$(MAKE) -C root -f root.mk clean
it will call sub DIR *.mk during the compile. The sub DIR makefile, I just write a simple example for you reference:
LIB = $(MAKE_DIR)/libs/yourmodulename.a
SRCS = $(wildcard *.c)
OBJS = $(patsubst %.c, %.o, $(SRCS))
$(LIB): $(OBJS)
#mkdir -p ../libs
#$(AR) cr $# $^
#echo " Archive $(notdir $#)"
$(OBJS): $(SRCS)
#$(CC) $(CFLAGS) -c $^
#echo " CC $(OBJS)"
.PHONY: clean
clean:
#$(RM) -f $(LIB) $(OBJS)
#$(RM) -f *.expand
#echo " Remove Objects: $(OBJS)"
for the makefile, which generate the final target file(like a.out) is little bit different, because I use the sub makefile to generate LIB file, and I use a root.mk to generate final target:
PROG = ../prog/DEMO
SRCS = $(wildcard *.c)
OBJS = $(patsubst %.c, %.o, $(SRCS))
$(PROG): $(SRCS)
#mkdir -p ../prog
#$(CC) $^ $(CFLAGS) -Wl,-Map=$(PROG).map $(LIBS) -o $#
#echo " Generate Program $(notdir $(PROG)) from $^"
.PHONY: clean
clean:
#$(RM) -f $(OBJS) $(PROG)
#$(RM) -f *.expand
#$(RM) -rf ../prog ../libs
#echo " Remove Objects: $(OBJS)"
#echo " Remove Libraries: $(notdir $(PROG))"
I've this:
include makefile_vars.mk
# Target
TARGET := $(OBJ)/$(TARGETNAME)
# Move objects to ../Obj
OBJECTS := $(addsuffix .obj,$(SOURCES))
override OBJECTS := $(OBJECTS:$(SRC)/%.obj=$(OBJ)/%.obj)
# Objects o
OBJ_INC_DIRS := $(sort $(dir $(OBJECTS)))
# Target
all: $(TARGET)
$(TARGET): $(OBJECTS)
# Objects
$(OBJ)/%.c.obj: $(SRC)/%.c | $(OBJ_INC_DIRS)
#echo Compiling $(<F) ...
$(OBJ)/%.a66.obj: $(SRC)/%.a66 | $(OBJ_INC_DIRS)
#echo Compiling $(<F) ...
$(OBJ_INC_DIRS):
mkdir -p $#
The first time I launch it, it says me that there is no rule to make the target MyFile.c.obj, when running again (whitout modifying anything) the rule is found and the compilation goes on.
What am I doing wrong?
I'm not sure that this will work, but I would move $(OBJ_INC_DIRS) order-only prerequisite out from the pattern rules:
$(OBJECTS) : | $(OBJ_INC_DIRS)
$(OBJ)/%.c.obj: $(SRC)/%.c
#echo Compiling $(<F) ...
...