通过在实际 C/C++ 源文件中包含预处理器构建指令来编译 C/C++ 代码

use*_*076 0 programming gcc c++ linker static-linking

我有理由不想依赖特定的构建系统。我并不是要否定任何人的最爱,但我真的只想坚持编译器附带的内容。在这种情况下,GCC。Automake 有一定的兼容性问题,尤其是在 Windows 上。<3 GNU make 是如此有限以至于它经常需要用 shell 脚本来补充。Shell 脚本可以有多种形式,长话短说,可能会激怒很多人,这就是我想要做的——

主要的切入点是上帝。无论是 C 还是 C++ 源文件,它都是应用程序的中心。我不仅希望主入口点是第一个被执行的东西,我还希望它是第一个被编译的东西。让我解释 -

曾经有一段时间,专有库和闭源库很常见。多亏了苹果转向 Unix 和微软在脚下开枪,那个时代结束了。任何需要动态链接的库都可以作为应用程序的支持文件包含在内。出于这个原因,单独的 .SOs(可能还有 .DLLs ;])的构建指令都很好而且很花哨,因为它们是单独的可执行文件。任何其他库都应该静态链接。现在,让我们谈谈静态链接——

静态链接是一个真正的婊子。这就是 makefile 的用途。如果整个项目是用一种语言编写的(例如 C 或 C++),您可以将库作为头文件#include。那很好。但是现在,让我们考虑另一种情况——

假设你和我一样,无法找出 C 对字符串的困难借口,所以你决定使用 C++。但是您想使用 C 库,例如 MiniBasic。上帝帮助我们。如果 C 库的设计不符合 C++ 的语法,那你就完蛋了。这就是 makefile 出现的时候,因为您需要使用 C 编译器编译 C 源文件,并使用 C++ 编译器编译 C++ 源文件。我不想使用makefile。

我希望有一种方法可以利用 GCC 的预处理器宏来告诉它如下内容:

嗨,海合会。你好吗?如果您忘记了,您现在正在查看的这个源文件是用 C++ 编写的。你当然应该用 G++ 编译它。这个文件需要另一个文件,但它是用 C 编写的。它被称为“locats.c”。我想让你用 GCC 把那个编译成一个目标文件,我想让你用 G++ 把这个编译成主目标文件,然后我想让你把它们链接成一个可执行文件。

我怎么能用预处理器行话写这样的东西?海湾合作委员会甚至这样做吗?

War*_*ung 6

主要的切入点是上帝。无论是 C 还是 C++ 源文件,它都是应用程序的中心。

就像氮是松树的中心一样。它是一切开始的地方,但 C 或 C++ 并没有让您将应用程序的“中心”放在main().

许多 C 和 C++ 程序都建立在事件循环I/O 泵上。这些是此类程序的“中心”。你甚至不用把这些循环相同的模块作为main()

我不仅希望主入口点是第一个被执行的东西,我还希望它是第一个被编译的东西。

main() 最后放在 C 或 C++ 源文件中实际上是最容易的。

C 和 C++ 不像某些语言,可以在声明之前使用符号。把main()你必须先手段前瞻性声明一切。

曾经有一段时间,专有库和闭源库很常见。多亏了苹果转向 Unix 和微软在脚下开枪,那个时代结束了。

告诉‘我在做梦’!

OS X 和 iOS充满了专有代码,微软不会很快消失。

无论如何,Microsoft 当前的困难与您的问题有什么关系?您说您可能想要制作 DLL,并且您提到 Automake 无法有效处理 Windows。这告诉我微软在你的世界中也仍然重要。

静态链接是一个真正的婊子。

真的吗?我一直发现它比链接到动态库更容易。这是一种更古老、更简单的技术,出错的地方更少。

静态链接将外部依赖项合并到可执行文件中,因此可执行文件是独立的、自包含的。从您的其余问题来看,这应该会吸引您。

你可以 #include 库作为标题

不...您是#include 库标题,而不是库。

这不仅仅是迂腐。术语很重要。它是有意义的。

如果你可以#include图书馆,#include </usr/lib/libfoo.a>会工作。

在许多编程语言中,这就是外部模块/库引用的工作方式。也就是说,您直接引用外部代码。

C 和 C++ 不属于以这种方式工作的语言。

如果 C 库的设计不符合 C++ 的语法,那你就完蛋了。

不,您只需要学习使用 C++。具体在这里,extern "C"

我怎么能用预处理器行话写这样的东西?

对于#include另一个 C 或 C++ 文件是完全合法的:

#include <some/library/main.cpp>

#include <some/other/library/main.c>
#include <some/other/library/secondary_module.c>

#include <iostream>

int main()
{
   call_the_library();
   do_other_stuff();
   return 0;
}
Run Code Online (Sandbox Code Playgroud)

我们不在extern "C"这里使用,因为这会将其他库中的 C 和 C++ 代码直接提取到我们的 C++ 文件中,因此 C 模块也需要是合法的 C++。C 和 C++ 之间有许多令人讨厌的小差异,但是如果您要混合使用这两种语言,则无论如何都必须知道如何处理它们。

这样做的另一个棘手部分是,#includes如果是链接器命令,则 的顺序比库引用的顺序更敏感。当您以这种方式绕过链接器时,您最终必须手动完成一些链接器原本会自动为您完成的工作。

为了证明这一点,我采用了MiniBasic(您自己的示例)并将其script.c驱动程序转换为一个独立的 C++ 程序,该程序#include <basic.c>不是#include <basic.h>. ( patch ) 现在只是为了证明它确实是一个 C++ 程序,我将所有printf()调用更改为cout流插入。

我不得不做一些其他的改变,对于那些打算混合 C 和 C++ 的人来说,所有这些都在正常的一天工作中完成:

  1. MiniBasic 代码利用了 C 允许从void*任何其他指针类型自动转换的意愿。C++ 让你变得明确。

  2. 较新的编译器不再允许"Hello, world!\n"char*上下文中使用 C 字符串常量(例如)。该标准说允许编译器将它们放入只读内存中,因此您需要使用const char*.

就是这样。只需几分钟即可解决 GCC 投诉。

我必须对basic.c链接的script.c补丁文件中的更改进行一些类似的更改。我没有费心发布差异,因为它们更相似。

另一种方法是研究SQLite Amalgamation,与SQLite 源代码树相比。SQLite 不会将#include所有其他文件都使用到一个主文件中;它们实际上是连接在一起的,但#include在 C 或 C++ 中也是如此。