7

I've been trying to build an OpenMP sample program with an LLVM compiler integrated to Visual Studio 2019.

LLVM compiler was downloaded from here (version 10.0, win64), C:\Program Files\LLVM\bin added to the PATH environment variable. LLVM Compiler Toolchain extension was installed from Visual Studio Marketplace.

It successfully builds a hello world program, but when I try to use OpenMP the linker fails with the following errors:

1>clang version 10.0.0
1>Target: x86_64-pc-windows-msvc
1>Thread model: posix
1>InstalledDir: C:\Program Files\LLVM\bin
1> (in-process)
1> "C:\\Program Files\\LLVM\\bin\\clang-cl.exe" -cc1 -triple x86_64-pc-windows-msvc19.26.28805 -emit-obj -mrelax-all -mincremental-linker-compatible -disable-free -disable-llvm-verifier -discard-value-names -main-file-name llvmtest.cpp -mrelocation-model pic -pic-level 2 -mthread-model posix -mframe-pointer=none -relaxed-aliasing -fmath-errno -fno-rounding-math -masm-verbose -mconstructor-aliases -munwind-tables -target-cpu x86-64 -mllvm -x86-asm-syntax=intel -D_DEBUG -D_MT -D_DLL --dependent-lib=msvcrtd --dependent-lib=oldnames -stack-protector 2 -fcxx-exceptions -fexceptions -fexternc-nounwind -fms-volatile -fdefault-calling-conv=cdecl -fdiagnostics-format msvc -gcodeview -debug-info-kind=limited -v -resource-dir "C:\\Program Files\\LLVM\\lib\\clang\\10.0.0" -D _DEBUG -D _CONSOLE -D _UNICODE -D UNICODE -internal-isystem "C:\\Program Files\\LLVM\\lib\\clang\\10.0.0\\include" -internal-isystem "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.26.28801\\include" -internal-isystem "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.26.28801\\atlmfc\\include" -internal-isystem "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\VS\\include" -internal-isystem "C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.18362.0\\ucrt" -internal-isystem "C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.18362.0\\um" -internal-isystem "C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.18362.0\\shared" -internal-isystem "C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.18362.0\\winrt" -internal-isystem "C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.18362.0\\cppwinrt" -internal-isystem "C:\\Program Files (x86)\\Windows Kits\\NETFXSDK\\4.6.1\\Include\\um" -O0 -Wall -Wno-error -fdeprecated-macro -fdebug-compilation-dir "Z:\\llvmtest" -ferror-limit 19 -fmessage-length 0 -fopenmp -fno-use-cxa-atexit -fms-extensions -fms-compatibility -fms-compatibility-version=19.26.28805 -std=c++14 -fdelayed-template-parsing -fobjc-runtime=gcc -fno-caret-diagnostics -fdiagnostics-show-option -faddrsig -o "Debug\\llvmtest.obj" -x c++ llvmtest.cpp
1>clang -cc1 version 10.0.0 based upon LLVM 10.0.0 default target x86_64-pc-windows-msvc
1>#include "..." search starts here:
1>#include <...> search starts here:
1> C:\Program Files\LLVM\lib\clang\10.0.0\include
1> C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.26.28801\include
1> C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.26.28801\atlmfc\include
1> C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\VS\include
1> C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\ucrt
1> C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\um
1> C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\shared
1> C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\winrt
1> C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\cppwinrt
1> C:\Program Files (x86)\Windows Kits\NETFXSDK\4.6.1\Include\um
1>End of search list.
1>lld-link : error : undefined symbol: __kmpc_global_thread_num
1>>>> referenced by Z:\llvmtest\llvmtest.cpp:9
1>>>>               Debug\llvmtest.obj:(main)
1>
1>lld-link : error : undefined symbol: __kmpc_push_num_threads
1>>>> referenced by Z:\llvmtest\llvmtest.cpp:15
1>>>>               Debug\llvmtest.obj:(main)
1>
1>lld-link : error : undefined symbol: __kmpc_fork_call
1>>>> referenced by Z:\llvmtest\llvmtest.cpp:15
1>>>>               Debug\llvmtest.obj:(main)
1>
1>lld-link : error : undefined symbol: omp_get_thread_num
1>>>> referenced by Z:\llvmtest\llvmtest.cpp:19
1>>>>               Debug\llvmtest.obj:(.omp_outlined._debug__)
1>
1>lld-link : error : undefined symbol: omp_get_num_threads
1>>>> referenced by Z:\llvmtest\llvmtest.cpp:25
1>>>>               Debug\llvmtest.obj:(.omp_outlined._debug__)
1>Done building project "llvmtest.vcxproj" -- FAILED.

The code is rather trivial:

    #include <omp.h>
    #include <stdio.h>

    int main()
    {
        int nthreads, tid;

        //omp_set_num_threads(4);   

    #pragma omp parallel private(tid) num_threads(3)
        {               
            tid = omp_get_thread_num();
            printf("Hello World from thread = %d\n", tid);

            if (tid == 0)
            {
                nthreads = omp_get_num_threads();
                printf("Number of threads = %d\n", nthreads);
            }

        }  /* All threads join master thread and terminate */
    }

Project settings shown below: enter image description here enter image description here

I have tried different options: -fopenmp, -Xclang -fopenmp compiler flags, passing -openmp and -fopenmp as linker flags, changing x64 to x86, adding C:\Program Files\LLVM\lib to the PATH. Nothing helped so far.

Interestingly enough, I can build the same code from the command line by running the following from x64 Native Tools Command Prompt for VS 2019:

clang-cl -openmp llvmtest.cpp

So, basically, -openmp flag was enough... Does anyone have an idea how to make it work in Visual Studio?

mentalmushroom
  • 2,261
  • 1
  • 26
  • 34
  • These are all missing symbols from the OpenMP runtime library. Somewhere in the LLVM's `lib` directory there should be a `libomp.lib` file. You need to add it to the additional libraries in the linker settings. The problem is that VS does a separate link step and the linker doesn't know that you need the OpenMP runtime too. When you compile with `clang-cl -openmp ...`, the compiler driver automatically adds the OpenMP runtime library when calling the linker. – Hristo Iliev Jun 01 '20 at 14:24
  • @HristoIliev I was thinking of that, but I don't know how to properly add those libs to the linker. It seems to me 'usual' VS linker settings are irrelevant in this case as I am using LLVM, hence lld-link is used instead of the Microsoft linker. There is 'Additional Linker Options' field under LLVM (see the image), but I have no idea what to pass there. Can you give me a hint on that? – mentalmushroom Jun 01 '20 at 14:51
  • I guess `-lomp`. – Hristo Iliev Jun 01 '20 at 16:03
  • @HristoIliev lld-link : warning : ignoring unknown argument '-lomp' – mentalmushroom Jun 01 '20 at 16:27
  • Assuming `lld-link` is command-line compatible with `link`, then the additional option should be `libomp.lib`. You may also need to add the path to LLVM's `lib` directory somewhere too. – Hristo Iliev Jun 01 '20 at 17:33

3 Answers3

8

Finally, I have managed to make it work (thanks to Marek Aniola, the author of the LLVM Toolchain extension, who helped me out).

First, I passed the /openmp flag to LLVM -> Additional Compiler Options (it works with -openmp too).

Second, it turns out that OpenMP is not automatically linked when building from Visual Studio (in contrast to compiling from the command line by means of clang-cl). Linker settings for LLVM are specified the same way as for the Microsoft linker.

The path to libraries C:\Program Files\LLVM\lib has to be added to Linker -> General -> Additional Library Directories.

It is also necessary to list libomp.lib in Linker -> Input -> Additional Dependencies.

Linker -> Optimization -> Link Time Code Generation must be set to Default.

These steps let me successfully build the code (64-bit application). Although the 64-bit LLVM compiler can build a 32-bit program, it includes only x64 version of OpenMP libraries, so in order to build a 32-bit application I had to link libomp.lib and copy libomp.dll from another LLVM distribution. If there is a better way to do that, please let me know.

mentalmushroom
  • 2,261
  • 1
  • 26
  • 34
  • Visual Studio 2019 16.6.0 comes Clang 10.0.0 that targets both x86 and x64. You can install it using the Visual Studio Installer. – Hristo Iliev Jun 02 '20 at 10:53
  • @HristoIliev Yes, I've tried it first. But it seems to work in CMake projects only. And it also has some issues with finding OpenMP. I think it's discussed here: https://stackoverflow.com/questions/57209524/using-openmp-with-clang-and-cmake-in-visual-studio – mentalmushroom Jun 02 '20 at 14:20
  • @mentalmushroom, it works if you switch off the error on multi-threading in `Microsoft.Cpp.ClangCl.Common.targets` like this ``. – Ivan Siutsou Jun 21 '20 at 10:20
  • BTW: Which OpenMP version is supported by Clang in VS2019? – Laci Jul 05 '21 at 20:17
0

In addition to @mentalmushroom answer, it seems only step two is now necessary:

"...It is also necessary to list libomp.lib in Linker -> Input -> Additional Dependencies..."

Visual Studio 2019 16.10.3 using LLVM tool-set.

Chef Gladiator
  • 902
  • 11
  • 23
0

I also spent some time on getting Clang + OpenMP working in Visual Studio 2019. Here's my approach, hopefully it's useful to someone. It largely mimics the approach you would take on Linux with gcc.

Right-click Project in Visual Studio's Solution Explorer > Properties:
(1) General > Platform Toolset > LLVM (clang-cl)
(2) C/C++ > General > Additional Include Directories > C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\Llvm\lib\clang\10.0.0\include //Tells compiler where to find omp.h (in gcc: -I)
//The 64-bit version is located in C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\Llvm\x64\lib\clang\10.0.0\include
(3) C/C++ > Command Line > Additional Options > -openmp //Tells the compiler to use OpenMP (gcc: -fopenmp)
(4) Linker > General > Additional Library Directories > C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\Llvm\lib //Tells linker where to look for the OpenMP library (in gcc: -L)
//The 64-bit .lib file is located in C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\Llvm\x64\lib
(5) Linker > Input > Additional Dependencies > libomp.lib (or whatever the library file is called in C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\Llvm\lib) //Tells linker which library to link to (N.B. libomp.lib depends on libomp.dll) (in gcc: -l)
(6) Add to PATH system environment variable: C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\Llvm\bin //Here libomp.dll is located, so Windows can dynamically link the built executable to libomp.dll (in Linux: LD_LIBRARY_PATH)
//The 64-bit .dll file is located in C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\Llvm\x64\bin
//Restart CommandPrompt/PowerShell or computer to reload the environment variables
(7) Additionally, for 64 bit (fatal error LNK1112: module machine type 'x64' conflicts with target machine type 'X86'):
(7.1) Linker > Target Machine > MachineX64 (/MACHINE:x64)
(7.2) VC++ Directories > Executable Directories > C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\Llvm\x64\bin

The above process needs to be repeated for each combination of Release/Debug and x86(or Win32)/x64 (why do people prefer GUIs in a build system...)

Bart
  • 179
  • 1
  • 9