Frage

Ich arbeite routinemäßig auf verschiedenen Computern und verschiedenen Betriebssystemen, die sind Mac OS X, Linux oder Solaris. Für das Projekt arbeite ich an, ziehe ich meinen Code von einem entfernten Git Repository.

Ich mag die Lage sein, auf meinen Projekten zu arbeiten, unabhängig davon, welches Endgerät ich bin an. Bisher habe ich Wege gefunden, um die OS Änderungen zu erhalten, indem Sie die Make-Datei zu ändern jedes Mal, wenn ich Computer wechseln. Dies ist jedoch mühsam und verursacht eine Reihe von Kopfschmerzen.

Wie kann ich meine Make-Datei ändern, so dass es die OS erkennt Ich verwende und modifiziert Syntax entsprechend?

Hier ist die Make-Datei:

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
War es hilfreich?

Lösung

Es gibt viele gute Antworten hier schon, aber ich wollte ein vollständigeres Beispiel, dass beide teilen:

  • geht nicht davon aus uname existiert unter Windows
  • erkennt auch der Prozessor

Die CCFLAGS hier definiert sind, nicht unbedingt zu empfehlen oder ideal; sie sind genau das, was das Projekt, zu dem ich das Hinzufügen OS / CPU automatische Erkennung verwendet werden passiert ist.

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

Andere Tipps

Der Befehl uname ( http: // developer. apple.com/documentation/Darwin/Reference/ManPages/man1/uname.1.html ) ohne Parameter sollten Sie das Betriebssystem Namen sagen. Ich würde das verwenden, dann conditionals machen basierend auf dem Rückgabewert.

Beispiel

UNAME := $(shell uname)

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

Detect das Betriebssystem mit zwei einfachen Tricks:

  • Zunächst wird die Umgebungsvariable OS
  • Dann wird der uname Befehl
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

Oder ein sicherer Weg, wenn auch nicht auf Windows und uname nicht verfügbar:

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

Ken Jackson eine interessante Alternative schlägt, wenn Sie Cygwin / MinGW / MSYS / Windows unterscheiden wollen. Siehe seine Antwort , dass so aussieht:

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

Dann können Sie das entsprechende Material je nach detected_OS wählen:

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

Weitere Informationen:

  • Befehl uname ist die gleiche wie uname -s , weil Option -s ( --kernel-name ) ist die Standardeinstellung. Siehe warum uname -s ist besser als uname -o .

  • Die Verwendung von OS (statt uname) vereinfacht den Identifikationsalgorithmus. Sie können nach wie vor nur uname verwenden, aber Sie haben mit if/else Blöcke behandeln alle MinGW zu überprüfen, Cygwin usw. Variationen.

  • Die Umgebungsvariable OS ist immer gesetzt auf verschiedenen Windows-Versionen "Windows_NT" (siehe %OS% Umgebung Variable auf Wikipedia ).

  • Eine Alternative von OS ist der Umgebungsvariable MSVC (er überprüft das Vorhandensein von MS Visual Studio finden Sie unter Beispiel Visual C ++ ).


Im Folgenden wird ich biete ein komplettes Beispiel mit make und gcc eine gemeinsame Bibliothek bauen: *.so oder *.dll auf der Plattform abhängig. Das Beispiel ist als einfachste möglichst verständlicher zu sein.

Um make und gcc unter Windows zu installieren finden Sie unter Cygwin oder MinGW .

Mein Beispiel basiert auf fünf Dateien

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

Zur Erinnerung: Makefile ist zerklüftet mit Auftabellierung . Vorsicht beim Kopieren-Einfügen unter Beispieldateien.

Die beiden Makefile Dateien

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"

Um mehr zu erfahren, lesen Sie Automatische Variablen Dokumentation wie erwähnt von cfi .

Der Quellcode

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

Der Build

Fixieren Sie die Copy-Paste von Makefile (ersetzen führende Leerzeichen durch eine tabellarische Aufstellung).

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

Der make Befehl ist das gleiche auf beiden Plattformen. Die angegebene Ausgabe ist auf Unix-ähnlichen Betriebssystemen:

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

Der Lauf

Die Anwendung erfordert zu wissen, wo ist die gemeinsame Bibliothek.

Unter Windows eine einfache Lösung ist es, die Bibliothek zu kopieren, in dem die Anwendung:

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

Auf Unix-ähnlichen Betriebssystemen können Sie die LD_LIBRARY_PATH Umgebungsvariable verwenden:

> export LD_LIBRARY_PATH=lib

Run der Befehl unter Windows:

> app/app.exe
hello

Führen Sie den Befehl auf Unix-ähnlichen Betriebssystemen:

> app/app
hello

Ich experimentiere vor kurzem, um diese Frage zu beantworten ich mich frage. Hier sind meine Schlussfolgerungen:

Da in Windows können Sie nicht sicher sein kann, dass der uname Befehl verfügbar ist, können Sie gcc -dumpmachine verwenden. Dadurch wird das Compiler Ziel angezeigt werden soll.

Es kann auch ein Problem, wenn uname verwenden, wenn Sie etwas Querübersetzbarkeit tun wollen.

Hier ist ein Beispiel Liste der möglichen Ausgabe von gcc -dumpmachine:

  • mingw32
  • i686-pc-Cygwin
  • x86_64-RedHat-Linux

Sie können das Ergebnis in der Make-Datei überprüfen wie folgt aus:

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

Es funktionierte gut für mich, aber ich bin nicht sicher, es ist ein zuverlässiger Weg, um den Systemtyp des Erhaltens. Zumindest ist es zuverlässig über MinGW und das ist alles, was ich da es brauche erfordern nicht den uname Befehl oder MSYS hat Paket in Windows.

Um es zusammenzufassen, uname gibt Ihnen das System auf , die Sie kompilieren und gcc -dumpmachine gibt Ihnen das System für , die Sie kompilieren.

Die git Make-Datei enthält zahlreiche Beispiele dafür, wie ohne autoconf / auto zu verwalten, aber immer noch arbeitet auf einer Vielzahl von Plattformen Unixy.

Update: Ich halte jetzt diese Antwort obsolet. Ich stellte eine neue perfekte Lösung weiter unten.

Wenn Ihre Make-Datei auf Nicht-Cygwin Windows ausgeführt sein kann, uname möglicherweise nicht zur Verfügung. Das ist umständlich, aber das ist eine mögliche Lösung. Sie müssen sich zuerst für Cygwin überprüfen, es auszuschließen, weil es zu WINDOWS in seiner PATH Umgebungsvariable hat.

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

Das ist die Aufgabe, die GNU auto / autoconf zu lösen sind entworfen, um. Sie könnten sie untersuchen wollen.

Alternativ können Sie Umgebungsvariablen auf verschiedenen Plattformen gesetzt und machen Sie gegen sie bedingte Makefile.

ich in dieses Problem lief heute und ich brauchte es auf Solaris so ist hier ein POSIX-Standard Weg (etwas ganz in der Nähe), dies zu tun.

#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

Hier ist eine einfache Lösung, die überprüft, ob Sie in einer Windows oder Posix-like (Linux / Unix / Cygwin / Mac) Umgebung sind:

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

Es nutzt die Tatsache, dass Echo auf beiden Posix-like und Windows-Umgebungen vorhanden ist, und dass in Windows ist die Shell nicht die Anführungszeichen filtern.

Schließlich fand ich die perfekte Lösung, um dieses Problem für mich löst.

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

Die UNAME Variable wird auf Linux, Cygwin, MSYS Windows, FreeBSD, NetBSD (oder vermutlich Solaris, Darwin, OpenBSD, AIX, HP-UX) oder unbekannt. Es kann dann über den Rest des Makefiles verglichen werden, um alle OS empfindlichen Variablen und Befehle zu trennen.

Der Schlüssel ist, dass Windows Semikolons zu trennen Pfade in der PATH-Variable verwendet, während alle anderen Doppelpunkte verwendet. (Es ist möglich, ein Linux-Verzeichnis mit einem machen ‚‘ im Namen und fügen Sie ihn in PATH, die diese brechen würde, aber wer würde so etwas tun?) Dies scheint die am wenigsten riskante Methode, um native Windows zu erkennen, weil es kein Shell-Aufruf benötigen. Die Cygwin und MSYS PATH Verwendung Doppelpunkte so uname ist für sie genannt.

Beachten Sie, dass das OS-Umgebungsvariable verwendet werden, kann mit Windows zu erkennen, aber nicht zwischen Cygwin und native Windows zu unterscheiden. Testen auf das Echo von Zitaten funktionieren, aber es erfordert einen Shell-Aufruf.

Leider fügt Cygwin einige Versionsinformationen an den Ausgang des uname , so fügte ich die ‚patsubst‘ nennt, sie zu ändern, um nur ‚Cygwin‘. Auch uname für MSYS hat tatsächlich drei mögliche Ausgänge mit MSYS oder mingw starten, aber ich benutze auch zu verwandeln alle nur ‚MSYS‘ patsubst.

Wenn es wichtig, zwischen dem nativen Windows-Systemen mit und ohne einige uname.exe auf dem Weg zu unterscheiden, kann diese Linie anstelle der einfachen Zuordnung verwendet werden:

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

Natürlich in allen Fällen GNU machen erforderlich ist, oder eine andere machen , das die Funktionen unterstützt verwendet.

Beachten Sie, dass Makefiles sind extrem empfindlich auf Abstand. Hier ist ein Beispiel eines Makefiles, die auf OS X einen zusätzlichen Befehl ausgeführt wird und das funktioniert auf OS X und Linux. Insgesamt aber autoconf / auto ist der Weg für irgendetwas überhaupt nicht trivial zu gehen.

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 load.o lock.o search.o server.o thread.o utility.o vor.o

all: vor

clean:
    rm -f $(OBJECTS) vor

vor: $(OBJECTS)
    $(CPP) $(LDFLAGS) -o vor $(OBJECTS)
ifeq ($(UNAME),Darwin)
    # Set the Boost library location
    install_name_tool -change libboost_system.dylib /nexopia/lib/libboost_system.dylib vor
endif

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

Eine andere Möglichkeit, dies zu tun ist, indem ein „konfigurieren“ Skript. Wenn Sie bereits ein mit Ihrem Make-Datei verwenden, können Sie eine Kombination aus uname verwenden und sed Dinge kennen zu trainieren. Zuerst in Ihrem Skript zu tun:

UNAME=uname

Dann wird, um diese in Ihrem Makefile zu setzen, mit Makefile.in beginnen, die so etwas wie

haben sollten
UNAME=@@UNAME@@

drin.

Mit dem folgenden sed-Befehl in der Configure-Skript nach dem UNAME=uname Bit.

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

Nun sollte Ihr Make-Datei UNAME definiert haben, wie gewünscht. Wenn / elif / else-Anweisungen sind alles, was noch übrig ist!

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top