ChatGPT解决这个技术问题 Extra ChatGPT

操作系统检测生成文件

我经常在几台不同的计算机和几个不同的操作系统上工作,它们是 Mac OS X、Linux 或 Solaris。对于我正在处理的项目,我从远程 git 存储库中提取代码。

无论我在哪个终端,我都希望能够处理我的项目。到目前为止,我已经找到了通过在每次切换计算机时更改生成文件来绕过操作系统更改的方法。然而,这很乏味并且会引起很多头痛。

如何修改我的 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

A
Adam

这里已经有很多很好的答案,但我想分享一个更完整的例子:

不假定 Windows 上存在 uname

还检测处理器

此处定义的 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

遗憾的是,PROCESSOR_ARCHITECTURE envvar 似乎是虚拟化的,具体取决于进程是 32 位还是 64 位。因此,如果您的 make 是 32 位,并且您正在尝试构建 64 位应用程序,它将失败。将它与 PROCESSOR_ARCHITEW6432 结合使用对我有用(参见 thisthat
如果 make 团队添加几个带有 os 和 arch 的魔法变量会很好,可能太麻烦了。
@JanusTroelsen:在非 Windows 系统上是否设置 OS 无关紧要。将 unset 视为空,这将导致跳转到基于 uname 的块。你只需要在那里添加一个 FreeBSD 检查。
这也打破了osx。 /bin/sh: -c: line 0: syntax error near unexpected token ,Windows_NT' /bin/sh: -c: 第 0 行:ifeq (,Windows_NT)' make: *** [os] Error 2
ifelseendif 不得缩进(在我的实验中)。我也只能在目标块的外部工作
d
dbrown0708

不带参数的 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。这将告诉您该操作系统的价值。 OSX 很可能是“达尔文”。
GnuWin32 项目将 uname 和 Gnu 都作为本地 Windows 应用程序提供,这使得该技术可以在命令提示符下移植到 MingW 以及 Windows 上的 Cygwin。
当它在 makefile 中时,它在我的 Solaris 机器上失败。 uname 命令在该系统上可用。
请注意,如果您将其放在 Maketarget 中,则不得缩进。
":=" 语法不是 GNU Make 特有的吗?
o
oHo

使用两个简单的技巧检测操作系统:

首先是环境变量 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 提出了一个有趣的替代方案。请参阅看起来像这样的 his answer

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 等变体。

在不同的 Windows 版本上,环境变量 OS 始终设置为“Windows_NT”(参见 Wikipedia 上的 %OS% 环境变量)。

OS 的替代方案是环境变量 MSVC(它检查 MS Visual Studio 的存在,参见使用 Visual C++ 的示例)。

下面我提供了一个使用 makegcc 构建共享库的完整示例:*.so*.dll,具体取决于平台。该示例尽可能简单以便更易于理解。

要在 Windows 上安装 makegcc,请参阅 CygwinMinGW

我的示例基于五个文件

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

提醒: Makefile 使用 tabulation 缩进。复制粘贴下面的示例文件时要小心。

两个 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.应用程序/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 指出的 Automatic Variables documentation

源代码

lib/hello.h

#ifndef HELLO_H_
#define HELLO_H_

const char* hello();

#endif

- lib/hello.c

#include "hello.h"

const char* hello()
{
    return "hello";
}

- 应用程序/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。你是对的,我的回答并没有给出与其他答案不同的方法。此外,当 uname 不是 Linux 时,我的脚本假定平台是 Windows。我只是举了一个你可能不需要的例子,但这可能有助于某人(在网络上)搜索一种为两个平台实现 Makefile 的方法 ;-) 我应该在我的答案中改变什么?干杯
尝试想出正确识别其他操作系统的方法!目标是找到一种不太复杂,但更重要的是防弹的方法。也就是说,无论如何它都不会出错。
@olibre 感谢您提供详细的示例,非常感谢并帮助我快速入门。在 lib/Makefile 示例中,target 用于 .so.dllapp/makefile 的并行示例对于应用程序文件名的 empty string.exe 比较很有用。例如,我通常不会在类 Unix 操作系统上看到 app.exe。 ;-)
LSF? LFS?错字?
P
Peter Mortensen

我最近在做实验,以回答我问自己的这个问题。以下是我的结论:

由于在 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 为您提供了您正在编译的系统 on,而 gcc -dumpmachine 为您提供了您正在编译的系统 for


这是个好的观点。但是,uname 不是随 MinGW 一起出现的吗?不过,关于交叉编译的额外说明很棒。
@Shahbaz MinGW 安装程序可以安装 MSYS(其中包含 uname),但它是可选的。仍然可以找到仅使用 MinGW gcc 工具的系统
这在 Clang 是默认编译器的任何地方都不起作用,例如 OS X 和 FreeBSD。
@SebastianGodelet @MarcusJ 一个简单的解决方法是 $(shell $(CC) -dumpmachine)。从 OS X Sierra 开始,-dumpmachine 命令适用于 Clang。
在 OS X 10.12.5 上,它是 x86_64-apple-darwin16.6.0,无论您称它为 gcccc 还是 clang,它都有效,但不是 cl
J
JesperE

git makefile 包含许多示例,说明如何在不使用 autoconf/automake 的情况下进行管理,但仍可在众多 unixy 平台上工作。


知道 Git 不使用 Autofools 不知何故让我觉得厌恶它们是有道理的......
“自动傻瓜”?那是故意的错字吗? :)
它是。但转念一想,我觉得我更喜欢“Autostools”。 :D
顺便说一句,你说的“他们”是谁? Git 或 Autotools 的人? :D
英语就是这样一种不精确的语言。这个怎么样:if (!usesAutotools(git)) aversionTo(autotools) = justified;我还要澄清一下,这只是我不喜欢的工具。我敢肯定 Autotools 的人都是好人。
K
Ken Jackson

更新:我现在认为这个答案已经过时了。我在下面发布了一个新的完美解决方案。

如果您的 makefile 可能在非 Cygwin Windows 上运行,则 uname 可能不可用。这很尴尬,但这是一个潜在的解决方案。您必须首先检查 Cygwin 以排除它,因为它的 PATH 环境变量中也有 WINDOWS。

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

这很好到现在!不过,你能告诉我一件事吗?我不使用 Cygwin,但我在 PATH 中安装了 MinGW,它的 bin 路径。如果我从普通的 cmd 终端发出 uname,它会给我 MINGW。我的意思是,我仍然有 uname 而不使用 Cygwin。我也有 git bash,但我没有尝试过 uname(现在我在 Linux 中)。您能告诉我如何将这两者合并到您的代码中吗?
如果您确定 uname 可用,那是最好的解决方案。但是在我的环境中,每个人都在使用 Windows,很少有人安装 cygwinmingw,所以我不能保证任何像 uname 一样标准的东西都能正常工作。我目前在 cmd shell 中运行 make.exe 时遇到了一些困难。 Windows 是一个非常令人沮丧的平台。
我的意思是,在测试 PATH 中是否存在 WINDOWS 之前,请确保您没有与 cygwin 打交道,如何确保您没有与 MinGW 打交道?例如,是否可以在 Makefile 中测试命令是否可以运行,如果 uname 无法运行,我们会理解我们在 Windows 中吗?
我也在努力为这个 Mingw/cygwin/shell-or-cmd/Linux 找到一个干净的解决方案。归根结底,像 premake 或 cmake 这样的东西似乎是最好的主意。
这不再是最好的解决方案。我发布的新解决方案通过查找“;”来区分原生 Windows在 PATH 变量中,没有 shell 调用。
D
Douglas Leeder

这就是 GNU 的 automake/autoconf 旨在解决的工作。你可能想调查他们。

或者,您可以在不同平台上设置环境变量,并使 Makefile 以它们为条件。


我强烈建议不要使用 automake/autoconf。它们使用起来很乏味,给您的文件和构建时间增加了很多开销。它们只是增加了复杂性,通常影响很小(系统之间仍然没有可移植性)。
我只是花了几天时间学习让 make 做我想做的事。我现在也想进入 automake/autoconf 吗? - 不。 可以在 makefile 中完成,当然应该在 makefile 中完成,只要这样我每次想修改 compile & 时就没有几个停止点。关联。
您的 makefile 支持多少个平台?当您想要移植到许多平台时,automake 和 autoconf 真正发挥了作用。
我不会需要无用的依赖项,而是更改我的整个构建系统只是为了找出它正在编译的操作系统。
H
Huckle

我今天遇到了这个问题,我在 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

在 OSX 上出现错误:“Makefile:22: *** 缺少分隔符。停止。”。在这一行:“-@make $(UNAME_S)”。
OSX 可能不兼容,因此请按顺序尝试这些。 (1) 确保您使用 TAB 作为该行的第一个字符 (2) 删除 make 前面的“-@” (2a) 如果 2 有效,请先尝试一个字符,然后再尝试另一个 (3) 确保UNAME_S 已定义,尝试 echo $(UNAME_S) 而不是 -@make $(UNAME_S)
K
Ken Jackson

我终于找到了为我解决这个问题的完美解决方案。

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)或未知。然后可以在 Makefile 的其余部分进行比较,以分离任何操作系统敏感的变量和命令。

关键是 Windows 使用分号来分隔 PATH 变量中的路径,而其他所有人都使用冒号。 (可以在名称中创建一个带有 ';' 的 Linux 目录并将其添加到 PATH 中,这会破坏这一点,但谁会这样做呢?)这似乎是检测本机 Windows 风险最小的方法,因为它不需要外壳调用。 Cygwin 和 MSYS PATH 使用冒号,因此为它们调用 uname。

请注意,OS 环境变量可用于检测 Windows,但不能用于区分 Cygwin 和原生 Windows。测试引号的回声是可行的,但它需要一个 shell 调用。

不幸的是,Cygwin 在 uname 的输出中添加了一些版本信息,所以我添加了“patsubst”调用以将其更改为“Cygwin”。此外,MSYS 的 uname 实际上有三个可能的输出,以 MSYS 或 MINGW 开头,但我也使用 patsubst 将所有输出转换为“MSYS”。

如果区分路径上带有和不带有 uname.exe 的本地 Windows 系统很重要,则可以使用这一行来代替简单的赋值:

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

当然,在所有情况下都需要 GNU make,或者另一个支持所使用功能的 make。


S
Samuel

这是一个简单的解决方案,用于检查您是否处于 Windows 或类似 posix 的 (Linux/Unix/Cygwin/Mac) 环境中:

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

它利用了 echo 在类 posix 和 Windows 环境中都存在的事实,并且在 Windows 中,shell 不会过滤引号。


非常不安全,因为 $PATH 可能引用另一个 echo(我的确实...)
@YoYoYonnY 为什么你的路径引用另一个回声?似乎是一个非常不可能的情况。
不是真的,git 做到了,mingw 做到了,cygwin 做到了......我个人将 C:\Windows\System32 放在我路径的底部。
这种“解决方案”“适用于”所有环境,但我的观点是,这绝对不能安全地检测到窗口。如果我想设置一个 -mwindows 标志或在 .dll.so 之间进行选择,这将失败。
@YoYoYonnY 感谢您的澄清。在我的情况下,我只关心我是否在 Cygwin 或 Windows 或 Linux 环境中,而不是我所在的操作系统,所以这对我很有帮助。听起来您的需求与我的需求不同。
P
Peter Mortensen

请注意,Makefile 对间距非常敏感。这是一个在 OS X 上运行额外命令并在 OS X 和 Linux 上运行的 Makefile 示例。不过,总的来说,autoconf/automake 是解决任何不平凡的事情的方法。

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 $

d
dandan78

另一种方法是使用“配置”脚本。如果您已经在 makefile 中使用了一个,则可以结合使用 uname 和 sed 来解决问题。首先,在您的脚本中,执行以下操作:

UNAME=uname

然后,为了把它放在你的 Makefile 中,从 Makefile.in 开始,它应该有类似的东西

UNAME=@@UNAME@@

在里面。

UNAME=uname 位之后的配置脚本中使用以下 sed 命令。

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

现在您的 makefile 应该已根据需要定义了 UNAME。剩下的就是 if/elif/else 语句!


P
Patrick B Warren

我有一个案例,我必须检测两个版本的 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 中的 shell 命令返回字符串 VERSION_ID=<value>,然后 eval 命令对此进行操作以设置 Makefile 变量 VERSION_ID。这显然可以针对其他操作系统进行调整,具体取决于元数据的存储方式。请注意,在 Fedora 中没有提供操作系统版本的默认环境变量,否则我会使用它!


L
LucasJ

我还没有看到任何人谈论的另一种方法是使用内置变量 SHELL。用作 shell 的程序取自变量 SHELL。在 MS-Windows 系统上,它很可能是带有 .exe 扩展名的可执行文件(如 sh.exe)。

在这种情况下,以下条件测试:

ifeq ($(suffix $(SHELL)),.exe)
    # Windows system
else
    # Non-Windows system
endif

与使用环境变量 OS 的结果相同:

ifeq ($(OS),Windows_NT)
    # Windows system
else
    # Non-Windows system
endif

然而,后者似乎是最受欢迎的解决方案,所以我建议你坚持下去。