我有一个简单的C-Programm(1个源文件),我想在Linux上和Windows上通过make resp编译。 NMAKE。是否有可能使用单个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',我不想拥有它。
有没有人知道另一种方式?或者我正在尝试的绝对不可能?
答案 0 :(得分:9)
这可能并非不可能,但最有可能的是,无论如何写两个makefile会更容易。
GNU make(在Linux中使用)和nmake都有include伪指令,因此一些常见的东西可以放在主makefile包含的公共makefile中。
答案 1 :(得分:7)
您应该考虑使用CMake。有一个源文件应该很容易!
编辑:
以下是设置简单项目的方法:
cmake_minimum_required(VERSION 2.8)
project(Simple)
include_directories("${PROJECT_BINARY_DIR}")
add_executable(Simple simple.cpp)
要构建简单项目,您可以执行以下操作(假设您的源和CMakeLists.txt文件位于~/src/simple
中:
foo@bar~/src/simple$ mkdir build
foo@bar~/src/simple$ cd build
foo@bar~/src/simple$ cmake ..
foo@bar~/src/simple$ make
答案 2 :(得分:7)
我想使用make和nmake使用的相同makefile include。由于make在注释行上识别行继续但nmake没有,这意味着我们可以为make和nmake提供单独的指令。例如:
# \
!ifndef 0 # \
# nmake code here \
MV=move # \
RM=del # \
CP=copy # \
!else
# make code here
MV=mv -f
RM=rm -f
CP=cp -f
# \
!endif
只需确保#e
终止nmake特定代码答案 3 :(得分:4)
我无法找到一种方法来使用通用的makefile来同时使用GNU make和MS nmake,主要是因为它们的“include”和/或“if”指令的语法不兼容。 MS nmake需要使用!指令的前缀。例如,!if,!include等...
但是,如果允许使用单独的宏,则可能会被欺骗。在这里,我提出了迄今为止我发现的最佳方法,通过观察以下内容使makefile兼容GNU make和MS nmake:
注意:以下内容已使用MS 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)),其中只指定了dependecies。
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和MS nmake
$ nmake
$ make clean
$ nmake clean
$ make
答案 4 :(得分:2)
解决方案: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
答案 5 :(得分:1)
我只是想到了一些完全不同的东西。
如果您坚持使用非常简单的Makefile,您可以使用它,只需将“标准”变量CC和CFLAGS放在各自的环境中,比如说
export CC=gcc
分别
set CC=CL.EXE
和
export CFLAGS=-o myexecutable
分别
set CFLAGS=/out:myexecutable.exe
它可能会起作用。
请注意,我不确定使用的确切选项,你必须自己弄明白。但AFAIK都使变体识别同一组标志。您甚至可以在相应的命令行中设置它们(但不在makefile中,因为NMAKE使用不同的'ifeq'语法...)
答案 6 :(得分:1)
是的,您可以使用单个Makefile执行此操作。这种材料的最佳来源是O' Reilly Book:
Managing Projects with GNU Make, Third Edition By 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 ..
答案 7 :(得分:0)
我最近尝试使用C预处理程序从包含预处理程序符号的模板Makefile.cc生成可移植的Makefile。到目前为止,它的工作出奇地出色。第一个发现是NMAKE将预扫描Tools.ini文件,该文件与我在同一目录中提供
[NMAKE]
MAKECONFIG=-D_NMAKE
然后我旁边有一个“ true” 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程序,操作系统和操作系统自定义Makefile.mk。您正在使用的编译器。
如果您有任何“ make”,您可能也已经有一个C编译器;无需安装其他软件,例如CMake或自动工具。它使用的机制很旧,因此很可能在很多环境中都可以使用。到目前为止,根据我的判断,这确实非常快。至少比在自动工具中运行配置步骤要快。我所面临的唯一缺点是,由于预处理程序会更改代码的缩进,因此它将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 $<
#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 $<
# ifndef _NMAKE
-include $(SRC:.cpp=.d)
# endif
#else
# error "Cannot determine your compiler."
#endif
答案 8 :(得分:0)
我的解决方案是使用两个不同的文件名。 (因为在不同的操作系统中,Makefile名称搜索的优先级将不同)
对于Windows,我使用普通的“ Makefile”。
对于Linux,我根据this article使用特殊的“ GNUmakefile”。
nmake(Win)将找到“ Makefile”,而make(Linux)将找到“ GNUmakefile”。