LLVM系列第十一章:写一个Hello World

系列文章目录

LLVM系列第一章:编译LLVM源码
LLVM系列第二章:模块Module
LLVM系列第三章:函数Function
LLVM系列第四章:逻辑代码块Block
LLVM系列第五章:全局变量Global Variable
LLVM系列第六章:函数返回值Return
LLVM系列第七章:函数参数Function Arguments
LLVM系列第八章:算术运算语句Arithmetic Statement
LLVM系列第九章:控制流语句if-else
LLVM系列第十章:控制流语句if-else-phi
LLVM系列第十一章:写一个Hello World
LLVM系列第十二章:写一个简单的词法分析器Lexer
LLVM系列第十三章:写一个简单的语法分析器Parser
LLVM系列第十四章:写一个简单的语义分析器Semantic Analyzer
LLVM系列第十五章:写一个简单的中间代码生成器IR Generator
LLVM系列第十六章:写一个简单的编译器
LLVM系列第十七章:for循环
LLVM系列第十八章:写一个简单的IR处理流程Pass
LLVM系列第十九章:写一个简单的Module Pass
LLVM系列第二十章:写一个简单的Function Pass
LLVM系列第二十一章:写一个简单的Loop Pass
LLVM系列第二十二章:写一个简单的编译时函数调用统计器(Pass)
LLVM系列第二十三章:写一个简单的运行时函数调用统计器(Pass)
LLVM系列第二十四章:用Xcode编译调试LLVM源码
LLVM系列第二十五章:简单统计一下LLVM源码行数
LLVM系列第二十六章:理解LLVMContext
LLVM系列第二十七章:理解IRBuilder
LLVM系列第二十八章:写一个JIT Hello World
LLVM系列第二十九章:写一个简单的常量加法“消除”工具(Pass)

flex&bison系列


本文目录

  • 前言
  • 一、项目结构
  • 二、项目细节
    • 1. 程序模块
    • 2. 引入LLVM
    • 3. Hello World
  • 三、编译LLVM
    • 1. 生成项目文件
    • 2. 编译
    • 3. 安装
  • 三、编译Hello World
    • 1. 生成项目文件
    • 2. 编译
    • 3. 安装
    • 4. 运行
  • 四、总结


前言

在此记录下基于LLVM写一个Hello World的过程,以备查阅。

开发环境的配置请参考第一章 《LLVM系列第一章:编译LLVM源码》。

一、项目结构

我们把这个简单的项目命名为SimpleLang。可以参考LLVM及Clang的源码组织结构,来组织我们自己的代码(示例):

% tree -I "build|build-simplelang|llvm-12"      
.
├── CMakeLists.txt
├── README.md
├── cmake
│   └── modules
│       └── AddSimpleLang.cmake
├── include
│   └── simplelang
│       └── Basic
│           ├── Version.h
│           └── Version.inc.in
├── lib
│   ├── Basic
│   │   ├── CMakeLists.txt
│   │   └── Version.cpp
│   └── CMakeLists.txt
└── tools
    ├── CMakeLists.txt
    └── driver
        ├── CMakeLists.txt
        └── Driver.cpp

9 directories, 11 files

注意我们自己的项目可以放在任何位置,没有必要放在LLVM的源码目录下。

二、项目细节

1. 程序模块

这个简单的项目只包含了两个模块:

  1. simplelang,一个简单的可执行文件
  2. simplelangBasic,一个简单的library(库)

simplelang将会调用simplelangBasic中的函数,并把结果打印出来。simplelang需要链接simplelangBasic,才能调用其函数。

以下是跟项目组织结构相关的部分CMake脚本。

(1) 项目根目录(示例):

# CMakeLists.txt

if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
  project(SimpleLang)
  ...
endif()

add_subdirectory(lib)
add_subdirectory(tools)

(2) lib目录(示例):

# lib/CMakeLists.txt

add_subdirectory(Basic)
# lib/Basic/CMakeLists.txt

add_simplelang_library(simplelangBasic
  ....cpp
)

注意到这里会构建出simplelangBasic library。

(3) tools目录(示例):

# tools/CMakeLists.txt

add_simplelang_subdirectory(driver)
# tools/driver/CMakeLists.txt

set(LLVM_LINK_COMPONENTS
  Support
)

add_simplelang_tool(simplelang
  ....cpp
)

target_link_libraries(simplelang
  PRIVATE
  simplelangBasic
)

注意到这里会构建出simplelang, 并且让其链接simplelangBasic。

2. 引入LLVM

我们需要做一些与LLVM相关的配置,才能顺利地使用LLVM(示例):

find_package(LLVM REQUIRED HINTS "${LLVM_CMAKE_PATH}")
list(APPEND CMAKE_MODULE_PATH ${LLVM_DIR})

include(AddLLVM)
include(HandleLLVMOptions)

include_directories("${LLVM_BINARY_DIR}/include" "${LLVM_INCLUDE_DIR}")
link_directories("${LLVM_LIBRARY_DIR}")

set(SIMPLELANG_BUILT_STANDALONE 1)

3. Hello World

我们的C++代码放在两个文件中:

  1. tools/driver/Driver.cpp,属于模块simplelang
  2. lib/Basic/Version.cpp,属于模块simplelangBasic

main函数在Driver.cpp中(示例):

#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/raw_ostream.h"
#include "simplelang/Basic/Version.h"

int main(int argc, const char **argv)
{
    llvm::InitLLVM llvmInitializer(argc, argv);
  
    llvm::outs() << "Hello World! (version " << simplelang::getSimpleLangVersion() << ")\n";
}

我们看到以上代码调用了函数getSimpleLangVersion(),它来自于Version.cpp(示例):

std::string simplelang::getSimpleLangVersion()
{
    return SIMPLELANG_VERSION_STRING;
}

其中SIMPLELANG_VERSION_STRING仅仅是个string而已,它的值为"0.1"。

三、编译LLVM

1. 生成项目文件

用CMake工具生成项目文件(示例):

mkdir build
cd build

cmake -G Ninja -DCMAKE_BUILD_TYPE=Release \
	-DLLVM_EXTERNAL_PROJECTS=simplelang \
	-DLLVM_EXTERNAL_SIMPLELANG_SOURCE_DIR=../simplelang \
	-DCMAKE_INSTALL_PREFIX=../llvm-12 \
	/path/to/llvm-project/llvm

注意/path/to/llvm-project代表的是llvm-project的源代码路径。

输出log如下(示例):

-- The C compiler identification is AppleClang 13.0.0.13000029
-- The CXX compiler identification is AppleClang 13.0.0.13000029
-- The ASM compiler identification is Clang with GNU-like command-line
-- Found assembler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found libtool - /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool
...
-- Configuring done
-- Generating done
-- Build files have been written to: /path/to/hello-world/build

2. 编译

用ninja工具进行编译(示例):

ninja

输出log如下(示例):

[2996/2996] Linking CXX executable bin/obj2yaml

3. 安装

用ninja进行安装(示例):

ninja install

输出log如下(示例):

[0/1] Install the project...
-- Install configuration: "Release"
-- Installing: /path/to/hello-world/llvm-12/include/llvm
...

三、编译Hello World

1. 生成项目文件

用CMake生成项目文件(示例):

mkdir build-simplelang
cd build-simplelang
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release \
-DLLVM_DIR=../llvm-12/lib/cmake/llvm \
-DCMAKE_INSTALL_PREFIX=../llvm-12 \
../

输出log如下(示例):

-- The C compiler identification is AppleClang 13.0.0.13000029
-- The CXX compiler identification is AppleClang 13.0.0.13000029
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found ZLIB: /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.1.sdk/usr/lib/libz.tbd (found version "1.2.11") 
-- Found LibXml2: /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.1.sdk/usr/lib/libxml2.tbd (found version "2.9.4") 
-- Linker detection: ld64
...
...
-- Building with -fPIC
-- Configuring done
-- Generating done
-- Build files have been written to: /path/to/hello-world/build-simplelang

2. 编译

用ninja进行编译(示例):

ninja

输出log如下(示例):

[4/4] Linking CXX executable tools/driver/simplelang

3. 安装

用ninja进行安装(示例):

ninja install

输出log如下(示例):

[0/1] Install the project...
-- Install configuration: "Release"
-- Installing: /path/to/hello-world/llvm-12/lib/libsimplelangBasic.a
-- Installing: /path/to/hello-world/llvm-12/bin/simplelang

4. 运行

运行Hello World(示例):

../llvm-12/bin/simplelang

输出结果如下(示例):

Hello World! (version 0.1)

四、总结

我们参考LLVM的项目组织结构,基于LLVM提供的API,用C++写了一个Hello World,并且编译运行成功。完整源码示例请参看:
https://github.com/wuzhanglin/llvm-hello-world

你可能感兴趣的:(编译器,C++,编译器)