Я пытаюсь сгенерировать файл байт-кода LLVM из исходного файла C (hello.c) с помощью CMake. А ниже мой файл CMakeLists.
###### CMakelists.txt ############
cmake_minimum_required(VERSION 2.8.9)
set(CMAKE_C_COMPILER "clang")
set(CMAKE_C_FLAGS "-emit-llvm")
project (hello)
add_executable(hello hello.c)
Я новичок в CMake и не уверен, что это правильный путь. Я не смог найти никаких правил для создания *.bc в сгенерированном MakeFile. . Пожалуйста, поправьте меня здесь. Я также пробовал "-save-temps"
Учитывая это для одного файла .c. Было бы очень полезно, если бы вы могли дать мне несколько советов по созданию того же самого для полного проекта C.





Я думаю, что вы в конечном итоге хотите, чтобы иметь возможность построить C-программу проект с CMake и clang, в котором исходные файлы скомпилированы в биткод LLVM и исполняемый файл связан с файлами битового кода.
При использовании CMake просьба к clang to связать файлы битового кода означает запрос на ссылку в режим LTO,
с опцией связи -flto.
И вы можете получить clang для биткода компилировать в LLVM с компиляцией -flto
или с опцией -emit-llvm.
Для иллюстрации вот проект Hello World, состоящий из двух исходных файлов и одного заголовка:
$ ls -R
.:
CMakeLists.txt hello.c hello.h main.c
Здесь:
CMakeLists.txt
cmake_minimum_required(VERSION 3.0.2)
project (hello)
set(CMAKE_C_COMPILER clang)
set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} "-flto")
add_executable(hello main.c hello.c)
target_compile_options(hello PUBLIC ${CMAKE_C_FLAGS} -flto)
#target_compile_options(hello PUBLIC ${CMAKE_C_FLAGS} -emit-llvm)
Он будет одинаково хорошо работать с:
#target_compile_options(hello PUBLIC ${CMAKE_C_FLAGS} -flto)
target_compile_options(hello PUBLIC ${CMAKE_C_FLAGS} -emit-llvm)
Создайте каталог сборки для CMake и перейдите туда:
$ mkdir build
$ cd build
Сгенерируйте систему сборки:
$ cmake ..
Строить:
$ make
Scanning dependencies of target hello
[ 33%] Building C object CMakeFiles/hello.dir/main.c.o
[ 66%] Building C object CMakeFiles/hello.dir/hello.c.o
[100%] Linking C executable hello
[100%] Built target hello
Вы не найдете ни *.bc целей в Makefiles, ни *.bc файлов.
сгенерировано:
$ egrep -r '.*\.bc'; echo Done
Done
$ find -name '*.bc'; echo Done
Done
потому что вариант компиляции -flto или -emit-llvm приводит к выводу
файл:
CMakeFiles/hello.dir/main.c.o
CMakeFiles/hello.dir/hello.c.o
который соответствует обычному соглашению об именах CMake, но на самом деле не является объектный файл но файл битового кода LLVM, как вы видите:
$ file $(find -name '*.o')
./CMakeFiles/hello.dir/hello.c.o: LLVM IR bitcode
./CMakeFiles/hello.dir/main.c.o: LLVM IR bitcode
Программа делает обычное дело:
$ ./hello
Hello World!
Позже
When I try " make hello.o " it should generate the object file right? the cmd executes successfully but, could not find the generated object file. Am I doing it right?
Вы делаете это одним правильным способом, хотя и не единственным правильным, но ваши ожидания ошибочны. Посмотрите еще раз:
$ file $(find -name '*.o')
./CMakeFiles/hello.dir/hello.c.o: LLVM IR bitcode
./CMakeFiles/hello.dir/main.c.o: LLVM IR bitcode
Вы можете видеть, что файлы .o, созданные из hello.c и main.c
make-файлом, сгенерированным CMake, вызываются не hello.o и main.o, а hello.c.o
и main.c.o. CMake предпочитает скомпилированное имя файла, чтобы сохранить расширение
исходный файл и добавьте .o. Это довольно распространенная практика. Итак, если вы хотели
использовать make-файл для компиляции hello.c, наиболее очевидным правильным способом будет
make hello.c.o.
Давайте посмотрим, что происходит на самом деле. В моем каталоге сборки CMake:
$ make VERBOSE=1 hello.c.o
make -f CMakeFiles/hello.dir/build.make CMakeFiles/hello.dir/hello.c.o
make[1]: Entering directory '/home/imk/develop/so/scrap/build'
make[1]: 'CMakeFiles/hello.dir/hello.c.o' is up to date.
make[1]: Leaving directory '/home/imk/develop/so/scrap/build'
Делать было нечего, потому что мой hello.c.o был в актуальном состоянии. Так что я
удалите его и повторите:
$ rm CMakeFiles/hello.dir/hello.c.o
$ make VERBOSE=1 hello.c.o
make -f CMakeFiles/hello.dir/build.make CMakeFiles/hello.dir/hello.c.o
make[1]: Entering directory '/home/imk/develop/so/scrap/build'
Building C object CMakeFiles/hello.dir/hello.c.o
clang -flto -o CMakeFiles/hello.dir/hello.c.o -c /home/imk/develop/so/scrap/hello.c
make[1]: Leaving directory '/home/imk/develop/so/scrap/build'
Теперь он был перекомпилирован.
Однако, поскольку многие люди, такие как вы, ожидают, что hello.o будет скомпилирован
из hello.c, CMake услужливо определяет hello.o как .PHONY цель
это зависит от hello.c.o:
$ egrep -A3 'hello.o.*:.*hello.c.o' Makefile
hello.o: hello.c.o
.PHONY : hello.o
Так что на самом деле я могу сделать:
$ rm CMakeFiles/hello.dir/hello.c.o
$ make VERBOSE=1 hello.o
make -f CMakeFiles/hello.dir/build.make CMakeFiles/hello.dir/hello.c.o
make[1]: Entering directory '/home/imk/develop/so/scrap/build'
Building C object CMakeFiles/hello.dir/hello.c.o
clang -flto -o CMakeFiles/hello.dir/hello.c.o -c /home/imk/develop/so/scrap/hello.c
make[1]: Leaving directory '/home/imk/develop/so/scrap/build'
make hello.o это еще один способ сделать hello.c.o
Спасибо, сэр, я понял это. Я хочу попросить вас еще об одной помощи. Основная цель — сгенерировать единый файл битового кода LLVM для всей программы. И LLVMgold нужно исключить. Итак, теперь у нас есть файлы битового кода, что нужно добавить в CMakelists.txt, чтобы он использовал llvm-link для создания окончательного файла битового кода, связывающего эти предыдущие. Не могли бы вы помочь мне с этим? Спасибо
@ manojh93 manojh93 Извините, в Stackoverflow вы не можете продолжать сворачивать вопрос в новые вопросы. См. Что мне делать, когда кто-то отвечает на мой вопрос?. Если у вас есть проблема, выходящая за рамки исходного вопроса, которую вы не можете решить самостоятельно, вам следует задать новый вопрос
Проблема в том, что использование флага -emit-llvm не создает окончательный двоичный файл и останавливает тесты конфигурации, которые выполняет CMake, когда в них используется этот флаг.
Помимо того, что уже было написано об использовании инфраструктуры ДН, у вас есть 3 (или 2 с половиной) других альтернативы.
Один из них — использовать Полная программа LLVM и использовать предоставленные команды для извлечения соответствующих частей битового кода.
Другой способ — вручную настроить пользовательские цели (см. add_custom_target и add_custom_command) на ваших двоичных целях CMake, которые будут срабатывать при изменениях и будут воспроизводить желаемый результат, как если бы каждый раз выполнялись вручную в командной строке.
Теперь, в этом последнем пункте, у меня была аналогичная потребность, поэтому я создал проект CMake, который обеспечивает эту функциональность (llvm-ir-cmake-утилиты), но позволяет вам подключать эти пользовательские цели к существующим, как вам угодно и сочтете нужным, без необходимости переписывать все из каждый раз царапать.
В репозитории есть примеры, но, короче говоря, он позволяет вам прикреплять пользовательские цели к уже существующим целям CMake, например.
[...]
add_executable(qux ${SOURCES})
[...]
# this will create a bitcode generating target
# and allow it to depend on the initial target in order to detect source code changes
llvmir_attach_bc_target(qux_bc qux)
add_dependencies(qux_bc qux)
[...]
После сделать,
$>file CMakeFiles/hello.dir/hello.c.o
CMakeFiles/hello.dir/hello.c.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
если установить (CMAKE_C_FLAGS "-emit-llvm")
написано раньше
project (hello)
Чтобы получить биткод IR, я написал:
###### CMakelists.txt ############
cmake_minimum_required(VERSION 2.8.9)
project (hello)
set(CMAKE_C_COMPILER "clang")
set(CMAKE_C_FLAGS "-flto")
set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} "-flto")
add_executable(hello hello.c)
target_compile_options(hello PUBLIC ${CMAKE_C_FLAGS} -flto)
Я работал несколько часов, чтобы Makefile работал для компиляции из IR код в родной с помощью lld, тогда с cmake это было намного быстрее. Затем, прочитав сгенерированный cmake Makefile, я смог исправить свой Makefile:
clang -flto -flto <hello.c.o> ..
это сработало, но я не знаю, почему -flto пишется дважды.
Большое спасибо за этот пост, показывающий clang как централизованный интерфейс для различных команд, предоставляемых llvm.
Спасибо за подробное объяснение. Я попытался и получил ошибку, связанную с золотым линкером. " ошибка при загрузке плагина: /usr/bin/../lib/LLVMgold.so: невозможно открыть общий объектный файл: нет такого файла или каталога " Я работаю над этим, но когда я пытаюсь " сделать hello.o ", он должен генерировать объектный файл не так ли? cmd выполняется успешно, но не может найти сгенерированный объектный файл. Правильно ли я делаю?