Is llvm able to compile, assemble and link x86-64 code on windows and/or linux using llvm-mc and lld?
If so, is there a hello-world level example out there? The documentation is pretty sparse at present.
I've tried building a simple hello world (main0.cpp) using trunk LLVM (with clang & lld).
main0.cpp:
int main(int argc, char const* argv[])
{ return 0; }
Compile (no errors):
[MY-LLVM]/clang -S -o main0.s main0.cpp
Assemble (no errors):
[MY-LLVM]/llvm-mc -arch=x86-64 -triple=x86_64-linux-gnu -o main0.o main0.s
Link (FAILS HERE!):
[MY-LLVM]/lld -flavor gnu --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -L/usr/lib/gcc/x86_64-linux-gnu/4.8 -L/usr/lib/x86_64-linux-gnu -L/lib/x86_64-linux-gnu -L/lib64 -L/usr/lib/x86_64-linux-gnu -L/usr/lib -L/<MY-LLVM>/lib -L/lib -L/usr/lib -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.8/crtbegin.o /usr/lib/gcc/x86_64-linux-gnu/4.8/crtend.o /usr/lib/x86_64-linux-gnu/crtn.o -o main0.run main.o
Link error:
lld: unknown input file format for file main.o
I obtained the linker command via clang -o main0.run main0.cpp -### (replacing ld with [MY-LLVM]/lld -flavor gnu).
I assume that I'm either generating the wrong type of object file when assembling, or using the wrong parameters when linking.
Does anyone know how to do this right?
(My ultimate aim is to get full C++14 working on win64 (without massive hacks), but I'm struggling with getting trunk clang to work with the mingw tools so I thought I'd try pure LLVM).
lld developer here.
lld self hosts on both Linux and Windows, so I would expect them to work here. The way I generally get clang to use lld is to make a symlink to lld named ld and add it to PATH. lld will behave like gnu-ld in this case.
As for llvm-mc, it is not an assembler. It is a tool for testing the MC layer of llvm. By default it simply parses the assembly and prints it back out. This is why lld is rejecting the main0.o file, as it's actually a text file.
The correct thing to do here without having lld as ld in the path is either:
clang -c -o main0.o main0.cpp
or:
clang -S -o main0.s main0.cpp
clang -c -o main0.o main0.s
If you really want the assembly for some reason.
Related
Passing --coverage to gcc while also linking LLVM causes an undefined reference to `__gcov_exit' error from the linker. I've set up a fresh project to try to isolate this problem. You can view the source on github and inspect the compiler output on Travis-CI.
This is the difference between a coverage and a non-coverage build
-DCMAKE_CXX_FLAGS="--coverage"
This is the difference between an LLVM and a non-LLVM build
target_link_libraries(Test
PUBLIC
LLVMCore
)
The LLVM job succeeds. The Coverage job succeeds. The LLVM + Coverage job fails with this error
undefined reference to `__gcov_exit'
Notes:
Check [CMake 3.13]: CMAKE_<LANG>_FLAGS for details regarding which env var affects which cmake var - as you figured out in your (deleted) answer
Only noticed cxx_std_17 from CMake 3.8, so you might want to update your cmake_minimum_required
Forked your repo to [GitHub]: CristiFati/gcov_error - An attempt to reproduce the gcov/llvm linker error and did some debugging on it
Beware, I might delete it someday
Was able to get my head around Travis CI, it's a real gold-mine
At the beginning I thought that it would be a trivial fix (something related to -fprofile-arcs, -ftest-coverage, -lgcov flags) as noted in [Man7]: GCC(1) (--coverage option), but it wasn't.
I wasn't able to reproduce the problem on my Ubuntu 16 pc064 VM (although Travis is very nice, it's kind of slow for debugging purposes (especially when due to rushing one might forget or add an extra character when editing :) ) and also it doesn't offer the same access level that a local machine does,) because the environment:
CMake 3.5.1
GCC 5.4.0
LLVM 3.8.0
is pretty far away from what's on the Travis Docker image. I must mention that neither I tried building the packages from sources (that would probably have caused lots of headaches), nor did I try downloading them from the repositories where they are downloaded during CI builds (didn't even check if those repos are public). Anyway the VM was pretty much unusable because:
I couldn't reproduce the issue (after some minor changes to adapt to older tools), everything worked
More: I ran into [SO]: Error when using CMake with LLVM (#CristiFati's answer)
It was eating me alive, so I ended up building 48 freaking times (on Travis) in order to get it working, and that is only because I failed to notice the obvious.
The problem
For each of the 3 configurations I'm going to paste the compile and link (G++) commands generated (from your build: [Travis CI]: Kerndog73/gcov_error - Build #24)
LLVM:
/usr/bin/g++-7 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/usr/lib/llvm-7/include -std=gnu++1z -o CMakeFiles/Test.dir/main.cpp.o -c /home/travis/build/Kerndog73/gcov_error/main.cpp
/usr/bin/g++-7 -rdynamic CMakeFiles/Test.dir/main.cpp.o -o Test -L/usr/lib/gcc/x86_64-linux-gnu/4.8 /usr/lib/llvm-7/lib/libLLVMCore.a /usr/lib/llvm-7/lib/libLLVMBinaryFormat.a /usr/lib/llvm-7/lib/libLLVMSupport.a -lz -lrt -ldl -ltinfo -lpthread -lm /usr/lib/llvm-7/lib/libLLVMDemangle.a
Coverage:
/usr/bin/g++-7 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/usr/lib/llvm-7/include --coverage -std=gnu++1z -o CMakeFiles/Test.dir/main.cpp.o -c /home/travis/build/Kerndog73/gcov_error/main.cpp
/usr/bin/g++-7 --coverage -rdynamic CMakeFiles/Test.dir/main.cpp.o -o Test
LLVM + Coverage:
/usr/bin/g++-7 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/usr/lib/llvm-7/include --coverage -std=gnu++1z -o CMakeFiles/Test.dir/main.cpp.o -c /home/travis/build/Kerndog73/gcov_error/main.cpp
/usr/bin/g++-7 --coverage -rdynamic CMakeFiles/Test.dir/main.cpp.o -o Test -L/usr/lib/gcc/x86_64-linux-gnu/4.8 /usr/lib/llvm-7/lib/libLLVMCore.a /usr/lib/llvm-7/lib/libLLVMBinaryFormat.a /usr/lib/llvm-7/lib/libLLVMSupport.a -lz -lrt -ldl -ltinfo -lpthread -lm /usr/lib/llvm-7/lib/libLLVMDemangle.a
After lots of ghosts chasing, I noticed -L/usr/lib/gcc/x86_64-linux-gnu/4.8 being passed to the linker when LLVM is included. GCC 4.8 is installed on the Docker, so apparently GCC 7.4 was used for compilation, and GCC 4.8 for linking, which is Undefined Behavior.
I'm also pasting the Collect command (closer to the linker) from a slight variation (with -v) of #3. (all the libraries specified with -l* and without the full path (e.g. -lgcov, -lgcc_s, -lgcc) have the wrong version because will be picked up from the wrong directory):
/usr/lib/gcc/x86_64-linux-gnu/7/collect2 -plugin /usr/lib/gcc/x86_64-linux-gnu/7/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/7/lto-wrapper -plugin-opt=-fresolution=/tmp/ccyDh97q.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --sysroot=/ --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -export-dynamic -dynamic-linker /lib64/ld-linux-x86-64.so.2 -z relro -o Test /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/7/crtbegin.o -L/usr/lib/gcc/x86_64-linux-gnu/4.8 -L/usr/lib/gcc/x86_64-linux-gnu/7 -L/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/7/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/7/../../.. CMakeFiles/Test.dir/main.cpp.o /usr/lib/llvm-7/lib/libLLVMCore.a /usr/lib/llvm-7/lib/libLLVMBinaryFormat.a /usr/lib/llvm-7/lib/libLLVMSupport.a -lz -lrt -ldl -ltinfo -lpthread /usr/lib/llvm-7/lib/libLLVMDemangle.a -lstdc++ -lm -lgcov -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-linux-gnu/7/crtend.o /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crtn.0
Some test commands placed in .travis.yml's after_script section, yielded the following output:
$ _GCOV_LIB7=/usr/lib/gcc/x86_64-linux-gnu/7/libgcov.a
$ (nm -S ${_GCOV_LIB7} 2>/dev/null | grep __gcov_exit) || echo ${_GCOV_LIB7}
0000000000001e40 000000000000008b T __gcov_exit
$ _GCOV_LIB48=/usr/lib/gcc/x86_64-linux-gnu/4.8/libgcov.a
$ (nm -S ${_GCOV_LIB48} 2>/dev/null | grep __gcov_exit) || echo ${_GCOV_LIB48}
/usr/lib/gcc/x86_64-linux-gnu/4.8/libgcov.a
So, LibGCC (libgcov.a) was modified somewhere between the 2 involved versions (__gcov_exit symbol was added), and G++ knew it has one but Ld didn't provide it (because of the wrong lib) hence the error.
Now, why does LLVM add this library search path, I don't know (probably because it was built with GCC 4.8 - or smth close to it), but here's what I can think of:
LLVM is not meant to be used with GCC 7 (although I didn't find any such restriction while quickly browsing [LLVM]: Getting Started with the LLVM System)
A bug in LLVM (considering the other issue that I ran into, I tend to think this is the winner)
I found ways for both of them:
Use an older G++ (v4.8 - installed by default on the Docker)
export CXX=g++ (might even not be necessary)
G++ (not CMake this time) doesn't know about cxx_std_17, so the easiest way is to remove the afferent target_compile_features (the drawback is that code won't be C++17 "compliant")
Since I don't know how to "undo" passing the (faulty) library search path, the workaround that I came up with is to specify the correct one before it.
CMakeLists.txt:
cmake_minimum_required(VERSION 3.2)
project(gcov_test)
find_package(LLVM 7.0.0 REQUIRED CONFIG)
message(STATUS "Found LLVM: ${LLVM_DIR} ${LLVM_PACKAGE_VERSION}")
add_executable(Test
"main.cpp"
)
target_compile_features(Test
PUBLIC cxx_std_17
)
target_include_directories(Test
PUBLIC ${LLVM_INCLUDE_DIRS}
)
target_compile_definitions(Test
PUBLIC ${LLVM_DEFINITIONS}
)
if(LINK_WITH_LLVM)
# #TODO - cfati: Everything in this block is to avoid hardcoding default libgcc path (/usr/lib/gcc/x86_64-linux-gnu/7)
set(_COLLECT_LTO_WRAPPER_TEXT "COLLECT_LTO_WRAPPER=")
execute_process(
COMMAND bash -c "$0 -v 2>&1 | grep ${_COLLECT_LTO_WRAPPER_TEXT} | sed s/${_COLLECT_LTO_WRAPPER_TEXT}//" "${CMAKE_CXX_COMPILER}"
OUTPUT_VARIABLE _GAINARIE_COLLECT_TMP_VAR
)
get_filename_component(_GAINARIE_GCC_DEFAULT_PATH ${_GAINARIE_COLLECT_TMP_VAR} DIRECTORY)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L${_GAINARIE_GCC_DEFAULT_PATH}")
#set (GCCOPT "${GCCOPT} -L${_GAINARIE_GCC_DEFAULT_PATH}")
# #TODO END
target_link_libraries(Test
PUBLIC LLVMCore
)
endif()
Note: I tried to come up with something more elegant (I'm sure that it is), but I couldn't (tried using CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES, target_link_libraries, link_directories and a few more) at this point.
Somehow my CUDA binary build process has been messed up. All of the .cu files compile nicely to .o files, but when I try to link, I get:
CMakeFiles/tester.dir/tester_intermediate_link.o: In function `__cudaRegisterLinkedBinary_66_tmpxft_00007a5f_00000000_16_cuda_device_runtime_compute_52_cpp1_ii_8b1a5d37':
/tmp/tmpxft_00006b54_00000000-2_tester_intermediate_link.reg.c:7: undefined reference to `__fatbinwrap_66_tmpxft_00007a5f_00000000_16_cuda_device_runtime_compute_52_cpp1_ii_8b1a5d37'
Now, I have not used compute_52 anywhere. My nvcc command-line is:
/usr/local/cuda/bin/nvcc -M -D__CUDACC__ /home/joeuser/src/my_project/src/kernel_specific/elementwise/Add.cu -o /home/joeuser/src/my_project/CMakeFiles/tester.dir/src/kernel_specific/elementwise/tester_generated_Add.cu.o.NVCC-depend -ccbin /usr/bin/gcc-4.9.3 -m64 --std c++11 -D__STRICT_ANSI__ -Xcompiler ,\"-Wall\",\"-g\",\"-g\",\"-O0\" -gencode arch=compute_35,code=compute_35 -g -G --generate-line-info -DNVCC -I/usr/local/cuda/include -I/opt/cub -I/usr/local/cuda/include
and my link line is:
/usr/bin/g++-4.9.3 -Wall -std=c++11 -g some.o files.o here.o blah.o blahblah.o bar.cu.o baz.cu.o -o bin/myapp -rdynamic -Wl,-Bstatic -lcudart_static -Wl,-Bdynamic -lpthread -lrt -ldl /usr/lib/libboost_system.so /usr/lib/libboost_program_options.so -Wl,-Bstatic -lcudart_static -Wl,-Bdynamic -lpthread -lrt -ldl /usr/local/cuda/extras/CUPTI/lib64/libcupti.so -lnvToolsExt -lOpenCL /usr/lib/libboost_system.so /usr/lib/libboost_program_options.so /usr/local/cuda/extras/CUPTI/lib64/libcupti.so -lnvToolsExt -lOpenCL -Wl,-rpath,/usr/lib:/usr/local/cuda/extras/CUPTI/lib64
I'll note I have separate compilation enabled, and do not seem to have skipped my intermediate link phase.
Why is this happening?
CUDA has two compilation modes, relocatable and static.
The relocatable mode is required for some configurations-which we will not get into now.
If you want to compile in relocatable mode -rdc=true, you'll need the Cuda device runtime library.
Which is located in the file cudadevrt.lib.
On some instances, supplying -lcudadevrt as a command line switch to the CUDA linker does the job, but on e.g. MSVC, you'll also need to specify cudadebrt.lib as a link dependency.
Well, I'm not sure why I'm seeing missing references to Compute 5.2 calls, but adding -lcudadevrt to the end of the link command makes the error go away.
I am working on a project where I need to generate just the bitcode using clang, run some optimization passes using opt and then create an executable and measure its hardware counters.
I am able to link through clang directly using:
clang -g -O0 -w -I/opt/apps/papi/5.3.0/include -Wl,-rpath,$PAPI_LIB -L$PAPI_LIB \
-lpapi /scratch/02681/user/papi_helper.c prog.c -o a.out
However now I want to link it after using the front end of clang and applying optimization passes using opt.
I am trying the following way:
clang -g -O0 -w -c -emit-llvm -I/opt/apps/papi/5.3.0/include -Wl,-rpath,$PAPI_LIB -L$PAPI_LIB \
-lpapi /scratch/02681/user/papi_helper.c prog.c -o prog.o
llvm-link prog.o papi_helper.o -o prog-link.o
// run optimization passes
opt -licm prog-link.o -o prog-opt.o
llc -filetype=obj prog-opt.o -o prog-exec.o
clang prog-exec.o
After going through the above process I get the following error:
undefined reference to `PAPI_event_code_to_name'
It's not able to resolve papi functions. Thanks in advance for any help.
Clearly, you need to add -lpapi to the last clang invocation. How else the linker would know about libpapi?
I am compiling a C++ application using GNU g++. The project takes advantage of OpenSSL libraries.
Background
On my machine (a 64 bit CentOS quad core) I compile and link my files.
g++ -g -c -L/usr/local/lib/ -L/usr/lib64/
-I/usr/local/include/ -I/usr/local/ssl/include/
-lcrypto mysrc1.cpp mysrc2.cpp mysrc3.cpp
g++ -L/usr/local/lib/ -L/usr/lib64/ -lcrypto
*.o -o ./myapp.out
My application uses function MD5 which is contained in libcrypto.so. As you can see I specify to g++ the dirs where to search using the -L, -I options and which libraries to look for with the -l<lib-name> option. There are some trivial paths like /usr/local/lib which can be omitted of course, but I specified them because the makefile is parametric.
The problem
My problem is that I can successfully compile my stuff (first command), but linking fails (second command):
/usr/bin/ld: cannot find -lcrypto
collect2: ld returned 1 exit status
make: * [cppsims_par] Error 1
But I did check folders and everything... libcrypto.so is inside /usr/lib64/. What is going on?
It may help if you try strace to find why it failed the file lookup
strace -f -e trace=file g++ -L/usr/local/lib/ -L/usr/lib64/ -lcrypto
*.o -o ./myapp.out
I did find the problem and it is related to this question: ld cannot find an existing library
Actually I had no symlink libcrypto.so and the compiler was not able to find the library...
I had related issue, and resolved it after inspecting the trace.
I had
-L<my/path/to/lib> -llib_some_library
when it should have been
-L<my/path/to/lib> -lsome_library
I'm having a weird problem with making an SFML2 application. I'm using Clang++ from the Repositories as well as libc++ (both updated today). SFML2 was also updated from the SVN repo. I'm using the latest version of Kubuntu. I also had the same problem when I last tried about a month ago with the then up-to-date repositories.
The parameters I'm passing through to the compiler for c++11 and stdlib are: -std=c++11 -stdlib=libc++
Here's the full version of what I'm calling:
clang++ -std=c++11 -stdlib=libc++ main2.cpp -o main -L/home/jonathan/OpenSource/sfml/SFML-Build/lib/ -I/home/jonathan/OpenSource/sfml/SFML/include/ -lsfml-system -lsfml-window -lsfml-graphics -v
When I try to compile the application, I get a linking error from Clang :
/tmp/main2-stOJMp.o: In function `main':
main2.cpp:(.text+0x108): undefined reference to `sf::Window::create(sf::VideoMode, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, unsigned int, sf::ContextSettings const&)'
All the application does (currently) is create a RenderWindow. It's just a test application, but for most SFML2 functions I use, there will be some linking problem like this. If I don't use libc++, the program compiles perfectly fine.
From what I can tell, if I include the -stdlib=libc++, it doesn't search the SFML2 lib folder for the SFML2 libraries to correctly link with.
When I use the -v command for the invocation with Clang, here is the ld call:
"/usr/bin/ld" -z relro --hash-style=gnu --build-id --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o main /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.6/crtbegin.o -L/home/jonathan/OpenSource/sfml/SFML-Build/lib/ -L/usr/lib/gcc/x86_64-linux-gnu/4.6 -L/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu -L/lib/x86_64-linux-gnu -L/lib/../lib64 -L/usr/lib/x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/4.6/../../.. -L/lib -L/usr/lib /tmp/main2-kOZbfN.o -lsfml-system -lsfml-window -lsfml-graphics -lc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-linux-gnu/4.6/crtend.o /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crtn.o
And if I don't use -stdlib=libc++...
"/usr/bin/ld" -z relro --hash-style=gnu --build-id --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o main /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.6/crtbegin.o -L/home/jonathan/OpenSource/sfml/SFML-Build/lib/ -L/usr/lib/gcc/x86_64-linux-gnu/4.6 -L/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu -L/lib/x86_64-linux-gnu -L/lib/../lib64 -L/usr/lib/x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/4.6/../../.. -L/lib -L/usr/lib /tmp/main2-2IOIxv.o -lsfml-system -lsfml-window -lsfml-graphics -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-linux-gnu/4.6/crtend.o /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crtn.o
So, In case I've confused people: if I use libc++ with Clang, I get the above error from the first ld call. If I don't use it, the second ld call goes through perfectly fine and the application runs successfully.
The reason I'm using libc++ is because I want to use the Threading from C++11. Without it, I get a ton of errors from the GNU C++ standard library my computer has. I won't post the error list for this, as it's huge and not relevant to this problem.
Does anyone have any clue as to how I might be able solve the SFML2 problem? I'd rather not use the pthreads library if I don't have to.
The SFML2 library has been compiled against some C++ library other than libc++ (perhaps libstdc++?). To correct, recompile SFML2 with -stdlib=libc++, and be sure the linker sees -stdlib=libc++ when linking SFML2 to your application.
The key to debugging this is noting that the linker is looking for sf::Window::create with std::__1 symbols. And libc++ mangles things with std::__1. But other std::libs mangle things with just std. This is a safety feature to keep you from accidentally mixing std::string from two different std::libs and ending up with a run time error instead of a link time error.