我通常使用干草叉目录布局:
project/
├─ src/
├─ include/
其中 src/ 和 /include 是镜像的(取决于哪些标头需要公开):
project/
├─ include/
│ ├─ common/
│ │ ├─ language.h
│ │ ├─ settings.h
├─ src/
│ ├─ common/
│ │ ├─ settings.cpp
│ │ ├─ error.h
│ │ ├─ file.h
│ │ ├─ language.cpp
│ ├─ flow/
│ │ ├─ flow.cpp
│ │ ├─ flow.h
│ ├─ main.cpp
include
是公开的,在部署项目时暴露,而src
则不是。
该项目只有 include/
和 src/
作为包含目录(例如,我指定 #include "common/language.h"
)可以说,在上面的示例中,一个模块就是
project.common
。
但是,这应该怎么做呢,因为一部分是公开的,一部分是非公开的。
对于标题,我只包含我需要的标题(我没有大的
commons.h
文件)。
对于模块来说,这似乎并不那么容易,如果我想要一个
project.common
模块,既可以被外部应用程序使用,也可以被项目本身使用。
是否有商定的惯例或最佳实践来制作基于模块的时尚项目?
编辑: 这里的“私有”是指项目内部使用。 例如,使用假设模块
project.common
,
对于项目本身的消耗,它将导出 error
和 file
- 项目私有标头,
而它应该仅向外部应用程序公开language
和settings
。
我想这取决于您想要分发的内容,但让我们考虑一下您想要分发最少的内容以使用您的库的编译版本。
在模块之前,源文件 (
.cpp
) 被编译为 目标文件 (.o
)。但为了可供另一个源文件使用,它必须知道编译后的目标文件中可用内容的“接口”。因此,您还必须提供一个公共头文件(.h
)。 (当然,我们通常不会分发许多 .o,而是将它们链接到单个 .lib
,但这与解释无关。)
现在,一个模块接口文件(
.cppm
)将生成2个文件:预编译的模块接口(命名为IFC、BMI、CMI等,具体取决于编译器,具有不同的扩展名)和已编译的目标文件 (.o
)。
其他想要使用它的模块和源文件不再需要公共标头,而是需要预编译的模块接口文件。
因此,在您的示例中,如果您将所有源文件转换为模块,并且最终没有公共标头,那么会更容易,因为所有源文件现在都位于
/src
中,并且 您可以摆脱 /include
目录。
(除非您还有一些带有宏的标头要分发。)
如果你想分发所有源文件,也是一样的。因为无论如何,当您
import
模块时,它不依赖于包含路径,因此您不需要将特定文件夹添加到您的包含目录中。请注意,它还允许轻松移动文件/重新组织整个目录树,而无需更改一行代码。
最后,还要注意,分发 public headers 通常用作基本 api 文档。使用模块,您仍然可以将 module 接口 (
.cppm
) 和 module 实现 (.cpp
) 分成单独的文件,我想您也可以将模块接口分发到公共文件夹中,而不是分发预编译的模块接口。我不知道我们是否已经有关于哪种解决方案更好的良好实践(或者在哪种情况下一种解决方案比另一种更好)。