I would like to compile software using the autotools build system to LLVM bitcode; that is, I would like the executables obtained at the end to be LLVM bitcode, not actual machine code.
(The goal is to be able to run LLVM bitcode analysis tools on the whole program.)
I've tried specifying CC="clang -emit-llvm -use-gold-plugins" and variants to the configure script, to no avail. There is always something going wrong (e.g. the package builds .a static libraries, which are refused by the linker).
It seems to me that the correct way to do it would be that LLVM bitcode should be a cross-compilation target. to be set with --host=, but there is no such standard target (even though there is a target for Knuth's MMIX).
So far I've used kludges, such as compiling with CC="clang -emit-llvm -use-gold-plugins" and running linking lines (using llvm-ld or llvm-link) manually. This works for simple packages such as grep.
I would like a method that's robust and works with most, if not all, configure scripts, including when there are intermediate .a files, or intermediate targets.
There are some methods like this. But for simple builds where intermediate static libraries are not used, then you can do something simpler. The list of things you will need are
llvm, configured with gold plugin support. Refer to this
clang
dragonegg, if you need front-end for fortran, go, etc.
The key is to enable '-flto' for either clang or dragonegg(front-end), both at compile time and link time. It is straightforward for clang:
CC = clang
CLINKER = clang
CFLAGS = -flto -c
CLINKFLAGS = -flto -Wl,-plugin-opt=also-emit-llvm
If needed, add additional '-plugin-opt' option to specify llvm-specific codegen option:
-Wl,-plugin-opt=also-emit-llvm,-plugin-opt=-disable-fp-elim
The dumped whole problem bytecode would be sitting along with your final executable.
Two additional things are needed when using dragonegg.
First, the dragonegg is not aware of the location of llvm gold plugin, it needs to be specified in the linker flags like this -Wl,-plugin=/path/to/LLVMgold.so,-plugin-opt=...
Second, dragonegg is only able to dump IR rather than bytecode. You need a wrapper script for that purpose. I created one here. Works fine for me.
Related
I want to build GCC from source as a cross compiler for ARM bare-metal targets. Specifically, I need support for the architectures armv4t and armv5te with softfp for both of them since they lack a proper FPU.
The (relevant) flags I used are
--with-cpu=arm946e-s --with-mode=arm --with-float=soft --enable-interwork --enable-multilib --with-multilib-list=armv4t,armv5te
This way I tried to achieve that the compiler will default to armv5te with the --with-cpu option and still maintain the opportunity to build for armv4t.
Binutils build worked fine, however when building gcc's subdir gcc the multilib check failed with:
For arm946e-s real value is arm946e-s
Error: --with-multilib-list=armv4t,armv5te not supported.
make: *** [Makefile:4356: configure-gcc] Error 1
I looked up on how to enable armv5te support since armv4t with the arm7tdmi seems to be a default multilib target but found no results. There doesn't even seem to be a proper list of valid multilib targets. Removing the multilib list yielded a build of armv4t and armv7-a multilibs which I don't need to support.
How can I build both targets successfully with softfp?
TL-DR; There is no need. Use a wrapper and link to the desired standard libraries.
For soft and hard float, both the gcc libraries and generated code are effected. For a system with armv4 and armv5, the same compiler will always be able to generate the same code. Moreover, the generated objects are the same ABI. Ie, they pass parameters using the same mechanism. So the assembler instruction with-in an object may target armv4 or armv5. If you are on the armv5 architecture you may even link and run the armv4 objects. There is no issue except the code is sub-optimal.
You may build gcc libraries twice with the armv4 and armv5 options. Save the generated libraries. Headers will be identical. When you build armv5, use the armv5 libraries. Use -mcpu, -isystem (if you like) and -L to get the armv5 optimized libraries. For this reason I would use the armv4 build as the default. For certain this can be done with -freestanding and a gcc-armv5 wrapper script.
The multilib configuration is special in that the actual compiler binary can generate two sets of prologue and epilogue. Even before multilib it was always possible to generate either armv4 or armv5 code using the same compiler with -mcpu, or -march and -mtune. It is just they had the same prologue and epilogue. The instruction generation backend in gcc has always been multicpu. Probably multilib would better be named multiabi.
Several static analysis tools designed for C/C++ exist, but they are not particularly useful for testing CUDA sources.
Since clang version 6 is able to compile CUDA, I wanted to check what are my options with using clang-tidy, which does not seem to have option for switching architectures.
Is there a way to make it work? For example compile time switch for turning on CUDA parser, extension in form of custom check, or is it maybe planned feature?
One of the problem with the clang-based tools is that they are not parsing the files in exactly the same way as clang does.
The first problem is that unlike C/C++ compilation, CUDA compilation compiles the source multiple times. By default clang creates multiple compilation jobs when you give it a CUDA file and that trips many tools that expect only one compilation. In order to work that around you need to pass --cuda-host-only option to clang-tidy.
You may also need to pass --cuda-path=/path/to/your/CUDA/install/root so clang can find CUDA headers.
Another problem you may run into would be related to include paths. Clang-derived tools do not have the same default include paths that clang itself uses and that occasionally causes weird problems. At the very least clang-tidy needs to find __clang_cuda_runtime_wrapper.h which is installed along with clang. If you run clang-tidy your-file.c -- -v it will print clang's arguments and include search paths it uses. Compare that to what clang -x c /dev/null -fsyntax-only -vprints. You may need to give clang-tidy extra include paths to match those used by clang itself. Note that you should not explicitly add the path to the CUDA includes here. It will be added in the right place automatically by --cuda-path=....
Once you have it all in place, clang-tidy should work on CUDA files.
Something like this:
clang-tidy your-file.cu -- --cuda-host-only --cuda-path=... -isystem /clang/includes -isystem /extra/system/includes
I have my pass that I tested on toy programs and now I want to run it on large programs, many of which are open source programs like memcached. Such programs have their own Makefile and a complicated compilation procedure. I want to generate a bitcode file for such programs to let my pass work on them. Help and suggestions will be appreciated!
Depending on what you're pass is doing you can:
Build with LTO: adding -flto to the CFLAGS and building your application with your own built linker plugin is quite seamless from a build system point of view. However it requires some understand about how to setup LTO.
Build with your own built clang: adding statically your pass to the LLVM pipeline and use your own built clang. Depending on the build system, exporting CC/CXX environment variable pointing to your installed clang should be enough.
Build by loading your pass dynamically into clang, for example this is what Polly is (optionally) doing.
If you add -emit-llvm to your clang flags, it will emit BC files instead of object files or LL files instead of assembly.
You'll likely have to modify the makefile some more bit that should get you started in the right direction.
My current work flow requires me to rebuild the Rust compiler nearly every day to get the "standard crates" like libstd for another target platform (arm-unknown-linux-gnueabihf).
This is not ideal. I already use the nightly compiler, which is able to target the ARM platform, but it does not include the standard libraries for ARM, but only for my host machines platform.
How can I build just the libraries from source, without building the whole compiler toolchain with 3 compiler stages, llvm, jemalloc, etc...?
Can't say I'm 100% sure, but something like this might work.
Run:
rustc -v --version
Make a note of the commit-hash, then navigate to your rust src folder and run:
git checkout *your commit-hash*
Finally compile with:
rustc -O --target=arm-unknown-linux-gnueabihf rust/src/libstd/lib.rs
This should compile the library to your current working directory.
See http://spin.atomicobject.com/2015/02/20/rust-language-c-embedded/ for the original, and a more detailed explanation.
Based on LLVM official page, it is possible to have install-time optimization, based on my understanding, which first compiles to bytecode on build machine before distribution, and then on target machines, converts the bytecode to native code when installing.
Is there any real world example on this feature? More specifically, I am wondering if it is possible to take an arbitrary open source C/C++ project which uses autoconf (i.e. typically built and installed by ./configure && make && make install), and
on build machine, by running ./configure && make in a special
way (e.g. setting some environment variables, or even modify the
configure.ac or some other autoconf files) so that it generates
executable and libraries as byte code;
I transfer the build tree to target machine, and run make install
in a special way so that it installs all files as usual,
but converts byte code to native code for executable and libraries.
As #delnan indicated, this isn't possible in general. LLVM is a target independent IR, but it is not portable.
There have been a few attempts to construct a portable IR, PNaCl among them, but these are different from LLVM.
LLVM IR is target independent, meaning that it could be generated on one machine (compile time) and converted to bytecode (link time) on another and it would still generate the same bytecode as it would have on the first machine, provided that you were using the same version of LLVM with the same options. It does not mean that the IR that was generated would produce a valid binary on all machines.
The problem with this lies in the way that the ABI can vary between different systems.
This post addresses those differences in more detail:
LLVM bitcode cross-platform