So in my project I have a src directory and an obj directory. I'm recursively finding the .c and .cpp files in my src directory, and then its corresponding .o file gets put right in the obj directory. So for example if I have a .cpp file: src/dir1/dir2/file.cpp, its corresponding .o file would be obj/file.o. Then I'm generating the rule to get the .o file from the .cpp file using a make foreach function using this code:
rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2)$(filter $(subst *,%,$2),$d))
src = $(call rwildcard,src/,*.cpp *.c)
obj = $(patsubst %,obj/%.o,$(basename $(notdir $(src))))
$(info src: [$(src)])
$(info obj: [$(obj)])
game.exe: $(obj)
g++ $^ -o $#
define objFromSrc
$(1): $(2)
$(info $(1) $(2))
g++ -c $(2) -o $(1)
endef
$(foreach t,$(src),$(call objFromSrc,$(patsubst %,obj/%.o,$(basename $(notdir $(t)))),$(t)))
Here is the output for some example files:
src: [src/dir/main.cpp src/dir/dir2/other3.cpp src/dir/other2.cpp src/other.c]
obj: [obj/main.o obj/other3.o obj/other2.o obj/other.o]
obj/main.o src/dir/main.cpp
obj/other3.o src/dir/dir2/other3.cpp
obj/other2.o src/dir/other2.cpp
obj/other.o src/other.c
makefile:20: *** multiple target patterns. Stop.
You can see the obj variable correctly holds the corresponding .o file names. And the objFromSrc function generates a rule where the target and dependency are correct, but yet I get a multiple target patterns error.
Why am I getting this error and how can I fix it?
You are missing the $(eval) to parse the generated makefile code:
$(eval $(foreach t,$(src),...))
I would also suggest to add an empty line at the end of the multi-line define. Leaving this out is usually calling for trouble when $(eval)uating dynamically generated makefile code.
define objFromSrc
$(1): $(2)
$(info $(1) $(2))
g++ -c $(2) -o $(1)
endef
$(info eval $(foreach t,$(src),...))
BONUS CODE: your recipe is a constant so there is no need to re-generate it for every rule. Use a static pattern rule for $(obj) instead:
.DEFAULT_GOAL := game.exe
obj :=
define objFromSrc
$(1): $(2)
obj += $(1)
endef
$(eval $(foreach t,$(src),...))
$(info obj: [$(obj)])
$(obj): %.o:
g++ -o $# -c $<
game.exe: $(obj)
g++ $^ -o $#
Why am I getting this error and how can I fix it?
All these define and $(call ...) in make produce simple strings. You have to eval it to make the make do what you've ordered (i.e. to create the rule $1 : $2):
$(foreach t,$(src),$(eval $(call objFromSrc,$(patsubst %,obj/%.o,$(basename $(notdir $(t)))),$(t))))
Related
I'am starting using Linux and I have some trouble using some stm32f4 libraries for my project gcc-testing.
All the CMSIS programs needed are inside the STM32F4_Discovery_FW_V1.1.0 and the project is arranged like this:
~
|__
| |
| STM32F4XX
| |
src STM32F4_Discovery_FW_V1.1.0
|
ggc-testing
|
makefile
main.c
stm32f4xx_config.h
stm32_flash.ld
system_stm32f4xx.c
The main.c and the system_stm32f4xx.c use the stm32f4xx.h file that is inside the STM32F4_Discovery_FW_V1.1.0/Libraries/CMSIS/ST/STM32F4xx/Include
The error I get from the terminal is:
Make file console error
My make file:
PROJ_NAME=main
STM_DIR=~/STM32F4XX/STM32F4-Discovery_FW_V1.1.0
STM_SRC = $(STM_DIR)/Libraries/STM32F4xx_StdPeriph_Driver/src
vpath %.c $(STM_SRC)
SRCS = main.c
SRCS += system_stm32f4xx.c
SRCS += $(STM_DIR)/Libraries/CMSIS/ST/STM32F4xx/Source/Templates/TrueSTUDIO/startup_stm32f4xx.s
INC_DIRS = $(STM_DIR)/Utilities/STM32F4-Discovery
INC_DIRS += $(STM_DIR)/Libraries/CMSIS/Include
INC_DIRS += $(STM_DIR)/Libraries/CMSIS/ST/STM32F4xx/Include
INC_DIRS += $(STM_DIR)/Libraries/STM32F4xx_StdPeriph_Driver/inc
INC_DIRS += .
TOOLS_DIR = /opt/gcc-arm-embedded/gcc-arm-none-eabi-4_7-2013q1/bin
CC = arm-none-eabi-gcc
OBJCOPY = arm-none-eabi-objcopy
GDB = arm-none-eabi-gdb
INCLUDE = $(addprefix -I,$(INC_DIRS))
DEFS = -DUSE_STDPERIPH_DRIVER
CFLAGS = -ggdb
CFLAGS += -O0
CFLAGS += -Wall -Wextra -Warray-bounds
CFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork
CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
LFLAGS = -Tstm32_flash.ld
.PHONY: $(PROJ_NAME)
$(PROJ_NAME): $(PROJ_NAME).elf
$(PROJ_NAME).elf: $(SRCS)
$(CC) $(INCLUDE) $(DEFS) $(CFLAGS) $(LFLAGS) $^ -o $#
$(OBJCOPY) -O ihex $(PROJ_NAME).elf $(PROJ_NAME).hex
$(OBJCOPY) -O binary $(PROJ_NAME).elf $(PROJ_NAME).bin
clean:
rm -f *.o $(PROJ_NAME).elf $(PROJ_NAME).hex $(PROJ_NAME).bin
# Flash the STM32F4
flash:
st-flash write $(PROJ_NAME).bin 0x8000000
.PHONY: debug
debug:
# before you start gdb, you must start st-util
$(GDB) $(PROJ_NAME).elf
Hope enyne can help with this.
After gnu make generates a cmd-line (eg gcc), use of a ~ would rely on make executing a shell and the shell expanding an arg with a leading unquoted ~. Based on your line with $(addprefix, try adding a space between -I and ,$(INC_DIRS)
However, the overhead from executing a shell can be undesirable and the extra exec is often easy to avoid; for this case, replace ~ with $(HOME)
Example Makefile :
SUBDIR := some/incdir
TILDE_SUBDIR := ~/$(SUBDIR)
NOT_DELIM := $(addprefix -I,$(TILDE_SUBDIR))
DELIM_INC := $(addprefix -I ,$(TILDE_SUBDIR))
HOME_SUBDIR := $(HOME)/$(SUBDIR)
PHONY: all
all:
#echo NOT_DELIM $(NOT_DELIM)
#echo DELIM_INC $(DELIM_INC)
#echo HOME_SUBDIR $(HOME_SUBDIR)
Output :
NOT_DELIM -I~/some/incdir
DELIM_INC -I /home/user1/some/incdir
HOME_SUBDIR /home/user1/some/incdir
I have the following makefile:
#.SUFFIXES:
#.SUFFIXES: .F90 .cuf .o
ROOT = /home/ccevallos/finalMIT
SRCDIR := $(ROOT)/external/lib_eigesolve
#F90SRC = $(notdir $(wildcard $(SRCDIR)/*.F90))
#F90OBJS = $(patsubst %.F90,%.o,$(F90SRC))
F90OBJS = eigsolve_vars.o toolbox.o zhegst_gpu.o zhemv_gpu.o zhetd2_gpu.o zhetrd_gpu.o zheevd_gpu.o zhegvdx_gpu.o \
dsygst_gpu.o dsymv_gpu.o dsytd2_gpu.o dsytrd_gpu.o dsyevd_gpu.o dsygvdx_gpu.o
#CUFSRC = $(notdir $(wildcard $(SRCDIR)/*.cuf))
#CUFOBJS = $(patsubst %.cuf,%.o,$(CUFSRC))
CUFOBJS = cusolverDn_m.o
FLAGS = -O3 -mp -pgf90libs -Mcuda=cc60,cuda9.1,ptxinfo -Mlarge_arrays
FLAGS2 = -O3 -mp -pgf90libs -Mcuda=cc60,cuda9.1,ptxinfo,maxregcount:64 -Mlarge_arrays
FLAGS3 = -O3 -mp -pgf90libs -Mcuda=cc60,cuda9.1,ptxinfo,nordc,maxregcount:255 -Mlarge_arrays
.PHONY: all
all: lib_eigsolve.a
zhetd2_gpu.o : zhetd2_gpu.F90
pgf90 -c ${FLAGS2} ${OPTFLAGS} $*.F90 -o $*.o
zhemv_gpu.o : zhemv_gpu.F90
pgf90 -c ${FLAGS3} ${OPTFLAGS} $*.F90 -o $*.o
dsytd2_gpu.o : dsytd2_gpu.F90
pgf90 -c ${FLAGS2} ${OPTFLAGS} $*.F90 -o $*.o
dsymv_gpu.o : dsymv_gpu.F90
pgf90 -c ${FLAGS3} ${OPTFLAGS} $*.F90 -o $*.o
cusolverDn_m.o: cusolverDn_m.cuf
pgf90 -c ${FLAGS} ${OPTFLAGS} $*.cuf -o $*.o
%.o: %.F90
pgf90 -c ${FLAGS} ${OPTFLAGS} $*.F90 -o $*.o
lib_eigsolve.a: $(F90OBJS) $(CUFOBJS)
ar rcs $# $^
PHONY: clean
clean:
rm -f lib_eigsolve.a *.mod *.o
This makefile compiles perfectly well, however I basically want to uncomment the lines with # to make this simpler, but when I do that only
ar rcs lib_eigsolve.a
appears in the terminal, with no object file created, and thus lib_eigsolve.a is empty...
Why is it not compiling the object files?
P.S. You can find this Makefile with some modifications here https://github.com/NVIDIA/Eigensolver_gpu
You have a simple typo in $(SRCDIR): the source directory inside Eigensolver_gpu is called lib_eigsolve not lib_eigesolve.
$ cd ~workarea/playground
$ git clone https://github.com/NVIDIA/Eigensolver_gpu.git
$ ls Eigensolver_gpu/
lib_eigsolve LICENSE README.md test_driver
I then proceeded to create a dummy makefile by copy & pasting the relevant lines from your question:
ROOT := $(HOME)/workarea/playground/Eigensolver_gpu
ifndef FIXED
SRCDIR := $(ROOT)/lib_eigesolve
else
SRCDIR := $(ROOT)/lib_eigsolve
endif
F90SRC = $(notdir $(wildcard $(SRCDIR)/*.F90))
$(info F90SRC '$(F90SRC)')
F90OBJS = $(patsubst %.F90,%.o,$(F90SRC))
$(info F90OBJS '$(F90OBJS)')
CUFSRC = $(notdir $(wildcard $(SRCDIR)/*.cuf))
$(info CUFSRC '$(CUFSRC)')
CUFOBJS = $(patsubst %.cuf,%.o,$(CUFSRC))
$(info CUFOBJS '$(CUFOBJS)')
lib_eigsolve.a: $(F90OBJS) $(CUFOBJS)
echo ar rcs $# $^
Test runs:
$ make
F90SRC ''
F90OBJS ''
CUFSRC ''
CUFOBJS ''
echo ar rcs lib_eigsolve.a
ar rcs lib_eigsolve.a
$ make FIXED=1
F90SRC 'dsyevd_gpu.F90 ... zhemv_gpu.F90'
F90OBJS 'dsyevd_gpu.o ... zhemv_gpu.o'
CUFSRC 'cusolverDn_m.cuf'
CUFOBJS 'cusolverDn_m.o'
make: *** No rule to make target 'dsyevd_gpu.o', needed by 'lib_eigsolve.a'. Stop.
Ensure that $(SRCDIR) has no spaces:
SRCDIR := $(strip ${SRCDIR})
ifneq (1,$(words ${SRCDIR}))
$(error Not without further fiddling, friend)
endif
Specifying the path in the wildcard expression looks strange. When you are executing make directly in the srcdir (make -C lib_eigsolve), you should write
F90SRC = $(notdir $(wildcard *.F90))
or
srcdir = .
F90SRC = $(notdir $(wildcard ${srcdir}/*.F90))
when you want to keep your option for out-of-tree builds.
For instance, from variable:
files = dirx/a.cc diry/b.cc dirz/b.cc
I want to effectively have these rules: (without resorting to define/eval)
a_a.o: dirx/a.cc
b_b.o: diry/b.cc
c_c.o: dirz/c.cc
The problem seems unlikely, but this makefile does what you want:
Makefile
VPATH := dirx:diry:dirz
SRCS := a.cc b.cc c.cc
OBJS := $(foreach src,$(SRCS),$(basename $(src))_$(basename $(src)).o)
.PHONY: all clean
.SECONDEXPANSION:
%.o: $$(basename $$(subst _,.,$$*)).cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $# $<
all: $(OBJS)
clean:
rm -f $(OBJS)
With directories and files set up as per your example:
$ ls -R
.:
dirx diry dirz Makefile
./dirx:
a.cc
./diry:
b.cc
./dirz:
c.cc
it runs like:
$ make
g++ -c -o a_a.o dirx/a.cc
g++ -c -o b_b.o diry/b.cc
g++ -c -o c_c.o dirz/c.cc
Cribs: -
VPATH
foreach
basename
subst
.SECONDEXPANSION
I am new to GNUmakefile and I am just not sure how to handle the strings in the for loop below. I can print out each file using the echo command below. My questions are:
1. How to assign the $$f to a variable?
2. How to print out the content of the new variable?
For example, I did assign the content of $$f to "abc" but echo ${abc}; prints out blank.
Where did I miss? Thanks
DIR := MyDir
CFILES := $(wildcard $(DIR:=/*.c))
.PHONY: all
all:
for f in $(CFILES); \
echo $$f; \
abc=$$f; \
echo ${abc}; \
done
Your for loop is missing a do?
Inside the tabbed block you have scripting.
So you are setting shell vars not make vars.
You must escape the $s in shell block so printing $$abc or $${abc} would work. You can use make var as you have done $(CFILES).
What do you expect/want in abc ?
Do you wish to manipulate a shell or make var?
echo CFILES=$(CFILES)
for f in $(CFILES); do\
echo ff $$f;\
abc=$$f; \
echo $${abc};\
bn=$$(basename $$f);\
b=$${bn%%.*};\
echo you want this b= stripped down file tag $$b basename of file $$bn bash style;\
done
As ever there are more than one ways of doing things.
Make style maybe you could use pattern rules and automatic vars to do what you want?
http://www.gnu.org/software/make/manual/make.html#Automatic-Variables
http://www.gnu.org/software/make/manual/make.html#Pattern-Examples
e.g.
%.o : %.c
echo make var $< matches file.c
echo make var $# matches file.o
echo make var $* matches stem file
echo $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $#
Consider the following:
SRCS = somefile.c util/someother.c ../src/more.c
%.o : %.c
$(GCC) -MD -c $< -o $# -Wp,-MD,.deps/$*.d
#cp .deps/$*.d .deps/$*.P; \
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < .deps/$*.d >> .deps/$*.P; \
rm -f .deps/$*.d
-include $(SRCS:%.c=.deps/%.P)
How would I change the above so that the .o files end up in ./? Currently they build in the directory the source file exists in and that's bad.
I'd do it this way:
SRCS = somefile.c someother.c more.c
%.o : %.c
[same as before]
-include $(SRCS:%.c=.deps/%.P)
vpath %.c util ../src