passing strings to a make file - gnu-make

I would like to do the following. I don't know whether it's possible to do it. If possible I would like to know how to do it.
make VAR1=arg1,arg2,arg3
based on the arg I would like to pass a switch to gcc.
For example,
if arg1 and arg2 are passed I would like to define a switch and if arg2 and arg3 are passed I would like to define another switch in the make file. How do I do that?

Use make VAR1="arg1 arg2 arg3" with this in the makefile:
ifeq (arg1 arg2,$(findstring arg1,$(VAR1)) $(findstring arg2,$(VAR1)))
# define a switch
endif
ifeq (arg2 arg3,$(findstring arg2,$(VAR1)) $(findstring arg3,$(VAR1)))
# define another switch
endif
If there are a lot of these switches, you can define a macro to simplify the makefile.

Did you check GMSL?
http://gmsl.sourceforge.net/
conditional-directive
text-if-true
endif
https://stackoverflow.com/a/180818/643500
...
if you want to pass it seperated by commas, then you can split the string and pass it to the if statements.

Related

Is it possible to define a custom "#" escape functions in jq?

We have a number of builtin format/escape functions: #csv, #sh, etc
… | #sh
#sh "\( … )"
It is possible to define a custom format/escape function, say #sql?
Um. Technically, yes. I don't think I could recommend it, but it does appear to be possible.
First of all, you need to understand that #csv, #sh etc aren't separate functions from jq's point of view. They're all implemented by the format/1 function. This function takes a single string argument that is the name of the format to use, e.g. "csv" or "sh". You can redefine this function, and lo and behold jq will use it for formatting!
jq -n 'def format(fstring): "XXX";[1,2,3]|#json'
"XXX"
Okay, that's not very useful. How about this?
jq -n '
def format(fstring):
if fstring=="sparkle" then
".:!" + (tostring) + "!:."
else
oldformat(fstring)
end
;
[1,2,3]|#sparkle
'
".:![1,2,3]!:."
It worked! But don't get too excited...
jq -n '
def format(fstring):
if fstring=="sparkle" then
".:!" + (tostring) + "!:."
else
oldformat(fstring)
end
;
[1,2,3]|#json
'
Uh oh, that just hangs. Although we were hoping to delegate to the original format when we don't know what to do with the format, we actually called our new format function recursively. It just keeps calling itself forever. It looks like we might be out of luck on our extremely cursed quest. However, if we read the jq manual carefully, there is a glimmer of hope:
Multiple definitions using the same function name are allowed. Each re-definition replaces the previous one for the same number of function arguments, but only for references from functions (or main program) subsequent to the re-definition. See also the section below on scoping.
Great! We can use this to save the old format function:
jq -n '
def oldformat(fstring):
format(fstring);
def format(fstring):
if fstring=="sparkle" then
".:!" + (tostring) + "!:."
else
oldformat(fstring)
end
;
[1,2,3]|(#sparkle,#json,#sh)
'
".:![1,2,3]!:."
"[1,2,3]"
"1 2 3"
I really don't recommend this: it's awkward to do, not terribly useful, and I have no idea if it's going to break something else. The format function doesn't appear to be documented so it's likely an unsupported implementation detail. But it was fascinating to find out that this is technically possible.

How to limit recursion depth while expanding variable in GNU makefile?

I need macro (variable) for GNU makefile, that searches file/directory by given mask at some of toplevel directories. For example, current working directory is /home/sysop/powerup/native/apps/toopl. Also exists directory /home/sysop/powerup/native/SDK/build. I want to find location of SDK/build directory relative to current one. So, I wrote recursive macros for that:
upfind = $(if $(wildcard $(1)),$(1),$(if $(filter $(abspath $(1)),$(abspath ../$(1))),$(error "can't find $(1)"),$(call upfind,../$(1))))
And I now can use it in following way:
relpath = $(call upfind, ../SDK/build)
And this assigns value "../../SDK/build" to relpath variable.
All fine, but I need propagate such macro to multiple makefiles, so I'am looking way to minimize it (upfind macro). I hope, anybody suggests me how to rewrite this macro in more compact way. For example, it's enought to limit recursion at some level, using of $(abspath) macro isn't necessary. But how can I determine recursion level or measure argument ($(1))length?
Not sure what you are asking here, so this probably isn't an answer.
The recursion limit is simple enough.
First, a bit of tidying:
assert-root = $(if $(filter $(abspath $1),$(abspath ../$1)),$(error Can't find $1))
upfind = $(if $(wildcard $1),$1,${assert-root}$(call upfind,../$1))
(Note how $assert-root is not called, it simply inherits the exisiting $1.)
Makes it a bit clearer how we can limit recursion depth: just pass an ever-lengthening $2.
maxup := 3
assert-depth = $(if $(filter ${maxup},$(words $2)),$(error Can't find [$1] within ${maxup} parents))
upfind = $(if $(wildcard $1),$1,${assert-depth}$(call upfind,../$1,_ $2))
Do both at the same time if you like
upfind = $(if $(wildcard $1),$1,${assert-depth}${assert-root}$(call upfind,../$1,_ $2))

Parameter file in ArgParse.jl?

Python's argparse has a simple way to read parameters from a file:
https://docs.python.org/2/library/argparse.html#fromfile-prefix-chars
Instead of passing your arguments one by one:
python script.py --arg1 val1 --arg2 val2 ...
You can say:
python script.py #args.txt
and then the arguments are read from args.txt.
Is there a way to do this in ArgParse.jl?
P.S.: If there is no "default" way of doing this, maybe I can do it by hand, by calling parse_args on a list of arguments read from a file. I know how to do this in a dirty way, but it gets messy if I want to replicate the behavior of argparse in Python, where I can pass multiple files with #, as well as arguments in the command line, and then the value of a parameter is simply the last value passed to this parameter. What's the best way of doing this?
This feature is not currently present in ArgParse.jl, although it would not be difficult to add. I have prepared a pull request.
In the interim, the following code suffices for what you need:
# faithful reproduction of Python 3.5.1 argparse.py
# partial copyright Python Software Foundation
function read_args_from_files(arg_strings, prefixes)
new_arg_strings = AbstractString[]
for arg_string in arg_strings
if isempty(arg_string) || arg_string[1] ∉ prefixes
# for regular arguments, just add them back into the list
push!(new_arg_strings, arg_string)
else
# replace arguments referencing files with the file content
open(arg_string[2:end]) do args_file
arg_strings = AbstractString[]
for arg_line in readlines(args_file)
push!(arg_strings, rstrip(arg_line, '\n'))
end
arg_strings = read_args_from_files(arg_strings, prefixes)
append!(new_arg_strings, arg_strings)
end
end
end
# return the modified argument list
return new_arg_strings
end
# preprocess args, then parse as usual
ARGS = read_args_from_files(ARGS, ['#'])
args = parse_args(ARGS, s)

Printing unexpanded recursive variables in gnu make

Is there a way to print the unexpanded definition of a recursive variable? I have a complicated build system, and a user can set some values. I'd like to echo the user definition to another file, for later use.
For example,
externals = $(HOME)/externals
all:
echo $(externals)
doesn't work, because it echos using the current definition of HOME. I'd like it to echo
the literal string $(HOME)/externals without expanding $(HOME).
The value function is probably what you want here.
8.8 The value Function
The value function provides a way for you to use the value of a variable without having it expanded. Please note that this does not undo expansions which have already occurred; for example if you create a simply expanded variable its value is expanded during the definition; in that case the value function will return the same result as using the variable directly.
The syntax of the value function is:
$(value variable)
Note that variable is the name of a variable, not a reference to that variable. Therefore you would not normally use a ‘$’ or parentheses when writing it. (You can, however, use a variable reference in the name if you want the name not to be a constant.)
The result of this function is a string containing the value of variable, without any expansion occurring. For example, in this makefile:
FOO = $PATH
all:
#echo $(FOO)
#echo $(value FOO)
The first output line would be ATH, since the “$P” would be expanded as a make variable, while the second output line would be the current value of your $PATH environment variable, since the value function avoided the expansion.
The value function is most often used in conjunction with the eval function (see Eval Function).
Though in addition to this you are going to need to use single quotes on that echo line or the shell will expand things on you.
$ cat Makefile
externals = $(HOME)/externals
all:
echo $(externals)
allv:
echo $(value externals)
allvq:
echo '$(value externals)'
$ make all
echo /home/user/externals
/home/user/externals
$ make allv
echo $(HOME)/externals
/bin/sh: HOME: command not found
/externals
$ make allvq
echo '$(HOME)/externals'
$(HOME)/externals

Bourne shell scripts with user input

I'm trying to teach myself the basics of Bourne shell scripting using a textbook I borrowed from the library, and I'm working through the questions at the end of each chapter. However, I just got to one and I'm stumped...
Write a script that takes zero or more arguments and prints the last argument in the list. For example, given the argument 'myProgram arg1 arg2 arg3', the output would be 'arg3'.
Could anyone give me some advice on how to set this one up? I'm trying to review the section on user input and arguments, but I haven't worked with that much so far, so I don't have much practice yet.
echo ${!#} # bash only
eval echo \${$#} # sh-compatible
Explanation
The number of arguments is $#. Variables can be accessed indirectly via ${!VAR}. For example:
$ VAR="PATH"
$ echo ${!VAR}
/sbin:/bin:/usr/sbin:/usr/bin
Put those together and if we have a variable $n containing an integer we can access the $nth command-line argument with ${!n}. Or instead of $n let's use $#; the last command-line argument is ${!#}!
Additionally, this can be more longwindedly written using array slicing ($# is an array holding all the command-line arguments) as:
echo ${#:$#:$#}
Oddly, you cannot use an array index:
# Does not work
echo ${#[$#]}
I'll just give you some pointers. Since you want to learn bash, you probably don't just want a piece of code that does what the question asks:
1) Do you know how to count how many arguments your bash function has?
2) Do you know how to loop?
3) Do you know how to "pop" one of the arguments?
4) Do you know how to print out the first argument?
If you put all that together, I bet you'll come up with it.

Resources