操作系统检测 makefile

发布于 2024-07-16 06:45:54 字数 727 浏览 6 评论 0原文

我经常在几台不同的计算机和几个不同的操作系统上工作,其中包括 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(14

吃颗糖壮壮胆 2024-07-23 06:45:55

另一种方法是使用“配置”脚本。 如果您已经在 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 语句了!

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:

UNAME=uname

Then, in order to put this in your Makefile, start out with Makefile.in which should have something like

UNAME=@@UNAME@@

in it.

Use the following sed command in your configure script after the UNAME=uname bit.

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

Now your makefile should have UNAME defined as desired. If/elif/else statements are all that's left!

好倦 2024-07-23 06:45:55

我遇到过这样的情况:我必须检测两个版本的 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 
lt; --$(EXPORT)=$@

这是有效的,因为 /etc/os-release 包含一行,

VERSION_ID=<value>

因此 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

# 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 
lt; --$(EXPORT)=$@

This works because /etc/os-release contains a line

VERSION_ID=<value>

so the shell command in the Makefile returns the string VERSION_ID=<value>, then the eval command acts on this to set the Makefile variable VERSION_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!

烂柯人 2024-07-23 06:45:55

我还没有看到有人谈论的另一种方法是使用内置变量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

但是,后者似乎是最流行的解决方案,所以我建议您坚持使用它。

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 variable SHELL. On MS-Windows systems, it is most likely to be an executable file with .exe extension (like sh.exe).

In that case, the following conditional test:

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

Would have the same result as using the environment variable OS:

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

However, it seems the latter is the most popular solution, so I would recommend you stick with it.

纵性 2024-07-23 06:45:54

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

  • 不假设 Windows 上存在 uname
  • 也检测处理器

此处定义的 CCFLAGS不一定是推荐或理想的; 它们正是我添加操作系统/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

There are many good answers here already, but I wanted to share a more complete example that both:

  • doesn't assume uname exists on Windows
  • also detects the processor

The 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.

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
客…行舟 2024-07-23 06:45:54

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

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

UNAME := $(shell uname)

ifeq ($(UNAME), Linux)
# do something Linux-y
endif
ifeq ($(UNAME), Solaris)
# do something Solaris-y
endif
云朵有点甜 2024-07-23 06:45:54

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

  • 首先是环境变量 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

注意:

  • 命令unameuname -s 相同,因为选项 -s (< Strong>--kernel-name)是默认值。 了解为什么 uname -suname - 更好o

  • 使用OS(而不是uname)简化了识别算法。 您仍然可以单独使用 uname,但必须处理 if/else 块来检查所有 MinGW、Cygwin 等变体。

  • 在不同的 Windows 版本上,环境变量 OS 始终设置为 "Windows_NT"(请参阅 维基百科上的 %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 使用制表缩进。 复制粘贴以下示例文件时请小心。

两个 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 
lt;  -fPIC  -o $@
    # -c 
lt;  => 
lt; 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 
lt; -I ../lib  -o $@
    # -c 
lt;     => compile (-c) 
lt; (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"

至了解更多信息,请阅读自动变量文档< /a> 正如 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

Detect the operating system using two simple tricks:

  • First the environment variable OS
  • Then the uname command
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

Or a more safe way, if not on Windows and uname unavailable:

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

Ken Jackson proposes an interesting alternative if you want to distinguish Cygwin/MinGW/MSYS/Windows. See his answer that looks like that:

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

Then you can select the relevant stuff depending on 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

Notes:

  • Command uname is same as uname -s because option -s (--kernel-name) is the default. See why uname -s is better than uname -o.

  • The use of OS (instead of uname) simplifies the identification algorithm. You can still use solely uname, but you have to deal with if/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 variable MSVC (it checks the presence of MS Visual Studio, see example using Visual C++).


Below I provide a complete example using make and gcc 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 and gcc on Windows see Cygwin or MinGW.

My example is based on five files

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

Reminder: Makefile is indented using tabulation. Caution when copy-pasting below sample files.

The two Makefile files

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 
lt;  -fPIC  -o $@
    # -c 
lt;  => 
lt; 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 
lt; -I ../lib  -o $@
    # -c 
lt;     => compile (-c) 
lt; (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"

To learn more, read Automatic Variables documentation as pointed out by cfi.

The source code

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

The build

Fix the copy-paste of Makefile (replace leading spaces by one tabulation).

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

The make command is the same on both platforms. The given output is on Unix-like OSes:

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

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:

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

On Unix-like OSes, you can use the LD_LIBRARY_PATH environment variable:

> export LD_LIBRARY_PATH=lib

Run the command on Windows:

> app/app.exe
hello

Run the command on Unix-like OSes:

> app/app
hello
浮云落日 2024-07-23 06:45:54

我最近正在尝试回答这个我问自己的问题。 以下是我的结论:

由于在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 为您提供了用于<的系统。 /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 use gcc -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:

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

You can check the result in the makefile like this:

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

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, and gcc -dumpmachine gives you the system for which you are compiling.

青萝楚歌 2024-07-23 06:45:54

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.

去了角落 2024-07-23 06:45:54

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

如果您的 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

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 its PATH environment variable too.

ifneq (,$(findstring /cygdrive/,$(PATH)))
    UNAME := Cygwin
else
ifneq (,$(findstring WINDOWS,$(PATH)))
    UNAME := Windows
else
    UNAME := $(shell uname -s)
endif
endif
旧夏天 2024-07-23 06:45:54

这就是 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.

趁年轻赶紧闹 2024-07-23 06:45:54

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

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.

#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
孤独陪着我 2024-07-23 06:45:54

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

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

它利用了 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:

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

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.

街道布景 2024-07-23 06:45:54

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

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 风险最小的方法,因为它不需要 shell 调用。 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 支持所使用的函数。

I finally found the perfect solution that solves this problem for me.

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

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:

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

Of course in all cases GNU make is required, or another make which supports the functions used.

寄居人 2024-07-23 06:45:54

请注意,Makefile 对间距极其敏感。 下面是一个 Makefile 示例,它在 OS X 上运行额外的命令,并且适用于 OS X 和 Linux。 但总的来说,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 $

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.

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 $
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文