我正在尝试使用CMake从C源文件(hello.c)生成LLVM字节码文件。下面是我的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的新手,不确定这是否正确。我在生成的MakeFile中找不到任何使* .bc的规则 。请在这里纠正我。我也尝试过“ -save-temps”
将其视为单个.c文件。如果您能给我一些有关为完整的C项目生成相同内容的提示,那将真的很有帮助。
答案 0 :(得分:1)
完成后,
$>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提供的各种命令的集中前端。
答案 1 :(得分:0)
我认为您最终想要的是能够构建C程序 CMake和clang的项目,其中源文件被编译为LLVM位码 并且可执行文件是从位码文件链接的。
对于CMake,要求clang链接位代码文件意味着要求其链接LTO mode中的内容,
使用-flto
链接选项。
您可以使用-flto
编译使clang编译为 到LLVM位代码
选项,或使用-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
在Makefile文件中找不到任何*.bc
个目标,也没有*.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生成的makefile生成的hello.o
不是main.o
,而是hello.c.o
和main.c.o
。 CMake更喜欢使用编译后的文件名来保留扩展名。
源文件,并附加.o
。这是相当普遍的做法。所以如果你想
使用makefile来编译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
答案 2 :(得分:0)
问题在于,使用-emit-llvm
标志不会产生最终的二进制文件,并且一旦在其中使用了该标志,CMake将停止配置测试。
除了关于使用LTO基础结构的文章外,还有3种(或2种半)其他选择。
一种方法是使用Whole-Program LLVM并使用提供的命令来提取相关的位码部分。
另一种方法是采用手动方式在CMake二进制目标上设置自定义目标(请参见add_custom_target
和add_custom_command
),该目标将在更改时触发,并且将再现所需的结果,就像每次在命令行上手动执行。
现在,在最后一点上,我有类似的需求,因此我创建了一个提供该功能(llvm-ir-cmake-utils)的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)
[...]