Makefile 处理 Windows 和 Linux 下的不同源目录和对象目录
Makefile dealing with different source and object directories under Windows and Linux
我在为源文件分散在不同文件夹中的项目创建 Makefile 时遇到问题。由于源文件可能具有相同的名称,因此我也想将对象发送到不同的文件夹中。使用单个源文件和目标文件,我可以很好地遵循其他地方发布的规则 (Automatic makefile with source and object files in different directories)。 Makefile 必须足以与 Windows 和 Linux 一起使用,我通过 pathfix
定义解决了这个问题(参见下面的代码)。这部分做得很好,但我可能会忽略一些细节。
这是 Makefile 的简化版本,展示了我的方法:
CXX = g++
CFLAGS = -O0 -g -Wall -Wextra -pedantic -std=c++11 -fopenmp
FILES = main.cpp
FILES_MINIME = minime_class.cpp fifo_class.cpp fit_fun.cpp funcs.cpp gabe_class.cpp minimizer_s.cpp random.cpp
# check the OS
ifdef windir
binfix = .exe
pathfix = $(subst /,\,)
OSID = 1
else
ifeq ($(shell uname), Linux)
binfix =
pathfix =
OSID = 0
else
ifneq ($(shell uname), Linux)
$(error OS not identified)
endif
endif
endif
# define the different paths of objects and sources
ODIR = obj
SDIR = .
MINIME_SDIR = $(call pathfix, ../minime_pp/src)
MINIME_ODIR = $(call pathfix, obj/minime_pp)
# create templates for the objects by replacing the cpp with an o
_OBJECTS = $(patsubst %.cpp, %.o, $(FILES))
_OBJECTS_MINIME = $(patsubst %.cpp, %.o, $(FILES_MINIME))
# combine the source- and the file names
SOURCE_MINIME = $(call pathfix, $(addprefix $(MINIME_SDIR)/, $(FILES_MINIME)))
# now combine the object- and the file names
OBJECTS = $(call pathfix, $(addprefix $(ODIR)/, $(_OBJECTS)))
OBJECTS_MINIME = $(call pathfix, $(addprefix $(MINIME_ODIR)/, $(_OBJECTS_MINIME)))
# add upp all the objects
OBJECTS_ALL = $(OBJECTS) $(OBJECTS_MINIME)
# define the rules
$(PROJECT): $(OBJECTS_ALL)
$(CXX) -o $@$(binfix) $^
$(OBJECTS): $(FILES) Makefile
$(CXX) $(CFLAGS) -c $< -o $@
$(OBJECTS_MINIME): $(SOURCE_MINIME)
$(CXX) $(CFLAGS) -c $< -o $@
# create the folders (if necessary)
$(OBJECTS): | $(ODIR)
$(OBJECTS_MINIME): | $(MINIME_ODIR)
$(ODIR):
mkdir $(ODIR)
$(MINIME_ODIR):
mkdir $(MINIME_ODIR)
输出中最容易说明问题。在 Windows 上,mingw32-make > output.txt
读取
g++ -O0 -g -Wall -Wextra -pedantic -std=c++11 -fopenmp -c main.cpp -o obj\main.o
g++ -O0 -g -Wall -Wextra -pedantic -std=c++11 -fopenmp -c ..\minime_pp\src\minime_class.cpp -o obj\minime_pp\minime_class.o
g++ -O0 -g -Wall -Wextra -pedantic -std=c++11 -fopenmp -c ..\minime_pp\src\minime_class.cpp -o obj\minime_pp\fifo_class.o
g++ -O0 -g -Wall -Wextra -pedantic -std=c++11 -fopenmp -c ..\minime_pp\src\minime_class.cpp -o obj\minime_pp\fit_fun.o
g++ -O0 -g -Wall -Wextra -pedantic -std=c++11 -fopenmp -c ..\minime_pp\src\minime_class.cpp -o obj\minime_pp\funcs.o
g++ -O0 -g -Wall -Wextra -pedantic -std=c++11 -fopenmp -c ..\minime_pp\src\minime_class.cpp -o obj\minime_pp\gabe_class.o
g++ -O0 -g -Wall -Wextra -pedantic -std=c++11 -fopenmp -c ..\minime_pp\src\minime_class.cpp -o obj\minime_pp\minimizer_s.o
g++ -O0 -g -Wall -Wextra -pedantic -std=c++11 -fopenmp -c ..\minime_pp\src\minime_class.cpp -o obj\minime_pp\random.o
原因是 -c $<
语法只接受依赖项的第一个条目(在本例中为 ..\minime_pp\src\minime_class.cpp
)。
这个问题的解决方案可能是切换回像
这样的定义
$(MINIME_ODIR)/%.o: $(MINIME_SDIR)/%.cpp
$(CXX) $(CFLAGS) -c $< -o $@
现在的问题是反斜杠 - $(OBJECTS_ALL)
中没有要求匹配这个新定义,因此没有任何反应。在定义中使用 \
是行不通的。所以我认为你摆脱了反斜杠 - 正斜杠转换,但是自动目录创建将无法在 Windows 上工作。类似 -c $<
但 $<
从列表中选择 'matching' 没有 /%.cpp
的东西基本上就是我要找的东西。
如果有人知道编写两个 Makefile 的方法(Windows、Linux),感谢您的提示。
永远不要在 makefile 中使用反斜杠分隔符。几乎所有 Windows 工具都支持普通的 UNIX 斜杠作为目录分隔符。对于那些不这样做的少数人来说,将它们转换为配方中的特定实用程序会更容易:换句话说,将对 $(pathfix ...)
的调用仅放在需要它们的地方。
请注意,几乎所有需要反斜杠的命令都是 Windows 特定的 (command.com) 命令,无论如何都无法移植到 UNIX。
我这样做是为了让 Windows 和 Linux/MacOS 具有相同的 makefile:
ifeq ($(OS),Windows_NT)
RM = del /Q /F
RRM = rmdir /Q /S
mkdirp = mkdir $(subst /,\,)
else
RM = rm -f
RRM = rm -rf
mkdirp = mkdir -p
endif
$(BUILDDIR):
$(call mkdirp, $@)
clean:
-$(RRM) $(BUILDDIR)
-$(RM) $(TARGET)
我在为源文件分散在不同文件夹中的项目创建 Makefile 时遇到问题。由于源文件可能具有相同的名称,因此我也想将对象发送到不同的文件夹中。使用单个源文件和目标文件,我可以很好地遵循其他地方发布的规则 (Automatic makefile with source and object files in different directories)。 Makefile 必须足以与 Windows 和 Linux 一起使用,我通过 pathfix
定义解决了这个问题(参见下面的代码)。这部分做得很好,但我可能会忽略一些细节。
这是 Makefile 的简化版本,展示了我的方法:
CXX = g++
CFLAGS = -O0 -g -Wall -Wextra -pedantic -std=c++11 -fopenmp
FILES = main.cpp
FILES_MINIME = minime_class.cpp fifo_class.cpp fit_fun.cpp funcs.cpp gabe_class.cpp minimizer_s.cpp random.cpp
# check the OS
ifdef windir
binfix = .exe
pathfix = $(subst /,\,)
OSID = 1
else
ifeq ($(shell uname), Linux)
binfix =
pathfix =
OSID = 0
else
ifneq ($(shell uname), Linux)
$(error OS not identified)
endif
endif
endif
# define the different paths of objects and sources
ODIR = obj
SDIR = .
MINIME_SDIR = $(call pathfix, ../minime_pp/src)
MINIME_ODIR = $(call pathfix, obj/minime_pp)
# create templates for the objects by replacing the cpp with an o
_OBJECTS = $(patsubst %.cpp, %.o, $(FILES))
_OBJECTS_MINIME = $(patsubst %.cpp, %.o, $(FILES_MINIME))
# combine the source- and the file names
SOURCE_MINIME = $(call pathfix, $(addprefix $(MINIME_SDIR)/, $(FILES_MINIME)))
# now combine the object- and the file names
OBJECTS = $(call pathfix, $(addprefix $(ODIR)/, $(_OBJECTS)))
OBJECTS_MINIME = $(call pathfix, $(addprefix $(MINIME_ODIR)/, $(_OBJECTS_MINIME)))
# add upp all the objects
OBJECTS_ALL = $(OBJECTS) $(OBJECTS_MINIME)
# define the rules
$(PROJECT): $(OBJECTS_ALL)
$(CXX) -o $@$(binfix) $^
$(OBJECTS): $(FILES) Makefile
$(CXX) $(CFLAGS) -c $< -o $@
$(OBJECTS_MINIME): $(SOURCE_MINIME)
$(CXX) $(CFLAGS) -c $< -o $@
# create the folders (if necessary)
$(OBJECTS): | $(ODIR)
$(OBJECTS_MINIME): | $(MINIME_ODIR)
$(ODIR):
mkdir $(ODIR)
$(MINIME_ODIR):
mkdir $(MINIME_ODIR)
输出中最容易说明问题。在 Windows 上,mingw32-make > output.txt
读取
g++ -O0 -g -Wall -Wextra -pedantic -std=c++11 -fopenmp -c main.cpp -o obj\main.o
g++ -O0 -g -Wall -Wextra -pedantic -std=c++11 -fopenmp -c ..\minime_pp\src\minime_class.cpp -o obj\minime_pp\minime_class.o
g++ -O0 -g -Wall -Wextra -pedantic -std=c++11 -fopenmp -c ..\minime_pp\src\minime_class.cpp -o obj\minime_pp\fifo_class.o
g++ -O0 -g -Wall -Wextra -pedantic -std=c++11 -fopenmp -c ..\minime_pp\src\minime_class.cpp -o obj\minime_pp\fit_fun.o
g++ -O0 -g -Wall -Wextra -pedantic -std=c++11 -fopenmp -c ..\minime_pp\src\minime_class.cpp -o obj\minime_pp\funcs.o
g++ -O0 -g -Wall -Wextra -pedantic -std=c++11 -fopenmp -c ..\minime_pp\src\minime_class.cpp -o obj\minime_pp\gabe_class.o
g++ -O0 -g -Wall -Wextra -pedantic -std=c++11 -fopenmp -c ..\minime_pp\src\minime_class.cpp -o obj\minime_pp\minimizer_s.o
g++ -O0 -g -Wall -Wextra -pedantic -std=c++11 -fopenmp -c ..\minime_pp\src\minime_class.cpp -o obj\minime_pp\random.o
原因是 -c $<
语法只接受依赖项的第一个条目(在本例中为 ..\minime_pp\src\minime_class.cpp
)。
这个问题的解决方案可能是切换回像
这样的定义$(MINIME_ODIR)/%.o: $(MINIME_SDIR)/%.cpp
$(CXX) $(CFLAGS) -c $< -o $@
现在的问题是反斜杠 - $(OBJECTS_ALL)
中没有要求匹配这个新定义,因此没有任何反应。在定义中使用 \
是行不通的。所以我认为你摆脱了反斜杠 - 正斜杠转换,但是自动目录创建将无法在 Windows 上工作。类似 -c $<
但 $<
从列表中选择 'matching' 没有 /%.cpp
的东西基本上就是我要找的东西。
如果有人知道编写两个 Makefile 的方法(Windows、Linux),感谢您的提示。
永远不要在 makefile 中使用反斜杠分隔符。几乎所有 Windows 工具都支持普通的 UNIX 斜杠作为目录分隔符。对于那些不这样做的少数人来说,将它们转换为配方中的特定实用程序会更容易:换句话说,将对 $(pathfix ...)
的调用仅放在需要它们的地方。
请注意,几乎所有需要反斜杠的命令都是 Windows 特定的 (command.com) 命令,无论如何都无法移植到 UNIX。
我这样做是为了让 Windows 和 Linux/MacOS 具有相同的 makefile:
ifeq ($(OS),Windows_NT)
RM = del /Q /F
RRM = rmdir /Q /S
mkdirp = mkdir $(subst /,\,)
else
RM = rm -f
RRM = rm -rf
mkdirp = mkdir -p
endif
$(BUILDDIR):
$(call mkdirp, $@)
clean:
-$(RRM) $(BUILDDIR)
-$(RM) $(TARGET)