Pasando variables adicionales desde la línea de comando para hacer

614

¿Puedo pasar variables a un archivo Make de GNU como argumentos de línea de comandos? En otras palabras, quiero pasar algunos argumentos que eventualmente se convertirán en variables en el Makefile.

Pablo
fuente

Respuestas:

754

Tiene varias opciones para configurar variables desde fuera de su archivo MAKE:

  • Desde el entorno : cada variable de entorno se transforma en una variable de archivo MAKE con el mismo nombre y valor.

    También es posible que desee establecer la -eopción (aka --environments-override) activada , y sus variables de entorno anularán las asignaciones realizadas en el archivo MAKE (a menos que estas asignaciones usen la overridedirectiva . Sin embargo, no es recomendable, y es mucho mejor y flexible usar la ?=asignación (la variable condicional operador de asignación, solo tiene efecto si la variable aún no está definida):

    FOO?=default_value_if_not_set_in_environment
    

    Tenga en cuenta que ciertas variables no se heredan del entorno:

    • MAKE se obtiene del nombre del guión
    • SHELLse establece dentro de un archivo MAKE o se establece de manera predeterminada /bin/sh(justificación: los comandos se especifican dentro del archivo MAKE y son específicos del shell).
  • Desde la línea de comando : makepuede tomar asignaciones variables como parte de su línea de comando, mezcladas con objetivos:

    make target FOO=bar
    

    Pero entonces todas las asignaciones a FOOvariables dentro del archivo MAKE serán ignoradas a menos que use la overridedirectiva en la asignación. (El efecto es el mismo que con la -eopción para las variables de entorno).

  • Exportar desde el Make primario : si llama a Make desde un Makefile, por lo general no debería escribir explícitamente asignaciones de variables como esta:

    # Don't do this!
    target:
            $(MAKE) -C target CC=$(CC) CFLAGS=$(CFLAGS)
    

    En cambio, la mejor solución podría ser exportar estas variables. La exportación de una variable lo convierte en el entorno de cada invocación de shell, y Realizar llamadas desde estos comandos selecciona estas variables de entorno como se especifica anteriormente.

    # Do like this
    CFLAGS=-g
    export CFLAGS
    target:
            $(MAKE) -C target
    

    También puede exportar todas las variables utilizando exportsin argumentos.

P Shved
fuente
11
pasar de la línea de comando algo con espacios hacermake A='"as df"'
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
44
Parece que estás buscando problemas si te interesan las variables de entorno. Por un lado, es una pesadilla de depuración si funciona en el lugar A y no en el lugar B, solo porque tienen entornos diferentes.
James Moore
12
Basándose en la experiencia, exportar cosas como CFLAGS es una receta para la pesadilla para grandes proyectos. Los proyectos grandes a menudo tienen bibliotecas de terceros que solo se compilan con un conjunto dado de indicadores (que nadie se molesta en arreglar). Si exporta CFLAGS, los CFLAGS de su proyecto terminan anulando la biblioteca de terceros y desencadenan errores de compilación. Una forma alternativa podría ser definirlo export PROJECT_MAKE_ARGS = CC=$(CC) CFLAGS=$(CFLAGS)y pasarlo como make -C folder $(PROJECT_MAKE_FLAGS). Si hay una manera de decirle al archivo MAKE de la biblioteca que ignore el entorno, sería ideal (opuesto a -e).
RD
24
ADVERTENCIA: en la sección "Exportar desde la marca principal" anterior, "¡No haga esto!" Es críticamente engañoso . Pasar variables en la línea de comando anula las asignaciones en el sub-archivo MAKE pero las variables exportadas no anulan las asignaciones en el sub-archivo MAKE. Estos dos métodos para pasar variables a un sub-makefile no son equivalentes y no deben confundirse.
Jonathan Ben-Avraham
44
Alguna diferencia ? make target FOO=bar make FOO=bar target?
gfan
213

La forma más simple es:

make foo=bar target

Luego, en su archivo MAKE puede consultar $(foo). Tenga en cuenta que esto no se propagará a sub-marcas automáticamente.

Si está utilizando sub-marcas, vea este artículo: Comunicación de variables a una sub-marca

Mark Byers
fuente
2
por sub-marcas te refieres a los makefiles includeden el makefile principal?
Pablo
2
@Michael: significa llamar a make nuevamente desde el interior del makefile. He actualizado mi respuesta ya que parece estar interesado en este detalle.
Mark Byers,
2
"Tenga en cuenta que esto no se propagará a sub-marcas automáticamente". ¡Falso! "Por defecto, solo las variables que provienen del entorno o de la línea de comandos se pasan a invocaciones recursivas. Puede usar la directiva de exportación para pasar otras variables". gnu.org/software/make/manual/html_node/…
ThomasMcLeod
82

Digamos que tienes un makefile como este:

action:
    echo argument is $(argument)

Entonces lo llamarías make action argument=something

nc3b
fuente
55
entonces, ¿el objetivo y los argumentos pueden intercambiarse en términos de posición?
Pablo
44
@Michael: Sí (vea la respuesta de Mark Byers)
nc3b
25

Del manual :

Las variables en make pueden provenir del entorno en el que se ejecuta make. Cada variable de entorno que hace ver cuando se inicia se transforma en una variable de creación con el mismo nombre y valor. Sin embargo, una asignación explícita en el archivo MAKE, o con un argumento de comando, anula el entorno.

Entonces puedes hacer (desde bash):

FOOBAR=1 make

resultando en una variable FOOBARen su Makefile.

Thomas
fuente
2
La otra forma es realmente mejor en casi todos los casos. Dejaré esto aquí para completar.
Thomas
Esta es la única respuesta que muestra la asignación de variables antes del comando make en la misma línea; vale la pena saber que esto no es un error de sintaxis.
M_M
7

Hay otra opción no citada aquí que está incluida en el libro Make de GNU de Stallman y McGrath (ver http://www.chemie.fu-berlin.de/chemnet/use/info/make/make_7.html ). Proporciona el ejemplo:

archive.a: ...
ifneq (,$(findstring t,$(MAKEFLAGS)))
        +touch archive.a
        +ranlib -t archive.a
else
        ranlib archive.a
endif

Implica verificar si un parámetro dado aparece en MAKEFLAGS. Por ejemplo ... suponga que está estudiando sobre subprocesos en c ++ 11 y ha dividido su estudio en varios archivos ( class01, ..., classNM) y desea: compilar todo y ejecutarlo individualmente o compilar uno a la vez tiempo y ejecútelo si se especifica un indicador ( -rpor ejemplo). Entonces, podrías llegar a lo siguiente Makefile:

CXX=clang++-3.5
CXXFLAGS = -Wall -Werror -std=c++11
LDLIBS = -lpthread

SOURCES = class01 class02 class03

%: %.cxx
    $(CXX) $(CXXFLAGS) -o [email protected] $^ $(LDLIBS)
ifneq (,$(findstring r,  $(MAKEFLAGS)))
    ./[email protected]
endif

all: $(SOURCES)

.PHONY: clean

clean:
    find . -name "*.out" -delete

Teniendo eso, usted:

  • construir y ejecutar un archivo w / make -r class02;
  • construir todo w / makeor make all;
  • compila y ejecuta todos los w / make -r(supongamos que todos ellos contienen cierto tipo de afirmación y solo quieres probarlos todos)
Ciro Costa
fuente
6

parece

comando args sobrescribir variable de entorno

Makefile

send:
    echo $(MESSAGE1) $(MESSAGE2)

Ejecutar ejemplo

$ MESSAGE1=YES MESSAGE2=NG  make send MESSAGE2=OK
echo YES OK
YES OK
YumaInaura
fuente
5

Si crea un archivo llamado Makefile y agrega una variable como esta $ (unittest), entonces podrá usar esta variable dentro del Makefile incluso con comodines

ejemplo:

make unittest=*

Uso BOOST_TEST y al asignar un comodín al parámetro --run_test = $ (unittest), podré usar expresiones regulares para filtrar la prueba que quiero que ejecute mi Makefile

serup
fuente
4
export ROOT_DIR=<path/value>

Luego use la variable, $(ROOT_DIR)en el Makefile.

parasitar
fuente