Здравствуйте, коллеги-разработчики! Я Максим, и я хочу поделиться новостью из мира C++. Я смог в 15 лет собрать Clang, LLD, LLDB, clang-extra-tools нативно в Windows, и оно работает. Но начнем мы издалека: как я вообще выбрал C++; почему не остался на MSVC, G++; как я собрал LLVM; почему не скачал уже готовые сборки от Мартина Сторшё.
Дисклеймер
Эта статья прежде всего история моего пути, борьбы с ошибками и выбора инструментов. Если вас интересуют только технические детали (Fix, Скрипты) или вы хотите скачать уже готовый и проверенный LLVM-Toolchain для C++, переходите на GitHub, там всё описано - клик

С чего всё началось?
Мой путь в IT начался с «железа». В 2020 году на старом отцовском ПК отвалился чип видеокарты. Денег на новую не было, и я три года копил со школьных обедов на новый конфиг. К 13 годам, цель была достигнута, но со временем мне стало не интересно просто играть — захотелось создавать свое.
Первым делом я пошел по советам из интернета в Python. Всё было отлично, пока я не начал писать код, от которого падал интерпретатор, а ИИ того времени (начало 2023) не мог внятно объяснить почему. Попробовал Java, но быстро устал от многословности и бесконечных абстракций.
В итоге я пришел к C++. Мне понравилось то что на нем пишут всё: от операционных систем до AAA-игр. Установил MSVC и начал разбираться.
Почему не остался на MSVC/GCC?
В какой-то момент я задумался: MSVC крут, но весит 20+ ГБ, он закрытый, и я вечно боялся найти в лицензии какой-нибудь пункт мелким шрифтом о том, что я стану должен Microsoft, если сделаю что-то серьезное.
Начал искать замену. Сначала был GCC от WinLibs. Вроде всё ок, но чем больше я копал, тем больше бесила топорность GDB и страшные ошибки G++, которые приходилось постоянно гуглить. А потом я попробовал Clang — и это был кайф! Удобно, как в MSVC, но при этом лицензия даже свободнее, чем у GCC.
Но была проблема: в готовых сборках WinLibs версия LLVM отставала. У меня стояла 19-я, а в мире была 21-я. Я ждал но понял что дальше не будет и решил что соберу свежайший LLVM сам. Так я скачал MSYS2 и начал свои первые попытки.
Как я собрал Clang?
Как я уже написал, я начал гуглить и спрашивать у ИИ, как собрать LLVM. Мой первый конфиг был очень простой и наивный: я думал, что LLVM просто и быстро заработает. К моему удивлению, оно заработало с первой попытки, но конфиг был очень примитивный: я включил только clang и lld, так как больше ничего не хотел.
Со временем я понял, что хочу собрать LLVM Runtimes и уйти от GNU Runtimes, и вот тут начались проблемы. Самая первая и бесячая моя ошибка - LLD не мог импортировать символыerror: no matching function for call to '__copy_move_unwrap_iters'
error: 'value' is not a member of 'std::__1::__can_rewrap<...>'
error: no type named 'type' in 'struct std::__1::add_lvalue_reference<...>'
Я потратил от 1 до 2 месяцев, перебирая конфиги,форумы. Я пробовал менять флаги, переставлять инклуды, гуглить каждый error — ничего не помогало. В какой-то момент я был на грани того, чтобы всё бросить. Но потом решил: «Либо я LLVM, либо я LLVM», — и продолжил.
Решение пришло случайно: Оказалось, что нельзя просто так взять и смешать статичные библиотеки с динамичными (DLL). Линкер LLD в такой ситуации просто теряет символы и мы видим
error: no matching function for call to '__copy_move_unwrap_iters' error: 'value' is not a member of 'std::__1::__can_rewrap<...>' error: no type named 'type' in 'struct std::__1::add_lvalue_reference<...>'
Через время я смог сделать LLVM Runtimes, но появилась новая ошибка:
In file included from main.cpp:1: C:/Program Files (x86)/LLVM/include/c++/v1/__mbstate_t.h:51:4: error: "We don't know how to get the definition of mbstate_t on your platform."
...
C:/Program Files (x86)/LLVM/include/c++/v1/iosfwd:144:14: error: reference to unresolved using declaration 144 | typedef fpos<mbstate_t> u32streampos;
...
C:/Program Files (x86)/LLVM/include/c++/v1/__locale_dir/support/windows.h:18:10: fatal error: 'locale.h' file not found 18 | #include <locale.h> // ::_locale_t |
^~~~~~~~~~ 10 errors generated.
(Это не вся ошибка но я сократил её до сути)
Я долго не мог понять что это за ошибка неужели libc++ не готов, но потом я присмотрелся внимательнее и заметил что оно ищет в C++ Runtimes, C Runtimes и тут я вспомнил что C++ использует C Runtimes, я попробовал собрать LibC от LLVM но он был крайне сырой даже для MSVC.Решение проблемы была в сборке классического MinGW-UCRT.
Почему именно UCRT а не MSVCRT ? и ответ простой MSVCRT имеет старые стандарты C (вроде C11 последний хотя в 2024 C23 вышел) и проблемы с UTF-8 кодировкой, UCRT таких проблем не имеет.
Позже я захотел LLDB и ClangD. Будь я нормальным человеком, я бы просто скачал ClangD, но нет — я решил его собрать. На удивление, clang‑extra‑tools (частью которого является ClangD) работает прекрасно. А вот с LLDB была проблема: он падал на MainLoopWindows.cpp:
[1817/3216] Building CXX object tools/lldb/source/Host/CMakeFiles/lldbHost.dir/windows/MainLoopWindows.cpp.obj
FAILED: tools/lldb/source/Host/CMakeFiles/lldbHost.dir/windows/MainLoopWindows.cpp.obj
C:\CPP\mingw64\bin\g++.exe -DEXPERIMENTAL_KEY_INSTRUCTIONS -DGTEST_HAS_RTTI=0 -DHAVE_ROUND -DUNICODE -D_UNICODE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -IC:/CPP/MSYS2/home/User/llvm-project-21.1.8.src/lldb/source/Host -IC:/CPP/MSYS2/home/User/llvm-project-21.1.8.src/build/2/include -IC:/CPP/MSYS2/home/User/llvm-project-21.1.8.src/llvm/include -Wa,-mbig-obj -Werror=date-time -Wall -Wextra -Wcast-qual -pedantic -O2 -std=c++17 -fno-exceptions -funwind-tables -fno-rtti -MD -MT tools/lldb/source/Host/CMakeFiles/lldbHost.dir/windows/MainLoopWindows.cpp.obj -c C:/CPP/MSYS2/home/User/llvm-project-21.1.8.src/lldb/source/Host/windows/MainLoopWindows.cppC:/.../lldb/source/Host/windows/MainLoopWindows.cpp: In destructor 'virtual {anonymous}::PipeEvent::~PipeEvent()':
C:/.../lldb/source/Host/windows/MainLoopWindows.cpp:61:66: error: invalid conversion from 'std::thread::native_handle_type' {aka 'long long unsigned int'} to 'HANDLE' {aka 'void*'} [-fpermissive]
61 | } while (WaitForSingleObject(m_monitor_thread.native_handle(), 1)
| ~~~~~~~~~~~~~~~~~~~~~~~~~~^~
|
| std::thread::native_handle_type {aka long long unsigned int}In file included from C:/CPP/mingw64/x86_64-w64-mingw32/include/winbase.h:35,
from C:/CPP/mingw64/x86_64-w64-mingw32/include/windows.h:70:
C:/.../include/synchapi.h:115:55: note: initializing argument 1 of 'DWORD WaitForSingleObject(HANDLE, DWORD)'
115 | WINBASEAPI DWORD WINAPI WaitForSingleObject (HANDLE hHandle, DWORD dwMilliseconds);
|
ninja: build stopped: subcommand failed.
Я спросил у ИИ, хотя был настроен скептично и думал, что придется разбираться и руками модифицировать код. НО он с первой попытки выдал полностью рабочий код!
Я удивился «Странно, обычно ИИ дает что-то не то, а тут даже докопаться нельзя». Я хотел уже выдать себя за гения, который портировал LLDB на MinGW-UCRT, но чувствовал что-то не то. Мне казалось, что ИИ украл откуда-то этот код, потому что не бывает таких идеальных совпадений. И знаете что? Я был прав! Он взял этот код из LLVM 22 (на 22.12.2025 это экспериментальная ветка).
У меня были смешанные эмоции. С одной стороны — я был прав, с другой — если я опубликую этот код как свой, то это — карма на всю жизнь. И я решил удалить любые упоминания, что код мой. Но пока я удалял упоминания, заметил, что можно добавить std::mutex, и подумал: с одной стороны — там работают умные люди и они бы не упустили такое, с другой — они же тоже люди и могли не заметить или не подумать.
В итоге я решил прогнать тесты и сборку. Результаты тестов ninja check-lldb вы можете посмотреть на фото ниже.




Но я подумал: а если тесты слишком «сухие» и на реальной работе это скажется? Я попросил ИИ сделать какой-нибудь супернавороченный код с Atomic, Threads, Vector, и LLDB с этим тоже справился. На мое удивление, даже не было ничего страшного, потому я оставил мой вариант кода (кто шарит - можете проверить и написать, я, как и говорил, новичок, поэтому буду рад экспертному мнению).
Почему не готовые варианты?
Пока я гуглил, как собрать, не раз натыкался на сборки Мартина Сторшё, известного в мире как mstorsjö. Я смотрел на его сборки, но проблема в том, что он очень сильно модифицирует исходники и собирает их из‑под Linux (могу ошибаться, но сайты, которые я смотрел, говорили про Linux). Любой, кто использует его сборки, может сказать, что они отлично работают, и вообще — какая разница, меняет он код или нет?
На что я отвечаю: допустим, он гений программирования, но он один. А в LLVM — 50 хороших программистов (условно). Пока он один будет сам себя проверять и сам писать, команда LLVM будет писать 50 разных частей, потому что каждый пишет свое. Плюс каждый сможет оценить работу своего коллеги и заметить ошибку, о которой знал только он. И что немаловажно: проект mstorsjö популярен в кругах MinGW, а не глобально. Инженеру на Linux/MacOS вообще все равно на MinGW, а в глобальном проекте огромная посещаемость и шанс, что кто‑то что‑то заметит, куда выше.
Заключение
Начал я свою работу 1 сентября 2025 года и надеялся, что максимум это займет пару дней. Но в итоге это переросло в нечто большее, на что я потратил около 3.8 месяца. Собралось оно у меня ровно так, как я обещал в самом начале статьи, только к 19 декабря 2025 года. Работал я по 3-5 часов (как я писал, я школьник, поэтому работал, когда мог, и предпочитал не играть, а работать).
Надеюсь, вам понравилось и вы оцените мой труд. Кому интересно — вот ссылка на репозиторий.
-----------------------------------------------------------------------------------------------------------------------------------
Список правок (Как я упоминал я новичок и потому учусь на ходу)
Правка 1 - Сократил вступление (Биографию, Почему именно Clang выбрал);Добавил дисклеймер; уточнил что скрин с тестом из MSYS2 может быть не правильным
Правка 2 - Изменены скриншоты с ninja check (Объяснение - MSYS2 не правильно вызывал ninja check)
Правка 3 - Добавил конкретные логи ошибок и разбор проблемных мест, с которыми столкнулся во время сборки; немного изменен Дисклеймер
