Sistema operativo que detecta el archivo MAKE


249

Rutinariamente trabajo en varias computadoras y sistemas operativos diferentes, que son Mac OS X, Linux o Solaris. Para el proyecto en el que estoy trabajando, extraigo mi código de un repositorio de git remoto.

Me gusta poder trabajar en mis proyectos sin importar en qué terminal estoy. Hasta ahora, he encontrado formas de sortear los cambios del sistema operativo cambiando el archivo MAKE cada vez que cambio de computadora. Sin embargo, esto es tedioso y causa muchos dolores de cabeza.

¿Cómo puedo modificar mi archivo MAKE para que detecte qué sistema operativo estoy usando y modifique la sintaxis en consecuencia?

Aquí está el archivo MAKE:

cc = gcc -g
CC = g++ -g
yacc=$(YACC)
lex=$(FLEX)

all: assembler

assembler: y.tab.o lex.yy.o
        $(CC) -o assembler y.tab.o lex.yy.o -ll -l y

assembler.o: assembler.c
        $(cc) -o assembler.o assembler.c

y.tab.o: assem.y
        $(yacc) -d assem.y
        $(CC) -c y.tab.c

lex.yy.o: assem.l
        $(lex) assem.l
        $(cc) -c lex.yy.c

clean:
        rm -f lex.yy.c y.tab.c y.tab.h assembler *.o *.tmp *.debug *.acts

Respuestas:


282

Ya hay muchas buenas respuestas aquí, pero quería compartir un ejemplo más completo que ambas:

  • no asume que unameexiste en Windows
  • también detecta el procesador

Los CCFLAGS definidos aquí no son necesariamente recomendados o ideales; son exactamente lo que estaba usando el proyecto al que estaba agregando la detección automática de SO / CPU.

ifeq ($(OS),Windows_NT)
    CCFLAGS += -D WIN32
    ifeq ($(PROCESSOR_ARCHITEW6432),AMD64)
        CCFLAGS += -D AMD64
    else
        ifeq ($(PROCESSOR_ARCHITECTURE),AMD64)
            CCFLAGS += -D AMD64
        endif
        ifeq ($(PROCESSOR_ARCHITECTURE),x86)
            CCFLAGS += -D IA32
        endif
    endif
else
    UNAME_S := $(shell uname -s)
    ifeq ($(UNAME_S),Linux)
        CCFLAGS += -D LINUX
    endif
    ifeq ($(UNAME_S),Darwin)
        CCFLAGS += -D OSX
    endif
    UNAME_P := $(shell uname -p)
    ifeq ($(UNAME_P),x86_64)
        CCFLAGS += -D AMD64
    endif
    ifneq ($(filter %86,$(UNAME_P)),)
        CCFLAGS += -D IA32
    endif
    ifneq ($(filter arm%,$(UNAME_P)),)
        CCFLAGS += -D ARM
    endif
endif

8
Lamentablemente, el PROCESSOR_ARCHITECTUREentorno parece estar virtualizado dependiendo de si el proceso es de 32 bits o de 64 bits. Entonces, si su makees de 32 bits y está tratando de construir una aplicación de 64 bits, fallará. Usarlo en combinación con PROCESSOR_ARCHITEW6432funcionó para mí (ver esto y aquello )
Thomas

44
Sería bueno si el makeequipo agrega un par de variables mágicas con os y arch, probablemente demasiados problemas.
Alex

66
@JanusTroelsen: no debería importar si OSestá configurado en sistemas que no sean Windows. Haga que las golosinas no estén configuradas como vacías, lo que provocará un salto al unamebloque basado. Solo necesita agregar un cheque de FreeBSD allí.
Trevor Robinson

3
esto también se rompe en osx. /bin/sh: -c: line 0: syntax error near unexpected token , Windows_NT '/ bin / sh: -c: línea 0:ifeq (,Windows_NT)' make: *** [os] Error 2
k107

1
@kristi Parece que ejecutó esto como comandos de shell y no en el contexto de las directivas de makefile.
Phord

119

El comando uname ( http://developer.apple.com/documentation/Darwin/Reference/ManPages/man1/uname.1.html ) sin parámetros debería indicarle el nombre del sistema operativo. Usaría eso, luego haría condicionales basados ​​en el valor de retorno.

Ejemplo

UNAME := $(shell uname)

ifeq ($(UNAME), Linux)
# do something Linux-y
endif
ifeq ($(UNAME), Solaris)
# do something Solaris-y
endif

Solo para ser explícito, esa línea va en su Makefile. Acabo de probar esa construcción en Makefiles en Cygwin y OSX, y funcionó como se esperaba. Algo para probar: escriba uname en su línea de comando. Eso le dirá el valor para ese sistema operativo. OSX probablemente será "Darwin".
dbrown0708 03 de

El proyecto GnuWin32 tiene uname y Gnu disponibles como aplicaciones nativas de Windows, lo que hace que esta técnica sea portátil para MingW en el símbolo del sistema, así como Cygwin en Windows.
RBerteig

Falla en mi máquina Solaris cuando está dentro del archivo MAKE. El comando uname está disponible en ese sistema.
samoz

44
Tenga en cuenta que si coloca esto dentro de un Maketarget no debe sangrarse.
nylund

44
¿No es la sintaxis ": =" específica de GNU Make?
Ankur Sethi

40

Detecta el sistema operativo usando dos trucos simples:

  • Primero la variable de entorno OS
  • Entonces el unamecomando
ifeq ($(OS),Windows_NT)     # is Windows_NT on XP, 2000, 7, Vista, 10...
    detected_OS := Windows
else
    detected_OS := $(shell uname)  # same as "uname -s"
endif

O una forma más segura, si no está en Windows y unameno está disponible:

ifeq ($(OS),Windows_NT) 
    detected_OS := Windows
else
    detected_OS := $(shell sh -c 'uname 2>/dev/null || echo Unknown')
endif

Ken Jackson propone una alternativa interesante si desea distinguir Cygwin / MinGW / MSYS / Windows. Vea su respuesta que se ve así:

ifeq '$(findstring ;,$(PATH))' ';'
    detected_OS := Windows
else
    detected_OS := $(shell uname 2>/dev/null || echo Unknown)
    detected_OS := $(patsubst CYGWIN%,Cygwin,$(detected_OS))
    detected_OS := $(patsubst MSYS%,MSYS,$(detected_OS))
    detected_OS := $(patsubst MINGW%,MSYS,$(detected_OS))
endif

Luego puede seleccionar las cosas relevantes dependiendo de detected_OS:

ifeq ($(detected_OS),Windows)
    CFLAGS += -D WIN32
endif
ifeq ($(detected_OS),Darwin)        # Mac OS X
    CFLAGS += -D OSX
endif
ifeq ($(detected_OS),Linux)
    CFLAGS   +=   -D LINUX
endif
ifeq ($(detected_OS),GNU)           # Debian GNU Hurd
    CFLAGS   +=   -D GNU_HURD
endif
ifeq ($(detected_OS),GNU/kFreeBSD)  # Debian kFreeBSD
    CFLAGS   +=   -D GNU_kFreeBSD
endif
ifeq ($(detected_OS),FreeBSD)
    CFLAGS   +=   -D FreeBSD
endif
ifeq ($(detected_OS),NetBSD)
    CFLAGS   +=   -D NetBSD
endif
ifeq ($(detected_OS),DragonFly)
    CFLAGS   +=   -D DragonFly
endif
ifeq ($(detected_OS),Haiku)
    CFLAGS   +=   -D Haiku
endif

Notas:

  • El comando unamees el mismo que uname -sporque la opción -s( --kernel-name) es la predeterminada. Mira por qué uname -ses mejor queuname -o .

  • El uso de OS(en lugar de uname) simplifica el algoritmo de identificación. Todavía puede usar únicamente uname, pero debe lidiar con if/elsebloques para verificar todas las variaciones de MinGW, Cygwin, etc.

  • La variable de entorno OSsiempre se establece "Windows_NT"en diferentes versiones de Windows (consulte %OS%la variable de entorno en Wikipedia ).

  • Una alternativa OSes la variable de entorno MSVC(verifica la presencia de MS Visual Studio , ver ejemplo usando Visual C ++ ).


A continuación proporciono un ejemplo completo usando makey gccpara construir una biblioteca compartida: *.soo *.dlldependiendo de la plataforma. El ejemplo es lo más simple posible para ser más comprensible.

Para instalar makey gccen Windows, vea Cygwin o MinGW .

Mi ejemplo se basa en cinco archivos.

 ├── lib
    └── Makefile
    └── hello.h
    └── hello.c
 └── app
     └── Makefile
     └── main.c

Recordatorio: Makefile se sangra con tabulación . Precaución al copiar y pegar debajo de archivos de muestra.

Los dos Makefilearchivos

1) lib/Makefile

ifeq ($(OS),Windows_NT)
    uname_S := Windows
else
    uname_S := $(shell uname -s)
endif

ifeq ($(uname_S), Windows)
    target = hello.dll
endif
ifeq ($(uname_S), Linux)
    target = libhello.so
endif
#ifeq ($(uname_S), .....) #See https://stackoverflow.com/a/27776822/938111
#    target = .....
#endif

%.o: %.c
    gcc  -c $<  -fPIC  -o $@
    # -c $<  => $< is first file after ':' => Compile hello.c
    # -fPIC  => Position-Independent Code (required for shared lib)
    # -o $@  => $@ is the target => Output file (-o) is hello.o

$(target): hello.o
    gcc  $^  -shared  -o $@
    # $^      => $^ expand to all prerequisites (after ':') => hello.o
    # -shared => Generate shared library
    # -o $@   => Output file (-o) is $@ (libhello.so or hello.dll)

2) app/Makefile

ifeq ($(OS),Windows_NT)
    uname_S := Windows
else
    uname_S := $(shell uname -s)
endif

ifeq ($(uname_S), Windows)
    target = app.exe
endif
ifeq ($(uname_S), Linux)
    target = app
endif
#ifeq ($(uname_S), .....) #See https://stackoverflow.com/a/27776822/938111
#    target = .....
#endif

%.o: %.c
    gcc  -c $< -I ../lib  -o $@
    # -c $<     => compile (-c) $< (first file after :) = main.c
    # -I ../lib => search headers (*.h) in directory ../lib
    # -o $@     => output file (-o) is $@ (target) = main.o

$(target): main.o
    gcc  $^  -L../lib  -lhello  -o $@
    # $^       => $^ (all files after the :) = main.o (here only one file)
    # -L../lib => look for libraries in directory ../lib
    # -lhello  => use shared library hello (libhello.so or hello.dll)
    # -o $@    => output file (-o) is $@ (target) = "app.exe" or "app"

Para obtener más información, lea la documentación de Variables automáticas según lo indicado por cfi .

El código fuente

- lib/hello.h

#ifndef HELLO_H_
#define HELLO_H_

const char* hello();

#endif

- lib/hello.c

#include "hello.h"

const char* hello()
{
    return "hello";
}

- app/main.c

#include "hello.h" //hello()
#include <stdio.h> //puts()

int main()
{
    const char* str = hello();
    puts(str);
}

La construcción

Arregle el copiar y pegar de Makefile(reemplazar espacios iniciales por una tabulación)

> sed  's/^  */\t/'  -i  */Makefile

El makecomando es el mismo en ambas plataformas. La salida dada es en sistemas operativos tipo Unix:

> make -C lib
make: Entering directory '/tmp/lib'
gcc  -c hello.c  -fPIC  -o hello.o
# -c hello.c  => hello.c is first file after ':' => Compile hello.c
# -fPIC       => Position-Independent Code (required for shared lib)
# -o hello.o  => hello.o is the target => Output file (-o) is hello.o
gcc  hello.o  -shared  -o libhello.so
# hello.o        => hello.o is the first after ':' => Link hello.o
# -shared        => Generate shared library
# -o libhello.so => Output file (-o) is libhello.so (libhello.so or hello.dll)
make: Leaving directory '/tmp/lib'

> make -C app
make: Entering directory '/tmp/app'
gcc  -c main.c -I ../lib  -o main.o
# -c main.c => compile (-c) main.c (first file after :) = main.cpp
# -I ../lib => search headers (*.h) in directory ../lib
# -o main.o => output file (-o) is main.o (target) = main.o
gcc  main.o  -L../lib  -lhello  -o app
# main.o   => main.o (all files after the :) = main.o (here only one file)
# -L../lib => look for libraries in directory ../lib
# -lhello  => use shared library hello (libhello.so or hello.dll)
# -o app   => output file (-o) is app.exe (target) = "app.exe" or "app"
make: Leaving directory '/tmp/app'

La carrera

La aplicación requiere saber dónde está la biblioteca compartida.

En Windows, una solución simple es copiar la biblioteca donde está la aplicación:

> cp -v lib/hello.dll app
`lib/hello.dll' -> `app/hello.dll'

En sistemas operativos tipo Unix, puede usar la LD_LIBRARY_PATHvariable de entorno:

> export LD_LIBRARY_PATH=lib

Ejecute el comando en Windows:

> app/app.exe
hello

Ejecute el comando en sistemas operativos tipo Unix:

> app/app
hello

Agradezco su esfuerzo, pero la pregunta principal fue detectar el sistema operativo. Su ejemplo solo detecta Linux y, de lo contrario, asume directamente Windows.
Shahbaz

Hola @Shahbaz Tienes razón, mi respuesta no ofrece un enfoque diferente al de las otras respuestas. Además, mi script asume que la plataforma es Windows cuando unameno es Linux. Solo doy un ejemplo que puede que no necesite, pero esto puede ayudar a alguien que busca (en la web) una forma de implementar una Makefilepara ambas plataformas ;-) ¿Qué debo cambiar en mi respuesta? Saludos
olibre

¡Trate de encontrar formas de identificar correctamente otros sistemas operativos también! El objetivo es encontrar un método que no sea demasiado complicado, pero más importante es a prueba de balas. Es decir, no se equivocaría sin importar qué.
Shahbaz

1
@olibre Gracias por el ejemplo detallado, muy apreciado y me ayuda a comenzar rápidamente. En el lib/Makefileejemplo, targetse utiliza para .sovs .dll. Un ejemplo paralelo para el app/makefilesería útil para la comparación empty stringvs .exepara el nombre de archivo de la aplicación. Por ejemplo, generalmente no veo app.exeen sistemas operativos tipo Unix. ;-)

1
LSF? LFS? ¿Error de tipografía?
Franklin Yu

19

Hace poco estuve experimentando para responder a esta pregunta que me hacía. Aquí están mis conclusiones:

Dado que en Windows, no puede estar seguro de que el unamecomando esté disponible, puede usarlo gcc -dumpmachine. Esto mostrará el objetivo del compilador.

También puede haber un problema al usarlo unamesi desea hacer una compilación cruzada.

Aquí hay una lista de ejemplos de posibles resultados de gcc -dumpmachine:

  • mingw32
  • i686-pc-cygwin
  • x86_64-redhat-linux

Puede verificar el resultado en el archivo MAKE de esta manera:

SYS := $(shell gcc -dumpmachine)
ifneq (, $(findstring linux, $(SYS)))
 # Do Linux things
else ifneq(, $(findstring mingw, $(SYS)))
 # Do MinGW things
else ifneq(, $(findstring cygwin, $(SYS)))
 # Do Cygwin things
else
 # Do things for others
endif

Funcionó bien para mí, pero no estoy seguro de que sea una forma confiable de obtener el tipo de sistema. Al menos es confiable sobre MinGW y eso es todo lo que necesito, ya que no requiere tener el unamecomando o el paquete MSYS en Windows.

En resumen, unamele da el sistema en el que está compilando y gcc -dumpmachinele da el sistema para el que está compilando.


Este es un buen punto. Sin embargo, no unameviene con de MinGWtodos modos? Sin embargo, la nota adicional con respecto a la compilación cruzada es excelente.
Shahbaz

2
La configuración de @Shahbaz MinGW puede instalar MSYS (que contiene uname) pero es opcional. Todavía es posible encontrar sistemas con solo herramientas MinGW gcc
phsym

1
Eso no funciona en ningún lugar Clang es el compilador predeterminado, como OS X y FreeBSD.
MarcusJ

@SebastianGodelet @MarcusJ Una solución fácil es $(shell $(CC) -dumpmachine). A partir de OS X Sierra, el comando -dumpmachine funciona en Clang.
Vortico

En OS X es 10.12.5 x86_64-apple-darwin16.6.0y que las obras ya sea que se lo llama gcc, cco clang, pero nocl
MarcusJ

17

El archivo make de git contiene numerosos ejemplos de cómo administrar sin autoconf / automake, pero aún funciona en una multitud de plataformas unixy.


13
Saber que Git no usa los Autofools de alguna manera me hace sentir justificado en mi aversión a ellos ...
Dan Molding

11
"Autofools"? ¿Fue un error deliberado? :)
JesperE

66
Era. Pero pensándolo bien, creo que me gustan aún más los "Autostools". : D
Dan Moulding

Por cierto, ¿a quién te refieres con "ellos"? ¿La gente de Git o Autotools? : D
JesperE

8
El inglés es un idioma tan impreciso. Qué tal esto: if (!usesAutotools(git)) aversionTo(autotools) = justified;también aclararé que solo son las herramientas a las que no me gusta. Estoy seguro de que las personas de Autotools son buenas personas.
Dan Molding

11

Actualización: ahora considero que esta respuesta es obsoleta. Publiqué una nueva solución perfecta más abajo.

Si su archivo MAKE puede estar ejecutándose en Windows unameque no sea Cygwin, es posible que no esté disponible. Eso es incómodo, pero esta es una solución potencial. Primero debe verificar Cygwin para descartarlo, porque también tiene WINDOWS en su PATHvariable de entorno.

ifneq (,$(findstring /cygdrive/,$(PATH)))
    UNAME := Cygwin
else
ifneq (,$(findstring WINDOWS,$(PATH)))
    UNAME := Windows
else
    UNAME := $(shell uname -s)
endif
endif

¡Esto es bueno ahora! Sin embargo, ¿puedes decirme una cosa? No uso Cygwin, pero tengo MinGW instalado con su ruta bin en PATH. Si unameemito desde un terminal cmd normal, me da MINGW. Lo que quiero decir es que todavía tengo unamesin usar Cygwin. También tengo git bash, pero no he probado uname en él (ahora estoy en Linux). ¿Me puede decir cómo se pueden incorporar estos dos en su código?
Shahbaz

Si está seguro de que uname está disponible, esa es la mejor solución. Pero en mi entorno, todos usan Windows y pocas personas tienen instalado cygwin o mingw , por lo que no tengo garantía de que algo tan estándar como uname funcione. Actualmente tengo algunas dificultades con el código anterior que ejecuta make.exe en un shell de cmd. Windows es una plataforma muy frustrante para trabajar.
Ken Jackson

Lo que quiero decir es que, antes de probar la existencia de WINDOWS en PATH, te aseguras de no tratar con cygwin, ¿cómo puedes asegurarte de que no estás tratando con MinGW? Por ejemplo, ¿es posible en Makefile probar si se puede ejecutar un comando, y si unameno se pudiera ejecutar, entenderíamos que estamos en Windows?
Shahbaz

Estoy luchando por encontrar una solución limpia para este Mingw / cygwin / shell-or-cmd / Linux también. Al final del día, algo como premake o cmake parece ser la mejor idea.
Isaac Nequittepas

Esta ya no es la mejor solución. La nueva solución que publiqué distingue a Windows nativo al buscar ';' en la variable PATH, sin una llamada de shell.
Ken Jackson

7

Ese es el trabajo que el automake / autoconf de GNU está diseñado para resolver. Es posible que desee investigarlos.

Alternativamente, puede establecer variables de entorno en sus diferentes plataformas y hacer que Makefile sea condicional contra ellas.


11
Recomiendo encarecidamente no utilizar automake / autoconf. Son tediosos de usar, agregan mucha sobrecarga a sus archivos, a su tiempo de compilación. Simplemente agregan complejidad por lo general muy poco efecto (todavía no hay portabilidad entre sistemas).
Johannes Overmann el

1
Acabo de pasar un par de días aprendiendo makea hacer lo que quiero. ¿Ahora quiero entrar también en automake / autoconf? - NO. Lo que se puede hacer en el archivo MAKE, sin duda, debe hacerse en el archivo MAKE, aunque solo sea para que no tenga varios puntos de parada cada vez que quiera modificar la compilación y el enlace.
Ingeniero

¿Cuántas plataformas soportan sus archivos MAKE? automake y autoconf realmente cobran importancia cuando se desea la portabilidad en muchas plataformas.
Douglas Leeder

2
No voy a requerir dependencias inútiles y cambiar todo mi sistema de compilación solo para averiguar para qué sistema operativo se está compilando.
MarcusJ

7

Finalmente encontré la solución perfecta que resuelve este problema para mí.

ifeq '$(findstring ;,$(PATH))' ';'
    UNAME := Windows
else
    UNAME := $(shell uname 2>/dev/null || echo Unknown)
    UNAME := $(patsubst CYGWIN%,Cygwin,$(UNAME))
    UNAME := $(patsubst MSYS%,MSYS,$(UNAME))
    UNAME := $(patsubst MINGW%,MSYS,$(UNAME))
endif

La variable UNAME está configurada en Linux, Cygwin, MSYS, Windows, FreeBSD, NetBSD (o presumiblemente Solaris, Darwin, OpenBSD, AIX, HP-UX) o Desconocido. Luego se puede comparar en el resto del Makefile para separar las variables y comandos sensibles al sistema operativo.

La clave es que Windows usa punto y coma para separar las rutas en la variable PATH, mientras que todos los demás usan dos puntos. (Es posible hacer un directorio de Linux con un ';' en el nombre y agregarlo a PATH, lo que rompería esto, pero ¿quién haría algo así?) Este parece ser el método menos riesgoso para detectar Windows nativo porque no necesita una llamada de shell. Cygwin y MSYS PATH usan dos puntos, por lo que se llama a uname .

Tenga en cuenta que la variable de entorno del sistema operativo se puede utilizar para detectar Windows, pero no para distinguir entre Cygwin y Windows nativo. La prueba de eco de comillas funciona, pero requiere una llamada de shell.

Desafortunadamente, Cygwin agrega información de la versión a la salida de uname , así que agregué las llamadas 'patsubst' para cambiarlo solo a 'Cygwin'. Además, uname para MSYS en realidad tiene tres salidas posibles que comienzan con MSYS o MINGW, pero también uso patsubst para transformar todo a solo 'MSYS'.

Si es importante distinguir entre sistemas nativos de Windows con y sin uname.exe en la ruta, esta línea se puede usar en lugar de la simple asignación:

UNAME := $(shell uname 2>NUL || echo Windows)

Por supuesto, en todos los casos se requiere la marca GNU u otra marca que admita las funciones utilizadas.


6

Me encontré con este problema hoy y lo necesitaba en Solaris, así que aquí hay una forma estándar POSIX de hacer esto (algo muy parecido).

#Detect OS
UNAME = `uname`

# Build based on OS name
DetectOS:
    -@make $(UNAME)


# OS is Linux, use GCC
Linux: program.c
    @SHELL_VARIABLE="-D_LINUX_STUFF_HERE_"
    rm -f program
    gcc $(SHELL_VARIABLE) -o program program.c

# OS is Solaris, use c99
SunOS: program.c
    @SHELL_VARIABLE="-D_SOLARIS_STUFF_HERE_"
    rm -f program
    c99 $(SHELL_VARIABLE) -o program program.c

1
Obteniendo error en OSX: "Makefile: 22: *** falta separador. Detener". En esta línea: "- @ make $ (UNAME_S)".
Czarek Tomczak

Es probable que OSX no sea compatible, así que pruébelos en orden. (1) Asegúrese de estar usando una TAB como primer carácter en la línea (2) Quite el "- @" delante de la marca (2a) Si 2 funcionó, intente con un carácter y luego con el otro (3) Asegúrese de que UNAME_S está definido, intente echo $ (UNAME_S) en lugar de - @ make $ (UNAME_S)
Huckle

6

Aquí hay una solución simple que comprueba si está en un entorno Windows o similar a posix (Linux / Unix / Cygwin / Mac):

ifeq ($(shell echo "check_quotes"),"check_quotes")
   WINDOWS := yes
else
   WINDOWS := no
endif

Aprovecha el hecho de que el eco existe tanto en entornos de posix como en Windows, y que en Windows el shell no filtra las comillas.


1
Bastante inseguro ya que $PATHpodría referirse a otro echo(el mío sí ...)
yyny

@YoYoYonnY ¿Por qué su camino se refiere a otro eco? Parece una situación muy poco probable.
Samuel

1
en realidad no, git lo hace, mingw lo hace, cygwin lo hace ... Y personalmente puse C: \ Windows \ System32 al final de mi camino.
yyny

1
Esta "solución" "funciona" para todos los entornos, pero mi punto es que definitivamente no detecta ventanas de forma segura. Si quiero establecer una -mwindowsbandera o elegir entre un .dllo .so, esto fallará.
yyny

1
@YoYoYonnY Gracias por aclarar. En mi situación, solo me importaba si estaba en un entorno Cygwin o Windows o Linux en lugar de en el sistema operativo en el que estaba, por lo que esto fue útil para mí. Parece que sus necesidades son diferentes a las mías.
Samuel

3

Tenga en cuenta que los Makefiles son extremadamente sensibles al espaciado. Aquí hay un ejemplo de un Makefile que ejecuta un comando adicional en OS X y que funciona en OS X y Linux. En general, sin embargo, autoconf / automake es el camino a seguir para cualquier cosa que no sea trivial.

UNAME: = $ (shell uname -s)
CPP = g ++
CPPFLAGS = -pthread -ansi -Wall -Werror -pedantic -O0 -g3 -I / nexopia / include
LDFLAGS = -pthread -L / nexopia / lib -lboost_system

HEADERS = data_structures.h http_client.h load.h lock.h search.h server.h thread.h utility.h
OBJETOS = http_client.o load.o lock.o search.o server.o thread.o utility.o vor.o

todos: vor

limpiar:
    rm -f $ (OBJETOS) vor

vor: $ (OBJETOS)
    $ (CPP) $ (LDFLAGS) -o vor $ (OBJETOS)
ifeq ($ (UNAME), Darwin)
    # Establecer la ubicación de la biblioteca Boost
    install_name_tool -change libboost_system.dylib /nexopia/lib/libboost_system.dylib vor
terminara si

% .o:% .cpp $ (HEADERS) Makefile
    $ (CPP) $ (CPPFLAGS) -c $

2

Otra forma de hacerlo es mediante el uso de un script "configurar". Si ya está usando uno con su archivo MAKE, puede usar una combinación de uname y sed para que todo funcione. Primero, en tu guión, haz:

UNAME=uname

Luego, para poner esto en su Makefile, comience con Makefile.in que debería tener algo como

UNAME=@@UNAME@@

en eso.

Use el siguiente comando sed en su script de configuración después del UNAME=unamebit.

sed -e "s|@@UNAME@@|$UNAME|" < Makefile.in > Makefile

Ahora su archivo MAKE debería haberse UNAMEdefinido como se desea. ¡Si las declaraciones / elif / else son todo lo que queda!


¿No debería ser el primer equivalente? UNAME = $ (uname)
Ken Jackson

0

Tuve un caso en el que tuve que detectar la diferencia entre dos versiones de Fedora, para ajustar las opciones de línea de comandos para Inkscape:
- en Fedora 31, el Inkscape predeterminado es 1.0beta que usa --export-file
- en Fedora <31, el Inkscape predeterminado es 0.92 que utiliza--export-pdf

Mi Makefile contiene lo siguiente

# set VERSION_ID from /etc/os-release

$(eval $(shell grep VERSION_ID /etc/os-release))

# select the inkscape export syntax

ifeq ($(VERSION_ID),31)
EXPORT = export-file
else
EXPORT = export-pdf
endif

# rule to convert inkscape SVG (drawing) to PDF

%.pdf : %.svg
    inkscape --export-area-drawing $< --$(EXPORT)=$@

Esto funciona porque /etc/os-releasecontiene una línea

VERSION_ID=<value>

entonces el comando de shell en el Makefile devuelve la cadena VERSION_ID=<value>, luego el comando eval actúa sobre esto para establecer la variable Makefile VERSION_ID. Obviamente, esto puede modificarse para otros sistemas operativos dependiendo de cómo se almacenan los metadatos. Tenga en cuenta que en Fedora no hay una variable de entorno predeterminada que proporcione la versión del sistema operativo, de lo contrario, ¡lo habría usado!

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.