Я думаю, что в конечном итоге вам нужно иметь возможность создать проект 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