İşletim sistemi tespit dosyası


250

Mac OS X, Linux veya Solaris olan birkaç farklı bilgisayarda ve birkaç farklı işletim sisteminde rutin olarak çalışıyorum. Üzerinde çalıştığım proje için kodumu uzak git deposundan alıyorum.

Hangi terminalde olduğumdan bağımsız olarak projelerim üzerinde çalışmayı seviyorum. Şimdiye kadar, bilgisayarları her değiştirdiğimde makefile değiştirerek OS değişikliklerini aşmanın yollarını buldum. Bununla birlikte, bu sıkıcıdır ve bir sürü baş ağrısına neden olur.

Hangi dosyayı kullandığımı tespit edip sözdizimini buna göre değiştirecek şekilde makefile'ımı nasıl değiştirebilirim?

İşte 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

Yanıtlar:


283

Burada zaten çok iyi cevaplar var, ancak her ikisinin de daha eksiksiz bir örneğini paylaşmak istedim:

  • unameWindows'ta var olduğunu varsaymıyor
  • ayrıca işlemciyi de algılar

Burada tanımlanan CCFLAGS mutlaka tavsiye edilmez veya ideal değildir; onlar sadece OS / CPU otomatik algılama eklediğim projenin kullandıkları şeydi.

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
Ne yazık ki, PROCESSOR_ARCHITECTUREenvvar, işlemin 32 bit mi yoksa 64 bit mi olduğuna bağlı olarak sanallaştırılmış gibi görünüyor. Eğer make32 bit ise ve 64 bit bir uygulama oluşturmaya çalışıyorsanız başarısız olur. İle birlikte onu kullanma PROCESSOR_ARCHITEW6432(bkz benim için çalıştı bu ve o )
Thomas

4
Eğer maketakım os ve arch ile birkaç sihirli değişken eklerseniz iyi olurdu , muhtemelen çok fazla sorun.
Alex

6
@JanusTroelsen: OSWindows olmayan sistemlerde ayarlanıp ayarlanmadığı önemli değildir . İkramları boş olanla aynı değere getirin, bu da unametemelli bloğa atlamaya neden olur . Buraya bir FreeBSD kontrolü eklemeniz yeterlidir.
Trevor Robinson

3
bu osx'u da kırıyor. /bin/sh: -c: line 0: syntax error near unexpected token , Windows_NT '/ bin / sh: -c: satır 0:ifeq (,Windows_NT)' make: *** [os] Error 2
k107

1
@kristi Görünüşe göre bunu makefile yönergeleri bağlamında değil, shell komutları olarak çalıştırdınız.
17'de phord

119

Parametresiz uname komutu ( http://developer.apple.com/documentation/Darwin/Reference/ManPages/man1/uname.1.html ) işletim sistemi adını size bildirmelidir. Bunu kullanmak, sonra dönüş değerine dayalı koşullu yapmak.

Misal

UNAME := $(shell uname)

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

Sadece açık olmak gerekirse, bu çizgi Makefile'nize gider. Cygwin ve OSX'teki Makefiles'de bu yapıyı denedim ve beklendiği gibi çalıştı. Denenecek bir şey: Komut satırınıza uname yazın. Bu size bu işletim sisteminin değerini söyleyecektir. OSX muhtemelen "Darwin" olacaktır.
dbrown0708

GnuWin32 projesi hem uname hem de Gnu'nun yerel Windows uygulamaları olarak kullanılmasını sağlayarak, bu tekniği komut isteminde MingW'ye ve Windows'ta Cygwin'e taşınabilir hale getiriyor.
RBerteig

Makefile içinde olduğunda Solaris makinemde başarısız oluyor. Uname komutu bu sistemde kullanılabilir.
samoz

4
Bunu bir Maketarget içine koyarsanız, girintili olmaması gerektiğini unutmayın.
nylund

4
": =" Sözdizimi GNU Make'a özgü değil mi?
Ankur Sethi

40

İşletim sistemini iki basit numara kullanarak tespit edin:

  • İlk olarak çevre değişkeni OS
  • Sonra unamekomut
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

Veya Windows'da unameyoksa ve kullanılamıyorsa daha güvenli bir yol :

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

Cygwin / MinGW / MSYS / Windows'ı ayırt etmek istiyorsanız Ken Jackson ilginç bir alternatif öneriyor. Şuna benzeyen cevabını görün :

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

Ardından aşağıdakilere bağlı olarak ilgili şeyleri seçebilirsiniz 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

Notlar:

  • Komut unameaynıdır, uname -sçünkü option -s( --kernel-name) varsayılan değerdir. Neden uname -sdaha iyi olduğunuuname -o görün .

  • Kullanımı OS(yerine uname) tanıma algoritması kolaylaştırır. Yine de yalnızca kullanabilirsiniz uname, ancak if/elsetüm MinGW, Cygwin vb. Varyasyonlarını kontrol etmek için bloklarla uğraşmanız gerekir.

  • Ortam değişkeni OSher zaman "Windows_NT"farklı Windows sürümlerinde olarak ayarlanır ( %OS%Wikipedia'daki ortam değişkenine bakın ).

  • Alternatifi OSortam değişkenidir MSVC( MS Visual Studio'nun varlığını kontrol eder, Visual C ++ kullanarak örneğe bakın ).


Aşağıda makeve kullanarak gccpaylaşılan bir kütüphane oluşturmak için *.soveya *.dllplatforma bağlı olarak tam bir örnek sunuyorum . Örnek, daha anlaşılır olması için mümkün olduğunca basittir.

Windows'a kurmak makeve yüklemek için gccbkz. Cygwin veya MinGW .

Örneğim beş dosyaya dayanıyor

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

Hatırlatma: tabloMakefile kullanılarak girintilenir . Örnek dosyaların altına kopya yapıştırırken dikkat edin.

İki Makefiledosya

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"

Daha fazla bilgi edinmek için cfi tarafından belirtilen Otomatik Değişkenler belgelerini okuyun .

Kaynak kodu

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

Yapı

Kopyasını yapıştırın Makefile(önde gelen boşlukları bir tablo ile değiştirin).

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

makeKomut her iki platformda da aynıdır. Verilen çıktı Unix benzeri işletim sistemlerinde:

> 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'

Koşmak

Uygulama, paylaşılan kitaplığın nerede olduğunu bilmeyi gerektirir.

Windows'ta basit bir çözüm, uygulamanın bulunduğu kütüphaneyi kopyalamaktır:

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

Unix benzeri işletim sistemlerinde, LD_LIBRARY_PATHortam değişkenini kullanabilirsiniz :

> export LD_LIBRARY_PATH=lib

Komutu Windows'ta çalıştırın:

> app/app.exe
hello

Komutu Unix benzeri işletim sistemlerinde çalıştırın:

> app/app
hello

Çabalarınızı takdir ediyorum, ancak asıl soru işletim sistemini tespit etmekti. Örneğiniz yalnızca Linux'u algılar ve aksi takdirde Windows varsayar.
Shahbaz

Merhaba @Shahbaz. Haklısın, cevabım diğer cevaplardan farklı bir yaklaşım vermiyor. Ayrıca, betiğim unameLinux olmadığında platformun Windows olduğunu varsayar . İhtiyacınız olmayabilir sadece bir örnek veriyorum, ancak bu (web'de) birisinin Makefileher iki platform için de bir uygulama yolu aramasına yardımcı olabilir ;-) Cevabımda ne değiştirmeliyim? Şerefe
olibre

diğer işletim sistemlerini de doğru bir şekilde tanımlamanın yollarını bulmaya çalışın! Amaç çok karmaşık olmayan, ancak daha da önemlisi kurşun geçirmez bir yöntem bulmaktır. Yani, ne olursa olsun hata yapmaz.
Shahbaz

1
@olibre Ayrıntılı örnek için teşekkürler, çok takdir ediyorum ve hızlı bir şekilde başlamama yardımcı oluyor. Olarak lib/Makefile, örneğin, targetkullanılan .sovs .dll. İçin paralel bir örnek app/makefileiçin yararlı olacaktır empty stringvs .exeuygulama dosya için bir karşılaştırma. Örneğin, genellikle app.exeUnix benzeri işletim sistemlerinde göremiyorum . ;-)

1
LSF? LFS? Tipo?
Franklin Yu

19

Son zamanlarda kendime sorduğum bu soruyu cevaplamak için denemeler yapıyordum. İşte sonuçlarım:

Windows'da, unamekomutun kullanılabilir olduğundan emin olamayacağınız için kullanabilirsiniz gcc -dumpmachine. Bu, derleyici hedefini görüntüler.

unameÇapraz derleme yapmak istiyorsanız , kullanırken de bir sorun olabilir .

Aşağıda olası çıktıların örnek bir listesi verilmiştir gcc -dumpmachine:

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

Sonuçları makefile içinde şu şekilde kontrol edebilirsiniz:

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

Benim için iyi çalıştı, ancak sistem türünü almanın güvenilir bir yolu olduğundan emin değilim. En azından MinGW hakkında güvenilir ve Windows'da unamekomut veya MSYS paketine sahip olması gerekmediği için ihtiyacım olan tek şey bu .

Özetle, unamesize sistemini verir üzerinde derleme olduğunuz ve gcc -dumpmachinesize sistemini verir için size derleme hangi.


Bu iyi bir nokta. Ancak, yine de unamegelmiyor MinGWmu? Bununla birlikte, çapraz derleme ile ilgili ekstra not harika.
Shahbaz

2
@Shahbaz MinGW kurulumu MSYS'yi (uname içeren) yükleyebilir, ancak isteğe bağlıdır. Sadece MinGW gcc araçları olan sistemleri bulmak hala mümkündür
phsym

1
Bu hiçbir yerde çalışmaz Clang, OS X ve FreeBSD gibi varsayılan derleyicidir.
MarcusJ

@SebastianGodelet @MarcusJ Kolay bir düzeltme $(shell $(CC) -dumpmachine). OS X Sierra'dan itibaren -dumpmachine komutu Clang üzerinde çalışıyor.
Vortico

OS X 10.12.5 On öyle x86_64-apple-darwin16.6.0ve sizin Hava eserleri diyoruz o gcc, ccya clangdeğilcl
MarcusJ

17

Git makefile autoconf / automake, unixy çok sayıda platform üzerinde henüz hala iş olmadan nasıl yönetileceği sayısız örnekler içerir.


13
Git'in Autofools'u bir şekilde kullanmadığını bilmek, onlara olan ilgimde haklı hissetmemi sağlıyor ...
Dan Moulding

11
"Autofools"? Bu kasıtlı bir yazım hatası mıydı? :)
JesperE

6
Öyleydi. Ama ikinci düşüncede, bence "Autostools" u daha iyi seviyorum. : D
Dan Moulding

Btw, "onlar" ile kimi kast ettin? Git veya Autotools çalışanları mı? : D
JesperE

8
İngilizce öyle belirsiz bir dildir. Buna ne dersiniz: if (!usesAutotools(git)) aversionTo(autotools) = justified;Bunun sadece benim aştığım araçlar olduğunu da anlatacağım. Ben Autotools insanlar hoş insanlar eminim.
Dan Moulding

11

Güncelleme: Şimdi bu cevabın eski olduğunu düşünüyorum. Daha sonra yeni bir mükemmel çözüm yayınladım.

Dosyanız Cygwin olmayan Windows işletim sistemlerinde çalışıyorsa, unamekullanılamayabilir. Bu garip, ama bu potansiyel bir çözüm. PATHOrtam değişkeninde de WINDOWS bulunduğundan, Cygwin'i dışlamak için önce kontrol etmeniz gerekir .

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

Şimdilik bu iyi! Yine de bana bir şey söyleyebilir misin? Cygwin kullanmıyorum, ancak PATH'de bin yolu ile yüklü MinGW var. Ben sorunu varsa unamenormal cmd terminalden bana MinGW veriyor. Demek istediğim, hala unameCygwin kullanmadan var . Ben de git bash var, ama üzerinde uname denemedim (şu anda Linux'tayım). Bana bu ikisinin kodunuza nasıl dahil edilebileceğini söyleyebilir misiniz?
Şahbaz

Uname'in kullanılabilir olduğundan eminseniz, bu en iyi çözümdür. Ama çevremde herkes Windows kullanıyor ve az sayıda kişi cygwin veya mingw yüklü, bu yüzden uname gibi standart bir şeyin bile çalışacağını garanti edemiyorum. Şu anda bir cmd kabuğunda make.exe çalışan yukarıdaki kod ile bazı zorluk yaşıyorum. Windows ile çalışmak çok sinir bozucu bir platform.
Ken Jackson

Demek istediğim, PATH'de WINDOWS'un varlığını test etmeden önce, cygwin ile ilgilenmediğinizden emin olun, MinGW ile ilgilenmediğinizden nasıl emin olabilirsiniz? Örneğin, Makefile'de bir komutun çalıştırılıp çalıştırılamayacağını test etmek mümkün müdür ve unameçalıştırılamazsa Windows'da olduğumuzu anlayabiliriz?
Shahbaz

Bu Mingw / cygwin / shell-or-cmd / Linux'a da temiz bir çözüm bulmakta zorlanıyorum. Günün sonunda, premake veya cmake gibi bir şey en iyi fikir gibi görünüyor.
Isaac Nequittepas

Bu artık en iyi çözüm değil. Gönderdiğim yeni çözüm yerel Windows'u ';' kabuk çağrısı olmadan PATH değişkeninde.
Ken Jackson

7

GNU'nun automake / autoconf'unun çözmek için tasarladığı iş budur . Onları araştırmak isteyebilirsiniz.

Alternatif olarak, ortam değişkenlerini farklı platformlarınızda ayarlayabilir ve Makefile'i bunlara karşı koşullu hale getirebilirsiniz.


11
Automake / autoconf kullanılmamasını şiddetle tavsiye ederim. Kullanmak sıkıcıdır, dosyalarınıza, ek yükünüze çok fazla yük eklerler. Genellikle çok az etki için karmaşıklık eklerler (sistemler arasında hala taşınabilirlik yoktur).
Johannes Overmann

1
İstediğimi makeyapmayı öğrenmek için birkaç gün geçirdim . Şimdi automake / autoconf'a da girmek ister miyim? - HAYIR. Ne olabilir ben birkaç Dur kapatma noktaları Ben derleme ve bağlantıyı değiştirme istediğiniz her zaman sahip olmadığını sadece eğer öyleyse makefile'ında yapılması, kesinlikle makefile'ında yapılmalıdır.
Mühendis

Makyaj dosyalarınız kaç platformu destekliyor? automake ve autoconf gerçekten birçok platforma taşınabilirlik istediğinizde kendi haline gelir.
Douglas Leeder

2
İşe yaramaz bağımlılıklara ihtiyacım olmayacak ve tüm derleme sistemimi sadece hangi işletim sistemi için derlendiğini öğrenmek için değiştirmeyeceğim.
MarcusJ

7

Sonunda bu sorunu benim için çözen mükemmel çözümü buldum.

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

UNAME değişkeni Linux, Cygwin, MSYS, Windows, FreeBSD, NetBSD (veya muhtemelen Solaris, Darwin, OpenBSD, AIX, HP-UX) veya Bilinmeyen olarak ayarlanmıştır. Daha sonra Makefile'nin geri kalanı boyunca işletim sistemine duyarlı değişkenleri ve komutları ayırmak için karşılaştırılabilir.

Anahtar, Windows'un PATH değişkenindeki yolları ayırmak için noktalı virgül kullanması, diğerlerinin ise noktalı virgül kullanmasıdır. (Adında ';' ile bir Linux dizini oluşturmak ve PATH'ye eklemek mümkündür, bu da bunu kıracaktır, ancak böyle bir şey kim yapabilir?) Bu, yerel Windows'u algılamak için en az riskli yöntem gibi görünüyor çünkü kabuk çağrısı gerektirmez. Cygwin ve MSYS PATH iki nokta üst üste kullanır, bu nedenle onlar için uname çağrılır.

İşletim sistemi ortam değişkeninin Windows'u algılamak için kullanılabileceğini, ancak Cygwin ve yerel Windows arasında ayrım yapmak için kullanılabileceğini unutmayın. Tırnakların yankılanmasını test etmek işe yarar, ancak bir kabuk çağrısı gerektirir.

Ne yazık ki, Cygwin, uname çıktısına bazı sürüm bilgileri eklediğinden, sadece 'Cygwin' olarak değiştirmek için 'patsubst' çağrılarını ekledim. Ayrıca, MSYS için uname aslında MSYS veya MINGW ile başlayan üç olası çıkışa sahiptir, ancak ben de patsubst'u sadece 'MSYS' ye dönüştürmek için kullanıyorum.

Yolda bazı uname.exe içeren ve içermeyen yerel Windows sistemleri arasında ayrım yapmak önemliyse, bu atama basit atama yerine kullanılabilir:

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

Elbette her durumda GNU markası veya kullanılan işlevleri destekleyen başka bir marka gereklidir .


6

Bugün bu problemle karşılaştım ve Solaris'e ihtiyacım vardı, bu yüzden bunu yapmak için POSIX standart bir yol (çok yakın bir şey).

#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
OSX'te hata oluşuyor: "Makefile: 22: *** ayırıcı eksik. Dur." Bu satırda: "- @ $ (UNAME_S) yap".
Czarek Tomczak

OSX muhtemelen uyumlu değil, bu yüzden bunları sırayla deneyin. (1) Satırdaki ilk karakter olarak bir SEKME kullandığınızdan emin olun (2) Markanın önündeki "- @" işaretini kaldırın (2a) 2 işe yaradıysa, önce bir karakter, sonra diğerini (3) deneyin UNAME_S tanımlandı, - @ make $ (UNAME_S) yerine echo $ (UNAME_S) öğesini deneyin
Huckle

6

Windows veya posix benzeri (Linux / Unix / Cygwin / Mac) bir ortamda olup olmadığınızı kontrol eden basit bir çözüm:

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

Eko'nun hem posix benzeri hem de Windows ortamlarında var olmasından ve Windows'ta kabuğun tırnak işaretlerini filtrelememesinden yararlanır.


1
Oldukça güvensiz beri $PATHbaşka bir atıfta bulunabilir echo(benim ...)
yyny

@YoYoYonnY Yolunuz neden başka bir yankıya işaret ediyor? Çok beklenmedik bir durum gibi görünüyor.
Samuel

1
gerçekten değil, git yapar, mingw yapar, cygwin yapar ... Ve ben şahsen C: \ Windows \ System32 yolumu altına koydu.
yyny

1
Bu "çözüm" "tüm ortamlar için çalışır" ama benim açımdan bunun pencereleri kesin olarak algılamaması. Bir -mwindowsbayrak ayarlamak veya bir .dllveya arasında seçim yapmak istersem .so, bu başarısız olur.
yyny

1
@YoYoYonnY Açıkladığınız için teşekkürler. Benim durumumda sadece içinde bulunduğum işletim sistemi yerine bir Cygwin veya Windows veya Linux ortamında olsaydım umursadım, bu yüzden benim için yararlı oldu. İhtiyaçlarınız benimkinden farklı.
Samuel

3

Makefiles'in boşluklara karşı son derece hassas olduğunu unutmayın. İşte OS X'de ekstra bir komut çalıştıran ve OS X ve Linux'ta çalışan bir Makefile örneği. Genel olarak, autoconf / automake önemsiz olmayan bir şey için gitmek için bir yoldur.

UNAME: = $ (kabuk uname -s)
CPP = g ++
CPPFLAGS = -pthread -ansi -Duvar -Beyaz -pedantik -O0 -g3 -I / nexopia / dahil
LDFLAGS = -pthread -L / nexopia / lib -lboost_system

BAŞLIKLAR = data_structures.h http_client.h load.h lock.h search.h server.h thread.h yardımcı program.h
NESNELER = http_client.o load.o lock.o search.o server.o thread.o yardımcı programı.o vor.o

hepsi: vor

temiz:
    rm -f $ (NESNELER) vor

vor: $ (NESNELER)
    $ (CPP) $ (LDFLAGS) -veya $ (NESNELER)
ifeq ($ (UNAME), Darwin)
    # Boost kitaplığı konumunu ayarlama
    install_name_tool -change libboost_system.dylib /nexopia/lib/libboost_system.dylib vor
endif

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

2

Bunu yapmanın başka bir yolu da "configure" betiği kullanmaktır. Zaten makefile ile bir tane kullanıyorsanız, işleri halletmek için uname ve sed kombinasyonunu kullanabilirsiniz. İlk olarak, senaryonuzda şunları yapın:

UNAME=uname

Sonra, bunu Makefile'nize koymak için, Makefile.in ile başlayın.

UNAME=@@UNAME@@

içinde.

UNAME=unameBiraz sonra configure betiğinizde aşağıdaki sed komutunu kullanın .

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

Şimdi dosya dosyanız UNAMEistediğiniz gibi tanımlanmış olmalıdır . / Elif / else ifadeleri kalan her şeyse!


İlk denklem bu olmamalı mı? UNAME = $ (uname)
Ken Jackson

0


Inkscape için komut satırı seçeneklerini ayarlamak için Fedora'nın iki sürümü arasındaki farkı tespit etmek zorunda kaldığım bir durumum vardı : - Fedora 31'de varsayılan inkscape kullanan 1.0beta --export-file
- Fedora <31'de varsayılan inkscape 0.92 kullanan--export-pdf

Makefile'm aşağıdakileri içeriyor

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

Bu /etc/os-release, bir satır içerdiği için çalışır

VERSION_ID=<value>

Böylece Makefile içindeki shell komutu dizeyi döndürür VERSION_ID=<value>, daha sonra eval komutu Makefile değişkenini ayarlamak için buna göre hareket eder VERSION_ID. Bu, meta verilerin nasıl depolandığına bağlı olarak diğer işletim sistemleri için açık bir şekilde değiştirilebilir. Fedora'da işletim sistemi sürümünü veren varsayılan bir ortam değişkeni olmadığını unutmayın, aksi takdirde bunu kullanırdım!

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.