Code Monkey home page Code Monkey logo

llvm-ir-cmake-utils's Introduction

LLVM IR cmake utilities

Introduction

A collection of helper cmake functions/macros that eases the generation of LLVM IR and the application of various LLVM opt passes while obtaining and preserving the separate IR files that are generated by each user-defined step.

Requirements

  • cmake 3.0.0 or later
  • LLVM tools:
    • Currently used:
      • clang/clang++
      • opt
      • llvm-dis / llvm-as
      • llvm-link
    • Tested with:
      • 3.7 and later

Installation

  • Clone this repo (or even add it as a submodule to your project).
  • In your CMakeLists.txt file include(LLVMIRUtil).
  • You are good to go!

Quick overview

The provided cmake commands are expected to work in a parasitic way to targets created via add_executable() and add_library. The "gateway" command is llvmir_attach_bc_target() which generates the required bitcode files. Currently, C/C++ are supported via clang/clang++, but in theory any compiler which produces LLVM bitcode should be easily supported (depending how nice it plays with cmake too).

The cmake calls currently provided are:

  • llvmir_attach_bc_target() Attaches to an existing target that can be compiled down to LLVM IR and does just that, using all the related flags and options from the main target. The existing supported targets make use of clang/clang++, so currently this means that the C/C++ language is supported. It uses add_custom_library() cmake command under the hood. This creates a target of type LLVMIR.

  • llvmir_attach_opt_pass_target() Attaches to a target of type LLVMIR and applies various opt passes to its bitcode files, specified as arguments. It uses add_custom_library() cmake command under the hood. This creates a target of type LLVMIR.

  • llvmir_attach_disassemble_target() Attaches to a target of type LLVMIR and uses llvm-dis to disassemble its bitcode files. It uses add_custom_library() cmake command under the hood. This creates a target of type LLVMIR.

  • llvmir_attach_assemble_target() Attaches to a target of type LLVMIR and uses llvm-as to assemble its bitcode files. It uses add_custom_library() cmake command under the hood. This creates a target of type LLVMIR.

  • llvmir_attach_link_target() Attaches to a target of type LLVMIR and uses llvm-link to link its bitcode files to a single bitcode file. The output bitcode file is names after the target name. It uses add_custom_library() cmake command under the hood. This creates a target of type LLVMIR.

  • llvmir_attach_library() Attaches to a target of type LLVMIR and uses the appropriate compiler to compile its bitcode files to a native library. The output library name uses the target name according to platform rules. It uses add_library() cmake command under the hood. This creates a target of type LLVMIR.

  • llvmir_attach_executable() Attaches to a target of type LLVMIR and uses the appropriate compiler to compile its bitcode files to a native executable. The output library name uses the target name according to platform rules. It uses add_executable() cmake command under the hood. This creates a target of type LLVMIR.

Influential properties

  • LLVMIR_SHORT_NAME This property, if present, controls the output name for the calls that produce a single object (e.g. archive, library, etc.):
    • llvmir_attach_link_target()
    • llvmir_attach_library()
    • llvmir_attach_executable()

CAUTION

If you require to get raw unoptimized LLVM IR, but with the ability to further optimize it later on and you are compiling with LLVM 5 or later, you need to add the following compile options, either:

-O1 -Xclang -disable-llvm-passes

or

-O0 -Xclang -disable-O0-optnone

This is because, since LLVM 5, using -O0 add the optnone attribute to all functions.

Basic Usage

Have a look and toy around with the included examples in this repo. The easiest way to start is:

  1. git clone this repo.
  2. Create a directory for an out-of-source build and cd into it.
  3. CC=clang CXX=clang++ cmake [path to example source dir]
  4. cmake --build .
  5. cmake --build . --target help to see available target and use them for bitcode generation.

llvm-ir-cmake-utils's People

Contributors

compor avatar otsmr avatar tandf avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

llvm-ir-cmake-utils's Issues

Allow custom 'clean' targets for bitcode generation to work with other generators

Currently the use of ADDITIONAL_MAKE_CLEAN_FILES for marking custom generated files in the build directory to be clean up, only works for the make generator. Use a custom target to work around and allow proper clean-up when other generators are used (e.g. ninja).

Also, see this for why there is currently no way to add dependencies to the special clean target.

get absolute IN_FILE based on SOURCE_DIR of DEPENDS_TRGT

Hi compor,

In llvmir_attach_bc_target, to get the absolute path of the in-file, currently get_filename_component is used:

get_filename_component(INFILE ${IN_FILE} ABSOLUTE)

According to the doc, get_filename_component resolves the absolute path based on the CMAKE_CURRENT_SOURCE_DIR variable.

If no base directory is provided, the default base directory will be CMAKE_CURRENT_SOURCE_DIR.

However, the CMAKE_CURRENT_SOURCE_DIR variable doesn't always stand for the path where the DEPENDS_TRGT is defined. To handle the cases where CMAKE_CURRENT_SOURCE_DIR is messed up, I propose to instead explicitly look for the source path of DEPENDS_TRGT, i.e. use the SOURCE_DIR:

This read-only property reports the value of the CMAKE_CURRENT_SOURCE_DIR variable in the directory in which the target was defined.

For normal cases where the CMAKE_CURRENT_SOURCE_DIR variable is not messed up, it should contain the same value as SOURCE_DIR.

I have submitted a pull request for this change, see #28. Please let me know if you have any question. Thanks!

Adding source code files from linked libraries

Hi compor,

Regarding #23, I think you have a point. I didn't know that it's possible to use llvmir_attach_bc_targets to the library target first. Thanks for the information!

I'm building an automatic pipeline to generate IR files for a lot of cmake projects. What I have in my script is to find all targets defined using add_excutable() and add llvmir_attach_bc_targets(), llvmir_attach_link_target() and llvmir_attach_disassemble_target() for them. So for the libraries, do you think I should add an additional llvmir_attach_bc_targets() and then include it in llvmir_attach_link_target()? Thank you!

Linking a LLVMIR library

I am trying to link a static library that was created with llvmir_attach_library to a target that then in turn goes through the llvmir stages itself. However, it fails when trying to link the library:

/usr/bin/ld: lib/libbar_bc_lib.a: error adding symbols: archive has no index; run ranlib to add one
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [src/CMakeFiles/foo.dir/build.make:98: src/foo] Error 1
make[1]: *** [CMakeFiles/Makefile2:367: src/CMakeFiles/foo.dir/all] Error 2
make: *** [Makefile:91: all] Error 2

What I noticed, is that the object file bar.cpp.o is missing. But when I modify the src/lib/CMakeLists.txt, so it can be treated as its own cmake project, everything works fine and the object files are present. Any idea what I might be doing wrong? This is the commit with the example I added

How to support px4 compilation?

hello, I'm trying to generate llvm IR in px4 compilation using your tool, I imported cmake as you requested and added include to CMakeLists.txt, during cmake I see the console output - LLVM IR Utils. finally I run make to compile but it doesn't work until I don't see IR until the binary is generated. Does your tool support px4 compilation?

Fix debug messages

Hi compor,

I notice there are some mistakes in the debug messages. I just submitted a pull request to fix them, see #26. It'll be great if you could help me review it. Please tell me if you have any questions. Thanks.

Example 3: No bytecode generation

Is it intentional that Example 3 does not generate bytecode?

root@d590c2e5d6fb:/opt/src/example03/build# tree
.
|-- CMakeCache.txt
|-- CMakeFiles
| |-- 3.26.4
| | |-- CMakeCCompiler.cmake
| | |-- CMakeCXXCompiler.cmake
| | |-- CMakeDetermineCompilerABI_C.bin
| | |-- CMakeDetermineCompilerABI_CXX.bin
| | |-- CMakeSystem.cmake
| | |-- CompilerIdC
| | | |-- CMakeCCompilerId.c
| | | |-- a.out
| | | -- tmp | | -- CompilerIdCXX
| | |-- CMakeCXXCompilerId.cpp
| | |-- a.out
| | -- tmp | |-- CMakeConfigureLog.yaml | |-- CMakeDirectoryInformation.cmake | |-- CMakeRuleHashes.txt | |-- CMakeScratch | |-- Makefile.cmake | |-- Makefile2 | |-- TargetDirectories.txt | |-- cmake.check_cache | |-- pkgRedirects | -- progress.marks
|-- Makefile
|-- cmake_install.cmake
-- src |-- CMakeFiles | |-- CMakeDirectoryInformation.cmake | |-- bar.dir | | |-- DependInfo.cmake | | |-- bar.cpp.o | | |-- bar.cpp.o.d | | |-- build.make | | |-- cmake_clean.cmake | | |-- cmake_clean_target.cmake | | |-- compiler_depend.make | | |-- compiler_depend.ts | | |-- depend.make | | |-- flags.make | | |-- link.txt | | -- progress.make
| |-- bar_as.dir
| | |-- DependInfo.cmake
| | |-- build.make
| | |-- cmake_clean.cmake
| | |-- compiler_depend.make
| | |-- compiler_depend.ts
| | -- progress.make | |-- bar_bc.dir | | |-- DependInfo.cmake | | |-- build.make | | |-- cmake_clean.cmake | | |-- compiler_depend.make | | |-- compiler_depend.ts | | -- progress.make
| |-- bar_bc_lib.dir
| | |-- DependInfo.cmake
| | |-- build.make
| | |-- cmake_clean.cmake
| | |-- compiler_depend.make
| | |-- compiler_depend.ts
| | |-- depend.make
| | |-- flags.make
| | |-- link.txt
| | -- progress.make | |-- bar_dis.dir | | |-- DependInfo.cmake | | |-- build.make | | |-- cmake_clean.cmake | | |-- compiler_depend.make | | |-- compiler_depend.ts | | -- progress.make
| |-- bar_llvmlink.dir
| | |-- DependInfo.cmake
| | |-- build.make
| | |-- cmake_clean.cmake
| | |-- compiler_depend.make
| | |-- compiler_depend.ts
| | -- progress.make | |-- bar_pass1.dir | | |-- DependInfo.cmake | | |-- build.make | | |-- cmake_clean.cmake | | |-- compiler_depend.make | | |-- compiler_depend.ts | | -- progress.make
| |-- bar_pass2.dir
| | |-- DependInfo.cmake
| | |-- build.make
| | |-- cmake_clean.cmake
| | |-- compiler_depend.make
| | |-- compiler_depend.ts
| | -- progress.make | |-- bar_pass3.dir | | |-- DependInfo.cmake | | |-- build.make | | |-- cmake_clean.cmake | | |-- compiler_depend.make | | |-- compiler_depend.ts | | -- progress.make
| |-- bar_pass4.dir
| | |-- DependInfo.cmake
| | |-- build.make
| | |-- cmake_clean.cmake
| | |-- compiler_depend.make
| | |-- compiler_depend.ts
| | -- progress.make | -- progress.marks
|-- Makefile
|-- cmake_install.cmake
|-- libbar.a
-- llvm-ir |-- bar_as |-- bar_bc |-- bar_bc_lib |-- bar_dis |-- bar_llvmlink |-- bar_pass1 |-- bar_pass2 |-- bar_pass3 -- bar_pass4

CMake configuration error

I'm getting this error when I try to cmake ..:

-- Configuring incomplete, errors occurred!
See also "[...]/CMakeFiles/CMakeOutput.log".

Without the include(LLVMIRUitls) does not appear

Inaccurate documentation: use of CMAKE_MODULE_PATH during inclusion

The documentation says:

  • In your CMakeLists.txt file include(LLVMIRUtil.cmake).

However, CMake doesn't search your CMAKE_MODULE_PATH in that case and so that doesn't work very well.

As per the examples, it should simply be:

  • In your CMakeLists.txt file include(LLVMIRUtil).

Skip header files in llvmir_attach_bc_target

Hi compor,

Thanks for the wonderful cmake module! It really helps me a lot.

Regarding #22, I found that some of the CMakeLists.txt files I analyze may contain something like:

add_executable(...
a.cpp
a.hpp
)

The problem is that since get_filename_component(OUTFILE ${IN_FILE} NAME_WE) is used in the LLVMIRUtil.cmake file, a.cpp and a.hpp are both regarded as target a. cmake therefore complains that there are two rules for the same target. So the first thing I did is change NAME_WE to NAME.
Another thing is that because a.hpp is actually a header file, which should probably not be compiled like a source file (just my guess), I got a bunch of errors. My solution is to 1. add these header files as included files. Actually, I add their directories, which I think should do the same thing without causing trouble. 2. skip these header files when handling IN_FILES.

Custom commands fail with certain generator expressions

Given this particular line:

ARGS ${CMD_ARGS} -c ${INFILE} -o ${FULL_OUT_LLVMIR_FILE}

If any of the target properties that compose CMD_ARGS contain command-specific generator expressions, CMake will fail.

For example, attaching a bitcode target to a library or executable containing $<OR:$<COMPILE_LANGUAGE:C>,$<COMPILE_LANGUAGE:CXX>>:-UNDEBUG> will cause CMake to fail with the following error:

CMake Error at src/cmake/LLVMIRUtil.cmake:139 (add_custom_command):
  Error evaluating generator expression:

    $<COMPILE_LANGUAGE:C>

  $<COMPILE_LANGUAGE:...> may only be used to specify include directories,
  compile definitions, compile options, and to evaluate components of the
  file(GENERATE) command.

Two possible solutions involve stripping out these types of generator expressions using string(GENEX_STRIP) (NOT ideal) or using file(GENERATE) to write all the arguments to a response file for Clang to consume. This is also less-than-ideal as this response file won't exist until build time so it can't be used for testing compilation flags, but it's better than removing the generator expressions entirely.

Add travis-ci support

Add travis-ci support for the various to test the various versions of the LLVM toolchain.

Correctly produce unoptimized LLVM IR code based on LLVM version

There seems to have been a change in the way -O0 works in conjunction with --emit-llvm.

If -O0 is used with the latest LLVM versions, functions get annotated with optnone attribute, which prohibits further optimizations. The workaround seems to be to use -O1 along with -disable-llvm-optzns and/or -disable-llvm-passes.

The related discussion can be found here.

  • Determine minimum affected LLVM version
  • Determine LLVM commit number
  • Determine exact command line arguments required
  • Resolve and test against various versions (having a test, it'd have been nice)

Add github workflow support

Add support for GitHub workflows to:

  • test different LLVM versions and interactions with this module
  • exercise module functionality

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.