没有标准库的准系统 C++?
Barebones C++ without standard library?
GCC 和 Clang 等编译器允许在没有 C++ 标准库的情况下编译 C++ 程序,例如使用 -nostdlib
命令行标志。好像这样的经常不行link你,例如:
void f() noexcept { throw 42; }
int main() { f(); }
通常由于 __cxa_allocate_exception
、typeinfo for int
、__cxa_throw
、__gxx_personality_v0
、__clang_call_terminate
、[= 等未定义符号而无法 link 18=]、std::terminate()
等
即使是简单的
int main() {}
无法 link
ld: warning: cannot find entry symbol _start
; defaulting to 0000000000400120
并在执行时被 OS 杀死。使用 -c
编译器仍然运行 linker,它公然失败:
ld: error in mytest
(.eh_frame
); no .eh_frame_hdr
table will be created.
在不使用和 link 标准库的情况下编写和编译 C++ 应用程序或库是否是一个现实的目标?如何在 Linux 上使用 GCC 或 Clang 编译我的代码?如果没有标准库,哪些核心语言功能将无法使用?
您基本上会在 osdev.org 找到您所有问题的答案,但无论如何我都会给出一个简短的总结。
当你给 GCC -nostdlib
时,你说的是 "no startup or library files"。这包括:
crti.o
、crtbegin.o
、crtend.o
和 crtn.o
。通常内核开发人员只关心实现 crti.o
和 crtend.o
并让 GCC 通过将 -print-file-name=
传递给链接器来提供 crtbegin.o
和 crtend.o
。通常这些只是分别由 .init
和 .fini
组成的存根,为 GCC 分别推送 crtbegin.o
和 crtend.o
的内容留出空间。这些文件是调用全局 constructors/destructors 所必需的。
- 您无法避免链接
libgcc
(the "low-level runtime library" (-lgcc
) because even if you pass -nostdlib
GCC will emit calls to its functions whenever you use it, leading to inexplicable linking errors for seemingly no reason. This is the case even when you're implementing/porting a C library。
- 您不需要 "need"
libstdc++
不,但通常内核开发人员需要它。 Porting a C library 那么从头开始实现 C++ 标准库是一项极其困难的任务。
由于您只想摆脱 "standard library",但保留 libc(在 Linux 系统上),您实际上只是在使用 C 库对 C++ 进行编程。当然,这没有错,你做你,但最终我不明白这一点,除非你打算开发内核。
必读:
OSDev's C++ page - If you really care about RTTI/exception support, it's more annoying to implement than it sounds。通常人们只是通过 -fno-rtti
或 -fno-exceptions
然后担心它是否在线。
"Standard" 是用词不当。在这种情况下,它并不意味着 "the library (set of functions, classes etc) as defined by the C++ standard",而是 "the usual set of libraries and objects (compiled files in a certain format) gcc links with by default"。其中一些是大多数甚至所有程序运行所必需的。
如果您使用此标志,则您有责任提供任何缺失的功能。有几种方法可以这样做:
- 从默认集合中挑选出您的程序真正需要的库和对象。 (没有什么意义,因为结果很可能与默认的 link 标志完全相同)。
- 提供您自己的缺失功能实现。
- 通过编译器标志明确禁用您的程序未使用的语言功能。我知道有两个这样的特性:异常和 RTTI。这是必需的,因为编译器需要生成与异常相关的代码和 RTTI 信息,即使这些功能未明确使用在此模块。
GCC 和 Clang 等编译器允许在没有 C++ 标准库的情况下编译 C++ 程序,例如使用 -nostdlib
命令行标志。好像这样的经常不行link你,例如:
void f() noexcept { throw 42; }
int main() { f(); }
通常由于 __cxa_allocate_exception
、typeinfo for int
、__cxa_throw
、__gxx_personality_v0
、__clang_call_terminate
、[= 等未定义符号而无法 link 18=]、std::terminate()
等
即使是简单的
int main() {}
无法 link
ld: warning: cannot find entry symbol
_start
; defaulting to 0000000000400120
并在执行时被 OS 杀死。使用 -c
编译器仍然运行 linker,它公然失败:
ld: error in
mytest
(.eh_frame
); no.eh_frame_hdr
table will be created.
在不使用和 link 标准库的情况下编写和编译 C++ 应用程序或库是否是一个现实的目标?如何在 Linux 上使用 GCC 或 Clang 编译我的代码?如果没有标准库,哪些核心语言功能将无法使用?
您基本上会在 osdev.org 找到您所有问题的答案,但无论如何我都会给出一个简短的总结。
当你给 GCC -nostdlib
时,你说的是 "no startup or library files"。这包括:
crti.o
、crtbegin.o
、crtend.o
和crtn.o
。通常内核开发人员只关心实现crti.o
和crtend.o
并让 GCC 通过将-print-file-name=
传递给链接器来提供crtbegin.o
和crtend.o
。通常这些只是分别由.init
和.fini
组成的存根,为 GCC 分别推送crtbegin.o
和crtend.o
的内容留出空间。这些文件是调用全局 constructors/destructors 所必需的。- 您无法避免链接
libgcc
(the "low-level runtime library" (-lgcc
) because even if you pass-nostdlib
GCC will emit calls to its functions whenever you use it, leading to inexplicable linking errors for seemingly no reason. This is the case even when you're implementing/porting a C library。 - 您不需要 "need"
libstdc++
不,但通常内核开发人员需要它。 Porting a C library 那么从头开始实现 C++ 标准库是一项极其困难的任务。
由于您只想摆脱 "standard library",但保留 libc(在 Linux 系统上),您实际上只是在使用 C 库对 C++ 进行编程。当然,这没有错,你做你,但最终我不明白这一点,除非你打算开发内核。
必读:
OSDev's C++ page - If you really care about RTTI/exception support, it's more annoying to implement than it sounds。通常人们只是通过 -fno-rtti
或 -fno-exceptions
然后担心它是否在线。
"Standard" 是用词不当。在这种情况下,它并不意味着 "the library (set of functions, classes etc) as defined by the C++ standard",而是 "the usual set of libraries and objects (compiled files in a certain format) gcc links with by default"。其中一些是大多数甚至所有程序运行所必需的。
如果您使用此标志,则您有责任提供任何缺失的功能。有几种方法可以这样做:
- 从默认集合中挑选出您的程序真正需要的库和对象。 (没有什么意义,因为结果很可能与默认的 link 标志完全相同)。
- 提供您自己的缺失功能实现。
- 通过编译器标志明确禁用您的程序未使用的语言功能。我知道有两个这样的特性:异常和 RTTI。这是必需的,因为编译器需要生成与异常相关的代码和 RTTI 信息,即使这些功能未明确使用在此模块。