If I have something like this:
PROJECTS += path/to/first
PROJECTS += path/to/second
PROJECTS += path/to/third
and
LIBS += lib_output/first.lib
LIBS += lib_output/second.lib
LIBS += lib_output/third.lib
How could I associate the project from PROJECTS += path/to/first with LIBS += lib_output/first.lib? Is there something like a hashmap available in a makefile? Or possibility to search in an array?
You can simulate lookup tables using computed variable names and the fact that make variable names can include some special characters like dot and forward slash:
PROJECTS += path/to/first
PROJECTS += path/to/second
PROJECTS += path/to/third
LIBS += lib_output/first.lib
LIBS += lib_output/second.lib
LIBS += lib_output/third.lib
lookup.path/to/first := lib_output/first.lib
lookup.path/to/second := lib_output/second.lib
lookup.path/to/third := lib_output/third.lib
path := path/to/first
$(info ${path} -> ${lookup.${path}})
path := path/to/second
$(info ${path} -> ${lookup.${path}})
path := path/to/third
$(info ${path} -> ${lookup.${path}})
Outputs:
$ make
path/to/first -> lib_output/first.lib
path/to/second -> lib_output/second.lib
path/to/third -> lib_output/third.lib
I'm not sure if I completely understand your question, but I think the word function might be what you need (it may be a GNU make extension):
$(word 2, $(PROJECTS)) returns path/to/second,
$(word 2, $(LIBS)) returns lib_output/second.lib.
Related
I am working on a C++ library where I am following the structure below:
ROOTDIR = ~/path/to/proj
BLDDIR = $(ROOTDIR)/build
INCDIR = $(ROOTDIR)/include
SRCDIR = $(ROOTDIR)/src
LIBSRCDIR = $(SRCDIR)/lib
TESTSRCDIR = $(SRCDIR)/test
OBJDIR = $(ROOTDIR)/obj
LIBOBJDIR = $(OBJDIR)/lib
TESTOBJDIR = $(OBJDIR)/test
LIBDIR = $(ROOTDIR)/lib
BINDIR = $(ROOTDIR)/bin
And the file definitions are:
MKFILE = $(BLDDIR)/Makefile
HDRFILES = $(wildcard $(INCDIR)/*.hpp)
LIBSRCFILES := $(wildcard $(LIBSRCDIR)/*.cpp)
TESTSRC = $(TESTSCRCDIR)/test.cpp
LIBOBJFILES := $(patsubst $(LIBSRCDIR)/%.cpp, $(LIBOBJDIR)/%.o, $(LIBSRCFILES))
TESTOBJ := $(TESTOBJDIR)/test.o
LIBFILE = $(LIBDIR)/$(NAME)-$(VERSION).a
TESTFILE = $(BINDIR)/test
ZIPFILE = $(ROOTDIR)/$(NAME).$(VERSION).zip
I have tested & confirmed that everything works, but for some reason $(TESTSRC) is printing empty even though Make is able to set $(TESTOBJ). I tried setting up the variable definitions in the hierarchy to ensure everything is generated in level, but that one variable remains empty.
EDIT 1:
Make is finding all of the directories properly
I have made sure that the file extension is correct
The variable is not being overwritten
EDIT 2:
The specific error I"mg getting is:
make: *** No rule to make target /test.cpp', needed by ..../test.o
..../test.o is in the right directory & defined separately without being dependent on a patsubst like the libsrc.
Read carefully:
TESTSRCDIR = $(SRCDIR)/test
^^^
and:
TESTSRC = $(TESTSCRCDIR)/test.cpp
^^^
I have issues assigning the same variable multiple times in Makefile.
I am making a kind of modular makefile where I only deal with components instead of every source file and include directory.
This first solution works fine
MainRootDir = Components/Main
include $(RootDir)/$(MainRootDir)/Main.mak
Debug_Includes += $(addprefix $(MainRootDir)/,$(Main_Includes))
Debug_ASM_Sources += $(addprefix $(MainRootDir)/,$(Main_ASM_Static))
Debug_CC_Sources += $(addprefix $(MainRootDir)/,$(Main_CC_Static))
Debug_ASM_Sources += $(addprefix $(CfgDir)/, $(Main_ASM_Config))
Debug_CC_Sources += $(addprefix $(CfgDir)/, $(Main_CC_Config))
AdderRootDir = Components/Adder
include $(RootDir)/$(AdderRootDir)/Adder.mak
Debug_Includes += $(addprefix $(AdderRootDir)/,$(Adder_Includes))
Debug_ASM_Sources += $(addprefix $(AdderRootDir)/,$(Adder_ASM_Static))
Debug_CC_Sources += $(addprefix $(AdderRootDir)/,$(Adder_CC_Static))
Debug_ASM_Sources += $(addprefix $(CfgDir)/, $(Adder_ASM_Config))
Debug_CC_Sources += $(addprefix $(CfgDir)/, $(Adder_CC_Config))
However, if I try to standardize the block by defining variables and Re-Assigning new value before adding the software component each time, it stops working:
SwcName = Main
SwcRootDir = Components/$(SwcName)
include $(RootDir)/$(SwcRootDir)/$(SwcName).mak
Debug_Includes += $(addprefix $(SwcRootDir)/,$($(SwcName)_Includes))
Debug_ASM_Sources += $(addprefix $(SwcRootDir)/,$($(SwcName)_ASM_Static))
Debug_CC_Sources += $(addprefix $(SwcRootDir)/,$($(SwcName)_CC_Static))
Debug_ASM_Sources += $(addprefix $(CfgDir)/, $($(SwcName)_ASM_Config))
Debug_CC_Sources += $(addprefix $(CfgDir)/, $($(SwcName)_CC_Config))
SwcName = Adder
SwcRootDir = Components/$(SwcName)
include $(RootDir)/$(SwcRootDir)/$(SwcName).mak
Debug_Includes += $(addprefix $(SwcRootDir)/,$($(SwcName)_Includes))
Debug_ASM_Sources += $(addprefix $(SwcRootDir)/,$($(SwcName)_ASM_Static))
Debug_CC_Sources += $(addprefix $(SwcRootDir)/,$($(SwcName)_CC_Static))
Debug_ASM_Sources += $(addprefix $(CfgDir)/, $($(SwcName)_ASM_Config))
Debug_CC_Sources += $(addprefix $(CfgDir)/, $($(SwcName)_CC_Config))
The issue is that the source files of component Main are defined multiple times.
As if the Adder block is also expanding SwcName with the value Main.
Any idea how to prevent this?
You are using recursively expanded variables (var = ...), which is the default. So make defers the evaluation of the right hand side of your assignments until the variable's value is really needed. Example:
a = 1
b += $(a)
a = 2
b += $(a)
.PHONY: all
all:
#echo $(b)
will print 2 2 instead of the 1 2 you expect because what make actually stored in variable b was $(a) $(a), which it evaluated only before passing the recipe of all to the shell. And at that time a has only one single value: the last one it has been assigned, that is, 2.
You could use simply expanded variables (var := ...), instead:
b :=
a := 1
b += $(a)
a := 2
b += $(a)
.PHONY: all
all:
#echo $(b)
which will print 1 2. Do not forget the apparently useless b :=: it tells make that b is not a recursively expanded variable but a simply expanded one. Different from the default form, the value assigned to a simply expanded variable is evaluated when it is defined, its expansion is not deferred until the variable's value is needed.
But repeating large portions of code as in what you show is not optimal. Indeed, repeating things is frequently needed with humans but almost never optimal with computers. If you are using GNU make, as suggested by tripleee, you could use a kind of user-defined function:
Debug_Includes :=
Debug_ASM_Sources :=
...
# $(1) is the current SwcName
define MY_FUNC
SwcRootDir := Components/$(1)
include $$(RootDir)/$$(SwcRootDir)/$$(1).mak
Debug_Includes += $$(addprefix $$(SwcRootDir)/,$$($(1)_Includes))
Debug_ASM_Sources += $$(addprefix $$(SwcRootDir)/,$$($$(1)_ASM_Static))
...
endef
and then:
$(foreach SwcName,Main Adder,$(eval $(call MY_FUNC,$(SwcName))))
Do not forget the $$ in the macro definition. They are needed. See the GNU make manual for the full explanation.
This is a matter of recursive vs simply expanded variables. I'm going to guess that Debug_Includes is not initialized with a := earlier on, which means it defaults to be a recursively expanded variable. Therefore it is set to $(RootDir)/$(SwcRootDir)/$(SwcName).mak, and the internal variables are only expanded when it is referenced (at which point SwcRootDir will be Components/$(SwcName)).
Try initializing your variables with := at the top of your file to make them simple. Then they will be assigned values right away, and the internal variables will be set to what they were at the time of the definition.
The following snippet:
... rest of makefile ...
SRCS += $(BASEDIR)FingerCell/Source/STM32F4-DISCOVERY_USB/usb_bsp.c
SRCS += $(BASEDIR)FingerCell/Source/STM32F4-DISCOVERY_USB/usb_core.c
SRCS += $(BASEDIR)FingerCell/Source/STM32F4-DISCOVERY_USB/usb_dcd.c
SRCS += $(BASEDIR)FingerCell/Source/STM32F4-DISCOVERY_USB/usbd_cdc_core.c
SRCS += $(BASEDIR)FingerCell/Source/STM32F4-DISCOVERY_USB/usbd_cdc_vcp.c
SRCS += $(BASEDIR)FingerCell/Source/STM32F4-DISCOVERY_USB/usb_dcd_int.c
SRCS += $(BASEDIR)FingerCell/Source/STM32F4-DISCOVERY_USB/usbd_core.c
SRCS += $(BASEDIR)FingerCell/Source/STM32F4-DISCOVERY_USB/usbd_desc.c
SRCS += $(BASEDIR)FingerCell/Source/STM32F4-DISCOVERY_USB/usbd_ioreq.c
SRCS += $(BASEDIR)FingerCell/Source/STM32F4-DISCOVERY_USB/usbd_req.c
SRCS += $(BASEDIR)FingerCell/Source/STM32F4-DISCOVERY_USB/usbd_usr.c
... rest of makefile
Compiles, but if I replace it by:
SRCS += $(BASEDIR)FingerCell/Source/STM32F4-DISCOVERY_USB/$(wildcard *.c)
make command returns a linker error:
FingerCell/Source/STM32F4-DISCOVERY_USB/User.o: No such file or directory
The STM32F4-DISCOVERY_USB directory contains no other .c files than the ones listed in the first code snippet. Am I using the wildcard incorrectly here?
SRCS += $(wildcard $(BASEDIR)FingerCell/Source/STM32F4-DISCOVERY_USB/*.c)
I've got a build configuration that looks something like this:
Makefile:
build-for-x: X := yes
build-for-x: all
build-for-y: Y := yes
build-for-y: all
SRC :=
include foo.mk
include bar.mk
all: # ... some targets which use SRC eventually
foo.mk:
ifeq ($(X),yes)
SRC += foo_x.c
endif
ifeq ($(Y),yes)
SRC += foo_y.c
endif
bar.mk:
ifeq ($(X),yes)
SRC += bar_x.c
endif
ifeq ($(Y),yes)
SRC += bar_y.c
endif
This is obviously highly simplified. What I'm actually doing is building the same codebase for two different embedded platforms, with many different modularized sections (foo and bar here) and several variables for source, include, tests, etc.
The above doesn't work, because X or Y are only set within the targets which build-for-x/build-for-y have as prerequisites. The code within foo.mk/bar.mk is evaluated beforehand, when neither variable is set.
Is there a good way to handle situations like this? What's a sane way I might restructure my build configuration to:
Preserve the modularity (foo.mk/bar.mk are separate files)
Allow one to run make build-for-x/make build-for-y to build the separate implementations
I want to avoid making foo.mk look something like:
build-for-x: SRC += foo_x.c
build-for-y: SRC += foo_y.c
unless I absolutely have to, since this forces me to have a dependency on a particular target. I would much rather keep all the target-dependent assignments at the top level.
How about this:
Makefile:
build-for-x: SRC := SRC_X
build-for-x: all
build-for-y: SRC := SRC_Y
build-for-y: all
foo.mk:
SRC_X += foo.x_c
SRC_Y += foo.y_c
bar.mk:
SRC_X += bar.x_c
SRC_Y += bar.y_c
I have a makefile which takes a TYPE parameter and runs a test file using that name. Otherwise it takes all the test files.
ifneq (,$(TYPE))
TEST_SRCS := $(wildcard test/$(TYPE)Test.cpp)
else
TEST_SRCS := $(wildcard test/*Test.cpp)
endif
print:
echo $(TEST_SRCS)
This works fine If I execute like,
make TYPE=Add
But Now I want to give more than one value to TYPE So that it should take both AddTest.cpp and SubtractTest.cpp
e.g.
make TYPE=Add,Subtract
I have tried $(foreach var,$(TYPE), TEST_FILES += var)
Make isn't good at this kind of manipulation, but you can break a comma-separated list into a space-separated list like this:
COMMA = ,
TYPE_LIST = $(subst $(COMMA), ,$(TYPE))
Then you can apply your wildcard logic like this:
FILE_LIST = $(patsubst %,test/%Test.cpp,$(TYPE_LIST))
TEST_SRCS := $(wildcard $(FILE_LIST))