Программирование на С/C++

From KolibriOS wiki
Revision as of 14:38, 13 November 2020 by IgorA (talk | contribs) (→‎Borland C++)
Jump to navigation Jump to search

Здесь описывается, как использовать разные компиляторы C/C++, чтобы скомпилировать программу под KolibriOS

Visual C++ 6/.NET/2005

  • Лицензия: команднострочная версия (Visual C++ Toolkit, компилятор/линковщик, стандартные включаемые файлы и RTL-библиотеки) бесплатна (http://microsoft.com, поиск по сайту), полная версия (IDE, исходники RTL) коммерческая
  • Доступные библиотеки для Колибри: библиотека LZMA-упаковки lzmapack.lib; можно использовать любой код, не использующий вызовов ОС и компилирующийся в объектные файлы, которые понимает линковщик от Microsoft (в частности, огромное количество Сишных библиотек). К сожалению, к стандартной RTL (Run-Time Library) это не относится, так что все недостающие функции придётся реализовывать "ручками". Реализация некоторых, впрочем, уже есть.
  • Примеры программирования для Колибри: ac97snd, fara, xonix
  • Генерируемые форматы: 32-bit PE и 64-bit PE64
  • Средства разработки: командная строка в Windows; IDE для Windows


Visual C++ - один из лучших оптимизирующих компиляторов C++. Команднострочный компилятор распространяется Microsoft бесплатно, за IDE нужно платить, поэтому здесь рассматриваются оба варианта. Версия VC6, хоть и довольно давно выпущенная, всё ещё популярна, версии VS.NET и VS2005 имеют свойство тормозить. Пакет VC (точнее, линковщик link.exe) генерирует исключительно PE-файлы, так что с 32-битностью проблем нет, а вот с генерацией двоичного файла придётся повозиться. При работе в IDE сначала создадим проект: (для VC6) File->New->Projects->Win32 Application, Project name: hello, (для VS) File->New->Project->Visual C++,General->Empty Project, Name: hello, для VC6 появится мастер, ему указываем "An empty project", подтвердим серьёзность намерений нажатием OK в последнем диалоговом окне и получим в полном соответствии с пожеланиями пустой проект с двумя конфигурациями. Конфигурацию Debug рекомендуется сразу удалить (для VC6 Build->Configurations->кнопка Remove, для VS Build->Configuration Manager->(в выпадающем списке)Edit->кнопка Remove), поскольку отладчик VC в данном контексте заведомо бесполезен. Теперь добавляем в проект (для VC6 Project->Add to Project->Files, для VS Project->Add Existing Item) включаемые файлы kosSyst.h, KosFile.h, mcsmemm.h и файлы с исходным кодом kosSyst.cpp, KosFile.cpp, mcsmemm.cpp (входят в прилагаемые к статье примеры - немного модифицированный вариант из исходников дистрибутива для возможности компиляции с VC6). Кстати, возникающий диалог поддерживает выбор нескольких файлов (если удерживать Ctrl). Далее, создаём основной файл hello.cpp (можно и main.cpp, можно взять любое другое имя) (для VC6 File->New->Files->C++ Source File, File name: hello, для VS File->New->File->Visual C++,C++ File, потом File->Save source1.cpp As, потом File->Move hello.cpp into->hello) и далее начинаем писать сам код. Рекомендуется изучить kosSyst.h, там указаны прототипы функций-обёрток системных вызовов.

#include "kosSyst.h"
#include "kosFile.h"

const char header[] = "HelloWorld test";
const char string[] = "Hello, World!";

void draw_window(void)
{
	// start redraw
	kos_WindowRedrawStatus(1);
	// define&draw window
	kos_DefineAndDrawWindow(10,40,150,50,
		0x33,0xFFFFFF,0,0,(Dword)header);
	// display string
	kos_WriteTextToWindow(30,10,8,0,(char*)string,0);
	// end redraw
	kos_WindowRedrawStatus(2);
}

void kos_Main()
{
	draw_window();
	for (;;)
	{
		switch (kos_WaitForEvent())
		{
		case 1:
			draw_window();
			break;
		case 2:
			// key pressed, read it and ignore
			Byte keyCode;
			kos_GetKey(keyCode);
			break;
		case 3:
			// button pressed; we have only one button, close
			kos_ExitApp();
		}
	}
}

Теперь настраиваем компиляцию. RTL-библиотеку использовать нельзя, она потянет за собой линковку к Windows-библиотекам, так что для VC6 на вкладке Project->Settings->Link в Category: Input очищаем поле Object/library modules и устанавливаем флажок Ignore all default libraries. Выполнение начинается с функции crtStartUp, так что устанавливаем в Category: Output устанавливаем Entry-point symbol:crtStartUp. Кроме того, в поле Project Options рекомендуется добавить опцию /align:16 (это необязательно, но сильно уменьшает размер бинарника). Для VS соответствующий диалог вызывается по Project->hello Properties и вместо вкладок там treeview, те же действия выполняются так: Configuration Properties->Linker->Input-> Ignore All Default Libraries: Yes, Linker->Advanced->Entry Point: crtStartUp, Linker->Command Line->Additional options: /align:16. Кроме того, для VS нужно явно установить подсистему: Linker->System->SubSystem (возьмите любую, она ни на что не влияет) и отключить при компиляции проверки переполнения стековых буферов и RTTI (они ссылаются на RTL): C/C++ ->Code Generation->Buffer Security Check: No, C/C++ ->Language->Enable Run-Time Type Info: No. Также манифест, вставляемый VS, нам ни к чему, так что Linker->Manifest File->Generate Manifest: No. Теперь компилятор уже способен сгенерировать код, но он окажется в формате PE. Основная идея заключается в том, чтобы получаемый PE-файл пропустить через программу pe2kos.exe, которая сменит его формат на используемый в Колибри. pe2kos.exe включена с исходниками в исходники дистрибутива (папка develop\pe2kos), а также без исходников в прилагаемые к статье примеры. (Есть и альтернативный подход, про который можно прочитать в разделе по MASM, описание линковки.) Колибри-бинарники требуется загружать по нулевому адресу, Колибри-заголовок окажется в начале файла вместо PE-заголовка, так что требуется установить базовый адрес (на той же самой вкладке - Output для VC6, Linker->Advanced для VS - поле Base address) в 0, для VS нужно ещё установить Fixed Base Address в "Image must be loaded at a fixed address (/FIXED)" (VC6 по умолчанию и так не генерирует релокейшенов).


Hll vc1.gif

Hll vc2.gif

Осталось настроить вызов pe2kos. Для VC6: Project->Settings->Custom Build, для VS: Project->hello Properties->Custom Build Step. В поле Commands/Command Line пишем

pe2kos Release\hello.exe hello

(предполагается, что pe2kos либо лежит в одном из PATH-каталогов, либо в каталоге проекта), в поле Outputs записываем имя бинарника - hello, он сгенерируется в каталоге проекта. Ах да, собственно компиляция теперь как обычно - либо F7, либо Build->Build hello.exe(VC)/Build->Build Solution(VS), либо соответствующая кнопка на панели инструментов. Теперь поработаем с командной строкой. Для начала установим необходимые переменные окружения. При установке VC Toolkit, VC6 или VS в соответствующем разделе главного меню появляется пункт "... Command Prompt", который вызывает консоль, устанавливает нужное окружение и ждёт действий пользователя. Можно самостоятельно запустить консоль и выполнить файл vcvars32.bat. После этого требуется перейти в рабочую папку (диск меняется командой X:, папка на диске - командой cd \folder1\folder2). Предполагается, что в эту папку уже скопированы kosFile.cpp,kosSyst.cpp,mcsmemm.cpp,kosFile.h,kosSyst.h,mcsmemm.h и набран hello.cpp. Необходимые опции компиляции точно такие же, как и в IDE, только теперь они задаются не через GUI, а в командной строке. Компиляция до VS2005:

cl /c /O2 /nologo hello.cpp kosFile.cpp kosSyst.cpp mcsmemm.cpp
link /nologo /entry:crtStartUp /subsystem:native /base:0 /fixed
	/align:16 /nodefaultlib hello.obj kosFile.obj kosSyst.obj mcsmemm.obj
pe2kos hello.exe hello

Hll vc3.gif

В VS2005 добавляются новые ключи:

cl /c /O2 /nologo /GS- /GR- hello.cpp kosFile.cpp kosSyst.cpp mcsmemm.cpp
link /nologo /manifest:no /entry:crtStartUp /subsystem:native /base:0 /fixed
	/align:16 /nodefaultlib hello.obj kosFile.obj kosSyst.obj mcsmemm.obj
pe2kos hello.exe hello

Hll vc4.gif

GCC/G++

  • Лицензия: бесплатные, OpenSource
  • Доступные библиотеки для Колибри: портированные RTL (Run-Time Library, стандартная Си-библиотека), SDL (Simple DirectMedia Layer, на ней основаны куча программ); можно использовать любой код, не использующий вызовов ОС и компилирующийся в объектные файлы, которые понимает ld (GNU линковщик).
  • Примеры программирования для Колибри: dosbox, sdlfire, sdlquake, pig
  • Генерируемые форматы: 32-bit, probably, 16-bit
  • Средства разработки: MinGW - командная строка в Windows (http://www.mingw.org); GCC/G++ - стандартные компиляторы, входящие во все пакеты Linux и cygwin (http://www.cygwin.com)

GCC/G++ - один из лучших оптимизирующих компиляторов C/C++. Двоичные файлы как специальный формат не поддерживает, однако, линковщик понимает специальные скрипты, с помощью которых можно ему сказать довольно много.

Надо установить toolchain:

Для Windows

Для Linux

Теперь пишем обещанный "helloworld". Здесь прототипы функций-обёрток системных вызовов находятся в kos32sys.h. Код (hello.c):

#include <kos32sys.h>

static char * title="Window";

void _draw_window(){
    BeginDraw();
    DrawWindow(100,100,400,200,title,0x80ffffff,0x13);
    EndDraw();
}

int main()
{
    _draw_window();
    for (;;)
    {
       switch(get_os_event())
       {
          case 1:
             _draw_window();
             continue;
          case 2:
             // key pressed, read it and ignore
             get_key();
             continue;
          case 3:
             // button pressed; we have only one button, close
             if(get_os_button() == 1) return 0;
             continue;
       }
    }
}

Как компилировать, написано в инструкции выше.

Borland C++

  • Лицензия: утилиты командной строки бесплатны ( www.borland.com/bcppbuilder/freecompiler или поиск "Command-Line tools" по сайту), IDE коммерческая
  • Доступные библиотеки для Колибри: базовая, необходимая для работы (включает работу с многопоточностью, обёртки системных вызовов, работу с кучей, работу с файлами, но RTL нет).
  • Примеры программирования для Колибри: life2 (programs\demos\life2)
  • Генерируемые форматы: 32-bit PE
  • Средства разработки: командная строка в Windows; IDE для Windows

Компилятор не позволяет генерировать двоичные файлы. Здесь используется интересный подход: раз создавать Колибри-бинарники с помощью компилятора не получается, не будем его использовать! Будем использовать FASM, он позволяет генерировать всё, что нужно. Вопрос: а причём же здесь тогда C++? Ответ: будем писать на C++, но компилировать в ассемблерный текст! "Мелкие" проблемы с несоответствием TASM-синтаксиса выходных файлов от Borland C++ FASM-синтаксису решаются несложной программой t2fasm.exe. Для компиляции потребуется библиотека базовых функций, она входит в вышеупомянутые исходники life2. Собственно код (window.cpp) bcc32:

#include <kolibri.h>
#include <kos_heap.h>
#include <kos_file.h>

using namespace Kolibri;

const char header[] = "Colors";

bool KolibriOnStart(TStartData &kos_start, TThreadData th)
{
       kos_start.Left = 10;
       kos_start.Top = 40;
       kos_start.Width = 135;
       kos_start.Height = 80;
       kos_start.WinData.WindowColor = 0xFFFFFF;
       kos_start.WinData.WindowType = 0x34; // 0x34 - fixed, 0x33 - not fixed
       kos_start.WinData.Title = header;
       return true;
}

void KolibriOnPaint(void)
{
       // If button have ID 1, this is close button
       DrawButton(2,0xff0000, 10,40,50,20);
       DrawButton(3,0x00ff00, 70,10,50,20);
       DrawButton(4,0x0000ff, 70,40,50,20);
       DrawButton(5,0xFFFE00, 10,10,50,20);
}

void KolibriOnButton(long id, TThreadData th)
{
       switch(id){
       case 2:
               SetWindowCaption("Red");
               break;
       case 3:
               SetWindowCaption("Green");
               break;
       case 4:
               SetWindowCaption("Blue");
               break;
       case 5:
               SetWindowCaption("Yellow");
               //break;
       };
}
/*
int KolibriOnIdle(TThreadData th)
{
       return -1;
}
void KolibriOnSize(int window_rect[], TThreadData th) {}
void KolibriOnKeyPress(TThreadData th)
{
       GetKey();
}
void KolibriOnMouse(TThreadData th) {}
*/

Что-бы компилировать FASM версией выше 1.64 нужно пропатчить компилятор. Пример файла window_cpp.bat:

Set NAME=window
Set BCC_DIR=..\..\..\bcc32
kos32-bcc -S -v- -R- -6 -a4 -O2 -Og -Oi -Ov -OS -k- -D__KOLIBRI__ -I..\..\..\bcc32\include %NAME%.cpp

echo STACKSIZE equ 102400> kos_make.inc
echo HEAPSIZE equ 102400>> kos_make.inc
echo include "%BCC_DIR%\include\kos_start.inc">> kos_make.inc
echo include "%BCC_DIR%\include\kos_func.inc">> kos_make.inc
echo include "%BCC_DIR%\include\kos_heap.inc">> kos_make.inc

echo include "kos_make.inc" > f_%NAME%.asm
t2fasm < %NAME%.asm >> f_%NAME%.asm
fasm f_%NAME%.asm %NAME%.kex
if exist %NAME%.kex kpack %NAME%.kex
if exist %NAME%.kex del kos_make.inc
pause


Hll bc1.gif

Tiny C Compiler

  • Лицензия: бесплатный, OpenSource
  • Доступные библиотеки для Колибри: солидная часть RTL (Run-Time Library, стандартная Си-библиотека)
  • Программы: TinyTextEditor, TinyHashView
  • Генерируемые форматы: 32-bit COFF, ELF, PE, Kolibri
  • Средства разработки: командная строка в Windows, Kolibri

Компилятор TCC был доработан для генерации Колибри-бинарников. Также написана некоторая часть C RTL на базе функций Колибри. Исходники как самого компилятора, так и RTL доступны на svn-сервере Колибри: svn://kolibrios.org/programs/develop/ktcc/trunk.


Код (hello.c):

#include <kos32sys1.h>
#include <stdlib.h>
 
#define WIN_W 640
#define WIN_H 563
 
char* title = "TinyC Compiler";
int win_bg_color = 0x858585;

void draw_window(){
        begin_draw();
        sys_create_window(215,100,WIN_W,WIN_H,title,win_bg_color,0x34);
        end_draw();
}
 
int main()
{
        while(1)
        {
                switch(get_os_event())
                {
                        case 3:
                                if (get_os_button() == 1) exit(0);
                                break;
                 
                        case 2:
                                get_key();
                                break;
                            
                        case 1:
                                draw_window();
                                break;
                }
        }
}

Компиляция:

tcc hello.c -lck -o hello.kex