makefile: find a position of word in a variable

后端 未结 6 1429
我寻月下人不归
我寻月下人不归 2020-12-20 21:16

In my makefile, I need to make a variable assignment based on a command line variable value. for example, I do:

make var_1=xxx

where

相关标签:
6条回答
  • 2020-12-20 21:51

    There's a smooth way to do this using recursion as follows. First define a function called pos that finds the position of an element in a list and then use $(word) to extract the corresponding element in another list.

    Here's pos:

    _pos = $(if $(findstring $1,$2),$(call _pos,$1,\
           $(wordlist 2,$(words $2),$2),x $3),$3)
    pos = $(words $(call _pos,$1,$2))
    

    Read this answer to understand how it works: Makefile: find function which returns position

    Now it's easy to define a function that finds an element in a list and the finds the corresponding element in another list.

    lookup = $(word $(call pos,$1,$2),$3)
    

    And then try if out like this:

    ALPHA := a b c d e f g h i j k l m n o p q r s t u v w x y z
    NATO := alpha beta charlie delta echo foxtrot gamma hotel india\
            juliet kilo lima mike november oscar papa quebec romeo\
            sierra tango uniform victor whisky yankee zulu
    to-nato = $(call lookup,$1,$(ALPHA),$(NATO))
    

    To make a to-nato function that converts from a letter of the alphabet to the NATO alphabet.

    0 讨论(0)
  • 2020-12-20 21:53

    It's a little kludgey, but if there's a symbol you know won't be in any of the values (such as "_") you could do this:

    var_1_values = a b c d
    var_2_values = A B C D
    
    # This will be a_A b_B c_C d_D
    LIST1 = $(join $(addsuffix _,$(var_1_values)),$(var_2_values))
    
    var_1 := a
    
    # The filter gives a_A, the subst turns it into A
    var_2 = $(subst $(var_1)_,,$(filter $(var_1)_%, $(LIST1)))
    
    0 讨论(0)
  • 2020-12-20 21:53

    This works in mingw gnu make 4.3 :

    define get_index
    $(shell \
        $(eval _c = 1)\
        $(eval _b = n n) \
        $(foreach x,$(2), \
            $(eval _b += n \
            $(eval _c = $(words $(_b)) \
            $(if $(filter $(1),$(x)), \
                $(eval _r = $(_c)))))) \
                echo $(_r) \
        $(eval _c =) \
        $(eval _b =) \
        $(eval _r =) \
    )
    endef
    

    Takes two arguments; the word to search for and the list where to search. The index is 'returned' by echoing in $(shell ...)

    Example:

    list = cow horse chicken
    index = $(call get_index,horse,$(list))
    @echo $(index)
    
    # output: 2
    
    0 讨论(0)
  • 2020-12-20 21:57
    FAB = macrofab
    # NOTE: base starts at 1 instead of 0
    none := 1
    seeed := 1
    oshpark := 2
    macrofab := 2
    pcbng := 3
    #NOTE: String must end with a space for word function to work
    SUFFIX_DRILLS := "txt xln drl "
    
    .PHONY: gerber
    
    gerber:
        @echo $(FAB) drill suffix is $(word $($(FAB)), $(SUFFIX_DRILLS))
    

    Output of make is: macrofab drill suffix is xln

    0 讨论(0)
  • 2020-12-20 22:04

    This can be done quite slickly using recursion inside GNU make functions as follows:

    _pos = $(if $(findstring $1,$2),$(call _pos,$1,\
           $(wordlist 2,$(words $2),$2),x $3),$3)
    pos = $(words $(call _pos,$1,$2))
    

    To use it you would $(call) the pos function with two arguments: the item to find and the list to find it in. For example,

    $(call pos,a,a b c d e f g)
    $(call pos,e,a b c d e f g)
    $(call pos,g,a b c d e f g)
    $(call pos,h,a b c d e f g)
    $(call pos,e,))
    

    It works by recursing through the $2 argument until it can no longer find the value in $1. Each time it recurses it lops the head off $2 using $(wordlist 2,$(words $2),$2). Each time is recurses it adds an x to the returned string so that there is one x for each position through $2 up to where $1 was found.

    It then just uses $(words) to count the length of the return from _pos (the number of xs).

    If you use the GMSL project this can be written more slickly write this as:

    _pos = $(if $(findstring $1,$2),$(call $0,$1,$(call rest,$2),x $3),$3)
    pos = $(words $(call _$0,$1,$2))
    

    Note that I used $0 here which will contain the name of the current function (that's a standard GNU make feature) and the GMSL function rest to lop the head off the list.

    0 讨论(0)
  • 2020-12-20 22:09

    One way simulate associative containers in make is to use computed variables. E.g.:

    var_2.a := A
    var_2.b := B
    # ...
    
    # lookup
    var_2 = ${var_2.${var_1}}
    # or, lookup and assign a default value if lookup fails
    var_2_or_default = $(or ${var_2.${var_1}},<default-value>)
    
    0 讨论(0)
提交回复
热议问题