使用 makefile (c++) 部分编译和包含 boost
Partially compile and include boost with makefile (c++)
我有一个 c++ 项目,我希望它具有合理的可移植性,并且可以通过发出单个 "make" 命令进行编译。我目前使用 boost headers 进行某些操作,但现在需要来自 boost 的 "filesystem",这需要编译。
我知道有一种方法可以使用包含的 shell 脚本编译 boost,但这需要永远。我很好奇一种有选择地编译 boost 库的方法,如 makefile 中指定的那样,并将它们包含在链接过程中。
我目前的大致思路是:
有一个要编译和包含的 boost 库的 makefile 变量。
从 boost 分发文件夹编译这些库(在任何依赖项目之前),并将编译后的二进制文件输出到 makefile 项目中的特定文件夹(例如:"lib" 文件夹)
我了解如何使用以下方法将这些文件包含在项目中:
-Llib
执行此操作的最佳方法是什么,以及选择编译的增强输出在哪里?文件应该是 .a 还是 .o 文件? (或者没有扩展名?)
这是先前答案的手动makefile 的更狂野的哥哥。给定 BOOST 发行版的路径 BOOST_DISTRO
,它会找到 TARGET_BOOST_LIBS
中指定的目标库的相关源文件,将它们编译成 $(WORK_FOLDER)/<lib>/
,并将生成的对象存档到 [=14] =].
BOOST_DISTRO=.
DEST_FOLDER=libs
WORK_FOLDER=build
TARGET_BOOST_LIBS=\
system \
filesystem \
serialization
.PHONY: all
all: $(foreach lib,$(TARGET_BOOST_LIBS),$(DEST_FOLDER)/libboost_$(lib).a )
$(DEST_FOLDER):
mkdir -p $(DEST_FOLDER)
$(WORK_FOLDER):
mkdir -p $(WORK_FOLDER)
#####
# helper for building the .o files in WORK_FOLDER
#####
define MAKE_BOOST_LIB_COMPILE_RULES
$(foreach cppfile,$(shell ls $(BOOST_DISTRO)/boost/libs/$(1)/src/*.cpp),$(WORK_FOLDER)/$(1)/$(notdir $(cppfile:.cpp=.o)): $(cppfile) | $(WORK_FOLDER)/$(1)
$(CXX) $(CXXFLAGS) -D BOOST_ALL_NO_LIB \
-I$(BOOST_DISTRO)/boost \
-c $$^ \
-o $$@
)
endef
#####
# define the build rules based on the files we find in the subfolders of
# the boost distro that correspond to our library names
#####
define BUILD_BOOST_LIB
$(WORK_FOLDER)/$(1): | $(WORK_FOLDER)
mkdir -p $$@
$(call MAKE_BOOST_LIB_COMPILE_RULES,$(1))
$(DEST_FOLDER)/libboost_$(1).a: $(foreach cppfile,$(notdir $(shell ls $(BOOST_DISTRO)/boost/libs/$(1)/src/*.cpp)),$(WORK_FOLDER)/$(1)/$(cppfile:.cpp=.o)) | $(DEST_FOLDER)
ar r $$@ $$^
ranlib $$@
endef
#####
# dynamically generate the build rules from the list of libs
#####
$(foreach lib,$(TARGET_BOOST_LIBS),$(eval $(call BUILD_BOOST_LIB,$(lib))))
.PHONY: clean
clean:
-rm -rf $(WORK_FOLDER)
-rm -rf $(DEST_FOLDER)
使用我古老的 BOOST (#define BOOST_VERSION 105500
) 进行测试,这将构建列出的库,并且虚拟测试程序成功编译并调用 boost::filesystem::absolute()
。
使用 lockcmpxchg8b 的答案,我能够根据我的需要对其进行调整。
在递归调用时让 makefile 正常工作有点棘手,但我能够让它工作。
SHELL = /bin/sh
# This makefile expects multiple arguments to be passed:
#
# Use the pattern: make var_name="var_value" when invoking this makefile
#
# BOOST_VER (the version suffix )
# BOOST_LIBS_TO_BUILD (space delimited list of boost libraries to build)
# BOOST_LIB_DIR (the output lib dir for the boost libraries)
# BOOSTDIR (the base directory to build from)
#
# Compile Info
CXX = g++
CXXFLAGS = -Wall -std=c++11
WORK_FOLDER = obj_boost$(BOOST_VER)
.PHONY: all
all: $(foreach lib,$(BOOST_LIBS_TO_BUILD),$(BOOST_LIB_DIR)/libboost_$(lib).a )
$(BOOST_LIB_DIR):
@mkdir -p $(BOOST_LIB_DIR)
$(WORK_FOLDER):
@mkdir -p $(WORK_FOLDER)
#####
# helper for building the .o files in WORK_FOLDER
#####
define MAKE_BOOST_LIB_COMPILE_RULES
$(foreach cppfile,$(shell ls $(BOOSTDIR)/libs/$(1)/src/*.cpp),$(WORK_FOLDER)/$(1)/$(notdir $(cppfile:.cpp=.o)): $(cppfile) | $(WORK_FOLDER)/$(1)
$(CXX) $(CXXFLAGS) -D BOOST_ALL_NO_LIB \
-I$(BOOSTDIR) \
-c $$^ \
-o $$@
)
endef
#####
# define the build rules based on the files we find in the subfolders of
# the boost distro that correspond to our library names
#####
define BUILD_BOOST_LIB
$(WORK_FOLDER)/$(1): | $(WORK_FOLDER)
@mkdir -p $$@
$(call MAKE_BOOST_LIB_COMPILE_RULES,$(1))
$(BOOST_LIB_DIR)/libboost_$(1).a: $(foreach cppfile,$(notdir $(shell ls $(BOOSTDIR)/libs/$(1)/src/*.cpp)),$(WORK_FOLDER)/$(1)/$(cppfile:.cpp=.o)) | $(BOOST_LIB_DIR)
@ar r $$@ $$^
@ranlib $$@
endef
#####
# dynamically generate the build rules from the list of libs
#####
$(foreach lib,$(BOOST_LIBS_TO_BUILD),$(eval $(call BUILD_BOOST_LIB,$(lib))))
.PHONY: clean
clean:
@rm -rf $(WORK_FOLDER)
@rm -rf $(BOOST_LIB_DIR)/*
@echo "---- Done Cleaning Boost Libs ----"
要调用此 makefile,我使用以下命令从另一个 makefile 调用它:
# Boost
BOOST_VER= _1_65_1
BOOST_LIBS_TO_BUILD = filesystem timer chrono
#relative to this file
BOOST_LIB_DIR = shared/lib_boost$(BOOST_VER)
#relative to this file
BOOSTDIR = shared/boost$(BOOST_VER)
#Subdirectories
DIRECTORIES = $(sort $(dir $(wildcard */makefile)))
.PHONY: build
build: dependencies
@$(foreach dir,$(DIRECTORIES),$(MAKE) -C $(dir);)
dependencies:
@echo "---- Build Dependencies ----"
@$(MAKE) -C shared -f build_boost_libs.mk BOOST_LIBS_TO_BUILD="$(BOOST_LIBS_TO_BUILD)" BOOST_LIB_DIR="../$(BOOST_LIB_DIR)" BOOSTDIR="../$(BOOSTDIR)" BOOST_VER="$(BOOST_VER)"
正确调用递归 make 的模式是:
$(MAKE) -C subdir_of_makefile -f makefile_name.mk
使用 $(MAKE) 是调用 make 的正确方法(根据 documentation -- 它确保使用相同的 make 命令作为最顶层的 make)并正确更改 运行ning 目录,您需要使用 -C 参数(否则任何子 make 的目录上下文是调用堆栈中最顶层的父 makefile)。 -f 选项指定一个 makefile,它不是 makefile 的默认名称。这会在查找命名的 makefile 时考虑到 -C 选项。
我还发现将 "arguments" 传递给 makefile 有点棘手,通常通过 export 和 unexport 完成,但这些问题仅是由于最后一个 "status"要导出的变量用于整个 makefile。您不能导出一个变量,调用一个 sub-make,然后取消导出。它将在整个 makefile 运行 中不被导出(因为变量的最后一个 "status" 将被不导出,尽管它在子 make 之后被调用)。在 makefile 执行之前,变量 "status" 是 computed/parsed。
感谢您的帮助!我很感激。将来我也会在一个开源项目中发布这个 makefile(我会相信你的用户名有助于实现)
我有一个 c++ 项目,我希望它具有合理的可移植性,并且可以通过发出单个 "make" 命令进行编译。我目前使用 boost headers 进行某些操作,但现在需要来自 boost 的 "filesystem",这需要编译。
我知道有一种方法可以使用包含的 shell 脚本编译 boost,但这需要永远。我很好奇一种有选择地编译 boost 库的方法,如 makefile 中指定的那样,并将它们包含在链接过程中。
我目前的大致思路是:
有一个要编译和包含的 boost 库的 makefile 变量。
从 boost 分发文件夹编译这些库(在任何依赖项目之前),并将编译后的二进制文件输出到 makefile 项目中的特定文件夹(例如:"lib" 文件夹)
我了解如何使用以下方法将这些文件包含在项目中:
-Llib
执行此操作的最佳方法是什么,以及选择编译的增强输出在哪里?文件应该是 .a 还是 .o 文件? (或者没有扩展名?)
这是先前答案的手动makefile 的更狂野的哥哥。给定 BOOST 发行版的路径 BOOST_DISTRO
,它会找到 TARGET_BOOST_LIBS
中指定的目标库的相关源文件,将它们编译成 $(WORK_FOLDER)/<lib>/
,并将生成的对象存档到 [=14] =].
BOOST_DISTRO=.
DEST_FOLDER=libs
WORK_FOLDER=build
TARGET_BOOST_LIBS=\
system \
filesystem \
serialization
.PHONY: all
all: $(foreach lib,$(TARGET_BOOST_LIBS),$(DEST_FOLDER)/libboost_$(lib).a )
$(DEST_FOLDER):
mkdir -p $(DEST_FOLDER)
$(WORK_FOLDER):
mkdir -p $(WORK_FOLDER)
#####
# helper for building the .o files in WORK_FOLDER
#####
define MAKE_BOOST_LIB_COMPILE_RULES
$(foreach cppfile,$(shell ls $(BOOST_DISTRO)/boost/libs/$(1)/src/*.cpp),$(WORK_FOLDER)/$(1)/$(notdir $(cppfile:.cpp=.o)): $(cppfile) | $(WORK_FOLDER)/$(1)
$(CXX) $(CXXFLAGS) -D BOOST_ALL_NO_LIB \
-I$(BOOST_DISTRO)/boost \
-c $$^ \
-o $$@
)
endef
#####
# define the build rules based on the files we find in the subfolders of
# the boost distro that correspond to our library names
#####
define BUILD_BOOST_LIB
$(WORK_FOLDER)/$(1): | $(WORK_FOLDER)
mkdir -p $$@
$(call MAKE_BOOST_LIB_COMPILE_RULES,$(1))
$(DEST_FOLDER)/libboost_$(1).a: $(foreach cppfile,$(notdir $(shell ls $(BOOST_DISTRO)/boost/libs/$(1)/src/*.cpp)),$(WORK_FOLDER)/$(1)/$(cppfile:.cpp=.o)) | $(DEST_FOLDER)
ar r $$@ $$^
ranlib $$@
endef
#####
# dynamically generate the build rules from the list of libs
#####
$(foreach lib,$(TARGET_BOOST_LIBS),$(eval $(call BUILD_BOOST_LIB,$(lib))))
.PHONY: clean
clean:
-rm -rf $(WORK_FOLDER)
-rm -rf $(DEST_FOLDER)
使用我古老的 BOOST (#define BOOST_VERSION 105500
) 进行测试,这将构建列出的库,并且虚拟测试程序成功编译并调用 boost::filesystem::absolute()
。
使用 lockcmpxchg8b 的答案,我能够根据我的需要对其进行调整。
在递归调用时让 makefile 正常工作有点棘手,但我能够让它工作。
SHELL = /bin/sh
# This makefile expects multiple arguments to be passed:
#
# Use the pattern: make var_name="var_value" when invoking this makefile
#
# BOOST_VER (the version suffix )
# BOOST_LIBS_TO_BUILD (space delimited list of boost libraries to build)
# BOOST_LIB_DIR (the output lib dir for the boost libraries)
# BOOSTDIR (the base directory to build from)
#
# Compile Info
CXX = g++
CXXFLAGS = -Wall -std=c++11
WORK_FOLDER = obj_boost$(BOOST_VER)
.PHONY: all
all: $(foreach lib,$(BOOST_LIBS_TO_BUILD),$(BOOST_LIB_DIR)/libboost_$(lib).a )
$(BOOST_LIB_DIR):
@mkdir -p $(BOOST_LIB_DIR)
$(WORK_FOLDER):
@mkdir -p $(WORK_FOLDER)
#####
# helper for building the .o files in WORK_FOLDER
#####
define MAKE_BOOST_LIB_COMPILE_RULES
$(foreach cppfile,$(shell ls $(BOOSTDIR)/libs/$(1)/src/*.cpp),$(WORK_FOLDER)/$(1)/$(notdir $(cppfile:.cpp=.o)): $(cppfile) | $(WORK_FOLDER)/$(1)
$(CXX) $(CXXFLAGS) -D BOOST_ALL_NO_LIB \
-I$(BOOSTDIR) \
-c $$^ \
-o $$@
)
endef
#####
# define the build rules based on the files we find in the subfolders of
# the boost distro that correspond to our library names
#####
define BUILD_BOOST_LIB
$(WORK_FOLDER)/$(1): | $(WORK_FOLDER)
@mkdir -p $$@
$(call MAKE_BOOST_LIB_COMPILE_RULES,$(1))
$(BOOST_LIB_DIR)/libboost_$(1).a: $(foreach cppfile,$(notdir $(shell ls $(BOOSTDIR)/libs/$(1)/src/*.cpp)),$(WORK_FOLDER)/$(1)/$(cppfile:.cpp=.o)) | $(BOOST_LIB_DIR)
@ar r $$@ $$^
@ranlib $$@
endef
#####
# dynamically generate the build rules from the list of libs
#####
$(foreach lib,$(BOOST_LIBS_TO_BUILD),$(eval $(call BUILD_BOOST_LIB,$(lib))))
.PHONY: clean
clean:
@rm -rf $(WORK_FOLDER)
@rm -rf $(BOOST_LIB_DIR)/*
@echo "---- Done Cleaning Boost Libs ----"
要调用此 makefile,我使用以下命令从另一个 makefile 调用它:
# Boost
BOOST_VER= _1_65_1
BOOST_LIBS_TO_BUILD = filesystem timer chrono
#relative to this file
BOOST_LIB_DIR = shared/lib_boost$(BOOST_VER)
#relative to this file
BOOSTDIR = shared/boost$(BOOST_VER)
#Subdirectories
DIRECTORIES = $(sort $(dir $(wildcard */makefile)))
.PHONY: build
build: dependencies
@$(foreach dir,$(DIRECTORIES),$(MAKE) -C $(dir);)
dependencies:
@echo "---- Build Dependencies ----"
@$(MAKE) -C shared -f build_boost_libs.mk BOOST_LIBS_TO_BUILD="$(BOOST_LIBS_TO_BUILD)" BOOST_LIB_DIR="../$(BOOST_LIB_DIR)" BOOSTDIR="../$(BOOSTDIR)" BOOST_VER="$(BOOST_VER)"
正确调用递归 make 的模式是:
$(MAKE) -C subdir_of_makefile -f makefile_name.mk
使用 $(MAKE) 是调用 make 的正确方法(根据 documentation -- 它确保使用相同的 make 命令作为最顶层的 make)并正确更改 运行ning 目录,您需要使用 -C 参数(否则任何子 make 的目录上下文是调用堆栈中最顶层的父 makefile)。 -f 选项指定一个 makefile,它不是 makefile 的默认名称。这会在查找命名的 makefile 时考虑到 -C 选项。
我还发现将 "arguments" 传递给 makefile 有点棘手,通常通过 export 和 unexport 完成,但这些问题仅是由于最后一个 "status"要导出的变量用于整个 makefile。您不能导出一个变量,调用一个 sub-make,然后取消导出。它将在整个 makefile 运行 中不被导出(因为变量的最后一个 "status" 将被不导出,尽管它在子 make 之后被调用)。在 makefile 执行之前,变量 "status" 是 computed/parsed。
感谢您的帮助!我很感激。将来我也会在一个开源项目中发布这个 makefile(我会相信你的用户名有助于实现)