├── .clang-format ├── .devcontainer ├── Dockerfile └── devcontainer.json ├── .editorconfig ├── .github └── workflows │ └── build.yml ├── .gitignore ├── .vscode ├── extensions.json └── settings.json ├── CMakeLists.txt ├── CMakePresets.json ├── LICENSE ├── README.md ├── cmake ├── FindClang-Wrapper.cmake ├── FindLLVM-Wrapper.cmake └── HunterPackages.cmake ├── examples └── example.bc └── src ├── example.cpp └── utility.hpp /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: LLVM 3 | AlignAfterOpenBracket: DontAlign 4 | AllowAllArgumentsOnNextLine: false 5 | AllowAllConstructorInitializersOnNextLine: false 6 | AllowAllParametersOfDeclarationOnNextLine: false 7 | AllowShortFunctionsOnASingleLine: None 8 | AllowShortLambdasOnASingleLine: None 9 | BinPackArguments: false 10 | BinPackParameters: false 11 | BreakConstructorInitializers: BeforeComma 12 | BreakInheritanceList: BeforeComma 13 | ColumnLimit: 100 14 | ConstructorInitializerIndentWidth: 2 15 | ContinuationIndentWidth: 2 16 | PackConstructorInitializers: Never 17 | PenaltyBreakAssignment: 200 18 | PenaltyReturnTypeOnItsOwnLine: 1000 19 | SortIncludes: Never 20 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/llvmparty/packages/ubuntu:22.04-llvm19.1.7 2 | 3 | RUN apt update && apt install -y --no-install-recommends \ 4 | gdb \ 5 | && rm -rf /var/lib/apt/lists/* 6 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | // README at: https://github.com/devcontainers/templates/tree/main/src/cpp 3 | { 4 | "name": "LLVMCMakeTemplate", 5 | "build": { 6 | "dockerfile": "Dockerfile" 7 | }, 8 | // Configure tool-specific properties. 9 | "customizations": { 10 | "vscode": { 11 | "extensions": [ 12 | "llvm-vs-code-extensions.vscode-clangd", 13 | "sunshaoce.llvmir", 14 | "twxs.cmake", 15 | "ms-vscode.cmake-tools", 16 | "EditorConfig.EditorConfig", 17 | "tamasfe.even-better-toml", 18 | "ms-vscode.cpptools", 19 | "esbenp.prettier-vscode" 20 | ] 21 | }, 22 | "codespaces": { 23 | "openFiles": [ 24 | "src/example.cpp" 25 | ] 26 | } 27 | }, 28 | "remoteEnv": { 29 | "PATH": "${containerWorkspaceFolder}/build:/cxx-common/install/bin:${containerEnv:PATH}" 30 | }, 31 | "postCreateCommand": "rm -rf build && cmake --preset clang" 32 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 4 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | insert_final_newline = true 13 | 14 | [*.md] 15 | indent_size = 2 16 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | cmake: 7 | # Skip building pull requests from the same repository 8 | if: ${{ github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository) }} 9 | runs-on: ubuntu-22.04 10 | container: 11 | image: ghcr.io/llvmparty/packages/ubuntu:22.04-llvm19.1.7 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v4 15 | 16 | - name: Build 17 | shell: bash 18 | run: | 19 | cmake --preset clang 20 | cmake --build build 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build*/ 2 | CMakeLists.txt.user 3 | .idea/ 4 | cmake-build-*/ 5 | llvm-project*/ 6 | .cache/ 7 | .DS_Store 8 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-vscode-remote.remote-containers" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | "**/.cache": true, 4 | }, 5 | "workbench.startupEditor": "none", 6 | "editor.formatOnSave": false, 7 | "C_Cpp.intelliSenseEngine": "disabled", 8 | "[cpp]": { 9 | "editor.formatOnSave": true, 10 | "editor.defaultFormatter": "llvm-vs-code-extensions.vscode-clangd" 11 | }, 12 | "[c]": { 13 | "editor.formatOnSave": true, 14 | "editor.defaultFormatter": "llvm-vs-code-extensions.vscode-clangd" 15 | }, 16 | "[json]": { 17 | "editor.formatOnSave": true 18 | }, 19 | "clangd.arguments": [ 20 | "--compile-commands-dir=${workspaceFolder}/build", 21 | "-header-insertion=never", 22 | "--function-arg-placeholders=0" 23 | ], 24 | "cmake.configureOnOpen": false, 25 | "cmake.useCMakePresets": "always", 26 | "cmake.options.statusBarVisibility": "hidden", 27 | "cmake.skipConfigureIfCachePresent": false, 28 | "cmake.showOptionsMovedNotification": false, // https://github.com/microsoft/vscode-cmake-tools/issues/3423#issuecomment-2002011868 29 | "cmake.options.advanced": { 30 | "build": { 31 | "statusBarVisibility": "visible" 32 | }, 33 | "launch": { 34 | "statusBarVisibility": "visible" 35 | }, 36 | "debug": { 37 | "statusBarVisibility": "visible" 38 | }, 39 | "buildTarget": { 40 | "statusBarVisibility": "visible" 41 | }, 42 | "launchTarget": { 43 | "statusBarVisibility": "visible" 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Needed for CMAKE_MSVC_RUNTIME_LIBRARY 2 | cmake_minimum_required(VERSION 3.15) 3 | cmake_policy(SET CMP0091 NEW) 4 | 5 | if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) 6 | message(FATAL_ERROR "In-tree builds are not supported. Run CMake from a separate directory: cmake -B build") 7 | endif() 8 | 9 | # Hunter package configuration 10 | option(HUNTER_ENABLED "Enable the hunter package manager to automatically download and compile LLVM" OFF) 11 | if(HUNTER_ENABLED) 12 | include(cmake/HunterPackages.cmake) 13 | endif() 14 | 15 | project(LLVMCMakeTemplate) 16 | 17 | # Enable solution folder support 18 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 19 | 20 | # Require c++17 21 | set(CMAKE_CXX_STANDARD 14) 22 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 23 | 24 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") 25 | 26 | find_package(LLVM-Wrapper REQUIRED) 27 | 28 | # MSVC-specific options 29 | if(MSVC) 30 | # TODO: This assumes the installed LLVM was built in Release mode 31 | # TODO: this is not very friendly cmake, probably this should respect the cache and not override the user's choice 32 | set(CMAKE_C_FLAGS_DEBUG "/ZI /Od /Ob0 /DNDEBUG" CACHE STRING "" FORCE) 33 | set(CMAKE_CXX_FLAGS_DEBUG "/ZI /Od /Ob0 /DNDEBUG" CACHE STRING "" FORCE) 34 | 35 | if(${LLVM_USE_CRT_RELEASE} STREQUAL "MD") 36 | set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreadedDLL) 37 | elseif(${LLVM_USE_CRT_RELEASE} STREQUAL "MT") 38 | set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded) 39 | else() 40 | message(FATAL_ERROR "Unsupported LLVM_USE_CRT_RELEASE=${LLVM_USE_CRT_RELEASE}") 41 | endif() 42 | endif() 43 | 44 | add_executable(example 45 | src/example.cpp 46 | ) 47 | target_link_libraries(example PRIVATE 48 | LLVM-Wrapper 49 | ) 50 | target_compile_features(example PRIVATE 51 | cxx_std_20 52 | ) 53 | 54 | # Set the main project as the startup project 55 | set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT example) 56 | -------------------------------------------------------------------------------- /CMakePresets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "configurePresets": [ 4 | { 5 | "name": "clang", 6 | "binaryDir": "${sourceDir}/build", 7 | "generator": "Ninja", 8 | "cacheVariables": { 9 | "CMAKE_C_COMPILER": "clang", 10 | "CMAKE_CXX_COMPILER": "clang++", 11 | "CMAKE_BUILD_TYPE": "Debug", 12 | "CMAKE_EXPORT_COMPILE_COMMANDS": "ON" 13 | } 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LLVMCMakeTemplate 2 | 3 | Just a simple example of how to properly link to LLVM with CMake on Windows, Linux and macos. 4 | 5 | ## Requirements 6 | 7 | - Visual Studio 2019 or a C++17 compiler that can build LLVM. 8 | - CMake 3.15 9 | 10 | **NOTE**: On Windows you may need to [enable long paths](https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd#enable-long-paths-in-windows-10-version-1607-and-later) to compile LLVM: 11 | 12 | ``` 13 | Windows Registry Editor Version 5.00 14 | 15 | [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem] 16 | "LongPathsEnabled"=dword:00000001 17 | ``` 18 | 19 | You will then need to reboot your machine for the changes to take effect. 20 | 21 | ## Compiling LLVM 22 | 23 | On Windows open a Visual Studio x64 command prompt: 24 | 25 | ```bash 26 | # Checkout LLVM 15 27 | git clone -b release/15.x --single-branch https://github.com/llvm/llvm-project.git --depth 1 28 | cd llvm-project 29 | 30 | # Build LLVM 31 | cmake -G Ninja -B build -S llvm -DCMAKE_BUILD_TYPE=Release "-DLLVM_ENABLE_PROJECTS=clang;lld" -DLLVM_PARALLEL_LINK_JOBS=1 -DLLVM_BUILD_EXAMPLES=OFF -DLLVM_BUILD_TESTS=OFF 32 | cmake --build build 33 | cmake --install build --prefix build/install 34 | ``` 35 | 36 | You can ZIP the install prefix to move it between machines. 37 | 38 | ## Building the project 39 | 40 | ```bash 41 | cmake -G Ninja -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_PREFIX_PATH=llvm-project/build/install 42 | cmake --build build 43 | ``` 44 | -------------------------------------------------------------------------------- /cmake/FindClang-Wrapper.cmake: -------------------------------------------------------------------------------- 1 | # This is an INTERFACE target for LLVM, usage: 2 | # target_link_libraries(${PROJECT_NAME} LLVM-Wrapper) 3 | # The include directories and compile definitions will be properly handled. 4 | 5 | set(CMAKE_FOLDER_LLVM "${CMAKE_FOLDER}") 6 | if(CMAKE_FOLDER) 7 | set(CMAKE_FOLDER "${CMAKE_FOLDER}/LLVM") 8 | else() 9 | set(CMAKE_FOLDER "LLVM") 10 | endif() 11 | 12 | # Find Clang 13 | find_package(Clang REQUIRED CONFIG) 14 | set(CLANG_LIBRARIES "clangBasic;clangLex;clangParse;clangAST;clangDynamicASTMatchers;clangASTMatchers;clangCrossTU;clangSema;clangCodeGen;clangAnalysis;clangEdit;clangRewrite;clangARCMigrate;clangDriver;clangSerialization;clangRewriteFrontend;clangFrontend;clangFrontendTool;clangToolingCore;clangToolingInclusions;clangToolingRefactoring;clangToolingASTDiff;clangToolingSyntax;clangDependencyScanning;clangTransformer;clangTooling;clangDirectoryWatcher;clangIndex;clangStaticAnalyzerCore;clangStaticAnalyzerCheckers;clangStaticAnalyzerFrontend;clangFormat;clangTesting;clangHandleCXX;clangHandleLLVM;libclang") 15 | 16 | message(STATUS "Using ClangConfig.cmake in: ${CLANG_CMAKE_DIR}") 17 | message(STATUS "Clang libraries: ${CLANG_LIBRARIES}") 18 | message(STATUS "Clang includes: ${CLANG_INCLUDE_DIRS}") 19 | 20 | add_library(Clang-Wrapper INTERFACE) 21 | target_include_directories(Clang-Wrapper SYSTEM INTERFACE ${CLANG_INCLUDE_DIRS}) 22 | 23 | # For LLVM: https://github.com/JonathanSalwan/Triton/issues/1082#issuecomment-1030826696 24 | # This variable also exists for Clang, but I don't know what the target is called 25 | if(CLANG_LINK_LLVM_DYLIB) 26 | message(FATAL_ERROR "Untested scenario, remove this and see if it works") 27 | target_link_libraries(Clang-Wrapper INTERFACE Clang) 28 | else() 29 | target_link_libraries(Clang-Wrapper INTERFACE ${CLANG_LIBRARIES}) 30 | endif() 31 | 32 | set(CMAKE_FOLDER "${CMAKE_FOLDER_LLVM}") 33 | unset(CMAKE_FOLDER_LLVM) 34 | -------------------------------------------------------------------------------- /cmake/FindLLVM-Wrapper.cmake: -------------------------------------------------------------------------------- 1 | # This is an INTERFACE target for LLVM, usage: 2 | # target_link_libraries(${PROJECT_NAME} LLVM-Wrapper) 3 | # The include directories and compile definitions will be properly handled. 4 | 5 | if(LLVM-Wrapper_FOUND OR TARGET LLVM-Wrapper) 6 | return() 7 | endif() 8 | 9 | set(CMAKE_FOLDER_LLVM "${CMAKE_FOLDER}") 10 | if(CMAKE_FOLDER) 11 | set(CMAKE_FOLDER "${CMAKE_FOLDER}/LLVM") 12 | else() 13 | set(CMAKE_FOLDER "LLVM") 14 | endif() 15 | 16 | # Extract the arguments passed to find_package 17 | # Documentation: https://cmake.org/cmake/help/latest/manual/cmake-developer.7.html#find-modules 18 | list(APPEND FIND_ARGS "${LLVM-Wrapper_FIND_VERSION}") 19 | if(LLVM-Wrapper_FIND_QUIETLY) 20 | list(APPEND FIND_ARGS "QUIET") 21 | endif() 22 | if(LLVM-Wrapper_FIND_REQUIRED) 23 | list(APPEND FIND_ARGS "REQUIRED") 24 | endif() 25 | 26 | # Find LLVM 27 | find_package(LLVM ${FIND_ARGS}) 28 | unset(FIND_ARGS) 29 | 30 | if(NOT LLVM-Wrapper_FIND_QUIETLY) 31 | message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") 32 | message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") 33 | endif() 34 | 35 | # Split the definitions properly (https://weliveindetail.github.io/blog/post/2017/07/17/notes-setup.html) 36 | separate_arguments(LLVM_DEFINITIONS) 37 | 38 | # https://github.com/JonathanSalwan/Triton/issues/1082#issuecomment-1030826696 39 | if(LLVM_LINK_LLVM_DYLIB) 40 | set(LLVM-Wrapper_LIBS LLVM) 41 | elseif(LLVM-Wrapper_FIND_COMPONENTS) 42 | if(NOT LLVM-Wrapper_FIND_QUIETLY) 43 | message(STATUS "LLVM components: ${LLVM-Wrapper_FIND_COMPONENTS}") 44 | endif() 45 | llvm_map_components_to_libnames(LLVM-Wrapper_LIBS ${LLVM-Wrapper_FIND_COMPONENTS}) 46 | else() 47 | set(LLVM-Wrapper_LIBS ${LLVM_AVAILABLE_LIBS}) 48 | endif() 49 | 50 | # Some diagnostics (https://stackoverflow.com/a/17666004/1806760) 51 | if(NOT LLVM-Wrapper_FIND_QUIETLY) 52 | message(STATUS "LLVM libraries: ${LLVM-Wrapper_LIBS}") 53 | message(STATUS "LLVM includes: ${LLVM_INCLUDE_DIRS}") 54 | message(STATUS "LLVM definitions: ${LLVM_DEFINITIONS}") 55 | message(STATUS "LLVM tools: ${LLVM_TOOLS_BINARY_DIR}") 56 | endif() 57 | 58 | add_library(LLVM-Wrapper INTERFACE IMPORTED) 59 | target_include_directories(LLVM-Wrapper SYSTEM INTERFACE ${LLVM_INCLUDE_DIRS}) 60 | target_link_libraries(LLVM-Wrapper INTERFACE ${LLVM-Wrapper_LIBS}) 61 | target_compile_definitions(LLVM-Wrapper INTERFACE ${LLVM_DEFINITIONS}) 62 | 63 | # Set the appropriate minimum C++ standard 64 | if(LLVM_VERSION VERSION_GREATER_EQUAL "16.0.0") 65 | # https://releases.llvm.org/16.0.0/docs/CodingStandards.html#c-standard-versions 66 | target_compile_features(LLVM-Wrapper INTERFACE cxx_std_17) 67 | elseif(LLVM_VERSION VERSION_GREATER_EQUAL "10.0.0") 68 | # https://releases.llvm.org/10.0.0/docs/CodingStandards.html#c-standard-versions 69 | target_compile_features(LLVM-Wrapper INTERFACE cxx_std_14) 70 | else() 71 | # https://releases.llvm.org/9.0.0/docs/CodingStandards.html#c-standard-versions 72 | target_compile_features(LLVM-Wrapper INTERFACE cxx_std_11) 73 | endif() 74 | 75 | if(WIN32) 76 | target_compile_definitions(LLVM-Wrapper INTERFACE NOMINMAX) 77 | 78 | # This target has an unnecessary diaguids.lib embedded in the installation 79 | if(TARGET LLVMDebugInfoPDB) 80 | get_target_property(LLVMDebugInfoPDB_LIBS LLVMDebugInfoPDB INTERFACE_LINK_LIBRARIES) 81 | foreach(LLVMDebugInfoPDB_LIB ${LLVMDebugInfoPDB_LIBS}) 82 | if(LLVMDebugInfoPDB_LIB MATCHES "diaguids.lib") 83 | list(REMOVE_ITEM LLVMDebugInfoPDB_LIBS "${LLVMDebugInfoPDB_LIB}") 84 | break() 85 | endif() 86 | endforeach() 87 | set_target_properties(LLVMDebugInfoPDB PROPERTIES 88 | INTERFACE_LINK_LIBRARIES "${LLVMDebugInfoPDB_LIBS}" 89 | ) 90 | unset(LLVMDebugInfoPDB_LIBS) 91 | endif() 92 | endif() 93 | 94 | set(CMAKE_FOLDER "${CMAKE_FOLDER_LLVM}") 95 | unset(CMAKE_FOLDER_LLVM) 96 | 97 | set(LLVM-Wrapper_FOUND ON) 98 | -------------------------------------------------------------------------------- /cmake/HunterPackages.cmake: -------------------------------------------------------------------------------- 1 | # Set up Hunter 2 | set(HUNTER_URL "https://github.com/LLVMParty/hunter/archive/ac772212b1da5bec948768feda299e2055486876.zip") 3 | set(HUNTER_SHA1 "9A8F3597943B56AE4C9C325FB90D85C161A3EB8F") 4 | 5 | set(HUNTER_LLVM_VERSION 13.0.1) 6 | set(HUNTER_LLVM_CMAKE_ARGS 7 | LLVM_ENABLE_CRASH_OVERRIDES=OFF 8 | LLVM_ENABLE_ASSERTIONS=ON 9 | LLVM_ENABLE_PROJECTS=clang;lld 10 | ) 11 | set(HUNTER_PACKAGES LLVM) 12 | 13 | include(FetchContent) 14 | message(STATUS "Fetching hunter...") 15 | FetchContent_Declare(SetupHunter GIT_REPOSITORY https://github.com/cpp-pm/gate) 16 | FetchContent_MakeAvailable(SetupHunter) -------------------------------------------------------------------------------- /examples/example.bc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LLVMParty/LLVMCMakeTemplate/e4769489d3b144f2978ce00880df306801582f64/examples/example.bc -------------------------------------------------------------------------------- /src/example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "utility.hpp" 5 | 6 | using namespace llvm; 7 | 8 | static void ProcessModule(Module &M) { 9 | // TODO: do something meaningful here 10 | for (Function &F : M.functions()) { 11 | for (BasicBlock &BB : F) { 12 | for (Instruction &I : BB) { 13 | if (auto Load = dyn_cast(&I)) { 14 | } 15 | } 16 | } 17 | } 18 | } 19 | 20 | int main(int argc, char **argv) { 21 | // Parse arguments 22 | if (argc < 2) { 23 | puts("Usage: example in.bc [out.bc]"); 24 | return EXIT_FAILURE; 25 | } 26 | auto inFile = argv[1]; 27 | auto outFile = argc > 2 ? argv[2] : nullptr; 28 | 29 | // Load module 30 | LLVMContext C; 31 | auto M = LoadModule(C, inFile); 32 | 33 | // Process module 34 | try { 35 | ProcessModule(*M); 36 | } catch (const std::exception &x) { 37 | outs() << x.what() << "\n"; 38 | return EXIT_FAILURE; 39 | } 40 | 41 | // Save module 42 | if (outFile != nullptr) { 43 | SaveModule(M.get(), outFile); 44 | } 45 | 46 | return EXIT_SUCCESS; 47 | } 48 | -------------------------------------------------------------------------------- /src/utility.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | inline std::unique_ptr LoadModule(llvm::LLVMContext &Context, 18 | const std::string &Filename) { 19 | llvm::SMDiagnostic Err; 20 | auto M = llvm::parseIRFile(Filename, Err, Context); 21 | if (!M) { 22 | llvm::errs() << "Failed to parse IR: " << Err.getMessage() << "\n"; 23 | llvm::errs().flush(); 24 | std::exit(EXIT_FAILURE); 25 | } 26 | return M; 27 | } 28 | 29 | inline void SaveModule(llvm::Module *Module, const std::string &Filename) { 30 | if (Filename.ends_with(".ll") || Filename.ends_with(".txt")) { 31 | std::error_code EC; 32 | llvm::raw_fd_ostream RFO(Filename, EC); 33 | Module->print(RFO, nullptr, true, true); 34 | } else if (Filename.ends_with(".bc")) { 35 | std::error_code EC; 36 | llvm::ToolOutputFile Out(Filename, EC, llvm::sys::fs::OF_None); 37 | WriteBitcodeToFile(*Module, Out.os(), true); 38 | if (EC) { 39 | llvm::errs() << "Failed to write IR: " << EC.message() << "\n"; 40 | llvm::errs().flush(); 41 | std::exit(EXIT_FAILURE); 42 | } 43 | Out.keep(); 44 | } else { 45 | llvm::errs() << "Unsupported output extension for filename '" << Filename << "'\n"; 46 | llvm::errs().flush(); 47 | std::exit(EXIT_FAILURE); 48 | } 49 | } 50 | --------------------------------------------------------------------------------