ОС виявлення makefile


250

Я регулярно працюю на декількох різних комп’ютерах та декількох різних операційних системах, які є Mac OS X, Linux або Solaris. Для проекту, над яким я працюю, я витягую свій код із віддаленого сховища git.

Мені подобається працювати над своїми проектами незалежно від того, на якому терміналі я перебуваю. Поки я знайшов способи обійти зміни ОС, змінюючи makefile щоразу, коли перемикаю комп'ютери. Однак це нудно і викликає купу головних болів.

Як я можу змінити свій 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

Тут вже є багато хороших відповідей, але я хотів поділитися більш повним прикладом, що обидва:

  • не припускає, що unameіснує в Windows
  • також виявляє процесор

Визначені тут 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_ARCHITECTUREсхоже, що envvar віртуалізується залежно від того, чи є процес 32-бітним або 64-бітовим. Отже, якщо ваш make32-розрядний і ви намагаєтеся створити 64-розрядну програму, вона не вдасться. Використовуючи його в поєднанні з PROCESSOR_ARCHITEW6432працюючим для мене (див. Це , і це )
Томас

4
Було б добре, якби makeкоманда додала пару магічних змінних з os та arch, ймовірно, занадто багато проблем.
Олексій

6
@JanusTroelsen: не має значення, чи OSвстановлено він у системах, що не належать до Windows. Зробіть ласощі таким же, як порожнє, що спричинить перехід до unameблоку, що базується. Вам просто потрібно додати чек FreeBSD.
Тревор Робінсон

3
це також ламається на osx. /bin/sh: -c: line 0: syntax error near unexpected token , Windows_NT '/ bin / sh: -c: рядок 0:ifeq (,Windows_NT)' make: *** [os] Error 2
k107

1
@kristi Це здається, що ви виконали це як команди оболонки, а не в контексті директив makefile.
фрад

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. Я щойно спробував цю конструкцію в Makefiles у Cygwin та OSX, і вона працювала як слід. Що спробувати: Введіть унімес у своєму командному рядку. Це скаже вам значення для цієї ОС. OSX, швидше за все, буде "Дарвіном".
dbrown0708

Проект GnuWin32 має як uname, так і Gnu надає доступ як як рідні програми для Windows, що робить цю техніку переносною для MingW в командному рядку, а також Cygwin у Windows.
RBerteig

Він виходить з ладу на моїй машині Solaris, коли він знаходиться всередині makefile. Команда uname доступна в цій системі.
самоз

4
Зауважте, що якщо ви помістите це всередині Maketarget, воно не повинно бути відступним.
nylund

4
Чи не синтаксис ": =" характерний для створення GNU?
Анкур Сеті

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. Дивіться його відповідь, яка виглядає так:

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-name) за замовчуванням. Подивіться, чому uname -sкраще, ніжuname -o .

  • Використання OS(замість uname) спрощує алгоритм ідентифікації. Ви все ще можете користуватися виключно uname, але вам доведеться мати справу з if/elseблоками, щоб перевірити всі варіанти MinGW, Cygwin тощо.

  • Змінна середовища OSзавжди встановлена ​​в "Windows_NT"різних версіях Windows (див. %OS%Змінну середовища у Вікіпедії ).

  • Альтернатива OS є змінна середовище MSVC(вона перевіряє наявність MS Visual Studio , див. Приклад за допомогою Visual C ++ ).


Нижче я наводимо повний приклад використання makeта gccстворення спільної бібліотеки: *.soабо *.dllзалежно від платформи. Приклад є максимально простим, щоб бути зрозумілішим.

Для встановлення makeта роботи gccв Windows див. Cygwin або MinGW .

Мій приклад ґрунтується на п'яти файлах

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

Нагадування: 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Команда однакова на обох платформах. Даний вихід є на 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'

Біг

Додаток повинен знати, де знаходиться спільна бібліотека.

У Windows просте рішення - скопіювати бібліотеку, де знаходиться додаток:

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

На ОС, схожих на Unix, ви можете використовувати LD_LIBRARY_PATHзмінну середовища:

> export LD_LIBRARY_PATH=lib

Запустіть команду в Windows:

> app/app.exe
hello

Виконайте команду на Unix-подібних ОС:

> app/app
hello

Я ціную ваші зусилля, але головне питання було виявити операційну систему. Ваш приклад виявляє лише Linux, інакше відверто припускає Windows.
Шахбаз

Привіт @Shahbaz. Ви маєте рацію, моя відповідь не дає іншого підходу, ніж інші відповіді. Більше того, мій сценарій передбачає, що платформа - це Windows, коли unameце не Linux. Я наводжу лише приклад, який вам може не знадобитися, але це може допомогти комусь, що шукає (в Інтернеті) спосіб реалізувати Makefileдля обох платформ ;-) Що мені змінити у своїй відповіді? Ура
олібре

спробуйте придумати способи правильного визначення інших операційних систем! Мета - знайти метод, який не надто складний, але важливіше - куленепробивність. Тобто, це б не помилилось, хоч би що.
Шахбаз

1
@olibre Дякую за детальний приклад, високо оцінений та допомагає мені швидко почати роботу. У lib/Makefileприкладі targetвикористовується .soпроти .dll. Паралельний приклад для цього app/makefileбуде корисним для empty stringпорівняння .exeпорівняння для імені файлу програми. Наприклад, я зазвичай не бачу app.exeна Unix-подібних ОС. ;-)

1
LSF? LFS? Друкарська помилка?
Франклін Ю

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, і це все, що мені потрібно, оскільки для нього не потрібно мати unameкоманду або пакет MSYS в Windows.

Підводячи підсумок, unameнаводиться система, для якої ви компілюєте, та gcc -dumpmachineдає вам систему, для якої ви компілюєте.


Це хороший момент. Однак, все одно не unameйде MinGW? Тим не менш, додаткова примітка щодо крос-компіляції є чудовою.
Шахбаз

2
Налаштування @Shahbaz MinGW може встановити MSYS (який містить уніме), але це опціонально. Ще можна знайти системи лише з інструментами MinGW gcc
phsym

1
Це не працює ніде Clang є компілятором за замовчуванням, як OS X і FreeBSD.
MarcusJ

@SebastianGodelet @MarcusJ Просте виправлення $(shell $(CC) -dumpmachine). Як і в OS X Sierra, команда -dumpmachine працює над Clang.
Vortico

В ОС X 10.12.5 це x86_64-apple-darwin16.6.0 і працює Wether вас називають його gcc, ccабо clang, але неcl
MarcusJ

17

Мерзотник Makefile містить численні приклади того , як обійтися без AUTOCONF / Automake, але по- , як і раніше працювати на безлічі платформ unixy.


13
Знаючи, що Git не використовує Autofools якось змушує мене відчувати себе виправданим у своїй відразі до них ...
Dan Molding

11
"Автофори"? Це була навмисна друкарська помилка? :)
JesperE

6
Це було. Але по-друге, я думаю, що мені ще більше подобаються "Автостоли". : D
Dan Molding

Btw, кого ти мав на увазі під "ними"? Люди Git чи Autotools? : D
JesperE

8
Англійська мова - така неточна мова. Як щодо цього: if (!usesAutotools(git)) aversionTo(autotools) = justified;я також уточню, що це лише інструменти, до яких я проти. Я впевнений, що люди Autotools - хороші люди.
Дан Ліплення

11

Оновлення: зараз я вважаю цю відповідь застарілою. Я розмістив нове ідеальне рішення далі вниз.

Якщо ваш файл файлів може працювати в Windows, який unameне використовується Cygwin, можливо, він недоступний. Це незручно, але це потенційне рішення. Ви повинні спершу перевірити Cygwin, щоб виключити це, оскільки він має WINDOWS і в PATHзмінній його середовища.

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

Це добре зараз! Чи можете ви мені сказати одне? Я не використовую Cygwin, але у мене встановлено MinGW з його бін-трактом у PATH. Якщо я випускаю unameз звичайного CMD-терміналу, він дає мені MINGW. Що я маю на увазі, це я все ще маю, unameне використовуючи Cygwin. У мене також є git bash, але я не намагався його зняти (зараз я в Linux). Чи можете ви сказати мені, як ці двоє можуть бути включені у ваш код?
Шахбаз

Якщо ви впевнені, що Uname доступний, це найкраще рішення. Але в моєму середовищі всі користуються Windows, і мало хто має встановити cygwin або mingw , тож я не маю гарантії, що будь-що навіть стандартне, як уніме, не спрацює. В даний час у мене виникають труднощі з вищезазначеним кодом, який працює make.exe в оболонці cmd. Windows - це дуже неприємна платформа для роботи.
Кен Джексон

Що я маю на увазі, перш ніж тестувати на наявність WINDOWS в PATH, ви переконайтеся, що не маєте справу з cygwin, як ви можете переконатися, що ви не маєте справу з MinGW? Наприклад, чи можливо в Makefile перевірити, чи можна запускати команду, і якщо unameне вдалося виконати, ми зрозуміли б, що ми в Windows?
Шахбаз

Я намагаюся знайти чітке рішення для цього Mingw / cygwin / shell-або-cmd / Linux. Зрештою, щось на кшталт premake або cmake здається найкращою ідеєю.
Ісаак Некіттепас

Це вже не найкраще рішення. Нове рішення, яке я розмістив, відрізняє рідну Windows, шукаючи ';' у змінній PATH, без виклику оболонки.
Кен Джексон

7

Це завдання, яке GNU automake / autoconf призначені для вирішення. Ви можете розглянути їх.

Крім того, ви можете встановити змінні середовища на різних своїх платформах і зробити так, щоб Makefile умовно застосовувався до них.


11
Я настійно не рекомендую використовувати автоматичне / автоконтф. Вони є стомлюючими у використанні, додають багато накладних витрат до ваших файлів, до вашого часу складання. Вони просто додають складності для зазвичай дуже малого ефекту (все ще немає портативності між системами).
Йоганнес Оверманн

1
Я просто витратив пару днів на навчання, makeщоб зробити те, що хочу. Чи хочу я зараз потрапити в автоматичне / автоконтф - НЕМАЄ. Що можна зробити в makefile, безумовно, слід зробити в makefile, хоча б так, щоб у мене не було декількох точок зупинки кожен раз, коли я хочу змінити компіляцію та посилання.
Інженер

Скільки платформ підтримують ваші файли? automake та autoconf дійсно приходять у свої сили, коли потрібно переносити на багатьох платформах.
Дуглас Лідер

2
Мені не потрібно буде марних залежностей, а я зміню всю свою систему побудови лише для того, щоб дізнатися, для якої ОС вона складається.
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, щоб розділити будь-які чутливі до ОС змінні та команди.

Ключовим моментом є те, що Windows використовує крапки з комою для розділення шляхів у змінній PATH, тоді як усі інші використовують двокрапки. (Можна створити каталог Linux з іменем ';' у своєму імені та додати його до PATH, що би це порушило, але хто б робив таке?) Це здається найменш ризикованим методом виявлення рідної Windows, оскільки це не потрібен виклик оболонки. У Cygwin і MSys використовувати PATH колони так uname викликається для них.

Зауважте, що змінна середовища ОС може використовуватися для виявлення Windows, але не для розрізнення Cygwin від рідної Windows. Тестування на лунання лапок працює, але це вимагає виклику оболонки.

На жаль, Cygwin додає деяку інформацію про версію до виводу uname , тому я додав виклики "patsubst", щоб змінити її на просто "Cygwin". Крім того, uname для MSYS насправді має три можливі виходи, починаючи з MSYS або MINGW, але я також використовую patsubst для перетворення всіх на просто MSYS.

Якщо важливо розрізнити рідні системи Windows з і без деякого uname.exe на шляху, цей рядок може використовуватися замість простого призначення:

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

Звичайно, у всіх випадках необхідне виготовлення GNU або іншого виготовлення, яке підтримує використовувані функції.


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)".
Чарек Томчак

OSX, ймовірно, не сумісний, тому спробуйте їх у порядку. (1) Переконайтеся, що ви використовуєте TAB в якості першого символу в рядку (2) Видаліть "- @" перед макетом (2a) Якщо 2 працювали, спробуйте один символ, а потім інший (3) Переконайтеся, що UNAME_S визначається, спробуйте відлуння $ (UNAME_S) замість - @ зробити $ (UNAME_S)
клубової

6

Ось просте рішення, яке перевіряє, чи перебуваєте ви в середовищі Windows або схожих на позиції (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прапор або вибрати між a .dllабо .so, це не вдасться.
yyny

1
@YoYoYonnY Дякую за уточнення. У своїй ситуації я дбав лише про те, якщо я знаходився в середовищі Cygwin або Windows чи Linux, а не в ОС, в якій я був, тож це було мені корисно. Звучить, що ваші потреби відрізняються від моїх.
Самуїл

3

Зауважте, що Makefiles надзвичайно чутливі до інтервалів. Ось приклад Makefile, який виконує додаткову команду в OS X і який працює в OS X та Linux. Однак у цілому, автоконфорування / автоматичне - це спосіб зробити що-небудь взагалі нетривіальним.

UNAME: = $ (оболонка не має)
CPP = g ++
CPPFLAGS = -pthread -ansi -Wall -Werror -pedantic -O0 -g3 -I / nexopia / включають
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

всі: вир

чисто:
    rm -f $ (ОБ'ЄКТИ) vor

vor: $ (ОБ'ЄКТИ)
    $ (CPP) $ (LDFLAGS) -o vor $ (ОБЕКТИ)
ifeq ($ (UNAME), Дарвін)
    # Встановіть розташування бібліотеки Boost
    install_name_tool -change libboost_system.dylib /nexopia/lib/libboost_system.dylib vor
закінчення

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

2

Ще один спосіб зробити це за допомогою скрипта "конфігурувати". Якщо ви вже використовуєте його для свого makefile, ви можете використовувати комбінацію уніме та sed, щоб налагодити щось. Спочатку у своєму сценарії виконайте:

UNAME=uname

Потім, щоб помістити це у свій Makefile, почніть з Makefile.in, який повинен мати щось на кшталт

UNAME=@@UNAME@@

в цьому.

Використовуйте таку команду sed у своєму сценарії налаштування після UNAME=unameбіту.

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

Тепер ваш makefile повинен був UNAMEвизначатись за бажанням. Якщо / elif / else заяви - це все, що залишилося!


Чи не повинно це бути першим рівним? UNAME = $ (uname)
Кен Джексон

0

У мене був випадок, коли мені довелося виявити різницю між двома версіями Fedora, щоб змінити параметри командного рядка для inkscape:
- у Fedora 31 типовий inkscape - 1,0beta, який використовує --export-file
- у Fedora <31, inkscape за замовчуванням - 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. Це, очевидно, можна змінити для інших ОС, залежно від того, як зберігаються метадані. Зауважте, що у Fedora не існує змінної середовища за замовчуванням, яка дає версію ОС, інакше я б це використав!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.