【问题标题】:g++ without libstdc++ - can it be done? - a very configurable lightweight libstdc++ where I can take stuff out easily would also do the trick没有 libstdc++ 的 g++ - 可以吗? - 一个非常可配置的轻量级 libstdc++,我可以轻松取出东西也可以解决问题
【发布时间】:2010-09-15 01:57:50
【问题描述】:

我在这里尝试一些令人毛骨悚然的东西。我正在尝试编写使用 GNU 的 g++ 编译的 C++ 程序,但不依赖于 libstdc++ :) 但似乎我需要它,即使是最基本的东西也需要它。

具有可配置功能集的 libstdc++ 是可以接受的。

我使用的命令是

g++ -nodefaultlibs -fno-rtti -fno-exceptions -lc

没有 libstdc++,我得到:

undefined reference to `operator delete(void*)'  
undefined reference to `operator new(unsigned int)'  
undefined reference to `vtable for __cxxabiv1::__class_type_info'  
undefined reference to `vtable for __cxxabiv1::__si_class_type_info'  
undefined reference to `__cxa_pure_virtual'

这些不在 libc 中,那么是否有一个真正轻量级的 libstdc++ 可以实现这些东西?

我想以这种方式构建的测试代码目前如下所示:

#include <stdio.h>

template <class T>
class X
{
    public:
    T a;
};

class A1
{
    public:
        virtual void f() = 0;
        virtual ~A1() {}
};

class A2 : public A1
{
    public:
        virtual void f() {};
        virtual ~A2() {}
};

class Y
{
    public:
        ~Y() {}
};

int main()
{
    X<int> A;
    X<float> B;
    Y *C = new Y;

    A.a = 12;
    B.a = 2.3;

    printf("A: %d; B: %f\n", A.a, B.a);

    A2 *a2 = new A2;
    a2->f();

    return 0;
}

【问题讨论】:

  • 如果您可以限制自己使用 malloc/free,您甚至可以删除这些依赖项。也就是说,首先不确定您的目标是什么。
  • 我不清楚为什么 libc 可以,但 libstdc++ 不行,如果真的是这样,只需用 C 语言编写,与尝试使用任意残缺的 C++ 子集相比,您会更头疼。
  • libc 非常稳定,您通常不必担心依赖关系; libstd++ 更少。如果您在各种机器上发布 C++ 应用程序,这可能会成为一个问题。我认为您不能完全避免链接 libstd++;它需要诸如用于调用全局 ctor 的启动逻辑之类的东西。
  • @aaa carp 出于空间限制的原因,我实际上正试图摆脱 libstdc++
  • 这篇文章 (wiki.osdev.org/C%2B%2B_Bare_Bones) 提供了一些关于在内核环境中使用没有运行时支持的 C++ 的信息,或者更准确地说是让您开始编写自己的运行时支持,以及这篇文章 (wiki.osdev.org/C%2B%2B)剩下的。这是非常低级的,但也许会有用。

标签: c++ libstdc++


【解决方案1】:

是的,像 operator newoperator delete 这样的东西确实是在 C++ 中定义的,不是 在 C 中,所以将它们放在 C 的运行时库中而不是那个是荒谬的对于 C++(用于明确诊断对纯虚拟方法的错误调用的“纯虚拟”也是如此,等等)。如果您在没有动态库访问权限的情况下链接整个可执行文件,则链接器应该(希望 - 取决于 C++ 运行时库的模块化编码方式)挑选并选择您在代码中使用的标准 C++ 库的最小部分(以及您使用的 C++ 特定功能越少——例如 new 暗示 delete 用于析构函数调用等等——当然,避免拉入更大的库块的机会就越大;-)。

【讨论】:

  • 我很好奇你为什么说我在那里用纯虚拟做的事情是错误的。我只是想要一个纯虚拟来触发链接器错误,但是既然你说它是错误的,我想知道为什么,以防万一我对纯虚拟有更深入的理解问题。谢谢。
  • 这些不在 libc 中确实是有道理的,但我正在寻找一个适合我需要的 libstdc++。 IE。取出除最低限度之外的所有东西。 uClibc++ 对我眨眼。
  • @Radu,拥有纯虚拟并没有错(但没有理由错误应该出现在 link 时间!),但它需要特定于 C++ 的支持(就像 new 一样)。
  • @Alex Martelli:好吧,当使用纯虚拟时,编译器会放入一个符号,并且该符号需要链接到某些东西,这就是链接器在没有 libstdc++(其中包含表示符号)。这里没有什么奇怪的。
  • @Radu,我没有在您发布的代码中发现任何纯虚拟,这使得它不仅仅是奇怪 - 非常奇怪(我刚刚错过了吗?)。
【解决方案2】:

也许这个答案有点晚了,但是……

在没有 libstdc++ 的情况下编写 c++ 程序很容易。我这样做了几十年。 只是避免与 libstdc++ 链接。这很简单:要么使用 gcc 而不是 g++ 进行链接,要么提供一个只有 new、del 和其他一些函数的假 libstdc++。

下面是一个示例,您可以使用 malloc 周围的透明包装器替换基本的 libstdc++ 功能:

#include <stdlib.h>

// MSVC uses __cdecl calling convention for new/delete :-O
#ifdef _MSC_VER
#  define NEWDEL_CALL __cdecl
#else
#  define NEWDEL_CALL
#endif

extern "C" void __cxa_pure_virtual ()
{
    abort ();
}

void * NEWDEL_CALL operator new (size_t size)
{
    return malloc (size);
}

void * NEWDEL_CALL operator new [] (size_t size)
{
    return malloc (size);
}

void NEWDEL_CALL operator delete (void *p)
{
    if (p) free (p);
}

void NEWDEL_CALL operator delete [] (void *p)
{
    if (p) free (p);
}

void NEWDEL_CALL operator delete (void *p, size_t)
{
    if (p) free (p);
}

现在将它放入一个名为 libstd--.cpp 的文件中,然后构建您自己的 libstdc++.a:

gcc -c -O libstdc--.cpp
ar crs libstdc++.a libstdc--.o

那么你可以尝试一个简单的测试:

class A
{
    int *x;

public:
    A () { x = new int [10]; }
    ~A () { delete [] x; }
};

int main ()
{
    A a;
    return 0;
}

编译并查看链接的内容:

g++ -g test.cpp -o test -L.

# ldd ./test
    linux-vdso.so.1 (0x00007ffed0b8d000)
    libm.so.6 => /lib64/libm.so.6 (0x00007f4d18df0000)
    libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f4d18bd9000)
    libc.so.6 => /lib64/libc.so.6 (0x00007f4d18823000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f4d1913b000)

嘿,看,妈,没有 libstdc++!

作为替代方案,您可以通过使用 gcc 而不是 g++ 链接并在链接器命令行上提供 libstdc--.o 来避免使用假 libstdc++,以便您的代码可以找到替换新闻并删除。

【讨论】:

    【解决方案3】:

    尝试链接libsupc++.a。它是纯 C++ support 库,没有重量级的 iostreams 函数或任何东西。

    我不确定,但我相信使用它而不是 libstdc++.a 将获得“独立”C++ 实现,而不是标准第 1 条中定义的“托管”或完整实现。

    【讨论】:

    • 刚刚尝试链接 libsupc++.a 并没有改变任何东西。
    • 如果您查看过 libsupc++ 中的代码(不要问为什么),您会发现它更多地支持 libstdc++,而不是 C++ 运行时的子集。如果你愿意的话,它就像一个 C++ 运行时运行时,我认为它不会让你走得太远。
    • @Radu:真的吗?使用 GCC 4.2.1 g++ -nostdlib -lsupc++ -lc -lcrt1.o barenew.cpp 可以很好地编译您的代码。省略 -lsupc++ 我收到了几个与您的错误相符的错误。
    • @Logan:好吧,当我查看代码时,我看到了 operator new 和 delete (new_op.cc)、typeinfo 的 vtable (tinfo.cc)、异常支持代码等的定义。跨度>
    • @Potatoswatter:这里是 GCC 4.4.3。我将尝试 GCC 4.2.1 或类似版本,看看是否有任何改变,因为我的 GCC 到目前为止根本不喜欢 -lcrt1.o,并将其替换为 /usr/lib/crt1.o 并重新添加 - lsupc++ 不会改变任何东西。
    【解决方案4】:

    这里有一个很好的解释:

    http://www.trilithium.com/johan/2005/06/static-libstdc/

    这篇文章更详细地解释了这样做的一个关键原因 是 C++ 特定的库往往不如基本的 libc 东西稳定。 这可能有助于减少依赖性问题。

    【讨论】:

    • 我担心的不是 ABI 稳定性,因为在这种情况下,我编译了整个 Linux 发行版(嵌入式固件)。我只需要清理一些空间。如果我不能,那么 c'est la vie :) 我将不得不努力并实际修复代码:D
    • 如果您的空间非常有限,那么使用裸 C 可能是一个不错的选择。 (你可以很容易地“伪造”OOP)。
    • 如果我可以重写我想要这样做的应用程序,我就不会问这个问题了。我对一个非常可配置的 libstdc++ 持开放态度,我可以使用make menuconfig 或类似的工具取出我不需要的所有东西。
    【解决方案5】:

    另一种方法可能是“分类”您的程序。这意味着将所有库嵌入到静态可执行文件中,这样您的代码将始终使用您用于编译的机器中的 glibc。您唯一需要的是运行机器中的兼容内核。我知道有两个程序可以做到这一点,一个是开源的:

    另一个是商业软件:

    当然,这种方法有一些缺点,例如,如果您更新应用程序用来修复错误的动态库,因为在嵌入该库的可执行文件中,您将不得不再次编译您的应用程序。

    【讨论】:

    • 算了,如果您的空间非常有限,这将无法解决您的问题。
    猜你喜欢
    • 2011-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-22
    • 2018-07-21
    • 1970-01-01
    • 2011-08-27
    • 1970-01-01
    相关资源
    最近更新 更多