Potential Bug in 'cmake/Modules/Compiler/clang.cmake' (CMAKE_C(XX)_COMPILE_OPTIONS_PIC)

I was attempting to cross-compile gRPC (https://github.com/grpc/grpc) from Windows to Linux as a third-party dependency using CMake and the Clang compiler; however, I encountered what I believe may be incorrect behavior in CMake:

  • When attempting this cross-compilation, my project (executable) was unable to link to the static libraries in gRPC. The reported error was something to the following effect: “relocation R_X86_64_32S against `***’ can not be used when making a shared object; recompile with -fPIC”.

  • I initially suspected the CMAKE_POSITION_INDEPENDENT_CODE variable was not being set correctly; however, I confirmed the CMAKE_POSITION_INDEPENDENT_CODE had the correct value of ‘ON’.

  • Upon further investigation, I noticed that when using the Clang compiler, the CMAKE_C(XX)_COMPILE_OPTIONS_PIC variables do not get set to ‘-fPIC’ in cmake/Modules/Compiler/clang.cmake; however, this same variable is set to ‘-fPIC’ in cmake/Modules/Compiler/GNU.cmake.

  • This difference in behavior explains why I saw the linker error reported above. It also explains why this cross-compilation fails when using Clang, but is successful when using the GNU compiler.

Is this difference in behavior for the CMAKE_C(XX)_COMPILE_OPTIONS_PIC variables when using the GNU and Clang compilers expected? In case it helps, this issue is similar to the one addressed by the following merge request: https://gitlab.kitware.com/cmake/cmake/-/merge_requests/1692/diffs.

The Clang settings re-use the GNU settings here, and that should get the PIC option from here. You could run cmake . --trace-expand 2>log in your build tree and look at the log file to see the verbose trace of execution. That will show whether the flag variable is set.

Thank you for the quick response.

I performed the steps you outlined to generate the log file using the Clang compiler. After reviewing the log file, I can confirm the following:

  • The CMAKE_C_COMPILE_OPTIONS_PIC flag variable is not set
  • Line 102 of CMakeCXXInformation.cmake sets CMAKE_CXX_COMPILE_OPTIONS_PIC to “” (since CMAKE_C_COMPILE_OPTIONS_PIC was not set).

I also tried the following steps to further narrow down the issue:

  • If I manually set CMAKE_C_COMPILE_OPTIONS_PIC to -fPIC in my project’s CMakeLists.txt file, then I can successfully compile and link to the third-party libraries. The log file also confirms that if I manually set CMAKE_C_COMPILE_OPTIONS_PIC to -fPIC, then CMAKE_CXX_COMPILE_OPTIONS_PIC is set to -fPIC. This is the temporary workaround that I have implemented.

  • If I change the compiler from Clang to GNU compiler, the log file confirms that CMAKE_C_COMPILE_OPTIONS_PIC is set to -fPIC (by line 22 of GNU.cmake). In other words, I do not have to manually set this flag variable in my project’s CMakeLists.txt file and it appears to be different behavior compared to when I use the Clang compiler.

In case it helps, here are the values of other flag variables in the resulting CMakeCCompiler.cmake file when using the Clang compiler that may impact this behavior:

  • CMAKE_C_PLATFORM_ID is set to “Windows” (this is set to “MinGW” when using GNU compiler)
  • CMAKE_C_SIMULATE_ID is set to “MSVC” (this is set to “” when using GNU compiler)

Does this information help to narrow down whether I am not using CMake correctly? My suspicion is that __compiler_gnu(${lang}) is not getting called in Clang.cmake because CMAKE_C_SIMULATE_ID equals MSVC.

Is it possible that Clang-DetermineCompilerInternal.cmake is setting CMAKE_C_SIMULATE_ID to MSVC if Clang is defining the _MSC_VER macro by default on Windows (even though CMAKE_C_COMPILER_FRONTEND_VARIANT is GNU): http://clang.llvm.org/docs/UsersManual.html#microsoft-extensions?

Please let me know if you need any additional information from me.

If CMAKE_C_SIMULATE_ID is MSVC and CMAKE_C_COMPILER_FRONTEND_VARIANT is GNU, that means it thinks you’re targeting Windows and not Linux. Please post your toolchain file. Is it setting CMAKE_C_COMPILER_TARGET to an appropriate Clang triple?

Here is the toolchain file:

set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR x86_64)

set(triple x86_64-unknown-linux-gnu)

set(toolchain C:/v15_clang-8.0.1-centos7/${triple})

set(CMAKE_SYSROOT ${toolchain})

set(CMAKE_C_COMPILER ${toolchain}/bin/clang.exe)
set(CMAKE_C_COMPILER_TARGET ${triple})

set(CMAKE_CXX_COMPILER ${toolchain}/bin/clang++.exe)
set(CMAKE_CXX_COMPILER_TARGET ${triple})

set(CMAKE_BUILD_WITH_INSTALL_RPATH ON)

set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

#The following line is a workaround until the following issue is addressed: Potential Bug in 'cmake/Modules/Compiler/clang.cmake' (CMAKE_C(XX)_COMPILE_OPTIONS_PIC)
#Once the issue is addressed, we should be able to delete the following line.
set(CMAKE_C_COMPILE_OPTIONS_PIC “-fPIC”)

add_compile_options(–target=${triple} --sysroot=${CMAKE_SYSROOT})
add_link_options(-v --target=${triple} --sysroot=${CMAKE_SYSROOT})
add_compile_definitions(GRPC_LINUX_TCP_H=1)

As far as I can tell, this toolchain file sets CMAKE_C_COMPILER_TARGET to an appropriate Clang triple (i.e., x86_64-unknown-linux-gnu) in set(CMAKE_C_COMPILER_TARGET ${triple}).

Ah, this looks like CMake Issue 21097 which will be fixed in 3.19. You can either build CMake from source using the upstream master branch, or try a recent nightly binary.

1 Like

I tested the following binary and it looks like the issue is resolved: cmake-3.18.20200929-g365b5dc-win64-x64. Now, when I read the value of CMAKE_C_COMPILE_OPTIONS_PIC, it is set to “-fPIC”, as expected, and I am able to link successfully to the third-party libraries without having to manually set this flag variable in my toolchain file.

Thank you for the outstanding support.