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

Сборка (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)
```

![](https://4112636200-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FKMqUSFKgvT06FCJhm51b%2Fuploads%2Fgit-blob-fded569c195c98f68d3d224eb8845a0ad0631f72%2Fcompiling_c-%D0%9A%D0%BE%D0%BF%D0%B8%D1%8F%20%D0%A1%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0%20%E2%80%94%201.drawio.png?alt=media)

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

Пусть имеется файл `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="https://4112636200-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FKMqUSFKgvT06FCJhm51b%2Fuploads%2Fgit-blob-0768ff9e08e00f168c9a9172947eef56d4f86ac3%2Fcompiling_c-%D0%A1%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0%20%E2%80%94%202.drawio.png?alt=media" 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="https://4112636200-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FKMqUSFKgvT06FCJhm51b%2Fuploads%2Fgit-blob-e4a529f8c374d7492348503efea06da839d78d25%2Fcompiling_c-%D0%A1%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0%20%E2%80%94%203.drawio.png?alt=media" 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 %}
