Как заставить g ++ встроенных функций?

Недавно я столкнулся с проблемой встроенных функций C ++ при использовании Haskell FFI для C / C ++.
А именно, g ++ на самом деле не встроенные функции, которые объявлены inlineи генерировать символы для них. В конечном итоге это приводит к ошибке компоновщика, когда ghci пытается загрузить объектный файл, который вызывает встроенную функцию:

Loading object (static) solveeq.o ... done
Loading object (dynamic) /usr/lib/gcc/x86_64-linux-gnu/4.6/libstdc++.so ... done
final link ... ghc: solveeq.o: unknown symbol `_ZN5Eigen8internal19throw_std_bad_allocEv'

Вот, _ZN5Eigen8internal19throw_std_bad_allocEv является inline Функция в библиотеке Eigen C ++ только для заголовков рассматривается как реальная функция и получает символ компоновщика. solveeq.o мой объектный файл, который делает (косвенные) вызовы этой функции. Средой является Ubuntu 12.04 64bit, ghc 7.4.1.

Вопрос заключается в следующем: я могу использовать extern "C" чтобы предотвратить C ++ украшение имен функций для моих собственных функций. Но я не могу / не должен изменять заголовки C ++, определенные другими (по понятным причинам). По моему мнению, компилятор не должен создавать функцию для этого встроенного определения, во-первых, чтобы вызвать эту ошибку. Причина проста. Если рассматриваемая функция действительно встроена, я не получу ошибку компоновщика. Если компилятор становится умным и решает создать для него реальную функцию, я получаю такие ошибки (или несколько определений одной и той же функции, как я читал в другом месте). Так что теперь правильность компиляции / компоновки зависит от настроения компилятора.

Кроме того, я думаю, что такие проблемы компоновщика практически побеждают библиотеки C ++ только для заголовков (которые привлекают своей переносимостью), потому что теперь их нельзя экспортировать с помощью extern "C",

Это проблема проектирования c ++ или проблема g ++? Мой вопрос заключается в том, есть ли способ предотвратить компиляторы C ++ или G ++ не встраивать встроенные функции? Например, есть ли опция командной строки для этого? (Изменение исходных кодов не подлежит обсуждению, поскольку они являются библиотечными кодами.)

Также мне интересно, как C ++ STL справляется с этой проблемой. Они также только для заголовков?

9

Решение

Функции быть inline это подсказка компиляторам, которую компилятор с радостью проигнорирует, когда посчитает нужным. Некоторые компиляторы делают предупреждение о объявленных функциях inline но не будучи встроенным, например НКУ«s -Winline, но отключение всех встроенных функций обязательно будет неработоспособным: есть несколько довольно значительных функций, работающих со структурами данных, которые определены как шаблоны. Весь код шаблона, который неявно может быть встроенным, и экземпляры этого шаблона могут передаваться в нескольких единицах перевода.

Вместо того, чтобы пытаться использовать поведение C ++ с целью интеграции его с каким-либо другим инструментом, другой инструмент должен умничать и игнорировать символы, которые ему не интересны. В частности, если он действительно не заинтересован в нежелательных экземплярах inline функции, он должен просто игнорировать их. Так как они могут появляться в нескольких единицах перевода, они обычно используют слабые символы. Когда вы используете nm -po your-object-file.o в системе UNIX и grep для символов, которыми ваш инструмент оскорблен, вы должны увидеть их помеченными с помощью символов, отличных от обычных символов (T).

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

3

Другие решения

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

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

widget_decl_fwd.H:

template<typename C> void widget(C c_arg);

А потом:

widget_decl_impl.H:

template<typename C> void widget(C c_arg)
{
// Whatever widget() needs to do, here
}

Тогда вы невинно идете и пишете:

widget_factory.C:

#include "widget_decl_fwd.H"
void make_widgets(int n)
{
widget(n);
}

Затем вы пытаетесь скомпилировать это. Он будет хорошо скомпилирован, но не сможет связать. Компилятор видел объявление функции шаблона, но не ее определение. Итак, компилятор сделал вызов widget () ссылкой на внешний символ. Если так получилось, что какой-то другой модуль, который был связан вместе, извлек в объявлении, создал экземпляр функции шаблона и экспортировал правильный символ, ссылка может просто успешно завершиться, но, скорее всего, произойдет сбой из-за неразрешенного символа.

В этом контексте встроенные функции аналогичны шаблонам. Таким образом, компоновщик жалуется на неразрешенный символ из solveeq.C

Это означает, что вам нужно проверить, что solveeq.C включает в себя и проверяет, что оно фактически извлекает фактическое определение этой встроенной функции или шаблона, а не только его объявление, откуда-то. Если включения заголовка сбивают с толку, используйте опцию -E и получите вывод grep.

2

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

Невозможность загрузить слабые символы это давняя ошибка GHCi. Это исправлено в версии 7.8.1 (я проверил 7.8.3). Просто обновите свой GHC, и проблема исчезнет.

Если вы не можете обновить GHC, вы можете создать общую библиотеку и указать GCC скрыть встроенные функции. Это сделано с -fvisibility-inlines-hidden флаг. Я проверил с GHCi 7.0.1, что этот метод действительно работает. Возможно, вам придется указать абсолютный путь к вашему общему объекту (т.е. ghci /full/path/to/your.so) или поместите общий объект в какое-то место, где его может найти динамический загрузчик. Относительные пути не работают по некоторым причинам.

2

Если вы не хотите встроенных функций, есть опция

-fno-inline

«Не расширяйте никакие встроенные функции, кроме тех, которые отмечены атрибутом Always_inline. Это значение по умолчанию, когда не выполняется оптимизация»

Существует также больше контроля над размером встроенной функции

-finline-limit=n

где n это количество инструкций

1
По вопросам рекламы [email protected]