Calculating a file path in makefile - makefile

I need to calculate a file path based on some subsytem names. See MWE below. Is there an easier way to achieve the same please? See my aa, ab, ac and join approach below.
I'm not keen on the double use of $(subsystem) as relies on make executing in the same order. I've tried using $(patsubst) but it only replaces the first instance of %. Any hints please?
#
## Given some subsystem names
subsystem := pi_sub_chris \
pi_sub_rob \
pi_sub_greg
#
## And an output directory
dir_export := ../pi_sw/export
#
## Calculate a file path in export directory to be made
## Is there a better way to do this!?
aa := $(addprefix $(dir_export)/,$(subsystem))
ab := $(addsuffix /a2l/, $(aa))
ac := $(addsuffix .a2l, $(subsystem))
files_to_be_made := $(join $(ab), $(ac))
.PHONY :
go : $(files_to_be_made)
#echo Done!
%.a2l :
#echo A perl script is run here to generate file $#
Which correctly outputs:
A perl script is run here to generate file ../pi_sw/export/pi_sub_chris/a2l/pi_sub_chris.a2l
A perl script is run here to generate file ../pi_sw/export/pi_sub_rob/a2l/pi_sub_rob.a2l
A perl script is run here to generate file ../pi_sw/export/pi_sub_greg/a2l/pi_sub_greg.a2l
Done!

There's no problem relying on the order in which these variables are expanded; that MUST be true or just about every makefile will break. It's absolutely guaranteed.
However, if you don't like it you could use something like:
files_to_be_made := $(foreach S,$(subsystem),$(dir_export)/$S/a21/$S.a21)

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.

Getting parent directory's basename in makefile

I need to automate a variable alignment in my Makefile. My Makefile's full file path is:
/home/e2/branchname/projectname/modulename/Makefile
In my Makefile, I have a variable BUILD_DIR, a part of which should be equal to the branchname in the full path.
So I did this:
BRANCH_NAME= $(shell cd ../.. && basename "$PWD" && cd projectname/modulename)
BUILD_DIR=$(HOME)/$(BRANCH_NAME)/build
Apparently I expected BUILD_DIR to be ~/branchname/build here, but after make I got ~/WD/build instead. I think it's most likely that I got a wrong BRANCH_NAME. Is there something wrong with what I did? And if yes I'd like to get some advice about how to do it correctly.
Thanks.
It's because $ has a special meaning to Make, so if you want to pass that up to shell you have to "escape" it. In case of Make, you escape the dollar sign by doubling. So you have to use $$PWD.
Also, what you are doing is not really the best way - it is always best to avoid the shell and use Make functionality if possible. In your case, the best way to do what you want is this:
BUILD_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))/../../build)
You have to put the above line in the makefile in question, near the top, so that it is before you include any other makefiles.
I came up with this:
ENVIRONMENT := $(shell basename $(dir $(abspath $(dir $$PWD))))
If this were executed, you'd have:
ENVIRONMENT=projectname

How to use make to convert files in subdirectories?

I have a directory with a bunch of subdirectories. Each subdirectory contains a traj.dat file. I want to use a Makefile to make sure that the file traj.dat gets converted to a different format, and the output file is printed in the same subdirectory as the original file.
Therefore, if I wanted to specify the names of the subdirectories, I could just use:
subdir1/traj.dat.xyz: subdir1/traj.dat
my_convert subdir1/traj.dat subdir1/traj.dat.xyz
subdir2/traj.dat.xyz: subdir2/traj.dat
my_convert subdir2/traj.dat subdir2/traj.dat.xyz
and so on.
How can I get the above result FOR ALL the subdirectories containing a traj.dat file, regardless of their name, without having to list them explicitly?
Cheers!
Assuming you're using GNU make, try:
DATFILES := $(shell find . -name traj.dat)
OUTFILES := $(addsuffix .xyz,$(DATFILES))
all: $(OUTFILES)
%.dat.xyz : %.dat
my_convert $< $#
You weren't really clear what you mean by "subdirectories"; if you just mean immediate subdirectories you can use this instead of the shell function, which is more efficient (and works on Windows):
DATFILES := $(wildcard */traj.dat)

Exporting environment variables to Makefile shell

I want to do immediate expansion of a shell command within a Makefile, but I want the shell command to have access to the environment variables within the Makefile. If I use the $(shell ...), it expands immediately, but there is no access to the variables. If I use the backquotes, the expansion is not immediate, and it causes problems for me later in the Makefile. I'm wondering if there is any way to make the backquotes expand immediately, or to pass the current environment to a $(shell) command.
For example, the following makefile:
SOME_VAR := some_val
export SOME_VAR
VAR1 := `echo $$SOME_VAR`
export VAR1
VAR2 := `echo $$VAR1`
all:
#echo VAR1=$(VAR1)
#echo VAR2=$(VAR2)
Will output:
~/tmp/t2> make
VAR1=some_val
VAR2=`echo $SOME_VAR`
Where I want it to print "VAR2=some_val". The real example is a bit more complicated (environment variables are inherited from parent makefiles, and I'm trying to use a perl script to edit the variables), but the principle is the same.
Any help is appreciated.
Is this what you want?
VAR2 := $(shell VAR1="$(VAR1)" script_that_uses_var1)
What's wrong with this?
VAR1 := $(shell echo $(SOME_VAR))
VAR2 := $(shell echo $(VAR1))
You may try to use Special Built-in Target Name: .EXPORT_ALL_VARIABLES
.EXPORT_ALL_VARIABLES:
MY_VAR = foo
test:
#echo $$MY_VAR
As I mentioned in some of the comments, my actual goal was to make the script generate filenames based on the settings the object was being compiled with. I then need another script to generate a specially formatted list of all the filenames generated (the target is an embedded system which doesn't have a JIT compiler on it). At any given time, there are over thirty settings which can potentially effect the binary, and this may be used on more than one module in the future, so I'd like something scalable.
My solution is as follows. Instead of passing the variables in, I modified my script to output a makefile-parsable string based on the settings:
-include $(SOME_MK_FILE)
$(SOME_MK_FILE) : .phony
script.pl $(SETTINGS_OF_INTEREST_LIST) > $(SOME_MK_FILE)
someFilename := $(shell script2.pl $(VAR1))
script.pl outputs a string that looks something like:
VAR1 := CONFIG_X1=$(CONFIG_X1) CONFIG_X2=$(CONFIG_X2) CONFIG_X33=$(CONFIG_X33)
and script2 outputs a filename that looks something like 'someFilename.X1_y.X2_n.elf'
and then, later on, in another rule, I have:
someobj: somedep
script3.pl $(someFilename) >> builtfiles.txt
which properly builds builtfiles.txt (which in turn is the input for yet another script...). In the end this is a workaround to the fact that make cannot pass its environement to $(shell). It's not overly pretty but it works.
John
Here you go:
export FOO=bar
Here's a page with a lot more info:
http://www.cmcrossroads.com/article/basics-getting-environment-variables-gnu-make?page=0%2C1

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