Gnu make with multiple % in pattern rule? - makefile

If I understand the make documentation correctly I can only use character % once in my target-pattern!
I am facing a condition which my target is look like:
$(Home)/ecc_%_1st_%.gff: %.fpp
And whenever I am trying to match /home/ecc_map_1st_map.gff: map.fpp
Make complains that can't find a pattern.
I know it is because of using % twice ($(Home)/ecc_map_1st_%.gff: %.fpp runes perfectly)
Is there anyway which I can use two % in one target!?
Thanks

You can't have two patterns. The best way would be not having map twice in the target name.
If you must, and you're using GNU make, secondary expansion might be useful:
.SECONDEXPANSION:
$(Home)/ecc_%.gff: $$(word 1,$$(subst _, ,$$*)).fpp
Normally you can't use automatic variables such as $* in prerequisites, but secondary expansion allows you to do just that. Note that I used $$ in place of $ so that the real expansion happens in the second pass and not in the first one.
Say you are making $(Home)/ecc_map_1st_map.gff. The $* variable is going to be the stem, i.e. map_1st_map. Then $(subst _, ,...) replaces underscores with spaces, to obtain map 1st map. Now $(word N,...) extracts the N-th space-separated word in there. First word would be the first map, second would be 1st, third would be the second map. I'm picking the first one.
Of course this is pretty lax and doesn't guarantee you'll match exactly the targets you wanted ($(Home)/ecc_map_2nd_notmap__foo.gff would match and give map.fpp). You could do further checks (1st in the middle, other two must match) and bail out:
extract-name = $(call extract-name-helper,$1,$(word 1,$(subst _, ,$1)))
extract-name-helper = $(if $(filter $2_1st_$2,$1),$2,$(error Invalid .gff target))
.SECONDEXPANSION:
ecc_%.gff: $$(call extract-name,$$*).fpp
But that doesn't look like a sensible solution.
Wrapping up, if don't have similarly named files, then the first solution would work well. Also, if you know the target names beforehand, you could make it safer with an explicit pattern rule (or even generate them on the fly).

Related

Glob string pattern for one or more files

I need a pattern for one or more files, name of each will be known before the matching occurs (but I do not know what they are right now).
For example, one occurence could be two files: A.lkml and B.lkml, and another could be three: CDFDFDSADF.lkml, SD.lkml and R4545452.lkml. The filenames will be passed as a single argument with single space as separator (So for example 1, will see A.lkml B.lkml).
What I can be sure of:
all files end with .lkml
for each matching, I need to add a manifest.lkml into the list. For example, in example 1, the list should contain 3 instead of 2 filenames, A.lkml, B.lkml and manifest.lkml
What puzzles me is that glob pattern matching doesn't seem to be able to do logic "OR". I have tried to use ",", "|" to no avail. In my experiments I fixed the filenames but in reality they change each time.
Update: I think brace expression such as {a.lkml,manifest.lkml} should work. Somehow it doesn't pass.

Jflex ambiguity

I have these two rules from a jflex code:
Bool = true
Ident = [:letter:][:letterdigit:]*
if I try for example to analyse the word "trueStat", it gets recognnized as an Ident expression and not Bool.
How can I avoid this type of ambiguity in Jflex?
In almost all languages, a keyword is only recognised as such if it is a complete word. Otherwise, you would end up banning identifiers like format, downtime and endurance (which would instead start with the keywords for, do and end, respectively). That's quite confusing for programmers, although it's not unheard-of. Lexical scanner generators, like Flex and JFlex generally try to make the common case easy; thus, the snippet you provide, which recognises trueStat as an identifier. But if you really want to recognise it as a keyword followed by an identifier, you can accomplish that by adding trailing context to all your keywords:
Bool = true/[:letterdigit:]*
Ident = [:letter:][:letterdigit:]*
With that pair of patterns, true will match the Bool rule, even if it occurs as trueStat. The pattern matches true and any alphanumeric string immediately following it, and then rewinds the input cursor so that the token matched is just true.
Note that like Lex and Flex, JFlex accepts the longest match at the current input position; if more than one rule accepts this match, the action corresponding to the first such rule is executed. (See the manual section "How the Input is Matched" for a slightly longer explanation of the matching algorithm.) Trailing context is considered part of the match for the purposes of this rule (but, as noted above, is then removed from the match).
The consequence of this rule is that you should always place more specific patterns before the general patterns they might override, whether or not the specific pattern uses trailing context. So the Bool rule must precede the Ident rule.

How to replace any one of many possible matches in bash

I want to reduce this down to one line:
item=${_menu_sel_value/M--/}
item=${item/-M-/}
item=${item/D--/}
item=${item/-D-/}
item=${item/??-/}
Here is a test sample. User chooses one of the following from a shell menu and their choice is passed into bash script code above (so, only need to match ONE of the possibilities):
-D-branch.sh
M--cfg/aliases.cfg
-M-functions/0300.menu.sh
M--git_aliases.sh
??-add.sh
Is it possible?
I tried something like:
item=${_menu_sel_value/^[M\-]/}
But it didn't work.
I think this is what you are looking for.
shopt -s extglob
item=${_menu_sel_value/#(M--|-M-|D--|-D-|\?\?-)/}
The pattern #(a|b|c) matches any one of the patterns a, b, or c. Note the need to escape the ?, as it is a wildcard that matches any single character in a pattern.
If you know that you'll always have the first three characters that need to be stripped off, you can just use a substring operation:
item=${_menu_sel_value:3}

How to change the extension of each file in a list with multiple extensions in GNU make?

In a GNU makefile, I am wondering if it is possible, with an file list input, to make a file list output with new extensions.
In input, I get this list:
FILES_IN=file1.doc file2.xls
And I would like to build this variable in my makefile from FILES_IN variable:
FILES_OUT=file1.docx file2.xlsx
Is it possible ? How ?
It's quite difficult because I have to parse file list, and detect each extension (.doc, .xls) to replace it to correct extension.
Substituting extensions in a list of whitespace-separated file names is a common requirement, and there are built-in features for this. If you want to add an x at the end of every name in the list:
FILES_OUT = $(FILES_IN:=x)
The general form is $(VARIABLE:OLD_SUFFIX=NEW_SUFFIX). This takes the value of VARIABLE and replaces OLD_SUFFIX at the end of each word that ends with this suffix by NEW_SUFFIX (non-matching words are left unchanged). GNU make calls this feature (which exists in every make implementation) substitution references.
If you just want to change .doc into .docx and .xls into .xlsx using this feature, you need to use an intermediate variable.
FILES_OUT_1 = $(FILES_IN:.doc=.docx)
FILES_OUT = $(FILES_OUT_1:.xls=.xlsx)
You can also use the slightly more general syntax $(VARIABLE:OLD_PREFIX%OLD_SUFFIX=NEW_PREFIX%NEW_SUFFIX). This feature is not unique to GNU make, but it is not as portable as the plain suffix-changing substitution.
There is also a GNU make feature that lets you chain multiple substitutions on the same line: the patsubst function.
FILES_OUT = $(patsubst %.xls,%.xlsx,$(patsubst %.doc,%.docx,$(FILES_IN)))

One more difference between gcc's and MS preprocessor

One more difference between gcc preprocessor and that of MS VS cl. Consider the following snippet:
# define A(x) L ## x
# define B A("b")
# define C(x) x
C(A("a" B))
For 'gcc -E' we get the following:
L"a" A("b")
For 'cl /E' the output is different:
L"a" L"b"
MS preprocessor somehow performs an additional macro expansion. Algorithm of its work is obviously different from that of gcc, but this algorithm also seems to be a secret. Does anyone know how the observed difference can be explained and what is the scheme of preprocessing in MS cl?
GCC is correct. The standard specifies:
C99 6.10.3.4/2 (and also C++98/11 16.3.4/2): If the name of the macro being replaced is found during this scan of the replacement list
(not including the rest of the source file’s preprocessing tokens), it is not replaced.
So, when expanding A("a" B), we first replace B to give A("a" A("B")).
A("B") is not replaced, according to the quoted rule, so the final result is L"a" A("B").
Mike's answer is correct, but he actually elides the critical part of the standard that shows why this is so:
6.10.3.4/2 If the name of the macro being replaced is found during this scan of the replacement list
(not including the rest of the source file’s preprocessing tokens), it is not replaced.
Furthermore, if any nested replacements encounter the name of the macro being replaced,
it is not replaced. These nonreplaced macro name preprocessing tokens are no longer
available for further replacement even if they are later (re)examined in contexts in which
that macro name preprocessing token would otherwise have been replaced.
Note the last clause here that I've emphasized.
So both gcc and MSVC expand the macro A("a" B) to L"a" A("b"), but the interesting case (where MSVC screws up) is when the macro is wrapped by the C macro.
When expanding the C macro, its argument is first examined for macros to expand and A is expanded. This is then substituted into the body of C, and then that body is then scanned AGAIN for macros to replace. Now you might think that since this is the expansion of C, only the name C will be skipped, but this last clause means that the tokens from the expansion of A will also skip reexpansions of A.
There are basically two ways of how one could think that the remaining occurrance of the A macro should be replaced:
The first would be the processing or macro arguments before they are inserted in place of the corresponding parameter in the macro's replacement list. Usually each argument is complete macro-replaced as if it formed the rest of the input file, as decribed in section 6.10.3.1
of the standard. However, this is not done if the parameter (here: x) occurs next to the ##; in this case the parameter is simply replaced with the argument according to 6.10.3.3, without any recursive macro replacement.
The second way would be the "rescanning and further replacement" of section 6.10.3.4, but this not done recursively for a macro that has already been replaced once.
So neither applies in this case, which means that gcc is correct in leaving that occurrence of A unreplaced.

Resources