вызов C++ кода из C
Модератор: Olej
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
вызов C++ кода из C
Конкретная задача:
- код достаточно обстоятельной задачи, из области компьютерного зрения
- используется OpenCV
- в OpenCV есть API C & API C++ ... но API C++ намного богаче, а задача достаточно сложная...
- но и это не главное, в задаче очень много динамических объектов непредсказуемой размерности ... хотелось бы использовать STL
- вызывать хотелось бы из C-кода, 1 (2,3,...) достаточно простых итоговых вызова ... boolean признак "да/нет" на предмет распознавания некоторого образа
- и поместить этот C-код в DLL библиотеку для использования её в бэк-энде какого-то там WEB проекта.
Здесь вопрос связывания, линковки, приведение в соответствие соглашений вызовов C/C++ и заталкивание всего этого (и C++ и C) в shared DLL.
Задача чисто техническая...
- код достаточно обстоятельной задачи, из области компьютерного зрения
- используется OpenCV
- в OpenCV есть API C & API C++ ... но API C++ намного богаче, а задача достаточно сложная...
- но и это не главное, в задаче очень много динамических объектов непредсказуемой размерности ... хотелось бы использовать STL
- вызывать хотелось бы из C-кода, 1 (2,3,...) достаточно простых итоговых вызова ... boolean признак "да/нет" на предмет распознавания некоторого образа
- и поместить этот C-код в DLL библиотеку для использования её в бэк-энде какого-то там WEB проекта.
Здесь вопрос связывания, линковки, приведение в соответствие соглашений вызовов C/C++ и заталкивание всего этого (и C++ и C) в shared DLL.
Задача чисто техническая...
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: вызов C++ кода из C
Схема такая:Olej писал(а):Задача чисто техническая...
1. Код С++ в библиотеке DLL (файл child.cc):
Код: Выделить всё
#include "common.h"
int debug_level = 2;
bool predicat( test_t *t ) {
return t->level == debug_level;
}
__attribute__ ((destructor)) static void on_exit( void ) {
cout << "завершение: подчистка перед выгрузкой" << endl;
}
Код: Выделить всё
#ifndef CHILD_H
#define CHILD_H
#include <stdlib.h>
extern int debug_level;
typedef struct { // class test
char s[ 77 ];
int level;
} test_t;
#ifdef __cplusplus
#include <iostream>
using namespace std;
extern "C" {
#else
#include <stdbool.h>
#include <stdio.h>
#endif
bool predicat( test_t* );
#ifdef __cplusplus
}
#endif
#endif // CHILD_H
Код: Выделить всё
#include "common.h"
static void on_exit( void ) {
printf( "завершение процесса\n" );
}
int main( int argc, char *argv[] ) {
atexit( on_exit );
test_t t = { "", 2 };
printf( "результат: %s\n", predicat( &t ) ? "TRUE" : "FALSE" );
debug_level = 3;
printf( "результат: %s\n", predicat( &t ) ? "TRUE" : "FALSE" );
return 0;
}
Код: Выделить всё
#include "common.h"
static void on_exit( void ) {
printf( "завершение процесса\n" );
}
int main( int argc, char *argv[] ) {
atexit( on_exit );
test_t t = { "", 2 };
cout << "результат: " << ( predicat( &t ) ? "TRUE" : "FALSE" ) << endl;
debug_level = 3;
cout << "результат: " << ( predicat( &t ) ? "TRUE" : "FALSE" ) << endl;
}
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: вызов C++ кода из C
Теперь собираем всё это вместе, Makefile :Olej писал(а): Схема такая:
Код: Выделить всё
TARGET = proxi
CHILD = child
TARGETM = $(TARGET)m
TARGETA = $(TARGET)a
TARGETP = $(TARGET)p
LIB = lib$(TARGET).so
CC += -Wall -std=c99 -O3
CXX += -Wall -std=c++11 -O3
all: $(LIB) $(TARGETM) $(TARGETA) $(TARGETP)
$(LIB): $(CHILD).cc common.h
$(CXX) -c -fpic -fPIC -shared $(CHILD).cc -o $(CHILD).o
$(CXX) -shared -o $(LIB) $(CHILD).o
rm -f *.o
$(TARGETM): $(TARGET).c $(CHILD).cc common.h
$(CXX) -c $(CHILD).cc -o $(CHILD).o
$(CC) -c $(TARGET).c -o $(TARGET).o
$(CC) $(TARGET).o $(CHILD).o -lstdc++ -o $@
rm -f *.o
$(TARGETA): $(TARGET).c common.h
$(CC) $< -Bdynamic -L./ -l$(TARGET) -o $@
$(TARGETP): $(TARGET).cc common.h
$(CXX) $< -Bdynamic -L./ -l$(TARGET) -o $@
clean:
rm -f *.o $(LIB) $(TARGETM) $(TARGETA) $(TARGETP)
Код: Выделить всё
[olej@dell libcpp]$ make
g++ -Wall -std=c++11 -O3 -c child.cc -o child.o
cc -Wall -std=c99 -O3 -c proxi.c -o proxi.o
cc -Wall -std=c99 -O3 proxi.o child.o -lstdc++ -o proxim
rm -f *.o
cc -Wall -std=c99 -O3 proxi.c -Bdynamic -L./ -lproxi -o proxia
g++ -Wall -std=c++11 -O3 proxi.cc -Bdynamic -L./ -lproxi -o proxip
Код: Выделить всё
[olej@dell libcpp]$ ls *proxi*
libproxi.so proxia proxi.c proxi.cc proxim proxip
proxia - приложение на чистом C, использующем библиотеку DLL libproxi.so на C++, которая, в свою очередь, использует libstdc++.so;
proxip - приложение на C++, использующее ту же библиотеку libproxi.so;
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: вызов C++ кода из C
Olej писал(а): proxim - монолитная сборка C & C++ кодов в единое приложение, без всяких библиотек (для контроля);
proxia - приложение на чистом C, использующем библиотеку DLL libproxi.so на C++, которая, в свою очередь, использует libstdc++.so;
proxip - приложение на C++, использующее ту же библиотеку libproxi.so;
Код: Выделить всё
[olej@dell libcpp]$ ./proxim
результат: TRUE
результат: FALSE
завершение процесса
завершение: подчистка перед выгрузкой
Код: Выделить всё
[olej@dell libcpp]$ export LD_LIBRARY_PATH=.
Код: Выделить всё
[olej@dell libcpp]$ export LD_LIBRARY_PATH=`pwd`
Код: Выделить всё
[olej@dell libcpp]$ ./proxia
результат: TRUE
результат: FALSE
завершение процесса
завершение: подчистка перед выгрузкой
[olej@dell libcpp]$ ./proxip
результат: TRUE
результат: FALSE
завершение процесса
завершение: подчистка перед выгрузкой
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: вызов C++ кода из C
Внешнее имя (для link) функций а). образуется по правилам C, б). не содержит, как в C++, в имени типов параметров и возвращаемого значенияи в). может связываться как с кодом C, так и с кодом C++:Olej писал(а):А теперь используем DLL:
Код: Выделить всё
[olej@dell libcpp]$ nm libproxi.so | grep ' T '
0000000000000a20 T _fini
0000000000000820 T _init
0000000000000a10 T predicat
Код: Выделить всё
[olej@dell libcpp]$ nm libproxi.so | grep ' D '
0000000000201048 D debug_level
000000000020104c D _edata
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: вызов C++ кода из C
Т.е. подобная структура может применяться в самых разнообразных проектах:Olej писал(а): Это проделывалось (мной) для систематизации, как подготовительная часть крупного порученного мне проекта
- основной проект на C, построенный на API POSIX ...
- и узкий интерфейс (2, 3, 4... вызова) к обрабатывающей части...
- а сама обрабатывающая часть выполнена как DLL и написана на C++, но, самое главное, может использовать API обширных сторонних библиотек C++: STL, контейнеры, обощённые алгоритмы, компьютерное зрение OpenCV, регулярные выражения и т.д. и т.п.
- и даже там, где объектно-структурированные данные C++ (такие как контейнеры, или форматированные изображения) нужно передавать-возвращать между вызовами DLL, они в C-шной части (координирующей, вызывающей) просто преобразовываются к не типизированным указателям void* (так как это делается, например, при создании pthread_t).
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: вызов C++ кода из C
Во-первых, обнаружил, что не прикрепил к обсуждению готовый программный код, который обсуждается...Olej писал(а): Это проделывалось (мной) для систематизации, как подготовительная часть крупного порученного мне проекта ... но, может, как сведенное в систему, окажется и ещё кому полезным?
А это не в моих правилах.
Поэтому восполняю.
А, во-вторых, для чего и кому это может быть особенно интересно?
Для фронтэнд WEB-проектов, когда основная (т.е. вызываемая) часть этого фронтэнда написана на Go, скажем (или на Python), и нужен интерфейс к какой-то развитой библиотеке, использующей C++ - та же библиотека компьютерного зрения OpenCV, как характерный пример.
Написать из Go/Python интерфейс к коду C - не проблема, а вот к специфике C++ - довольно хлопотное дело.
И вот тут на помощь может прийти такое вот связывание.
- Вложения
-
- libcpp.tgz
- (2.65 КБ) 106 скачиваний
Кто сейчас на конференции
Сейчас этот форум просматривают: FAST WebCrawler [Crawler] и 4 гостя