对 make (Linux) 和 nmake (Windows) 使用相同的 makefile

发布于 2024-12-18 07:09:42 字数 510 浏览 2 评论 0原文

我有一个简单的 C 程序(一个源文件),我想分别通过 make 和 nmake 在 Linux 和 Windows 上编译它。是否有可能使用单个 makefile 来完成此任务?

我想到了类似的事情,

ifeq($(MAKE), nmake)
    // nmake code here
else
    // make code here
endif

不幸的是 nmake 似乎不理解 ifeq,所以我不能使用它。我有一个可用的 makefile,但这会产生非常丑陋的结果:

hello: hello.c
    $(CC) hello.c

这在两个系统上都有效。问题是结果取决于各个编译器的默认行为。在 Linux 下,我得到一个名为“a.out”而不是“hello”的可执行文件。在 Windows 下,我得到“hello.exe”,但也有我不想拥有的“hello.obj”。

还有其他方法吗?或者我正在尝试的事情是绝对不可能的?

I have a simple C program (one source file) which I want to compile on Linux and on Windows via make and nmake, respectively. Is there a possibility to accomplish this with a single makefile?

I thought about something like

ifeq($(MAKE), nmake)
    // nmake code here
else
    // make code here
endif

Unfortunately nmake seems not to understand ifeq, so I cannot use that. I have a working makefile, but that produces very ugly results:

hello: hello.c
    $(CC) hello.c

That works on both systems. The problem is that the outcome depends on the default behaviors of the respective compilers. Under Linux I get an executeable named 'a.out' rather than 'hello'. Under Windows I get 'hello.exe' but there is also 'hello.obj' which I do not want to have.

Is there an alternative way? Or is what I'm trying absolutely impossible?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(10

一念一轮回 2024-12-25 07:09:42

这可能并非不可能,但很可能太难了,无论如何编写两个 makefile 会更容易。

GNU make(在 Linux 中使用)和 nmake 都有 include 指令,因此一些常见的东西可以放在主 makefile 包含的公共 makefile 中。

It's probably not impossible, but most likely so hard that it would be easier to write two makefiles anyway.

Both GNU make (used in Linux) and nmake have include directives though, so some common things can be put in a common makefile that is included by the main makefile.

余生共白头 2024-12-25 07:09:42

您应该考虑使用 CMake 来实现此目的。有了一个源文件,这应该是很容易的。以下是如何设置一个简单的项目:

cmake_minimum_required(VERSION 3.10)

# set the project name
project(Hello)

# add the executable
add_executable(Hello hello.c)

要构建这个简单的项目,您将执行以下操作(假设您的源文件和 CMakeLists.txt 文件与源文件 hello.c

mkdir build
cd build
cmake ..
cmake --build .

You should look at using CMake for this. With one source file, it should be quite easy. Here is how you could set up a simple project:

cmake_minimum_required(VERSION 3.10)

# set the project name
project(Hello)

# add the executable
add_executable(Hello hello.c)

To build the simple project, you would do the following (this assumes your source and CMakeLists.txt files are in the same directory as the source file hello.c:

mkdir build
cd build
cmake ..
cmake --build .
肥爪爪 2024-12-25 07:09:42

我想使用 Make 和 NMAKE 使用的相同 makefile include。由于 make 可以识别注释行上的行继续,但 NMAKE 不能,这意味着我们可以为 Make 和 NMAKE 提供单独的指令。例如:

# NMAKE code here \
!ifndef 0 # \    
MV=move # \
RM=del # \
CP=copy # \
!else
# Make code here
MV=mv -f
RM=rm -f
CP=cp -f
# \
!endif

您只需确保 NMAKE 特定的代码包含在 # \ 中。

I wanted to use the same makefile include to be used by Make and NMAKE. Since make recognises line continuation on comment lines, but NMAKE doesn't, this means that we can have separate instructions for Make and NMAKE. For example:

# NMAKE code here \
!ifndef 0 # \    
MV=move # \
RM=del # \
CP=copy # \
!else
# Make code here
MV=mv -f
RM=rm -f
CP=cp -f
# \
!endif

You just have to make sure that NMAKE-specific code is encompassed by # \.

要走干脆点 2024-12-25 07:09:42

我无法找到一种方法来使用通用的 makefile 同时适用于 GNU Make 和 Microsoft NMAKE,主要是因为它们的“include”和/或“if”指令的语法不兼容。需要使用Microsoft NMAKE!指令的前缀。例如,!if、!include 等...

但是,如果允许有单独的宏,则可能会被欺骗。在这里,我通过观察以下内容介绍了迄今为止我发现的使 makefile 兼容 GNU Make 和 Microsoft NMAKE 的最佳方法:

  1. Microsoft NMAKE 读取 TOOLS.ini 文件中的默认宏。
  2. Microsoft 套件使用 .obj 作为目标文件扩展名。
  3. GNU Make 读取 MAKEFILES 环境变量中定义的文件。
  4. GNU 套件使用 .o 作为目标文件扩展名。
  5. GNU make 不需要为目标提供可执行扩展名 .exe。

注意:以下内容已使用 Microsoft Visual Studio 2015 和 MINGW32 进行了测试。

步骤1:创建以下DOS批处理文件,并让它在调用CMD提示符时运行。

set MAKEFILES=TOOLS.gcc
call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"

步骤 2:在您的工作目录下创建一个 TOOLS.ini 文件,如下所示:(该文件与您的项目依赖项无关,可能除了库)

[NMAKE]
LDLIBS  =
CDEBUG  = /Zi
LDEBUG  = /debug:full
WDFLAGS = /wd4996 /wd4774 /wd4018 /wd4710 /wd4820
CFLAGS  = /nologo $(CDEBUG) /EHsc /Wall $(WDFLAGS)
LDFLAGS = /nologo $(LDEBUG)
RM      = del /F /Q
LINK     = "$(VCINSTALLDIR)bin\link" $(LDFLAGS)
CP    = copy
CC    = cl
CPP = $(CC) /P
X    = .exe
O    = .obj

.obj.exe:
    $(LINK) $** $(LOADLIBES) $(LDLIBS) /Out:$@

步骤 3:在您的工作目录下创建一个 TOOLS.gcc,如下所示:(该文件是独立的项目依赖项(可能除了库)

LD_LIBS =
LDLIBS  =
CDEBUG  = -g
LDEBUG  = -g
CFLAGS  = $(CDEBUG)
LDFLAGS = $(LDEBUG)
RM      = rm -f
LINK     = gcc $(LDFLAGS)
CP        = cp
CC        = gcc
CPP     = $(CC) -E
X        =
O        = .o

%: %.o
    $(LINK) $^ $(LOADLIBES) $(LDLIBS) -o $@

步骤 4:如下编辑 makefile(注意 $(X) 和 $(O)),其中仅指定依赖项。

SHELL    = /usr/bin/sh
app: app1$(X) app2$(X)
app1$(X): app1$(O)
app2$(X): app2$(O)

clean:
    $(RM) *.exe *.o *.obj *.ilk *.pdb *.tmp *.i *~

第 5 步:使用相同的 makefile 享受 GNU Make 和 Microsoft NMAKE

$ nmake
$ make clean
$ nmake clean
$ make

I am not able to find a way to use a common makefile to work for both GNU Make and Microsoft NMAKE, mainly because they have an incompatible syntax for "include" and/or "if" directives. Microsoft NMAKE requires to use ! prefix for directives. For example, !if, !include, etc...

If it is allowed to have separate macros, however, it could be tricked around. Here I presents the best way I found so far for making a makefile compatible for both GNU Make and Microsoft NMAKE by observing the followings:

  1. Microsoft NMAKE reads TOOLS.ini file for default macros.
  2. The Microsoft suite uses .obj as the object file extension.
  3. GNU Make reads files defined in a MAKEFILES environment variable.
  4. The GNU suite use .o as the object file extension.
  5. GNU make need not give an executable extension .exe for a target.

Note: The following has been tested using Microsoft Visual Studio 2015 and MINGW32.

Step 1: create a following DOS batch file and let it run whenever the CMD prompt is invoked.

set MAKEFILES=TOOLS.gcc
call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"

Step 2: Create a TOOLS.ini file under your working directory as below: (this file is independent of your project dependencies except the libraries possibly)

[NMAKE]
LDLIBS  =
CDEBUG  = /Zi
LDEBUG  = /debug:full
WDFLAGS = /wd4996 /wd4774 /wd4018 /wd4710 /wd4820
CFLAGS  = /nologo $(CDEBUG) /EHsc /Wall $(WDFLAGS)
LDFLAGS = /nologo $(LDEBUG)
RM      = del /F /Q
LINK     = "$(VCINSTALLDIR)bin\link" $(LDFLAGS)
CP    = copy
CC    = cl
CPP = $(CC) /P
X    = .exe
O    = .obj

.obj.exe:
    $(LINK) $** $(LOADLIBES) $(LDLIBS) /Out:$@

Step 3: Create a TOOLS.gcc under your working directory as below: (this file is independent of your project dependencies except the libraries possibly)

LD_LIBS =
LDLIBS  =
CDEBUG  = -g
LDEBUG  = -g
CFLAGS  = $(CDEBUG)
LDFLAGS = $(LDEBUG)
RM      = rm -f
LINK     = gcc $(LDFLAGS)
CP        = cp
CC        = gcc
CPP     = $(CC) -E
X        =
O        = .o

%: %.o
    $(LINK) $^ $(LOADLIBES) $(LDLIBS) -o $@

Step 4: Edit your makefile as below (note $(X) and $(O)) where only dependencies are specified.

SHELL    = /usr/bin/sh
app: app1$(X) app2$(X)
app1$(X): app1$(O)
app2$(X): app2$(O)

clean:
    $(RM) *.exe *.o *.obj *.ilk *.pdb *.tmp *.i *~

Step 5: Enjoy GNU Make and Microsoft NMAKE with the same makefile

$ nmake
$ make clean
$ nmake clean
$ make
少年亿悲伤 2024-12-25 07:09:42

我的解决方案是使用两个不同的文件名。 (因为不同操作系统中Makefile名称搜索优先级不会相同)

对于Windows,我使用普通的“Makefile”。

对于Linux,我根据这篇文章使用特殊的“GNUmakefile”< /a>.

这样 nmake (Win) 将找到“Makefile”,而 make (Linux) 将找到“GNUmakefile”。

My solution is to use two different filenames. (since the Makefile name searching priority in different OSes will not be the same)

For Windows, I use normal "Makefile."

For Linux, I use the special "GNUmakefile" according to this article.

So that nmake (Win) will find "Makefile," and make (Linux) will find "GNUmakefile."

橙幽之幻 2024-12-25 07:09:42

解决方案: https://github.com/jaykrell/w3/blob/master/Makefile< /a>

# This one Makefile works with Microsoft nmake and GNU make.
# They use different conditional syntax, but each can be
# nested and inverted within the other.

all: default

ifdef MAKEDIR: # gmake: false; nmake: unused target
!ifdef MAKEDIR # gmake: not seen; nmake: true

#
# Microsoft nmake.
#

!else # and now the other
else

#
# GNU (Posix?) make.
#

endif    # gmake: close condition; nmake: not seen
!endif : # gmake: unused target; nmake close conditional

default: # default target for both

Solution: https://github.com/jaykrell/w3/blob/master/Makefile

# This one Makefile works with Microsoft nmake and GNU make.
# They use different conditional syntax, but each can be
# nested and inverted within the other.

all: default

ifdef MAKEDIR: # gmake: false; nmake: unused target
!ifdef MAKEDIR # gmake: not seen; nmake: true

#
# Microsoft nmake.
#

!else # and now the other
else

#
# GNU (Posix?) make.
#

endif    # gmake: close condition; nmake: not seen
!endif : # gmake: unused target; nmake close conditional

default: # default target for both
猫七 2024-12-25 07:09:42

是的,您可以使用单个 Makefile 来完成此操作。此材料的最佳来源是 O'Reilly 的书:

使用 GNU Make 管理项目,第三版,作者:Robert Mecklenburg

请参阅第 7 章:可移植 Makefile。

总之,该技术是测试环境变量 ComSpec,它表示 Windows 命令解释器是否存在:

ifdef COMSPEC
  MV ?= move
  RM ?= del
else
  MV ?= mv -f
  RM ?= rm -f
endif

我用一个便携式 shell 脚本包装它,该脚本使用 sed 编辑 Nmake 或 GNU make 的 makefile...

Yes, you can do this with a single Makefile. The best source for this material is the O'Reilly book:

Managing Projects with GNU Make, Third Edition By Robert Mecklenburg

See chapter 7: Portable Makefiles.

In summary, the technique is to test the environment variable ComSpec which says if the Windows command interpreter is present:

ifdef COMSPEC
  MV ?= move
  RM ?= del
else
  MV ?= mv -f
  RM ?= rm -f
endif

I wrap this with a portable shell script which uses sed to edit the makefile for Nmake or GNU make...

会发光的星星闪亮亮i 2024-12-25 07:09:42

我只是想到了一些完全不同的东西。

如果你坚持使用极其简单的 Makefile,你说它可以工作,并且只是将“标准”变量 CC 和 CFLAGS

  export CC=gcc

分别

  set CC=CL.EXE

放入你各自的环境中,那么

  export CFLAGS=-o myexecutable

  set CFLAGS=/out:myexecutable.exe

它可能会工作

请注意,我对使用的确切选项并不坚定,您必须自己弄清楚。但据我所知,两者都使变体识别同一组标志。您甚至可以在相应的命令行上设置它们(但不能在 makefile 中设置,因为 NMAKE 使用不同的“ifeq”语法...)

I just thought of something completely different.

If you stick to your extremely simple Makefile, which, you say, works, and just put the 'standard' variables CC and CFLAGS in your respective environments, say

  export CC=gcc

respectively

  set CC=CL.EXE

and

  export CFLAGS=-o myexecutable

respectively

  set CFLAGS=/out:myexecutable.exe

it might just work.

Be aware, I'm not firm in the exact options to use, you'll have to figure them out yourself. But AFAIK both make variants recognize the same set of flags. You may even set those on the respective command lines (but not in the makefile, since NMAKE uses a different 'ifeq' syntax...)

笔芯 2024-12-25 07:09:42

我最近尝试使用 C 预处理器从包含预处理器符号的模板 Makefile.cc 生成可移植的 Makefile。到目前为止,它的效果出奇的好。第一个观察结果是,NMAKE 将预扫描一个 Tools.ini 文件,该文件位于与 Then 相同的目录中,

[NMAKE]
MAKECONFIG=-D_NMAKE

旁边有一个“真正的”Makefile,该文件仅以 GNU Make 和 NMAKE 的公共子语言编写。

MAKEFILE=Makefile.mk
TEMPLATE=Makefile.cc

all: $(MAKEFILE)
    $(MAKE) -f $(MAKEFILE)

clean: $(MAKEFILE)
    $(MAKE) -f $(MAKEFILE) clean

$(MAKEFILE): $(TEMPLATE)
    $(CXX) $(MAKECONFIG) -E $(TEMPLATE) > $(MAKEFILE)

请注意,-E 开关对于编译器(至少是我使用的三大编译器:GCC、Clang 和 CL)来说非常常见,仅用于预处理文件。在 GNU Make 中,$(MAKECONFIG) 扩展为空,但在 NMAKE 中,它提供了声明自身的预处理器变量。由于您的模板 Makefile.cc 可以使用 #ifdef 检查它,以及检查编译器声明自身的公共变量,因此您可以为“make”程序、您的操作系统和您正在使用的编译器。

如果你有任何“make”,你可能也已经有了一个 C 编译器;无需安装额外的软件,如 CMake 或 autotools。它使用旧的机制,因此可能在很多环境中工作。据我目前所知,速度真的很快。至少比在自动工具中运行配置步骤更快。我遇到的唯一缺点是它限制了 Make 规则的样式位于同一行,因为预处理器会更改代码的缩进。此外,预处理器会输出带有 # 标记的行,但由于这些行在 Makefile 中开始注释,因此它们无论如何都会被忽略。

A 有一个较小的 C++ 项目,其中包含 Makefile.cc,如下所示。它可以使用 GCC、Clang 或 CL 在 GNU Make 或 NMAKE 上以及 Windows 或 POSIX 环境中进行编译。不过,我还没有支持 BSD Make 或测试任何其他编译器。

// Make Version

#ifdef _NMAKE
# define ifdef !ifdef
# define ifndef !ifndef
# define else !else
# define endif !endif
# define err(x) !error x
# define cat(x, y) x=$(x) y
#else // GNU Make
# define err(x) $(error x)
# define cat(x, y) x += y
#endif

// System Commands

ifdef SHELL
RM=rm -f
else
ifdef COMSPEC
RM=del /f
else
err("Cannot determine your system commands.")
endif // COMSPEC
endif // SHELL

// Project Variables

STD=c++17
SRC=test.cpp dbg.cpp dir.cpp dll.cpp env.cpp err.cpp fifo.cpp file.cpp shm.cpp sig.cpp socket.cpp sys.cpp xdg.cpp
BIN=test

.SUFFIXES: .cpp .hpp .o .d .obj .pdb .lib .exp .ilk .log .i .db

// Operating system

#ifdef _WIN32
cat(CFLAGS, -D_WIN32)
EXE=$(BIN).exe
#else
cat(CFLAGS, -D_POSIX_C_SOURCE)
cat(LDFLAGS, -ldl -lrt -lpthread)
EXE=$(BIN)
#endif

// Make Targets

all: $(EXE)

clean: ; $(RM) $(EXE) *.o *.d *.obj *.pdb *.lib *.exp *.ilk *.log *.i

// Compiler Options

#ifdef _MSC_VER

cat(CFLAGS, -nologo -std:$(STD) -W4 -DNOMINMAX -D_CRT_SECURE_NO_WARNINGS -EHsc -permissive-)
ifndef NDEBUG
cat(CFLAGS, -Zi)
endif
cat(LDFLAGS, -nologo)

OBJ=$(SRC:.cpp=.obj)

$(EXE): $(OBJ); $(CXX) $(LDFLAGS) $(OBJ) -Fe$@
.cpp.obj: ; $(CXX) $(CFLAGS) -c 
lt;

#elif defined(__GNUC__) || defined(__llvm__) || defined(__clang__)

cat(CFLAGS, -std=$(STD) -Wall -Wextra -Wpedantic -MP -MMD)
ifndef NDEBUG
cat(CFALGS, -g)
endif
cat(LDFLAGS, -rdynamic)

OBJ=$(SRC:.cpp=.o)

$(EXE): $(OBJ); $(CXX) $(LDFLAGS) $(OBJ) -o $@
.cpp.o: ; $(CXX) $(CFLAGS) -c 
lt;

# ifndef _NMAKE
-include $(SRC:.cpp=.d)
# endif
#else
# error "Cannot determine your compiler."
#endif

I've recently experimented with using the C preprocessor to generate a portable Makefile from a template Makefile.cc containing preprocessor symbols. So far it's worked surprisingly well. The first observation is that NMAKE will prescan a Tools.ini file, which I provide in the same directory as

[NMAKE]
MAKECONFIG=-D_NMAKE

Then I have a 'true' Makefile next to it which is written in only the common sub language of GNU Make and NMAKE.

MAKEFILE=Makefile.mk
TEMPLATE=Makefile.cc

all: $(MAKEFILE)
    $(MAKE) -f $(MAKEFILE)

clean: $(MAKEFILE)
    $(MAKE) -f $(MAKEFILE) clean

$(MAKEFILE): $(TEMPLATE)
    $(CXX) $(MAKECONFIG) -E $(TEMPLATE) > $(MAKEFILE)

Note that the -E switch is pretty common for compilers (at least the big three I work with: GCC, Clang, and CL) for only preprocessing the file. With GNU Make the $(MAKECONFIG) expands to nothing, but in NMAKE it provides the preprocessor variable declaring itself. Since your template Makefile.cc can check it with #ifdef, as well as check for common variables with which the compiler declares itself, you can customize your Makefile.mk quite a bit for both the 'make' program, your operating system, and the compiler you're using.

If you have any 'make' you probably already have a C compiler too; there's no need to install additional software like CMake or autotools. It uses mechanisms that are old and so likely to work in a lot of environments. And from what I've been able to tell so far, it's really fast. Faster at least than running a configuration step in autotools. The only disadvantage I've faced is that it limits the style of your Make rules to being on the same line, because the preprocessor changes the indentation of the code. Also the preprocessor spits out lines with # tags, but since these start a comment in a Makefile, they get ignored anyway.

A have a somewhat small C++ project with a Makefile.cc that looks like the following snippet. It compiles on GNU Make or NMAKE with either GCC, Clang, or CL and on either Windows or in a POSIX environment. I've yet to support BSD Make or test any other compiler though.

// Make Version

#ifdef _NMAKE
# define ifdef !ifdef
# define ifndef !ifndef
# define else !else
# define endif !endif
# define err(x) !error x
# define cat(x, y) x=$(x) y
#else // GNU Make
# define err(x) $(error x)
# define cat(x, y) x += y
#endif

// System Commands

ifdef SHELL
RM=rm -f
else
ifdef COMSPEC
RM=del /f
else
err("Cannot determine your system commands.")
endif // COMSPEC
endif // SHELL

// Project Variables

STD=c++17
SRC=test.cpp dbg.cpp dir.cpp dll.cpp env.cpp err.cpp fifo.cpp file.cpp shm.cpp sig.cpp socket.cpp sys.cpp xdg.cpp
BIN=test

.SUFFIXES: .cpp .hpp .o .d .obj .pdb .lib .exp .ilk .log .i .db

// Operating system

#ifdef _WIN32
cat(CFLAGS, -D_WIN32)
EXE=$(BIN).exe
#else
cat(CFLAGS, -D_POSIX_C_SOURCE)
cat(LDFLAGS, -ldl -lrt -lpthread)
EXE=$(BIN)
#endif

// Make Targets

all: $(EXE)

clean: ; $(RM) $(EXE) *.o *.d *.obj *.pdb *.lib *.exp *.ilk *.log *.i

// Compiler Options

#ifdef _MSC_VER

cat(CFLAGS, -nologo -std:$(STD) -W4 -DNOMINMAX -D_CRT_SECURE_NO_WARNINGS -EHsc -permissive-)
ifndef NDEBUG
cat(CFLAGS, -Zi)
endif
cat(LDFLAGS, -nologo)

OBJ=$(SRC:.cpp=.obj)

$(EXE): $(OBJ); $(CXX) $(LDFLAGS) $(OBJ) -Fe$@
.cpp.obj: ; $(CXX) $(CFLAGS) -c 
lt;

#elif defined(__GNUC__) || defined(__llvm__) || defined(__clang__)

cat(CFLAGS, -std=$(STD) -Wall -Wextra -Wpedantic -MP -MMD)
ifndef NDEBUG
cat(CFALGS, -g)
endif
cat(LDFLAGS, -rdynamic)

OBJ=$(SRC:.cpp=.o)

$(EXE): $(OBJ); $(CXX) $(LDFLAGS) $(OBJ) -o $@
.cpp.o: ; $(CXX) $(CFLAGS) -c 
lt;

# ifndef _NMAKE
-include $(SRC:.cpp=.d)
# endif
#else
# error "Cannot determine your compiler."
#endif
淡笑忘祈一世凡恋 2024-12-25 07:09:42

是否可以使用 gnu sed 或 perl 中的脚本将主机的 Makefile 转换为 Microsoft 兼容的 NMakefile?毕竟,Makefile 是文本文件,可为您使用的任何辅助工具提供输入。 Sed 和 Perl 都适用于 Linux 和 Windows。

Wouldn't it be possible to use a script in gnu sed, or perl to translate the host's Makefile to a Microsoft compatible NMakefile? The Makefiles, after all, are text files to provide input for whichever helper tool you're using. Sed and Perl both exist for Linux and Windows.

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