是否有自动方法来获取大量C ++头文件并将它们组合在一起?
当然,此操作必须以正确的顺序连接文件,以便在即将到来的类和函数中使用之前不会定义任何类型等。
基本上,我正在寻找一些允许我将库分发到两个文件(libfoo.h, libfoo.a
)中的东西,而不是当前的一堆包含文件+二进制库。
答案 0 :(得分:9)
正如你的评论所说:
..我想让图书馆用户更容易,所以他们可以只做一个#include并拥有一切。
然后您可以花一些时间,包括所有标题在“包装”标题中,按正确的顺序。 50个标题不是那么多。做一些像:
// libfoo.h
#include "header1.h"
#include "header2.h"
// ..
#include "headerN.h"
如果您手动执行此操作,则不会花费太多时间。
此外,稍后添加新标题 - 只需几秒钟,即可将其添加到此“包装标题”中。
在我看来,这是最简单,最干净,最有效的解决方案。
答案 1 :(得分:2)
你想做什么听起来像是“javascriptish”给我:-)。但如果你坚持,总会有“猫”(或Windows中的等价物):
$ cat file1.h file2.h file3.h > my_big_file.h
或者,如果您使用的是gcc,请创建一个文件my_decent_lib_header.h,其中包含以下内容:
#include "file1.h"
#include "file2.h"
#include "file3.h"
然后使用
$ gcc -C -E my_decent_lib_header.h -o my_big_file.h
这样你甚至可以得到引用原始文件的文件/行指令(如果你愿意,可以禁用它)。
至于你的文件订单的自动化程度,嗯,它根本不是;你必须自己决定订单。事实上,我会惊讶地听到可以构建一个在C / C ++的所有情况下正确排序标头依赖关系的工具。
答案 2 :(得分:2)
(适应我的重复问题的答案:)
还有其他一些库,这些库旨在以单头形式分发,但是使用多个文件进行开发。他们也需要这样的机制。对于某些(大多数?),它是不透明的,不是分布式代码的一部分。幸运的是,至少有一个例外:Lyra,一个命令行参数解析库;它使用基于Python的包含文件融合/合并脚本,您可以找到here。
该脚本的文档记录不充分,但是您使用它们的方式是使用3个命令行参数:
--src-include
-要转换的包含文件,即将其包含指令合并到其主体中。您的情况是libfoo.h
包括其他文件。--dst-include
-要写入的输出文件-合并的结果。--src-include-dir
-指定相对于包含文件的目录(即一个目录的“包含搜索路径”;该脚本不支持C ++编译器提供的多个包含路径和搜索优先级的复杂机制优惠)该脚本具有递归作用,因此,如果file1.h
在--src-include-dir
下包含另一个文件,则该文件也应合并。
现在,我可以挑剔该脚本的代码,但是-嘿,它可以工作,并且它是FOSS-随Boost许可证一起分发。
答案 3 :(得分:1)
如果您有一个包含所有其他可用的主包含文件,您可以简单地在Perl中破解C预处理器重新实现。仅处理“”样式包括并递归粘贴这些文件的内容。应该是二十二班。
如果没有,你必须自己写一个或随机尝试。 C ++中的自动依赖关系跟踪是 hard 。就像“让我们看看这个模板实例化是否会导致参数类的隐式实例化”一样。我看到的唯一自动化方式是将您的包含文件随机排序,查看整个数据库是否编译,并重新混洗它们直到它编译。哪个会拿n!时间,你手写包含文件可能会更好。
虽然第一个变体很容易破解,但我怀疑这个hack的敏感性,因为你想要在包级别(源代码tarball,deb
包,Windows安装程序)而不是文件级别上进行分发。
答案 4 :(得分:1)
如果您的库太大而无法构建和维护像Kiril建议的单个包装头文件,这可能意味着它的架构不够好。
因此,如果您的库非常庞大(超过一百万行源代码),您可以考虑使用
等工具实现自动化。-M
-MD
-MF
等,并使用另一个手工制作的脚本对其进行排序但我不明白为什么你想要一种自动化的方法。如果库的大小合理,您应该理解它并且能够手动编写和维护包装头。自动执行该任务将花费您一些努力(可能是几周,而不是几分钟),因此仅适用于非常大的库。
答案 5 :(得分:0)
通常,您不希望将所有标题中的所有信息都包含在特殊标题中,以便潜在用户实际使用您的库。非平凡的类型定义删除,进一步包括或定义,对于您的界面的用户来说不是必需的,无法自动完成。据我所知。
对你的主要问题的简短回答:
我的建议:
手动创建一个新标题,其中包含库接口用户的所有相关信息(仅此而已)。为它包含的每个组件添加好的文档注释。
尽可能使用前向声明,而不是完整的包含定义。将实际包含放在您的实现文件中。您在标题中包含的声明越少越好。
不要构建包含深层嵌套的层次结构。这使得很难对您包含的每个位的内容进行概述。您的库的用户将查看标题以了解如何使用它。并且他可能无法区分相关代码和第一眼看不相关的代码。您希望最大化库中主标题中每个总代码的相关代码的比率。
修改强>
如果你真的有一个工具包库,并且包含的顺序无关紧要,并且你有一堆独立的标题,你想要枚举只是为了方便单个标题,那么你可以使用一个简单的脚本。像下面的Python(未经测试):
import glob
with open("convenience_header.h", 'w') as f:
for header in glob.glob("*.h"):
f.write("#include \"%s\"\n" % header)
答案 6 :(得分:0)
你真的需要一个构建脚本来在你工作时生成它,以及一个预处理器标志来禁止使用合并(可能是你的用途)。
为简化此脚本/程序,有助于获得标题结构并以最佳形式包含卫生。
您的程序/脚本需要知道您的发现路径(提示:如果可能,请尽量减少搜索路径的数量)。
运行脚本或程序(您创建)以使用头文件内容替换include指令。
假设您的标题都是典型的保护标记,您可以跟踪已实际包含的文件,如果有其他请求包含它们,则不执行任何操作。如果找不到标题,请保持原样(作为include指令) - 这是系统/第三方标题所必需的 - 除非您为外部包含使用单独的标题(这根本不是一个坏主意)
最好只包含标题的构建阶段/翻译,并产生零警告或错误(警告为错误)。
或者,您可以创建一个特殊的分发存储库,这样他们就不需要做更多的工作,而不是偶尔从中获取。
答案 7 :(得分:0)
有点晚了,但现在确实如此。我最近自己偶然发现了同样的问题并编写了这个解决方案:https://github.com/rpvelloso/oneheader
它是如何运作的?
扫描您项目的文件夹中的C / C ++标题,并创建找到的标题列表;
对于列表中的每个标头,它会分析其#include指令并按以下方式组合依赖关系图:
如果包含的标题不在项目文件夹中,则会被忽略(例如,如果它是系统标题);
如果包含的标题位于项目文件夹内,则在依赖关系图中创建边缘,将包含的标题链接到正在分析的当前标题;
- 醇>
依赖关系图在拓扑上排序,以确定将标头连接到单个文件的正确顺序。如果在图表中找到一个循环,则该过程被中断(即,如果它不是DAG);
限制:
- 目前只检测单行#include指令(例如,#include);
- 它不处理不同路径中具有相同名称的标头;
- 它只给你一个正确的顺序来组合所有标题,你仍然需要连接它们(也许你想要在合并之前删除或修改它们中的一些)。
醇>编译:
g ++ -Wall -ggdb -std = c ++ 1y -lstdc ++ fs oneheader.cpp -o oneheader [.exe]
用法:
./ oneheader [.exe] project_folder /> file_sequence.txt