How to use environment variable PROGRAMFILES(X86) in a GNU makefile? - makefile

I try to use the environment variable PROGRAMFILES(X86) of Windows 7 inside a GNU makefile without success.
Here a minimal example:
$(info DIR: $(PROGRAMFILES(X86)))
nop:
#echo x
If I execute this makefile I get only
DIR: )
x
while I expected:
DIR: C:\Program Files (x86)
x
Any idea how to use environment variable PROGRAMFILES(X86) in a GNU makefile?
I am using GNU make version 4.1 on Cygwin (and version 3.81 on native Windows).
I know that that there is also and environment variable "PROGRAMFILES", but I really need "PROGRAMFILES(X86)"

Etan came up with a very nice idea.
I did a slight modification and thus, the following actually works:
b1 := (
b2 := )
$(info DIR: $(ProgramFiles$(b1)x86$(b2)) )
nop:
#echo x
However I figured out a more easy way: Curly braces seem to do the trick too:
$(info DIR: ${ProgramFiles(x86)} )
nop:
#echo x
For both solutions it is also important to write ProgramFiles(x86) instead of upper case PROGRAMFILES(X86).

Related

How to modify PATH in GNU Make and perform commands with $(shell ...) successfully?

Background: I am having a customized toolchain which shall be used by a Makefile. The toolchain is checkout out (by svn:externals) into the working copy of the project. The Makefile must adapt the PATH Variable. Otherwise the toolchain-binaries cannot be found. Adapting the ´PATH´ in ´.bashrc´ or ´.profile´ is no option because there are several projects using different versions of the toolchain.
See this little minimal Makefile demonstrating the call to the cross compiler ´cc´ which is located next to several other tools in ´/home/edeviser/bin´:
export PATH:=/home/edeviser/bin:$(PATH)$
$(info Compiler used: $(shell which cc))
all:
#echo "Compiler used: $(shell which cc)"
#echo -n "Compiler used: "
#which cc
The output after calling make:
Compiler used: /usr/bin/cc
Compiler used: /usr/bin/cc
Compiler used: /home/edeviser/bin/cc
My expectation is:
Compiler used: /home/edeviser/bin/cc
Compiler used: /home/edeviser/bin/cc
Compiler used: /home/edeviser/bin/cc
How to modify PATH in GNU Make and perform commands with $(shell ...) successfully?
You have to write a shell invocation like this:
$(info Compiler used: $(shell PATH='$(PATH)' which cc))
to set the PATH in the shell function.

What is the nmake equivalent of filter-out?

I've been given a makefile for ubuntu, and I'm trying to use it with nmake on Windows 10.
nmake doesn't seem to recognize the filter-out keyword such as in the following line:
OBJS_TEST = $(filter-out $(EXE_OBJ), $(OBJS))
Does nmake have a keyword with the same functionality?
For completeness, the lines from the beginning of the file before the above line (and a few lines below) are as follows:
EXE = main
TEST = test
OBJS_DIR = .objs
###############################################
### THE LINE IN QUESTION IS BELOW #############
OBJS_TEST = $(filter-out $(EXE_OBJ), $(OBJS))
###############################################
CPP_TEST = $(wildcard tests/*.cpp)
# CPP_TEST += uiuc/catch/catchmain.cpp
# The above line doesn't work with the "+=" extension in nmake; replace with below.
CPP_TEST = $(CPP_TEST) $(wildcard tests/*.cpp)
The error reported is:
fatal error U1001: syntax error : illegal character '-' in macro
As far as I'm aware there is no equivalent to filter-out in nmake. Also, nmake does not support the wildcard function so you'll have to deal with that. And, I'm suspicious that your replacement for += won't work; in most versions of POSIX make FOO = $(FOO) is illegal as it gives an infinite loop of variable lookup. Maybe nmake works differently, though.
nmake is SO different from POSIX make and GNU make that you will either have to rewrite the makefile from scratch, or else just go get a version of GNU make for Windows (or build it yourself). GNU make is quite portable and runs well on Windows. That would be a LOT less work.

How to change PATH for Makefile $(shell ...) commands?

When I run
export PATH := mypath
$(error $(shell echo "$${PATH}"))
it seems my PATH isn't changed on the call to shell.
Why is this and how do I actually change the PATH for shell calls?
Is this with GNU make? There is a long-standing GNU make feature request to honor exported variables with $(shell …). This is not specific to PATH at all, it affects (or does not affect) all export variables.
According to the GNU make sources, this is tricky to implement:
/* Using a target environment for 'shell' loses in cases like:
export var = $(shell echo foobie)
bad := $(var)
because target_environment hits a loop trying to expand $(var) to put it
in the environment. This is even more confusing when 'var' was not
explicitly exported, but just appeared in the calling environment.
See Savannah bug #10593.
envp = target_environment (NULL);
*/
The solution is simple: never ever use $(shell) or export.
Environment variables should be part of the recipe that needs them.
For $(shell) invocations that are supposed to fill a makefile variable you can use instead.
it also has the advantage to be more flexible, because you can fill more than one variable with one recipe
you can also define proper dependencies, whereas $(shell) is always executed, either when the makefile is parsed or the recursively expanded variable gets expanded.
you get build errors and recipes are logged, whereas $(shell) can make the DevOp engineers life a living h...
PATH := mypath
Makefile.variables:
#PATH=$(PATH) echo "This my path '$${PATH}'"
echo >$# "MY_DYNAMIC_CONTENT := abcd"
include Makefile.variables
$(info MY_DYNAMIC_CONTENT '$(MY_DYNAMIC_CONTENT)')
Example run:
$ make
MY_DYNAMIC_CONTENT ''
This my path 'mypath'
echo >Makefile.variables "MY_DYNAMIC_CONTENT := abcd"
MY_DYNAMIC_CONTENT 'abcd'
make: 'Makefile.variables' is up to date.

Define a makefile target from variables set with eval

I have to define a target that contains a version number, which in turn is extracted from some file (the prerequisite of this target) retrieved from git.
What I first tried was to set a variable with eval and use this in the name, like this.
version_file:
#checkout
version: version_file
#eval version := get version from version_file
file_$(version):
#echo file_$(version)
final_target: file_$(version)
#echo $#
This cannot work: make reads the makefile in the first pass and does not find the variable dynamic_prerequisite, so the target created is simply named file_.
But when I try to create the rule dynamically, after the variable has been set, like this
...
define rule_file_version
file_$(version):
#echo version: $#
endef
version: version_file
#eval version := get version from version_file
$(eval $(rule_file_version))
... this gives me the error message:
makefile:12: *** prerequisites cannot be defined in recipes.
Of course I cannot move the eval for the target outside of the recipe, as I then encounter the same problem as before.
Is there a way to achieve what I want with gnu make?
I found the problem can be solved by using constructed include files.
For the construction of the files itself I created a simple shell script, that takes the dynamically set variable as an argument:
#!/bin/bash
read -r -d '' MAKE <<EOF
file_$1:
#echo version: $1
final_target: file_$1
#echo final_target: $1
EOF
echo "$MAKE" > rules.mk
This is used in the makefile to create an included makefile rules.mk, like this:
version_file:
#checkout
version: version_file
#eval version := get version from version_file
rules.mk: version
$(shell ./create_rules_mk.sh $(version))
-include rules.mk
When I run make final_target it creates the rules.mk as wished.
The bottom line for me is, that target names, that themselves depend on other targets have to use dynamic creation of makefiles.
Here is a much simpler approach:
blackbox.sh:
#!/bin/bash
echo 1.0
Makefile:
dynamic_prerequisite := $(shell ./blackbox.sh)
file_$(dynamic_prerequisite):
#echo target is $#
Another option is to use a build tool more suited to dynamic targets. For example, I've written a Gnu Make-like tool incorporating some of the concepts from DJB's ReDo, called GoodMake. Your equivalent makefile would just be:
#? version_file
checkout
#? final_target
$0 version_file # Static dependency
version=$(get version from version_file)
$0 file_$version # Dynamic dependency
Simpler, huh? If you try out GoodMake, I'd love to hear what you think!

Accessing environment variables from within a recipe in GNU make in windwos

I am trying to set an environment variable in windows and access the same within a recipe windows make.
The general code goes something like this:
$(foreach i, $(SHORTCUT_TARGETS), $(eval $(call BUILD_ARTIFACT,$(i),$(param1),$(param2))))
define BUILD_ARTIFACT
Rule: Prerequisites
#echo Building : $(1)
$(if $(filter $(1),string), ,setx LAST $(1) )
$(if $(filter $(1),string),\
#echo path-%LAST%,\
#echo path-$(1)
endef
When I run this, the setx command is executed successfully, generally giving an output "SUCCESS: Specified value was saved."
But the output of the echo will be path-%LAST% as opposed to an output with the environment variable replaced in. I have tried it from cmd and powershell and I've gotten the same output in both cases.
I have also tried replacing setx with set and export, neither approaches produced a positive result.

Resources