GNU Make using : syntax - makefile

Working with this simple code, can someone explain how are the last two lines compiled
PROJECT_NAME := PRJ
TARGETS := nrf52840_xxaa
OUTPUT_DIRECTORY := _build
SDK_ROOT := ../nRF5_SDK_17.1.0_ddde560
$(OUTPUT_DIRECTORY)/nrf52840_xxaa.out: \
LINKER_SCRIPT := Core/PRJ.ld

The last two lines don't specify any build rule, but instead specify a target-specific variable value for the target $(OUTPUT_DIRECTORY)/nrf52840_xxaa.out and the variable LINKER_SCRIPT. The build rule is either specified elsewhere, or a default build rule is used.

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.

Makefile: add directory and modify extenstion in path

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))

Make: Variable assignment

I am facing the issue while accessing a variable from other makefile which is included.
i have test.mak which has variable LIBS32 := $(TESTLIBS)/$(NEW_PLAT32)
i have included test.mak in other makefile and trying to assign that variable in one of the target.
extlib32: EXTLIBS = $(LIBS32)
extlib64: EXTLIBS = $(LIBS64)
The expected value of EXTLIBS should be '/home/testlib/extlibs/Linux' . But here when i print EXTLIBS the value which i am seeing is '/home/testlib/extlibs/'
Note:- When i jut print LIBS i can see the content as expected. But when i assigned to EXTLIBS and try to use it.. I can see word 'Linux' is missing.
Thanks!
You set EXTLIBS as a target-specific variable for target extlib32. Such variables are non-global and their value is only available in the target recipe and target's prerequisites, rather than globally (this is why $(info $(EXTLIBS)) doesn't print the expected value).
To print its value you need to print it from the recipe of target extlib32, e.g.:
extlib32:
#echo "EXTLIBS=${EXTLIBS}"
If extlib32 and extlib64 are .PHONY targets to build something then your original target-specific assignments should propagate to the dependencies and be available in their recipes. You just cannot print its value from the global makefile scope.
To have one makefile build both in 32 and 64-bit mode (as well as release and debug) you need to structure it differently and invoke make separately for each build mode. Example:
# User can overrided capitalized variables. E.g.
# make BUILD=release MODE=32 LDLIBS=-lrt
BUILD := debug
MODE := 64
build_dir := ${BUILD}/${MODE}
ldlibs.32 := my-32-bit-libs
ldlibs.64 := my-64-bit-libs
ldlibs := ${ldlibs.${MODE}} ${LDLIBS}
all :
#echo "build_dir=${build_dir}"
#echo "ldlibs=${ldlibs}"
Usage examples:
$ make
build_dir=debug/64
ldlibs=my-64-bit-libs
$ make BUILD=release MODE=32
build_dir=release/32
ldlibs=my-32-bit-libs
Another example for debug/release compiler options.

Make not reevaluating dependency variable

I have a Makefile designed to build a few different programmes. My SOURCES and OBJECTS depend on PRODUCT, which should be the product being built. At the moment, I set PRODUCT before listing the dependency on OBJECTS on each rule:
CORE_LIB := libcore
SCANNER := scanner
FLETCHER := fletcher
PRODUCT := $(SCANNER)
SOURCE_DIR := ./src
BUILD_DIR := ./build
OBJECTS_DIR := $(BUILD_DIR)/intermediate
PRODUCT_DIR := $(BUILD_DIR)/product
SOURCES = $(wildcard $(SOURCE_DIR)/$(PRODUCT)/*.c) $(wildcard $(SOURCE_DIR)/$(PRODUCT)/*/*.c)
OBJECTS = $(SOURCES:$(SOURCE_DIR)/%.c=$(OBJECTS_DIR)/%.o)
# change PRODUCT based on rule being ran
$(SCANNER): PRODUCT := $(SCANNER)
$(SCANNER): $(OBJECTS)
# link stuff
$(CORE_LIB): PRODUCT := $(CORE_LIB)
$(CORE_LIB): $(OBJECTS)
# link stuff
However, OBJECTS keep being evaluated before PRODUCT is set, and never changes based on the rule. Is there anything I'm missing?
You can't do that. The GNU make manual states, regarding target-specific variables:
As with automatic variables, these values are only available within the context of a target’s recipe (and in other target-specific assignments).
This means that you can't use target-specific variable values during the expansion of prerequisites, like $(OBJECTS). Or rather, you can use any variable there but the target-specific value is not available. Since you set the value of PRODUCT globally to be $(SCANNER), which is scanner, that's the value that will be used in all prerequisites.
You have multiple options. You can just define multiple variables, like this:
$(SCANNER)_SOURCES = $(wildcard $(SOURCE_DIR)/$(SCANNER)/*.c) $(wildcard $(SOURCE_DIR)/$(SCANNER)/*/*.c)
$(CORE_LIB)_SOURCES = $(wildcard $(SOURCE_DIR)/$(CORE_LIB)/*.c) $(wildcard $(SOURCE_DIR)/$(CORE_LIB)/*/*.c)
Then create rules like this:
$(SCANNER): $($(SCANNER)_SOURCES:$(SOURCE_DIR)/%.c=$(OBJECTS_DIR)/%.o)
# link stuff
$(CORE_LIB): $($(CORE_LIB)_SOURCES:$(SOURCE_DIR)/%.c=$(OBJECTS_DIR)/%.o)
# link stuff
If you have more of these, you could create a macro and use eval but I wouldn't bother with the complexity unless you really are going to have a bunch of them.
You can simplify the target definitions a bit using Secondary Expansion, like this:
OBJECTS = $$($$#_SOURCES:$(SOURCE_DIR)/%.c=$(OBJECTS_DIR)/%.o)
.SECONDEXPANSION:
$(SCANNER): $(OBJECTS)
# link stuff
$(CORE_LIB): $(OBJECTS)
# link stuff

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