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

From KolibriOS wiki
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 по умолчанию и так не генерирует релокейшенов).


Error creating thumbnail: Unable to save thumbnail to destination
Error creating thumbnail: Unable to save thumbnail to destination

Осталось настроить вызов 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
Error creating thumbnail: Unable to save thumbnail to destination

В 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
Error creating thumbnail: Unable to save thumbnail to destination

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++. Двоичные файлы как специальный формат не поддерживает, однако, линковщик понимает специальные скрипты, с помощью которых можно ему сказать довольно много.

Для кросс-компиляции программ на C и C++ для KolibriOS был создан специальный тулчейн.

Ниже приведены руководства по установке данного тулчейна на Linux и Windows.

Установка на Linux

Подробное руководство по установке тулчейна http://board.kolibrios.org/viewtopic.php?f=33&t=3540 Чтобы сделать установку более удобной, turbocat'ом был написан специальный скрипт, которые сделает все за вас). Скачать скрипт-установщик можно на этой странице http://board.kolibrios.org/viewtopic.php?f=33&t=3540&p=76381#p76381

Пример с компиляцией Hello world здесь https://habr.com/ru/post/527144/

ВАЖНО: замечание от автора скрипта:

 Вот написал небольшой скрипт на BASH. Выполняет все действия по установке kos32-gcc и библиотек для Линукса автоматически.
 Не рекомендую запускать от рута(предоставляйте рут только когда скрипт сам потребует).
 Иначе тулчейн будет установлен в папку /root а не ваш домашний каталог!

Установка на Windows

Инструкция по установке тулчейна под Windows: https://habr.com/ru/post/229231/

Для удобства Boppan собрал тулчейн в один архив, скачать его можно тут:

http://board.kolibrios.org/viewtopic.php?f=33&t=1218&p=74401&hilit=kossdk#p74401

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


Error creating thumbnail: Unable to save thumbnail to destination

Tiny C Compiler

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

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

Примеры программ находятся в дистрибутиве по адресу "/kolibrios/develop/tcc/samples". Так же они доступны на SVN[1]

Пример базовой оконной программы (hello.c):

#include <sys/ksys.h>

enum BUTTONS {
    BTN_QUIT  = 1,
    BTN_CLICK = 2,
};

int count = 0;
ksys_colors_table_t sys_colors;

void redraw_window(void) {
    _ksys_start_draw();
    _ksys_create_window(10, 40, 400, 200, "My window", sys_colors.work_area, 0x14);
    _ksys_draw_text("TCC example", 15, 34, 0, 0x91000000 | sys_colors.work_text);
    _ksys_define_button(150, 100 , 100, 50, BTN_CLICK, sys_colors.work_button);
    _ksys_draw_text("Click!", 155, 115, 0, 0x91000000 | sys_colors.work_button_text);
    _ksys_draw_number(count, 15, 100, 0, 0x92000000 | sys_colors.work_text);
    _ksys_end_draw();
}

int main() {
    _ksys_get_system_colors(&sys_colors);
    while (1) {
        switch (_ksys_get_event()) {
        case KSYS_EVENT_REDRAW:
            redraw_window();
            break;
        case KSYS_EVENT_BUTTON:
            switch (_ksys_get_button()) {
            case BTN_CLICK:
                count++;
                redraw_window();
                break;
            case BTN_QUIT:
                return 0;
            }
            break;
         }
     }
}

Компиляция:

tcc hello.c -o hello