# Сборка программы

Сборка (build) – процесс получения программы или библиотеки из исходного кода. Сборку разделяют на 3 крупных этапа: препроцессинг, компиляцию, линковку. Если один из этапов завершился неуспешно, то будет выведено сообщение компилятора или линковщика с ошибками.

## Общие сведения

Сборка состоит из нескольких этапов, среди которых выделяют 3 крупных:

1. <mark style="color:red;">Preprocessing</mark> – Препроцессирование, препроцессинг. Выполнение директив препроцессора (`#include`, `#define` и пр.). Обычно расширение `*.i`.

   ```powershell
   clang -E main.c -o main.i    # (preprocessing)
   ```
2. <mark style="color:green;">Compiling</mark> – Компиляция. Перевод в машинный код. Обычно расширение `*.obj` или `*.o` (он же объектный файл).

   ```powershell
   clang -c main.c -o main.obj    # (preprocessing + compile)
   ```
3. <mark style="color:blue;">Linking</mark> – Линковка (компоновка). Обычно расширение `*.exe/*.out` (исполняемый файл) и `*.dll/*.so` (файл динамической библиотеки).

   ```powershell
   lld-link /subsystem:console /defaultlib:libcmt main.obj     # (linking)
   ```

```powershell
clang main.c -o main.exe       # (all steps)
```

![](/files/JCGmydraJJXsbvVzbn5U)

## Сборка из терминала

Пусть имеется файл `main.c`, содержащий следующий код:

{% code title="main.c" overflow="wrap" lineNumbers="true" %}

```c
#include <stdio.h>

int main (int argc, char *argv[])
{
    printf("%i\n", argc);
    return 0;
}
```

{% endcode %}

Компиляция из терминала с использованием компилятора Clang:

```powershell
clang main.c
```

На выходе будет создан файл `a.exe` или `a.out` в зависимости от системы (Windows или Linux соответственно).

Как правило, компилятор – это консольное приложение с интерфейсом опций. Для задания параметров работы компиляторы имеют набор специальных опций (ключей), которые указываются в командной строке.

Зададим компилятору имя результирующего файла как `main.exe`:

```powershell
clang main.c -o main.exe
```

## Ключи компиляции

Современные компиляторы обладают большими возможностями по оптимизации генерируемого кода и "нацеливание" его на конкретные архитектуры процессоров. Помимо `-o` компиляторы поддерживают большое число других ключей.

Рассмотрим следующий пример:

{% code title="main.c" overflow="wrap" lineNumbers="true" %}

```c
#include <stdio.h>
#include <stdlib.h>
#define C 1
int bar(int i)
{
    return C * 5;
}

int foo(int i)
{
    return i * bar(i);
}

int main(void) 
{
    int n = 20;
    int* arr = malloc(sizeof(int) * n);

    for (int i = 0; i < C; n; ++i)
        arr[i] = foo(i);

    free(arr);
    return 0;
}
```

{% endcode %}

Существует несколько уровней комплексной оптимизации. Каждый следующий уровень обычно включает все техники оптимизации с предыдущего уровня + некоторые новые. Кроме того, могут быть и отдельные наборы для особых случаев (например, оптимизация по размеру исполняемого кода).

Для задания уровня оптимизации используется ключ `-O*`: `-O0`, `-O1 (или -O)`, `-O2`, `-Ofast` и т.д. Набор таких ключей для каждого компилятора свой.

Зададим компилятору ключ оптимизации:

```powershell
clang main.c -O2 -o main.exe
```

Рассмотрим ряд других ключей для компилятора `clang` и `llvm-based intel`:

<table><thead><tr><th width="118">Ключ</th><th width="172">Задаёт</th><th width="285">Пример</th><th>По умолчанию</th></tr></thead><tbody><tr><td><code>-o</code></td><td>имя результирующего файла</td><td><code>-o main.exe</code></td><td><code>a.exe</code> или <code>a.out</code> для Windows или Linux соответственно</td></tr><tr><td><code>-O*</code></td><td>уровень оптимизации</td><td><code>-O0</code>, <code>-O1</code> (или <code>-O</code>), <code>-O2</code>, <code>-Ofast</code> ...</td><td><code>-O0</code></td></tr><tr><td><code>-I</code></td><td>include directory</td><td><code>-I include</code></td><td><code>-I .</code></td></tr><tr><td><code>-L</code></td><td>library directory</td><td><code>-L lib</code></td><td><code>-L .</code></td></tr><tr><td><code>-l</code></td><td>library file</td><td><code>-l lab2.lib</code></td><td></td></tr><tr><td><code>-std=</code></td><td>стандарт языка</td><td><code>-std=c17</code></td><td>зависит от версии компилятора</td></tr><tr><td><code>-D</code></td><td>preprocessor definitions</td><td><code>-D_CRT_SECURE_NO_WARNINGS</code></td><td></td></tr><tr><td><code>-v</code></td><td>вывод подробного лога сборки</td><td><code>-v</code></td><td></td></tr><tr><td><code>-m</code></td><td>битность целевой платформы</td><td><code>-m32</code>, <code>-m64</code></td><td><code>-m64</code></td></tr><tr><td><code>-W</code></td><td>enable the specified warning</td><td><code>-Wall</code></td><td>зависит от версии компилятора</td></tr><tr><td><code>-Wno</code></td><td>disable the specified warning</td><td><code>-Wno-endif-labels</code></td><td>зависит от версии компилятора</td></tr></tbody></table>

### debug VS release

**Debug** – код не оптимизируется (`-O0`), работает медленно, но хорошо работает отладчик.

**Release** – код оптимизируется (`-O2` или `-O3`), работает быстро, но под отладчиком не видно значения переменных, не работают точки остановок отладки и прочее.

В **Debug** конфигурации неинициализированные локальные переменные нередко инициализируются специальным, так называемым, "мусором" (0xBAADF00D, 0xCCCCCCCC и другие) для упрощения отладки.

В **Release** же ничего не инициализируется и неинициализированные переменные содержат то, что оказалось в памяти (часто 0, но это не гарантируется).

### [`-W` значит WARNING](https://clang.llvm.org/docs/DiagnosticsReference.html)

Предупреждение – это потенциальная ошибка. Предупреждение – это сигнал от компилятора о том, что написано одно, а требуется, возможно, что-то совершенно иное.

Поэтому программист должен помочь компилятору понять, как трактовать спорную ситуацию. То есть либо поправить свою ошибку, либо сообщить компилятору явно о том, что нужно верить программисту и делать именно то, что написано.

#### Общие предупреждения

<table><thead><tr><th width="230">Ключ</th><th>Назначение</th></tr></thead><tbody><tr><td><code>-Werror</code></td><td>делает все предупреждения ошибками</td></tr><tr><td><code>-Werror=[error-type]</code></td><td>делает только указанное предупреждение ошибкой</td></tr><tr><td><code>-Wall</code></td><td>"агрегатор" базовых предупреждений (не всех)</td></tr><tr><td><code>-Wextra</code></td><td>дополнительные предупреждения, которых нет в <code>-Wall</code></td></tr><tr><td><code>-Wpedantic</code></td><td>проверяет соответствие кода стандарту ISO C++, сообщает об использовании запрещённых расширений, о наличии лишних точек с запятой, нехватке переноса строки в конце файла и прочих полезных штуках.</td></tr><tr><td><code>-Weverything</code></td><td>использование всех предупреждений</td></tr></tbody></table>

#### [Полезные предупреждения (clang specific)](https://clang.llvm.org/docs/DiagnosticsReference.html)

<table><thead><tr><th width="230">Ключ</th><th>Назначение</th></tr></thead><tbody><tr><td><code>-Warray-bounds</code></td><td>выход за пределы массивов</td></tr><tr><td><code>-Warray-bounds-pointer-arithmetic</code></td><td>выход за границы массивов при использовании арифметике указателей</td></tr><tr><td><code>-Wreturn-type</code></td><td>не все ветви исполнения кода возвращают значение</td></tr><tr><td><code>-Wvla</code></td><td>использование VLA (VLA + VMT)</td></tr><tr><td><code>-Wunused-variable</code></td><td>объявлена неиспользуемая переменная</td></tr><tr><td><code>-Wunused</code></td><td>набор предупреждений <code>-Wunused-argument, -Wunused-but-set-variable, -Wunused-function, -Wunused-label, -Wunused-lambda-capture, -Wunused-local-typedef, -Wunused-private-field, -Wunused-property-ivar, -Wunused-value, -Wunused-variable.</code></td></tr><tr><td><code>-Wshift-op-parentheses</code></td><td><code>warning: operator ‘A’ has lower precedence than ‘B’; ‘B’ will be evaluated first</code></td></tr></tbody></table>

Пример кода, на котором появляется сообщение с предупреждением:

{% code title="main.c" overflow="wrap" lineNumbers="true" %}

```c
int main (void)
{
    const char * a = "abc";
    if (a == "abc")
        return 0;
}
```

{% endcode %}

Предупреждение `-Wstring-compare`

```powershell
clang main.c
```

{% code title="clang main.c" overflow="wrap" lineNumbers="true" %}

```powershell
main.c: In function 'int main()':
main.c:4:11: warning: comparison with string literal results in unspecified behavior [-Wstring-compare]
    4 |     if (a == "abc")
      | 
```

{% endcode %}

Компиляция с игнорированием этого исключения (лог пустой, сборка прошла успешно):

```powershell
clang -Wno-string-compare main.c
```

### Сборка программы из нескольких исходников без заголовочных файлов

Имена элементов программы, таких как переменные, функции, классы и т. д., должны быть объявлены перед их использованием. Например, вы не можете просто написать `x = 42`, не объявив `x`.

Рассмотрим пример кода, представленного в двух разных файлах: `main.c` и `print_hello_world.c`.

{% code title="main.c" overflow="wrap" lineNumbers="true" %}

```c
int main(void)
{
    print_hello_world();
    return 0;
}
```

{% endcode %}

{% code title="print\_hello\_world.c" overflow="wrap" lineNumbers="true" %}

```c
#include <stdio.h>

void print_hello_world(void) 
{
    printf("Hello, world!\n");
}
```

{% endcode %}

При попытке скомпилировать файлы будет ошибка компиляции:

```powershell
clang main.c print_hello_world.c
```

При попытке скомпилировать файлы будет ошибка компиляции:

{% code title="clang main.c print\_hello\_world.c" overflow="wrap" lineNumbers="true" %}

```powershell
main.c:3:5: error: call to undeclared function 'print_hello_world'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
    print_hello_world();
    ^
1 error generated.
```

{% endcode %}

Для того, чтобы вызвать функцию, надо что-то про неё знать – а именно **объявление функции (declaration)**:

{% code title="main.c" overflow="wrap" lineNumbers="true" %}

```c
void print_hello_world(void); // declaration

int main(void)
{
    print_hello_world();
    return 0;
}
```

{% endcode %}

Объявление говорит о том, что где-то в программе такая функция есть. А когда мы пишем тело функции в фигурных скобках – это **определение (definition)**.

Следуя этому правилу можно писать код, в котором все функции определены ниже их первого вызова, указав до этого первого вызова объявления этих функций:

{% code title="main.c" overflow="wrap" lineNumbers="true" %}

```c
#include <stdio.h>

void print_hello_world(void); // declaration (объявление)

int main(void)
{
    print_hello_world();
    return 0;
}

void print_hello_world(void) // definition (определение)
{
    printf("Hello, world!\n");
}
```

{% endcode %}

## Подключение заголовочных файлов [#include](https://en.cppreference.com/w/c/preprocessor/include)

Когда исходного кода становится много, то делать предварительные объявления каждой функции, которую вы хотите использовать, и которая определена в другом файле, становится всё труднее.

Заголовочные файлы "подключаются" в файлы с исходным кодом при помощи директивы препроцессора `#include`. Используются `#include <...>` или `#include "..."` в зависимости от того, где компилятору следует искать этот файл – в своих **include directories** или относительно текущей директории.

```c
#include <stdlib.h>
#include <math.h>
```

Подключение *СИСТЕМНЫХ* и *СТАНДАРТНЫХ* (поставляемых вместе с компилятором) заголовочных файлов – указанный заголовочный будет искаться в папках с заголовчными компилятора, системных папках и в тех папках, который указаны при компиляции через ключ `-I`.

Компилятор не будет искать заголовочный файл в каталоге исходного кода вашего проекта и ему нужно задать директории, где они лежат.

```c
#include "myheader.h"
#include "include_folder/myheader.h"
```

Подключение остальных (*ВАШИХ*) заголовочных. Имя указаывается относительно текущей директории.

Таким образом:

* системные/стандартные заголовочные файлы подключаем через `#include <...>`
* заголовочные файлы из библиотек/сторонних проектов подключаем через `#include <...>` + добавляем пути до этих файлов в параметры компиляции
* свои заголовочные подключаем через `#include "..."`

рекомендуется указывать пути с использованием `/`, а не обратных косых черт.

### `return_codes.h`

Там лежат объявления макросов. В своём коде вы используете именно макросы, а не числа, которые рядом с ним написаны!

```c
#include "return_codes.h"

...
    return ERROR_ARGUMENTS_INVALID;
    return SUCCESS;
```

### Повторное подключение заголовочных файлов

Следующий пример состоит из 3 файлов.

<table data-header-hidden><thead><tr><th width="363"></th><th></th></tr></thead><tbody><tr><td><pre class="language-c" data-title="grandparent.h" data-overflow="wrap" data-line-numbers><code class="lang-c">struct foo
{
    int member;
};
</code></pre><pre class="language-c" data-title="parent.h" data-overflow="wrap" data-line-numbers><code class="lang-c">#include "grandparent.h"
</code></pre><pre class="language-c" data-title="child.c" data-overflow="wrap" data-line-numbers><code class="lang-c">#include "grandparent.h"
#include "parent.h"
</code></pre></td><td><img src="/files/C94dVAVT1DLHCt2WekG7" alt="" data-size="original"></td></tr></tbody></table>

В результате препроцессинга:

```powershell
clang -E child.c -o child.i
```

<table data-header-hidden><thead><tr><th width="372"></th><th></th></tr></thead><tbody><tr><td><pre class="language-c" data-title="child.i" data-overflow="wrap" data-line-numbers><code class="lang-c"># 1 "child.c"
# 1 "&#x3C;built-in>" 1
# 1 "&#x3C;built-in>" 3
# 368 "&#x3C;built-in>" 3
# 1 "&#x3C;command line>" 1
# 1 "&#x3C;built-in>" 2
# 1 "child.c" 2
1 "./grandparent.h" 1
struct foo
{
int member;
};
3 "child.c" 2
1 "./parent.h" 1
1 "./grandparent.h" 1
struct foo
{
int member;
};
2 "./parent.h" 2
4 "child.c" 2
</code></pre></td><td><img src="/files/WRYLLrfVCPDcV7knaWKs" alt="" data-size="original"></td></tr></tbody></table>

А теперь скомпилируем это в объектный файл

```powershell
clang -c child.c -o child.obj
```

{% code title="clang -c child.c -o child.obj" overflow="wrap" lineNumbers="true" %}

```powershell
In file included from child.c:3:
In file included from ./parent.h:1:
./grandparent.h:1:8: error: redefinition of 'foo'
    1 | struct foo
      |        ^
child.c:2:10: note: './grandparent.h' included multiple times, additional include site here
    2 | #include "grandparent.h"
      |          ^
./parent.h:1:10: note: './grandparent.h' included multiple times, additional include site here
    1 | #include "grandparent.h"
      |          ^
./grandparent.h:1:8: note: unguarded header; consider using #ifdef guards or #pragma once
    1 | struct foo
      |        ^
1 error generated.
```

{% endcode %}

**(」°ロ° )**

Ошибка компиляции `redefinition of 'smth'`

Для исправления такой ошибки необходимо сделать так, чтобы код из файла `grandparent.h` попал в итоговый `child.c` один раз. Для этого используют защиту от повторного включения или include guard.

### Include guard ([#define](https://en.cppreference.com/w/c/preprocessor/replace))

Old-style: всё содержимое заголовочного "обернуть" в

{% code overflow="wrap" lineNumbers="true" %}

```c
#ifndef GRANDPARENT_H
#define GRANDPARENT_H

//... contents of grandparent.h

#endif /* !GRANDPARENT_H */
```

{% endcode %}

New-style: в начале заголовочного указать

{% code overflow="wrap" lineNumbers="true" %}

```c
#pragma once

//... contents of grandparent.h
```

{% endcode %}

Последнее является нестандартной, но широкораспространённой директивой препроцессора.

**Не следует делать!**

Оставлять названия макросов, которые вам сгенерировала IDE на основе названия проекта

{% code overflow="wrap" lineNumbers="true" %}

```c
#ifndef UNTITLED12_LAB00011
#define UNTITLED12_LAB00011

//... contents of file

#endif
```

{% endcode %}

или что-то не относящееся к самому заданию

{% code overflow="wrap" lineNumbers="true" %}

```c
#ifndef OCHEN_HOCHU_STO_BALLOV
#define OCHEN_HOCHU_STO_BALLOV

//... contents of file

#endif
```

{% endcode %}

Подключать файлы с исходным кодом (\*.c/\*.cpp) через `#include` – зло (вас будут карать баллами)

**୧((#Φ益Φ#))୨**

## Include directories

Каталоги включаемых файлов настраиваются как часть вашего проекта / настроек IDE / настроек компилятора. Компилятор не будет искать заголовочный файл в каталоге исходного кода вашего проекта и ему нужно задать директории, где они лежат.

Вынесем определение (definition) функций `foo` и `bar` в отдельный исполняемый файл и создадим соответсвующий заголовочный:

{% code title="func/func.h" overflow="wrap" lineNumbers="true" %}

```c
#pragma once
#define C 1
int bar(int i);
int foo(int i);
```

{% endcode %}

{% code title="func/func.c" overflow="wrap" lineNumbers="true" %}

```c
#include "func.h"
int bar(int i)
{
    return C * 5;
}
int foo(int i)
{
    return i * bar(i);
}
```

{% endcode %}

{% code title="main.c" overflow="wrap" lineNumbers="true" %}

```c
#include <stdio.h>
#include <stdlib.h>
#include "func.h"
int main(void)
{
    int n = 20;
    int* arr = malloc(sizeof(int) * n);
    for (int i = 0; i < C; n; ++i)
        arr[i] = foo(i);
    free(arr);
    return 0;
}
```

{% endcode %}

Чтобы задать компилятору **include directories** нужно использовать ключ `-I`.

**Сборка без -I**

```powershell
clang main.c func/func.c -o main.exe
```

{% code title="clang main.c func/func.c -o main.exe" overflow="wrap" lineNumbers="true" %}

```powershell
main.c:3:10: fatal error: 'func.h' file not found
#include "func.h"
         ^~~~~~~~
1 error generated.
```

{% endcode %}

**Сборка с -I**

```powershell
clang main.c func/func.c -I func -o main.exe
```

## Library directories и library files

Следующий пример: вы хотите использовать в своей программу библиотеку, представляющую собой набор заголовочных файлов и файла статической библиотеки. В таком случае, помимо указания путей заголовочных файлов нужно будет указать где искать файл библиотеки и как он называется.

Для подключения сторонних библиотек помимо указания директорий, где следует искать заголовочные файлы (чаще всего это директории `include` или `inc`) может потребоваться указание директорий библиотек (`lib`). Для этого используются ключи `-L` и `-l`.

Рассмотрим пример кода, использующий фреймворк OpenCL. Для компиляции такого кода помимо необходимого заголовочного файла, расположение которого укажем через ключ `-I`, необходимо указать, где располагается файл статической библиотеки `opencl.lib` и сам этот файл.

**Структура проекта**

```
project [dir]
├── opencl_root [dir]
    ├── bin [dir]
        ├── opencl.dll [dynamic library file | Windows]
        ├── opencl.so [dynamic library file | Linux]
        ├── opencl.dylib [dynamic library file | MacOS]
    ├── include [dir]
        ├── CL [dir]
            ├── cl.h [header file]
    ├── lib
        ├── opencl.lib [static library file | Windows]
        ├── lopencl.a [static library file | Linux / MacOS]
├── opencl_test.c [source file]
```

{% hint style="danger" %}
**Сборка без указания директории заголовочных и библиотек (без -I и -L и -l)**

```powershell
clang opencl_test.c -o ocl.exe
```

{% code title="clang opencl\_test.c -o ocl.exe" overflow="wrap" lineNumbers="true" %}

```powershell
opencl_test.c:7:10: fatal error: 'CL/cl.h' file not found
#include <CL/cl.h>
         ^~~~~~~~~
1 error generated.
```

{% endcode %}
{% endhint %}

Видно, что в первую очередь не хватает заголовочного файла. Исправим ситуацию, указан компилятору include directory `opencl_root/include`.

{% hint style="danger" %}
**Сборка без указания директории библиотек (с -I и без -L и -l)**

```powershell
clang opencl_test.c -I"opencl_root/include" -o ocl.exe
```

{% code title="clang opencl\_test.c -I" lineNumbers="true" %}

```powershell
opencl_test-d454e7.o : error LNK2019: unresolved external symbol clGetPlatformIDs referenced in function main
opencl_test-d454e7.o : error LNK2019: unresolved external symbol clGetPlatformInfo referenced in function main       
opencl_test-d454e7.o : error LNK2019: unresolved external symbol clGetDeviceIDs referenced in function main
opencl_test-d454e7.o : error LNK2019: unresolved external symbol clGetDeviceInfo referenced in function main
ocl.exe : fatal error LNK1120: 4 unresolved externals
clang: error: linker command failed with exit code 1120 (use -v to see invocation)
```

{% endcode %}
{% endhint %}

Видно, что все текущие ошибки – ошибки линковки. Линкеру необходимо явно указать library directory и сами файлы библиотек.

{% hint style="danger" %}
**Сборка без указания имени библиотеки (с -I и -L и без -l)**

```powershell
clang -L"opencl_root/lib" -I"opencl_root/include" -O2 -o ocl.exe opencl_test.c
```

{% code title="clang -L" lineNumbers="true" %}

```powershell
opencl_test-f81bbf.o : error LNK2019: unresolved external symbol clGetPlatformIDs referenced in function main
opencl_test-f81bbf.o : error LNK2019: unresolved external symbol clGetPlatformInfo referenced in function main
opencl_test-f81bbf.o : error LNK2019: unresolved external symbol clGetDeviceIDs referenced in function main
opencl_test-f81bbf.o : error LNK2019: unresolved external symbol clGetDeviceInfo referenced in function main
ocl.exe : fatal error LNK1120: 4 unresolved externals
clang: error: linker command failed with exit code 1120 (use -v to see invocation)
```

{% endcode %}
{% endhint %}

Несмотря на указанную директорию всё ещё видим ошибки линковки. Укажем явно файл библиотеки, который лежит в указанной library directory. Файл библиотеки указывается без расширения, а также ключ `-l` с названием файла библиотеки должен идти последним параметром.

{% hint style="success" %}
**Сборка с -I и -L и -l**

```powershell
clang -L"opencl_root/lib" -I"opencl_root/include" -O2 -o ocl.exe opencl_test.c -lopencl 
```

{% code title="clang -L" lineNumbers="true" %}

```powershell
clang version 15.0.7
Target: x86_64-pc-windows-msvc
Thread model: posix
InstalledDir: C:\Program Files\LLVM\bin
 "...LLVM\\bin\\clang.exe" -cc1 -triple x86_64-pc-windows-msvc19.34.31937 -emit-obj -mincremental-linker-compatible ... -x c opencl_test.c
clang -cc1 version 15.0.7 based upon LLVM 15.0.7 default target x86_64-pc-windows-msvc
#include "..." search starts here:
#include <...> search starts here:
 C:\SDK\OCL_SDK_Light\include
 C:\Program Files\LLVM\lib\clang\15.0.7\include
 C:\Program Files\Microsoft Visual Studio 2022\VC\Tools\MSVC\14.34.31933\include
 C:\Program Files\Microsoft Visual Studio 2022\VC\Tools\MSVC\14.34.31933\atlmfc\include
 C:\Program Files (x86)\Windows Kits\10\Include\10.0.20348.0\ucrt
 C:\Program Files (x86)\Windows Kits\10\Include\10.0.20348.0\shared
 C:\Program Files (x86)\Windows Kits\10\Include\10.0.20348.0\um
 C:\Program Files (x86)\Windows Kits\10\Include\10.0.20348.0\winrt
 C:\Program Files (x86)\Windows Kits\10\Include\10.0.20348.0\cppwinrt
End of search list.
 "..VC\\Tools\\MSVC\\14.34.31933\\bin\\Hostx64\\x64\\link.exe" -out:ocl.exe -defaultlib:oldnames ... opencl.lib
```

{% endcode %}
{% endhint %}

Лог может отличаться в зависимости от версии компилятора и системы (может выводиться меньше информации). Главное, что никаких итогов с ошибками не наблюдается.

Но собранный исполняемый файл не означает, что на этапе исполнения не будет возникать ошибок.

При попытке запустить полученный `ocl.exe` будет ошибка. Чтобы программа отработала необходимо поместить рядом с исполняемым файлом файлы динамически подключаемых библиотек (`.dll` для Windows; `os` для UNIX систем; `dylib` для MacOS). Такие файлы чаще всего располагаются в директории `bin` библиотеки.

{% hint style="info" %}
Если же библиотека будет использоваться в нескольких проектах, то следует задуматься о добавлении пути до файлов динамически подключаемых библиотек в переменные окружения, чтобы не копировать их каждый раз к исполняемым файлам.
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://skkv-itmo.gitbook.io/c-cpp-cookies/build/building-program.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
