Динамическое приведение возвращает ноль, когда библиотека с расширениями Python C ++ используется в качестве плагина на RHEL5 - PullRequest
0 голосов
/ 26 февраля 2011

У меня есть библиотека с расширениями Python C ++ (C ++ вызывает python, который, в свою очередь, вызывает C ++) с использованием библиотек boost :: python и python (это грязно, но во многом является устаревшим), которая при тестировании автономно работает правильно. В частности, определенный dynamic_cast работает правильно.

Но когда библиотека упакована для использования в качестве плагина на RHEL5 с использованием gcc 4.1.2 с внешним приложением, dynamic_cast возвращает NULL, в результате чего приложение не работает должным образом. В Windows (тестирование Vista 64 bit с использованием Visual Studio 2005 и 2008) работает нормально. Когда я отлаживаю с использованием, например, DDD, я могу видеть, что указатель перед приведением имеет правильное имя типа (слегка искаженное компилятором, как обычно, я полагаю?). Любые конкретные советы по отладке здесь также будут полезны.

Reinterpret_cast решил проблему. Хотя это, безусловно, будет сбито с толку, я не знаю, как поступить, особенно. так как это может быть связано с проблемами с внешним приложением. Это запутанный беспорядок и кажется почти бесполезным, но если это поможет, вот пример кода. Следующий фрагмент кода C ++ создает «smart_handle» для постановки в очередь определенных команд Python, хранящихся в строке «input». Строка IMPORT импортирует местоположения и определения некоторых функций, которые вызываются boost :: python :: exec (..) в вызове функции py_api :: execute_py_command:

boost::shared_ptr<my_base_class> 
         processor(new my_derived_class());
std::map<std::string, smart_handle> context;
context.insert(std::make_pair<std::string, smart_handle>("default_queue", 
               make_smart_handle(processor)));
const std::string py_command =
       IMPORT + 
       "namesp.dialects.cpython.set_command_queue('default', default_queue)\n" + 
       input;
if( !py_api::execute_py_command(py_command, context) ) {
  return false; 
}

make_smart_handle определяется как:

template <typename type_t> 
const smart_handle make_smart_handle(const boost::shared_ptr<type_t>& ptr) {
   if( !ptr ) {
      return smart_handle();
   }
   return smart_handle(new detail::smart_handle_weak_impl<type_t>(ptr));
}

Функция set_command_queue определена в питоне __init__.py как:

import func1 
import func2
import func3
import func4

COMMAND_QUEUE_MAP = {}
def set_command_queue(queue_name, object):
COMMAND_QUEUE_MAP[queue_name] = object
def get_command_queue(queue_name = 'default'):
return COMMAND_QUEUE_MAP[queue_name]

Теперь фактические функции python func1, func2 и т. Д., Определенные в отдельных файлах python, вызывают функции C ++, определенные в пространстве имен «namesp». Самая первая строка этих функций C ++ состоит в том, чтобы восстановить «smart_handle» в «очередь» следующим образом:

boost::shared_ptr<my_base_class> queue = smart_handle_cast<my_base_class>(handle).lock();

Именно в вышеуказанной функции smart_handle_cast используется dynamic_cast, который возвращает NULL, когда библиотека используется в качестве плагина во внешнем приложении. Использование reinterpret_cast позволяет ему работать правильно. Smart_handle_cast возвращает const boost :: weak_ptr. Для тех, кто заинтересован, вот определение функции smart_handle_cast <..> ():

template <typename type_t> 
const boost::weak_ptr<type_t> smart_handle_cast(const smart_handle& handle, bool 
      throw_if_failure) {
   if( !handle.is_valid() ) {
       if( throw_if_failure ) {
          throw smart_handle::bad_handle("Bad handle, attempting to access an invalid 
                                          handle");
       }
       //-No throw version returns a non-initialized weak pointer
       return boost::weak_ptr<type_t>();
   }
   //-This line fails at run time and returns null.
   const detail::smart_handle_weak_impl<type_t>* casted = dynamic_cast<const 
                   detail::smart_handle_weak_impl<type_t>* >(handle.impl());
   if( !casted ) {
       if( throw_if_failure ) {
           throw smart_handle::bad_handle_cast("Bad handle cast, attempting to \
              convert to incorrect pointee type");
       }
       //-No throw version returns a non-initialized weak pointer
       return boost::weak_ptr<type_t>();
   }
   return casted->pointee;
}

1 Ответ

0 голосов
/ 26 февраля 2011

Взгляните на аналогичный вопрос и GCC FAQ

Если вы используете dlopen для явной загрузки кода из общей библиотеки, вы должны сделать несколько вещей. Сначала экспортируйте глобальные символы из исполняемого файла, связав его с флагом «-E» (вам нужно будет указать это как «-Wl, -E», если вы вызываете компоновщик обычным способом из драйвера компилятора, g ++) , Вы также должны сделать внешние символы в загруженной библиотеке доступными для последующих библиотек, предоставив флаг RTLD_GLOBAL для dlopen. Разрешение символа может быть немедленным или ленивым.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...