【问题标题】:Partially compile and include boost with makefile (c++)使用 makefile (c++) 部分编译并包含 boost
【发布时间】:2017-11-27 20:48:54
【问题描述】:

我有一个 C++ 项目,我希望它具有合理的可移植性,并且可以通过发出单个“make”命令进行编译。我目前对某些操作使用 boost 标头,但现在需要 boost 中的“文件系统”,这需要编译。

我知道有一种方法可以使用包含的 shell 脚本来编译 boost,但这需要永远。我很好奇有选择地编译从makefile指定的boost库并将它们包含在链接过程中的方法。

我目前的总体思路是:

  1. 有一个要编译和包含的 boost 库的 makefile 变量。

  2. 从 boost 分发文件夹编译这些库(在任何依赖项目之前),并将编译后的二进制文件输出到 makefile 项目中的特定文件夹(例如:“lib”文件夹)

  3. 我了解如何使用以下方法将这些文件包含在项目中:

    -Llib

最好的方法是什么,以及从编译中选择提升输出的位置?文件应该是 .a 还是 .o 文件? (或者没有扩展?)

【问题讨论】:

  • 哪种语言,C 还是 C++?它们是不同的语言。 Boost 库使用命名空间,而 C 没有命名空间。
  • 啊,是的,C++。我会更新问题/标题。
  • AFAIK,boost 构建系统可以选择仅编译其某些库以及安装这些库的位置。我认为编译那些请求的依赖提升库甚至足够聪明。
  • 我们是否应该假设您在谈论使用autoconf 及其朋友?
  • 我过去使用过这个方法:github.com/ser-pounce/ff7-tools/blob/master/boost_filesystem/…,请务必查看 boost_system 文件夹中的 makefile。可能需要对更新的 boost 版本进行一些调整,我不确定。

标签: c++ boost makefile static-libraries


【解决方案1】:

这是先前答案的手动生成文件的更狂野的哥哥。给定 BOOST 发行版的路径BOOST_DISTRO,它会找到TARGET_BOOST_LIBS 中指定的目标库的相关源文件,将它们编译为$(WORK_FOLDER)/<lib>/,并将生成的对象归档到$(DEST_FOLDER)/libboost_<lib>.a

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()

【讨论】:

  • 嗯,有没有更“通用”的版本,我可以从 boost 分发文件夹编译,并输出到项目特定目录?
  • 经过编辑使其更有趣……也更危险。
【解决方案2】:

使用 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)并正确更改运行目录,您需要使用 -C 参数(否则任何子生成的目录上下文是调用堆栈中最顶层的父生成文件)。 -f 选项指定的 makefile 不是 makefile 的默认名称。这在查找命名的 makefile 时考虑了 -C 选项。

我还发现将“参数”传递给 makefile 有点棘手,通常通过导出和取消导出来完成,但问题在于只有要导出的变量的最后一个“状态”是用于整个 makefile。您不能导出变量,调用子制作,然后取消导出。它将在整个 makefile 运行中不导出(因为变量的最后一个“状态”是不导出的,尽管它是在子生成之后调用的)。在 makefile 执行之前计算/解析变量“状态”。

感谢您的帮助!我很感激。将来我还将在一个开源项目中发布这个 makefile(我会相信你的用户名对此有帮助)

【讨论】:

    猜你喜欢
    • 2021-12-19
    • 2017-06-08
    • 1970-01-01
    • 1970-01-01
    • 2012-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多