g++ без libstdc++ — можно ли это сделать? - очень настраиваемая облегченная libstdc++, из которой я могу легко извлечь что-то, также поможет

Я пытаюсь сделать что-то жуткое здесь. Я пытаюсь писать программы на C++, скомпилированные с помощью GNU G++, но без зависимости от libstdc++ :) но, похоже, мне это нужно даже для самых простых вещей.

libstdС++ с настраиваемым набором функций был бы приемлем.

Я использую команду

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

Без libstdС++ я получаю:

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, так есть ли действительно легкая libstdС++, которая реализует именно эти вещи?

Мой тестовый код, который я хочу построить таким образом, в настоящее время выглядит так:

#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;
}

person Radu C    schedule 15.09.2010    source источник
comment
Если вы можете ограничить себя malloc/free, вы сможете вырезать даже эти зависимости. Тем не менее, не уверен, какова ваша цель здесь в первую очередь.   -  person Drew Hall    schedule 15.09.2010
comment
Мне непонятно, почему libc в порядке, но не libstdc++, если это действительно так, просто пишите на C, у вас будет меньше головной боли, чем пытаться использовать произвольное уродливое подмножество C++.   -  person Logan Capaldo    schedule 15.09.2010
comment
libc очень стабильна, и вам часто не нужно беспокоиться о зависимостях; libstd++ в меньшей степени. Это может быть проблемой, если вы отправляете приложения C++ на разные машины. Я не думаю, что вы можете полностью избежать связывания libstd++; ему нужны такие вещи, как логика запуска для вызова глобальных векторов и так далее.   -  person seand    schedule 15.09.2010
comment
@aaa carp Я на самом деле пытаюсь избавиться от libstdc++ из-за нехватки места   -  person Radu C    schedule 15.09.2010
comment
@Drew Hall К сожалению, malloc/free не вызывает конструкторы/деструкторы, поэтому я не могу ограничиться ими.   -  person Radu C    schedule 15.09.2010
comment
@Radu: Нет, но вы можете использовать malloc вместе с размещением new/delete (возможно). Мои мысли здесь связаны с Логаном - вероятно, будет менее сложно использовать C напрямую, если вы собираетесь до такой степени нанести вред C++. Кстати, вы можете попробовать gcc -std=c++98, чтобы получить C++ без зависимостей libstdc++.   -  person Drew Hall    schedule 15.09.2010
comment
@Drew Hall: Я, вероятно, могу возиться с operator new, поскольку он, кажется, жалуется на выделение целых чисел, но operator delete может быть немного сложным, если только void *, который он хочет, не является просто областью malloc. Это оставило бы меня с vtables (чистый виртуальный тест — это просто запоздалая мысль, и я думаю, что могу просто сделать код хуже и добавить пустые встроенные тела в эти объявления)   -  person Radu C    schedule 15.09.2010
comment
@Logan Capaldo: Хотел бы я, чтобы было так легко переписать то, что у меня есть на C. Лично я хотел бы сделать именно это, так как я поклонник C, а не поклонник C++, но это было бы довольно сложно, и если до этого дойдет, я попрошу кого-нибудь сделать это :)   -  person Radu C    schedule 15.09.2010
comment
@seand: Меня беспокоит не стабильность ABI, поскольку это для встроенного проекта, для которого я сам компилирую весь дистрибутив Linux (OpenWRT). Я просто застрял с некоторым кодом C++, который перерос устройство.   -  person Radu C    schedule 15.09.2010
comment
Что ж, код C++ не будет работать, если функции, которые он использует, не будут предоставлены средой выполнения. Либо сократите свой код C++ до чего-то гораздо более простого (и похожего на C), либо включите среду выполнения C++. (возможно, вы могли бы статически связать со средой выполнения? Это позволяет компоновщику удалить все неиспользуемые символы)   -  person jalf    schedule 16.09.2010
comment
@jalf: я открыт для легкого, очень настраиваемого с помощью make menuconfig libstdc++, который люди использовали раньше (т. Е. Они знают, что он уже работает, вместо того, чтобы гадать и молиться).   -  person Radu C    schedule 17.09.2010
comment
В этой статье (wiki.osdev.org/C%2B%2B_Bare_Bones) содержится некоторая информация по использованию C++ без поддержки среды выполнения в среде ядра или, точнее, по началу написания собственной поддержки среды выполнения, и эта статья (wiki.osdev.org/C%2B%2B) и все остальное. Это очень низкий уровень, но, возможно, это будет полезно.   -  person Jon Purdy    schedule 17.09.2010


Ответы (5)


Да, такие вещи, как operator new и operator delete, действительно определены в C++, не в C, поэтому было бы абсурдно иметь их в библиотеке времени выполнения для C, а не для C++ (то же самое для " чистый виртуальный», используемый для четкой диагностики неправомерных вызовов чисто виртуальных методов и т. д.). Если вы компонуете весь свой исполняемый файл без доступа к динамической библиотеке, компоновщик должен (надеюсь, в зависимости от того, насколько модульно закодирована библиотека времени выполнения C++) выбирать и выбирать самую минимальную часть стандартной библиотеки C++, которую вы используете в своем коде (и чем меньше специфических функций C++ вы используете, таких как new, подразумевающий delete для вызовов деструктора и т. д., тем больше у вас шансов избежать извлечения больших кусков библиотеки, конечно;-).

person Alex Martelli    schedule 15.09.2010
comment
Мне любопытно, почему вы говорите, что то, что я сделал с чистым виртуальным, было неправомерным. Я просто хотел чистый виртуальный, чтобы вызвать ошибку компоновщика, но, поскольку вы говорите, что это неправомерно, интересно, почему, на тот случай, если у меня есть более глубокое понимание проблемы чистых виртуальных. Спасибо. - person Radu C; 15.09.2010
comment
Имеет смысл, что их нет в libc, но я ищу libstdc++, который я адаптирую под свои нужды. т.е. брать все кроме минимума. uClibc++ подмигивает мне. - person Radu C; 15.09.2010
comment
@Radu, нет ничего плохого в том, чтобы иметь чистый виртуальный (но нет причин, по которым ошибка должна быть во время link!), но для этого потребуется поддержка, специфичная для C++ (точно так же, как new будет). - person Alex Martelli; 15.09.2010
comment
@Alex Martelli: Ну, есть символ, который компилятор вставляет при использовании чистого виртуального, и этот символ нужно с чем-то связать, поэтому компоновщик не работает без libstdc++ (который содержит указанный символ). Здесь нет ничего странного. - person Radu C; 15.09.2010
comment
@Radu, я не заметил ни одного чистого виртуального в вашем опубликованном коде, что делает его более чем странным - определенно странным (я только что пропустил это?). - person Alex Martelli; 15.09.2010
comment
@Alex, извини за это: D Я думал, что разместил тот, который был чисто виртуальным. Я удалил его непосредственно перед тем, как скопировать код. Это было virtual void f() = 0 в class A1, так что я внесу это редактирование сейчас. - person Radu C; 15.09.2010

Может быть, этот ответ немного запоздал, но...

Писать программы на С++ без libstdС++ легко. Я делаю это десятилетиями. Просто избегайте связывания с libstdc++. Это просто: либо используйте для линковки gcc вместо g++, либо предоставьте поддельную libstdc++ только с новыми, del и некоторыми другими функциями.

Вот пример того, как вы можете заменить базовую функциональность libstdc++ прозрачной оболочкой для malloc:

#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++!

В качестве альтернативы вы можете избежать использования фальшивого libstdc++, связавшись с gcc вместо g++ и указав libstdc--.o в командной строке компоновщика, чтобы ваш код мог найти замену news и удалить.

person Andrey Zabolotnyi    schedule 03.11.2018

Попробуйте связать с libsupc++.a. Это голая библиотека C++ support, без тяжеловесных функций iostreams или чего-то подобного.

Я не уверен, но я полагаю, что использование этого вместо libstdc++.a позволит получить «автономную» реализацию C++, в отличие от «размещенной» или полной реализации, как определено в пункте 1 стандарта.

person Potatoswatter    schedule 15.09.2010
comment
Только что попробовал связать с libsupc++.a, ничего не изменилось. - person Radu C; 15.09.2010
comment
Если вы смотрели на код в libsupc++ (не спрашивайте почему), вы увидите, что поддержка libstdc++ больше, чем подмножество среды выполнения C++. Это похоже на среду выполнения C++, если хотите, и я не думаю, что это поможет вам далеко продвинуться. - person Logan Capaldo; 15.09.2010
comment
@Раду: Правда? Использование GCC 4.2.1 g++ -nostdlib -lsupc++ -lc -lcrt1.o barenew.cpp отлично компилирует ваш код. Опуская -lsupc++, я получаю несколько ошибок, совпадающих с вашими. - person Potatoswatter; 15.09.2010
comment
@Logan: Ну, когда я смотрю на код, я вижу определения для операторов new и delete (new_op.cc), vtable typeinfo (tinfo.cc), код поддержки исключений и т. д. - person Potatoswatter; 15.09.2010
comment
@Potatoswatter: GCC 4.4.3 здесь. Я попробую GCC 4.2.1 или аналогичный и посмотрю, изменит ли это что-нибудь, так как мой GCC пока вообще не любит -lcrt1.o, и заменив его на /usr/lib/crt1.o и повторно добавив - lsupc++ ничего не меняет. - person Radu C; 15.09.2010
comment
@Radu: Похоже, я использовал -nostdlib, а вы использовали -nodefaultlibs, что объясняет разницу с -crt1.o. - person Potatoswatter; 15.09.2010
comment
@Potatoswatter: тоже пробовал это, в итоге появилось больше ошибок компоновщика, например undefined reference to '_Unwind_Resume'. Я все еще не пробовал GCC 4.2.1. - person Radu C; 16.09.2010
comment
@Radu: Звучит очень странно. Возможно, что-то происходит с вашими путями к библиотеке, когда она просто не загружает эту библиотеку. Несоответствие версий или что-то в этом роде. - person Potatoswatter; 16.09.2010

Вот хорошее объяснение:

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

В статье объясняется более подробно, но одной из основных причин для этого является то, что специфичные для C++ библиотеки имеют тенденцию быть менее стабильными, чем базовый материал libc. Это может помочь уменьшить проблемы с зависимостями.

person seand    schedule 15.09.2010
comment
Меня беспокоит не стабильность ABI, так как в этом случае я компилирую весь дистрибутив Linux (встроенную прошивку). Мне просто нужно освободить место. Если я не могу, то c'est la vie :) Придется пойти трудным путем и реально исправить код :D - person Radu C; 15.09.2010
comment
Если вы очень ограничены в пространстве, использование C может быть хорошим выбором. (вы можете легко «подделать» ООП). - person seand; 15.09.2010
comment
Если бы я мог просто переписать приложение, для которого хочу это сделать, я бы не задавал этот вопрос. Я открыт для очень настраиваемой libstdС++, где я могу вынуть все, что мне не нужно, используя make menuconfig или подобное. - person Radu C; 15.09.2010

Другой подход может состоять в том, чтобы "статифицировать" вашу программу. Это означает встроить все библиотеки в статический исполняемый файл, и таким образом ваш код всегда будет использовать glibc, который был в машине, которую вы использовали для компиляции. Единственное, что вам нужно, это совместимое ядро ​​​​на работающей машине. Я знаю две программы для этого, одна с открытым исходным кодом:

а другой - коммерческое программное обеспечение:

Конечно, у этого подхода есть недостатки, например, если вы обновляете динамическую библиотеку, которую ваше приложение использует для исправления ошибки, потому что в исполняемый файл встроена эта библиотека, вам придется снова компилировать ваше приложение.

person javier-sanz    schedule 16.09.2010
comment
забудьте об этом, если вы очень ограничены в пространстве, это не решит вашу проблему. - person javier-sanz; 16.09.2010