Sistema operacional detectando makefile

249

Rotineiramente, trabalho em vários computadores e sistemas operacionais diferentes, que são Mac OS X, Linux ou Solaris. Para o projeto em que estou trabalhando, retiro meu código de um repositório git remoto.

Eu gosto de poder trabalhar em meus projetos, independentemente do terminal em que estou. Até agora, encontrei maneiras de contornar as alterações no sistema operacional alterando o makefile toda vez que troco de computador. No entanto, isso é tedioso e causa um monte de dores de cabeça.

Como posso modificar meu makefile para detectar qual SO estou usando e modificar a sintaxe de acordo?

Aqui está o makefile:

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
samoz
fonte

Respostas:

282

Já existem muitas boas respostas aqui, mas eu queria compartilhar um exemplo mais completo de que ambos:

  • não assume que unameexiste no Windows
  • também detecta o processador

Os CCFLAGS definidos aqui não são necessariamente recomendados ou ideais; eles são exatamente o que o projeto ao qual eu estava adicionando a detecção automática de SO / CPU estava usando.

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
Trevor Robinson
fonte
8
Infelizmente, o PROCESSOR_ARCHITECTUREenvvar parece estar virtualizado, dependendo se o processo é de 32 ou 64 bits. Portanto, se você maketem 32 bits e está tentando criar um aplicativo de 64 bits, ele falhará. Usá-lo em combinação com PROCESSOR_ARCHITEW6432funcionou para mim (ver esta , e que )
Thomas
4
Seria bom se a makeequipe adicionasse algumas variáveis ​​mágicas com os e arch, provavelmente com muitos problemas.
Alex
6
@ JanusTroelsen: não importa se OSestá definido em sistemas não Windows. Faça guloseimas desabilitadas da mesma forma que vazias, o que causará um salto no unamebloco baseado em. Você só precisa adicionar uma verificação do FreeBSD lá.
Trevor Robinson
3
isso também quebra no osx. /bin/sh: -c: line 0: syntax error near unexpected token , Windows_NT '/ bin / sh: -c: linha 0:ifeq (,Windows_NT)' make: *** [os] Error 2
k107
1
@ kristi Parece que você executou isso como comandos shell e não no contexto de diretivas makefile.
phord
119

O comando uname ( http://developer.apple.com/documentation/Darwin/Reference/ManPages/man1/uname.1.html ) sem parâmetros deve informar o nome do sistema operacional. Eu usaria isso, então faria condicionais com base no valor de retorno.

Exemplo

UNAME := $(shell uname)

ifeq ($(UNAME), Linux)
# do something Linux-y
endif
ifeq ($(UNAME), Solaris)
# do something Solaris-y
endif
dbrown0708
fonte
Apenas para ser explícito, essa linha entra no seu Makefile. Eu apenas tentei essa construção em Makefiles no Cygwin e OSX, e funcionou como esperado. Algo a tentar: Digite uname na sua linha de comando. Isso mostrará o valor desse sistema operacional. OSX provavelmente será "Darwin".
Dbrown0708 03/04/09
O projeto GnuWin32 tem o uname e o Gnu disponíveis como aplicativos nativos do Windows, tornando esta técnica portátil para o MingW em um prompt de comando e para o Cygwin no Windows.
RBerteig
Falha na minha máquina Solaris quando está dentro do makefile. O comando uname está disponível nesse sistema.
samoz 4/04/09
4
Observe que, se você colocar isso dentro de um Maketarget, ele não deve ser recuado.
Nilund
4
A sintaxe ": =" não é específica para o GNU Make?
Ankur Sethi
40

Detecte o sistema operacional usando dois truques simples:

  • Primeiro a variável de ambiente OS
  • Então o 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

Ou uma maneira mais segura, se não estiver no Windows e unameindisponível:

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

Ken Jackson propõe uma alternativa interessante se você deseja distinguir Cygwin / MinGW / MSYS / Windows. Veja a resposta dele assim:

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

Depois, você pode selecionar o material relevante, dependendo 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:

  • O comando unameé o mesmo que uname -sopção -s( --kernel-name) é o padrão. Veja por que uname -sé melhor queuname -o .

  • O uso de OS(em vez de uname) simplifica o algoritmo de identificação. Você ainda pode usar apenas uname, mas precisa lidar com os if/elseblocos para verificar todas as variações do MinGW, Cygwin etc.

  • A variável de ambiente OSé sempre definida como "Windows_NT"em diferentes versões do Windows (consulte %OS%variável de ambiente na Wikipedia ).

  • Uma alternativa de OSé a variável de ambiente MSVC(verifica a presença do MS Visual Studio , veja o exemplo usando o Visual C ++ ).


Abaixo, forneço um exemplo completo usando makee gccpara criar uma biblioteca compartilhada: *.soou *.dlldependendo da plataforma. O exemplo é o mais simples possível para ser mais compreensível.

Para instalar makee gccno Windows, consulte Cygwin ou MinGW .

Meu exemplo é baseado em cinco arquivos

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

Lembrete: Makefile é recuado usando tabulação . Cuidado ao copiar e colar abaixo dos arquivos de amostra.

Os dois Makefilearquivos

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 saber mais, leia a documentação de Variáveis ​​automáticas , conforme indicado pelo cfi .

O código fonte

- 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);
}

A compilação

Corrija a copiar-colar de Makefile(substitua os espaços à esquerda por uma tabulação).

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

O makecomando é o mesmo nas duas plataformas. A saída fornecida é em sistemas operacionais semelhantes ao 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'

A corrida

O aplicativo requer saber onde está a biblioteca compartilhada.

No Windows, uma solução simples é copiar a biblioteca onde o aplicativo está:

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

Em sistemas operacionais semelhantes ao Unix, você pode usar a LD_LIBRARY_PATHvariável de ambiente:

> export LD_LIBRARY_PATH=lib

Execute o comando no Windows:

> app/app.exe
hello

Execute o comando em sistemas operacionais semelhantes ao Unix:

> app/app
hello
olibre
fonte
Agradeço seu esforço, mas a questão principal era detectar o sistema operacional. Seu exemplo detecta apenas o Linux e, de outra forma, assume o Windows.
Shahbaz 09/02
Olá @Shahbaz. Você está certo, minha resposta não oferece uma abordagem diferente das outras respostas. Além disso, meu script assume que a plataforma é Windows quando unamenão é Linux. Dou apenas um exemplo que você pode não precisar, mas isso pode ajudar alguém a pesquisar (na Web) uma maneira de implementar um Makefilepara ambas as plataformas ;-) O que devo mudar na minha resposta? Cheers
olibre
tente encontrar maneiras de identificar corretamente outros sistemas operacionais também! O objetivo é encontrar um método que não seja muito complicado, mas o mais importante é à prova de balas. Ou seja, não cometeria nenhum erro, não importa o quê.
Shahbaz
1
@olibre Obrigado pelo exemplo detalhado, muito apreciado e ajuda a começar rapidamente. No lib/Makefileexemplo, targeté usado para .sovs .dll. Um exemplo paralelo para o app/makefileseria útil para a comparação empty stringvs .exepara o nome do arquivo do aplicativo. Por exemplo, eu não costumo ver app.exeem sistemas operacionais semelhantes ao Unix. ;-)
1
LSF? LFS? Erro de digitação?
Franklin Yu
19

Eu estava experimentando recentemente para responder a essa pergunta que estava me perguntando. Aqui estão as minhas conclusões:

Como no Windows, você não pode ter certeza de que o unamecomando está disponível, você pode usá-lo gcc -dumpmachine. Isso exibirá o destino do compilador.

Também pode haver um problema ao usar unamese você deseja fazer alguma compilação cruzada.

Aqui está uma lista de exemplo de saída possível de gcc -dumpmachine:

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

Você pode verificar o resultado no makefile assim:

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

Funcionou bem para mim, mas não tenho certeza de que seja uma maneira confiável de obter o tipo de sistema. Pelo menos, é confiável sobre o MinGW e é tudo o que preciso, pois não requer o unamecomando ou o pacote MSYS no Windows.

Para resumir, unamefornece o sistema no qual você está compilando e gcc -dumpmachineo sistema para o qual você está compilando.

phsym
fonte
Este é um bom argumento. No entanto, não unamevem de MinGWqualquer maneira? No entanto, a nota extra sobre compilação cruzada é ótima.
Shahbaz
2
A instalação do @Shahbaz MinGW pode instalar o MSYS (que contém uname), mas é opcional. Ainda é possível encontrar sistemas com apenas ferramentas gcc MinGW
phsym
1
Isso não funciona em nenhum lugar. Clang é o compilador padrão, como OS X e FreeBSD.
MarcusJ
@SebastianGodelet @MarcusJ Uma solução fácil é $(shell $(CC) -dumpmachine). No OS X Sierra, o comando -dumpmachine funciona no Clang.
Vortico 15/06
No OS X 10.12.5 é x86_64-apple-darwin16.6.0e que obras o tempo que você chamá-lo gcc, ccou clang, mas nãocl
MarcusJ
17

O makefile do git contém vários exemplos de como gerenciar sem o autoconf / automake, mas ainda funciona em várias plataformas unixy.

JesperE
fonte
13
Sabendo que o Git não usar os Autofools de alguma forma me faz sentir justificado em minha aversão a eles ...
Dan Moulding
11
"Autofools"? Isso foi um erro de digitação deliberado? :)
JesperE
6
Isso foi. Mas, pensando bem, acho que gosto mais de "Autostools". : D
Dan Moulding
Btw, quem você quis dizer com "eles"? O pessoal do Git ou do Autotools? : D
JesperE
8
O inglês é uma língua imprecisa. Que tal isso: if (!usesAutotools(git)) aversionTo(autotools) = justified;vou esclarecer também que são apenas as ferramentas às quais sou avesso. Tenho certeza de que o pessoal da Autotools é uma pessoa legal.
Dan Moulding
11

Atualização: Agora considero esta resposta obsoleta. Postei uma nova solução perfeita mais abaixo.

Se o seu makefile pode estar em execução no Windows não Cygwin, unamepode não estar disponível. Isso é estranho, mas essa é uma solução potencial. Você deve verificar primeiro o Cygwin para descartá-lo, porque ele também possui o WINDOWS em sua PATHvariável de ambiente.

ifneq (,$(findstring /cygdrive/,$(PATH)))
    UNAME := Cygwin
else
ifneq (,$(findstring WINDOWS,$(PATH)))
    UNAME := Windows
else
    UNAME := $(shell uname -s)
endif
endif
Ken Jackson
fonte
Isso é bom agora! Você pode me dizer uma coisa? Não uso o Cygwin, mas tenho o MinGW instalado com o caminho bin no PATH. Se eu emitir a unamepartir de um terminal cmd normal, isso me dará MINGW. O que quero dizer é que ainda tenho unamesem usar o Cygwin. Eu também tenho o git bash, mas ainda não tentei uname (agora estou no Linux). Você pode me dizer como esses dois podem ser incorporados ao seu código?
Shahbaz
Se você tem certeza de que a uname está disponível, essa é a melhor solução. Mas no meu ambiente, todo mundo está usando o Windows e poucas pessoas têm o cygwin ou o mingw instalado, então não tenho garantia de que algo tão padrão quanto o uname funcione. No momento, estou tendo alguma dificuldade com o código acima executando o make.exe em um shell do cmd. O Windows é uma plataforma muito frustrante para se trabalhar.
Ken Jackson
O que quero dizer é que, antes de testar a existência do WINDOWS no PATH, você garante que não está lidando com o cygwin, como pode ter certeza de que não está lidando com o MinGW? Por exemplo, é possível no Makefile testar se um comando pode ser executado e, se unamenão for possível, entenderíamos que estamos no Windows?
Shahbaz
Estou lutando para encontrar uma solução limpa para este Mingw / cygwin / shell-ou-cmd / Linux também. No final do dia, algo como premake ou cmake parece ser a melhor ideia.
Isaac Nequittepas
Esta não é mais a melhor solução. A nova solução que publiquei distingue o Windows nativo procurando por ';' na variável PATH, sem uma chamada de shell.
27618 Ken Jackson
7

Esse é o trabalho que o automake / autoconf do GNU foi projetado para resolver. Você pode querer investigá-los.

Como alternativa, você pode definir variáveis ​​de ambiente em suas diferentes plataformas e tornar o Makefile condicional em relação a elas.

Douglas Leeder
fonte
11
Eu recomendo fortemente contra o uso do automake / autoconf. Eles são entediantes de usar, adicionam muita sobrecarga aos seus arquivos, ao seu tempo de compilação. Eles simplesmente adicionam complexidade para geralmente muito pouco efeito (ainda sem portabilidade entre sistemas).
Johannes Overmann 4/11
1
Passei alguns dias aprendendo makea fazer o que quero. Agora, também quero entrar no automake / autoconf? - NÃO. O que pode ser feito no makefile, certamente deve ser feito no makefile, mesmo que apenas para que eu não tenha vários pontos de parada toda vez que eu desejar alterar a compilação e o link.
Engenheiro
Quantas plataformas seus makefiles suportam? automake e autoconf realmente se destacam quando você quer portabilidade para muitas plataformas.
Douglas Leeder
2
Não vou precisar de dependências inúteis e mudar todo o meu sistema de compilação apenas para descobrir para qual sistema operacional ele está sendo compilado.
MarcusJ
7

Finalmente encontrei a solução perfeita que resolve esse problema para mim.

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

A variável UNAME está configurada para Linux, Cygwin, MSYS, Windows, FreeBSD, NetBSD (ou presumivelmente Solaris, Darwin, OpenBSD, AIX, HP-UX) ou Desconhecido. Em seguida, ele pode ser comparado em todo o restante do Makefile para separar quaisquer variáveis ​​e comandos sensíveis ao SO.

A chave é que o Windows usa ponto e vírgula para separar os caminhos na variável PATH, enquanto todos os outros usam dois pontos. (É possível criar um diretório Linux com um ';' no nome e adicioná-lo ao PATH, o que quebraria isso, mas quem faria isso?) Esse parece ser o método menos arriscado para detectar o Windows nativo porque ele não precisa de uma chamada de shell. Os Cygwin e Msys uso PATH dois pontos assim uname é chamado por eles.

Observe que a variável de ambiente do sistema operacional pode ser usada para detectar o Windows, mas não para distinguir entre o Cygwin e o Windows nativo. Testar o eco de aspas funciona, mas requer uma chamada de shell.

Infelizmente, Cygwin adiciona algumas informações de versão à saída de uname , então adicionei as chamadas 'patsubst' para alterá-las para apenas 'Cygwin'. Além disso, uname para MSYS na verdade tem três saídas possíveis começando com MSYS ou MINGW, mas eu também uso o patsubst para transformar tudo em apenas 'MSYS'.

Se é importante distinguir entre sistemas Windows nativos com e sem o uname.exe no caminho, essa linha pode ser usada em vez da atribuição simples:

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

É claro que em todos os casos é necessário o GNU make , ou outro make que suporte as funções usadas.

Ken Jackson
fonte
6

Encontrei esse problema hoje e precisava dele no Solaris, então aqui está uma maneira padrão do POSIX de fazer (algo muito próximo disso) isso.

#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
Quadril
fonte
1
Obtendo erro no OSX: "Makefile: 22: *** separador ausente. Pare.". Nesta linha: "- @ make $ (UNAME_S)".
Czarek Tomczak
Provavelmente o OSX não é compatível, portanto tente-os em ordem. (1) Verifique se você está usando um TAB como o primeiro caractere na linha (2) Remova o "- @" na frente do make (2a) Se 2 funcionou, tente um caractere e depois o outro (3) Verifique se UNAME_S é definido, tente echo $ (UNAME_S) em vez de - @ fazer $ (UNAME_S)
Huckle
6

Aqui está uma solução simples que verifica se você está em um ambiente Windows ou posix (Linux / Unix / Cygwin / Mac):

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

Ele aproveita o fato de que o eco existe nos ambientes do tipo posix e do Windows, e que no Windows o shell não filtra as aspas.

Samuel
fonte
1
Muito inseguro desde $PATHpode se referir a outro echo(Minas faz ...)
yyny
@YoYoYonnY Por que seu caminho se refere a outro eco? Parece uma situação muito improvável.
Samuel
1
na verdade não, git faz isso, mingw faz, cygwin faz ... E eu pessoalmente coloquei C: \ Windows \ System32 no final do meu caminho.
yyny
1
Essa "solução" "funciona" para todos os ambientes, mas meu argumento é que isso definitivamente não detecta janelas com segurança. Se eu quiser definir um -mwindowssinalizador ou escolher entre a .dllou .so, isso falhará.
yyny
1
@YoYoYonnY Obrigado por esclarecer. Na minha situação, eu me importava apenas se estivesse em um ambiente Cygwin ou Windows ou Linux, e não no SO em que estava, então isso foi útil para mim. Parece que suas necessidades são diferentes das minhas.
Samuel
3

Observe que os Makefiles são extremamente sensíveis ao espaçamento. Aqui está um exemplo de um Makefile que executa um comando extra no OS X e que funciona no OS X e Linux. No geral, porém, autoconf / automake é o caminho a percorrer para qualquer coisa que não seja 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
OBJECTS = http_client.o carga.o bloqueio.oa pesquisa.o servidor.o thread.o utilidade.o vor.o

tudo: vor

limpar \ limpo:
    rm -f $ (OBJETOS) por

vor: $ (OBJETOS)
    $ (CPP) $ (LDFLAGS) -o ou para $ (OBJETOS)
ifeq ($ (UNAME), Darwin)
    # Defina o local da biblioteca do Boost
    install_name_tool -change libboost_system.dylib /nexopia/lib/libboost_system.dylib vor
fim se

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

Outra maneira de fazer isso é usando um script "configure". Se você já está usando um com seu makefile, pode usar uma combinação de uname e sed para fazer com que as coisas funcionem. Primeiro, no seu script, faça:

UNAME=uname

Então, para colocar isso no seu Makefile, comece com Makefile.in, que deve ter algo como

UNAME=@@UNAME@@

iniciar.

Use o seguinte comando sed no seu script de configuração após o UNAME=unamebit.

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

Agora seu makefile deveria ter UNAMEdefinido como desejado. Se as instruções / elif / else são tudo o que resta!

Sean
fonte
O primeiro não deve ser o mesmo? UNAME = $ (uname)
Ken Jackson
0

Eu tive um caso em que tive que detectar a diferença entre duas versões do Fedora, para ajustar as opções de linha de comando do inkscape:
- no Fedora 31, o inkscape padrão é 1.0beta que usa --export-file
- no Fedora <31, o inkscape padrão é 0,92 que usa--export-pdf

Meu Makefile contém o seguinte

# 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)=$@

Isso funciona porque /etc/os-releasecontém uma linha

VERSION_ID=<value>

para que o comando shell no Makefile retorne a string VERSION_ID=<value>, o comando eval atua sobre isso para definir a variável Makefile VERSION_ID. Obviamente, isso pode ser ajustado para outros sistemas operacionais, dependendo de como os metadados são armazenados. Note que no Fedora não existe uma variável de ambiente padrão que dê a versão do sistema operacional, caso contrário eu teria usado isso!

Patrick B Warren
fonte