使用 make 构建 C++ 模板库

Building a C++ template library with make

我在将 re-writting 我的 C++ 库转换为模板形式时遇到困难;主要问题涉及 re-designing Makefile.

在以前的状态下,当它是 non-template 我有:

CC = g++
CFLAGS = -O2
SRC = lib.cpp
HDR = $(SRC:.cpp=.h)
OBJ = $(SRC:.cpp=.o)
LIB = $(OBJ:.o=.a)

.PHONY: all install clean uninstall

# =========================================================
# Build
# =========================================================

all: $(LIB)

# Create an object file
$(OBJ):
    $(CC) $(CFLAGS) -c -o $@ $(SRC)

# Create a static library file
$(LIB): $(OBJ)
    ar rcs $@ $<

# =========================================================
# Install
# =========================================================

install: ~/lib/lib/$(LIB) ~/lib/include/$(HDR)

# Create top-level directory for the libraries
~/lib:
    mkdir -p $@;

# Create top-level directory for the static library files
~/lib/lib:
    mkdir -p $@;

# Create top-level directory for the headers
~/lib/include:
    mkdir -p $@;

# Copy the library file into the right directory
~/lib/lib/$(LIB): $(LIB) ~/lib/lib
    cp $< $@

# Copy the header file into the right directory
~/lib/include/$(HDR): $(HDR) ~/lib/include
    cp $< $@
g++ -O0 -Wall --std=c++14 test.cpp -I ~/lib/include/ ~/lib/lib/lib.a -o test

此设置运行良好。


当我想 re-write 我的 class 成为模板时,问题出现了。

根据信息 in this post I have added an #include "lib.cpp" at the end of the header file for my library (inside the include guard, ofc). With that change I needed to adjust the compilation process and do not provide my implementation file in the command line (as it is already included in the header and I have to avoid re-definition errors). That works fine. The core of the problem is now in the Makefile, in the command to build an object file. As I try to compile the implementation file of my library, it includes the header and the header includes the implementation again... I red about the problem in this port,他们建议从实施文件中删除 header 包含。所以我这样做了,我评论了 #include "lib.h" 并尝试 运行:

g++ -O2 -c -o lib.o lib.cpp

最后我遇到了很多 error: use of undeclared identifier 错误...

如何使用 make 正确构建库?我的限制是库 保留在两个单独的文件中:header 和实现 。我最终想要的是能够 #include <lib.h> 在我的进一步计划中。

甚至可以创建存档的 object 文件吗? 共享object库呢(.so)

I have added an #include "lib.cpp" at the end of the header file for my library (inside the include guard, ofc).

我不能说我很重视你在那里采纳的建议。打算用作 header 或在 header 中使用的代码应适当命名(.h.hpp 或您的项目遵循的任何约定),并且适合直接编译的代码非常漂亮much 永远不属于 header。也许您的转换涉及将后一种类型的所有内容更改为前一种类型,因此您可能想将 lib.cpp 重命名为 lib_impl.h 或类似名称,并完全跳过尝试编译它。也许。

但是请注意,如果您将实现代码命名和构造为 header,那么它需要自己的包含保护。另请注意,它不得包含任何外部 non-template 函数。如果是这样,那么贡献于同一程序的两个单独的翻译单元都不能同时包含 header,因为这会导致重复的函数定义,尽管包含守卫。如果没有外部 non-template 函数(也没有外部 object 定义),那么尝试编译成 object 文件是没有意义的,因为没有可访问的入口点

中的任意函数

How can I build the library properly with make?

这与 make 无关。那只是提供自动化。问题在于库本身的结构和您的期望。

My constraint is that the library stays in two separate files: header and implementation.

仅当实现包含外部 object 或函数的任何实例化模板,或任何外部 non-template 函数或 object 时,此约束才有意义。这些内容有助于构建可构建的 object 文件,您可以直接或间接地 link 应用程序。如果转换为模板库意味着您的库中不再有任何此类实体,则约束是任意的,因为转换后的结果是 header-only 库。不过,您可以按照自己喜欢的任何方式拆分 header,只要每个结果的结构都是 as a header,并且只包含适合header,并有自己的包含保护。

另一方面,如果您转换后的实现代码确实包含任何这些东西,那么它们不得 #included 变成任何 header,如上所述。

What I want in the end is to be able to #include <lib.h> in my further programs.

如果转换后的实现代码适合用作 header 或在 header 中使用,那么您已经在那里了,但是将您的 lib.cpp 重命名为 [=55] 会更好=].如果您希望能够将 header 直接包含到主库 header 以外的代码中,那么它需要自己的包含保护——这将处理重复的声明。但是请注意,这些错误是由于您有循环依赖这一事实引起的,这是您应该重构的强烈信号。这样的重构将涉及将足够的代码从 lib.cpp 移动到 lib.h,以便可以删除循环依赖(其中一个文件将不再 #include 另一个)。

任何不适合在 header 中使用的实现代码显然都不能包含在 header 中。如果任何此类代码保留在转换后的库中,那么也许您将其保留在 lib.cpp 中,并将其余代码移至 lib.h

Is it even possible to create an archived object file? What about shared object library (.so)

无法编译模板。它们是可编译代码的 模板 :它们的实例化。如果您的转换没​​有留下任何其他内容,那么您将无法有效地创建 object 文件或共享库。你不需要这样做,因为这是一个 header-only 库。