OS 감지 makefile


250

나는 여러 다른 컴퓨터와 여러 다른 운영 체제 (Mac OS X, Linux 또는 Solaris)에서 일상적으로 작업합니다. 내가 작업중 인 프로젝트의 경우 원격 git 저장소에서 코드를 가져옵니다.

나는 어떤 터미널에 있는지에 관계없이 프로젝트를 수행 할 수 있기를 원합니다. 지금까지 컴퓨터를 바꿀 때마다 makefile을 변경하여 OS 변경을 피할 수있는 방법을 찾았습니다. 그러나 이것은 지루하며 두통을 유발합니다.

사용중인 OS를 감지하고 그에 따라 구문을 수정하도록 makefile을 어떻게 수정합니까?

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

답변:


283

여기에 좋은 답변이 많이 있지만, 다음과 같은 더 완전한 예제를 공유하고 싶었습니다.

  • unameWindows에 존재 한다고 가정하지 않습니다
  • 또한 프로세서를 감지

여기에 정의 된 CCFLAGS가 반드시 권장되거나 이상적인 것은 아닙니다. 그들은 내가 OS / 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
슬프게도 PROCESSOR_ARCHITECTUREenvvar는 프로세스가 32 비트인지 64 비트인지에 따라 가상화 된 것으로 보입니다. 따라서 make32 비트이고 64 비트 응용 프로그램을 만들려고하면 실패합니다. PROCESSOR_ARCHITEW6432나를 위해 일한 것과 함께 사용 ( 이것저것 참조 )
Thomas

4
경우 좋은이 될 것 make팀, 아마 너무 많은 문제를 OS와 마법 변수의 몇 가지를 추가하고 아치.
Alex 1

6
@JanusTroelsen : OSWindows 이외의 시스템에 설정되어 있는지 여부 는 중요하지 않습니다 . Make는 설정되지 않은 것을 빈 것으로 간주하여 uname기반 블록으로 점프합니다 . FreeBSD 검사 만 추가하면됩니다.
Trevor Robinson

3
이것은 osx에서도 깨집니다. /bin/sh: -c: line 0: syntax error near unexpected token , Windows_NT '/ bin / sh : -c : line 0 :ifeq (,Windows_NT)' make: *** [os] Error 2
k107

1
@kristi makefile 지시문 컨텍스트가 아닌 쉘 명령으로 이것을 실행 한 것처럼 들립니다.
phord

119

매개 변수가없는 uname 명령 ( http://developer.apple.com/documentation/Darwin/Reference/ManPages/man1/uname.1.html )은 운영 체제 이름을 알려줍니다. 그것을 사용하고 반환 값을 기준으로 조건을 만듭니다.

UNAME := $(shell uname)

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

분명히 말하면, 그 줄은 Makefile에 들어갑니다. 방금 Cygwin 및 OSX의 Makefiles에서 해당 구성을 시도했지만 예상대로 작동했습니다. 시도 할 사항 : 명령 행에 uname을 입력하십시오. 해당 OS의 가치를 알려줍니다. OSX는 "Darwin"일 것입니다.
dbrown0708

GnuWin32 프로젝트에는 uname과 Gnu가 기본 Windows 응용 프로그램으로 제공되므로 명령 프롬프트에서 MingW와 Windows의 Cygwin에서이 기술을 이식 할 수 있습니다.
RBerteig 2009

makefile 안에있을 때 내 Solaris 시스템에서 실패합니다. 해당 시스템에서 uname 명령을 사용할 수 있습니다.
samoz

4
이것을 Maketarget 안에 넣으면 들여 쓰기해서는 안됩니다.
nylund

4
": ="문법이 GNU Make에만 한정되지 않습니까?
Ankur Sethi

40

두 가지 간단한 트릭을 사용하여 운영 체제를 감지하십시오.

  • 먼저 환경 변수 OS
  • 그런 다음 uname명령
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

또는 Windows에없고 uname사용할 수없는 경우 더 안전한 방법 :

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

Cygwin / MinGW / MSYS / Windows를 구별하려면 Ken Jackson 이 흥미로운 대안을 제안합니다. 다음과 같은 답변 을 보십시오 .

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

그런 다음에 따라 관련 항목을 선택할 수 있습니다 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

노트:

  • 옵션 ( )이 기본값 이므로 명령 uname은 동일 합니다. 보다 나은 이유를 참조하십시오 .uname -s-s--kernel-nameuname -suname -o

  • OS대신 ( uname)을 사용 하면 식별 알고리즘이 간소화됩니다. 여전히 단독으로 사용할 수는 uname있지만 if/else모든 MinGW, Cygwin 등 변형을 확인하려면 블록을 처리해야합니다 .

  • 환경 변수 OS는 항상 "Windows_NT"다른 Windows 버전으로 설정됩니다 ( %OS%Wikipedia의 환경 변수 참조 ).

  • 대안은 OS환경 변수입니다 MSVC( MS Visual Studio 의 존재를 확인합니다 ( Visual C ++ 사용 예제 참조 )).


내가 사용하는 완전한 예를 제공 아래 makegcc: 공유 라이브러리를 구축 *.so또는 *.dll플랫폼에 따라. 예제는 이해하기 쉽게 가능한 한 단순합니다.

Windows에 설치 make하고 설치하려면 Cygwin 또는 MinGW를gcc 참조하십시오 .

내 예는 5 개의 파일을 기반으로합니다.

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

알림 : tabulation을Makefile 사용하여 들여 씁니다 . 샘플 파일 아래에 복사하여 붙여 넣을 때주의하십시오.

Makefile파일

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"

자세한 내용 은 cfi가 지적한 자동 변수 설명서참조하십시오 .

소스 코드

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

빌드

복사 붙여 넣기를 수정합니다 Makefile(앞의 공백을 하나의 표로 대체).

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

make명령은 두 플랫폼에서 동일합니다. 주어진 출력은 유닉스 계열 OS에 있습니다.

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

질주

응용 프로그램은 공유 라이브러리가 어디에 있는지 알아야합니다.

Windows에서 간단한 해결책은 애플리케이션이있는 라이브러리를 복사하는 것입니다.

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

유닉스 계열 OS에서는 LD_LIBRARY_PATH환경 변수를 사용할 수 있습니다 .

> export LD_LIBRARY_PATH=lib

Windows에서 명령을 실행하십시오.

> app/app.exe
hello

유닉스 계열 OS에서 명령을 실행하십시오.

> app/app
hello

귀하의 노력에 감사 드리지만 주요 질문은 운영 체제를 감지하는 것이 었습니다. 귀하의 예는 Linux 만 감지하고 그렇지 않으면 Windows를 완전히 가정합니다.
Shahbaz

안녕하세요 @Shahbaz. 당신은 옳습니다. 내 대답은 다른 대답과 다른 접근법을주지 않습니다. 또한 내 스크립트는 unameLinux가 아닌 경우 플랫폼이 Windows라고 가정합니다 . 나는 당신이 필요하지 않을 수도있는 예를 제시하지만, 누군가 웹 Makefile에서 두 플랫폼 모두 를 구현하는 방법을 찾는 데 도움이 될 수 있습니다. ;-) 내 대답에서 무엇을 변경해야합니까? 건배
올리버

다른 운영 체제도 올바르게 식별하는 방법을 생각해보십시오! 목표는 너무 복잡하지는 않지만 더 중요한 것은 방탄 방법을 찾는 것입니다. 즉, 그것은 무엇이든 실수하지 않을 것입니다.
Shahbaz

1
@olibre 자세한 예제에 감사드립니다. 이 lib/Makefile예 에서는 vs에 target사용됩니다 . 에 대한 병렬 예 에 유용 할 것이다 대 응용 프로그램 파일 이름에 대한 비교. 예를 들어, 나는 보통 유닉스 계열 OS 에서는 보이지 않습니다 . ;-).so.dllapp/makefileempty string.exeapp.exe

1
LSF? LFS? 오식?
Franklin Yu

19

나는 최근 나 자신에게 묻는이 질문에 대답하기 위해 실험하고있었습니다. 내 결론은 다음과 같습니다.

Windows에서는 uname명령이 사용 가능한지 확신 할 수 없으므로을 사용할 수 있습니다 gcc -dumpmachine. 컴파일러 대상이 표시됩니다.

uname크로스 컴파일을 수행하려는 경우 사용할 때 문제가 발생할 수도 있습니다 .

가능한 출력 목록은 다음과 같습니다 gcc -dumpmachine.

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

다음과 같이 makefile에서 결과를 확인할 수 있습니다.

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

그것은 나를 위해 잘 작동했지만 시스템 유형을 얻는 신뢰할 수있는 방법인지 확실하지 않습니다. 최소한 MinGW 에 대해 신뢰할 수 있으며 Windows에 uname명령이나 MSYS 패키지 가 필요하지 않기 때문에 필요한 것 입니다.

요약하면, uname당신에게 시스템 제공 당신이 컴파일중인, 그리고 gcc -dumpmachine당신에게 시스템 제공 을 위해 당신이 컴파일되는합니다.


이것은 좋은 지적입니다. 그러나 어쨌든 uname오지 MinGW않습니까? 그럼에도 불구하고 크로스 컴파일에 관한 추가 메모는 훌륭합니다.
Shahbaz

2
@Shahbaz MinGW 설정은 uname을 포함하는 MSYS를 설치할 수 있지만 선택 사항입니다. MinGW gcc 도구 만있는 시스템을 여전히 찾을 수 있습니다
phsym

1
Clang은 OS X 및 FreeBSD와 같은 기본 컴파일러입니다.
MarcusJ

@SebastianGodelet @MarcusJ 쉬운 해결책은 $(shell $(CC) -dumpmachine)입니다. OS X Sierra부터 -dumpmachine 명령은 Clang에서 작동합니다.
Vortico

OS X 10.12.5 에서는 , 또는 , 그러나 x86_64-apple-darwin16.6.0호출 하지 않아도 작동합니다gccccclangcl
MarcusJ

17

자식 메이크 autoconf를 / automake에, unixy 다양한 플랫폼에 아직 여전히 작업없이 관리하는 방법에 대한 많은 예제가 포함되어 있습니다.


13
힘내가 Autofools를 사용하지 않는다는 것을 알면 어떻게 든 그들에게 혐오감을 느끼게됩니다 ...
Dan Molding

11
"Autofools"? 고의적 인 오타입니까? :)
JesperE

6
그렇습니다. 그러나 두 번째 생각에, 나는 "Autostools"를 훨씬 더 좋아한다고 생각합니다. : D
Dan Molding

Btw, "그들"은 누구를 의미 했습니까? 힘내 또는 Autotools 사람들? : D
JesperE 2016 년

8
영어는 매우 부정확 한 언어입니다. 어떻습니까 : if (!usesAutotools(git)) aversionTo(autotools) = justified;나는 그것이 내가 싫어하는 도구 일뿐임을 분명히 할 것입니다. 나는 Autotools 사람들이 좋은 사람들이라고 확신합니다.
Dan Molding

11

업데이트 : 이제이 답변이 더 이상 사용되지 않는다고 생각합니다. 더 완벽한 새로운 솔루션을 게시했습니다.

makefile이 Cygwin이 아닌 Windows에서 실행중인 uname경우 사용하지 못할 수 있습니다. 어색하지만 이것은 잠재적 인 해결책입니다. Cygwin의 PATH환경 변수에도 WINDOWS가 있으므로 Cygwin을 먼저 제외해야합니다 .

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

이것은 지금에 좋습니다! 그래도 한 가지만 말해 줄래? Cygwin을 사용하지 않지만 MinGW가 PATH의 bin 경로와 함께 설치되어 있습니다. uname일반 cmd 터미널에서 발행 하면 MINGW가 표시됩니다. 내 말은, 여전히 unameCygwin을 사용하지 않고 있다는 것입니다 . 또한 git bash가 있지만 uname을 시도하지 않았습니다 (현재 Linux에 있습니다). 이 두 가지가 코드에 어떻게 통합 될 수 있는지 말해 줄 수 있습니까?
Shahbaz

uname을 사용할 수 있다고 확신하면 이것이 최선의 해결책입니다. 그러나 내 환경에서 모든 사람이 Windows를 사용하고 있으며 소수의 사람들이 cygwin 또는 mingw를 설치했기 때문에 uname만큼 표준이 작동한다고 보장하지 않습니다. 현재 cmd 쉘에서 make.exe를 실행하는 위의 코드에 어려움이 있습니다. Windows는 매우 실망스러운 플랫폼입니다.
Ken Jackson

내 말은 PATH에 WINDOWS가 있는지 테스트하기 전에 cygwin을 다루지 않는지 확인하고 MinGW를 다루지 않는지 어떻게 알 수 있습니까? 예를 들어, Makefile에서 명령을 실행할 수 있는지 테스트 할 수 uname있습니까? 실행할 수 없으면 Windows에 있다는 것을 알 수 있습니까?
Shahbaz

이 Mingw / cygwin / shell-or-cmd / Linux에 대한 깨끗한 솔루션을 찾기 위해 고심하고 있습니다. 하루가 끝나면 premake 또는 cmake와 같은 것이 가장 좋은 아이디어처럼 보입니다.
Isaac Nequittepas

이것은 더 이상 최고의 솔루션이 아닙니다. 내가 게시 한 새로운 솔루션은 ';' 쉘 호출없이 PATH 변수에.
Ken Jackson

7

이것이 GNU의 automake / autoconf 가 해결하도록 설계된 작업입니다 . 조사해 볼 수도 있습니다.

또는 다른 플랫폼에서 환경 변수를 설정하고 Makefile을 조건부로 만들 수 있습니다.


11
automake / autoconf를 사용하지 않는 것이 좋습니다. 그것들은 사용하기가 지루하고 파일에 많은 오버 헤드를 추가하고 빌드 시간을 단축시킵니다. 그들은 일반적으로 매우 적은 효과를 위해 복잡성을 추가합니다 (아직 시스템간에 이식성이 없음).
Johannes Overmann

1
방금 며칠 동안 make내가 원하는 것을하는 법을 배우는 데 보냈습니다 . 이제 automake / autoconf에 들어가고 싶습니까? - 아니. 무엇을 할 수 나는 여러 정지 - 오프 포인트 제가 컴파일 및 링크를 개정 할 때마다이 없다는에만 그렇다면 메이크에서 할 수 확실히, 메이크에서 수행해야합니다.
엔지니어

메이크 파일은 몇 개의 플랫폼을 지원합니까? automake 및 autoconf는 많은 플랫폼으로 이식성을 원할 때 실제로 자체적으로 제공됩니다.
Douglas Leeder

2
쓸모없는 종속성이 필요하지 않으며 컴파일되는 OS를 찾기 위해 전체 빌드 시스템을 변경하지 않습니다.
MarcusJ

7

마침내이 문제를 해결하는 완벽한 솔루션을 찾았습니다.

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 변수는 Linux, Cygwin, MSYS, Windows, FreeBSD, NetBSD (또는 아마도 Solaris, Darwin, OpenBSD, AIX, HP-UX) 또는 Unknown으로 설정됩니다. 그런 다음 나머지 Makefile에서 OS에 민감한 변수와 명령을 구분하기 위해 비교할 수 있습니다.

핵심은 Windows가 세미콜론을 사용하여 PATH 변수에서 경로를 구분하는 반면 다른 모든 사람은 콜론을 사용한다는 것입니다. (이름에 ';'을 사용하여 Linux 디렉토리를 만들어 PATH에 추가하면 문제가 발생하지만 누가 그런 일을합니까?) 네이티브 Windows를 감지하는 가장 위험한 방법 인 것 같습니다. 쉘 호출이 필요하지 않습니다. Cygwin 및 MSYS PATH는 콜론을 사용하므로 uname 이 필요합니다.

OS 환경 변수를 사용하여 Windows를 감지 할 수 있지만 Cygwin과 기본 Windows를 구별 할 수는 없습니다. 따옴표의 에코 테스트는 작동하지만 셸 호출이 필요합니다.

불행히도 Cygwin은 버전 정보를 uname 출력에 추가하므로 'patsubst'호출을 추가하여 'Cygwin'으로 변경했습니다. 또한 MSYS의 uname에는 실제로 MSYS 또는 MINGW로 시작하는 세 가지 가능한 출력이 있지만 patsubst를 사용하여 모두 'MSYS'로 변환합니다.

경로에 uname.exe가 있거나없는 기본 Windows 시스템을 구별해야하는 경우 간단한 지정 대신이 행을 사용할 수 있습니다.

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

물론 모든 경우에 GNU make 가 필요하거나 사용 된 기능을 지원하는 다른 make 가 필요합니다 .


6

오늘이 문제에 부딪 쳤고 Solaris 에서이 문제가 발생했기 때문에 POSIX 표준 방법이 있습니다 (매우 가까운 일).

#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에서 오류 발생 : "Makefile : 22 : *** 구분 기호가 없습니다. 중지하십시오." 이 줄에서 : "-@ make $ (UNAME_S)".
Czarek Tomczak

OSX가 호환되지 않을 수 있으므로 순서대로 시도하십시오. (1) 줄의 첫 번째 문자로 TAB을 사용하고 있는지 확인하십시오. (2) 제조업체 앞의 "-@"를 제거하십시오. UNAME_S는 에코 $ (UNAME_S) 대신 시도 정의 - @ $ (UNAME_S를) 만들
Huckle

6

다음은 Windows 또는 posix와 같은 (Linux / Unix / Cygwin / Mac) 환경에 있는지 확인하는 간단한 솔루션입니다.

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

에코는 posix와 같은 환경과 Windows 환경 모두에 존재하고 Windows에서는 쉘이 따옴표를 필터링하지 않는다는 사실을 이용합니다.


1
$PATH다른 것을 참조 할 수 있기 때문에 매우 안전하지 echo않습니다 (광산이 ...)
yyny

@YoYoYonnY 경로가 다른 반향을 참조하는 이유는 무엇입니까? 거의 상황이 아닌 것 같습니다.
사무엘

1
실제로, git은 그것을 수행하고, mingw는 그것을 수행하고, cygwin은 그것을 수행합니다 ... 그리고 개인적으로 C : \ Windows \ System32를 경로의 맨 아래에 놓습니다.
yyny

1
이 "솔루션"은 모든 환경에서 작동하지만 내 요점은 확실히 윈도우를 안전하게 감지하지 못한다는 것입니다. 내가 설정하려면 -mwindows플래그를하거나 사이에서 선택 .dll또는 .so,이 실패합니다.
yyny

1
@YoYoYonnY 설명해 주셔서 감사합니다. 내 상황에서 내가 사용했던 OS가 아닌 Cygwin 또는 Windows 또는 Linux 환경에있는 경우에만 관심이 있었으므로 도움이되었습니다. 당신의 요구와 같은 소리가 내 것과 다릅니다.
사무엘

3

Makefile은 간격에 매우 민감합니다. 다음은 OS X에서 추가 명령을 실행하고 OS X 및 Linux에서 작동하는 Makefile의 예입니다. 그러나 전체적으로 autoconf / automake는 사소하지 않은 모든 작업을 수행하는 방법입니다.

UNAME : = $ (쉘 uname -s)
CPP = g ++
CPPFLAGS = -pthread -ansi-벽-오류 -pedantic -O0 -g3 -I / nexopia / include
LDFLAGS = -pthread -L / nexopia / lib -lboost_system

헤더 = data_structures.h http_client.h load.h lock.h search.h server.h thread.h utility.h
객체 = http_client.o load.o lock.o search.o server.o thread.o utility.o vor.o

모두 : vor

깨끗한:
    rm -f $ (개체) vor

vor : $ (OBJECTS)
    $ (CPP) $ (LDFLAGS) -o vor $ (OBJECTS)
ifeq ($ (UNAME), 다윈)
    # Boost 라이브러리 위치 설정
    install_name_tool -change libboost_system.dylib /nexopia/lib/libboost_system.dylib vor
엔디 프

% .o : % .cpp $ (HEADERS) 메이크 파일
    $ (CPP) $ (CPPFLAGS) -c $

2

이를 수행하는 다른 방법은 "configure"스크립트를 사용하는 것입니다. makefile과 함께 이미 사용중인 경우 uname과 sed를 함께 사용하여 문제를 해결할 수 있습니다. 먼저 스크립트에서 다음을 수행하십시오.

UNAME=uname

그런 다음 이것을 Makefile에 넣으려면 Makefile.in으로 시작하십시오.

UNAME=@@UNAME@@

그 안에.

UNAME=uname비트 다음에 configure 스크립트에서 다음 sed 명령을 사용하십시오 .

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

이제 makefile이 UNAME원하는대로 정의 되었 어야 합니다. If / elif / else 문만 남았습니다!


첫 번째와 같지 않아야합니까? UNAME = $ (uname)
Ken Jackson

0


잉크 스케이프에 대한 명령 행 옵션을 조정하기 위해 두 버전의 페도라 간의 차이를 감지 해야하는 경우가있었습니다.-페도라 31에서 기본 잉크 스케이프는 1.0 베타입니다.--export-file
- 페도라 <31, 기본 잉크 스케이프는 사용하는 0.92--export-pdf

내 Makefile에는 다음이 포함됩니다

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

이것은 /etc/os-release라인을 포함 하기 때문에 작동 합니다

VERSION_ID=<value>

따라서 Makefile의 쉘 명령은 문자열을 반환 한 VERSION_ID=<value>다음 eval 명령이이를 수행하여 Makefile 변수를 설정합니다 VERSION_ID. 이것은 메타 데이터가 저장되는 방식에 따라 다른 OS에 맞게 조정될 수 있습니다. Fedora에는 OS 버전을 제공하는 기본 환경 변수가 없습니다. 그렇지 않으면 사용했을 것입니다!

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.