Файл CMakeList для создания файла битового кода LLVM из исходного файла C - PullRequest
0 голосов
/ 25 февраля 2019

Я пытаюсь сгенерировать файл байт-кода 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)
  1. Я новичок в CMake и не уверен, что это правильный путь.Я не смог найти никаких правил для создания * .bc в сгенерированном MakeFile.Пожалуйста, поправьте меня здесь.Я также попробовал "-save-temps"

  2. Учитывая это для одного файла .c.Было бы очень полезно, если бы вы могли дать мне несколько советов по генерации того же самого для полного проекта C.

Ответы [ 2 ]

0 голосов
/ 26 февраля 2019

Проблема в том, что использование флага -emit-llvm не создает окончательный двоичный файл и останавливает тесты конфигурации, которые CMake выполняет, когда этот флаг используется в них.

Помимо того, что уже было написано об использовании LTO инфраструктуры, у вас есть 3 (или 2 с половиной) других альтернативы.

Один из них - использовать Whole-Programme LLVM и использовать предоставленные команды для извлечениясоответствующие части битового кода.

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

Теперь, в этом последнем пункте, у меня возникла аналогичная потребность, поэтому я создал проект CMake, который предоставляетэта функциональность ( llvm-ir-cmake-utils ), но позволяет вам подключать эти пользовательские цели к существующим по своему усмотрению и при необходимости без необходимости переписывать всекаждый раз с нуля.

В репозитории есть примеры, но вкратце, это позволяет вам прикреплять пользовательские цели к уже существующим целям 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)
[...]
0 голосов
/ 25 февраля 2019

Я думаю, что в конечном итоге вам нужно иметь возможность создать проект C-программы с CMake и clang, в котором исходные файлы компилируются в битовый код LLVM, а исполняемый файл связан с файлами битового кода.

СCMake, запрашивать clang для связывания файлов с битовым кодом означает запрашивать его для связи в режиме LTO с опцией -flto.

И вы можете получить clang для compile в битовый код 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 в файлах Makefile, ни сгенерированных файлов *.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!

Позже

Когда япопробуйте "make hello.o", он должен сгенерировать объектный файл, верно?cmd выполняется успешно, но не может найти сгенерированный объектный файл.Я делаю это правильно?

Вы делаете это одним способом, который является правильным, хотя не единственным способом, который является правильным, но ваши ожидания ошибочны.Посмотрите еще раз:

$ 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 сгенерированным CMake make-файлом, не называются 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 target , который зависит от 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

...