CMakeList 文件从 C 源文件生成 LLVM 位码文件

2024-01-05

我正在尝试使用 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)
  1. 我是 CMake 新手,不确定这是否是正确的方法。我在生成的 MakeFile 中找不到任何制作 *.bc 的规则 。请在这里纠正我。我也尝试过“-save-temps”

  2. 对于单个 .c 文件考虑这一点。如果您能给我一些关于为完整的 C 项目生成相同内容的提示,那将非常有帮助。


我认为你最终想要的是能够构建一个 C 程序 使用 CMake 和 clang 的项目,其中源文件被编译为 LLVM 位码 可执行文件是从位码文件链接的。

使用 CMake,要求 clang 链接位码文件意味着要求它链接LTO mode https://llvm.org/docs/LinkTimeOptimization.html, 与-flto联动选项。

你可以得到叮当声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 ..

Build:

$ 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

你将找不到任何*.bcMakefile 中的目标,也没有任何*.bc文件 生成:

$ egrep -r '.*\.bc'; echo Done
Done
$ find -name '*.bc'; echo Done
Done

因为编译选项-flto or -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!

Later

当我尝试“ 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 and main.c由 CMake 生成的 makefile 不会被调用hello.o and main.o but hello.c.o and 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 as a .PHONY target https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html这取决于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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CMakeList 文件从 C 源文件生成 LLVM 位码文件 的相关文章

随机推荐