使用 make 构建 C++ 模板库
Building a C++ template library with make
我在将 re-writting 我的 C++ 库转换为模板形式时遇到困难;主要问题涉及 re-designing Makefile.
在以前的状态下,当它是 non-template 我有:
- a header 文件 lib.h 其中(由 include guards 保护)我们有 classes 和重载运算符的声明。此文件根本不包含任何其他库。
- 一个实现文件lib.cpp,其中,在文件顶部,我包含许多来自标准库(cmath、iostream、等)以及我为这个自定义库包含 header 文件:
#include "lib.h"
- a Makefile 带有 build/install 库的命令:
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 $< $@
- 安装后,我的 CI (GH Actions) 将编译一个小测试程序,其中包括我的库 header (
#include <lib.h>
),使用以下命令:
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,并有自己的包含保护。
另一方面,如果您转换后的实现代码确实包含任何这些东西,那么它们不得 #include
d 变成任何 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 库。
我在将 re-writting 我的 C++ 库转换为模板形式时遇到困难;主要问题涉及 re-designing Makefile.
在以前的状态下,当它是 non-template 我有:
- a header 文件 lib.h 其中(由 include guards 保护)我们有 classes 和重载运算符的声明。此文件根本不包含任何其他库。
- 一个实现文件lib.cpp,其中,在文件顶部,我包含许多来自标准库(cmath、iostream、等)以及我为这个自定义库包含 header 文件:
#include "lib.h"
- a Makefile 带有 build/install 库的命令:
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 $< $@
- 安装后,我的 CI (GH Actions) 将编译一个小测试程序,其中包括我的库 header (
#include <lib.h>
),使用以下命令:
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,并有自己的包含保护。
另一方面,如果您转换后的实现代码确实包含任何这些东西,那么它们不得 #include
d 变成任何 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 库。