Lazarus (GUI) + C++ (engine)

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Re: Lazarus (GUI) + C++ (engine)

Сообщение CRobin » 25.03.2016 02:25:02

скалогрыз общая идея понятна. Я сомневаюсь, что кроме конвертируемых в/из С типов, что то будет коректно передаваться, разве что самому декодировать данные, но это уже явный перебор. Не могли бы вы накидать пример кода для С++, который можно будет скомпилировать как объектный файл? Мне нужно реализовать в Lazarus примерно такую схему:

Код: Выделить всё
{$L parser.o} // Объектный файл с функцией
function parser_set_env(s: string): boolean; cdecl; external; // Функция задания параметров парсера
function parser_get_process(a: array of byte; var i: integer; d: double; s: string; b: boolean): cint; cdecl; external; // Сам парсер принимает массив байтов, возвращает 4 С-совместимых значения

parser_set_env("scheme.conf");

for n:= 0 to 99 do parser_get_process(source[n], res[n].i, res[n].d, res[n].s, res[n].b);


И еще, должен ли компилятор поддерживать такой тип программ как объектный файл? Я поставил NetBeans c компилятором Cygwin, это подойдет или нужен только GCC?
CRobin
постоялец
 
Сообщения: 145
Зарегистрирован: 26.01.2016 12:15:39

Re: Lazarus (GUI) + C++ (engine)

Сообщение скалогрыз » 25.03.2016 06:25:47

CRobin писал(а):Не могли бы вы накидать пример кода для С++, который можно будет скомпилировать как объектный файл?

любой .cpp превращается в объектный файл. Именно из набора объектных файлов компонуются всяческие .dll, .so, .exe и т.д.
Код: Выделить всё
extern "C" {
int Sample(int b)

  return b + 8;
}
}

Лучше покажи, что у тебя в заготовках, а лучше в заголовках :D

CRobin писал(а):Мне нужно реализовать в Lazarus примерно такую схему:

не используй тип "string". Си его не поймёт, используй PChar, который char *

так вот:
Код: Выделить всё
function parser_set_env(s: PChar): LongBool; cdecl; external; // Функция задания параметров парсера
function parser_get_process(const a: array of byte; var i: integer; var d: double; var b: boolean; s: PChar; slen: integer): integer; cdecl; external;

память, которую может выделить Си/Си++ модуль под строку, паскаль скорей всего не сможет освободить правильно. По-этому, самым надёжным способом это выделить буфер на стороне паскале, а Си функцию просто передать указатель на буфер (и размер буфера!)

Открытый массив const a: array of byte, на Си транслируется как указатель + размер
Код: Выделить всё

int parser_get_process(void * a, int alen, int * i, double *d, bool* b, char * s, int slen)


CRobin писал(а):Я поставил NetBeans c компилятором Cygwin, это подойдет или нужен только GCC

в cygwin-е, должен быть gcc. Но если исходники планируются быть закрытыми, то я настойчиво не рекомендую использовать Cygwin, т.к. он компилирует файлы защищённые GPL и привязанные к cygwin run-time-у.
лучше поставить MinGW!
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

Re: Lazarus (GUI) + C++ (engine)

Сообщение CRobin » 26.03.2016 03:17:25

скалогрыз писал(а):любой .cpp превращается в объектный файл. Именно из набора объектных файлов компонуются всяческие .dll, .so, .exe и т.д.


Если в вашем примере вместо 8 будет некая глобальная (в рамках С-модуля) переменная, как тогда должно выглядеть содержимое исходника для С++?

С остальным надо пробовать, пока вроде понятно.
CRobin
постоялец
 
Сообщения: 145
Зарегистрирован: 26.01.2016 12:15:39

Re: Lazarus (GUI) + C++ (engine)

Сообщение скалогрыз » 26.03.2016 03:55:47

CRobin писал(а):Если в вашем примере вместо 8 будет некая глобальная (в рамках С-модуля) переменная, как тогда должно выглядеть содержимое исходника для С++?

вот пример "с нуля". делаю в линухе, т.к. мингв ставить не хочу, а на маке свои тонкости.

1. написать С++ исходник, называется он my.cpp
Код: Выделить всё
int global = 8; // глобальная переменная! специально вынес её вне extern "C"

extern "C" {

int sample(int a)
{
  return  a + global;
}
}

2) нужно скомпилировать исходник, чтобы получить объектный файл.
Код: Выделить всё
gcc -c my.cpp

использование ключика "-c" критично, иначе он может подумать, что тебе нужно экзе файл или ещё чего-нибудь
Ожидается, что файл скомпилируется без ошибок, и просто появится my.o файл.
3) нужно написать паскаль программу, которая будет его использовать. имя файла test.pas. (в той же директории, где находится my.o)
Код: Выделить всё
{$l my.o} // линкуем объектный файл

// описываем функцию
function sample(a: integer): integer; cdecl; external;

// программа!
begin
  writeln(sample(2));
end.

4) компилируем
Код: Выделить всё
fpc test.pas

5) запускаем!
Код: Выделить всё
$ ./test
10


вот и всё!

На что обратить внимание:
1) умолчания компилятора. Не исключено, что по-умолчанию gcc может компилировать под x64, тогда, как нужна i386. И FPC может собирать по-умолчнию под ту же i386. А 64-битный объектный файл с 32-битной программой не сработается :)
2) зависимости! Если парсер зависит от дополнительных библиотек (например libc, lmath или ещё что-нибудь), то придётся линковать и зависимости тоже! С ними может быть проще, т.к. они могут входить в стандратный набор библиотек и уже находяся в нужном виде (либо .o либо .a). Просто нужно будет скопировать в папку с проектом, либо добавить их папку в пути поиска библиотек
Приведённый выше пример, ни от какой дополнительной библиотеки на зависит, по-этому всё получилось легко и просто :mrgreen:
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

Re: Lazarus (GUI) + C++ (engine)

Сообщение CRobin » 26.03.2016 16:58:28

Скажите, если в Лазарусе у меня есть такая логика

Код: Выделить всё
type  p_myrec = ^t_myrec;
      t_myrec    = record
        i            : longint;
        s            : pAnsiChar;       // указатель на строку
        d           : double;
        b           : LongBool;
      end;   

var data : pointer;

{$l my.o} // линкуем объектный файл
// описываем функцию
function sample(a: integer): pointer; cdecl; external;
data := sample(1);

with p_myrec (data)^ do
begin
   writeln(inttostr(i));
   writeln(pAnsiChar(s));
   writeln(floattostr(d));
   writeln(booltostr(b));
end;


Какую структуру нужно создавать в С функции для того чтоб все сработало? Я хочу создать структуру из конвертируемых типов и передавать в Лазарус указатель на нее.
CRobin
постоялец
 
Сообщения: 145
Зарегистрирован: 26.01.2016 12:15:39

Re: Lazarus (GUI) + C++ (engine)

Сообщение скалогрыз » 27.03.2016 01:06:08

CRobin писал(а):Какую структуру нужно создавать в С функции для того чтоб все сработало? Я хочу создать структуру из конвертируемых типов и передавать в Лазарус указатель на нее.

точно такую же
Код: Выделить всё
struct my_rec {
  int i,
  char * s,
  double d,
  bool b
}

только в паскале ей следует быть не просто "record", а "packed record"

Добавлено спустя 5 минут 53 секунды:
CRobin писал(а):Скажите, если в Лазарусе у меня есть такая логика

лучше следовать логике, что Си++ функция не будет выделять память, которая нужна будет в паскаль программе. (для внутреннего использования - сколько угодно!)

Код: Выделить всё
{$l my.o} // линкуем объектный файл
// описываем функцию
function sample(a: integer; var t: tmy_rect): integer; cdecl; external;

..
data: tmy_rect;
s    : string;

fillchar(data, sizeof(data), 0);
SetLength(s, 4096);
data.s := @s[1];

sample(1, data);
writeln(data.i);
writeln(data.s);
writeln(data.d);
writeln(data.b);

а Си++ выглядит так:
Код: Выделить всё

int sample( int a , my_rec* m )
{
  if (!m) return 0;
...
}


Либо, если Си++ всё-таки выделяет память которая потом будет использоваться в паскаль программе, обязательно предоставить процедуру, чтобы Си++ эту память и освободил.

Правило простое - кто память выделил, тот её и освобождает.
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

Re: Lazarus (GUI) + C++ (engine)

Сообщение CRobin » 27.03.2016 01:58:56

Большое спасибо, теперь все значительно прояснилось.
CRobin
постоялец
 
Сообщения: 145
Зарегистрирован: 26.01.2016 12:15:39

Пред.

Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 242

Рейтинг@Mail.ru