Makefile: add directory and modify extenstion in path - makefile

I have a variable (which typically reflects the target's name) in one of the following two forms (with and without extension)
BUILD_DIR/DIR1/DIR2/DIR3/A
BUILD_DIR/DIR1/DIR2/DIR3/B.ext
For a give variable I would like to add another layer (DIR0) under BUILD_DIR and add/change .ext to .new_ext.
So that the variables above are both transformed into
BUILD_DIR/DIR0/DIR1/DIR2/DIR3/A.new_ext
BUILD_DIR/DIR0/DIR1/DIR2/DIR3/B.new_ext
In other words DIR0 is added right after BUILD_DIR and extension is changed if it was present and added if not.
Having a function in the Makefile that does the job should also be sufficient.

Assuming the paths are in a variable such as...
PATHS := BUILD_DIR/DIR1/DIR2/DIR3/A BUILD_DIR/DIR1/DIR2/DIR3/B.ext
Then try something like...
EXTRA_DIR := DIR0
NEW_EXTENSION := new_ext
PATHS := $(addsuffix .$(NEW_EXTENSION),$(patsubst %.ext,%,$(patsubst BUILD_DIR/%,BUILD_DIR/$(EXTRA_DIR)/%,$(PATHS))))

Here is a solution that seems to be the shortest among presented so far
FUNC = $(patsubst $(2)/%,$(2)/$(DIR0)/%.new_ext,$(1:%.ext=%))
$(call FUNC,$(VARIABLE),$(BUILD_DIR))

Related

Make: How could i change the path of a files which matches certain pattern

I am new to GNUmake.
I have a requirement to replace the file paths based on certain condition.
TARGET_EXCEPTION := /home/ip/lib_build
TGT_TOOLS := /demo/build/new_project
ifdef SET_BUILD
ifneq (0,$(RELEASE))
FILES += $(addprefix $(TARGET_EXCEPTION)/tools/test/,$(subst $(TGTTOOLS)/tools/test/,,$(RELEASE_FILES)))
endif
endif
RELEASE_FILES variable has multiple file paths assigned. Out of those files i am interested only in folders with $(TGT_TOOLS)/tools/test/ and replace it with $(TARGET_EXCEPTION)/tools/test/.. Is there anything wrong in my above code? Please help!
I have a requirement to replace the file paths based on certain condition.
I daresay the actual requirement is probably more like "the tests should be installed in the directory named by $(TARGET_EXCEPTION) in a release build, but in the directory named by $(TGT_TOOLS) otherwise. The distinction is important, because it is clearer and more portable to just assign the path appropriately in the first place.
That might look something like this:
# Possible test install locations
TARGET_EXCEPTION := /home/ip/lib_build
TGT_TOOLS := /demo/build/new_project
####
#
# Determine which location to use
#
ifdef SET_BUILD
TEST_INSTALL_RELEASE := $(RELEASE)
else
TEST_INSTALL_RELEASE := 0
endif
ifneq (0,$(TEST_INSTALL_RELEASE))
TEST_DIR := $(TARGET_EXCEPTION)
else
TEST_DIR := $(TGT_TOOLS)
endif
#
####
# Define the release files in the desired location from the start
RELEASE_FILES := \
# ...
$(TEST_DIR)/tools/test/test1 \
$(TEST_DIR)/tools/test/test2 \
# ...
# No substitution needed; the targets are already named correctly
FILES += $(RELEASE_FILES)
Is there anything wrong in my above code?
It attempts to implement a poor approach. Also, it very well might not interoperate as you require with your makefile's rules related to the affected files. The above might also have the latter problem, but in that case there is also a clear solution: refer to the affected files everywhere by the name format given in the example.

How to substitute a string in list from other lists where there is a match

Assume I have two source directories:
srcdir0 - Contains source files for generation 0 compile
srcdir1 - Contains subset of srcdir0 files
I create file list for srcdir0 and srcdir1
S0SRCS := $(wildcard $(srcdir0)/*.c)
S1SRCS := $(wildcard $(srcdir1)/*.c)
I'm trying to create a final list that has the base srcdir0 files but are substituted by srcdir1 files of the same name. In other words the srcdir1 files take precedence.
I'm thinking that the filter or filter-out functions may be my friend here but I'm not experienced enough to know better.
I think it suffices to filter out the names from the S1 directory from the names of the S0:
S0NAMES := $(notdir $(S0SRCS))
S1NAMES := $(notdir $(S1SRCS))
FINAL-LIST := $(addprefix $(srcdir0)/,$(filter-out $(S1NAMES),$(S0NAMES))) $(S1SRCS)
Please test this first, I didn't have the opportunity to do so and wrote it just off the top of my head.

How to remove multiple source files after wildcard Makefile

The question is:
I have a makefile called A.mk (a general makefile for all projects). Over there, I have added all source files in folder src1 using
Var += $(wildcard src1/*.c)
Then, for a specific application I have a makefile (called B.mk), which includes A.mk in itself. Now, I want to substitute the source file foo1.c from folder src1 with a new one foo2.c from folder src2. How can I do that?
How can I do that if I want to substitute (or even delete) multiple files from Var in B.mk.
Thanks for your help in advance.
Make has a number of string functions, filter-out looks like it would apply here
# All .c files
Var := $(filter-out %.c,$(Var))
# A specific file
Var := $(filter-out src/foo.c,$(Var))

How can I shift a relative path up one level in make?

Sorry if this is a little esoteric, but in my makefile I have a variable $(BASE) which is a relative path. I need to get the path one level up.
So if I had "../../../src", I want "../../src".
Is there way to do this easily in Make?
If all values of BASE for which you want to do this begin with ../, you can try
$(patsubst ../%,%,$(BASE))
If you want to just drop the first component of an arbitrary path (i.e. a/b/c -> b/c), it takes a bit more work:
space := $(empty) $(empty)
shift-list = $(wordlist 2,$(words $1),$1)
shift-path = $(subst $(space),/,$(call shift-list,$(subst /, ,$1)))
and use it as $(call shift-path,$(BASE)). This breaks if your paths have spaces, but handling those in make is a nightmare for many other reasons anyway.

Common GNU makefile directory path

I'm trying to consolidate some build information by using a common makefile. My problem is that I want to use that makefile from different subdirectory levels, which makes the working directory value (pwd) unpredictable. For example:
# Makefile.common
TOP := $(shell pwd)
COMPONENT_DIR := $(TOP)/component
COMPONENT_INC := $(COMPONENT_DIR)/include
COMPONENT_LIB := $(COMPONENT_DIR)/libcomponent.a
If I include Makefile.common from a subdirectory, like so, the $(TOP) directory is incorrect and everything else follows suit:
# other_component/Makefile
include ../Makefile.common
# $(COMPONENT_LIB) is incorrectly other_component/component
What's the best way to get Makefile.common to use its own directory path instead of the more fickle pwd?
You should be able to use the MAKEFILE_LIST variable, like this:
# This must be the first line in Makefile.common
TOP := $(dir $(firstword $(MAKEFILE_LIST)))
From the documentation:
As make reads various makefiles, including any obtained from the MAKEFILES variable, the command line, the default files, or from include directives, their names will be automatically appended to the MAKEFILE_LIST variable. They are added right before make begins to parse them. This means that if the first thing a makefile does is examine the last word in this variable, it will be the name of the current makefile. Once the current makefile has used include, however, the last word will be the just-included makefile.
Try this:
ROOT_DIR := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
Edit: Be sure to use := instead of = because the latter causes make to use late-binding and MAKEFILE_LIST may have changed due to later includes.
Have you tried doing:
# Makefile.common
TOP ?= $(shell pwd)
COMPONENT_DIR := $(TOP)/component
COMPONENT_INC := $(COMPONENT_DIR)/include
COMPONENT_LIB := $(COMPONENT_DIR)/libcomponent.a
# other_component/Makefile
TOP ?= ..
include ../Makefile.common
Using the ?= construct will keep TOP from being redefined if it is already set. You can set it to the appropriate value based on where you are in the tree when you invoke make. I confess it's been awhile since I've used GNU make so this may not work or may need some tweaks.
My solution:
cwd := $(shell readlink -en $(dir $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))))
This also works for calls like make -f /opt/some/dir/Makefile whenn your in /opt/other/path/subdir.
write the common stuff in common.mk. Then put the common.mk in the default directories that Make looks for when it encounters an include statement. See the manual for common directories Make looks for.
You could also put the common.mk in custom directory, and then type make -I customdir.
Inside the Makefile in each subfolder, you do
include common.mk
That is all. No need to worry about path and moving things around.

Resources