浅谈如何使用clang替换gcc进行编译(2)

本来想直接把这一部分内容放到那一部分的,但是感觉篇幅有点太长了,就拆出新的一部分来发了。

接着上边的内容来说,本文会从一个相对比较复杂的project出发,来介绍使用clang来切换gcc的过程。

因为之前说想找到一个合适的project和一个合适的过程来介绍,后边就想到或许可以尝试下OpenCV来进行。选择OpenCV的理由主要为:

  1. 足够主流,能满足一部分人的实际需要,有真实价值
  2. OpenCV是一个大众(与小众相对)的软件,在写CMakeLists.txt的时候,考虑到了不同编译器,不同platform的需求,难度适中

 这里我没有经过太仔细的挑选,选的是master分支,看了下版本号,居然已经到了4.5.3版本,如果我的印象没错的话,我接触的第一个OpenCV版本还是2.4版本,变化真快。 下载代码:wget -O opencv.zip https://github.com/opencv/opencv/archive/master.zip 解压等过程不提

略过上边的废话,我想把我的思路分成两节,第一节是一个不考虑OpenCV特性的解决思路,第二节是OpenCV推荐的方式。这里的OpenCV特性,主要指的是OpenCV足够“大众”,它本身对多compiler、多platform进行了支持,不仅对host代码进行了支持,甚至对于类似于需要交叉编译的环境也进行了支持,这个良好的平台和编译器移植性,是其他软件不具备的,第一节就是从这种一般软件入手来说明OpenCV的移植问题。

第一节 普通软件的cmake编译移植

按照OpenCV官网的介绍,整个正常流程如下(https://docs.opencv.org/master/d7/d9f/tutorial_linux_install.html):

# Install minimal prerequisites (Ubuntu 18.04 as reference)
sudo apt update && sudo apt install -y cmake g++ wget unzip
# Download and unpack sources
wget -O opencv.zip https://github.com/opencv/opencv/archive/master.zip
unzip opencv.zip
# Create build directory
mkdir -p build && cd build
# Configure
cmake  ../opencv-master
# Build
cmake --build .

请务必直接按照这个流程走一遍,确认系统默认环境下有什么问题,先解决,再考虑如何进行交叉编译器或者clang什么的事情,gcc使用的默认C标准是C89,而clang使用的是C99,一般的差异就是这么多,剩下的option和链接问题基本上对照着都有解决方案,最害怕一个人编译用GCC都编译不过的东西让你改换Clang,用nvcc编译不过的CUDA程序也让你换Clang。

这里不考虑OpenCV本身的特性,考虑如何切换compiler。大概办法有两种,一种是直接指定,一种是在cmake执行的时候指定。

直接指定就是自己修改CMakeList.txt。打开这个文件,发现OpenCV的CMakeLists.txt开头就有这两个选项,直接修改:

# ----------------------------------------------------------------------------
#  Root CMake file for OpenCV
#
#    From the off-tree build directory, invoke:
#      $ cmake <PATH_TO_OPENCV_ROOT>
#
# ----------------------------------------------------------------------------

# Disable in-source builds to prevent source tree corruption.
if(" ${CMAKE_SOURCE_DIR}" STREQUAL " ${CMAKE_BINARY_DIR}")
  message(FATAL_ERROR "
FATAL: In-source builds are not allowed.
       You should create a separate directory for build files.
")
endif()
set(CMAKE_C_COMPILER "clang")
set(CMAKE_CXX_COMPILER "clang++")

include(cmake/OpenCVMinDepVersions.cmake)

然后按照上边的进行编译就好。当然有人会嫌改CMakeLists.txt有风险,在cmake的时候,使用-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++作用也是一样,这里简单说明一下,这两个选项是cmake自己所有的,因此没有这两个选项的CMakeLists.txt文件,建议搜下是否其包含的.cmake文件有对应的配置,如果确保都没有的话,请放心的加。

当然这种切换其实是有风险的,毕竟编译器不是完全相同,中间大概率会遇到一些问题。比如版本,我使用gcc去编译就没有问题,而在使用clang7.0的时候就遇到了avx512指令部分不支持的情况,切换到高版本的clang就得以解决,如果你的项目必须使用低版本的话,就需要对比一下这个地方有哪些功能还没有support,需要人肉去diff和打patch。

这里也介绍一点点经验,确定问题的真正来源,需要从make文件入手。在经历的cmake ..这一步骤后,往往会生成很多的文件,我这里拿OpenCV的dnn模块介绍一下。

 想确定dnn的问题,那么久需要切换到./modules/dnn/CMakeFiles/目录下查找问题,这种目录,基本的总控(或者说驱动)文件就是build.make文件,这里opencv_dnn又分成了 opencv_dnn.dir  opencv_perf_dnn.dir  opencv_test_dnn.dir这三个自文件,到了opencv_dnn.dir下边,可以清晰的看到

 居然有这么多文件,顾名思义,build.make驱动整个build过程,一般会依赖depend.make flags.make,link.txt是链接命令来源,想知道你对CmakeLists.txt的修改是否生效,请在这里最终确认,这里也可以方便的帮你确认最终的编译命令。比如build.make中的编译命令之一:

modules/dnn/CMakeFiles/opencv_dnn.dir/misc/caffe/opencv-caffe.pb.cc.o: ../modules/dnn/misc/caffe/opencv-caffe.pb.cc
    @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/daily_learning/opencv-master/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_2) "Building CXX object modules/dnn/CMakeFiles/opencv_dnn.dir/misc/caffe/opencv-caffe.pb.cc.o"
    cd /home/daily_learning/opencv-master/build/modules/dnn && /home/daily_learning/oldLLVM/build/bin/clang++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -Wno-inconsistent-missing-override -o CMakeFiles/opencv_dnn.dir/misc/caffe/opencv-caffe.pb.cc.o -c /home/daily_learning/opencv-master/modules/dnn/misc/caffe/opencv-caffe.pb.cc

 这个文件的最后甚至都清晰的告诉你了如何进行link:

lib/libopencv_dnn.so.4.5.3: modules/dnn/CMakeFiles/opencv_dnn.dir/link.txt
    @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --bold --progress-dir=/home/daily_learning/opencv-master/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_109) "Linking CXX shared library ../../lib/libopencv_dnn.so"
    cd /home/daily_learning/opencv-master/build/modules/dnn && $(CMAKE_COMMAND) -E cmake_link_script CMakeFiles/opencv_dnn.dir/link.txt --verbose=$(VERBOSE)
    cd /home/daily_learning/opencv-master/build/modules/dnn && $(CMAKE_COMMAND) -E cmake_symlink_library ../../lib/libopencv_dnn.so.4.5.3 ../../lib/libopencv_dnn.so.4.5 ../../lib/libopencv_dnn.so

 

到对应link.txt中去查找link命令就好

第二节 OpenCV推荐的编译思路

看下源码目录下的cmake文件夹,你会有很多新的发现:

 这里清清楚楚的写明白了OpenCVDetectCXXCompiler.cmake和OpenCVCompilerOptions.cmake这两个文件。

# Compilers:
# - CV_GCC - GNU compiler (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
# - CV_CLANG - Clang-compatible compiler (CMAKE_CXX_COMPILER_ID MATCHES "Clang" - Clang or AppleClang, see CMP0025)
# - CV_ICC - Intel compiler
# - MSVC - Microsoft Visual Compiler (CMake variable)
# - MINGW / CYGWIN / CMAKE_COMPILER_IS_MINGW / CMAKE_COMPILER_IS_CYGWIN (CMake original variables)
#
# CPU Platforms:
# - X86 / X86_64
# - ARM - ARM CPU, not defined for AArch64
# - AARCH64 - ARMv8+ (64-bit)
# - PPC64 / PPC64LE - PowerPC
# - MIPS
#
# OS:
# - WIN32 - Windows | MINGW
# - UNIX - Linux | MacOSX | ANDROID
# - ANDROID
# - IOS
# - APPLE - MacOSX | iOS
# ----------------------------------------------------------------------------

ocv_declare_removed_variables(MINGW64 MSVC64)
# do not use (CMake variables): CMAKE_CL_64

if(NOT DEFINED CV_GCC AND CMAKE_CXX_COMPILER_ID MATCHES "GNU")
  set(CV_GCC 1)
endif()
if(NOT DEFINED CV_CLANG AND CMAKE_CXX_COMPILER_ID MATCHES "Clang")  # Clang or AppleClang (see CMP0025)
  set(CV_CLANG 1)
  set(CMAKE_COMPILER_IS_CLANGCXX 1)  # TODO next release: remove this
  set(CMAKE_COMPILER_IS_CLANGCC 1)   # TODO next release: remove this
endif()

function(access_CMAKE_COMPILER_IS_CLANGCXX)
  if(NOT OPENCV_SUPPRESS_DEPRECATIONS)
    message(WARNING "DEPRECATED: CMAKE_COMPILER_IS_CLANGCXX support is deprecated in OpenCV.
    Consider using:
    - CV_GCC    # GCC
    - CV_CLANG  # Clang or AppleClang (see CMP0025)
")
  endif()
endfunction()
variable_watch(CMAKE_COMPILER_IS_CLANGCXX access_CMAKE_COMPILER_IS_CLANGCXX)
variable_watch(CMAKE_COMPILER_IS_CLANGCC access_CMAKE_COMPILER_IS_CLANGCXX)

 因此只需要配置下

set(CMAKE_CXX_COMPILER_ID "clang")
set(CV_CLANG 1)

  再进行cmake就可以顺利进行了,当然这里会进行一下版本和环境的检测。

原文地址:https://www.cnblogs.com/jourluohua/p/15026742.html