Hệ điều hành phát hiện tệp thực hiện


249

Tôi thường xuyên làm việc trên một số máy tính khác nhau và một số hệ điều hành khác nhau, đó là Mac OS X, Linux hoặc Solaris. Đối với dự án tôi đang thực hiện, tôi lấy mã của mình từ kho lưu trữ git từ xa.

Tôi thích có thể làm việc trên các dự án của mình bất kể tôi đang ở nhà ga nào. Cho đến nay, tôi đã tìm ra cách khắc phục các thay đổi của HĐH bằng cách thay đổi tệp thực hiện mỗi khi tôi chuyển đổi máy tính. Tuy nhiên, điều này là tẻ nhạt và gây ra một loạt các cơn đau đầu.

Làm cách nào tôi có thể sửa đổi tệp thực hiện của mình để nó phát hiện hệ điều hành nào tôi đang sử dụng và sửa đổi cú pháp cho phù hợp?

Đây là tệp thực hiện:

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

Câu trả lời:


282

Có nhiều câu trả lời hay ở đây, nhưng tôi muốn chia sẻ một ví dụ đầy đủ hơn rằng cả hai:

  • không giả sử unametồn tại trên Windows
  • cũng phát hiện bộ xử lý

CCFLAGS được xác định ở đây không nhất thiết phải được đề xuất hoặc lý tưởng; chúng chỉ là những gì mà dự án mà tôi đã thêm tính năng tự động phát hiện OS / CPU đã được sử dụng.

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
Đáng buồn là PROCESSOR_ARCHITECTUREenvvar dường như được ảo hóa tùy thuộc vào quá trình là 32 bit hay 64 bit. Vì vậy, nếu bạn makelà 32 bit và bạn đang cố gắng xây dựng một ứng dụng 64 bit, nó sẽ thất bại. Sử dụng kết hợp với PROCESSOR_ARCHITEW6432làm việc cho tôi (xem cái nàycái kia )
Thomas

4
Sẽ rất tuyệt nếu makenhóm thêm một vài biến ma thuật với os và vòm, có lẽ quá nhiều rắc rối.
Alex

6
@JanusTroelsen: không quan trọng việc có OSđược đặt trên các hệ thống không phải Windows hay không. Làm cho các đối xử không được đặt giống như trống, điều này sẽ gây ra một bước nhảy đến unamekhối dựa trên. Bạn chỉ cần thêm một kiểm tra FreeBSD ở đó.
Trevor Robinson

3
Điều này phá vỡ trên osx quá. /bin/sh: -c: line 0: syntax error near unexpected token , Windows_NT '/ bin / sh: -c: dòng 0:ifeq (,Windows_NT)' make: *** [os] Error 2
k107

1
@kristi Có vẻ như bạn đã chạy nó dưới dạng các lệnh shell chứ không phải trong ngữ cảnh của lệnh makefile.
phord

119

Lệnh uname ( http://developer.apple.com/documentation/Darwin/Reference/ManPages/man1/uname.1.html ) không có tham số nào sẽ cho bạn biết tên hệ điều hành. Tôi sẽ sử dụng nó, sau đó tạo các điều kiện dựa trên giá trị trả về.

Thí dụ

UNAME := $(shell uname)

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

Nói rõ hơn, dòng đó đi vào Makefile của bạn. Tôi vừa thử cấu trúc đó trong Makefiles trong Cygwin và OSX, và nó hoạt động như mong đợi. Một cái gì đó để thử: Nhập uname trên dòng lệnh của bạn. Điều đó sẽ cho bạn biết giá trị của hệ điều hành đó. OSX có thể sẽ là "Darwin".
dbrown0708

Dự án GnuWin32 có cả uname và Gnu cung cấp dưới dạng các ứng dụng Windows gốc, làm cho kỹ thuật này có thể di chuyển đến MingW tại một dấu nhắc lệnh cũng như Cygwin trên Windows.
RBerteig

Nó không hoạt động trên máy Solaris của tôi khi nó ở trong makefile. Lệnh uname có sẵn trên hệ thống đó.
samoz

4
Lưu ý rằng nếu bạn đặt mục tiêu này trong Maketarget thì không được thụt lề.
nylund

4
Không phải là cú pháp ": =" dành riêng cho GNU Make?
Ankur Sethi

40

Phát hiện hệ điều hành bằng hai thủ thuật đơn giản:

  • Đầu tiên là biến môi trường OS
  • Sau đó, unamelệnh
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

Hoặc một cách an toàn hơn, nếu không có trên Windows và unamekhông có sẵn:

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

Ken Jackson đề xuất một giải pháp thay thế thú vị nếu bạn muốn phân biệt Cygwin / MinGW / MSYS / Windows. Xem câu trả lời của anh ấy trông như thế:

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

Sau đó, bạn có thể chọn những thứ liên quan tùy thuộc vào 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

Ghi chú:

  • Lệnh unamegiống như uname -svì tùy chọn -s( --kernel-name) là mặc định. Xem tại sao uname -stốt hơnuname -o .

  • Việc sử dụng OS(thay vì uname) đơn giản hóa thuật toán nhận dạng. Bạn vẫn có thể sử dụng duy nhất uname, nhưng bạn phải xử lý if/elsecác khối để kiểm tra tất cả các biến thể của MinGW, Cygwin, v.v.

  • Biến môi trường OSluôn được đặt thành "Windows_NT"trên các phiên bản Windows khác nhau (xem %OS%biến môi trường trên Wikipedia ).

  • Một thay thế OSlà biến môi trường MSVC(nó kiểm tra sự hiện diện của MS Visual Studio , xem ví dụ sử dụng Visual C ++ ).


Dưới đây tôi cung cấp một ví dụ hoàn chỉnh bằng cách sử dụng makegccđể xây dựng thư viện dùng chung: *.sohoặc *.dlltùy thuộc vào nền tảng. Ví dụ đơn giản nhất có thể để dễ hiểu hơn.

Để cài đặt makegcctrên Windows, xem Cygwin hoặc MinGW .

Ví dụ của tôi dựa trên năm tệp

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

Nhắc nhở: Makefile được thụt lề bằng cách sử dụng bảng . Thận trọng khi sao chép-dán bên dưới các tập tin mẫu.

Hai Makefiletập tin

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"

Để tìm hiểu thêm, hãy đọc tài liệu Biến tự động như được chỉ ra bởi cfi .

Mã nguồn

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

Tòa nhà

Sửa lỗi sao chép-dán Makefile(thay thế khoảng trắng hàng đầu bằng một bảng).

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

Các makelệnh là như nhau trên cả hai nền tảng. Đầu ra đã cho là trên các HĐH giống 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'

Chạy

Ứng dụng này yêu cầu phải biết thư viện chia sẻ ở đâu.

Trên Windows, một giải pháp đơn giản là sao chép thư viện nơi có ứng dụng:

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

Trên các hệ điều hành giống Unix, bạn có thể sử dụng LD_LIBRARY_PATHbiến môi trường:

> export LD_LIBRARY_PATH=lib

Chạy lệnh trên Windows:

> app/app.exe
hello

Chạy lệnh trên các hệ điều hành giống Unix:

> app/app
hello

Tôi đánh giá cao nỗ lực của bạn, nhưng câu hỏi chính là phát hiện hệ điều hành. Ví dụ của bạn chỉ phát hiện Linux và hoàn toàn giả định Windows.
Shahbaz

Xin chào @Shahbaz. Bạn nói đúng, câu trả lời của tôi không đưa ra một cách tiếp cận khác so với các câu trả lời khác. Hơn nữa, tập lệnh của tôi giả định nền tảng là Windows khi unamekhông phải là Linux. Tôi chỉ đưa ra một ví dụ bạn có thể không cần, nhưng điều này có thể giúp ai đó tìm kiếm (trên web) một cách để triển khai Makefilecho cả hai nền tảng ;-) Tôi nên thay đổi gì trong câu trả lời của mình? Chúc mừng
olibre

cố gắng đưa ra các cách để xác định chính xác các hệ điều hành khác! Mục tiêu là tìm ra một phương pháp không quá phức tạp, nhưng quan trọng hơn là chống đạn. Đó là, nó sẽ không phạm sai lầm bất kể điều gì.
Shahbaz

1
@olibre Cảm ơn ví dụ chi tiết, được đánh giá cao và giúp tôi bắt đầu nhanh chóng. Trong lib/Makefileví dụ, targetđược sử dụng cho .sovs .dll. Một ví dụ song song app/makefilesẽ hữu ích cho việc empty stringso .exesánh so với tên tệp ứng dụng. Chẳng hạn, tôi thường không thấy app.exetrên các HĐH giống Unix. ;-)

1
LSF? LFS? Typo?
Franklin Yu

19

Gần đây tôi đã thử nghiệm để trả lời câu hỏi này, tôi đã tự hỏi mình. Dưới đây là kết luận của tôi:

Vì trong Windows, bạn không thể chắc chắn rằng unamelệnh có sẵn, bạn có thể sử dụng gcc -dumpmachine. Điều này sẽ hiển thị mục tiêu trình biên dịch.

Cũng có thể có một vấn đề khi sử dụng unamenếu bạn muốn thực hiện một số biên dịch chéo.

Dưới đây là danh sách ví dụ về đầu ra có thể có của gcc -dumpmachine:

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

Bạn có thể kiểm tra kết quả trong tệp thực hiện như thế này:

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

Nó hoạt động tốt với tôi, nhưng tôi không chắc đó là cách đáng tin cậy để có được loại hệ thống. Ít nhất là nó đáng tin cậy về MinGW và đó là tất cả những gì tôi cần vì nó không yêu cầu phải có unamelệnh hoặc gói MSYS trong Windows.

Tóm lại, unamemang đến cho bạn hệ thống trên mà bạn đang biên soạn và gcc -dumpmachinecung cấp cho bạn hệ thống cho mà bạn đang biên soạn.


đây là một quan điểm tốt. Tuy nhiên, không unameđi kèm với MinGWkhông? Tuy nhiên, lưu ý thêm về biên dịch chéo là rất tốt.
Shahbaz

2
@Shahbaz Thiết lập MinGW có thể cài đặt MSYS (có chứa uname) nhưng đó là tùy chọn. Bạn vẫn có thể tìm thấy các hệ thống chỉ với các công cụ gcc MinGW
phsym

1
Nó không hoạt động ở bất cứ đâu Clang là trình biên dịch mặc định, như OS X và FreeBSD.
MarcusJ

@SebastianGodelet @MarcusJ Một cách khắc phục dễ dàng là $(shell $(CC) -dumpmachine). Kể từ OS X Sierra, lệnh -dumpmachine hoạt động trên Clang.
Vortico

Trên OS X 10.12.5 nó x86_64-apple-darwin16.6.0và rằng công trình thời tiết bạn gọi nó gcc, cchoặc clang, nhưng khôngcl
MarcusJ

17

Các git makefile chứa rất nhiều ví dụ về cách quản lý mà không autoconf / automake, nhưng vẫn làm việc trên nhiều nền tảng unixy.


13
Biết rằng Git không sử dụng Autofools bằng cách nào đó khiến tôi cảm thấy hợp lý trong sự ác cảm với họ ...
Dan Mould

11
"Tự động hóa"? Đó có phải là một lỗi đánh máy có chủ ý? :)
JesperE

6
Nó đã được. Nhưng trong suy nghĩ thứ hai, tôi nghĩ rằng tôi thích "Autostools" thậm chí còn tốt hơn. : D
Dan Mould

Btw, ý của bạn là "họ" là ai? Người Git hay Autotools? : D
JesperE

8
Tiếng Anh là một ngôn ngữ không chính xác. Làm thế nào về điều này: if (!usesAutotools(git)) aversionTo(autotools) = justified;Tôi cũng sẽ làm rõ rằng đó chỉ là công cụ tôi không thích. Tôi chắc rằng những người Autotools là những người tốt.
Dan Mould

11

Cập nhật: Bây giờ tôi coi câu trả lời này là lỗi thời. Tôi đã đăng một giải pháp hoàn hảo mới hơn nữa.

Nếu tệp tạo tệp của bạn có thể đang chạy trên Windows không phải Cygwin, unamecó thể không khả dụng. Điều đó thật bất tiện, nhưng đây là một giải pháp tiềm năng. Trước tiên, bạn phải kiểm tra Cygwin để loại trừ nó, bởi vì nó cũng có WINDOWS trong PATHbiến môi trường của nó .

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

Điều này là tốt cho đến bây giờ! Bạn có thể cho tôi biết một điều, mặc dù? Tôi không sử dụng Cygwin, nhưng tôi đã cài đặt MinGW với đường dẫn bin trong PATH. Nếu tôi phát hành unametừ một thiết bị đầu cuối cmd bình thường, nó mang lại cho tôi MINGW. Ý tôi là, tôi vẫn có unamemà không sử dụng Cygwin. Tôi cũng có git bash, nhưng tôi đã không thử uname trên nó (ngay bây giờ tôi đang ở trong Linux). Bạn có thể cho tôi biết làm thế nào hai cái này có thể được kết hợp trong mã của bạn?
Shahbaz

Nếu bạn chắc chắn rằng uname có sẵn, đó là giải pháp tốt nhất. Nhưng trong môi trường của tôi, mọi người đều đang sử dụng Windows và rất ít người đã cài đặt cygwin hoặc mingw , vì vậy tôi không đảm bảo rằng mọi thứ ngay cả tiêu chuẩn như uname sẽ hoạt động. Tôi hiện đang gặp một số khó khăn với đoạn mã trên đang chạy make.exe trong trình bao cmd. Windows là một nền tảng rất khó chịu để làm việc.
Ken Jackson

Ý tôi là, trước khi thử nghiệm sự tồn tại của WINDOWS trong PATH, bạn chắc chắn rằng bạn không giao dịch với cygwin, làm thế nào bạn có thể chắc chắn rằng mình không giao dịch với MinGW? Ví dụ: Makefile có thể kiểm tra xem một lệnh có thể chạy hay không và nếu unamekhông thể chạy, chúng ta có hiểu chúng ta đang ở trong Windows không?
Shahbaz

Tôi đang vật lộn để tìm một giải pháp sạch cho Mingw / cygwin / shell-hoặc-cmd / Linux này. Vào cuối ngày, một cái gì đó như preake hoặc cmake có vẻ là ý tưởng tốt nhất.
Isaac Nequittepas

Đây không còn là giải pháp tốt nhất. Giải pháp mới tôi đã đăng phân biệt Windows gốc bằng cách tìm kiếm ';' trong biến PATH, không có lệnh gọi shell.
Ken Jackson

7

Đó là công việc mà automake / autoconf của GNU được thiết kế để giải quyết. Bạn có thể muốn điều tra chúng.

Ngoài ra, bạn có thể đặt các biến môi trường trên các nền tảng khác nhau của mình và khiến bạn Makefile có điều kiện chống lại chúng.


11
Tôi thực sự khuyên bạn không nên sử dụng automake / autoconf. Chúng rất tẻ nhạt khi sử dụng, thêm rất nhiều chi phí vào tệp của bạn, vào thời gian xây dựng của bạn. Chúng chỉ đơn giản là thêm độ phức tạp cho hiệu ứng thường rất ít (vẫn không có tính di động giữa các hệ thống).
Julian Overmann

1
Tôi chỉ mất vài ngày để học makecách làm những gì tôi muốn. Bây giờ tôi có muốn vào automake / autoconf không? - KHÔNG. Những gì có thể được thực hiện trong tệp tạo tệp, chắc chắn nên được thực hiện trong tệp tạo tệp, nếu chỉ để tôi không có một số điểm dừng mỗi lần tôi muốn sửa đổi biên dịch & liên kết.
Kỹ sư

Có bao nhiêu nền tảng để makefiles của bạn hỗ trợ? automake và autoconf thực sự trở thành của riêng họ khi bạn muốn tính di động cho nhiều nền tảng.
Douglas Leeder

2
Tôi sẽ không yêu cầu sự phụ thuộc vô ích, và thay đổi toàn bộ hệ thống xây dựng của tôi chỉ để tìm hiểu hệ điều hành mà nó đang được biên dịch.
MarcusJ

7

Cuối cùng tôi đã tìm thấy giải pháp hoàn hảo giải quyết vấn đề này cho tôi.

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

Biến UNAME được đặt thành Linux, Cygwin, MSYS, Windows, FreeBSD, NetBSD (hoặc có lẽ là Solaris, Darwin, OpenBSD, AIX, HP-UX) hoặc Unknown. Sau đó, nó có thể được so sánh trong suốt phần còn lại của Makefile để phân tách bất kỳ biến và lệnh nhạy cảm với hệ điều hành nào.

Điều quan trọng là Windows sử dụng dấu chấm phẩy để phân tách các đường dẫn trong biến PATH trong khi mọi người khác sử dụng dấu hai chấm. (Có thể tạo một thư mục Linux có tên ';' và thêm nó vào PATH, điều này sẽ phá vỡ điều này, nhưng ai sẽ làm điều đó?) Đây dường như là phương pháp ít rủi ro nhất để phát hiện Windows gốc không cần một cuộc gọi vỏ. Cygwin và MSYS PATH sử dụng dấu hai chấm để uname được gọi cho chúng.

Lưu ý rằng biến môi trường HĐH có thể được sử dụng để phát hiện Windows, nhưng không phân biệt giữa Cygwin và Windows gốc. Kiểm tra tiếng vang của trích dẫn hoạt động, nhưng nó đòi hỏi một cuộc gọi shell.

Thật không may, Cygwin thêm một số thông tin phiên bản vào đầu ra của uname , vì vậy tôi đã thêm các lệnh gọi 'patsubst' để thay đổi nó thành 'Cygwin'. Ngoài ra, uname cho MSYS thực sự có ba đầu ra có thể bắt đầu bằng MSYS hoặc MINGW, nhưng tôi cũng sử dụng patsubst để chuyển đổi tất cả thành 'MSYS'.

Nếu việc phân biệt giữa các hệ thống Windows gốc có và không có uname.exe trên đường dẫn là rất quan trọng, dòng này có thể được sử dụng thay vì gán đơn giản:

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

Tất nhiên trong tất cả các trường hợp GNU make là bắt buộc hoặc một make khác hỗ trợ các chức năng được sử dụng.


6

Tôi đã gặp vấn đề này ngày hôm nay và tôi cần nó trên Solaris vì vậy đây là một cách tiêu chuẩn POSIX để làm (một cái gì đó rất gần) này.

#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
Gặp lỗi trên OSX: "Makefile: 22: *** thiếu dấu phân cách. Dừng lại.". Trên dòng này: "- @ kiếm $ (UNAME_S)".
Czarek Tomczak

OSX có thể không tuân thủ, vì vậy hãy thử những thứ này. (1) Đảm bảo rằng bạn đang sử dụng TAB làm ký tự đầu tiên trên dòng (2) Xóa "- @" ở phía trước của sản phẩm (2a) Nếu 2 hoạt động, hãy thử một ký tự và sau đó (3) Đảm bảo rằng UNAME_S được xác định, hãy thử echo $ (UNAME_S) thay vì - @ make $ (UNAME_S)
Huckle

6

Đây là một giải pháp đơn giản kiểm tra xem bạn đang ở trong môi trường Windows hoặc giống như posix (Linux / Unix / Cygwin / Mac):

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

Nó lợi dụng thực tế là tiếng vang tồn tại trên cả hai môi trường giống như posix và trong Windows, shell không lọc các trích dẫn.


1
Khá không an toàn vì $PATHcó thể đề cập đến người khác echo(Của tôi ...)
yyny

@YoYoYonnY Tại sao đường dẫn của bạn đề cập đến tiếng vang khác? Có vẻ như một tình huống rất khó xảy ra.
Samuel

1
không thực sự, git làm điều đó, mingw làm điều đó, cygwin làm điều đó ... Và cá nhân tôi đặt C: \ Windows \ System32 ở cuối con đường của tôi.
yyny

1
"Giải pháp" "hoạt động" này cho tất cả các môi trường, nhưng quan điểm của tôi là điều này chắc chắn không phát hiện các cửa sổ một cách an toàn. Nếu tôi muốn đặt -mwindowscờ hoặc chọn giữa một .dllhoặc .so, điều này sẽ thất bại.
yyny

1
@YoYoYonnY Cảm ơn bạn đã làm rõ. Trong tình huống của tôi, tôi chỉ quan tâm nếu tôi ở trong môi trường Cygwin hoặc Windows hoặc Linux chứ không phải là hệ điều hành tôi đang sử dụng, vì vậy điều này hữu ích cho tôi. Âm thanh như nhu cầu của bạn khác với những gì tôi đã có.
Samuel

3

Lưu ý rằng Makefiles cực kỳ nhạy cảm với khoảng cách. Đây là một ví dụ về Makefile chạy một lệnh bổ sung trên OS X và hoạt động trên OS X và Linux. Tuy nhiên, nhìn chung, autoconf / automake là cách phù hợp với mọi thứ không hề nhỏ.

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

HEADERS = data_ cấu trúc.h http_client.h load.h lock.h search.h server.h thread.h Utility.h
ĐỐI TƯỢNG = http_client.o load.o lock.o search.o server.o thread.o Utility.o vor.o

tất cả: vor

dọn dẹp:
    rm -f $ (ĐỐI TƯỢNG) vor

vor: $ (ĐỐI TƯỢNG)
    $ (CPP) $ (LDFLAGS) -o vor $ (ĐỐI TƯỢNG)
ifeq ($ (UNAME), Darwin)
    # Đặt vị trí thư viện Boost
    install_name_tool -change libboost_system.dylib /nexopia/lib/libboost_system.dylib vor
endif

% .o:% .cpp $ (TIÊU ĐỀ) Makefile
    $ (CPP) $ (CPPFLAGS) -c $

2

Một cách khác để làm điều này là bằng cách sử dụng tập lệnh "configure". Nếu bạn đã sử dụng một cái với tệp tạo tệp của mình, bạn có thể sử dụng kết hợp uname và sed để giải quyết công việc. Đầu tiên, trong kịch bản của bạn, hãy làm:

UNAME=uname

Sau đó, để đặt cái này vào Makefile của bạn, hãy bắt đầu với Makefile.in sẽ có cái gì đó như

UNAME=@@UNAME@@

trong đó.

Sử dụng lệnh sed sau đây trong tập lệnh cấu hình của bạn sau UNAME=unamebit.

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

Bây giờ makefile của bạn đã UNAMEđược xác định như mong muốn. Các câu lệnh if / elif / other chỉ còn lại!


Không nên đánh đồng đầu tiên này? UNAME = $ (uname)
Ken Jackson

0

Tôi đã gặp trường hợp phải phát hiện sự khác biệt giữa hai phiên bản Fedora, để điều chỉnh các tùy chọn dòng lệnh cho inkscape:
- trong Fedora 31, inkscape mặc định là 1.0beta sử dụng --export-file
- trong Fedora <31, inkscape mặc định là 0,92 sử dụng--export-pdf

Makefile của tôi chứa các mục sau

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

Điều này hoạt động vì /etc/os-releasecó chứa một dòng

VERSION_ID=<value>

vì vậy lệnh shell trong Makefile trả về chuỗi VERSION_ID=<value>, sau đó lệnh eval tác động vào điều này để đặt biến Makefile VERSION_ID. Điều này rõ ràng có thể được điều chỉnh cho các hệ điều hành khác tùy thuộc vào cách siêu dữ liệu được lưu trữ. Lưu ý rằng trong Fedora không có biến môi trường mặc định cung cấp phiên bản HĐH, nếu không tôi sẽ sử dụng nó!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.