淺談如何使用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就可以順利進行了,當然這里會進行一下版本和環境的檢測。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM