操作系统检测 makefile
我经常在几台不同的计算机和几个不同的操作系统上工作,其中包括 Mac OS X、Linux 或 Solaris。 对于我正在从事的项目,我从远程 git 存储库中提取代码。
我希望无论我在哪个航站楼都能完成我的项目。 到目前为止,我已经找到了通过每次切换计算机时更改 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
I routinely work on several different computers and several different operating systems, which are Mac OS X, Linux, or Solaris. For the project I'm working on, I pull my code from a remote git repository.
I like to be able to work on my projects regardless of which terminal I'm at. So far, I've found ways to get around the OS changes by changing the makefile every time I switch computers. However, this is tedious and causes a bunch of headaches.
How can I modify my makefile so that it detects which OS I'm using and modifies syntax accordingly?
Here is the 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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(14)
另一种方法是使用“配置”脚本。 如果您已经在 makefile 中使用了其中一个,则可以结合使用 uname 和 sed 来解决问题。 首先,在你的脚本中,执行以下操作:
然后,为了将其放入 Makefile 中,请从 Makefile.in 开始,其中应该包含类似的内容
。
在配置脚本中的
UNAME=uname
位后使用以下 sed 命令。现在您的 makefile 应该已根据需要定义了
UNAME
。 只剩下 if/elif/else 语句了!Another way to do this is by using a "configure" script. If you are already using one with your makefile, you can use a combination of uname and sed to get things to work out. First, in your script, do:
Then, in order to put this in your Makefile, start out with Makefile.in which should have something like
in it.
Use the following sed command in your configure script after the
UNAME=uname
bit.Now your makefile should have
UNAME
defined as desired. If/elif/else statements are all that's left!我遇到过这样的情况:我必须检测两个版本的 Fedora 之间的差异,以调整 inkscape 的命令行选项:
- 在 Fedora 31 中,默认的 inkscape 是 1.0beta,它使用
--export-file
- 在 Fedora 中 < 31,默认的 inkscape 是 0.92,它使用
--export-pdf
我的 Makefile 包含以下内容
这是有效的,因为
/etc/os-release
包含一行,因此 shell 命令在Makefile 返回字符串
VERSION_ID=
,然后 eval 命令对其进行操作以设置 Makefile 变量VERSION_ID
。这显然可以针对其他操作系统进行调整,具体取决于元数据的存储方式。 请注意,在 Fedora 中,没有提供操作系统版本的默认环境变量,否则我会使用它!
I had a case where I had to detect the difference between two versions of Fedora, to tweak the command-line options for inkscape:
- in Fedora 31, the default inkscape is 1.0beta which uses
--export-file
- in Fedora < 31, the default inkscape is 0.92 which uses
--export-pdf
My Makefile contains the following
This works because
/etc/os-release
contains a lineso the shell command in the Makefile returns the string
VERSION_ID=<value>
, then the eval command acts on this to set the Makefile variableVERSION_ID
.This can obviously be tweaked for other OS's depending how the metadata is stored. Note that in Fedora there is not a default environment variable that gives the OS version, otherwise I would have used that!
我还没有看到有人谈论的另一种方法是使用内置变量
SHELL
。 用作 shell 的程序取自变量SHELL
。 在 MS-Windows 系统上,它很可能是扩展名为.exe
的可执行文件(如sh.exe
)。在这种情况下,以下条件测试:
与使用环境变量 OS 具有相同的结果:
但是,后者似乎是最流行的解决方案,所以我建议您坚持使用它。
An alternate way that I have not seen anyone talking about is using the built-in variable
SHELL
. The program used as the shell is taken from the variableSHELL
. On MS-Windows systems, it is most likely to be an executable file with.exe
extension (likesh.exe
).In that case, the following conditional test:
Would have the same result as using the environment variable
OS
:However, it seems the latter is the most popular solution, so I would recommend you stick with it.
这里已经有很多好的答案,但我想分享一个更完整的示例,两者:
uname
此处定义的
CCFLAGS
不一定是推荐或理想的; 它们正是我添加操作系统/CPU 自动检测的项目碰巧正在使用的。There are many good answers here already, but I wanted to share a more complete example that both:
uname
exists on WindowsThe
CCFLAGS
defined here aren't necessarily recommended or ideal; they're just what the project to which I was adding OS/CPU auto-detection happened to be using.uname
命令 (http: //developer.apple.com/documentation/Darwin/Reference/ManPages/man1/uname.1.html)不带参数应该告诉您操作系统名称。 我会使用它,然后根据返回值制定条件。例子
The
uname
command (http://developer.apple.com/documentation/Darwin/Reference/ManPages/man1/uname.1.html) with no parameters should tell you the operating system name. I'd use that, then make conditionals based on the return value.Example
使用两个简单的技巧检测操作系统:
OS
uname
命令或者更安全的方法(如果不是在 Windows 上)和
uname
> 不可用:如果您想区分 Cygwin/MinGW/MSYS/Windows,Ken Jackson 提出了一个有趣的替代方案。 请参阅他的答案,如下所示:
然后您可以根据
Detected_OS
选择相关内容:注意:
命令
uname
与
uname -s
相同,因为选项-s
(< Strong>--kernel-name
)是默认值。 了解为什么uname -s
比uname - 更好o
。使用
OS
(而不是uname
)简化了识别算法。 您仍然可以单独使用uname
,但必须处理if/else
块来检查所有 MinGW、Cygwin 等变体。在不同的 Windows 版本上,环境变量
OS
始终设置为"Windows_NT"
(请参阅 维基百科上的%OS%
环境变量)。OS
的替代方案是环境变量MSVC
(它检查 MS Visual Studio 的存在,请参阅使用 Visual C++ 的示例)。下面我提供了一个使用
make
和gcc
构建共享库的完整示例:*.so
或*.dll
取决于平台。 该示例尽可能简单,以便更容易理解。要在 Windows 上安装
make
和gcc
,请参阅 Cygwin或 MinGW。我的示例基于五个文件
提醒:
Makefile
使用制表缩进。 复制粘贴以下示例文件时请小心。两个
Makefile
文件1.
lib/Makefile
2.
app/Makefile
至了解更多信息,请阅读自动变量文档< /a> 正如 cfi 所指出的。
源代码
-
lib/hello.h
-
lib/hello.c
-
app/main.c
构建
修复
Makefile
的复制粘贴问题(用一个表格替换前导空格)。两个平台上的
make
命令是相同的。 给定的输出是在类 Unix 操作系统上:运行
应用程序需要知道共享库在哪里。
在 Windows 上,一个简单的解决方案是复制应用程序所在的库:
在类 Unix 操作系统上,您可以使用 LD_LIBRARY_PATH 环境变量:
在 Windows 上运行命令:
在类 Unix 上运行命令操作系统:
Detect the operating system using two simple tricks:
OS
uname
commandOr a more safe way, if not on Windows and
uname
unavailable:Ken Jackson proposes an interesting alternative if you want to distinguish Cygwin/MinGW/MSYS/Windows. See his answer that looks like that:
Then you can select the relevant stuff depending on
detected_OS
:Notes:
Command
uname
is same asuname -s
because option-s
(--kernel-name
) is the default. See whyuname -s
is better thanuname -o
.The use of
OS
(instead ofuname
) simplifies the identification algorithm. You can still use solelyuname
, but you have to deal withif/else
blocks to check all MinGW, Cygwin, etc. variations.The environment variable
OS
is always set to"Windows_NT"
on different Windows versions (see%OS%
environment variable on Wikipedia).An alternative of
OS
is the environment variableMSVC
(it checks the presence of MS Visual Studio, see example using Visual C++).Below I provide a complete example using
make
andgcc
to build a shared library:*.so
or*.dll
depending on the platform. The example is as simplest as possible to be more understandable.To install
make
andgcc
on Windows see Cygwin or MinGW.My example is based on five files
Reminder:
Makefile
is indented using tabulation. Caution when copy-pasting below sample files.The two
Makefile
files1.
lib/Makefile
2.
app/Makefile
To learn more, read Automatic Variables documentation as pointed out by cfi.
The source code
-
lib/hello.h
-
lib/hello.c
-
app/main.c
The build
Fix the copy-paste of
Makefile
(replace leading spaces by one tabulation).The
make
command is the same on both platforms. The given output is on Unix-like OSes:The run
The application requires to know where is the shared library.
On Windows, a simple solution is to copy the library where the application is:
On Unix-like OSes, you can use the
LD_LIBRARY_PATH
environment variable:Run the command on Windows:
Run the command on Unix-like OSes:
我最近正在尝试回答这个我问自己的问题。 以下是我的结论:
由于在Windows中,您无法确定
uname
命令是否可用,因此可以使用gcc -dumpmachine
。 这将显示编译器目标。如果你想进行一些交叉编译,那么使用
uname
时也可能会出现问题。以下是
gcc -dumpmachine
可能输出的示例列表:您可以像这样检查 makefile 中的结果:
它对我来说效果很好,但我'我不确定这是获取系统类型的可靠方法。 至少它对 MinGW 是可靠的,这就是我所需要的,因为它不需要 Windows 中的
uname
命令或 MSYS 包。总而言之,
uname
为您提供了正在编译的系统,gcc -dumpmachine
为您提供了用于<的系统。 /strong> 您正在编译的内容。I was recently experimenting in order to answer this question I was asking myself. Here are my conclusions:
Since in Windows, you can't be sure that the
uname
command is available, you can usegcc -dumpmachine
. This will display the compiler target.There may be also a problem when using
uname
if you want to do some cross-compilation.Here's a example list of possible output of
gcc -dumpmachine
:You can check the result in the makefile like this:
It worked well for me, but I'm not sure it's a reliable way of getting the system type. At least it's reliable about MinGW and that's all I need since it does not require to have the
uname
command or MSYS package in Windows.To sum up,
uname
gives you the system on which you're compiling, andgcc -dumpmachine
gives you the system for which you are compiling.git makefile 包含有大量关于如何在没有 autoconf/automake 的情况下进行管理的示例,但仍然可以在多种 unix 平台上工作。
The git makefile contains numerous examples of how to manage without autoconf/automake, yet still work on a multitude of unixy platforms.
更新:我现在认为这个答案已经过时了。 我在下面发布了一个新的完美解决方案。
如果您的 makefile 可能在非 Cygwin Windows 上运行,则
uname
可能不可用。 这很尴尬,但这是一个潜在的解决方案。 您必须首先检查 Cygwin 来排除它,因为它的PATH
环境变量中也有 WINDOWS。Update: I now consider this answer to be obsolete. I posted a new perfect solution further down.
If your makefile may be running on non-Cygwin Windows,
uname
may not be available. That's awkward, but this is a potential solution. You have to check for Cygwin first to rule it out, because it has WINDOWS in itsPATH
environment variable too.这就是 GNU automake/autoconf 就是为了解决这个问题而设计的。 您可能想调查它们。
或者,您可以在不同的平台上设置环境变量,并使 Makefile 以它们为条件。
That's the job that GNU's automake/autoconf are designed to solve. You might want to investigate them.
Alternatively you can set environment variables on your different platforms and make you Makefile conditional against them.
我今天遇到了这个问题,我在 Solaris 上需要它,所以这里有一个 POSIX 标准方法来做到这一点(非常接近)。
I ran into this problem today and I needed it on Solaris so here is a POSIX standard way to do (something very close to) this.
这是一个简单的解决方案,用于检查您是否处于 Windows 或类 posix (Linux/Unix/Cygwin/Mac) 环境中:
它利用了 echo 存在于类 posix 环境和 Windows 环境中的事实,并且在 Windows 中shell 不过滤引号。
Here's a simple solution that checks if you are in a Windows or posix-like (Linux/Unix/Cygwin/Mac) environment:
It takes advantage of the fact that echo exists on both posix-like and Windows environments, and that in Windows the shell does not filter the quotes.
我终于找到了为我解决这个问题的完美解决方案。
UNAME 变量设置为 Linux、Cygwin、MSYS、Windows、FreeBSD、NetBSD(或者可能是 Solaris、Darwin、OpenBSD、AIX、HP-UX)或 Unknown。 然后可以在 Makefile 的其余部分中进行比较,以分离任何操作系统敏感的变量和命令。
关键是 Windows 使用分号来分隔 PATH 变量中的路径,而其他人都使用冒号。 (可以创建一个名称中带有“;”的 Linux 目录并将其添加到 PATH 中,这会破坏这一点,但是谁会做这样的事情呢?)这似乎是检测本机 Windows 风险最小的方法,因为它不需要 shell 调用。 Cygwin 和 MSYS PATH 使用冒号,因此为它们调用 uname。
请注意,OS 环境变量可用于检测 Windows,但不能用于区分 Cygwin 和本机 Windows。 测试引号的回显是有效的,但它需要 shell 调用。
不幸的是,Cygwin 在 uname 的输出中添加了一些版本信息,因此我添加了“patsubst”调用以将其更改为“Cygwin”。 另外,MSYS 的 uname 实际上具有以 MSYS 或 MINGW 开头的三种可能的输出,但我还使用 patsubst 将所有输出转换为“MSYS”。
如果区分路径上有或没有 uname.exe 的本机 Windows 系统很重要,则可以使用此行而不是简单的赋值:
当然在所有情况下都需要 GNU make,或者其他make 支持所使用的函数。
I finally found the perfect solution that solves this problem for me.
The UNAME variable is set to Linux, Cygwin, MSYS, Windows, FreeBSD, NetBSD (or presumably Solaris, Darwin, OpenBSD, AIX, HP-UX), or Unknown. It can then be compared throughout the remainder of the Makefile to separate any OS-sensitive variables and commands.
The key is that Windows uses semicolons to separate paths in the PATH variable whereas everyone else uses colons. (It's possible to make a Linux directory with a ';' in the name and add it to PATH, which would break this, but who would do such a thing?) This seems to be the least risky method to detect native Windows because it doesn't need a shell call. The Cygwin and MSYS PATH use colons so uname is called for them.
Note that the OS environment variable can be used to detect Windows, but not to distinguish between Cygwin and native Windows. Testing for the echoing of quotes works, but it requires a shell call.
Unfortunately, Cygwin adds some version information to the output of uname, so I added the 'patsubst' calls to change it to just 'Cygwin'. Also, uname for MSYS actually has three possible outputs starting with MSYS or MINGW, but I use also patsubst to transform all to just 'MSYS'.
If it's important to distinguish between native Windows systems with and without some uname.exe on the path, this line can be used instead of the simple assignment:
Of course in all cases GNU make is required, or another make which supports the functions used.
请注意,Makefile 对间距极其敏感。 下面是一个 Makefile 示例,它在 OS X 上运行额外的命令,并且适用于 OS X 和 Linux。 但总的来说,autoconf/automake 是解决任何问题的方法。
Note that Makefiles are extremely sensitive to spacing. Here's an example of a Makefile that runs an extra command on OS X and which works on OS X and Linux. Overall, though, autoconf/automake is the way to go for anything at all non-trivial.